/***************************************************************************** * * xdbx - X Window System interface to the dbx debugger * * Copyright 1989 The University of Texas at Austin * Copyright 1990 Microelectronics and Computer Technology Corporation * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of The University of Texas * and Microelectronics and Computer Technology Corporation (MCC) not be * used in advertising or publicity pertaining to distribution of * the software without specific, written prior permission. The * University of Texas and MCC makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Po Cheung * Created: March 10, 1989 * ***************************************************************************** * * xxgdb - X Window System interface to the gdb debugger * * Copyright 1990 Thomson Consumer Electronics, Inc. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of Thomson Consumer * Electronics (TCE) not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. TCE makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT * SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * * Adaptation to GDB: Pierre Willard * XXGDB Created: December, 1990 * *****************************************************************************/ /* source.c * * Create the source window and handle display of file. * * source_init(): Initialization routine. * Update(): Action proc to update source window on scrollbar action. * NotifyResize(): Action proc to update source window on resize. * CreateSourceWindow(): Create the source window. * BuildLinePos(): Build an array of starting text position of each line. * LookUpFileTable():Check out source file info from a file table. * SaveDisplayedFileInfo(): records displayed file info into file table. * DisplayFile(): Display a file on the source window * LoadFile(): Search for a file and open it for display. */ #include #include #include #include "global.h" #ifdef SYSV #ifdef sco # include #endif #endif /* SYSV */ #ifdef GDB #include #endif #define MAXDIRS 256 /* max number of dirs in dirList */ char CurrentFile[MAXNAME]; /* current contents of file variable */ Widget sourceForm, /* parent of sourceWindow */ sourceWindow; /* text window for source file */ FileRec *displayedFile; /* pointer to table entry of currently displayed file */ static FileRec **fileTable; /* table of file records */ static int fileTableSize; /* size of file table */ static char *dirList[MAXDIRS]; /* list of dirs for searching files */ void source_init() { dirList[0] = NULL; } /* * Update topline, bottomline, arrow sign, updown sign, stop signs, and * line label. */ /* ARGSUSED */ void Update(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XawTextPosition pos; int topline; FileRec *file; if (displayedFile) { file = displayedFile; pos = XawTextTopPosition(sourceWindow); file->topPosition = pos; topline = TextPositionToLine(pos); /* Update the symbols only if the text scrolls */ if (file->topline != topline) { file->topline = topline; file->bottomline = MIN (file->topline + file->lines - 1, file->lastline); /* 03/26/91 mod 7 GWC Fixed a bug where the special margin symbols (arrows, stop signs, etc.) did not scroll when one moved the text with keyboard commands such as Ctrln. To do this the Update action procedure should be called after text widget actions such as next-line. Unfortunately Update needed to be enhanced a bit not to always warp the cursor to the top of the window. You can now call Update with a parameter "warp" to warp the cursor to the top of the screen; the default is not to warp. */ if (*num_params == 1 && strcmp(params[0], "warp") == 0) { XawTextSetInsertionPoint(sourceWindow, file->linepos[file->topline]); } UpdateLineLabel(file->topline); UpdateStops(file); UpdateArrow(file); UpdateUpdown(file); UpdateBomb(file); } else {/* Update caret position only */ pos = XawTextGetInsertionPoint(sourceWindow); UpdateLineLabel(TextPositionToLine(pos)); } } } /* * Update bottomline, arrow sign, updown sign and stop signs on resize. * Invoked by ConfigureNotify event. */ /* ARGSUSED */ static void NotifyResize(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XawTextPosition pos; TextWidget ctx = (TextWidget) sourceWindow; FileRec *file; if (file = displayedFile) { file->lines = ctx->text.lt.lines; pos = XawTextTopPosition(sourceWindow); file->topline = TextPositionToLine(pos); file->bottomline = MIN (file->topline + file->lines - 1, file->lastline); UpdateStops(file); UpdateArrow(file); UpdateUpdown(file); UpdateBomb(file); } } /* Update the position of the caret */ /* ARGSUSED */ #ifdef notdef void UpdateLine(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XawTextPosition pos; int line; pos = XawTextGetInsertionPoint(w); line = TextPositionToLine(pos); UpdateLineLabel(line); } #endif /* My select-start routine that cancels the effect of automatic scrolling * near the bottom of an Athena text widget window. */ /* ARGSUSED */ void SelectStart(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XawTextPosition topPosition; /* remember the top display position before automatic scrolling */ /* displayedFile->topPosition = XawTextTopPosition(w); */ topPosition = XawTextTopPosition(w); XtCallActionProc(w, "select-start", event, params, num_params); /* reset to remembered position if top position changed */ /* if (XawTextTopPosition(w) != displayedFile->topPosition) TextSetTopPosition(w, displayedFile->topPosition); */ if (XawTextTopPosition(w) != topPosition) TextSetTopPosition(w, topPosition); } /* My select-end routine to store the text selection into both the PRIMARY * selection and cut buffer 0. */ /* ARGSUSED */ void SelectEnd(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XawTextPosition begin, end, start; Widget textsrc; XawTextBlock buffer; char s[10000]; int nchars; XawTextGetSelectionPos(w, &begin, &end); XawTextSetSelection(w, begin, end); if (begin == end) return; textsrc = XawTextGetSource(w); strcpy(s, ""); for (start=begin, nchars=end-begin; nchars > 0; start=begin+buffer.length, nchars-=buffer.length) { XawTextSourceRead(textsrc, start, &buffer, nchars); strncat(s, buffer.ptr, buffer.length); } XStoreBytes(display, s, strlen(s)); } /* This is my own select word routine to replace the standard action * procedure provided by the Text widget. * It selects a word delimited by DELIMITERS, not whitespace. */ /* ARGSUSED */ void SelectWord(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XawTextPosition pos, left, right, start; XawTextBlock buffer; Widget textsrc; char s[LINESIZ]; char *p, *ls, *rs; int nchars; pos = XawTextGetInsertionPoint(w); textsrc = XawTextGetSource(w); XawTextSourceRead(textsrc, pos, &buffer, 1); if (buffer.length == 0 || (buffer.length == 1 && strchr(app_resources.delimiters, (int)*(buffer.ptr)) != NULL)) { XStoreBytes(display, NULL, 0); return; } left = XawTextSourceScan(textsrc, pos+1, XawstWhiteSpace, XawsdLeft, 1, FALSE); right = XawTextSourceScan(textsrc, left, XawstWhiteSpace, XawsdRight, 1, FALSE); strcpy(s, ""); for (start=left, nchars=right-left; nchars > 0; start=left+buffer.length, nchars-=buffer.length) { XawTextSourceRead(textsrc, start, &buffer, nchars); strncat(s, buffer.ptr, buffer.length); } if (!strcmp(s, "")) return; p = s+pos-left; ls = (char *) strtok(s, app_resources.delimiters); rs = (char *) strtok(NULL, app_resources.delimiters); if (!ls) return; while (rs<=p && rs!=NULL) { ls = rs; rs = (char *) strtok(NULL, app_resources.delimiters); } left = left + ls - s; right = left + strlen(ls) - 1; XawTextUnsetSelection(w); XStoreBytes(display, ls, strlen(ls)); XawTextSetSelection(w, left, right+1); } /* Print the value of the expression in cut buffer 0. */ /* ARGSUSED */ void PrintSelection(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char command[LINESIZ]; char *string; int nbytes; string = XFetchBytes(display, &nbytes); if (nbytes == 0) { UpdateMessageWindow(PRINT_HELP, NULL); bell(0); return; } sprintf(command, "print %s\n", string); send_command(command); AppendDialogText(command); } /* * On top of a form widget, we have a text widget with scrollbar, label * widgets for the stop sign, arrow sign, and updown signs. */ void CreateSourceWindow(parent) Widget parent; { TextWidget ctx; Arg args[MAXARGS]; Cardinal n; static XtActionsRec sbar_actions[] = { {"NotifyResize", NotifyResize}, {"Update", Update}, {NULL, NULL} }; static String sbarTranslations = "\ : NotifyResize() \n\ : StartScroll(Continuous) MoveThumb() NotifyThumb() \ Update() \n\ : MoveThumb() NotifyThumb() Update() \n\ : NotifyScroll(Proportional) EndScroll() Update() \n\ "; n = 0; XtSetArg(args[n], XtNdefaultDistance, 0); n++; sourceForm = XtCreateManagedWidget("sourceForm", formWidgetClass, parent, args, n); n = 0; XtSetArg(args[n], XtNborderWidth, 0); n++; XtSetArg(args[n], XtNtype, (XtArgVal)XawAsciiFile); n++; XtSetArg(args[n], XtNstring, (XtArgVal)"/dev/null"); n++; XtSetArg(args[n], XtNscrollVertical, (XtArgVal) XawtextScrollAlways);n++; sourceWindow = XtCreateManagedWidget("sourceWindow", asciiTextWidgetClass, sourceForm, args, n); ctx = (TextWidget) sourceWindow; if (ctx->text.vbar) XtOverrideTranslations(ctx->text.vbar, XtParseTranslationTable(sbarTranslations)); XtAppAddActions(app_context, sbar_actions, XtNumber(sbar_actions)); } /* * Build the array which gives the starting text position of each line. * > Estimate the number of lines in the file and allocate memory buffer. * > Starting position of line #1 is 0, and is stored in linepos[1]. * > Search for '\n' till end of buffer. */ static void BuildLinePos(file) FileRec *file; { char *p; int line, nlines; nlines = MAX(1, file->filesize/CHARS_PER_LINE); file->linepos = (XawTextPosition *) XtMalloc ((nlines+2) * sizeof(XawTextPosition)); p = file->buf; line = 0; file->linepos[line++] = 0; file->linepos[line++] = 0; while (*p) { if (*p++ == '\n') { if (line == nlines) { /* buffer full, need more memory */ file->linepos = (XawTextPosition *) XtRealloc (file->linepos, (nlines + ADD_LINES) * sizeof(XawTextPosition)); nlines += ADD_LINES; } file->linepos[line++] = p - file->buf; } } file->lastline = line - 2; file->linepos = (XawTextPosition *) XtRealloc /* shrink to min size */ (file->linepos, line * sizeof(XawTextPosition)); } /* * Look up the file table for an entry with "filename" * If not found, create an entry and initialize proper fields, * else, return pointer to entry found. */ static LookUpFileTable(pathname, filename, file) char *pathname, *filename; FileRec **file; { struct stat fileinfo; int fd; int i, j, n; for (i=0; fileTable && fileTable[i] && ipathname, pathname) == NULL) { /* file found */ if (stat(pathname, &fileinfo) == -1) { UpdateMessageWindow("Error: cannot stat file %s", pathname); *file = fileTable[i]; return 0; } if (fileinfo.st_mtime > fileTable[i]->mtime) { /* file modified */ XtFree((char *)fileTable[i]->buf); XtFree((char *)fileTable[i]->linepos); XtFree((char *)fileTable[i]); displayedFile = NULL; break; } else if (displayedFile && /* same as displayed file */ strcmp(pathname, displayedFile->pathname) == 0) { *file = NULL; return 0; } else { *file = fileTable[i]; return 0; } } } /* Record file into file table */ if (i == fileTableSize) { /* file table full, enlarge it */ fileTableSize += ADD_SIZE; fileTable = (FileRec **) XtRealloc (fileTable, fileTableSize * sizeof(FileRec *)); for (j=i; jfilesize = fileinfo.st_size + 1; fileTable[i]->mtime = fileinfo.st_mtime; fileTable[i]->buf = XtMalloc((int)fileTable[i]->filesize); if ((n = read(fd, fileTable[i]->buf, (int) fileTable[i]->filesize)) == -1) { UpdateMessageWindow("Error: cannot read file %s", pathname); XtFree(fileTable[i]->buf); XtFree(fileTable[i]); fileTable[i] = NULL; close(fd); return -1; } fileTable[i]->buf[n] = '\0'; fileTable[i]->pathname = XtNewString(pathname); fileTable[i]->filename = XtNewString(filename); fileTable[i]->currentline = 1; fileTable[i]->topline = 1; fileTable[i]->bottomline = 0; fileTable[i]->topPosition = 0; BuildLinePos(fileTable[i]); close(fd); *file = fileTable[i]; return 0; } /* * Remember file position and current line before closing. */ static void SaveDisplayedFileInfo() { XawTextPosition pos; if (displayedFile) { displayedFile->topPosition = XawTextTopPosition(sourceWindow); pos = XawTextGetInsertionPoint(sourceWindow); displayedFile->currentline = TextPositionToLine(pos); } } /* DisplayFile() displays the file onto the source window. It * uses topPosition to remember where it was last opened. But it * must recalculate bottomline because the window size might be * different. */ static void DisplayFile(file) FileRec *file; { Arg args[MAXARGS]; Cardinal n; TextWidget ctx = (TextWidget) sourceWindow; n = 0; XtSetArg(args[n], XtNdisplayPosition, (XtArgVal)file->topPosition); n++; XtSetArg(args[n], XtNstring, (XtArgVal) file->pathname); n++; XtSetArg(args[n], XtNeditType, (XtArgVal) XawtextRead); n++; XtSetValues(sourceWindow, args, n); file->lines = ctx->text.lt.lines; file->bottomline = MIN (file->topline + file->lines - 1, file->lastline); } /* Given a filename starting with a tilde (`~'), it expands ~[user] to * the home directory of that user, or to the login home directory if user * is not specified. */ static char *expand(filename) char *filename; { struct passwd *pwd; char *string, *name, newfile[MAXNAME]; string = XtNewString(filename+1); if (*string == '\0' || *string == '/') name = (char *) getlogin(); else name = (char *) strtok(string, "/"); if (name == NULL) return filename; pwd = (struct passwd *) getpwnam(name); if (pwd && pwd->pw_dir) { sprintf(newfile, "%s%s", pwd->pw_dir, filename+strlen(name)+1); return XtNewString(newfile); } else return filename; } /* Create a list of directories for searching source files. * It reads the list of directories specified by the user, adding * the current directory into the list if it is not already there. * * With fix from Dave Gagne (daveg@fs1.ee.ubc.ca) 7/30/90 */ void MakeDirList(output) char *output; { char *s, list[BUFSIZ], command[LINESIZ]; int i, use_cwd; for (i=0; dirList[i]; i++) /* remove old list */ XtFree(dirList[i]); i = 0; use_cwd = TRUE; if (output) { /* create list */ #ifdef GDB /* GDB uses ':' as separator character */ s = (char *) strtok(output, ": \n"); #else s = (char *) strtok(output, " \n"); #endif /* GDB */ while (s) { dirList[i] = XtNewString(s); if (dirList[i][0] == '~') /* expand '~' */ dirList[i] = expand(dirList[i]); if (LASTCH(dirList[i]) == '/') /* remove last '/' */ LASTCH(dirList[i]) = '\0'; if (strcmp(dirList[i], ".") == NULL) /* watch for "." */ use_cwd = FALSE; ++i; #ifdef GDB /* GDB uses ':' as separator character */ s = (char *) strtok(NULL, ": \n"); #else s = (char *) strtok(NULL, " \n"); #endif /* GDB */ } dirList[i] = NULL; } if (use_cwd) { /* include current dir */ dirList[i++] = XtNewString("."); dirList[i] = NULL; } #if defined(NeXT) && defined(GDB) /* for NeXT computer, send 'directory' command for each directory */ for (i=0; dirList[i]; i++) { sprintf(command, "directory %s\n", dirList[i]); query_gdb (command, PARSE_OFF | ECHO_OFF | FILTER_OFF); } #else /* not NeXT */ strcpy(list, ""); /* tell dbx our new list */ for (i=0; dirList[i]; i++) { strcat(list, dirList[i]); strcat(list, " "); } #ifdef GDB sprintf(command, "directory %s\n", list); query_gdb (command, PARSE_OFF | ECHO_OFF | FILTER_OFF); #else sprintf(command, "use %s\n", list); Parse = False; query_dbx(command); #endif /* GDB */ #endif /* not NeXT */ } #ifdef GDB /* (PW)11SEP91 : for gdb 4.0 */ extern char cdir[]; /* compilation directory */ #endif /* Returns the full pathname of a given file. * It searches for the file from a list of directories. */ char *GetPathname(filename) char *filename; { char pathname[LINESIZ]; int i; if (filename == NULL || strcmp(filename, "") == NULL) return NULL; for (i=0; dirList[i]; i++) { if (*filename == '/' && access(filename, R_OK) == -1) { /* this handles the exceptional case of sun4 dbx output */ strcpy(filename, &filename[1]); } if (*filename == '/' || *filename == '~') strcpy(pathname, filename); else if (strcmp(dirList[i], ".") == NULL) sprintf(pathname, "%s/%s", cwd, filename); #ifdef GDB /* (PW)(SH)11SEP91 : for gdb 4.0 */ else if (strcmp(dirList[i], "$cwd") == NULL) sprintf(pathname, "%s/%s", cwd, filename); else if (strcmp(dirList[i], "$cdir") == NULL) sprintf(pathname, "%s/%s", cdir, filename); #endif /* GDB */ else if (*dirList[i] == '/' || *dirList[i] == '~') sprintf(pathname, "%s/%s", dirList[i], filename); else sprintf(pathname, "%s/%s/%s", cwd, dirList[i], filename); #ifdef GDB /* (PW)11APR91 : replace all "/./" in pathname by "/". because sometimes gdb could produce "./filename", eg, when a C file is included in another C file. */ { char *s; char *s2; while (s = strstr ( pathname, "/./" )) { s++; /* replace "/./" by "/" */ s2 = s + sizeof("/./") - sizeof("/"); while ( *(s++) = *(s2++) ); } } #endif /* GDB */ if (access(pathname, R_OK) == 0) return XtNewString(pathname); } UpdateMessageWindow("File not found: %s", filename); return NULL; } /* * Given a file name, LoadFile attempts to open it and displays it onto * the source window: * 1. get the full pathname of the file * 2. LookUpFileTable() returns a pointer to the file's entry if it's * already in the table; else, creates an entry and return a pointer. * 3. save the current displayedFile info * 4. display the file * 5. update the file label and the various signs on the source window. * LoadFile returns 0 upon successful completion, -1 otherwise. */ int LoadFile(filename) char *filename; { FileRec *file; char *pathname; pathname = GetPathname(filename); if (pathname == NULL) { return -1; } if (LookUpFileTable(pathname, filename, &file) != -1) { if (file) { /* load new file */ SaveDisplayedFileInfo(); DisplayFile(file); UpdateFileLabel(pathname); XawTextUnsetSelection(sourceWindow); XawTextSetInsertionPoint(sourceWindow, file->linepos[file->currentline]); UpdateLineLabel(file->currentline); UpdateStops(file); UpdateArrow(file); UpdateUpdown(file); UpdateBomb(file); displayedFile = file; } return 0; } else { /* LookUpFileTable() fails */ return -1; } } int LoadCurrentFile() { #ifdef GDB query_gdb ("info line\n", PARSE_ON | ECHO_OFF | FILTER_OFF); #else query_dbx("file\n"); #endif /* GDB */ return LoadFile(CurrentFile); }