gdb-3.3
[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 "defs.h"
21 #include "symtab.h"
22 #include "param.h"
23
24 #ifdef USG
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #endif
28
29 #include <stdio.h>
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 fstat (desc, &st);
374 if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime)
375 printf ("Source file is more recent than executable.\n");
376
377 data = (char *) alloca (st.st_size);
378 myread (desc, data, st.st_size);
379 end = data + st.st_size;
380 p = data;
381 line_charpos[0] = 0;
382 nlines = 1;
383 while (p != end)
384 {
385 if (*p++ == '\n'
386 /* A newline at the end does not start a new line. */
387 && p != end)
388 {
389 if (nlines == lines_allocated)
390 {
391 lines_allocated *= 2;
392 line_charpos = (int *) xrealloc (line_charpos,
393 sizeof (int) * lines_allocated);
394 }
395 line_charpos[nlines++] = p - data;
396 }
397 }
398 s->nlines = nlines;
399 s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
400 }
401
402 /* Return the character position of a line LINE in symtab S.
403 Return 0 if anything is invalid. */
404
405 int
406 source_line_charpos (s, line)
407 struct symtab *s;
408 int line;
409 {
410 if (!s) return 0;
411 if (!s->line_charpos || line <= 0) return 0;
412 if (line > s->nlines)
413 line = s->nlines;
414 return s->line_charpos[line - 1];
415 }
416
417 /* Return the line number of character position POS in symtab S. */
418
419 int
420 source_charpos_line (s, chr)
421 register struct symtab *s;
422 register int chr;
423 {
424 register int line = 0;
425 register int *lnp;
426
427 if (s == 0 || s->line_charpos == 0) return 0;
428 lnp = s->line_charpos;
429 /* Files are usually short, so sequential search is Ok */
430 while (line < s->nlines && *lnp <= chr)
431 {
432 line++;
433 lnp++;
434 }
435 if (line >= s->nlines)
436 line = s->nlines;
437 return line;
438 }
439 \f
440 /* Get full pathname and line number positions for a symtab.
441 Return nonzero if line numbers may have changed.
442 Set *FULLNAME to actual name of the file as found by `openp',
443 or to 0 if the file is not found. */
444
445 int
446 get_filename_and_charpos (s, line, fullname)
447 struct symtab *s;
448 int line;
449 char **fullname;
450 {
451 register int desc, linenums_changed = 0;
452
453 desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
454 if (desc < 0)
455 {
456 if (fullname)
457 *fullname = NULL;
458 return 0;
459 }
460 if (fullname)
461 *fullname = s->fullname;
462 if (s->line_charpos == 0) linenums_changed = 1;
463 if (linenums_changed) find_source_lines (s, desc);
464 close (desc);
465 return linenums_changed;
466 }
467
468 /* Print text describing the full name of the source file S
469 and the line number LINE and its corresponding character position.
470 The text starts with two Ctrl-z so that the Emacs-GDB interface
471 can easily find it.
472
473 MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
474
475 Return 1 if successful, 0 if could not find the file. */
476
477 int
478 identify_source_line (s, line, mid_statement)
479 struct symtab *s;
480 int line;
481 int mid_statement;
482 {
483 if (s->line_charpos == 0)
484 get_filename_and_charpos (s, line, 0);
485 if (s->fullname == 0)
486 return 0;
487 printf ("\032\032%s:%d:%d:%s:0x%x\n", s->fullname,
488 line, s->line_charpos[line - 1],
489 mid_statement ? "middle" : "beg",
490 get_frame_pc (get_current_frame()));
491 current_source_line = line;
492 first_line_listed = line;
493 last_line_listed = line;
494 current_source_symtab = s;
495 return 1;
496 }
497 \f
498 /* Print source lines from the file of symtab S,
499 starting with line number LINE and stopping before line number STOPLINE. */
500
501 void
502 print_source_lines (s, line, stopline, noerror)
503 struct symtab *s;
504 int line, stopline;
505 int noerror;
506 {
507 register int c;
508 register int desc;
509 register FILE *stream;
510 int nlines = stopline - line;
511
512 desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname);
513 if (desc < 0)
514 {
515 extern int errno;
516 if (! noerror)
517 perror_with_name (s->filename);
518 print_sys_errmsg (s->filename, errno);
519 return;
520 }
521
522 if (s->line_charpos == 0)
523 find_source_lines (s, desc);
524
525 if (line < 1 || line > s->nlines)
526 {
527 close (desc);
528 error ("Line number out of range; %s has %d lines.",
529 s->filename, s->nlines);
530 }
531
532 if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
533 {
534 close (desc);
535 perror_with_name (s->filename);
536 }
537
538 current_source_symtab = s;
539 current_source_line = line;
540 first_line_listed = line;
541
542 stream = fdopen (desc, "r");
543 clearerr (stream);
544
545 while (nlines-- > 0)
546 {
547 c = fgetc (stream);
548 if (c == EOF) break;
549 last_line_listed = current_source_line;
550 printf_filtered ("%d\t", current_source_line++);
551 do
552 {
553 if (c < 040 && c != '\t' && c != '\n')
554 printf_filtered ("^%c", c + 0100);
555 else if (c == 0177)
556 printf_filtered ("^?");
557 else
558 printf_filtered ("%c", c);
559 } while (c != '\n' && (c = fgetc (stream)) >= 0);
560 }
561
562 fclose (stream);
563 }
564 \f
565
566
567 /*
568 C++
569 Print a list of files and line numbers which a user may choose from
570 in order to list a function which was specified ambiguously
571 (as with `list classname::overloadedfuncname', for example).
572 The vector in SALS provides the filenames and line numbers.
573 */
574 static void
575 ambiguous_line_spec (sals)
576 struct symtabs_and_lines *sals;
577 {
578 int i;
579
580 for (i = 0; i < sals->nelts; ++i)
581 printf("file: \"%s\", line number: %d\n",
582 sals->sals[i].symtab->filename, sals->sals[i].line);
583 }
584
585
586 static void
587 list_command (arg, from_tty)
588 char *arg;
589 int from_tty;
590 {
591 struct symtabs_and_lines sals, sals_end;
592 struct symtab_and_line sal, sal_end;
593 struct symbol *sym;
594 char *arg1;
595 int no_end = 1;
596 int dummy_end = 0;
597 int dummy_beg = 0;
598 int linenum_beg = 0;
599 char *p;
600
601 if (symtab_list == 0 && partial_symtab_list == 0)
602 error ("No symbol table is loaded. Use the \"symbol-file\" command.");
603
604 /* Pull in a current source symtab if necessary */
605 if (current_source_symtab == 0 &&
606 (arg == 0 || arg[0] == '+' || arg[0] == '-'))
607 select_source_symtab (0);
608
609 /* "l" or "l +" lists next ten lines. */
610
611 if (arg == 0 || !strcmp (arg, "+"))
612 {
613 if (current_source_symtab == 0)
614 error ("No default source file yet. Do \"help list\".");
615 print_source_lines (current_source_symtab, current_source_line,
616 current_source_line + 10, 0);
617 return;
618 }
619
620 /* "l -" lists previous ten lines, the ones before the ten just listed. */
621 if (!strcmp (arg, "-"))
622 {
623 if (current_source_symtab == 0)
624 error ("No default source file yet. Do \"help list\".");
625 print_source_lines (current_source_symtab,
626 max (first_line_listed - 10, 1),
627 first_line_listed, 0);
628 return;
629 }
630
631 /* Now if there is only one argument, decode it in SAL
632 and set NO_END.
633 If there are two arguments, decode them in SAL and SAL_END
634 and clear NO_END; however, if one of the arguments is blank,
635 set DUMMY_BEG or DUMMY_END to record that fact. */
636
637 arg1 = arg;
638 if (*arg1 == ',')
639 dummy_beg = 1;
640 else
641 {
642 sals = decode_line_1 (&arg1, 0, 0, 0);
643
644 if (! sals.nelts) return; /* C++ */
645 if (sals.nelts > 1)
646 {
647 ambiguous_line_spec (&sals);
648 free (sals.sals);
649 return;
650 }
651
652 sal = sals.sals[0];
653 free (sals.sals);
654 }
655
656 /* Record whether the BEG arg is all digits. */
657
658 for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
659 linenum_beg = (p == arg1);
660
661 while (*arg1 == ' ' || *arg1 == '\t')
662 arg1++;
663 if (*arg1 == ',')
664 {
665 no_end = 0;
666 arg1++;
667 while (*arg1 == ' ' || *arg1 == '\t')
668 arg1++;
669 if (*arg1 == 0)
670 dummy_end = 1;
671 else
672 {
673 if (dummy_beg)
674 sals_end = decode_line_1 (&arg1, 0, 0, 0);
675 else
676 sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
677 if (sals_end.nelts == 0)
678 return;
679 if (sals_end.nelts > 1)
680 {
681 ambiguous_line_spec (&sals_end);
682 free (sals_end.sals);
683 return;
684 }
685 sal_end = sals_end.sals[0];
686 free (sals_end.sals);
687 }
688 }
689
690 if (*arg1)
691 error ("Junk at end of line specification.");
692
693 if (!no_end && !dummy_beg && !dummy_end
694 && sal.symtab != sal_end.symtab)
695 error ("Specified start and end are in different files.");
696 if (dummy_beg && dummy_end)
697 error ("Two empty args do not say what lines to list.");
698
699 /* if line was specified by address,
700 first print exactly which line, and which file.
701 In this case, sal.symtab == 0 means address is outside
702 of all known source files, not that user failed to give a filename. */
703 if (*arg == '*')
704 {
705 if (sal.symtab == 0)
706 error ("No source file for address 0x%x.", sal.pc);
707 sym = find_pc_function (sal.pc);
708 if (sym)
709 printf ("0x%x is in %s (%s, line %d).\n",
710 sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
711 else
712 printf ("0x%x is in %s, line %d.\n",
713 sal.pc, sal.symtab->filename, sal.line);
714 }
715
716 /* If line was not specified by just a line number,
717 and it does not imply a symtab, it must be an undebuggable symbol
718 which means no source code. */
719
720 if (! linenum_beg && sal.symtab == 0)
721 error ("No line number known for %s.", arg);
722
723 /* If this command is repeated with RET,
724 turn it into the no-arg variant. */
725
726 if (from_tty)
727 *arg = 0;
728
729 if (dummy_beg && sal_end.symtab == 0)
730 error ("No default source file yet. Do \"help list\".");
731 if (dummy_beg)
732 print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1),
733 sal_end.line + 1, 0);
734 else if (sal.symtab == 0)
735 error ("No default source file yet. Do \"help list\".");
736 else if (no_end)
737 print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5, 0);
738 else
739 print_source_lines (sal.symtab, sal.line,
740 dummy_end ? sal.line + 10 : sal_end.line + 1,
741 0);
742 }
743 \f
744 /* Print info on range of pc's in a specified line. */
745
746 static void
747 line_info (arg, from_tty)
748 char *arg;
749 int from_tty;
750 {
751 struct symtabs_and_lines sals;
752 struct symtab_and_line sal;
753 int start_pc, end_pc;
754 int i;
755
756 if (arg == 0)
757 {
758 sal.symtab = current_source_symtab;
759 sal.line = last_line_listed;
760 sals.nelts = 1;
761 sals.sals = (struct symtab_and_line *)
762 xmalloc (sizeof (struct symtab_and_line));
763 sals.sals[0] = sal;
764 }
765 else
766 {
767 sals = decode_line_spec_1 (arg, 0);
768
769 /* If this command is repeated with RET,
770 turn it into the no-arg variant. */
771 if (from_tty)
772 *arg = 0;
773 }
774
775 /* C++ More than one line may have been specified, as when the user
776 specifies an overloaded function name. Print info on them all. */
777 for (i = 0; i < sals.nelts; i++)
778 {
779 sal = sals.sals[i];
780
781 if (sal.symtab == 0)
782 error ("No source file specified.");
783
784 if (sal.line > 0
785 && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
786 {
787 if (start_pc == end_pc)
788 printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
789 sal.line, sal.symtab->filename, start_pc);
790 else
791 printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
792 sal.line, sal.symtab->filename, start_pc, end_pc);
793 /* x/i should display this line's code. */
794 set_next_address (start_pc);
795 /* Repeating "info line" should do the following line. */
796 last_line_listed = sal.line + 1;
797 }
798 else
799 printf ("Line number %d is out of range for \"%s\".\n",
800 sal.line, sal.symtab->filename);
801 }
802 }
803 \f
804 /* Commands to search the source file for a regexp. */
805
806 static void
807 forward_search_command (regex, from_tty)
808 char *regex;
809 {
810 register int c;
811 register int desc;
812 register FILE *stream;
813 int line = last_line_listed + 1;
814 char *msg;
815
816 msg = (char *) re_comp (regex);
817 if (msg)
818 error (msg);
819
820 if (current_source_symtab == 0)
821 select_source_symtab (0);
822
823 /* Search from last_line_listed+1 in current_source_symtab */
824
825 desc = openp (source_path, 0, current_source_symtab->filename,
826 O_RDONLY, 0, &current_source_symtab->fullname);
827 if (desc < 0)
828 perror_with_name (current_source_symtab->filename);
829
830 if (current_source_symtab->line_charpos == 0)
831 find_source_lines (current_source_symtab, desc);
832
833 if (line < 1 || line > current_source_symtab->nlines)
834 {
835 close (desc);
836 error ("Expression not found");
837 }
838
839 if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
840 {
841 close (desc);
842 perror_with_name (current_source_symtab->filename);
843 }
844
845 stream = fdopen (desc, "r");
846 clearerr (stream);
847 while (1) {
848 char buf[4096]; /* Should be reasonable??? */
849 register char *p = buf;
850
851 c = fgetc (stream);
852 if (c == EOF)
853 break;
854 do {
855 *p++ = c;
856 } while (c != '\n' && (c = fgetc (stream)) >= 0);
857
858 /* we now have a source line in buf, null terminate and match */
859 *p = 0;
860 if (re_exec (buf) > 0)
861 {
862 /* Match! */
863 fclose (stream);
864 print_source_lines (current_source_symtab,
865 line, line+1, 0);
866 current_source_line = max (line - 5, 1);
867 return;
868 }
869 line++;
870 }
871
872 printf ("Expression not found\n");
873 fclose (stream);
874 }
875
876 static void
877 reverse_search_command (regex, from_tty)
878 char *regex;
879 {
880 register int c;
881 register int desc;
882 register FILE *stream;
883 int line = last_line_listed - 1;
884 char *msg;
885
886 msg = (char *) re_comp (regex);
887 if (msg)
888 error (msg);
889
890 if (current_source_symtab == 0)
891 select_source_symtab (0);
892
893 /* Search from last_line_listed-1 in current_source_symtab */
894
895 desc = openp (source_path, 0, current_source_symtab->filename,
896 O_RDONLY, 0, &current_source_symtab->fullname);
897 if (desc < 0)
898 perror_with_name (current_source_symtab->filename);
899
900 if (current_source_symtab->line_charpos == 0)
901 find_source_lines (current_source_symtab, desc);
902
903 if (line < 1 || line > current_source_symtab->nlines)
904 {
905 close (desc);
906 error ("Expression not found");
907 }
908
909 if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
910 {
911 close (desc);
912 perror_with_name (current_source_symtab->filename);
913 }
914
915 stream = fdopen (desc, "r");
916 clearerr (stream);
917 while (1)
918 {
919 char buf[4096]; /* Should be reasonable??? */
920 register char *p = buf;
921
922 c = fgetc (stream);
923 if (c == EOF)
924 break;
925 do {
926 *p++ = c;
927 } while (c != '\n' && (c = fgetc (stream)) >= 0);
928
929 /* We now have a source line in buf; null terminate and match. */
930 *p = 0;
931 if (re_exec (buf) > 0)
932 {
933 /* Match! */
934 fclose (stream);
935 print_source_lines (current_source_symtab,
936 line, line+1, 0);
937 current_source_line = max (line - 5, 1);
938 return;
939 }
940 line--;
941 if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
942 {
943 fclose (stream);
944 perror_with_name (current_source_symtab->filename);
945 }
946 }
947
948 printf ("Expression not found\n");
949 fclose (stream);
950 return;
951 }
952 \f
953 void
954 _initialize_source ()
955 {
956 current_source_symtab = 0;
957 init_source_path ();
958
959 add_com ("directory", class_files, directory_command,
960 "Add directory DIR to end of search path for source files.\n\
961 With no argument, reset the search path to just the working directory\n\
962 and forget cached info on line positions in source files.");
963
964 add_info ("directories", directories_info,
965 "Current search path for finding source files.");
966
967 add_info ("line", line_info,
968 "Core addresses of the code for a source line.\n\
969 Line can be specified as\n\
970 LINENUM, to list around that line in current file,\n\
971 FILE:LINENUM, to list around that line in that file,\n\
972 FUNCTION, to list around beginning of that function,\n\
973 FILE:FUNCTION, to distinguish among like-named static functions.\n\
974 Default is to describe the last source line that was listed.\n\n\
975 This sets the default address for \"x\" to the line's first instruction\n\
976 so that \"x/i\" suffices to start examining the machine code.\n\
977 The address is also stored as the value of \"$_\".");
978
979 add_com ("forward-search", class_files, forward_search_command,
980 "Search for regular expression (see regex(3)) from last line listed.");
981 add_com_alias ("search", "forward-search", class_files, 0);
982
983 add_com ("reverse-search", class_files, reverse_search_command,
984 "Search backward for regular expression (see regex(3)) from last line listed.");
985
986 add_com ("list", class_files, list_command,
987 "List specified function or line.\n\
988 With no argument, lists ten more lines after or around previous listing.\n\
989 \"list -\" lists the ten lines before a previous ten-line listing.\n\
990 One argument specifies a line, and ten lines are listed around that line.\n\
991 Two arguments with comma between specify starting and ending lines to list.\n\
992 Lines can be specified in these ways:\n\
993 LINENUM, to list around that line in current file,\n\
994 FILE:LINENUM, to list around that line in that file,\n\
995 FUNCTION, to list around beginning of that function,\n\
996 FILE:FUNCTION, to distinguish among like-named static functions.\n\
997 *ADDRESS, to list around the line containing that address.\n\
998 With two args if one is empty it stands for ten lines away from the other arg.");
999 }
1000