home *** CD-ROM | disk | FTP | other *** search
- /*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
- *
- * static char rcsid[] = "$Header: xgdb.c,v 1.9 90/12/16 16:01:05 van Exp $";
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)xgdb.c 6.3 (Berkeley) 5/8/91";
- #endif /* not lint */
-
- /*
- * Interface from GDB to X windows. Copyright (C) 1987 Free Software
- * Foundation, Inc.
- *
- * GDB is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY. No author or distributor accepts responsibility to anyone for
- * the consequences of using it or for whether it serves any particular
- * purpose or works at all, unless he says so in writing. Refer to the GDB
- * General Public License for full details.
- *
- * Everyone is granted permission to copy, modify and redistribute GDB, but only
- * under the conditions described in the GDB General Public License. A copy
- * of this license is supposed to have been given to you along with GDB so
- * you can know your rights and responsibilities. It should be in a file
- * named COPYING. Among other things, the copyright notice and this notice
- * must be preserved on all copies.
- *
- * In other words, go ahead and share GDB, but don't try to stop anyone else
- * from sharing it farther. Help stamp out software hoarding!
- */
-
- /*
- * Original version was contributed by Derek Beatty, 30 June 87.
- * This version is essentially a re-write of the original by Van
- * Jacobson (van@helios.ee.lbl.gov), Nov, 90.
- */
-
- #include "defs.h"
- #include "param.h"
- #include "symtab.h"
- #include "frame.h"
-
- extern int stop_breakpoint;
-
- #include <X11/IntrinsicP.h>
- #include <X11/StringDefs.h>
- #include <X11/Xaw/AsciiSink.h>
- #include <X11/Xaw/AsciiText.h>
- #include <X11/Xaw/Box.h>
- #include <X11/Xaw/Command.h>
- #include <X11/Xaw/Label.h>
- #include <X11/Xaw/Paned.h>
- #include <X11/Xaw/Text.h>
-
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/file.h>
- #include <sys/errno.h>
-
- extern int errno;
- extern char *getenv();
- extern char *malloc();
- extern void bcopy();
- extern int select();
-
- extern int get_filename_and_charpos();
- extern int source_line_charpos();
- extern int source_charpos_line();
- extern void execute_command();
- extern void error_no_arg();
- extern void add_com();
-
- /* The X display where the window appears. */
-
- static char *displayname;
- static Display *display;
-
- static XtAppContext app_context;
-
- /* Windows manipulated by this package. */
-
- static Widget main_widget;
- static Widget containing_widget;
- static Widget source_name_widget;
- static Widget source_text_widget;
- static Widget button_box_widget;
-
- /* Source text display. */
-
- static struct frame_info *last_fi;
- static CORE_ADDR last_pc;
- static struct symtab *last_cur_symtab;
- static int last_cur_line;
-
- static int source_window_line;
- static char *source_window_file;
- static struct symtab *source_window_symtab;
-
- static char version_label[64];
- extern char *version;
-
- /* Forward declarations */
-
- static Widget create_text_widget();
-
- static int
- safe_strcmp(a, b)
- register char *a, *b;
- {
- register int i;
-
- if (a == b)
- return (0);
- if (!a && b)
- return (1);
- if (a && !b)
- return (-1);
- return (strcmp(a, b));
- }
-
-
- /* Display an appropriate piece of source code in the source window. */
-
- void
- xgdb_display_source()
- {
- char *filename = NULL;
- struct symtab_and_line get_selected_frame_sal();
- struct symtab_and_line sal;
- struct frame_info *fi;
-
- /* Do nothing if called before we are initialized */
-
- if (!containing_widget)
- return;
-
- /*
- * Figure out what to display (the appropriate hooks to tell
- * us don't exist so we guess): If there's a current frame
- * and it or its pc changed from the last time we were here,
- * display appropriate source line. Otherwise if the current
- * source symtab or line is different, display that line.
- * Otherwise nothing changed so leave the display alone.
- */
- fi = get_frame_info(selected_frame);
- if (fi && (fi != last_fi || fi->pc != last_pc)) {
- last_fi = fi;
- last_pc = fi->pc;
- sal = find_pc_line(fi->pc, fi->next_frame);
- if (sal.symtab == NULL) { /* XXX */
- sal.symtab = current_source_symtab;
- sal.line = current_source_line;
- }
- current_source_symtab = sal.symtab;
- current_source_line = sal.line;
- } else if (current_source_symtab != last_cur_symtab ||
- current_source_line != last_cur_line) {
- sal.symtab = last_cur_symtab = current_source_symtab;
- sal.line = last_cur_line = current_source_line;
- } else
- return;
- /*
- * Do a path search and get the exact filename of this source file.
- * Also scan it and find its source lines if not already done.
- */
- if (sal.symtab && filename == NULL) {
- if (get_filename_and_charpos(sal.symtab, sal.line, &filename))
- /* line numbers may have changed - force highlight */
- source_window_line = -1;
- }
-
- /*
- * If the source window is wrong, destroy it and make a new one.
- */
- if (safe_strcmp(filename, source_window_file)) {
- Arg args[1];
- Widget src = XawTextGetSource(source_text_widget);
-
- if (filename) {
- XtSetArg(args[0], XtNstring, filename);
- XtSetValues(src, args, XtNumber(args));
- args[0].name = XtNlabel;
- XtSetValues(source_name_widget, args, XtNumber(args));
- } else {
- XtSetArg(args[0], XtNstring, "/dev/null");
- XtSetValues(src, args, XtNumber(args));
- XtSetArg(args[0], XtNlabel, "");
- XtSetValues(source_name_widget, args, XtNumber(args));
- }
- if (source_window_file)
- free(source_window_file);
- source_window_file = filename;
- source_window_line = sal.line + 1; /* force highlight */
- }
- if (sal.symtab && source_window_line != sal.line) {
- /*
- * Update display and cursor positions as necessary.
- * Cursor should be placed on line sal.line.
- */
- XawTextPosition l, r;
-
- source_window_symtab = sal.symtab;
- source_window_line = sal.line;
- l = source_line_charpos(source_window_symtab, sal.line);
- r = source_line_charpos(source_window_symtab, sal.line + 1);
- if (r < l)
- r = l + 1;
- XawTextSetSelection(source_text_widget, l, r);
- XawTextScrollToLine(source_text_widget, l, 10, 3);
- XawTextSetInsertionPoint(source_text_widget, l);
- }
- }
-
-
- /*
- * Handlers for buttons.
- */
-
- static int
- current_lineno()
- {
- XawTextPosition start, finish;
-
- XawTextGetSelectionPos(source_text_widget, &start, &finish);
- if (start >= finish)
- start = XawTextGetInsertionPoint(source_text_widget);
-
- return (source_charpos_line(source_window_symtab, start));
- }
-
- static char *
- append_selection(cp)
- char *cp;
- {
- int len;
- XawTextPosition l, r;
-
- XawTextGetSelectionPos(source_text_widget, &l, &r);
- if ((len = r - l) > 0) {
- Widget src = XawTextGetSource(source_text_widget);
-
- while (len > 0) {
- XawTextBlock tb;
-
- XawTextSourceRead(src, l, &tb, len);
- bcopy(tb.ptr, cp, tb.length);
- cp += tb.length;
- len -= tb.length;
- }
- if (cp[-1] == 0)
- --cp;
- }
- return (cp);
- }
-
- static char *
- append_selection_word(cp)
- register char *cp;
- {
- register int len;
- XawTextPosition l, r;
- XawTextBlock tb;
- register char c;
- register Widget src = XawTextGetSource(source_text_widget);
-
- XawTextGetSelectionPos(source_text_widget, &l, &r);
- if ((len = r - l) <= 0) {
- l = XawTextGetInsertionPoint(source_text_widget);
- len = 128; /* XXX */
-
- /* might have clicked in middle of word -- back up to start */
- for ( ; l > 0; --l) {
- XawTextSourceRead(src, l - 1, &tb, 1);
- c = tb.ptr[0];
- if (! isalnum(c) && c != '_' && c != '$')
- break;
- }
- }
- while (len > 0) {
- char *sp;
- int i;
-
- XawTextSourceRead(src, l, &tb, len);
- for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
- c = *sp++;
- if (!isalnum(c) && c != '_' && c != '$')
- return (cp);
- *cp++ = c;
- }
- len -= tb.length;
- }
- return (cp);
- }
-
- static char *
- append_selection_expr(cp)
- char *cp;
- {
- int len;
- XawTextPosition l, r;
- Widget src = XawTextGetSource(source_text_widget);
- XawTextBlock tb;
- char *sp;
- char c;
-
- XawTextGetSelectionPos(source_text_widget, &l, &r);
- if (r > l)
- return (append_selection(cp));
-
- l = XawTextGetInsertionPoint(source_text_widget);
-
- /* might have clicked in middle of word -- back up to start */
- for ( ; l > 0; --l) {
- XawTextSourceRead(src, l - 1, &tb, 1);
- c = tb.ptr[0];
- if (! isalnum(c) && c != '_' && c != '$')
- break;
- }
-
- len = 128; /* XXX */
- while (len > 0) {
- int i;
- char pstack[64];
- int pcnt = 0;
-
- XawTextSourceRead(src, l, &tb, len);
- for (sp = tb.ptr, i = tb.length; --i >= 0; ) {
- switch (c = *sp++) {
- case '\n':
- case ';':
- return (cp);
- case '=':
- if (cp[-1] != '=')
- return (cp - 1);
- if (len == 128)
- return (cp);
- break;
- case ',':
- if (pcnt <= 0)
- return (cp);
- break;
- case '(':
- pstack[pcnt] = ')';
- if (++pcnt >= sizeof(pstack))
- return (cp);
- break;
- case '[':
- pstack[pcnt] = ']';
- if (++pcnt >= sizeof(pstack))
- return (cp);
- break;
- case ')':
- case ']':
- if (--pcnt < 0 || pstack[pcnt] != c)
- return (cp);
- break;
- }
- *cp++ = c;
- }
- len -= tb.length;
- }
- return (cp);
- }
-
- static int input_avail; /* XXX kluge: do_command sets this when command
- * data from button is avaialble to force top level
- * to break out of its loop. */
- /*
- * Handle a button by running the command COMMAND.
- */
- static void
- do_command(w, command, call_data)
- Widget w;
- register char *command;
- caddr_t call_data;
- {
- char cmd_line[256];
- char buf[256];
- register char *out = cmd_line;
- char *cp;
- register char c;
- extern char *finish_command_input();
-
- while (c = *command++) {
- if (c == '%') {
- switch (*command++) {
- case 's': /* current selection */
- out = append_selection(out);
- break;
- case 'S': /* 1st selected "word" at curor */
- out = append_selection_word(out);
- break;
- case 'e': /* echo cmd before executing */
- break;
- case 'E': /* 1st selected expression at curor */
- out = append_selection_expr(out);
- break;
-
- case 'l': /* current line number */
- (void) sprintf(buf, "%d", current_lineno());
- for (cp = buf; c = *cp++; *out++ = c)
- ;
- break;
- case 'L': /* line we're stopped at */
- (void) sprintf(buf, "%d", source_window_line);
- for (cp = buf; c = *cp++; *out++ = c)
- ;
- break;
- case 'f': /* current file name */
- for (cp = source_window_symtab->filename;
- c = *cp++; *out++ = c)
- ;
- break;
- case 'b': /* break # we're stopped at */
- if (stop_breakpoint <= 0)
- /* if no breakpoint, don't do cmd */
- return;
-
- (void) sprintf(buf, "%d", stop_breakpoint);
- for (cp = buf; c = *cp++; *out++ = c)
- ;
- break;
- }
- } else
- *out++ = c;
- }
- *out = 0;
- reinitialize_more_filter();
- /* have to exit via readline or tty modes stay messed up */
- for (cp = cmd_line; c = *cp++; )
- rl_stuff_char(c);
- rl_stuff_char('\n');
- input_avail = 1;
- }
-
- /*
- * Define and display all the buttons.
- */
- static void
- addbutton(parent, name, function, closure)
- Widget parent;
- char *name;
- void (*function) ();
- caddr_t closure;
- {
- static XtCallbackRec Callback[] = {
- {NULL, (caddr_t) NULL},
- {NULL, (caddr_t) NULL},
- };
- static Arg commandArgs[] = {
- {XtNlabel, (XtArgVal) NULL},
- {XtNcallback, (XtArgVal) Callback},
- };
- Widget w;
- char wname[128];
- register char *cp;
-
- strcpy(wname, name);
- while ((cp = index(wname, '*')) || (cp = index(wname, '.')))
- *cp -= 0x10;
-
- if (w = XtNameToWidget(parent, wname))
- XtDestroyWidget(w);
-
- Callback[0].callback = (XtCallbackProc) function;
- Callback[0].closure = (caddr_t) closure;
- commandArgs[0].value = (XtArgVal) name;
- XtCreateManagedWidget(wname, commandWidgetClass, parent,
- commandArgs, XtNumber(commandArgs));
- }
-
- /*
- * Create the button windows and store them in `buttons'.
- */
- static void
- create_buttons(parent)
- Widget parent;
- {
- addbutton(parent, "quit", do_command, "quit");
- }
-
- static void
- button_command(arg)
- char *arg;
- {
- char *label;
- unsigned int len;
-
- if (! arg)
- error_no_arg("button label and command");
-
- for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
- ;
- if (len == 0)
- error_no_arg("button label and command");
- arg[len] = 0;
-
- /* make a copy of button label & command for toolkit to use */
- label = malloc(len + 1);
- strcpy(label, arg);
-
- /* find the end of the label */
- if (*label == '"') {
- if ((arg = index(++label, '"')) == 0) {
- printf("button label missing closing quote\n");
- return;
- }
- *arg++ = 0;
- } else if (arg = index(label, ' '))
- *arg++ = 0;
- else
- arg = label;
-
- while (*arg && isspace(*arg))
- ++arg;
-
- addbutton(button_box_widget, label, do_command, arg);
- }
-
- static void
- button_delete_command(arg)
- char *arg;
- {
- unsigned int len;
- Widget w;
- register char *cp;
-
- if (! arg)
- error_no_arg("button name");
-
- for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len)
- ;
- if (len == 0)
- error_no_arg("button name");
- arg[len] = 0;
-
- /* find the end of the label */
- if (*arg == '"') {
- if ((cp = index(++arg, '"')) == 0) {
- printf("button label missing closing quote\n");
- return;
- }
- *cp++ = 0;
- }
- while ((cp = index(arg, '*')) || (cp = index(arg, '.')))
- *cp -= 0x10;
-
- if (w = XtNameToWidget(button_box_widget, arg))
- XtDestroyWidget(w);
- }
-
- /*
- * Create a "label window" that just displays the string LABEL.
- */
- static Widget
- create_label(name, label)
- char *name, *label;
- {
- Arg args[1];
- Widget w;
-
- XtSetArg(args[0], XtNlabel, label);
- w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget,
- args, XtNumber(args));
- return (w);
- }
-
- /*
- * Create a subwindow of PARENT that displays and scrolls the contents of
- * file FILENAME.
- */
- static Widget
- create_text_widget(parent, filename)
- Widget parent;
- char *filename;
- {
- static Arg arg[] = {
- {XtNstring, NULL},
- {XtNtype, XawAsciiFile},
- {XtNcursor, None},
- };
- Widget text_widget;
-
- arg[0].value = (XtArgVal)filename;
- text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass,
- parent, arg, XtNumber(arg));
- return (text_widget);
- }
-
- /*
- * Entry point to create the widgets representing our display.
- */
- void
- xgdb_create_window()
- {
- /* initialize toolkit, setup defaults */
- #ifdef notyet
- main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
- argcptr, argv, NULL, NULL, 0);
- #else
- char *dummy_argv[] = { "xgdb", 0 };
- int dummy_argc = 1;
- main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0,
- &dummy_argc, dummy_argv, NULL, NULL, 0);
- #endif
- display = XtDisplay(main_widget);
- containing_widget = XtCreateManagedWidget("frame", panedWidgetClass,
- main_widget, NULL, 0);
-
- sprintf(version_label, "XGDB %s", version);
- button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass,
- containing_widget, NULL, 0);
- create_buttons(button_box_widget);
- source_name_widget = create_label("srcLabel", "No source file yet.");
- source_text_widget = create_text_widget(containing_widget, "/dev/null");
-
- XtRealizeWidget(main_widget);
- XFlush(display);
- }
-
- /*
- * If we use an X window, the readline input loop is told to call
- * this function before reading a character from stdin.
- */
- /*ARGSUSED*/
- static void
- xgdb_window_hook()
- {
- register int inmask = 1 << fileno(stdin);
- register int xmask = 1 << ConnectionNumber(display);
- register int nfds, pend;
- int input_rfds;
- XEvent ev;
-
- /*
- * Display our current idea of the `interesting' source file then
- * loop, dispatching window events until data is available on
- * stdin. Then return so the input data can be processed.
- */
- input_avail = 0;
- xgdb_display_source();
-
- input_rfds = 0;
- while (input_avail == 0 && (input_rfds & inmask) == 0) {
- pend = XPending(display);
- if (!pend) {
- input_rfds = inmask | xmask;
- nfds = select(32, &input_rfds, 0, 0,
- (struct timeval *)0);
- if (nfds == -1 && errno == EINTR)
- continue;
- }
- if (pend || (input_rfds & xmask)) {
- XNextEvent(display, &ev);
- XtDispatchEvent(&ev);
- }
- }
- }
-
- void
- _initialize_xgdb()
- {
- extern void (*window_hook) ();
- extern int inhibit_windows;
- extern struct cmd_list_element *deletelist;
-
- if (inhibit_windows)
- return;
-
- if (! displayname) {
- displayname = getenv("DISPLAY");
- if (! displayname) {
- fprintf(stderr, "xgdb: no display name\n");
- inhibit_windows = 1;
- return;
- }
- }
- xgdb_create_window();
- window_hook = xgdb_window_hook;
- add_com("button", class_support, button_command,
- "Add command button to xgdb window. First argument is button\n\
- label, second is command associated with button. Command can\n\
- include printf-like escapes:\n\
- %s for current selection,\n\
- %S for first 'word' of current selection,\n\
- %e for current selection or expression at insertion pt,\n\
- %E for current selection or expression at insertion pt,\n\
- %l for current line number,\n\
- %L for line program stopped at,\n\
- %f for current file name,\n\
- %b for current breakpoint number.");
- add_cmd("button", class_support, button_delete_command,
- "Delete a button from the xgdb window.\n\
- Argument is name of button to be deleted.",
- &deletelist);
- }
-