"Fossies" - the Fresh Open Source Software Archive

Member "xxgdb-1.12/source.c" (21 Apr 1995, 34421 Bytes) of package /linux/misc/old/xxgdb-1.12.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*****************************************************************************
    2  *
    3  *  xdbx - X Window System interface to the dbx debugger
    4  *
    5  *  Copyright 1989 The University of Texas at Austin
    6  *  Copyright 1990 Microelectronics and Computer Technology Corporation
    7  *
    8  *  Permission to use, copy, modify, and distribute this software and its
    9  *  documentation for any purpose and without fee is hereby granted,
   10  *  provided that the above copyright notice appear in all copies and that
   11  *  both that copyright notice and this permission notice appear in
   12  *  supporting documentation, and that the name of The University of Texas
   13  *  and Microelectronics and Computer Technology Corporation (MCC) not be 
   14  *  used in advertising or publicity pertaining to distribution of
   15  *  the software without specific, written prior permission.  The
   16  *  University of Texas and MCC makes no representations about the 
   17  *  suitability of this software for any purpose.  It is provided "as is" 
   18  *  without express or implied warranty.
   19  *
   20  *  THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
   21  *  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
   22  *  FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
   23  *  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
   24  *  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   25  *  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   26  *  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   27  *
   28  *  Author:     Po Cheung
   29  *  Created:    March 10, 1989
   30  * 
   31  *****************************************************************************
   32  * 
   33  *  xxgdb - X Window System interface to the gdb debugger
   34  *  
   35  *  Copyright 1990,1993 Thomson Consumer Electronics, Inc.
   36  *  
   37  *  Permission to use, copy, modify, and distribute this software and its
   38  *  documentation for any purpose and without fee is hereby granted,
   39  *  provided that the above copyright notice appear in all copies and that
   40  *  both that copyright notice and this permission notice appear in
   41  *  supporting documentation, and that the name of Thomson Consumer
   42  *  Electronics (TCE) not be used in advertising or publicity pertaining
   43  *  to distribution of the software without specific, written prior
   44  *  permission.  TCE makes no representations about the suitability of
   45  *  this software for any purpose.  It is provided "as is" without express
   46  *  or implied warranty.
   47  *
   48  *  TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   49  *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
   50  *  SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
   51  *  OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   52  *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   53  *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   54  *  SOFTWARE.
   55  *
   56  *  Adaptation to GDB:  Pierre Willard
   57  *  XXGDB Created:      December, 1990
   58  *
   59  *****************************************************************************/
   60 
   61 /*  source.c
   62  *
   63  *    Create the source window and handle display of file.
   64  *
   65  *    source_init():    Initialization routine.
   66  *    Update():     Action proc to update source window on scrollbar action.
   67  *    NotifyResize():   Action proc to update source window on resize.
   68  *    CreateSourceWindow(): Create the source window.
   69  *    BuildLinePos():   Build an array of starting text position of each line.
   70  *    LookUpFileTable():Check out source file info from a file table.
   71  *    SaveDisplayedFileInfo(): records displayed file info into file table.
   72  *    DisplayFile():    Display a file on the source window
   73  *    StartEditor():    Start a child process editor on the displayed file.
   74  *    LoadFile():   Search for a file and open it for display.
   75  */
   76 
   77 #ifndef NeXT
   78 #include <malloc.h>
   79 #endif
   80 #include <stdlib.h>
   81 
   82 #include <X11/Xos.h>
   83 #include <sys/stat.h>
   84 #include <pwd.h>
   85 #include "global.h"
   86 
   87 #ifdef SYSV 
   88 #ifdef sco
   89 #   include <fcntl.h>
   90 #endif
   91 #endif /* SYSV */
   92 
   93 #ifdef GDB
   94 #include <string.h>
   95 #endif
   96 
   97 #define MAXDIRS 256         /* max number of dirs in dirList */
   98 
   99 char        CurrentFile[MAXNAME];   /* current contents of file variable */
  100 Widget      sourceForm,     /* parent of sourceWindow */
  101         sourceWindow;       /* text window for source file */
  102 FileRec     *displayedFile;     /* pointer to table entry of currently
  103                        displayed file */
  104 
  105 static FileRec  **fileTable;        /* table of file records */
  106 static int  fileTableSize;      /* size of file table */
  107 static char     *dirList[MAXDIRS];  /* list of dirs for searching files */
  108 
  109 void source_init()
  110 {
  111     dirList[0] = NULL;
  112 }
  113 
  114 /*
  115  *  Update topline, bottomline, arrow sign, updown sign, stop signs, and
  116  *  line label.
  117  */
  118 /* ARGSUSED */
  119 void Update(w, event, params, num_params)
  120     Widget w;
  121     XEvent *event;
  122     String *params;
  123     Cardinal *num_params;
  124 {
  125     XawTextPosition     pos;
  126     int         topline;
  127     FileRec         *file;
  128 
  129     if (displayedFile) {
  130         file = displayedFile;
  131     pos = XawTextTopPosition(sourceWindow);
  132     file->topPosition = pos;
  133     topline = TextPositionToLine(pos);
  134     /* Update the symbols only if the text scrolls */
  135     if (file->topline != topline) {
  136         file->topline = topline;
  137         file->bottomline = MIN (file->topline + file->lines - 1, 
  138                     file->lastline);
  139         /* 
  140           03/26/91 mod 7 GWC
  141           Fixed a bug where the special margin symbols (arrows, stop signs,
  142           etc.) did not scroll when one moved the text with keyboard commands
  143           such as Ctrl<Key>n.  To do this the Update action procedure should
  144           be called after text widget actions such as next-line.
  145           Unfortunately Update needed to be enhanced a bit not to always warp
  146           the cursor to the top of the window.  You can now call Update with a
  147           parameter "warp" to warp the cursor to the top of the screen; the
  148           default is not to warp.
  149           */
  150         if (*num_params == 1 && strcmp(params[0], "warp") == 0)
  151           {
  152         XawTextSetInsertionPoint(sourceWindow,
  153                      file->linepos[file->topline]);
  154           }
  155 
  156         UpdateLineLabel(file->topline);
  157             UpdateStops(file);
  158             UpdateArrow(file);
  159             UpdateUpdown(file);
  160             UpdateBomb(file);
  161     }
  162     else {/* Update caret position only */
  163         pos = XawTextGetInsertionPoint(sourceWindow);
  164         UpdateLineLabel(TextPositionToLine(pos));
  165     }
  166     }
  167 }
  168 
  169 /*
  170  *  Update bottomline, arrow sign, updown sign and stop signs on resize.
  171  *  Invoked by ConfigureNotify event.
  172  */
  173 /* ARGSUSED */
  174 static void NotifyResize(w, event, params, num_params)
  175     Widget w;
  176     XEvent *event;
  177     String *params;
  178     Cardinal *num_params;
  179 {
  180     XawTextPosition pos;
  181     TextWidget  ctx = (TextWidget) sourceWindow;
  182     FileRec *file;
  183 
  184     if ((file = displayedFile)) {
  185     file->lines = ctx->text.lt.lines;
  186     pos = XawTextTopPosition(sourceWindow);
  187     file->topline = TextPositionToLine(pos);
  188         file->bottomline = MIN (file->topline + file->lines - 1, 
  189                 file->lastline);
  190         UpdateStops(file);
  191         UpdateArrow(file);
  192         UpdateUpdown(file);
  193         UpdateBomb(file);
  194     }
  195 }
  196 
  197 /*  Update the position of the caret */
  198 /*  ARGSUSED */
  199 #ifdef notdef
  200 void UpdateLine(w, event, params, num_params)
  201     Widget w;
  202     XEvent *event;
  203     String *params;
  204     Cardinal *num_params;
  205 {
  206     XawTextPosition pos;
  207     int line;
  208 
  209     pos = XawTextGetInsertionPoint(w);
  210     line = TextPositionToLine(pos);
  211     UpdateLineLabel(line);
  212 }
  213 #endif
  214 
  215 /*  My select-start routine that cancels the effect of automatic scrolling
  216  *  near the bottom of an Athena text widget window.
  217  */
  218 /*  ARGSUSED */
  219 void SelectStart(w, event, params, num_params)
  220     Widget w;
  221     XEvent *event;
  222     String *params;
  223     Cardinal *num_params;
  224 {
  225     XawTextPosition topPosition;
  226 
  227     /* remember the top display position before automatic scrolling */
  228     /* displayedFile->topPosition = XawTextTopPosition(w); */
  229     topPosition = XawTextTopPosition(w);
  230 
  231     XtCallActionProc(w, "select-start", event, params, *num_params);
  232 
  233     /* reset to remembered position if top position changed */
  234     /* if (XawTextTopPosition(w) != displayedFile->topPosition)
  235         TextSetTopPosition(w, displayedFile->topPosition); */
  236     if (XawTextTopPosition(w) != topPosition)
  237         TextSetTopPosition(w, topPosition);
  238 }
  239 
  240 /*  My select-end routine to store the text selection into both the PRIMARY
  241  *  selection and cut buffer 0. 
  242  */
  243 /*  ARGSUSED */
  244 void SelectEnd(w, event, params, num_params)
  245     Widget w;
  246     XEvent *event;
  247     String *params;
  248     Cardinal *num_params;
  249 {
  250     XawTextPosition begin, end, start;
  251     Widget textsrc;
  252     XawTextBlock buffer;
  253     char s_storage[LINESIZ]; /* fix bug where if selection is past 10k, xxgdb crashes */
  254     char* s = &s_storage[0];
  255     int nchars;
  256 
  257     XawTextGetSelectionPos(w, &begin, &end);
  258     XawTextSetSelection(w, begin, end);
  259     if (begin == end) return;
  260     if (end - begin > LINESIZ) s = (char*)malloc(end - begin + LINESIZ);
  261     textsrc = XawTextGetSource(w);
  262     strcpy(s, "");
  263     for (start=begin, nchars=end-begin; nchars > 0; 
  264     start=begin+buffer.length, nchars-=buffer.length) {
  265         XawTextSourceRead(textsrc, start, &buffer, nchars);
  266     strncat(s, buffer.ptr, buffer.length);
  267     }
  268     XStoreBytes(display, s, strlen(s));
  269     if (end - begin > LINESIZ) free(s);
  270 }
  271 
  272 /*  This is my own select word routine to replace the standard action
  273  *  procedure provided by the Text widget.
  274  *  It selects a word delimited by DELIMITERS, not whitespace.
  275  */
  276 /* ARGSUSED */
  277 void SelectWord(w, event, params, num_params)
  278     Widget w;
  279     XEvent *event;
  280     String *params;
  281     Cardinal *num_params;
  282 {
  283     XawTextPosition pos, left, right, start;
  284     XawTextBlock buffer;
  285     Widget  textsrc;
  286     char    s[LINESIZ];
  287     char    *p, *ls, *rs;
  288     int     nchars;
  289 
  290     pos = XawTextGetInsertionPoint(w);
  291     textsrc = XawTextGetSource(w);
  292 
  293     XawTextSourceRead(textsrc, pos, &buffer, 1);
  294     if (buffer.length == 0 || (buffer.length == 1 &&
  295     strchr(app_resources.delimiters, (int)*(buffer.ptr)) != NULL)) {
  296     XStoreBytes(display, NULL, 0);
  297     return;
  298     }
  299 
  300     left = XawTextSourceScan(textsrc, pos+1, XawstWhiteSpace, XawsdLeft, 1,
  301                              FALSE);
  302     right = XawTextSourceScan(textsrc, left, XawstWhiteSpace, XawsdRight, 1,
  303                               FALSE);
  304     
  305     strcpy(s, "");
  306     for (start=left, nchars=right-left; nchars > 0; 
  307     start=left+buffer.length, nchars-=buffer.length) {
  308         XawTextSourceRead(textsrc, start, &buffer, nchars);
  309     strncat(s, buffer.ptr, buffer.length);
  310     }
  311 
  312     if (!strcmp(s, "")) return;
  313     p = s+pos-left;
  314     ls = (char *) strtok(s, app_resources.delimiters);
  315     rs = (char *) strtok(NULL, app_resources.delimiters);
  316     if (!ls) return;
  317     while (rs<=p && rs!=NULL) {
  318     ls = rs;
  319     rs = (char *) strtok(NULL, app_resources.delimiters);
  320     }
  321     left = left + ls - s;
  322     right = left + strlen(ls) - 1; 
  323 
  324     XawTextUnsetSelection(w);
  325     XStoreBytes(display, ls, strlen(ls));
  326     XawTextSetSelection(w, left, right+1);
  327 }
  328 
  329 /*  Print the value of the expression  in cut buffer 0. */
  330 /*  ARGSUSED */
  331 void PrintSelection(w, event, params, num_params)
  332     Widget w;
  333     XEvent *event;
  334     String *params;
  335     Cardinal *num_params;
  336 {
  337     char command[LINESIZ];
  338     char *string;
  339     int nbytes;
  340 
  341     string = XFetchBytes(display, &nbytes);
  342     if (nbytes == 0) {
  343         UpdateMessageWindow(PRINT_HELP, NULL);
  344         bell(0);
  345         return;
  346     }
  347     sprintf(command, "print %s\n", string);
  348     send_command(command);
  349     AppendDialogText(command);
  350 }
  351 
  352 #ifdef EDIT_BUTTON
  353 /* allow invocation of favorite editor from within interface */
  354 extern void StartEditor();
  355 void EdAction(w, event, params, num_params)
  356     Widget w;
  357     XEvent *event;
  358     String *params;
  359     Cardinal *num_params;
  360 {
  361   StartEditor();
  362 }
  363 #endif /* EDIT_BUTTON */
  364 
  365 /* fixes keybindings in source window */
  366 extern PopupSearch();
  367 void Search(w, event, params, num_params)
  368     Widget w;
  369     XEvent *event;
  370     String *params;
  371     Cardinal *num_params;
  372 {
  373   PopupSearch(w, NULL, NULL);
  374 }
  375 
  376 /* 
  377  *  On top of a form widget, we have a text widget with scrollbar, label
  378  *  widgets for the stop sign, arrow sign, and updown signs.
  379  */
  380 
  381 /* add popupsearch which is triggered by ^S in file window also add
  382 -editor switch which can be set to vi or emacs (default is emacs) and
  383 have operative keys in the editor window for moving around (move stop
  384 signs and such around too) */
  385 
  386 void CreateSourceWindow(parent)
  387 Widget parent;
  388 {
  389     TextWidget ctx;
  390     Arg args[MAXARGS];
  391     Cardinal n;
  392 
  393     static XtActionsRec sbar_actions[] = {
  394         {"NotifyResize",   NotifyResize},
  395         {"Update",     Update},
  396         {NULL, NULL}
  397     };
  398 
  399     /* fixes keybindings in source window */
  400     static XtActionsRec text_actions[] = {
  401         {"Update",     Update},
  402 #ifdef EDIT_BUTTON
  403         {"Editor",         EdAction},
  404 #endif
  405         {"Search",         Search},
  406         {NULL, NULL}
  407     };
  408 
  409 #ifdef EDIT_BUTTON
  410 
  411     static String eTextTranslations = "#override \n\
  412         Ctrl<Key>V:    next-page() Update(warp) \n\
  413         Meta<Key>V:    previous-page() Update(warp) \n\
  414         Ctrl<Key>N:    next-line() Update() \n\
  415         Ctrl<Key>P:    previous-line() Update() \n\
  416         Ctrl<Key>Z:    scroll-one-line-up() Update(warp) \n\
  417         Meta<Key>Z:    scroll-one-line-down() Update(warp) \n\
  418         Meta<Key>]:    forward-paragraph() Update(warp) \n\
  419         Meta<Key>[:    backward-paragraph() Update(warp) \n\
  420         Meta<Key>F:    forward-word() Update() \n\
  421         Meta<Key>B:    backward-word() Update() \n\
  422         Ctrl<Key>F:    forward-character() Update() \n\
  423         Ctrl<Key>B:    backward-character() Update() \n\
  424         Meta<Key>E:    Editor() \n\
  425         Meta<Key><:   beginning-of-file() Update(warp) \n\
  426         Meta<Key>>:   end-of-file() Update(warp) \n\
  427         <Key>L:        redraw-display() Update() \n\
  428         <Key>S:        Search() Update() \n\
  429         <Key>R:        Search() Update() \n\
  430         <Btn1Down>:             SelectStart() SelectWord() \n\
  431     Shift<Btn1Up>:          Update() SelectEnd() PrintSelection() \n\
  432     <Btn1Up>:               Update() SelectEnd() \n\
  433       ";
  434   
  435     static String vTextTranslations = "#override \n\
  436         Ctrl<Key>F:    next-page() Update(warp) \n\
  437         Ctrl<Key>B:    previous-page() Update(warp) \n\
  438         Ctrl<Key>D:    next-page() Update() \n\
  439         Ctrl<Key>U:    previous-page() Update() \n\
  440         <Key>Return:   next-line() Update() \n\
  441         <Key>-:        previous-line() Update() \n\
  442         <Key>j:        next-line() Update() \n\
  443         <Key>k:        previous-line() Update() \n\
  444         <Key>space:    forward-character() Update() \n\
  445         <Key>BackSpace: backward-character() Update() \n\
  446         <Key>1:        beginning-of-file() Update(warp) \n\
  447         <Key>G:        end-of-file() Update(warp) \n\
  448         <Key>E:        Editor() \n\
  449         <Key>L:        redraw-display() Update() \n\
  450         <Key>/:        Search() Update() \n\
  451         <Key>?:        Search() Update() \n\
  452         <Btn1Down>:             SelectStart() SelectWord() \n\
  453     Shift<Btn1Up>:          Update() SelectEnd() PrintSelection() \n\
  454     <Btn1Up>:               Update() SelectEnd() \n\
  455     ";
  456 
  457 #else /* not EDIT_BUTTON */
  458 
  459     static String eTextTranslations = "#override \n\
  460         Ctrl<Key>V:    next-page() Update(warp) \n\
  461         Meta<Key>V:    previous-page() Update(warp) \n\
  462         Ctrl<Key>N:    next-line() Update() \n\
  463         Ctrl<Key>P:    previous-line() Update() \n\
  464         Ctrl<Key>Z:    scroll-one-line-up() Update(warp) \n\
  465         Meta<Key>Z:    scroll-one-line-down() Update(warp) \n\
  466         Meta<Key>]:    forward-paragraph() Update(warp) \n\
  467         Meta<Key>[:    backward-paragraph() Update(warp) \n\
  468         Meta<Key>F:    forward-word() Update() \n\
  469         Meta<Key>B:    backward-word() Update() \n\
  470         Ctrl<Key>F:    forward-character() Update() \n\
  471         Ctrl<Key>B:    backward-character() Update() \n\
  472         Meta<Key><:   beginning-of-file() Update(warp) \n\
  473         Meta<Key>>:   end-of-file() Update(warp) \n\
  474         <Key>L:        redraw-display() Update() \n\
  475         <Key>S:        Search() Update() \n\
  476         <Key>R:        Search() Update() \n\
  477         <Btn1Down>:             SelectStart() SelectWord() \n\
  478     Shift<Btn1Up>:          Update() SelectEnd() PrintSelection() \n\
  479     <Btn1Up>:               Update() SelectEnd() \n\
  480       ";
  481   
  482     static String vTextTranslations = "#override \n\
  483         Ctrl<Key>F:    next-page() Update(warp) \n\
  484         Ctrl<Key>B:    previous-page() Update(warp) \n\
  485         Ctrl<Key>D:    next-page() Update() \n\
  486         Ctrl<Key>U:    previous-page() Update() \n\
  487         <Key>Return:   next-line() Update() \n\
  488         <Key>-:        previous-line() Update() \n\
  489         <Key>j:        next-line() Update() \n\
  490         <Key>k:        previous-line() Update() \n\
  491         <Key>space:    forward-character() Update() \n\
  492         <Key>BackSpace: backward-character() Update() \n\
  493         <Key>1:        beginning-of-file() Update(warp) \n\
  494         <Key>G:        end-of-file() Update(warp) \n\
  495         <Key>L:        redraw-display() Update() \n\
  496         <Key>/:        Search() Update() \n\
  497         <Key>?:        Search() Update() \n\
  498         <Btn1Down>:             SelectStart() SelectWord() \n\
  499     Shift<Btn1Up>:          Update() SelectEnd() PrintSelection() \n\
  500     <Btn1Up>:               Update() SelectEnd() \n\
  501     ";
  502 
  503 #endif /* EDIT_BUTTON */
  504 
  505     /* fixes keybindings in source window */
  506     static String sbarTranslations = "\
  507         <Configure>:    NotifyResize() \n\
  508         <Btn2Down>:     StartScroll(Continuous) MoveThumb() NotifyThumb() \
  509                         Update() \n\
  510         <Btn2Motion>:   MoveThumb() NotifyThumb() Update() \n\
  511         <BtnUp>:        NotifyScroll(Proportional) EndScroll() Update() \n\
  512     ";
  513 
  514     n = 0;
  515     XtSetArg(args[n], XtNdefaultDistance, 0);                           n++;
  516     sourceForm = XtCreateManagedWidget("sourceForm", formWidgetClass, 
  517                      parent, args, n);
  518 
  519     n = 0;
  520     XtSetArg(args[n], XtNborderWidth, 0);               n++;
  521     XtSetArg(args[n], XtNtype, (XtArgVal)XawAsciiFile);         n++;
  522     XtSetArg(args[n], XtNstring, (XtArgVal)"/dev/null");        n++;
  523     XtSetArg(args[n], XtNscrollVertical, (XtArgVal) XawtextScrollAlways);n++;
  524     sourceWindow = XtCreateManagedWidget("sourceWindow", asciiTextWidgetClass,
  525                       sourceForm, args, n);
  526 
  527     ctx = (TextWidget) sourceWindow;
  528     if (ctx->text.vbar)
  529         XtOverrideTranslations(ctx->text.vbar, 
  530                 XtParseTranslationTable(sbarTranslations));
  531     XtAppAddActions(app_context, sbar_actions, XtNumber(sbar_actions));
  532 
  533     /* fixes keybindings in source window */
  534     XtAppAddActions(app_context, text_actions, XtNumber(text_actions));
  535     if (app_resources.bindings && strcmp(app_resources.bindings, "vi") == 0)
  536       XtOverrideTranslations((Widget) ctx, XtParseTranslationTable(vTextTranslations));
  537     else
  538       XtOverrideTranslations((Widget) ctx, XtParseTranslationTable(eTextTranslations));
  539 
  540     /* setup tabulation */
  541     if (app_resources.tabstop >= 0) {
  542         int tab, tabs[256];
  543         for (n = 0, tab = 0; n < sizeof tabs / sizeof *tabs; n++)
  544             tabs[n] = (tab += app_resources.tabstop);
  545         XawTextSinkSetTabs(ctx->text.sink, sizeof tabs / sizeof *tabs, tabs);
  546     }
  547 }
  548 
  549 
  550 /*
  551  *  Build the array which gives the starting text position of each line.
  552  *  > Estimate the number of lines in the file and allocate memory buffer.
  553  *  > Starting position of line #1 is 0, and is stored in linepos[1].
  554  *  > Search for '\n' till end of buffer.
  555  */
  556 static void BuildLinePos(file)
  557 FileRec *file;
  558 {
  559     char *p;
  560     int  line, nlines;
  561 
  562     nlines = MAX(1, file->filesize/CHARS_PER_LINE);
  563     file->linepos = (XawTextPosition *)
  564             XtMalloc ((nlines+2) * sizeof(XawTextPosition));
  565     p = file->buf;
  566     line = 0;
  567     file->linepos[line++] = 0;
  568     file->linepos[line++] = 0;
  569     while (*p) {
  570     if (*p++ == '\n') {
  571         if (line == nlines) {   /* buffer full, need more memory */
  572                 file->linepos = (XawTextPosition *) XtRealloc ((void*)file->linepos, 
  573               (nlines + ADD_LINES) * sizeof(XawTextPosition));
  574         nlines += ADD_LINES;
  575             }
  576             file->linepos[line++] = p - file->buf;
  577     }
  578     }
  579     file->lastline = line - 2;
  580     file->linepos = (XawTextPosition *) XtRealloc   /* shrink to min size */
  581             ((void*)file->linepos, line * sizeof(XawTextPosition));
  582 }
  583 
  584 /*
  585  * Function to check the file table.
  586  * This might be useful after a 'dir' or 'cd' command when
  587  * there might be another path to the same files.
  588  */
  589 
  590 static void CheckLookUpFileTable()
  591 {
  592     int i;
  593     char * newfullname;
  594 
  595     for (i=0; fileTable && i<fileTableSize; i++)
  596         {
  597         if (fileTable[i] != NULL)
  598             {
  599             newfullname = GetPathname(fileTable[i]->filename);
  600             if (newfullname != NULL)
  601                 {
  602                 /* if the two files are different, then it means there
  603                 is a new full path for this file. So we better forget
  604                 everything about the old file.
  605                 */
  606                 if (strcmp (newfullname, fileTable[i]->pathname))
  607                     {
  608                     /* if filenames  are different */
  609                     if (debug)
  610                         fprintf (stderr, "Clearing file table entry \"%s\" : was \"%s\" : is \"%s\"\n",
  611                             fileTable[i]->filename,
  612                             fileTable[i]->pathname,
  613                             newfullname);
  614 
  615                     AppendDialogText("Warning : new path to \"");
  616                     AppendDialogText(fileTable[i]->filename);
  617                     AppendDialogText("\" is \"");
  618                     AppendDialogText(newfullname);
  619                     AppendDialogText("\".\n");
  620 
  621                     if (displayedFile ==  fileTable[i])
  622                         {
  623                         displayedFile = NULL;
  624                         }
  625 
  626                     XtFree((char *)fileTable[i]->buf);
  627                     XtFree((char *)fileTable[i]->linepos);
  628                     XtFree((char *)fileTable[i]);
  629                     fileTable[i] = NULL;
  630                     }
  631                 XtFree (newfullname);
  632                 }
  633             }
  634         }
  635 }
  636 
  637 /*
  638  * Function to clean up the file table and update the
  639  * display if necessary.
  640  *
  641  */
  642 void CleanUpFileTable ()
  643 {
  644     CheckLookUpFileTable();
  645     if (displayedFile == NULL)
  646         LoadCurrentFile();
  647 }
  648 
  649 /*
  650  * Look up the file table for an entry with "filename"
  651  * If not found, create an entry and initialize proper fields,
  652  * else, return pointer to entry found.
  653  */
  654 static int LookUpFileTable(pathname, filename, file)
  655 char *pathname, *filename;
  656 FileRec **file;
  657 {
  658     struct stat fileinfo;
  659     int     fd;
  660     int     i, j, n;
  661     int     available;
  662     
  663     available = -1;
  664 
  665     for (i=0; fileTable && i<fileTableSize; i++) {
  666     if (fileTable[i] == NULL) {
  667         if (available != -1)
  668             available = i;
  669     } else {
  670         if (strcmp(fileTable[i]->pathname, pathname) == 0) /* file found */
  671             {
  672             if (stat(pathname, &fileinfo) == -1)
  673                 {
  674                 UpdateMessageWindow("Error: cannot stat file %s", pathname);
  675                 *file = fileTable[i];
  676                 return 0;
  677                 }
  678 
  679             if (fileinfo.st_mtime > fileTable[i]->mtime) /* file modified */
  680                 {
  681                 XtFree((char *)fileTable[i]->buf);
  682                 XtFree((char *)fileTable[i]->linepos);
  683                 XtFree((char *)fileTable[i]);
  684                 fileTable[i] = NULL;
  685                 UpdateMessageWindow("WARNING : file %s was modified", pathname);
  686                 }
  687 
  688             if (displayedFile &&        /* same as displayed file */
  689                 strcmp(pathname, displayedFile->pathname) == 0)
  690                 {
  691                 if (fileTable[i] == NULL) /* means file was modified */
  692                     displayedFile = NULL;
  693                 else
  694                     {
  695                     *file = NULL;
  696                     return 0;
  697                     }
  698                 }
  699             else
  700                 {
  701                 *file = fileTable[i];
  702                 return 0;
  703                 }
  704             }
  705         }
  706     }
  707 
  708     /* Record file into file table */
  709 
  710     if (available == -1) {      /* file table full, enlarge it */
  711     available = fileTableSize;
  712     fileTableSize += ADD_SIZE;
  713     fileTable = (FileRec **) 
  714              XtRealloc ((void*)fileTable, fileTableSize * sizeof(FileRec *));
  715     for (j=available; j<fileTableSize; j++)
  716         fileTable[j] = NULL;
  717     }
  718 
  719     if ((fd = open(pathname, O_RDONLY)) == -1) {
  720     UpdateMessageWindow("Error: cannot open file %s", pathname);
  721     return -1;
  722     }
  723     if (fstat(fd, &fileinfo) == -1) {
  724     UpdateMessageWindow("Error: cannot fstat file %s", pathname);
  725     close(fd);
  726     return -1;
  727     }
  728     i = available;
  729     fileTable[i] = (FileRec *) XtMalloc (sizeof(FileRec));
  730     fileTable[i]->filesize = fileinfo.st_size + 1;
  731     fileTable[i]->mtime = fileinfo.st_mtime;
  732     fileTable[i]->buf = XtMalloc((int)fileTable[i]->filesize);
  733     if ((n = read(fd, fileTable[i]->buf, (int) fileTable[i]->filesize)) == -1) {
  734     UpdateMessageWindow("Error: cannot read file %s", pathname);
  735     XtFree(fileTable[i]->buf);
  736     XtFree((void*)fileTable[i]);
  737     fileTable[i] = NULL;
  738     close(fd);
  739     return -1;
  740     }
  741     fileTable[i]->buf[n] = '\0';
  742     fileTable[i]->pathname = XtNewString(pathname);
  743     fileTable[i]->filename = XtNewString(filename);
  744     fileTable[i]->currentline = 1;
  745     fileTable[i]->topline = 1;
  746     fileTable[i]->bottomline = 0;
  747     fileTable[i]->topPosition = 0;
  748     BuildLinePos(fileTable[i]);
  749     close(fd);
  750     *file = fileTable[i];
  751     return 0;
  752 }
  753 
  754 /*  
  755  *  Remember file position and current line before closing.
  756  */
  757 static void SaveDisplayedFileInfo()
  758 {
  759     XawTextPosition pos;
  760 
  761     if (displayedFile) {
  762         displayedFile->topPosition = XawTextTopPosition(sourceWindow);
  763     pos = XawTextGetInsertionPoint(sourceWindow);
  764     displayedFile->currentline = TextPositionToLine(pos);
  765     }
  766 }
  767 
  768 
  769 /*   DisplayFile() displays the file onto the source window.  It
  770  *     uses topPosition to remember where it was last opened.  But it
  771  *     must recalculate bottomline because the window size might be
  772  *     different.
  773  */
  774 static void DisplayFile(file)
  775 FileRec *file;
  776 {
  777     Arg     args[MAXARGS];
  778     Cardinal    n;
  779     TextWidget  ctx = (TextWidget) sourceWindow;
  780 
  781     n = 0;
  782     XtSetArg(args[n], XtNdisplayPosition, (XtArgVal)file->topPosition); n++;
  783     XtSetArg(args[n], XtNstring, (XtArgVal) file->pathname);        n++;
  784     XtSetArg(args[n], XtNeditType, (XtArgVal) XawtextRead);     n++;
  785     XtSetValues(sourceWindow, args, n);
  786     file->lines = ctx->text.lt.lines;
  787     file->bottomline = MIN (file->topline + file->lines - 1, file->lastline);
  788 }
  789 
  790 
  791 /*  Given a filename starting with a tilde (`~'), it expands ~[user] to
  792  *  the home directory of that user, or to the login home directory if user
  793  *  is not specified.
  794  */
  795 static char *expand(filename)
  796 char *filename;
  797 {
  798     struct passwd *pwd;
  799     char      *string, *name, newfile[MAXNAME];
  800 
  801     string = XtNewString(filename+1);
  802     if (*string == '\0' || *string == '/')
  803     name = (char *) getlogin();
  804     else
  805         name = (char *) strtok(string, "/");
  806     if (name == NULL)
  807     return filename;
  808     pwd = (struct passwd *) getpwnam(name);
  809     if (pwd && pwd->pw_dir) {
  810         sprintf(newfile, "%s%s", pwd->pw_dir, filename+strlen(name)+1);
  811         return XtNewString(newfile);
  812     }
  813     else
  814     return filename;
  815 }
  816 
  817 
  818 /*  Create a list of directories for searching source files.
  819  *  It reads the list of directories specified by the user, adding
  820  *  the current directory into the list if it is not already there.
  821  *
  822  *  With fix from Dave Gagne (daveg@fs1.ee.ubc.ca) 7/30/90
  823  */
  824 void MakeDirList(output)
  825 char *output;
  826 {
  827     /* fix bug where if text of a directories command is > 1k, crashes.  Now works to 4k */
  828     char *s, list[LINESIZ], command[LINESIZ];
  829     int  i, use_cwd;
  830 
  831     for (i=0; dirList[i]; i++)          /* remove old list */
  832     XtFree(dirList[i]);
  833     i = 0;
  834     use_cwd = TRUE;
  835     if (output) {                                        /* create list */
  836 #ifdef GDB  /* GDB uses ':' as separator character */
  837         s = (char *) strtok(output, ": \n");
  838 #else
  839         s = (char *) strtok(output, " \n");
  840 #endif /* GDB */
  841         while (s) {
  842             dirList[i] = XtNewString(s);
  843 
  844             if (dirList[i][0] == '~')                   /* expand '~' */
  845                 dirList[i] = expand(dirList[i]);
  846             if (LASTCH(dirList[i]) == '/')              /* remove last '/' */
  847                 LASTCH(dirList[i]) = '\0';
  848             if (strcmp(dirList[i], ".") == 0)        /* watch for "." */
  849                 use_cwd = FALSE;
  850 
  851             ++i;
  852 #ifdef GDB  /* GDB uses ':' as separator character */
  853             s = (char *) strtok(NULL, ": \n");
  854 #else
  855             s = (char *) strtok(NULL, " \n");
  856 #endif /* GDB */
  857         }
  858         dirList[i] = NULL;
  859     }
  860 
  861     if (use_cwd) {              /* include current dir */
  862     dirList[i++] = XtNewString(".");        
  863         dirList[i] = NULL;
  864     }
  865 
  866 #if defined(NeXT) && defined(GDB)
  867     /* for NeXT computer, send 'directory' command for each directory */
  868     for (i=0; dirList[i]; i++) {
  869     sprintf(command, "directory %s\n", dirList[i]);
  870     query_gdb (command, PARSE_OFF | ECHO_OFF | FILTER_OFF);
  871     }
  872 #else /* not NeXT */
  873     strcpy(list, "");               /* tell dbx our new list */
  874     for (i=0; dirList[i]; i++) {
  875     strcat(list, dirList[i]);
  876     strcat(list, " ");
  877     }
  878 #ifdef GDB
  879     sprintf(command, "directory %s\n", list);
  880     query_gdb (command, PARSE_OFF | ECHO_OFF | FILTER_OFF);
  881 #else
  882     sprintf(command, "use %s\n", list);
  883     Parse = False;
  884     query_dbx(command);
  885 #endif /* GDB */
  886 #endif /* not NeXT */
  887 }
  888 
  889 /*  Returns the full pathname of a given file.
  890  *  It searches for the file from a list of directories.
  891  */
  892 char *GetPathname(filename)
  893 char *filename;
  894 {
  895     char    pathname[LINESIZ];
  896     int     i;
  897 
  898     if (filename == NULL || strcmp(filename, "") == 0)
  899         return NULL;
  900     for (i=0; dirList[i]; i++) {
  901         if (*filename == '/' && access(filename, R_OK) == -1) { 
  902             /* this handles the exceptional case of sun4 dbx output */
  903             strcpy(filename, &filename[1]);
  904         }
  905         if (*filename == '/' || *filename == '~')
  906             strcpy(pathname, filename);
  907         else if (strcmp(dirList[i], ".") == 0)
  908             sprintf(pathname, "%s/%s", cwd, filename);
  909          
  910 #ifdef GDB  /* (PW)(SH)11SEP91 : for gdb 4.0 */
  911         else if (strcmp(dirList[i], "$cwd") == 0)
  912             sprintf(pathname, "%s/%s", cwd, filename);
  913         else if (strcmp(dirList[i], "$cdir") == 0)
  914             sprintf(pathname, "%s/%s", cdir, filename);
  915 #endif /* GDB */
  916 
  917         else if (*dirList[i] == '/' || *dirList[i] == '~')
  918             sprintf(pathname, "%s/%s", dirList[i], filename);
  919         else
  920             sprintf(pathname, "%s/%s/%s", cwd, dirList[i], filename);
  921 
  922 #ifdef GDB 
  923         simplify_path (pathname);  /* be sure to get only significant path */
  924 #endif       
  925 
  926         if (access(pathname, R_OK) == 0) {
  927             if (debug)
  928                 fprintf(stderr,"Full path of %s is \"%s\"\n", filename, pathname);
  929             return XtNewString(pathname);
  930         }
  931 
  932         if (*filename == '/' || *filename == '~') {
  933             break;  /* no need to loop over all directories */
  934         }
  935     }
  936     UpdateMessageWindow("File not found: %s", filename);
  937     bell(0);
  938     return NULL;
  939 }
  940 
  941 /*
  942  * Given a file name, LoadFile attempts to open it and displays it onto
  943  * the source window:
  944  *   1. get the full pathname of the file
  945  *   2. LookUpFileTable() returns a pointer to the file's entry if it's
  946  *      already in the table; else, creates an entry and return a pointer.
  947  *   3. save the current displayedFile info
  948  *   4. display the file
  949  *   5. update the file label and the various signs on the source window.
  950  *  LoadFile returns 0 upon successful completion, -1 otherwise.
  951  */
  952 int LoadFile(filename)
  953 char *filename;
  954 {
  955     FileRec     *file;
  956     char    *pathname;
  957 
  958     pathname = GetPathname(filename);
  959     if (pathname == NULL) { 
  960     return -1;
  961     }
  962     if (LookUpFileTable(pathname, filename, &file) != -1) {
  963     if (file) { /* load new file */
  964         SaveDisplayedFileInfo();
  965         DisplayFile(file);
  966         UpdateFileLabel(pathname);
  967         XawTextUnsetSelection(sourceWindow);
  968         XawTextSetInsertionPoint(sourceWindow, file->linepos[file->currentline]);
  969         UpdateLineLabel(file->currentline);
  970         UpdateStops(file);
  971         UpdateArrow(file);
  972         UpdateUpdown(file);
  973         UpdateBomb(file);
  974         displayedFile = file;
  975     }
  976         return 0;
  977     }
  978     else {      /* LookUpFileTable() fails */
  979         return -1;
  980     }
  981 }
  982 
  983 int LoadCurrentFile()
  984 {
  985 #ifdef GDB
  986     query_gdb ("info line\n", PARSE_ON | ECHO_OFF | FILTER_OFF);
  987 #else
  988     query_dbx("file\n");
  989 #endif /* GDB */
  990     return LoadFile(CurrentFile);
  991 }
  992 
  993 #ifdef EDIT_BUTTON
  994 /* simply add editor button that calls  $XXGDBWINEDIT, $WINEDIT, xxgdbedit in that order */
  995 /* allow invocation of fav. editor from within interface */
  996 /* button and the EdAction action procedure for the source window */
  997 void StartEditor ()
  998 {
  999   XawTextPosition pos;
 1000   char* editor;
 1001   char string[128];
 1002   int result;
 1003   
 1004   if (displayedFile == NULL) return;
 1005   editor = (char *) getenv("XXGDBWINEDIT");
 1006   if (editor == NULL)
 1007     editor = (char *) getenv("WINEDIT");
 1008   if (editor == NULL)
 1009     editor = "xxgdbedit";
 1010   pos = XawTextGetInsertionPoint(sourceWindow);
 1011   displayedFile->currentline = TextPositionToLine(pos);
 1012   sprintf(string, "nohup %s +%d %s&\n",
 1013       editor, displayedFile->currentline, displayedFile->pathname);
 1014   result =  system(string);
 1015   printf("result from system call: %d \n", result);
 1016   /* the following is more efficient but needs some work
 1017   {
 1018   int pid;
 1019   if (!(pid = fork()))
 1020     { 
 1021       execlp(editor, editor, linenum, displayedFile->pathname, (char *) 0);
 1022       printf("editor command fails\n");
 1023     }
 1024   else 
 1025     {
 1026       if (pid == -1) printf("unable to start editor\n");
 1027     }
 1028   }
 1029   */
 1030 }
 1031 #endif /* EDIT_BUTTON */
 1032 
 1033 #ifdef GDB
 1034 /*
 1035  * Function to get the full path of a source file.
 1036  *
 1037  * This function is implemented by doing a 'list sourcefile;1'
 1038  * and then a 'info source'. That is the only way I found to
 1039  * get this fullpath. If there is a better way, change here.
 1040  *
 1041  * Note that we have to save and restore the current source
 1042  * file in case it is not the same as 'filename'.
 1043  *
 1044  */
 1045 char *
 1046 GetSourcePathname (filename)
 1047 char *filename;
 1048 {
 1049 char *srcpath;
 1050 char curr_src [MAXPATHLEN];
 1051 char list_src_cmd [MAXPATHLEN+10]; /* +10 for room for "list :1\n" */
 1052 
 1053     if (filename == NULL || strcmp(filename, "") == 0)
 1054     return NULL;
 1055 
 1056     /* (PW)19NOV93: it is important to get new string because,
 1057        "info source" below will free Token.file (which could be
 1058        same as filename here.
 1059        */
 1060 
 1061     filename = XtNewString (filename);
 1062 
 1063     /* get current source */
 1064 
 1065     query_gdb("info source\n", PARSE_ON | ECHO_OFF | FILTER_OFF);
 1066     
 1067     strcpy (curr_src, source_path);
 1068 
 1069     if (*curr_src == 0) {
 1070         srcpath = GetPathname (filename);   /* when info source is not supported */
 1071     } else {
 1072 
 1073         /* tell gdb to go to filename */
 1074 
 1075         sprintf (list_src_cmd,"list %s:1\n", filename);
 1076 
 1077         query_gdb(list_src_cmd, PARSE_OFF | ECHO_OFF | FILTER_OFF);
 1078 
 1079         /* get source of filename  */
 1080 
 1081         query_gdb("info source\n", PARSE_ON | ECHO_OFF | FILTER_OFF);
 1082 
 1083         if (*source_fullpath)
 1084             srcpath = XtNewString (source_fullpath);
 1085         else
 1086             srcpath = NULL;
 1087 
 1088         /* reset original source */
 1089 
 1090         sprintf (list_src_cmd,"list %s:1\n", curr_src);
 1091 
 1092         query_gdb(list_src_cmd, PARSE_OFF | ECHO_OFF | FILTER_OFF);
 1093 
 1094         if (srcpath == NULL)
 1095             srcpath = GetPathname (filename);   /* when info source is not supported */
 1096     }
 1097 
 1098     XtFree (filename);
 1099 
 1100     return  srcpath;
 1101 }
 1102 #endif /* GDB */