home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / show.C < prev    next >
C/C++ Source or Header  |  1998-11-26  |  16KB  |  659 lines

  1. // $Id: show.C,v 1.74 1998/11/26 12:31:12 zeller Exp $ -*- C++ -*-
  2. // DDD info functions
  3.  
  4. // Copyright (C) 1996 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char show_rcsid[] = 
  30.     "$Id: show.C,v 1.74 1998/11/26 12:31:12 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "show.h"
  37.  
  38. #include "AppData.h"
  39. #include "LiterateA.h"
  40. #include "config.h"
  41. #include "configinfo.h"
  42. #include "cook.h"
  43. #include "ddd.h"
  44. #include "gdbinit.h"
  45. #include "host.h"
  46. #include "post.h"
  47. #include "regexps.h"
  48. #include "shell.h"
  49. #include "status.h"
  50. #include "string-fun.h"
  51. #include "version.h"
  52. #include "filetype.h"
  53.  
  54. #include <iostream.h>
  55. #include <iomanip.h>
  56. #include <fstream.h>
  57. #include <string.h>
  58. #include <errno.h>
  59.  
  60. #include "Xpm.h"
  61. #include "HelpCB.h"
  62.  
  63. #if !HAVE_POPEN_DECL
  64. extern "C" FILE *popen(const char *command, const char *mode);
  65. #endif
  66. #if !HAVE_PCLOSE_DECL
  67. extern "C" int pclose(FILE *stream);
  68. #endif
  69.  
  70. //-----------------------------------------------------------------------------
  71. // Show invocation
  72. //-----------------------------------------------------------------------------
  73.  
  74. void show_invocation(const string& gdb_command, ostream& os)
  75. {
  76.     string gdb_version = "";
  77.     string options     = "";
  78.     string title       = "";
  79.     string base        = "";
  80.  
  81.     string gdb_get_help    = sh_command(gdb_command + " -h");
  82.     string gdb_get_version = sh_command(gdb_command + " -v");
  83.  
  84.     DebuggerType type;
  85.     bool type_ok = get_debugger_type(gdb_command, type);
  86.     if (!type_ok)
  87.     type = GDB;
  88.  
  89.     string args = "executable-file [core-file | process-id]";
  90.  
  91.     switch (type)
  92.     {
  93.     case GDB:
  94.     {
  95.     title = "GDB";
  96.     base  = "GDB, the GNU debugger.";
  97.  
  98.     Agent help(gdb_get_help);
  99.     help.start();
  100.  
  101.     FILE *fp = help.inputfp();
  102.     if (fp)
  103.     {
  104.         enum { Init, Options, Other, Done } state = Init;
  105.         char buf[BUFSIZ];
  106.  
  107.         while (fgets(buf, sizeof(buf), fp) && state != Done)
  108.         {
  109.         if (buf[0] && buf[strlen(buf) - 1] == '\n')
  110.             buf[strlen(buf) - 1] = '\0';
  111.  
  112.         string option;
  113.         switch (state)
  114.         {
  115.         case Init:
  116.             gdb_version = string(buf) + "\n";
  117.             state = Other;
  118.             break;
  119.  
  120.         case Other:
  121.             if (string(buf).contains("Options:"))
  122.             state = Options;
  123.             break;
  124.  
  125.         case Options:
  126.             option = buf;
  127.             if (option == "")
  128.             state = Done;
  129.             else
  130.             options += option + "\n";
  131.             break;
  132.  
  133.         case Done:
  134.             break;
  135.         }
  136.         }
  137.     }
  138.     break;
  139.     }
  140.  
  141.     case DBX:
  142.     {
  143.     title = "DBX";
  144.     base  = "DBX, the UNIX debugger.";
  145.     options = "  [DBX options]      Pass option to DBX.\n";
  146.     }
  147.     break;
  148.  
  149.     case JDB:
  150.     {
  151.     title = "JDB";
  152.     base  = "JDB, the Java debugger.";
  153.     options = "  [JDB options]      Pass option to JDB.\n";
  154.     args = "[class]";
  155.     }
  156.     break;
  157.  
  158.     case PYDB:
  159.     {
  160.     title = "PYDB";
  161.     base  = "PYDB, the Python debugger.";
  162.     options = "  [PYDB options]     Pass option to PYDB.\n";
  163.     args = "program-file";
  164.     }
  165.     break;
  166.  
  167.     case PERL:
  168.     {
  169.     title = "Perl";
  170.     base  = "the Perl debugger.";
  171.     options = "  [Perl options]     Pass option to Perl.\n";
  172.     args = "program-file [args]";
  173.     }
  174.     break;
  175.  
  176.     case XDB:
  177.     {
  178.     title = "XDB";
  179.     base  = "XDB, the HP-UX debugger.";
  180.  
  181.     Agent version(gdb_get_version);
  182.     version.start();
  183.  
  184.     FILE *fp = version.inputfp();
  185.     if (fp)
  186.     {
  187.         char buf[BUFSIZ];
  188.         while (fgets(buf, sizeof(buf), fp))
  189.         {
  190.         if (buf[0] && buf[strlen(buf) - 1] == '\n')
  191.             buf[strlen(buf) - 1] = '\0';
  192.         gdb_version = string(buf) + "\n";
  193.         }
  194.     }
  195.  
  196.     Agent help(gdb_get_help);
  197.     help.start();
  198.  
  199.     fp = help.errorfp();
  200.     if (fp)
  201.     {
  202.         enum { Other, Options, Done } state = Other;
  203.         char buf[BUFSIZ];
  204.  
  205.         while (fgets(buf, sizeof(buf), fp) && state != Done)
  206.         {
  207.         if (buf[0] && buf[strlen(buf) - 1] == '\n')
  208.             buf[strlen(buf) - 1] = '\0';
  209.  
  210.         string option;
  211.         switch (state)
  212.         {
  213.         case Other:
  214.             if (string(buf).contains("Options:"))
  215.             state = Options;
  216.             break;
  217.  
  218.         case Options:
  219.             option = buf;
  220.             if (option == "")
  221.             state = Done;
  222.             else
  223.             options += "  " + option.after(rxwhite) + "\n";
  224.             break;
  225.  
  226.         case Done:
  227.             break;
  228.         }
  229.         }
  230.     }
  231.     }
  232.     break;
  233.     }
  234.  
  235.     show_version(os);
  236.     os << gdb_version <<
  237.     "This is " DDD_NAME ", the data display debugger, based on "
  238.     << base << "\n" << 
  239.     "Usage:\n"
  240.     "    " ddd_NAME " [options...] " << args << "\n"
  241.     "Options:\n"
  242.     << options <<
  243.     "  --gdb              Invoke GDB as inferior debugger.\n"
  244.     "  --dbx              Invoke DBX as inferior debugger.\n"
  245.     "  --xdb              Invoke XDB as inferior debugger.\n"
  246.     "  --jdb              Invoke JDB as inferior debugger.\n"
  247.     "  --pydb             Invoke PYDB as inferior debugger.\n"
  248.     "  --perl             Invoke Perl as inferior debugger.\n"
  249.     "  --debugger NAME    Invoke inferior debugger as NAME.\n"
  250.     "  --host USER@HOST   Run inferior debugger on HOST.\n"
  251.     "  --rhost USER@HOST  Like --host, but use a rlogin connection.\n"
  252.     "  --vsl-library LIB  Load VSL library LIB.\n"
  253.     "  --vsl-path PATH    Look for VSL libraries in PATH.\n"
  254.     "  --font FONT        Use font FONT as default.\n"
  255.     "  --fontsize SIZE    Use fonts sized SIZE 1/10 points.\n"
  256.     "  --trace-dialog     Show dialog with inferior debugger"
  257.     " on standard error.\n"
  258.     "  --trace-shell      Show shell commands on standard error.\n"
  259.     "  --exec-window      Create a window for"
  260.     " running debugged programs.\n"
  261.     "  --no-exec-window   Do not create a window for"
  262.     " running debugged programs.\n"
  263.     "  --attach-windows   Attach data and source windows to"
  264.     " debugger console.\n"
  265.     "  --separate-windows Do not attach data and source windows to"
  266.     " debugger console.\n"
  267.     "  --scrolled-graph   Use Motif scrollbars"
  268.     " for moving the data display.\n"
  269.     "  --panned-graph     Use an Athena panner"
  270.     " for moving the data display.\n"
  271.         "  --tty              Use controlling tty"
  272.     " as additional debugger console.\n"
  273.     "  --version          Show the DDD version and exit.\n"
  274.     "  --configuration    Show the DDD configuration flags and exit.\n"
  275.     "  --manual           Show the DDD manual and exit.\n"
  276.     "  --license          Show the DDD license and exit.\n"
  277.     "  --news             Show the DDD news and exit.\n"
  278.     "  --vsl-help         Show VSL options and exit.\n"
  279.     "\n"
  280.     "Standard X options are also accepted, such as:\n"
  281.     "  -display DISPLAY   Run on X server DISPLAY.\n"
  282.     "  -geometry GEOMETRY Specify initial size and location.\n"
  283.     "  -iconic            Start-up in iconic mode.\n"
  284.     "  -foreground COLOR  Use COLOR as foreground color.\n"
  285.     "  -background COLOR  Use COLOR as background color.\n"
  286.     "  -xrm RESOURCE      Specify a resource name and value.\n"
  287.     "\n"
  288.     "For more information, consult the " DDD_NAME " `Help' menu,"
  289.     " type `help' from\n"
  290.     "within " DDD_NAME ", "
  291.     "and see the " DDD_NAME " and " << title << " documentation.\n";
  292. }
  293.  
  294.  
  295. //-----------------------------------------------------------------------------
  296. // Show Version and Configuration
  297. //-----------------------------------------------------------------------------
  298.  
  299. #define _stringize(x) #x
  300. #define stringize(x) _stringize(x)
  301.  
  302. static void show_configuration(ostream& os, bool version_only)
  303. {
  304.     // Storing this as a string literal would create an SCCS entry
  305.     string sccs = "@(" + string("#)");
  306.  
  307.     string s;
  308.  
  309.     // Version info
  310.     s = "@(#)" DDD_NAME " " DDD_VERSION " (" DDD_HOST "), "
  311.     "Copyright (C) 1998 TU Braunschweig.\n";
  312.     s.gsub(sccs, string(""));
  313.     os << s;
  314.  
  315.     if (version_only)
  316.     return;
  317.  
  318.     // Compilation stuff
  319.     s = "@(#)Compiled with "
  320. #ifdef __GNUC__
  321.     "GCC "
  322. #ifdef __VERSION__
  323.     __VERSION__
  324. #else  // !defined(__VERSION__)
  325.     stringize(__GNUC__)
  326. #ifdef __GNUC_MINOR__
  327.         "." stringize(__GNUC_MINOR__)
  328. #endif
  329. #endif // !defined(__VERSION__)
  330.  
  331. #elif defined(__SUNPRO_CC)
  332.     "SunPRO CC " stringize(__SUNPRO_CC)
  333. #else  // Anything else
  334.     "CC"
  335. #endif
  336.  
  337. #ifdef _G_LIB_VERSION
  338.     ", libstdc++ " _G_LIB_VERSION
  339. #endif
  340.  
  341. #if defined(__GLIBC__)
  342.     ", GNU libc " stringize(__GLIBC__) "." stringize(__GLIBC_MINOR__)
  343. #elif defined(_LINUX_C_LIB_VERSION)
  344.         ", Linux libc " _LINUX_C_LIB_VERSION
  345. #endif
  346.     "\n";
  347.     s.gsub(sccs, string(""));
  348.     os << s;
  349.  
  350.     // X stuff
  351.     s = "@(#)Requires X" stringize(X_PROTOCOL) 
  352.     "R" stringize(XlibSpecificationRelease)
  353.     ", Xt" stringize(X_PROTOCOL) "R" stringize(XtSpecificationRelease)
  354.     ", Motif " stringize(XmVERSION) "." stringize(XmREVISION)
  355. #if XmUPDATE_LEVEL
  356.     "." stringize(XmUPDATE_LEVEL)
  357. #endif
  358. #ifdef XmVERSION_STRING
  359.         " (" XmVERSION_STRING ")"
  360. #endif
  361.         "\n";
  362.     s.gsub(sccs, string(""));
  363.     s.gsub("( ", "(");
  364.     s.gsub(" )", ")");
  365.     os << s;
  366.  
  367.     // Optional stuff
  368.     s = "@(#)Includes " DDD_NAME " core"
  369. #if WITH_BUILTIN_MANUAL
  370.     ", manual"
  371. #endif
  372. #if WITH_BUILTIN_APP_DEFAULTS
  373.     ", app-defaults"
  374. #endif
  375. #ifdef XpmFormat
  376.     ", XPM " stringize(XpmFormat) "." stringize(XpmVersion) 
  377.     "." stringize(XpmRevision)
  378. #endif
  379. #if HAVE_ATHENA
  380.     ", Athena Panner"
  381. #endif
  382.     "\n";
  383.     s.gsub(sccs, string(""));
  384.     os << s;
  385.  
  386.     string cinfo = config_info;
  387.     cinfo = cinfo.before("\n");
  388.     strip_space(cinfo);
  389.  
  390.     os << cinfo << "\n";
  391. }
  392.  
  393. void show_version(ostream& os)
  394. {
  395.     show_configuration(os, true);
  396. }
  397.  
  398. void show_configuration(ostream& os)
  399. {    
  400.     show_configuration(os, false);
  401. }
  402.  
  403. //-----------------------------------------------------------------------------
  404. // Helpers
  405. //-----------------------------------------------------------------------------
  406.  
  407. static int uncompress(ostream& os, const char *text, int size)
  408. {
  409.     string tempfile = tmpnam(0);
  410.     FILE *fp = fopen(tempfile, "w");
  411.     if (fp == 0)
  412.     {
  413.     os << tempfile << ": " << strerror(errno);
  414.     return -1;
  415.     }
  416.  
  417.     int i;
  418.     for (i = 0; i < size; i++)
  419.     {
  420.     if (i % 100 == 0)
  421.         process_pending_events();
  422.     putc(text[i], fp);
  423.     }
  424.     fclose(fp);
  425.  
  426.     string cmd = string(app_data.uncompress_command) + " < " + tempfile;
  427.  
  428.     fp = popen(sh_command(cmd, true) + " 2>&1", "r");
  429.     if (fp == 0)
  430.     {
  431.     os << app_data.uncompress_command << ": " << strerror(errno);
  432.     return -1;
  433.     }
  434.  
  435.     int c;
  436.     i = 0;
  437.     while ((c = getc(fp)) != EOF)
  438.     {
  439.     if (i % 100 == 0)
  440.         process_pending_events();
  441.     os << (char)c;
  442.     i++;
  443.     }
  444.     pclose(fp);
  445.  
  446.     unlink(tempfile);
  447.     return 0;
  448. }
  449.  
  450. void show(int (*formatter)(ostream& os))
  451. {
  452.     FILE *pager = 0;
  453.     if (isatty(fileno(stdout)))
  454.     {
  455.     // Try, in that order:
  456.     // 1. The pager specified in the $PAGER environment variable
  457.     // 2. less
  458.     // 3. more
  459.     // 4. cat  (I wonder if this can ever happen)
  460.     string cmd = "less || more || cat";
  461.  
  462.     char *env_pager = getenv("PAGER");
  463.     if (env_pager != 0)
  464.         cmd = string(env_pager) + " || " + cmd;
  465.     cmd = "( " + cmd + " )";
  466.     pager = popen(sh_command(cmd), "w");
  467.     }
  468.  
  469.     if (pager == 0)
  470.     {
  471.     formatter(cout);
  472.     cout << flush;
  473.     }
  474.     else
  475.     {
  476.     ostrstream text;
  477.     formatter(text);
  478.     string s(text);
  479.  
  480.     fputs(s.chars(), pager);
  481.     pclose(pager);
  482.     }
  483. }
  484.  
  485.  
  486. //-----------------------------------------------------------------------------
  487. // WWW Page
  488. //-----------------------------------------------------------------------------
  489.  
  490. void DDDWWWPageCB(Widget, XtPointer, XtPointer)
  491. {
  492.     string url = app_data.www_page;
  493.     string cmd = app_data.www_command;
  494.  
  495.     StatusDelay delay("Invoking WWW browser for " + quote(url));
  496.  
  497.     cmd.gsub("@URL@", url);
  498.     cmd += " &";
  499.     cmd = sh_command(cmd, true);
  500.     system(cmd);
  501. }
  502.  
  503.  
  504.  
  505. //-----------------------------------------------------------------------------
  506. // License
  507. //-----------------------------------------------------------------------------
  508.  
  509. int ddd_license(ostream& os)
  510. {
  511.     static const char COPYING[] =
  512. #include "COPYING.gz.C"
  513.     ;
  514.  
  515.     return uncompress(os, COPYING, sizeof(COPYING) - 1);
  516. }
  517.  
  518. void DDDLicenseCB(Widget w, XtPointer, XtPointer call_data)
  519. {
  520.     StatusMsg msg("Invoking " DDD_NAME " license browser");
  521.  
  522.     ostrstream license;
  523.     int ret = ddd_license(license);
  524.     string s(license);
  525.     s.prepend("@license@");
  526.  
  527.     TextHelpCB(w, XtPointer((char *)s), call_data);
  528.  
  529.     if (ret != 0 || !s.contains("GNU"))
  530.     post_error("The " DDD_NAME " license could not be uncompressed.", 
  531.            "no_license_error", w);
  532. }
  533.  
  534. //-----------------------------------------------------------------------------
  535. // News
  536. //-----------------------------------------------------------------------------
  537.  
  538. int ddd_news(ostream& os)
  539. {
  540.     static const char NEWS[] =
  541. #include "NEWS.gz.C"
  542.     ;
  543.  
  544.     return uncompress(os, NEWS, sizeof(NEWS) - 1);
  545. }
  546.  
  547. void DDDNewsCB(Widget w, XtPointer, XtPointer call_data)
  548. {
  549.     StatusMsg msg("Invoking " DDD_NAME " news browser");
  550.  
  551.     ostrstream news;
  552.     int ret = ddd_news(news);
  553.     string s(news);
  554.     s.prepend("@news@");
  555.  
  556.     TextHelpCB(w, XtPointer((char *)s), call_data);
  557.  
  558.     if (ret != 0 || !s.contains(DDD_NAME))
  559.     post_error("The " DDD_NAME " news could not be uncompressed.", 
  560.            "no_news_error", w);
  561. }
  562.  
  563.  
  564.  
  565. //-----------------------------------------------------------------------------
  566. // Manual
  567. //-----------------------------------------------------------------------------
  568.  
  569. int ddd_man(ostream& os)
  570. {
  571. #if WITH_BUILTIN_MANUAL
  572.     static const char MANUAL[] =
  573. #include "ddd.man.txt.gz.C"
  574.     ;
  575.  
  576.     return uncompress(os, MANUAL, sizeof(MANUAL) - 1);
  577. #else
  578.     // Try `man ddd' and `man xddd'.
  579.     FILE *fp = popen(sh_command("man " ddd_NAME " || man x" ddd_NAME), "r");
  580.     if (fp == 0)
  581.     return -1;
  582.  
  583.     int c;
  584.     int i = 0;
  585.     while ((c = getc(fp)) != EOF)
  586.     {
  587.     if (i % 100 == 0)
  588.         process_pending_events();
  589.     os << char(c);
  590.     i++;
  591.     }
  592.     pclose(fp);
  593.     return 0;
  594. #endif
  595. }
  596.  
  597. void DDDManualCB(Widget w, XtPointer, XtPointer)
  598. {
  599.     StatusMsg msg("Invoking " DDD_NAME " manual browser");
  600.     
  601.     ostrstream man;
  602.     int ret = ddd_man(man);
  603.     string s(man);
  604.  
  605.     MString title(DDD_NAME " Reference");
  606.     ManualStringHelpCB(w, title, s);
  607.  
  608.     if (ret != 0 || !s.contains(DDD_NAME))
  609.     {
  610. #if WITH_BUILTIN_MANUAL
  611.     post_error("The " DDD_NAME " manual could not be uncompressed.", 
  612.            "no_ddd_manual_error", w);
  613. #else
  614.     post_error("The " DDD_NAME " manual could not be accessed.",
  615.            "no_ddd_man_page_error", w);
  616. #endif
  617.     }
  618. }
  619.  
  620. void GDBManualCB(Widget w, XtPointer, XtPointer)
  621. {
  622.     StatusMsg msg("Invoking " + gdb->title() + " manual browser");
  623.  
  624.     string key = downcase(gdb->title());
  625.     if (gdb->type() == PERL)
  626.     key = "perldebug";
  627.  
  628.     string cmd = "man " + key + " 2>&1";
  629.  
  630.     if (gdb->type() == GDB)
  631.     {
  632.     // Try `info' first
  633.     cmd.prepend("info --subnodes -o - -f " + key + " 2> /dev/null || ");
  634.     }
  635.  
  636.     FILE *fp = popen(sh_command(cmd), "r");
  637.     if (fp != 0)
  638.     {
  639.     ostrstream man;
  640.     int c;
  641.     int i = 0;
  642.     while ((c = getc(fp)) != EOF)
  643.     {
  644.         if (i % 100 == 0)
  645.         process_pending_events();
  646.         man << char(c);
  647.         i++;
  648.     }
  649.     
  650.     string s(man);
  651.     bool info = s.contains("File: ", 0);
  652.  
  653.     MString title(gdb->title() + (info ? " Info" : " Manual"));
  654.     ManualStringHelpCB(w, title, s);
  655.  
  656.     pclose(fp);
  657.     }
  658. }
  659.