gdb-3.3
[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 "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