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