home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / gdb / xgdb / xgdb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  16.5 KB  |  701 lines

  1. /*-
  2.  * This code is derived from software copyrighted by the Free Software
  3.  * Foundation.
  4.  *
  5.  * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
  6.  * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
  7.  *
  8.  * static char rcsid[] = "$Header: xgdb.c,v 1.9 90/12/16 16:01:05 van Exp $";
  9.  */
  10.  
  11. #ifndef lint
  12. static char sccsid[] = "@(#)xgdb.c    6.3 (Berkeley) 5/8/91";
  13. #endif /* not lint */
  14.  
  15. /*
  16.  * Interface from GDB to X windows. Copyright (C) 1987 Free Software
  17.  * Foundation, Inc.
  18.  * 
  19.  * GDB is distributed in the hope that it will be useful, but WITHOUT ANY
  20.  * WARRANTY.  No author or distributor accepts responsibility to anyone for
  21.  * the consequences of using it or for whether it serves any particular
  22.  * purpose or works at all, unless he says so in writing. Refer to the GDB
  23.  * General Public License for full details.
  24.  * 
  25.  * Everyone is granted permission to copy, modify and redistribute GDB, but only
  26.  * under the conditions described in the GDB General Public License.  A copy
  27.  * of this license is supposed to have been given to you along with GDB so
  28.  * you can know your rights and responsibilities.  It should be in a file
  29.  * named COPYING.  Among other things, the copyright notice and this notice
  30.  * must be preserved on all copies.
  31.  * 
  32.  * In other words, go ahead and share GDB, but don't try to stop anyone else
  33.  * from sharing it farther.  Help stamp out software hoarding!
  34.  */
  35.  
  36. /*
  37.  * Original version was contributed by Derek Beatty, 30 June 87.
  38.  * This version is essentially a re-write of the original by Van
  39.  * Jacobson (van@helios.ee.lbl.gov), Nov, 90.
  40.  */
  41.  
  42. #include "defs.h"
  43. #include "param.h"
  44. #include "symtab.h"
  45. #include "frame.h"
  46.  
  47. extern int stop_breakpoint;
  48.  
  49. #include <X11/IntrinsicP.h>
  50. #include <X11/StringDefs.h>
  51. #include <X11/Xaw/AsciiSink.h>
  52. #include <X11/Xaw/AsciiText.h>
  53. #include <X11/Xaw/Box.h>
  54. #include <X11/Xaw/Command.h>
  55. #include <X11/Xaw/Label.h>
  56. #include <X11/Xaw/Paned.h>
  57. #include <X11/Xaw/Text.h>
  58.  
  59. #include <stdio.h>
  60. #include <ctype.h>
  61. #include <sys/file.h>
  62. #include <sys/errno.h>
  63.  
  64. extern int errno;
  65. extern char *getenv();
  66. extern char *malloc();
  67. extern void bcopy();
  68. extern int select();
  69.  
  70. extern int get_filename_and_charpos();
  71. extern int source_line_charpos();
  72. extern int source_charpos_line();
  73. extern void execute_command();
  74. extern void error_no_arg();
  75. extern void add_com();
  76.  
  77. /* The X display where the window appears.  */
  78.  
  79. static char *displayname;
  80. static Display *display;
  81.  
  82. static XtAppContext app_context;
  83.  
  84. /* Windows manipulated by this package.  */
  85.  
  86. static Widget main_widget;
  87. static Widget containing_widget;
  88. static Widget source_name_widget;
  89. static Widget source_text_widget;
  90. static Widget button_box_widget;
  91.  
  92. /* Source text display.  */
  93.  
  94. static struct frame_info *last_fi;
  95. static CORE_ADDR last_pc;
  96. static struct symtab *last_cur_symtab;
  97. static int last_cur_line;
  98.  
  99. static int source_window_line;
  100. static char *source_window_file;
  101. static struct symtab *source_window_symtab;
  102.  
  103. static char version_label[64];
  104. extern char *version;
  105.  
  106. /* Forward declarations */
  107.  
  108. static Widget create_text_widget();
  109.  
  110. static int
  111. safe_strcmp(a, b)
  112.     register char *a, *b;
  113. {
  114.     register int i;
  115.  
  116.     if (a == b)
  117.         return (0);
  118.     if (!a && b)
  119.         return (1);
  120.     if (a && !b)
  121.         return (-1);
  122.     return (strcmp(a, b));
  123. }
  124.  
  125.  
  126. /* Display an appropriate piece of source code in the source window.  */
  127.  
  128. void
  129. xgdb_display_source()
  130. {
  131.     char *filename = NULL;
  132.     struct symtab_and_line get_selected_frame_sal();
  133.     struct symtab_and_line sal;
  134.     struct frame_info *fi;
  135.  
  136.     /* Do nothing if called before we are initialized */
  137.  
  138.     if (!containing_widget)
  139.         return;
  140.  
  141.     /*
  142.      * Figure out what to display (the appropriate hooks to tell
  143.      * us don't exist so we guess):  If there's a current frame
  144.      * and it or its pc changed from the last time we were here,
  145.      * display appropriate source line.  Otherwise if the current
  146.      * source symtab or line is different, display that line.
  147.      * Otherwise nothing changed so leave the display alone.
  148.      */
  149.     fi = get_frame_info(selected_frame);
  150.     if (fi && (fi != last_fi || fi->pc != last_pc)) {
  151.         last_fi = fi;
  152.         last_pc = fi->pc;
  153.         sal = find_pc_line(fi->pc, fi->next_frame);
  154.         if (sal.symtab == NULL) {    /* XXX */
  155.             sal.symtab = current_source_symtab;
  156.             sal.line = current_source_line;
  157.         }
  158.         current_source_symtab = sal.symtab;
  159.         current_source_line = sal.line;
  160.     } else if (current_source_symtab != last_cur_symtab ||
  161.            current_source_line != last_cur_line) {
  162.         sal.symtab = last_cur_symtab = current_source_symtab;
  163.         sal.line = last_cur_line = current_source_line;
  164.     } else
  165.         return;
  166.     /*
  167.      * Do a path search and get the exact filename of this source file.
  168.      * Also scan it and find its source lines if not already done.
  169.      */
  170.     if (sal.symtab && filename == NULL) {
  171.         if (get_filename_and_charpos(sal.symtab, sal.line, &filename))
  172.             /* line numbers may have changed - force highlight */
  173.             source_window_line = -1;
  174.     }
  175.  
  176.     /*
  177.      * If the source window is wrong, destroy it and make a new one.
  178.      */
  179.     if (safe_strcmp(filename, source_window_file)) {
  180.         Arg args[1];
  181.         Widget src = XawTextGetSource(source_text_widget);
  182.  
  183.         if (filename) {
  184.             XtSetArg(args[0], XtNstring, filename);
  185.             XtSetValues(src, args, XtNumber(args));
  186.             args[0].name = XtNlabel;
  187.             XtSetValues(source_name_widget, args, XtNumber(args));
  188.         } else {
  189.             XtSetArg(args[0], XtNstring, "/dev/null");
  190.             XtSetValues(src, args, XtNumber(args));
  191.             XtSetArg(args[0], XtNlabel, "");
  192.             XtSetValues(source_name_widget, args, XtNumber(args));
  193.         }
  194.         if (source_window_file)
  195.             free(source_window_file);
  196.         source_window_file = filename;
  197.         source_window_line = sal.line + 1;  /* force highlight */
  198.     }
  199.     if (sal.symtab && source_window_line != sal.line) {
  200.         /*
  201.          * Update display and cursor positions as necessary.
  202.          * Cursor should be placed on line sal.line.
  203.          */
  204.         XawTextPosition l, r;
  205.  
  206.         source_window_symtab = sal.symtab;
  207.         source_window_line = sal.line;
  208.         l = source_line_charpos(source_window_symtab, sal.line);
  209.         r = source_line_charpos(source_window_symtab, sal.line + 1);
  210.         if (r < l)
  211.             r = l + 1;
  212.         XawTextSetSelection(source_text_widget, l, r);
  213.         XawTextScrollToLine(source_text_widget, l, 10, 3);
  214.         XawTextSetInsertionPoint(source_text_widget, l);
  215.     }
  216. }
  217.  
  218.  
  219. /*
  220.  * Handlers for buttons.
  221.  */
  222.  
  223. static int
  224. current_lineno()
  225. {
  226.     XawTextPosition start, finish;
  227.  
  228.     XawTextGetSelectionPos(source_text_widget, &start, &finish);
  229.     if (start >= finish)
  230.         start = XawTextGetInsertionPoint(source_text_widget);
  231.  
  232.     return (source_charpos_line(source_window_symtab, start));
  233. }
  234.  
  235. static char *
  236. append_selection(cp)
  237.     char *cp;
  238. {
  239.     int len;
  240.     XawTextPosition l, r;
  241.  
  242.     XawTextGetSelectionPos(source_text_widget, &l, &r);
  243.     if ((len = r - l) > 0) {
  244.         Widget src = XawTextGetSource(source_text_widget);
  245.  
  246.         while (len > 0) {
  247.             XawTextBlock tb;
  248.  
  249.             XawTextSourceRead(src, l, &tb, len);
  250.             bcopy(tb.ptr, cp, tb.length);
  251.             cp += tb.length;
  252.             len -= tb.length;
  253.         }
  254.         if (cp[-1] == 0)
  255.             --cp;
  256.     }
  257.     return (cp);
  258. }
  259.  
  260. static char *
  261. append_selection_word(cp)
  262.     register char *cp;
  263. {
  264.     register int len;
  265.     XawTextPosition l, r;
  266.     XawTextBlock tb;
  267.     register char c;
  268.     register Widget src = XawTextGetSource(source_text_widget);
  269.  
  270.     XawTextGetSelectionPos(source_text_widget, &l, &r);
  271.     if ((len = r - l) <= 0) {
  272.         l = XawTextGetInsertionPoint(source_text_widget);
  273.         len = 128;    /* XXX */
  274.  
  275.         /* might have clicked in middle of word -- back up to start */
  276.         for ( ; l > 0; --l) {
  277.             XawTextSourceRead(src, l - 1, &tb, 1);
  278.             c = tb.ptr[0];
  279.             if (! isalnum(c) && c != '_' && c != '$')
  280.                 break;
  281.         }
  282.     }
  283.     while (len > 0) {
  284.         char *sp;
  285.         int i;
  286.  
  287.         XawTextSourceRead(src, l, &tb, len);
  288.         for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
  289.             c = *sp++;
  290.             if (!isalnum(c) && c != '_' && c != '$')
  291.                 return (cp);
  292.             *cp++ = c;
  293.         }
  294.         len -= tb.length;
  295.     }
  296.     return (cp);
  297. }
  298.  
  299. static char *
  300. append_selection_expr(cp)
  301.     char *cp;
  302. {
  303.     int len;
  304.     XawTextPosition l, r;
  305.     Widget src = XawTextGetSource(source_text_widget);
  306.     XawTextBlock tb;
  307.     char *sp;
  308.     char c;
  309.  
  310.     XawTextGetSelectionPos(source_text_widget, &l, &r);
  311.     if (r > l)
  312.         return (append_selection(cp));
  313.  
  314.     l = XawTextGetInsertionPoint(source_text_widget);
  315.  
  316.     /* might have clicked in middle of word -- back up to start */
  317.     for ( ; l > 0; --l) {
  318.         XawTextSourceRead(src, l - 1, &tb, 1);
  319.         c = tb.ptr[0];
  320.         if (! isalnum(c) && c != '_' && c != '$')
  321.             break;
  322.     }
  323.  
  324.     len = 128;    /* XXX */
  325.     while (len > 0) {
  326.         int i;
  327.         char pstack[64];
  328.         int pcnt = 0;
  329.  
  330.         XawTextSourceRead(src, l, &tb, len);
  331.         for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
  332.             switch (c = *sp++) {
  333.             case '\n':
  334.             case ';':
  335.                 return (cp);
  336.             case '=':
  337.                 if (cp[-1] != '=')
  338.                     return (cp - 1);
  339.                 if (len == 128)
  340.                     return (cp);
  341.                 break;
  342.             case ',':
  343.                 if (pcnt <= 0)
  344.                     return (cp);
  345.                 break;
  346.             case '(':
  347.                 pstack[pcnt] = ')';
  348.                 if (++pcnt >= sizeof(pstack))
  349.                     return (cp);
  350.                 break;
  351.             case '[':
  352.                 pstack[pcnt] = ']';
  353.                 if (++pcnt >= sizeof(pstack))
  354.                     return (cp);
  355.                 break;
  356.             case ')':
  357.             case ']':
  358.                 if (--pcnt < 0 || pstack[pcnt] != c)
  359.                     return (cp);
  360.                 break;
  361.             }
  362.             *cp++ = c;
  363.         }
  364.         len -= tb.length;
  365.     }
  366.     return (cp);
  367. }
  368.  
  369. static int input_avail;    /* XXX kluge: do_command sets this when command
  370.              * data from button is avaialble to force top level
  371.              * to break out of its loop. */
  372. /*
  373.  * Handle a button by running the command COMMAND.
  374.  */
  375. static void
  376. do_command(w, command, call_data)
  377.     Widget w;
  378.     register char *command;
  379.     caddr_t call_data;
  380. {
  381.     char cmd_line[256];
  382.     char buf[256];
  383.     register char *out = cmd_line;
  384.     char *cp;
  385.     register char c;
  386.     extern char *finish_command_input();
  387.  
  388.     while (c = *command++) {
  389.         if (c == '%') {
  390.             switch (*command++) {
  391.             case 's':    /* current selection */
  392.                 out = append_selection(out);
  393.                 break;
  394.             case 'S':    /* 1st selected "word" at curor */
  395.                 out = append_selection_word(out);
  396.                 break;
  397.             case 'e':    /* echo cmd before executing */
  398.                 break;
  399.             case 'E':    /* 1st selected expression at curor */
  400.                 out = append_selection_expr(out);
  401.                 break;
  402.                 
  403.             case 'l':    /* current line number */
  404.                 (void) sprintf(buf, "%d", current_lineno());
  405.                 for (cp = buf; c = *cp++; *out++ = c)
  406.                     ;
  407.                 break;
  408.             case 'L':    /* line we're stopped at */
  409.                 (void) sprintf(buf, "%d", source_window_line);
  410.                 for (cp = buf; c = *cp++; *out++ = c)
  411.                     ;
  412.                 break;
  413.             case 'f':    /* current file name */
  414.                 for (cp = source_window_symtab->filename;
  415.                      c = *cp++; *out++ = c)
  416.                     ;
  417.                 break;
  418.             case 'b':    /* break # we're stopped at */
  419.                 if (stop_breakpoint <= 0)
  420.                     /* if no breakpoint, don't do cmd */
  421.                     return;
  422.  
  423.                 (void) sprintf(buf, "%d", stop_breakpoint);
  424.                 for (cp = buf; c = *cp++; *out++ = c)
  425.                     ;
  426.                 break;
  427.             }
  428.         } else
  429.             *out++ = c;
  430.     }
  431.     *out = 0;
  432.     reinitialize_more_filter();
  433.     /* have to exit via readline or tty modes stay messed up */
  434.     for (cp = cmd_line; c = *cp++; )
  435.         rl_stuff_char(c);
  436.     rl_stuff_char('\n');
  437.     input_avail = 1;
  438. }
  439.  
  440. /*
  441.  * Define and display all the buttons.
  442.  */
  443. static void
  444. addbutton(parent, name, function, closure)
  445.     Widget parent;
  446.     char *name;
  447.     void (*function) ();
  448.     caddr_t closure;
  449. {
  450.     static XtCallbackRec Callback[] = {
  451.         {NULL, (caddr_t) NULL},
  452.         {NULL, (caddr_t) NULL},
  453.     };
  454.     static Arg commandArgs[] = {
  455.         {XtNlabel, (XtArgVal) NULL},
  456.         {XtNcallback, (XtArgVal) Callback},
  457.     };
  458.     Widget w;
  459.     char wname[128];
  460.     register char *cp;
  461.  
  462.     strcpy(wname, name);
  463.     while ((cp = index(wname, '*')) || (cp = index(wname, '.')))
  464.         *cp -= 0x10;
  465.  
  466.     if (w = XtNameToWidget(parent, wname))
  467.         XtDestroyWidget(w);
  468.  
  469.     Callback[0].callback = (XtCallbackProc) function;
  470.     Callback[0].closure = (caddr_t) closure;
  471.     commandArgs[0].value = (XtArgVal) name;
  472.     XtCreateManagedWidget(wname, commandWidgetClass, parent,
  473.                   commandArgs, XtNumber(commandArgs));
  474. }
  475.  
  476. /*
  477.  * Create the button windows and store them in `buttons'.
  478.  */
  479. static void
  480. create_buttons(parent)
  481.     Widget parent;
  482. {
  483.     addbutton(parent, "quit", do_command, "quit");
  484. }
  485.  
  486. static void
  487. button_command(arg)
  488.     char *arg;
  489. {
  490.     char *label;
  491.     unsigned int len;
  492.     
  493.     if (! arg)
  494.         error_no_arg("button label and command");
  495.  
  496.     for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
  497.         ;
  498.     if (len == 0)
  499.         error_no_arg("button label and command");
  500.     arg[len] = 0;
  501.  
  502.     /* make a copy of button label & command for toolkit to use */
  503.     label = malloc(len + 1);
  504.     strcpy(label, arg);
  505.  
  506.     /* find the end of the label */
  507.     if (*label == '"') {
  508.         if ((arg = index(++label, '"')) == 0) {
  509.             printf("button label missing closing quote\n");
  510.             return;
  511.         }
  512.         *arg++ = 0;
  513.     } else if (arg = index(label, ' '))
  514.         *arg++ = 0;
  515.     else
  516.         arg = label;
  517.  
  518.     while (*arg && isspace(*arg))
  519.         ++arg;
  520.     
  521.     addbutton(button_box_widget, label, do_command, arg);
  522. }
  523.  
  524. static void
  525. button_delete_command(arg)
  526.     char *arg;
  527. {
  528.     unsigned int len;
  529.     Widget w;
  530.     register char *cp;
  531.  
  532.     if (! arg)
  533.         error_no_arg("button name");
  534.  
  535.     for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
  536.         ;
  537.     if (len == 0)
  538.         error_no_arg("button name");
  539.     arg[len] = 0;
  540.  
  541.     /* find the end of the label */
  542.     if (*arg == '"') {
  543.         if ((cp = index(++arg, '"')) == 0) {
  544.             printf("button label missing closing quote\n");
  545.             return;
  546.         }
  547.         *cp++ = 0;
  548.     }
  549.     while ((cp = index(arg, '*')) || (cp = index(arg, '.')))
  550.         *cp -= 0x10;
  551.  
  552.     if (w = XtNameToWidget(button_box_widget, arg))
  553.         XtDestroyWidget(w);
  554. }
  555.  
  556. /*
  557.  * Create a "label window" that just displays the string LABEL.
  558.  */
  559. static Widget
  560. create_label(name, label)
  561.     char *name, *label;
  562. {
  563.     Arg args[1];
  564.     Widget w;
  565.  
  566.     XtSetArg(args[0], XtNlabel, label);
  567.     w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget,
  568.                   args, XtNumber(args));
  569.     return (w);
  570. }
  571.  
  572. /*
  573.  * Create a subwindow of PARENT that displays and scrolls the contents of
  574.  * file FILENAME.
  575.  */
  576. static Widget
  577. create_text_widget(parent, filename)
  578.     Widget parent;
  579.     char *filename;
  580. {
  581.     static Arg arg[] = {
  582.         {XtNstring, NULL},
  583.         {XtNtype, XawAsciiFile},
  584.         {XtNcursor, None},
  585.     };
  586.     Widget text_widget;
  587.  
  588.     arg[0].value = (XtArgVal)filename;
  589.     text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass,
  590.                          parent, arg, XtNumber(arg));
  591.     return (text_widget);
  592. }
  593.  
  594. /*
  595.  * Entry point to create the widgets representing our display.
  596.  */
  597. void
  598. xgdb_create_window()
  599. {
  600.     /* initialize toolkit, setup defaults */
  601. #ifdef notyet
  602.     main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0, 
  603.                       argcptr, argv, NULL, NULL, 0);
  604. #else
  605.     char *dummy_argv[] = { "xgdb", 0 };
  606.     int dummy_argc = 1;
  607.     main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0, 
  608.                       &dummy_argc, dummy_argv, NULL, NULL, 0);
  609. #endif
  610.     display = XtDisplay(main_widget);
  611.     containing_widget = XtCreateManagedWidget("frame", panedWidgetClass,
  612.                               main_widget, NULL, 0);
  613.  
  614.     sprintf(version_label, "XGDB %s", version);
  615.     button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass,
  616.                           containing_widget, NULL, 0);
  617.     create_buttons(button_box_widget);
  618.     source_name_widget = create_label("srcLabel", "No source file yet.");
  619.     source_text_widget = create_text_widget(containing_widget, "/dev/null");
  620.  
  621.     XtRealizeWidget(main_widget);
  622.     XFlush(display);
  623. }
  624.  
  625. /*
  626.  * If we use an X window, the readline input loop is told to call
  627.  * this function before reading a character from stdin.
  628.  */
  629. /*ARGSUSED*/
  630. static void
  631. xgdb_window_hook()
  632. {
  633.     register int inmask = 1 << fileno(stdin);
  634.     register int xmask = 1 << ConnectionNumber(display);
  635.     register int nfds, pend;
  636.     int input_rfds;
  637.     XEvent ev;
  638.  
  639.     /*
  640.      * Display our current idea of the `interesting' source file then
  641.      * loop, dispatching window events until data is available on
  642.      * stdin. Then return so the input data can be processed.
  643.      */
  644.     input_avail = 0;
  645.     xgdb_display_source();
  646.  
  647.     input_rfds = 0;
  648.     while (input_avail == 0 && (input_rfds & inmask) == 0) {
  649.         pend = XPending(display);
  650.         if (!pend) {
  651.             input_rfds = inmask | xmask;
  652.             nfds = select(32, &input_rfds, 0, 0,
  653.                       (struct timeval *)0);
  654.             if (nfds == -1 && errno == EINTR)
  655.                 continue;
  656.         }
  657.         if (pend || (input_rfds & xmask)) {
  658.             XNextEvent(display, &ev);
  659.             XtDispatchEvent(&ev);
  660.         }
  661.     }
  662. }
  663.  
  664. void
  665. _initialize_xgdb()
  666. {
  667.     extern void (*window_hook) ();
  668.     extern int inhibit_windows;
  669.     extern struct cmd_list_element *deletelist;
  670.  
  671.     if (inhibit_windows)
  672.         return;
  673.  
  674.     if (! displayname) {
  675.         displayname = getenv("DISPLAY");
  676.         if (! displayname) {
  677.             fprintf(stderr, "xgdb: no display name\n");
  678.             inhibit_windows = 1;
  679.             return;
  680.         }
  681.     }
  682.     xgdb_create_window();
  683.     window_hook = xgdb_window_hook;
  684.     add_com("button", class_support, button_command,
  685. "Add command button to xgdb window.  First argument is button\n\
  686. label, second is command associated with button.  Command can\n\
  687. include printf-like escapes:\n\
  688.    %s for current selection,\n\
  689.    %S for first 'word' of current selection,\n\
  690.    %e for current selection or expression at insertion pt,\n\
  691.    %E for current selection or expression at insertion pt,\n\
  692.    %l for current line number,\n\
  693.    %L for line program stopped at,\n\
  694.    %f for current file name,\n\
  695.    %b for current breakpoint number.");
  696.     add_cmd("button", class_support, button_delete_command,
  697. "Delete a button from the xgdb window.\n\
  698. Argument is name of button to be deleted.",
  699.         &deletelist);
  700. }
  701.