argv@island.uu.net (Dan Heller) (04/06/89)
Submitted-by: Ps Cheung <po@volta.ece.utexas.edu> Posting-number: Volume 3, Issue 65 Archive-name: xdbx.patch/part01 #!/bin/sh echo x - CHANGES sed 's/^X//' > CHANGES <<'+END+OF+CHANGES' X XThis is patch #1 to vanilla xdbx posted to comp.sources.x. There are three Xparts. The first part consists of two files, CHANGES and filemenu.c, and Xsome initial patches. The other files contain patches only. X X1. Changes X X This is patch #1, upgrading xdbx version 1.0 to 1.1. Included in this X patch is a context diff file, plus two new files: CHANGES and filemenu.c. X The following changes have been made to this directory since version 1.0. X X o Xdbx now works under SunOS 4.0. To compile the program, edit the X Imakefile to include -DSUNOS4_0 flag. X o Terminal interrupt (^C) to dbx is fixed. X o Xdbx now handles the 'use' command. It keeps track of a list of X directories for searching source files. This is especially useful X for debugging programs with source files residing in multiple X directories. X o The file menu is extended into a directory browser. The user can X traverse up and down the directory tree, display source files, X and debug executable files (Sun dbx). X o For Berkeley dbx, the 'status' button is replaced by the 'return' X button. X o Lots of small changes to the source code. X X2. Bugs X X o Xdbx exercises some bugs in the Athena list widget. Creating a X file menu could cause segmentation violation. X X3. Acknowledgements X X I must thank Guy Harris for correcting my misunderstanding of ptys X and getting xdbx to work in SunOS 4.0. Many thanks go to Duane Voth X for his diffs, and many of his ideas in improving the user interface X of the file menu, and allowing user customization of translation tables. X D'arc Angel came up with the idea of introducing the DEBUGGER environment X variable. I would also like to thank Joseph Rahmeh, Mike Schoenfelder, X Gregory Melancon, and many others for their suggestions and bug fixes. +END+OF+CHANGES echo '-rw-rw-r-- 1 argv 1849 Apr 5 23:53 CHANGES (as sent)' chmod u=rw,g=rw,o=r CHANGES ls -l CHANGES echo x - filemenu.c sed 's/^X//' > filemenu.c <<'+END+OF+filemenu.c' X/****************************************************************************** X * X * xdbx - X Window System interface to dbx X * X * Copyright 1989 The University of Texas at Austin X * X * Author: Po Cheung X * Date: March 20, 1989 X * X * Permission to use, copy, modify, and distribute this software and X * its documentation for any purpose and without fee is hereby granted, X * provided that the above copyright notice appear in all copies and that X * both that copyright notice and this permission notice appear in X * supporting documentation. The University of Texas at Austin makes no X * representations about the suitability of this software for any purpose. X * It is provided "as is" without express or implied warranty. X * X ******************************************************************************/ X X X/* Filemenu.c X * X * This file contains routines for manipulation of a file menu. X * The file menu is popped up by the 'file' command button. It allows X * a user to go up and down the directory tree, to select text files X * to display, and to select executable files to debug. X * X * When xdbx is first started up, SetUpFileMenu() is called to construct X * the file menu. Each time the user changes the current directory, X * UpdateFileMenu() is called to destroy the old popupshell and call X * SetUpFileMenu() to build a new menu. X * X * Duane Voth contributed to the layout of the file menu, plus some X * other code and ideas. X */ X X#include <ctype.h> X#include <X11/Xos.h> X#include <sys/stat.h> X#ifdef SUNOS4_0 X#include <dirent.h> X#else X#include <sys/dir.h> X#endif X#include "global.h" X Xstatic char **filelist; /* list of file names in fileMenu */ Xstatic int nfiles = 0; /* number of files in filelist */ Xstatic Widget popupshell, /* parent of popup */ X popup, /* vpane widget containing file menu */ X fileMenu, /* list widget as file menu */ X fileMenuLabel; /* label widget as file menu label */ Xstatic char cwd[MAXPATHLEN]; /* current working directory of dbx */ X X X/* Returns the current working directory. X * For Berkeley dbx, the current working directory info is stored in X * the static variable, cwd. X * For Sun dbx, the current working directory can be obtained from dbx. X */ Xchar *dbxpwd() X{ X#ifdef BSD X if (strcmp(cwd, "") == NULL) X getwd(cwd); X#else X if (dbxfp == NULL) X getwd(cwd); X else X strcpy(cwd, (char *) strtok(QueryDbx("pwd\n", FALSE), "\n")); X#endif X return cwd; X} X X X/* Change working directory to 'dir'. X * For Berkeley dbx, modify static global variable, cwd, to keep track of X * current working directory. X * For Sun dbx, change working directory of dbx. X */ Xstatic void changeDir(dir) Xchar *dir; X{ X char command[LINESIZ]; X int i; X X#ifdef BSD X if (strcmp(dir, "./") == NULL) X return; X if (dir[0] == '/' || dir[0] == '~') X strcpy(cwd, dir); X if (strcmp(dir, "../") == NULL) { X for (i=strlen(cwd); cwd[i] != '/' && i > 0; i--); X cwd[i] = '\0'; X if (strcmp(cwd, "") == NULL) X strcpy(cwd, "/"); X } X else { X sprintf(cwd, "%s/%s", cwd, dir); X LASTCH(cwd) = '\0'; X } X#else X sprintf(command, "cd %s\n", dir); X QueryDbx(command, FALSE); X#endif X} X X X/* Determines if a directory entry should appear in the file menu. X * The files included in the menu are : X * .. (parent directory) X * directories X * text files X * executable files X */ Xstatic int InList(entry) XDirectory *entry; X{ X char buffer[16], pathname[LINESIZ]; X struct stat statbuf; X int i, n; X FILE *fp; X X if (strcmp(entry->d_name, ".") == NULL || /* ignore current directory */ X LASTCH(entry->d_name) == '~') /* ignore Emacs backup files */ X return False; X if (entry->d_name[0] == '.' && entry->d_name[1] != '.') X return False; /* ignore hidden files */ X if (strcmp(cwd, "")) /* give full path name */ X sprintf(pathname, "%s/%s", cwd, entry->d_name); X else X strcpy(pathname, entry->d_name); X if (stat(pathname, &statbuf) == -1) X return False; X if (statbuf.st_mode & S_IFDIR) { /* is directory */ X strcat(entry->d_name, "/"); X ++(entry->d_namlen); X return True; X } X if (statbuf.st_mode & S_IEXEC) { /* is executable */ X strcat(entry->d_name, "*"); X ++(entry->d_namlen); X return True; X } X if ((fp = fopen(pathname, "r")) == NULL) X return False; X if (n = fread(buffer, sizeof(char), sizeof(buffer), fp)) { X fclose(fp); X for (i=0; i<n && (isprint(buffer[i]) || isspace(buffer[i])); i++); X return ((i-sizeof(buffer)) ? False : True); /* only ascii text */ X } X fclose(fp); X return False; X} X X X/* Scans the working directory for files selected by InList(), sorted X * alphabetically, and stored in an array of pointers to directory X * entries called namelist. X * The names of the selected files are stored in filelist. X */ Xstatic void ScanDir(dir) Xchar *dir; X{ X extern alphasort(); X Directory **namelist; X int i, j; X X nfiles = scandir(dir, &namelist, InList, alphasort); X if (nfiles == -1) { X UpdateMessageWindow("scandir: cannot open %s", dir); X return; X } X if (filelist) { X for (i=0; filelist[i]; i++) X XtFree(filelist[i]); X XtFree(filelist); X } X filelist = (char **) XtMalloc((nfiles+1) * sizeof(char *)); X i = 0; X for (j=0; j<nfiles; j++) { X filelist[i++] = XtNewString(namelist[j]->d_name); X free(namelist[j]); X } X filelist[i++] = NULL; X free(namelist); X return; X} X X X/* Callback for the fileMenu list widget. X * > if the selected item is a directory, display contents of that directory. X * > (Sun dbx only) if the selected item is an executable file, issue the X * debug command. X * > if the selected item is a readable file, display the file. X */ X/* ARGSUSED */ Xstatic void DisplayMenuFile(w, client_data, call_data) X Widget w; X Widget client_data; X XtListReturnStruct *call_data; X{ X void UpdateFileMenu(), File(); X char string[LINESIZ], *filename; X X XtPopdown(client_data); X filename = call_data->string; X if (filename == NULL) return; X if (LASTCH(filename) == '/') { X changeDir(filename); X UpdateFileMenu(); /* create new menu */ X File(); /* pop it up */ X } X else if (LASTCH(filename) == '*') { X UpdateMessageWindow(""); X#ifndef BSD X strcpy(string, filename); X LASTCH(string) = '\0'; X sprintf(Command, "debug %s\n", string); X AppendDialogText(Command); X writeDbx(Command); X#endif X } X else { X UpdateMessageWindow(""); X LoadFile(filename); X sprintf(Command, "file %s\n", filename); X AppendDialogText(Command); X writeDbx(Command); X } X} X X X/* Callback to popdown the file menu X */ Xstatic void CancelFileMenu(w, client_data, call_data) X Widget w; X caddr_t client_data; X caddr_t call_data; X{ X XtPopdown(client_data); X UpdateMessageWindow(""); X} X X X/* Creates a popup shell with its child being a vpane widget containing X * a file menu label, a file menu containing file names returned from X * ScanDir(), and a cancel command button. X * When an item in the list is selected, DisplayMenuFile is called. X */ Xvoid SetUpFileMenu(dir) Xchar *dir; X{ X Widget cancelButton; X Arg args[MAXARGS]; X Cardinal n; X char menulabel[LINESIZ]; X int ncolumns; X X static String translations = "\ X <Btn1Down>,<Btn1Up>: Set() Notify() Unset()"; X X n = 0; X popupshell = XtCreatePopupShell("popupshell", overrideShellWidgetClass, X toplevel, args, n); X X popup = XtCreateManagedWidget("popup", vPanedWidgetClass, popupshell, X args, n); X ScanDir(dir); X X n = 0; X sprintf(menulabel, " %s ", dir); X XtSetArg(args[n], XtNlabel, (XtArgVal) menulabel); n++; X XtSetArg(args[n], XtNjustify, (XtArgVal) XtJustifyCenter); n++; X fileMenuLabel = XtCreateManagedWidget("fileMenuLabel", labelWidgetClass, X popup, args, n); X X n = 0; X ncolumns = nfiles/app_resources.filesPerColumn + 1; X ncolumns = MIN(ncolumns, MAXCOLUMNS); X XtSetArg(args[n], XtNlist, filelist); n++; X XtSetArg(args[n], XtNverticalList, True); n++; X XtSetArg(args[n], XtNcolumnSpacing, app_resources.columnSpacing); n++; X XtSetArg(args[n], XtNdefaultColumns, (XtArgVal) ncolumns); n++; X XtSetArg(args[n], XtNtranslations, XtParseTranslationTable(translations)); X n++; X fileMenu = XtCreateManagedWidget("fileMenu", listWidgetClass, X popup, args, n); X XtAddCallback(fileMenu, XtNcallback, DisplayMenuFile, popupshell); X X n = 0; X cancelButton = XtCreateManagedWidget("CANCEL", commandWidgetClass, X popup, args, n); X XtAddCallback(cancelButton, XtNcallback, CancelFileMenu, popupshell); X X DisableWindowResize(fileMenuLabel); X DisableWindowResize(cancelButton); X} X X X/* This routine is called when there is a a change in current directory. X * It destroys the existing popup shell and creates a new file menu based X * on the new current directory. A new directory list is created. X */ Xvoid UpdateFileMenu() X{ X XtDestroyWidget(popupshell); X SetUpFileMenu(dbxpwd()); X MakeDirList(QueryDbx("use\n", FALSE)); X} X X X/* File command button callback. X */ X/* ARGSUSED */ Xvoid File(w, client_data, call_data) X Widget w; X caddr_t client_data; X caddr_t call_data; X{ X Arg args[MAXARGS]; X Cardinal n; X Position x, y, x_offset; X Dimension fileMenu_width, fileMenuLabel_width, border_width, X width, dialog_width; X X /* Place the file menu relative to the top right corner of dialogWindow */ X X n = 0; X XtSetArg(args[n], XtNwidth, &fileMenu_width); n++; X XtSetArg(args[n], XtNborderWidth, &border_width); n++; X XtGetValues(fileMenu, args, n); X X n = 0; X XtSetArg(args[n], XtNwidth, &fileMenuLabel_width); n++; X XtGetValues(fileMenuLabel, args, n); X X n = 0; X XtSetArg(args[n], XtNwidth, &dialog_width); n++; X XtGetValues(dialogWindow, args, n); X X width = MAX(fileMenu_width, fileMenuLabel_width); X x_offset = (Position) (dialog_width - width - border_width); X X XtTranslateCoords(dialogWindow, x_offset, -1, &x, &y); X x = MAX(0, x); X y = MAX(0, y); X XtMoveWidget(popupshell, x, y); X XtPopup(popupshell, XtGrabNonexclusive); X UpdateMessageWindow("Select a file or directory"); X} +END+OF+filemenu.c echo '-rw-rw-r-- 1 argv 10219 Apr 5 23:54 filemenu.c (as sent)' chmod u=rw,g=rw,o=r filemenu.c ls -l filemenu.c echo x - xdbx.patch.1 sed 's/^X//' > xdbx.patch.1 <<'+END+OF+xdbx.patch.1' X*** xdbx1.0/source.c Fri Mar 24 01:18:41 1989 X--- xdbx1.1/source.c Sun Apr 2 17:48:23 1989 X*************** X*** 18,31 **** X ******************************************************************************/ X X X! #include "global.h" X #include <X11/Xos.h> X #include <sys/stat.h> X X! static FileRec fileTable[MAXFILES]; /* table of file records */ X FileRec *displayedFile; /* pointer to table entry of currently X displayed file */ X Boolean Echo = True; /* to intercept dbx output */ X X X void source_init() X--- 18,48 ---- X ******************************************************************************/ X X X! /* This file contains routines related to the source window. They include: X! * source_init : initialization routine. X! * Update : action proc to update source window on scrollbar action. X! * UpdateLine : action proc to update the current line. X! * NotifyResize : action proc to update source window on resize. X! * CreateSourceWindow : X! * BuildLinePos : build an array of starting text position of each line. X! * LookUpFileTable : check out source file info from a file table. X! * QueryFile : ask dbx for the name of current source file. X! * SaveDisplayedFileInfo : records displayed file info into file table. X! * DisplayFile : display a file on the source window X! * LoadFile : search for a file and open it for display. X! */ X! X #include <X11/Xos.h> X #include <sys/stat.h> X+ #include <pwd.h> X+ #include "global.h" X X! static FileRec **fileTable; /* table of file records */ X! static int fileTableSize; /* size of file table */ X FileRec *displayedFile; /* pointer to table entry of currently X displayed file */ X Boolean Echo = True; /* to intercept dbx output */ X+ static char *dirList[MAXDIRS]; /* list of dirs for searching files */ X X X void source_init() X*************** X*** 32,45 **** X { X int i; X X! for (i=0; i<MAXFILES; i++) { X! fileTable[i].filename = XtNewString(""); X } X } X X /* X * Update topline, bottomline, arrow sign, updown sign, stop signs, and X! * line label. Invoked by scrollbar action. X */ X /* ARGSUSED */ X static XtActionProc Update(w, event, params, num_params) X--- 49,65 ---- X { X int i; X X! fileTableSize = FILETABLESIZE; X! fileTable = (FileRec **) XtMalloc (fileTableSize * sizeof(FileRec *)); X! for (i=0; i<fileTableSize; i++) { X! fileTable[i] = NULL; X } X+ dirList[0] = NULL; X } X X /* X * Update topline, bottomline, arrow sign, updown sign, stop signs, and X! * line label. Invoked by scrolling action. X */ X /* ARGSUSED */ X static XtActionProc Update(w, event, params, num_params) X*************** X*** 70,76 **** X } X } X X! /* Invoked by left mouse button down, update the line label. X */ X /* ARGSUSED */ X static XtActionProc UpdateLine(w, event, params, num_params) X--- 90,97 ---- X } X } X X! X! /* Update the line label, invoked by left mouse button down. X */ X /* ARGSUSED */ X static XtActionProc UpdateLine(w, event, params, num_params) X*************** X*** 88,96 **** X } X X /* X! * Update bottomline, arrow sign, updown sign and stop signs X * Invoked by ConfigureNotify event. X- * Note that topline never changes with resize, only bottomline gets changed. X */ X /* ARGSUSED */ X static XtActionProc NotifyResize(w, event, params, num_params) X--- 109,116 ---- X } X X /* X! * Update bottomline, arrow sign, updown sign and stop signs on resize. X * Invoked by ConfigureNotify event. X */ X /* ARGSUSED */ X static XtActionProc NotifyResize(w, event, params, num_params) X*************** X*** 99,109 **** X--- 119,132 ---- X String *params; X Cardinal *num_params; X { X+ XtTextPosition pos; X TextWidget ctx = (TextWidget) sourceWindow; X FileRec *file; X X if (file = displayedFile) { X file->lines = ctx->text.lt.lines; X+ pos = XtTextTopPosition(sourceWindow); X+ file->topline = TextPositionToLine(pos); X file->bottomline = MIN (file->topline + file->lines - 1, X file->lastline); X UpdateStops(file); X*************** X*** 112,121 **** X } X } X X- X /* X! * On top of a form widget, we have a text widget with scrollbar, a label X! * widget for the arrow sign, one for the updown sign and some for stop signs. X */ X void CreateSourceWindow(parent) X Widget parent; X--- 135,143 ---- X } X } X X /* X! * On top of a form widget, we have a text widget with scrollbar, label X! * widgets for the stop sign, arrow sign, and updown signs. X */ X void CreateSourceWindow(parent) X Widget parent; X*************** X*** 126,138 **** X X static XtActionsRec actionTable[] = { X {"NotifyResize", (XtActionProc) NotifyResize}, X! {"MySelectWord", (XtActionProc) MySelectWord}, X! {"UpdateLine", (XtActionProc) UpdateLine}, X {"Update", (XtActionProc) Update}, X {NULL, NULL} X }; X X! static String translations = "\ X <Btn1Down>: select-start() ClearCutBuffer0() UpdateLine()\n\ X <Btn1Up>(2): MySelectWord()"; X X--- 148,160 ---- X X static XtActionsRec actionTable[] = { X {"NotifyResize", (XtActionProc) NotifyResize}, X! {"MySelectWord", (XtActionProc) MySelectWord}, X! {"UpdateLine", (XtActionProc) UpdateLine}, X {"Update", (XtActionProc) Update}, X {NULL, NULL} X }; X X! static String translations = "#replace\ X <Btn1Down>: select-start() ClearCutBuffer0() UpdateLine()\n\ X <Btn1Up>(2): MySelectWord()"; X X*************** X*** 150,258 **** X parent, args, n); X X n = 0; X XtSetArg(args[n], XtNheight, app_resources.sourceHeight); n++; X XtSetArg(args[n], XtNleftMargin, app_resources.leftMargin); n++; X- XtSetArg(args[n], XtNborderWidth, 0); n++; X XtSetArg(args[n], XtNtextOptions, (XtArgVal) scrollVertical); n++; X- X sourceWindow = XtCreateManagedWidget("sourceWindow", asciiStringWidgetClass, X sourceWidget, args, n); X ctx = (TextWidget) sourceWindow; X- XtOverrideTranslations(sourceWindow, X- XtParseTranslationTable(translations)); X XtOverrideTranslations(ctx->text.sbar, X XtParseTranslationTable(sbarTranslations)); X XtAddActions(actionTable, XtNumber(actionTable)); X } X X X /* X! * Build the array which gives the starting text position of each line X! * look for CR, get the position, add 1, which becomes the starting X! * position of next line. X */ X! static void BuildLinePos (file) X FileRec *file; X { X! char *s; X Line line, nlines; X X! nlines = file->filesize/CHARS_PER_LINE; X! file->linepos = (XtTextPosition *)XtMalloc(nlines * sizeof(XtTextPosition)); X! s = file->buf; X line = 0; X file->linepos[line++] = 0; X file->linepos[line++] = 0; X! while (*s) { X! if (*s++ == '\n') { X! if (line == nlines) { X file->linepos = (XtTextPosition *) XtRealloc (file->linepos, X (nlines + ADD_LINES) * sizeof(XtTextPosition)); X nlines += ADD_LINES; X } X! file->linepos[line++] = s - file->buf; X } X } X file->lastline = line - 2; X! file->linepos = (XtTextPosition *) XtRealloc X (file->linepos, line * sizeof(XtTextPosition)); X } X X X- static long GetFileSize(fd) X- int fd; X- { X- struct stat fileinfo; X- X- if (fstat(fd, &fileinfo)) X- return -1; X- return (fileinfo.st_size + 1); X- } X- X /* X * Look up the file table for an entry with "filename" X * If not found, create an entry and initialize proper fields, X * else, return pointer to entry found. X */ X! static FileRec *LookUpFileTable(filename, fd) X! char *filename; X! int fd; X { X! int i, c1, c2; X! char message[LINESIZ]; X X! for (i=0; fileTable[i].filename && X! (c1 = strcmp(fileTable[i].filename, "")) && X! (c2 = strcmp(fileTable[i].filename, filename)) && X! i < MAXFILES; i++); X X! if (i >= MAXFILES) { /* too many files */ X! i = 0; X! c1 = 0; X! XtFree(fileTable[i].buf); X } X! if (c1 == 0) { /* file does not exist in table */ X! if ((fileTable[i].filesize = GetFileSize(fd)) == -1) X! return NULL ; X! fileTable[i].buf = XtMalloc(fileTable[i].filesize); X! if (read(fd, fileTable[i].buf, fileTable[i].filesize) == -1) { X! sprintf(message, "Can't read %s: read error\n", filename); X! UpdateMessageWindow(message); X! XtFree(fileTable[i].buf); X! return NULL; X! } X! fileTable[i].filename = XtNewString(filename); X! strcpy(fileTable[i].funcname, ""); X! fileTable[i].currentline = 1; X! fileTable[i].topline = 1; X! fileTable[i].bottomline = 0; X! fileTable[i].topPosition = 0; X! BuildLinePos(&fileTable[i]); X! return &fileTable[i]; X } X! if (c2 == 0) { /* file exists in table */ X! return &fileTable[i]; X } X } X X X--- 172,294 ---- X parent, args, n); X X n = 0; X+ XtSetArg(args[n], XtNtranslations, X+ XtParseTranslationTable(translations)); n++; X+ XtSetArg(args[n], XtNborderWidth, 0); n++; X XtSetArg(args[n], XtNheight, app_resources.sourceHeight); n++; X XtSetArg(args[n], XtNleftMargin, app_resources.leftMargin); n++; X XtSetArg(args[n], XtNtextOptions, (XtArgVal) scrollVertical); n++; X sourceWindow = XtCreateManagedWidget("sourceWindow", asciiStringWidgetClass, X sourceWidget, args, n); X+ if (app_resources.sourceTranslTable) { X+ n = 0; X+ XtSetArg(args[n], XtNtranslations, app_resources.sourceTranslTable); X+ n++; X+ XtSetValues(sourceWindow, args, n); X+ } X+ X ctx = (TextWidget) sourceWindow; X XtOverrideTranslations(ctx->text.sbar, X XtParseTranslationTable(sbarTranslations)); X+ if (app_resources.sbarTranslTable) X+ XtOverrideTranslations(ctx->text.sbar, app_resources.sbarTranslTable); X+ X XtAddActions(actionTable, XtNumber(actionTable)); X } X X X /* X! * Build the array which gives the starting text position of each line. X! * > Estimate the number of lines in the file and allocate memory buffer. X! * > Starting position of line #1 is 0, and is stored in linepos[1]. X! * > Search for \n till end of buffer. X */ X! static void BuildLinePos(file) X FileRec *file; X { X! char *p; X Line line, nlines; X X! nlines = MAX(1, file->filesize/CHARS_PER_LINE); X! file->linepos = (XtTextPosition *) X! XtMalloc ((nlines+2) * sizeof(XtTextPosition)); X! p = file->buf; X line = 0; X file->linepos[line++] = 0; X file->linepos[line++] = 0; X! while (*p) { X! if (*p++ == '\n') { X! if (line == nlines) { /* buffer full, need more memory */ X file->linepos = (XtTextPosition *) XtRealloc (file->linepos, X (nlines + ADD_LINES) * sizeof(XtTextPosition)); X nlines += ADD_LINES; X } X! file->linepos[line++] = p - file->buf; X } X } X file->lastline = line - 2; X! file->linepos = (XtTextPosition *) XtRealloc /* shrink to min size */ X (file->linepos, line * sizeof(XtTextPosition)); X } X X X /* X * Look up the file table for an entry with "filename" X * If not found, create an entry and initialize proper fields, X * else, return pointer to entry found. X */ X! static FileRec *LookUpFileTable(pathname, filename) X! char *pathname, *filename; X { X! struct stat fileinfo; X! int fd; X! int i, j, n; X X! for (i=0; fileTable[i] && i<fileTableSize; i++) { X! if (strcmp(fileTable[i]->pathname, pathname) == NULL) X! return fileTable[i]; /* file found */ X! } X X! /* file not found, add into file table */ X! X! if (i == fileTableSize) { /* file table full, enlarge it */ X! fileTableSize += ADD_FILES; X! fileTable = (FileRec **) X! XtRealloc (fileTable, fileTableSize * sizeof(FileRec *)); X! for (j=i; j<fileTableSize; j++) X! fileTable[j] = NULL; X } X! if ((fd = open(pathname, O_RDONLY)) == -1) { X! UpdateMessageWindow("Error: cannot open file %s", pathname); X! return NULL; X } X! if (fstat(fd, &fileinfo) == -1) { X! UpdateMessageWindow("Error: cannot fstat file %s", pathname); X! close(fd); X! return NULL; X } X+ fileTable[i] = (FileRec *) XtMalloc (sizeof(FileRec)); X+ fileTable[i]->filesize = fileinfo.st_size + 1; X+ fileTable[i]->buf = XtMalloc(fileTable[i]->filesize); X+ if ((n = read(fd, fileTable[i]->buf, fileTable[i]->filesize)) == -1) { X+ UpdateMessageWindow("Error: cannot read file %s", pathname); X+ XtFree(fileTable[i]->buf); X+ XtFree(fileTable[i]); X+ fileTable[i] = NULL; X+ close(fd); X+ return NULL; X+ } X+ fileTable[i]->buf[n] = '\0'; X+ fileTable[i]->pathname = XtNewString(pathname); X+ fileTable[i]->filename = XtNewString(filename); X+ strcpy(fileTable[i]->funcname, ""); X+ fileTable[i]->currentline = 1; X+ fileTable[i]->topline = 1; X+ fileTable[i]->bottomline = 0; X+ fileTable[i]->topPosition = 0; X+ BuildLinePos(fileTable[i]); X+ close(fd); X+ return fileTable[i]; X } X X X*************** X*** 281,287 **** X X /* X * Remember file position before closing. X! * Clear field funcname for proper operation of parse() & UpdateFuncLabel() X */ X static void SaveDisplayedFileInfo() X { X--- 317,323 ---- X X /* X * Remember file position before closing. X! * Clear field funcname for parse(). X */ X static void SaveDisplayedFileInfo() X { X*************** X*** 296,301 **** X--- 332,342 ---- X } X X X+ /* DisplayFile() displays the file onto the source window. It X+ * uses topPosition to remember where it was last opened. But it X+ * must recalculate bottomline because the window size might be X+ * different. X+ */ X static void DisplayFile(file) X FileRec *file; X { X*************** X*** 316,383 **** X } X X X! static void FullPath(filename, path) X! char *filename, *path; X { X! char *dir; X X! dir = dbxpwd(); X! if (dir) { X! strcpy(path, dir); X! strcat(path, "/"); X! strcat(path, filename); X! XtFree(dir); X } X! else X! strcpy(path, filename); X } X X /* X * Given a file name, LoadFile attempts to open it and displays it onto X! * the source window. X! * LookUpFileTable checks if the file is already in the file table. X! * if it exists, a pointer to the file structure is retured; X! * otherwise, an entry is created and its info initialized; X! * returns NULL only if file table full. X! * SaveDisplayedFileInfo saves important information about the file X! * back in the file table; they include: topPosition, breakpoints. X! * DisplayFile displays the file onto the source window. It X! * uses topPosition to remember where it was last opened. But it X! * must recalculate bottomline because the window size might be X! * different. X */ X! FileRec *LoadFile(filename) X char *filename; X { X FileRec *file; X! int fd; X! char message[LINESIZ]; X! char pathname[LINESIZ]; X X! if (filename == NULL) X! return displayedFile; X! if (displayedFile && strcmp(filename, displayedFile->filename) == 0) X! return displayedFile; X! FullPath(filename, pathname); X! if ((fd = open(pathname, O_RDONLY)) == -1) { X! sprintf(message, "open: file not found : %s", pathname); X! UpdateMessageWindow(message); X! return displayedFile; X } X! else if (file = LookUpFileTable(filename, fd)) { X SaveDisplayedFileInfo(); X DisplayFile(file); X! UpdateFileLabel(file->filename); X XtTextSetInsertionPoint(sourceWindow, file->linepos[file->currentline]); X UpdateLineLabel(file->currentline); X UpdateStops(file); X UpdateArrow(file); X UpdateUpdown(file); X! close(fd); X! return file; X } X! else { X! close(fd); X! return displayedFile; X } X } X--- 357,499 ---- X } X X X! /* Given a filename starting with a tilde (`~'), it expands ~[user] to X! * the home directory of that user, or to the login home directory if user X! * is not specified. X! */ X! static char *expand(filename) X! char *filename; X { X! struct passwd *pwd; X! char *string, *name, newfile[MAXNAME]; X X! string = XtNewString(filename+1); X! if (*string == '\0' || *string == '/') X! name = (char *) getlogin(); X! else X! name = (char *) strtok(string, "/"); X! if (name == NULL) X! return filename; X! pwd = (struct passwd *) getpwnam(name); X! if (pwd && pwd->pw_dir) { X! sprintf(newfile, "%s%s", pwd->pw_dir, filename+strlen(name)+1); X! return XtNewString(newfile); X } X! else X! return filename; X } X X+ X+ /* Create a list of directories for searching source files. X+ * It reads the list of directories specified by the user, adding X+ * the current directory into the list if it is not already there. X+ */ X+ void MakeDirList(output) X+ char *output; X+ { X+ char *s, list[BUFSIZ], command[LINESIZ]; X+ int i, use_cwd; X+ struct passwd *pwd; X+ X+ for (i=0; dirList[i]; i++) /* remove old list */ X+ XtFree(dirList[i]); X+ i = 0; X+ if (output == NULL || strcmp(output, "") == NULL) { /* add "." */ X+ use_cwd = TRUE; X+ } X+ else { /* create list */ X+ dirList[i++] = (char *) strtok(output, " \n"); X+ while (s = (char *) strtok(NULL, " \n")) { X+ dirList[i++] = XtNewString(s); X+ } X+ dirList[i++] = NULL; X+ use_cwd = TRUE; X+ for (i=0; dirList[i]; i++) { X+ if (dirList[i][0] == '~') /* expand '~' */ X+ dirList[i] = expand(dirList[i]); X+ if (LASTCH(dirList[i]) == '/') /* remove last '/' */ X+ LASTCH(dirList[i]) = '\0'; X+ if (strcmp(dirList[i], ".") == NULL) /* watch for "." */ X+ use_cwd = FALSE; X+ } X+ } X+ if (use_cwd) { /* include current dir */ X+ dirList[i++] = XtNewString("."); X+ dirList[i] = NULL; X+ } X+ strcpy(list, ""); /* tell dbx our new list */ X+ for (i=0; dirList[i]; i++) { X+ strcat(list, dirList[i]); X+ strcat(list, " "); X+ } X+ sprintf(command, "use %s\n", list); X+ QueryDbx(command, FALSE); X+ } X+ X+ X+ /* Returns the full pathname of a given file. X+ * It searches for the file from a list of directories. X+ */ X+ char *GetPathname(filename) X+ char *filename; X+ { X+ char pathname[LINESIZ]; X+ int i; X+ X+ if (filename == NULL || strcmp(filename, "") == NULL) X+ return NULL; X+ for (i=0; dirList[i]; i++) { X+ if (*filename == '/' || *filename == '~') X+ strcpy(pathname, filename); X+ else if (*dirList[i] == '/' || *dirList[i] == '~') X+ sprintf(pathname, "%s/%s", dirList[i], filename); X+ else if (strcmp(dirList[i], ".") == NULL) X+ sprintf(pathname, "%s/%s", dbxpwd(), filename); X+ else X+ sprintf(pathname, "%s/%s/%s", dbxpwd(), dirList[i], filename); X+ if (access(pathname, R_OK) == 0) X+ return XtNewString(pathname); X+ } X+ UpdateMessageWindow("File not found: %s", filename); X+ return NULL; X+ } X+ X /* X * Given a file name, LoadFile attempts to open it and displays it onto X! * the source window: X! * 1. get the full pathname of the file X! * 2. LookUpFileTable() returns a pointer to the file's entry if it's X! * already in the table; else, creates an entry and return a pointer. X! * 3. save the current displayedFile info X! * 4. display the file X! * 5. update the file label and the various signs on the source window. X! * LoadFile returns 0 upon successful completion, -1 otherwise. X */ X! int LoadFile(filename) X char *filename; X { X FileRec *file; X! char *pathname; X X! pathname = GetPathname(filename); X! if (pathname == NULL) { X! return -1; X } X! if (displayedFile && strcmp(pathname, displayedFile->pathname) == 0) X! return -1; X! else if (file = LookUpFileTable(pathname, filename)) { X SaveDisplayedFileInfo(); X DisplayFile(file); X! UpdateFileLabel(pathname); X XtTextSetInsertionPoint(sourceWindow, file->linepos[file->currentline]); X UpdateLineLabel(file->currentline); X UpdateStops(file); X UpdateArrow(file); X UpdateUpdown(file); X! displayedFile = file; X! return 0; X } X! else { /* LookUpFileTable() fails */ X! return -1; X } X } X*** xdbx1.0/xdbx.c Fri Mar 24 01:18:44 1989 X--- xdbx1.1/xdbx.c Sun Apr 2 16:53:19 1989 X*************** X*** 18,23 **** X--- 18,24 ---- X ******************************************************************************/ X X X+ #include "errno.h" X #include "global.h" X X #define Offset(field) (XtOffset(XdbxResources *, field)) X*************** X*** 35,42 **** X dialogWindow; /* dialog window, asciiString widget */ X X XdbxResources app_resources; /* application resources of xdbx */ X! char *xdbxinit = "xdbx.XXXXXX"; X! Boolean Homedir; X X X static XtResource resources[] = { X--- 36,43 ---- X dialogWindow; /* dialog window, asciiString widget */ X X XdbxResources app_resources; /* application resources of xdbx */ X! char *xdbxinit = "/tmp/xdbx.XXXXXX"; /* temp file for .dbxinit */ X! int Homedir; /* .dbxinit or ~/.dbxinit */ X X X static XtResource resources[] = { X*************** X*** 76,83 **** X--- 77,112 ---- X Offset(arrowForeground), XtRString, "Blue"}, X {"updownForeground", "UpdownForeground", XtRPixel, sizeof(Pixel), X Offset(updownForeground), XtRString, "Blue"}, X+ {"sourceTranslTable", "SourceTranslTable", X+ XtRTranslationTable, sizeof(XtTranslations), X+ Offset(sourceTranslTable), XtRString, (caddr_t)NULL}, X+ {"dialogTranslTable", "DialogTranslTable", X+ XtRTranslationTable, sizeof(XtTranslations), X+ Offset(dialogTranslTable), XtRTranslationTable, (caddr_t)NULL}, X+ {"sbarTranslTable", "SbarTranslTable", X+ XtRTranslationTable, sizeof(XtTranslations), X+ Offset(sbarTranslTable), XtRString, (caddr_t)NULL}, X+ {"dbxopt_r", "Dbxoptions", XtRBoolean, sizeof(Boolean), X+ Offset(dbxopt_r), XtRImmediate, (caddr_t)False}, X+ {"dbxopt_i", "Dbxoptions", XtRBoolean, sizeof(Boolean), X+ Offset(dbxopt_i), XtRImmediate, (caddr_t)False}, X+ {"includeDir", "Dbxoptions", XtRString, sizeof(char *), X+ Offset(includeDir), XtRImmediate, (caddr_t)NULL}, X+ {"dbxopt_k", "Dbxoptions", XtRBoolean, sizeof(Boolean), X+ Offset(dbxopt_k), XtRImmediate, (caddr_t)False}, X+ {"cfile", "Dbxoptions", XtRString, sizeof(char *), X+ Offset(cfile), XtRImmediate, (caddr_t)NULL}, X+ {"dbxopt_kbd", "Dbxoptions", XtRBoolean, sizeof(Boolean), X+ Offset(dbxopt_kbd), XtRImmediate, (caddr_t)False}, X+ {"fcount", "Dbxoptions", XtRString, sizeof(char *), X+ Offset(fcount), XtRImmediate, (caddr_t)NULL}, X+ {"startup", "Dbxoptions", XtRString, sizeof(char *), X+ Offset(startup), XtRImmediate, (caddr_t)NULL}, X+ {"tstartup", "Dbxoptions", XtRString, sizeof(char *), X+ Offset(tstartup), XtRImmediate, (caddr_t)NULL}, X }; X X+ X static XrmOptionDescRec options[] = { X {"-r", "dbxopt_r", XrmoptionNoArg, "True"}, X {"-i", "dbxopt_i", XrmoptionNoArg, "True"}, X*************** X*** 85,94 **** X {"-k", "dbxopt_k", XrmoptionNoArg, "True"}, X #ifdef BSD /* Berkeley dbx */ X {"-c", "cfile", XrmoptionSepArg, NULL}, X! #else /* Sun Release 3.2 or 3.4 dbx */ X {"-kbd", "dbxopt_kbd", XrmoptionNoArg, "True"}, X #endif X! #ifdef sparc /* SunOS 4.0 dbx */ X {"-f", "fcount", XrmoptionSepArg, NULL}, X {"-s", "startup", XrmoptionSepArg, NULL}, X {"-sr", "tstartup", XrmoptionSepArg, NULL}, X--- 114,123 ---- X {"-k", "dbxopt_k", XrmoptionNoArg, "True"}, X #ifdef BSD /* Berkeley dbx */ X {"-c", "cfile", XrmoptionSepArg, NULL}, X! #else /* Sun dbx */ X {"-kbd", "dbxopt_kbd", XrmoptionNoArg, "True"}, X #endif X! #ifdef SUNOS4_0 /* SunOS 4.0 dbx */ X {"-f", "fcount", XrmoptionSepArg, NULL}, X {"-s", "startup", XrmoptionSepArg, NULL}, X {"-sr", "tstartup", XrmoptionSepArg, NULL}, X*************** X*** 105,111 **** X } X X X! static void Initialize() X { X source_init(); X signs_init(); X--- 134,152 ---- X } X X X! /* Initialize routines in source.c, signs.c and parser.c. X! * Disable window resize of titleBar and fileWindow. X! * Dbx reads .dbxinit or ~/.dbxinit only once during invocation. X! * (a) creates a temporary file /tmp/xdbx.XXXXXX X! * (b) attempts to rename .dbxinit to the temp file. X! * (c) if rename fails because .dbxinit does not exist, xdbx attempts to X! * rename ~/.dbxinit to the temp file. X! * (d) if rename fails for other reasons, xdbx creates another temporary file X! * xdbx.XXXXXX and repeat steps (b) and (c). X! * The Homedir flag is set to 1 if ~/.dbxinit is found, 0 if .dbxinit is X! * found, -1 if none of both is found. X! */ X! static void main_init() X { X source_init(); X signs_init(); X*************** X*** 113,161 **** X if (!app_resources.noTitleBar) DisableWindowResize(titleBar); X DisableWindowResize(fileWindow); X mktemp(xdbxinit); X! Homedir = False; X! if (rename(".dbxinit", xdbxinit) == -1) { X! rename("~/.dbxinit", xdbxinit); X! Homedir = True; X } X } X X X! int dbxoptions(argc, argv, app_resources) X! int argc; X char **argv; X! XdbxResources app_resources; X { X! if (app_resources.dbxopt_r) X! argv[argc++] = "-r"; X! if (app_resources.dbxopt_i) X! argv[argc++] = "-i"; X! if (app_resources.includeDir) { X! argv[argc++] = "-I"; X! strcpy(argv[argc++], app_resources.includeDir); X } X! if (app_resources.dbxopt_k) X! argv[argc++] = "-k"; X! if (app_resources.cfile) { X! argv[argc++] = "-c"; X! strcpy(argv[argc++], app_resources.cfile); X } X! if (app_resources.dbxopt_kbd) X! argv[argc++] = "-kbd"; X! if (app_resources.fcount) { X! argv[argc++] = "-f"; X! strcpy(argv[argc++], app_resources.fcount); X } X! if (app_resources.startup) { X! argv[argc++] = "-s"; X! strcpy(argv[argc++], app_resources.startup); X } X! if (app_resources.tstartup) { X! argv[argc++] = "-sr"; X! strcpy(argv[argc++], app_resources.tstartup); X } X! argv[argc] = NULL; X! return argc; X } X X X--- 154,225 ---- X if (!app_resources.noTitleBar) DisableWindowResize(titleBar); X DisableWindowResize(fileWindow); X mktemp(xdbxinit); X! Homedir = -1; X! if (rename(".dbxinit", xdbxinit) == 0) X! Homedir = 0; X! else if (errno == ENOENT) { X! if (rename("~/.dbxinit", xdbxinit) == 0) X! Homedir = 1; X } X+ else { X+ strcpy(xdbxinit, "xdbx.XXXXXX"); X+ mktemp(xdbxinit); X+ if (rename(".dbxinit", xdbxinit) == 0) X+ Homedir = 0; X+ else if (errno == ENOENT) { X+ if (rename("~/.dbxinit", xdbxinit) == 0) X+ Homedir = 1; X+ } X+ } X } X X X! /* Reconstruct command line arguments for calling dbx. X! * Return the argument list for dbx and new value of argc. X! */ X! char **dbxoptions(argc, argv, app_resources) X! int *argc; X char **argv; X! XdbxResources *app_resources; X { X! char **dbxargv; X! int i=0; X! X! dbxargv = (char **) XtMalloc (MAXARGS * sizeof(char *)); X! for (i=0; i < *argc; i++) X! dbxargv[i] = argv[i]; X! X! if (app_resources->dbxopt_r) X! dbxargv[i++] = "-r"; X! if (app_resources->dbxopt_i) X! dbxargv[i++] = "-i"; X! if (app_resources->includeDir) { X! dbxargv[i++] = "-I"; X! dbxargv[i++] = app_resources->includeDir; X } X! if (app_resources->dbxopt_k) X! dbxargv[i++] = "-k"; X! if (app_resources->cfile) { X! dbxargv[i++] = "-c"; X! dbxargv[i++] = app_resources->cfile; X } X! if (app_resources->dbxopt_kbd) X! dbxargv[i++] = "-kbd"; X! if (app_resources->fcount) { X! dbxargv[i++] = "-f"; X! dbxargv[i++] = app_resources->fcount; X } X! if (app_resources->startup) { X! dbxargv[i++] = "-s"; X! dbxargv[i++] = app_resources->startup; X } X! if (app_resources->tstartup) { X! dbxargv[i++] = "-sr"; X! dbxargv[i++] = app_resources->tstartup; X } X! dbxargv[i] = NULL; X! *argc = i; X! return dbxargv; X } X X X*************** X*** 163,168 **** X--- 227,234 ---- X unsigned int argc; X char **argv; X { X+ char **dbxargv; X+ X trap_signals(); X X toplevel = XtInitialize("toplevel", "XDbx", options, XtNumber(options), X*************** X*** 177,185 **** X X XtRealizeWidget(toplevel); X X! Initialize(); X! argc = dbxoptions(argc, argv, app_resources); X! calldbx(argc, argv); X X XtMainLoop(); X } X--- 243,251 ---- X X XtRealizeWidget(toplevel); X X! main_init(); X! dbxargv = dbxoptions(&argc, argv, &app_resources); X! calldbx(argc, dbxargv); X X XtMainLoop(); X } Xdiff -c xdbx1.0/xdbx.man xdbx1.1/xdbx.man X*** xdbx1.0/xdbx.man Fri Mar 24 01:18:41 1989 X--- xdbx1.1/xdbx.man Sun Apr 2 18:01:39 1989 X*************** X*** 29,34 **** X--- 29,37 ---- X If a file named \fIcore\fP exists in the current directory or a X \fIcorefile\fP is specified, \fIxdbx\fP can be used to examine the X state of the program when the core dump occurred. X+ .LP X+ The name of the debugger invoked by \fIxdbx\fP is, by default, dbx, X+ but it can be overridden with the environment variable DEBUGGER. X .SH OPTIONS X \fIXdbx\fP accepts all of the standard X Toolkit command line options X (see \fIX\fP(1)), and all the dbx options (see \fIdbx\fP(1)). X*************** X*** 83,88 **** X--- 86,94 ---- X contains a function call. X .IP "\fBnext\fP" X Execute one source line, without stepping into any function call. X+ .IP "\fBreturn\fP" X+ Continue execution until the selected procedure returns; the current X+ procedure is used if none is selected (only in Berkeley dbx). X X .LP X .SS "Breakpoint Commands" X*************** X*** 99,105 **** X Remove the breakpoint on the source line selected. The stop sign will X disappear. X .IP "\fBstatus\fP" X! Show the current breakpoints and traces. X X .LP X .SS "Stack Commands" X--- 105,111 ---- X Remove the breakpoint on the source line selected. The stop sign will X disappear. X .IP "\fBstatus\fP" X! Show the current breakpoints and traces (only in Sun dbx). X X .LP X .SS "Stack Commands" X*************** X*** 121,128 **** X variable name resolution to the selected function. The file scope is changed X to the file containing the function. X .IP "\fBfile\fP" X! Pop up a file menu to select a source file to be displayed, and X! change the file scope to the selected file. X .IP "\fBquit\fP" X Exit \fIxdbx\fP. X X--- 127,138 ---- X variable name resolution to the selected function. The file scope is changed X to the file containing the function. X .IP "\fBfile\fP" X! Pop up a file menu that allows the user to move up and down in the X! directory tree, to select a text file to be displayed, or (in Sun dbx) X! to select an executable file to debug. Directory entries are marked X! with a trailing slash (`/') and executables with a trailing asterisk (`*'). X! Filenames beginning with a dot (`.') or ending with a tilde (`~') are not X! included in the menu. X .IP "\fBquit\fP" X Exit \fIxdbx\fP. X X*************** X*** 187,192 **** X--- 197,208 ---- X Foreground color of the arrow sign. X .IP \fBupdownForeground\fP X Foreground color of the updown sign. X+ .IP \fBsourceTranslTable\fP X+ Translation table for the sourceWindow text widget. X+ .IP \fBsbarTranslTable\fP X+ Translation table for the sourceWindow scrollbar widget. X+ .IP \fBdialogTranslTable\fP X+ Translation table for the dialogWindow text widget. X .LP X X .SH FILES X*************** X*** 201,220 **** X \fIXdbx\fP is developed primarily for C program debugging. Other languages are X not fully supported. X .SH BUGS X! Typing control-C in the dialog window fails to interrupt dbx. X .LP X The \fBfile\fP button command does not unhighlight the button border. X .LP X Stuffing text to a window outside the \fIxdbx\fP window will sometimes give X! such message: X! .ce X "X Toolkit Error: AtomPtr was not initialized" X- .LP X- \fIXdbx\fP does not work under SunOS 4.0 due to a problem in disabling the X- packet mode (TIOCPKT) of the pseudo-terminal. If the packet mode is not X- disabled, each read from the master will return data written previously to X- the slave (dbx commands entered would reappear), and each newline character X- is incorrectly mapped to a carriage return and a newline during text display. X .LP X .SH COPYRIGHT X Copyright 1989 The University of Texas at Austin X--- 217,231 ---- X \fIXdbx\fP is developed primarily for C program debugging. Other languages are X not fully supported. X .SH BUGS X! \fIXdbx\fP exercises some bugs in the Athena list widget. Creating a file X! menu could cause segmentation violation. X .LP X The \fBfile\fP button command does not unhighlight the button border. X .LP X Stuffing text to a window outside the \fIxdbx\fP window will sometimes give X! an error message: X! .in 10 X "X Toolkit Error: AtomPtr was not initialized" X .LP X .SH COPYRIGHT X Copyright 1989 The University of Texas at Austin X X +END+OF+xdbx.patch.1 echo '-rw-r--r-- 1 argv 32685 Apr 5 23:56 xdbx.patch.1 (as sent)' chmod u=rw,g=r,o=r xdbx.patch.1 ls -l xdbx.patch.1 exit 0