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 #if !defined(NeXT) && !defined(__FreeBSD__) && !defined(__DragonFly__)
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 
source_init()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 */
Update(w,event,params,num_params)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 */
NotifyResize(w,event,params,num_params)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
UpdateLine(w,event,params,num_params)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 */
SelectStart(w,event,params,num_params)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 */
SelectEnd(w,event,params,num_params)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 */
SelectWord(w,event,params,num_params)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 */
PrintSelection(w,event,params,num_params)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();
EdAction(w,event,params,num_params)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();
Search(w,event,params,num_params)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 
CreateSourceWindow(parent)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  */
BuildLinePos(file)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 
CheckLookUpFileTable()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  */
CleanUpFileTable()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  */
LookUpFileTable(pathname,filename,file)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  */
SaveDisplayedFileInfo()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  */
DisplayFile(file)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  */
expand(filename)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  */
MakeDirList(output)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  */
GetPathname(filename)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  */
LoadFile(filename)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 
LoadCurrentFile()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 */
StartEditor()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 *
GetSourcePathname(filename)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 */
1103