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