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