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