gdb-3.5
[binutils-gdb.git] / gdb / source.c
1 /* List lines of source files for GDB, the GNU debugger.
2 Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 GDB is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GDB is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GDB; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include <stdio.h>
21 #include "defs.h"
22 #include "symtab.h"
23 #include "param.h"
24
25 #ifdef USG
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #endif
29
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/file.h>
33
34 /* Path of directories to search for source files.
35 Same format as the PATH environment variable's value. */
36
37 static char *source_path;
38
39 /* Symtab of default file for listing lines of. */
40
41 struct symtab *current_source_symtab;
42
43 /* Default next line to list. */
44
45 int current_source_line;
46
47 /* Line number of last line printed. Default for various commands.
48 current_source_line is usually, but not always, the same as this. */
49
50 static int last_line_listed;
51
52 /* First line number listed by last listing command. */
53
54 static int first_line_listed;
55
56 \f
57 struct symtab *psymtab_to_symtab ();
58
59 /* Set the source file default for the "list" command, specifying a
60 symtab. Sigh. Behaivior specification: If it is called with a
61 non-zero argument, that is the symtab to select. If it is not,
62 first lookup "main"; if it exists, use the symtab and line it
63 defines. If not, take the last symtab in the symtab_list (if it
64 exists) or the last symtab in the psytab_list (if *it* exists). If
65 none of this works, report an error. */
66
67 void
68 select_source_symtab (s)
69 register struct symtab *s;
70 {
71 struct symtabs_and_lines sals;
72 struct symtab_and_line sal;
73 struct partial_symtab *ps, *cs_pst;
74
75 if (s)
76 {
77 current_source_symtab = s;
78 current_source_line = 1;
79 return;
80 }
81
82 /* Make the default place to list be the function `main'
83 if one exists. */
84 if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0))
85 {
86 sals = decode_line_spec ("main", 1);
87 sal = sals.sals[0];
88 free (sals.sals);
89 current_source_symtab = sal.symtab;
90 current_source_line = max (sal.line - 9, 1);
91 return;
92 }
93
94 /* All right; find the last file in the symtab list (ignoring .h's). */
95
96 if (s = symtab_list)
97 {
98 do
99 {
100 char *name = s->filename;
101 int len = strlen (name);
102 if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
103 current_source_symtab = s;
104 s = s->next;
105 }
106 while (s);
107 current_source_line = 1;
108 }
109 else if (partial_symtab_list)
110 {
111 ps = partial_symtab_list;
112 while (ps)
113 {
114 char *name = ps->filename;
115 int len = strlen (name);
116 if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
117 cs_pst = ps;
118 ps = ps->next;
119 }
120 if (cs_pst)
121 if (cs_pst->readin)
122 fatal ("Internal: select_source_symtab: readin pst found and no symtabs.");
123 else
124 current_source_symtab = psymtab_to_symtab (cs_pst);
125 else
126 current_source_symtab = 0;
127 current_source_line = 1;
128 }
129 }
130 \f
131 static void
132 directories_info ()
133 {
134 printf ("Source directories searched: %s\n", source_path);
135 }
136
137 void
138 init_source_path ()
139 {
140 register struct symtab *s;
141
142 source_path = savestring (current_directory, strlen (current_directory));
143
144 /* Forget what we learned about line positions in source files;
145 must check again now since files may be found in
146 a different directory now. */
147 for (s = symtab_list; s; s = s->next)
148 if (s->line_charpos != 0)
149 {
150 free (s->line_charpos);
151 s->line_charpos = 0;
152 }
153 }
154
155 void
156 directory_command (dirname, from_tty)
157 char *dirname;
158 int from_tty;
159 {
160 char *old = source_path;
161
162 dont_repeat ();
163
164 if (dirname == 0)
165 {
166 if (query ("Reinitialize source path to %s? ", current_directory))
167 {
168 init_source_path ();
169 free (old);
170 }
171 }
172 else
173 {
174 dirname = tilde_expand (dirname);
175 make_cleanup (free, dirname);
176
177 do
178 {
179 extern char *index ();
180 char *name = dirname;
181 register char *p;
182 struct stat st;
183
184 {
185 char *colon = index (name, ':');
186 char *space = index (name, ' ');
187 char *tab = index (name, '\t');
188 if (colon == 0 && space == 0 && tab == 0)
189 p = dirname = name + strlen (name);
190 else
191 {
192 p = 0;
193 if (colon != 0 && (p == 0 || colon < p))
194 p = colon;
195 if (space != 0 && (p == 0 || space < p))
196 p = space;
197 if (tab != 0 && (p == 0 || tab < p))
198 p = tab;
199 dirname = p + 1;
200 while (*dirname == ':' || *dirname == ' ' || *dirname == '\t')
201 ++dirname;
202 }
203 }
204
205 if (p[-1] == '/')
206 /* Sigh. "foo/" => "foo" */
207 --p;
208 *p = '\0';
209
210 while (p[-1] == '.')
211 {
212 if (p - name == 1)
213 {
214 /* "." => getwd (). */
215 name = current_directory;
216 goto append;
217 }
218 else if (p[-2] == '/')
219 {
220 if (p - name == 2)
221 {
222 /* "/." => "/". */
223 *--p = '\0';
224 goto append;
225 }
226 else
227 {
228 /* "...foo/." => "...foo". */
229 p -= 2;
230 *p = '\0';
231 continue;
232 }
233 }
234 else
235 break;
236 }
237
238 if (*name != '/')
239 name = concat (current_directory, "/", name);
240 else
241 name = savestring (name, p - name);
242 make_cleanup (free, name);
243
244 if (stat (name, &st) < 0)
245 perror_with_name (name);
246 if ((st.st_mode & S_IFMT) != S_IFDIR)
247 error ("%s is not a directory.", name);
248
249 append:
250 {
251 register unsigned int len = strlen (name);
252
253 p = source_path;
254 while (1)
255 {
256 if (!strncmp (p, name, len)
257 && (p[len] == '\0' || p[len] == ':'))
258 {
259 if (from_tty)
260 printf ("\"%s\" is already in the source path.\n", name);
261 break;
262 }
263 p = index (p, ':');
264 if (p != 0)
265 ++p;
266 else
267 break;
268 }
269 if (p == 0)
270 {
271 source_path = concat (old, ":", name);
272 free (old);
273 old = source_path;
274 }
275 }
276 } while (*dirname != '\0');
277 if (from_tty)
278 directories_info ();
279 }
280 }
281 \f
282 /* Open a file named STRING, searching path PATH (dir names sep by colons)
283 using mode MODE and protection bits PROT in the calls to open.
284 If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
285 (ie pretend the first element of PATH is ".")
286 If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
287 the actual file opened (this string will always start with a "/"
288
289 If a file is found, return the descriptor.
290 Otherwise, return -1, with errno set for the last name we tried to open. */
291
292 /* >>>> This should only allow files of certain types,
293 >>>> eg executable, non-directory */
294 int
295 openp (path, try_cwd_first, string, mode, prot, filename_opened)
296 char *path;
297 int try_cwd_first;
298 char *string;
299 int mode;
300 int prot;
301 char **filename_opened;
302 {
303 register int fd;
304 register char *filename;
305 register char *p, *p1;
306 register int len;
307
308 if (!path)
309 path = ".";
310
311 /* ./foo => foo */
312 while (string[0] == '.' && string[1] == '/')
313 string += 2;
314
315 if (try_cwd_first || string[0] == '/')
316 {
317 filename = string;
318 fd = open (filename, mode, prot);
319 if (fd >= 0 || string[0] == '/')
320 goto done;
321 }
322
323 filename = (char *) alloca (strlen (path) + strlen (string) + 2);
324 fd = -1;
325 for (p = path; p; p = p1 ? p1 + 1 : 0)
326 {
327 p1 = (char *) index (p, ':');
328 if (p1)
329 len = p1 - p;
330 else
331 len = strlen (p);
332
333 strncpy (filename, p, len);
334 filename[len] = 0;
335 strcat (filename, "/");
336 strcat (filename, string);
337
338 fd = open (filename, mode, prot);
339 if (fd >= 0) break;
340 }
341
342 done:
343 if (filename_opened)
344 if (fd < 0)
345 *filename_opened = (char *) 0;
346 else if (filename[0] == '/')
347 *filename_opened = savestring (filename, strlen (filename));
348 else
349 {
350 *filename_opened = concat (current_directory, "/", filename);
351 }
352
353 return fd;
354 }
355 \f
356 /* Create and initialize the table S->line_charpos that records
357 the positions of the lines in the source file, which is assumed
358 to be open on descriptor DESC.
359 All set S->nlines to the number of such lines. */
360
361 static void
362 find_source_lines (s, desc)
363 struct symtab *s;
364 int desc;
365 {
366 struct stat st;
367 register char *data, *p, *end;
368 int nlines = 0;
369 int lines_allocated = 1000;
370 int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
371 extern int exec_mtime;
372
373 if (fstat (desc, &st) < 0)
374 perror_with_name (s->filename);
375 if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
376 printf ("Source file is more recent than executable.\n");
377
378 data = (char *) alloca (st.st_size);
379 if (myread (desc, data, st.st_size) < 0)
380 perror_with_name (s->filename);
381 end = data + st.st_size;
382 p = data;
383 line_charpos[0] = 0;
384 nlines = 1;
385 while (p != end)
386 {
387 if (*p++ == '\n'
388 /* A newline at the end does not start a new line. */
389 && p != end)
390 {
391 if (nlines == lines_allocated)
392 {
393 lines_allocated *= 2;
394 line_charpos = (int *) xrealloc (line_charpos,
395 sizeof (int) * lines_allocated);
396 }
397 line_charpos[nlines++] = p - data;
398 }
399 }
400 s->nlines = nlines;
401 s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
402 }
403
404 /* Return the character position of a line LINE in symtab S.
405 Return 0 if anything is invalid. */
406
407 int
408 source_line_charpos (s, line)
409 struct symtab *s;
410 int line;
411 {
412 if (!s) return 0;
413 if (!s->line_charpos || line <= 0) return 0;
414 if (line > s->nlines)
415 line = s->nlines;
416 return s->line_charpos[line - 1];
417 }
418
419 /* Return the line number of character position POS in symtab S. */
420
421 int
422 source_charpos_line (s, chr)
423 register struct symtab *s;
424 register int chr;
425 {
426 register int line = 0;
427 register int *lnp;
428
429 if (s == 0 || s->line_charpos == 0) return 0;
430 lnp = s->line_charpos;
431 /* Files are usually short, so sequential search is Ok */
432 while (line < s->nlines && *lnp <= chr)
433 {
434 line++;
435 lnp++;
436 }
437 if (line >= s->nlines)
438 line = s->nlines;
439 return line;
440 }
441 \f
442 /* Get full pathname and line number positions for a symtab.
443 Return nonzero if line numbers may have changed.
444 Set *FULLNAME to actual name of the file as found by `openp',
445 or to 0 if the file is not found. */
446
447 int
448 get_filename_and_charpos (s, line, fullname)
449 struct symtab *s;
450 int line;
451 char **fullname;
452 {
453 register int desc, linenums_changed = 0;
454
455 desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
456 if (desc < 0)
457 {
458 if (fullname)
459 *fullname = NULL;
460 return 0;
461 }
462 if (fullname)
463 *fullname = s->fullname;
464 if (s->line_charpos == 0) linenums_changed = 1;
465 if (linenums_changed) find_source_lines (s, desc);
466 close (desc);
467 return linenums_changed;
468 }
469
470 /* Print text describing the full name of the source file S
471 and the line number LINE and its corresponding character position.
472 The text starts with two Ctrl-z so that the Emacs-GDB interface
473 can easily find it.
474
475 MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
476
477 Return 1 if successful, 0 if could not find the file. */
478
479 int
480 identify_source_line (s, line, mid_statement)
481 struct symtab *s;
482 int line;
483 int mid_statement;
484 {
485 if (s->line_charpos == 0)
486 get_filename_and_charpos (s, line, 0);
487 if (s->fullname == 0)
488 return 0;
489 printf ("\032\032%s:%d:%d:%s:0x%x\n", s->fullname,
490 line, s->line_charpos[line - 1],
491 mid_statement ? "middle" : "beg",
492 get_frame_pc (get_current_frame()));
493 current_source_line = line;
494 first_line_listed = line;
495 last_line_listed = line;
496 current_source_symtab = s;
497 return 1;
498 }
499 \f
500 /* Print source lines from the file of symtab S,
501 starting with line number LINE and stopping before line number STOPLINE. */
502
503 void
504 print_source_lines (s, line, stopline, noerror)
505 struct symtab *s;
506 int line, stopline;
507 int noerror;
508 {
509 register int c;
510 register int desc;
511 register FILE *stream;
512 int nlines = stopline - line;
513
514 desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
515 if (desc < 0)
516 {
517 extern int errno;
518 if (! noerror)
519 perror_with_name (s->filename);
520 print_sys_errmsg (s->filename, errno);
521 return;
522 }
523
524 if (s->line_charpos == 0)
525 find_source_lines (s, desc);
526
527 if (line < 1 || line > s->nlines)
528 {
529 close (desc);
530 error ("Line number %d out of range; %s has %d lines.",
531 line, s->filename, s->nlines);
532 }
533
534 if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
535 {
536 close (desc);
537 perror_with_name (s->filename);
538 }
539
540 current_source_symtab = s;
541 current_source_line = line;
542 first_line_listed = line;
543
544 stream = fdopen (desc, "r");
545 clearerr (stream);
546
547 while (nlines-- > 0)
548 {
549 c = fgetc (stream);
550 if (c == EOF) break;
551 last_line_listed = current_source_line;
552 printf_filtered ("%d\t", current_source_line++);
553 do
554 {
555 if (c < 040 && c != '\t' && c != '\n')
556 printf_filtered ("^%c", c + 0100);
557 else if (c == 0177)
558 printf_filtered ("^?");
559 else
560 printf_filtered ("%c", c);
561 } while (c != '\n' && (c = fgetc (stream)) >= 0);
562 }
563
564 fclose (stream);
565 }
566 \f
567
568
569 /*
570 C++
571 Print a list of files and line numbers which a user may choose from
572 in order to list a function which was specified ambiguously
573 (as with `list classname::overloadedfuncname', for example).
574 The vector in SALS provides the filenames and line numbers.
575 */
576 static void
577 ambiguous_line_spec (sals)
578 struct symtabs_and_lines *sals;
579 {
580 int i;
581
582 for (i = 0; i < sals->nelts; ++i)
583 printf("file: \"%s\", line number: %d\n",
584 sals->sals[i].symtab->filename, sals->sals[i].line);
585 }
586
587
588 static void
589 list_command (arg, from_tty)
590 char *arg;
591 int from_tty;
592 {
593 struct symtabs_and_lines sals, sals_end;
594 struct symtab_and_line sal, sal_end;
595 struct symbol *sym;
596 char *arg1;
597 int no_end = 1;
598 int dummy_end = 0;
599 int dummy_beg = 0;
600 int linenum_beg = 0;
601 char *p;
602
603 if (symtab_list == 0 && partial_symtab_list == 0)
604 error ("No symbol table is loaded. Use the \"symbol-file\" command.");
605
606 /* Pull in a current source symtab if necessary */
607 if (current_source_symtab == 0 &&
608 (arg == 0 || arg[0] == '+' || arg[0] == '-'))
609 select_source_symtab (0);
610
611 /* "l" or "l +" lists next ten lines. */
612
613 if (arg == 0 || !strcmp (arg, "+"))
614 {
615 if (current_source_symtab == 0)
616 error ("No default source file yet. Do \"help list\".");
617 print_source_lines (current_source_symtab, current_source_line,
618 current_source_line + 10, 0);
619 return;
620 }
621
622 /* "l -" lists previous ten lines, the ones before the ten just listed. */
623 if (!strcmp (arg, "-"))
624 {
625 if (current_source_symtab == 0)
626 error ("No default source file yet. Do \"help list\".");
627 print_source_lines (current_source_symtab,
628 max (first_line_listed - 10, 1),
629 first_line_listed, 0);
630 return;
631 }
632
633 /* Now if there is only one argument, decode it in SAL
634 and set NO_END.
635 If there are two arguments, decode them in SAL and SAL_END
636 and clear NO_END; however, if one of the arguments is blank,
637 set DUMMY_BEG or DUMMY_END to record that fact. */
638
639 arg1 = arg;
640 if (*arg1 == ',')
641 dummy_beg = 1;
642 else
643 {
644 sals = decode_line_1 (&arg1, 0, 0, 0);
645
646 if (! sals.nelts) return; /* C++ */
647 if (sals.nelts > 1)
648 {
649 ambiguous_line_spec (&sals);
650 free (sals.sals);
651 return;
652 }
653
654 sal = sals.sals[0];
655 free (sals.sals);
656 }
657
658 /* Record whether the BEG arg is all digits. */
659
660 for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
661 linenum_beg = (p == arg1);
662
663 while (*arg1 == ' ' || *arg1 == '\t')
664 arg1++;
665 if (*arg1 == ',')
666 {
667 no_end = 0;
668 arg1++;
669 while (*arg1 == ' ' || *arg1 == '\t')
670 arg1++;
671 if (*arg1 == 0)
672 dummy_end = 1;
673 else
674 {
675 if (dummy_beg)
676 sals_end = decode_line_1 (&arg1, 0, 0, 0);
677 else
678 sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
679 if (sals_end.nelts == 0)
680 return;
681 if (sals_end.nelts > 1)
682 {
683 ambiguous_line_spec (&sals_end);
684 free (sals_end.sals);
685 return;
686 }
687 sal_end = sals_end.sals[0];
688 free (sals_end.sals);
689 }
690 }
691
692 if (*arg1)
693 error ("Junk at end of line specification.");
694
695 if (!no_end && !dummy_beg && !dummy_end
696 && sal.symtab != sal_end.symtab)
697 error ("Specified start and end are in different files.");
698 if (dummy_beg && dummy_end)
699 error ("Two empty args do not say what lines to list.");
700
701 /* if line was specified by address,
702 first print exactly which line, and which file.
703 In this case, sal.symtab == 0 means address is outside
704 of all known source files, not that user failed to give a filename. */
705 if (*arg == '*')
706 {
707 if (sal.symtab == 0)
708 error ("No source file for address 0x%x.", sal.pc);
709 sym = find_pc_function (sal.pc);
710 if (sym)
711 printf ("0x%x is in %s (%s, line %d).\n",
712 sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
713 else
714 printf ("0x%x is in %s, line %d.\n",
715 sal.pc, sal.symtab->filename, sal.line);
716 }
717
718 /* If line was not specified by just a line number,
719 and it does not imply a symtab, it must be an undebuggable symbol
720 which means no source code. */
721
722 if (! linenum_beg && sal.symtab == 0)
723 error ("No line number known for %s.", arg);
724
725 /* If this command is repeated with RET,
726 turn it into the no-arg variant. */
727
728 if (from_tty)
729 *arg = 0;
730
731 if (dummy_beg && sal_end.symtab == 0)
732 error ("No default source file yet. Do \"help list\".");
733 if (dummy_beg)
734 print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1),
735 sal_end.line + 1, 0);
736 else if (sal.symtab == 0)
737 error ("No default source file yet. Do \"help list\".");
738 else if (no_end)
739 print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5, 0);
740 else
741 print_source_lines (sal.symtab, sal.line,
742 dummy_end ? sal.line + 10 : sal_end.line + 1,
743 0);
744 }
745 \f
746 /* Print info on range of pc's in a specified line. */
747
748 static void
749 line_info (arg, from_tty)
750 char *arg;
751 int from_tty;
752 {
753 struct symtabs_and_lines sals;
754 struct symtab_and_line sal;
755 int start_pc, end_pc;
756 int i;
757
758 if (arg == 0)
759 {
760 sal.symtab = current_source_symtab;
761 sal.line = last_line_listed;
762 sals.nelts = 1;
763 sals.sals = (struct symtab_and_line *)
764 xmalloc (sizeof (struct symtab_and_line));
765 sals.sals[0] = sal;
766 }
767 else
768 {
769 sals = decode_line_spec_1 (arg, 0);
770
771 /* If this command is repeated with RET,
772 turn it into the no-arg variant. */
773 if (from_tty)
774 *arg = 0;
775 }
776
777 /* C++ More than one line may have been specified, as when the user
778 specifies an overloaded function name. Print info on them all. */
779 for (i = 0; i < sals.nelts; i++)
780 {
781 sal = sals.sals[i];
782
783 if (sal.symtab == 0)
784 error ("No source file specified.");
785
786 if (sal.line > 0
787 && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
788 {
789 if (start_pc == end_pc)
790 printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
791 sal.line, sal.symtab->filename, start_pc);
792 else
793 printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
794 sal.line, sal.symtab->filename, start_pc, end_pc);
795 /* x/i should display this line's code. */
796 set_next_address (start_pc);
797 /* Repeating "info line" should do the following line. */
798 last_line_listed = sal.line + 1;
799 }
800 else
801 printf ("Line number %d is out of range for \"%s\".\n",
802 sal.line, sal.symtab->filename);
803 }
804 }
805 \f
806 /* Commands to search the source file for a regexp. */
807
808 static void
809 forward_search_command (regex, from_tty)
810 char *regex;
811 {
812 register int c;
813 register int desc;
814 register FILE *stream;
815 int line = last_line_listed + 1;
816 char *msg;
817
818 msg = (char *) re_comp (regex);
819 if (msg)
820 error (msg);
821
822 if (current_source_symtab == 0)
823 select_source_symtab (0);
824
825 /* Search from last_line_listed+1 in current_source_symtab */
826
827 desc = openp (source_path, 0, current_source_symtab->filename,
828 O_RDONLY, 0, &current_source_symtab->fullname);
829 if (desc < 0)
830 perror_with_name (current_source_symtab->filename);
831
832 if (current_source_symtab->line_charpos == 0)
833 find_source_lines (current_source_symtab, desc);
834
835 if (line < 1 || line > current_source_symtab->nlines)
836 {
837 close (desc);
838 error ("Expression not found");
839 }
840
841 if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
842 {
843 close (desc);
844 perror_with_name (current_source_symtab->filename);
845 }
846
847 stream = fdopen (desc, "r");
848 clearerr (stream);
849 while (1) {
850 char buf[4096]; /* Should be reasonable??? */
851 register char *p = buf;
852
853 c = fgetc (stream);
854 if (c == EOF)
855 break;
856 do {
857 *p++ = c;
858 } while (c != '\n' && (c = fgetc (stream)) >= 0);
859
860 /* we now have a source line in buf, null terminate and match */
861 *p = 0;
862 if (re_exec (buf) > 0)
863 {
864 /* Match! */
865 fclose (stream);
866 print_source_lines (current_source_symtab,
867 line, line+1, 0);
868 current_source_line = max (line - 5, 1);
869 return;
870 }
871 line++;
872 }
873
874 printf ("Expression not found\n");
875 fclose (stream);
876 }
877
878 static void
879 reverse_search_command (regex, from_tty)
880 char *regex;
881 {
882 register int c;
883 register int desc;
884 register FILE *stream;
885 int line = last_line_listed - 1;
886 char *msg;
887
888 msg = (char *) re_comp (regex);
889 if (msg)
890 error (msg);
891
892 if (current_source_symtab == 0)
893 select_source_symtab (0);
894
895 /* Search from last_line_listed-1 in current_source_symtab */
896
897 desc = openp (source_path, 0, current_source_symtab->filename,
898 O_RDONLY, 0, &current_source_symtab->fullname);
899 if (desc < 0)
900 perror_with_name (current_source_symtab->filename);
901
902 if (current_source_symtab->line_charpos == 0)
903 find_source_lines (current_source_symtab, desc);
904
905 if (line < 1 || line > current_source_symtab->nlines)
906 {
907 close (desc);
908 error ("Expression not found");
909 }
910
911 if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
912 {
913 close (desc);
914 perror_with_name (current_source_symtab->filename);
915 }
916
917 stream = fdopen (desc, "r");
918 clearerr (stream);
919 while (1)
920 {
921 char buf[4096]; /* Should be reasonable??? */
922 register char *p = buf;
923
924 c = fgetc (stream);
925 if (c == EOF)
926 break;
927 do {
928 *p++ = c;
929 } while (c != '\n' && (c = fgetc (stream)) >= 0);
930
931 /* We now have a source line in buf; null terminate and match. */
932 *p = 0;
933 if (re_exec (buf) > 0)
934 {
935 /* Match! */
936 fclose (stream);
937 print_source_lines (current_source_symtab,
938 line, line+1, 0);
939 current_source_line = max (line - 5, 1);
940 return;
941 }
942 line--;
943 if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
944 {
945 fclose (stream);
946 perror_with_name (current_source_symtab->filename);
947 }
948 }
949
950 printf ("Expression not found\n");
951 fclose (stream);
952 return;
953 }
954 \f
955 void
956 _initialize_source ()
957 {
958 current_source_symtab = 0;
959 init_source_path ();
960
961 add_com ("directory", class_files, directory_command,
962 "Add directory DIR to end of search path for source files.\n\
963 With no argument, reset the search path to just the working directory\n\
964 and forget cached info on line positions in source files.");
965
966 add_info ("directories", directories_info,
967 "Current search path for finding source files.");
968
969 add_info ("line", line_info,
970 "Core addresses of the code for a source line.\n\
971 Line can be specified as\n\
972 LINENUM, to list around that line in current file,\n\
973 FILE:LINENUM, to list around that line in that file,\n\
974 FUNCTION, to list around beginning of that function,\n\
975 FILE:FUNCTION, to distinguish among like-named static functions.\n\
976 Default is to describe the last source line that was listed.\n\n\
977 This sets the default address for \"x\" to the line's first instruction\n\
978 so that \"x/i\" suffices to start examining the machine code.\n\
979 The address is also stored as the value of \"$_\".");
980
981 add_com ("forward-search", class_files, forward_search_command,
982 "Search for regular expression (see regex(3)) from last line listed.");
983 add_com_alias ("search", "forward-search", class_files, 0);
984
985 add_com ("reverse-search", class_files, reverse_search_command,
986 "Search backward for regular expression (see regex(3)) from last line listed.");
987
988 add_com ("list", class_files, list_command,
989 "List specified function or line.\n\
990 With no argument, lists ten more lines after or around previous listing.\n\
991 \"list -\" lists the ten lines before a previous ten-line listing.\n\
992 One argument specifies a line, and ten lines are listed around that line.\n\
993 Two arguments with comma between specify starting and ending lines to list.\n\
994 Lines can be specified in these ways:\n\
995 LINENUM, to list around that line in current file,\n\
996 FILE:LINENUM, to list around that line in that file,\n\
997 FUNCTION, to list around beginning of that function,\n\
998 FILE:FUNCTION, to distinguish among like-named static functions.\n\
999 *ADDRESS, to list around the line containing that address.\n\
1000 With two args if one is empty it stands for ten lines away from the other arg.");
1001 }
1002