gdb-3.5
[platform/upstream/binutils.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