(pick-random): Remove.
[bpt/emacs.git] / lib-src / etags.c
CommitLineData
c6d46f5f 1/* Tags file maker to go with GNU Emacs
13fde0cd 2 Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
c6d46f5f 3
ea6cd314 4This file is not considered part of GNU Emacs.
c6d46f5f 5
ea6cd314 6This program is free software; you can redistribute it and/or modify
c6d46f5f 7it under the terms of the GNU General Public License as published by
ea6cd314
RS
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
c6d46f5f 10
ea6cd314 11This program is distributed in the hope that it will be useful,
c6d46f5f
JB
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
ea6cd314
RS
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
c6d46f5f
JB
19
20/*
21 * Authors:
22 * Ctags originally by Ken Arnold.
23 * FORTRAN added by Jim Kleckner.
24 * Ed Pelegri-Llopart added C typedefs.
25 * Gnu Emacs TAGS format and modifications by RMS?
26 * Sam Kendall added C++.
27 */
28
72a339d7 29#ifdef HAVE_CONFIG_H
b827c6c1 30#include "../src/config.h"
1e134a5f
RM
31#endif
32
918f9ad1
JB
33#include <stdio.h>
34#include <ctype.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37
38#include "getopt.h"
39
c6d46f5f
JB
40extern char *malloc (), *realloc ();
41extern char *getenv ();
c6d46f5f
JB
42extern char *strcpy (), *strncpy ();
43extern int strcmp ();
44
8a6c8bcf
RS
45char *etags_index (), *etags_rindex ();
46char *savenstr ();
c6d46f5f
JB
47
48/* Define the symbol ETAGS to make the program "etags",
49 which makes emacs-style tag tables by default.
50 Define CTAGS to make the program "ctags" compatible with the usual one.
51 Define neither one to get behavior that depends
52 on the name with which the program is invoked
53 (but we don't normally compile it that way). */
54
55#if !defined(ETAGS) && !defined(CTAGS)
56/* If neither is defined, program can be run as either. */
57#define ETAGS
58#define CTAGS
59#endif
60
61/* On VMS, CTAGS is not useful, so always do ETAGS. */
62#ifdef VMS
63#ifndef ETAGS
64#define ETAGS
65#endif
66#endif
67
68/* Exit codes for success and failure. */
69#ifdef VMS
70#define GOOD (1)
71#define BAD (0)
72#else
73#define GOOD (0)
74#define BAD (1)
75#endif
76
77/*
78 * The FILEPOS abstract type, which represents a position in a file,
79 * plus the following accessor functions:
80 *
81 * long GET_CHARNO (pos)
82 * returns absolute char number.
c6d46f5f
JB
83 * void SET_FILEPOS (pos, fp, charno)
84 * FILE *fp; long charno;
85 * sets `pos' from the current file
86 * position of `fp' and from `charno',
87 * which must be the absolute character
88 * number corresponding to the current
89 * position of `fp'.
90 *
91 * The `pos' parameter is an lvalue expression of type FILEPOS.
92 * Parameters to the accessor functions are evaluated 0 or more times,
93 * and so must have no side effects.
94 *
95 * FILEPOS objects can also be assigned and passed to and from
96 * functions in the normal C manner.
97 *
98 * Implementation notes: the `+ 0' is to enforce rvalue-ness.
99 */
c6d46f5f 100
c6d46f5f 101#ifndef DEBUG
13fde0cd 102 /* real implementation */
c6d46f5f
JB
103typedef long FILEPOS;
104#define GET_CHARNO(pos) ((pos) + 0)
c6d46f5f
JB
105#define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))
106#else
13fde0cd 107 /* debugging implementation */
c6d46f5f
JB
108typedef struct
109{
110 long charno;
111} FILEPOS;
112
113#define GET_CHARNO(pos) ((pos).charno + 0)
c6d46f5f
JB
114#define SET_FILEPOS(pos, fp, cno) \
115 ((void) ((pos).charno = (cno), \
116 (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
117 : 0))
118#endif
c6d46f5f
JB
119
120#define streq(s, t) (strcmp (s, t) == 0)
121#define strneq(s, t, n) (strncmp (s, t, n) == 0)
13fde0cd 122#define logical int
c6d46f5f
JB
123
124#define TRUE 1
125#define FALSE 0
126
127#define iswhite(arg) (_wht[arg]) /* T if char is white */
128#define begtoken(arg) (_btk[arg]) /* T if char can start token */
129#define intoken(arg) (_itk[arg]) /* T if char can be in token */
130#define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
c6d46f5f
JB
131
132#define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
133
134struct nd_st
135{ /* sorting structure */
136 char *name; /* function or type name */
137 char *file; /* file name */
138 logical is_func; /* use pattern or line no */
139 logical rewritten; /* list name separately */
140 logical been_warned; /* set if noticed dup */
141 int lno; /* line number tag is on */
142 long cno; /* character number line starts on */
143 char *pat; /* search pattern */
144 struct nd_st *left, *right; /* left and right sons */
145};
146
147long ftell ();
148typedef struct nd_st NODE;
149
13fde0cd
RS
150logical header_file; /* TRUE if .h file, FALSE o.w. */
151/* boolean "functions" (see init) */
152logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
c6d46f5f
JB
153
154
155char *concat ();
156char *savenstr ();
157char *savestr ();
158char *xmalloc ();
159char *xrealloc ();
160int L_isdef ();
161int PF_funcs ();
162int total_size_of_entries ();
163logical consider_token ();
164logical tail ();
165long readline ();
166void Asm_funcs ();
167void C_entries ();
168void L_funcs ();
169void L_getit ();
170void PAS_funcs ();
171void Scheme_funcs ();
172void TEX_funcs ();
173void add_node ();
174void error ();
175void fatal ();
176void find_entries ();
177void free_tree ();
178void getit ();
179void getline ();
180void init ();
181void initbuffer ();
182void initbuffer ();
183void pfnote ();
184void process_file ();
185void put_entries ();
186void takeprec ();
187
188/*
189 * MACRO
190 * xnew -- allocate storage
191 *
192 * SYNOPSIS
193 * Type *xnew (int n, Type);
194 */
195#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
196\f
197
198
199/*
200 * Symbol table stuff.
201 *
202 * Should probably be implemented with hash table; linked list for now.
203 */
204
205enum sym_type
206{
207 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
208};
209
210struct stab_entry
211{
212 char *sym;
213 int symlen;
214 enum sym_type type;
215 struct stab_entry *next;
216};
217
218typedef struct stab_entry Stab_entry;
219typedef Stab_entry *Stab;
220
221/*
222 * NAME
223 * Stab, Stab_entry, stab_create, stab_search, stab_find -- symbol table
224 *
225 * SYNOPSIS
226 * Types: Stab, Stab_entry, enum sym_type
227 *
228 * Stab * stab_create ()
229 *
230 * Stab_entry * stab_find (stab, sym)
231 * Stab *stab;
232 * char *sym;
233 *
234 * Stab_entry * stab_search (stab, sym)
235 * Stab *stab;
236 * char *sym;
237 *
238 * DESCRIPTION
239 * stab_create creates a Stab, a symbol table object, and returns a
240 * pointer to it. stab_find finds a symbol in a Stab; it returns a
241 * pointer to the Stab_entry if found, otherwise NULL. stab_search
242 * is like stab_find, except that it creates a new Stab_entry,
243 * initialized with type = st_none, if one did not exist already
244 * (it never returns NULL).
245 *
246 * A Stab_entry is a structure that contains at least the following
247 * members:
248 *
249 * char *name; // must not be modified
250 * enum sym_type type; // should be set
251 *
252 * The type field is initially set to st_none; it should be set to
253 * something else by the caller of stab_search. Other possible values
254 * of an enum sym_type can be added.
255 */
256
257Stab *
258stab_create ()
259{
260 Stab *sp;
261 sp = xnew (1, Stab);
262 *sp = NULL; /* a Stab starts out as a null Stab_entry* */
263 return sp;
264}
265
266Stab_entry *
267stab_find (stab, sym, symlen)
268 Stab *stab;
269 register char *sym;
270 register int symlen;
271{
272 register Stab_entry *se;
273 for (se = *stab; se != NULL; se = se->next)
274 {
275 if (se->symlen == symlen && strneq (se->sym, sym, symlen))
276 return se;
277 }
278
279 return NULL;
280}
281
282Stab_entry *
283stab_search (stab, sym, symlen)
284 register Stab *stab;
285 char *sym;
286 int symlen;
287{
288 register Stab_entry *se;
289 se = stab_find (stab, sym, symlen);
290
291 if (se == NULL)
292 {
293 /* make a new one */
294 se = xnew (1, Stab_entry);
295 se->sym = savenstr (sym, symlen);
296 se->symlen = symlen;
297 se->type = st_none;
298 se->next = *stab;
299 *stab = se;
300 }
301
302 return se;
303}
304
305/*
306 * NAME
307 * stab_type -- type of a symbol table entry
308 *
309 * SYNOPSIS
310 * enum sym_type stab_type (Stab_entry *se);
311 *
312 * WARNING
313 * May evaluate its argument more than once.
314 */
315
316#define stab_type(se) ((se)==NULL ? st_none : (se)->type)
317\f
318
319
320typedef int LINENO;
321
322typedef struct
323{
324 char *p;
325 int len;
c6d46f5f
JB
326 LINENO lineno;
327 logical rewritten;
328} TOKEN;
c6d46f5f 329
13fde0cd 330/* C extensions.
c6d46f5f 331 */
13fde0cd
RS
332#define C_PLPL 0x00001 /* C++ */
333#define C_STAR 0x00003 /* C* */
334#define YACC 0x10000 /* yacc file */
c6d46f5f
JB
335
336char searchar = '/'; /* use /.../ searches */
337
338LINENO lineno; /* line number of current line */
339long charno; /* current character number */
c6d46f5f
JB
340
341long linecharno; /* charno of start of line; not used by C, but
342 * by every other language.
343 */
344
345char *curfile, /* current input file name */
346 *outfile, /* output file */
347 *white = " \f\t\n", /* white chars */
13fde0cd
RS
348 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
349 /* token starting chars */
350 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
351 /* valid in-token chars */
352 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
c6d46f5f 353
c6d46f5f
JB
354int append_to_tagfile; /* -a: append to tags */
355int emacs_tags_format; /* emacs style output (no -e option any more) */
356/* The following three default to 1 for etags, but to 0 for ctags. */
357int typedefs; /* -t: create tags for typedefs */
358int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
359 /* 0 struct/enum/union decls, and C++ */
360 /* member functions */
361int constantypedefs; /* -d: create tags for C #define and enum */
362 /* constants. Default under etags. Enum */
363 /* constants not implemented. */
364 /* -D: opposite of -d. Default under ctags. */
365int update; /* -u: update tags */
366int vgrind_style; /* -v: create vgrind style index output */
367int no_warnings; /* -w: suppress warnings */
368int cxref_style; /* -x: create cxref style output */
369int cplusplus; /* .[hc] means C++, not C */
370int noindentypedefs; /* -S: ignore indentation in C */
c6d46f5f
JB
371
372/* Name this program was invoked with. */
373char *progname;
374
4746118a
JB
375struct option longopts[] = {
376 { "append", no_argument, NULL, 'a' },
377 { "backward-search", no_argument, NULL, 'B' },
378 { "c++", no_argument, NULL, 'C' },
379 { "cxref", no_argument, NULL, 'x' },
380 { "defines", no_argument, NULL, 'd' },
381 { "forward-search", no_argument, NULL, 'F' },
382 { "help", no_argument, NULL, 'H' },
383 { "ignore-indentation", no_argument, NULL, 'S' },
384 { "include", required_argument, NULL, 'i' },
385 { "no-defines", no_argument, NULL, 'D' },
386 { "no-warn", no_argument, NULL, 'w' },
387 { "output", required_argument, NULL, 'o' },
388 { "typedefs", no_argument, NULL, 't' },
389 { "typedefs-and-c++", no_argument, NULL, 'T' },
390 { "update", no_argument, NULL, 'u' },
391 { "version", no_argument, NULL, 'V' },
392 { "vgrind", no_argument, NULL, 'v' },
393 { 0 }
394};
395
c6d46f5f
JB
396FILE *inf, /* ioptr for current input file */
397 *outf; /* ioptr for tags file */
398
399NODE *head; /* the head of the binary tree of tags */
400
401int permit_duplicates = 1; /* Nonzero means allow duplicate tags. */
402
403/* A `struct linebuffer' is a structure which holds a line of text.
404 `readline' reads a line from a stream into a linebuffer
405 and works regardless of the length of the line. */
406
407struct linebuffer
408{
409 long size;
410 char *buffer;
411};
412
413struct linebuffer lb; /* the current line */
c6d46f5f 414struct linebuffer filename_lb; /* used to read in filenames */
13fde0cd
RS
415struct
416{
417 FILEPOS linepos;
418 struct linebuffer lb; /* used by C_entries instead of lb */
419} lbs[2];
c6d46f5f 420\f
4746118a
JB
421void
422print_version ()
423{
424#ifdef CTAGS
425 printf ("CTAGS ");
426#ifdef ETAGS
427 printf ("and ");
428#endif
429#endif
430#ifdef ETAGS
431 printf ("ETAGS ");
432#endif
433 printf ("for Emacs version 19.0.\n");
434
435 exit (0);
436}
437
438void
439print_help ()
440{
441 printf ("These are the options accepted by %s. You may use unambiguous\n\
442abbreviations for the long option names.\n\n", progname);
443
52cc7c59
JB
444 puts ("-a, --append\n\
445 Append tag entries to existing tags file.");
446 puts ("-C, --c++\n\
4746118a
JB
447 Treat files with `.c' and `.h' extensions as C++ code, not C\n\
448 code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
52cc7c59
JB
449 extensions are always assumed to be C++ code.");
450 fputs ("-d, --defines\n\
4746118a
JB
451 Create tag entries for #defines, too.", stdout);
452
453#ifdef ETAGS
454 fputs (" This is the default\n\
455 behavior.", stdout);
456#endif
457
458 fputs ("\n\
459-D, --no-defines\n\
460 Don't create tag entries for #defines.", stdout);
461
462#ifdef CTAGS
463 fputs (" This is the default\n\
464 behavior.", stdout);
465#endif
466
467 puts ("\n\
468-o FILE, --output=FILE\n\
469 Write the tags to FILE.\n\
470-S, --ignore-indentation\n\
471 Don't rely on indentation quite as much as normal. Currently,\n\
472 this means not to assume that a closing brace in the first\n\
473 column is the final brace of a function or structure\n\
52cc7c59
JB
474 definition.");
475 puts ("-t, --typedefs\n\
4746118a 476 Generate tag entries for typedefs. This is the default\n\
52cc7c59
JB
477 behavior.");
478 puts ("-T, --typedefs-and-c++\n\
4746118a
JB
479 Generate tag entries for typedefs, struct/enum/union tags, and\n\
480 C++ member functions.");
481
482#ifdef ETAGS
483 puts ("-i FILE, --include=FILE\n\
484 Include a note in tag file indicating that, when searching for\n\
485 a tag, one should also consult the tags file FILE after\n\
486 checking the current file.");
487#endif
488
489#ifdef CTAGS
490 puts ("-B, --backward-search\n\
491 Write the search commands for the tag entries using '?', the\n\
52cc7c59
JB
492 backward-search command.");
493 puts ("-F, --forward-search\n\
4746118a 494 Write the search commands for the tag entries using '/', the\n\
52cc7c59
JB
495 forward-search command.");
496 puts ("-u, --update\n\
4746118a
JB
497 Update the tag entries for the given files, leaving tag\n\
498 entries for other files in place. Currently, this is\n\
499 implemented by deleting the existing entries for the given\n\
500 files and then rewriting the new entries at the end of the\n\
501 tags file. It is often faster to simply rebuild the entire\n\
52cc7c59
JB
502 tag file than to use this.");
503 puts ("-v, --vgrind\n\
4746118a
JB
504 Generates an index of items intended for human consumption,\n\
505 similar to the output of vgrind. The index is sorted, and\n\
52cc7c59
JB
506 gives the page number of each item.");
507 puts ("-x, --cxref\n\
4746118a
JB
508 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
509 The output uses line numbers instead of page numbers, but\n\
510 beyond that the differences are cosmetic; try both to see\n\
52cc7c59
JB
511 which you like.");
512 puts ("-w, --no-warn\n\
4746118a
JB
513 Suppress warning messages about entries defined in multiple\n\
514 files.");
515#endif
516
517 puts ("-V, --version\n\
518 Print the version of the program.\n\
519-H, --help\n\
520 Print this help message.");
521
522 exit (0);
523}
524
525\f
c6d46f5f
JB
526void
527main (argc, argv)
528 int argc;
529 char *argv[];
530{
531 char cmd[100];
532 int i;
1e134a5f 533 unsigned int nincluded_files = 0;
72a339d7 534 char **included_files = xnew (argc, char *);
c6d46f5f
JB
535 char *this_file;
536#ifdef VMS
537 char got_err;
538
539 extern char *gfnames ();
540 extern char *massage_name ();
541#endif
542
543 progname = argv[0];
544
545#ifndef CTAGS
546 emacs_tags_format = 1;
547#else
548 emacs_tags_format = 0;
549#endif
550
551 /*
552 * If etags, always find typedefs and structure tags. Why not?
553 * Also default is to find macro constants.
554 */
555 if (emacs_tags_format)
556 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
557
4746118a 558 for (;;)
c6d46f5f 559 {
4746118a 560 int opt;
3ed79319 561 opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0);
4746118a
JB
562
563 if (opt == EOF)
564 break;
565
566 switch (opt)
c6d46f5f 567 {
4746118a
JB
568 case '\0':
569 /* If getopt returns '\0', then it has already processed a
570 long-named option. We should do nothing. */
571 break;
572
573 /* Common options. */
574 case 'a':
575 append_to_tagfile++;
576 break;
577 case 'C':
578 cplusplus = 1;
579 break;
580 case 'd':
581 constantypedefs = 1;
582 break;
583 case 'D':
584 constantypedefs = 0;
585 break;
3ed79319 586 case 'f':
4746118a
JB
587 case 'o':
588 if (outfile)
c6d46f5f 589 {
4746118a 590 fprintf (stderr,
3ed79319 591 "%s: -%c flag may only be given once\n", progname, opt);
c6d46f5f
JB
592 goto usage;
593 }
4746118a
JB
594 outfile = optarg;
595 break;
596 case 'S':
597 noindentypedefs++;
598 break;
599 case 't':
600 typedefs++;
601 break;
602 case 'T':
603 typedefs++;
604 typedefs_and_cplusplus++;
605 break;
606 case 'V':
607 print_version ();
608 break;
609 case 'H':
610 print_help ();
611 break;
612
613 /* Etags options */
614 case 'i':
615 if (!emacs_tags_format)
616 goto usage;
617 included_files[nincluded_files++] = optarg;
618 break;
619
620 /* Ctags options. */
621 case 'B':
622 searchar = '?';
623 if (emacs_tags_format)
624 goto usage;
625 break;
626 case 'F':
627 searchar = '/';
628 if (emacs_tags_format)
629 goto usage;
630 break;
631 case 'u':
632 update++;
633 if (emacs_tags_format)
634 goto usage;
635 break;
636 case 'v':
637 vgrind_style++;
638 /*FALLTHRU*/
639 case 'x':
640 cxref_style++;
641 if (emacs_tags_format)
642 goto usage;
643 break;
644 case 'w':
645 no_warnings++;
646 if (emacs_tags_format)
647 goto usage;
648 break;
649
650 default:
651 goto usage;
c6d46f5f 652 }
c6d46f5f
JB
653 }
654
0e5ad25f 655 if (optind == argc && nincluded_files == 0)
c6d46f5f 656 {
4746118a
JB
657 fprintf (stderr, "%s: No input files specified.\n", progname);
658
c6d46f5f 659 usage:
0e5ad25f 660 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
4746118a 661 progname, progname);
c6d46f5f
JB
662 exit (BAD);
663 }
664
665 if (outfile == 0)
666 {
667 outfile = emacs_tags_format ? "TAGS" : "tags";
668 }
669
670 init (); /* set up boolean "functions" */
671
672 initbuffer (&lb);
13fde0cd
RS
673 initbuffer (&lbs[0].lb);
674 initbuffer (&lbs[1].lb);
c6d46f5f
JB
675 initbuffer (&filename_lb);
676 /*
677 * loop through files finding functions
678 */
679 if (emacs_tags_format)
680 {
681 if (streq (outfile, "-"))
682 outf = stdout;
683 else
684 outf = fopen (outfile, append_to_tagfile ? "a" : "w");
685 if (!outf)
686 {
687 perror (outfile);
688 exit (1);
689 }
690 }
691
c6d46f5f 692#ifdef VMS
4746118a
JB
693 argc -= optind;
694 argv += optind;
695 while (gfnames (&argc, &argv, &got_err) != NULL)
c6d46f5f
JB
696 {
697 if (got_err)
698 {
699 error ("Can't find file %s\n", this_file);
700 argc--, argv++;
701 }
702 else
703 {
704 this_file = massage_name (this_file);
705#if 0
706 }
13fde0cd 707 } /* solely to balance out the ifdef'd parens above */
c6d46f5f
JB
708#endif
709#else
4746118a 710 for (; optind < argc; optind++)
c6d46f5f 711 {
4746118a 712 this_file = argv[optind];
c6d46f5f
JB
713 if (1)
714 {
715#endif
716 /* Input file named "-" means read file names from stdin
717 and use them. */
718 if (streq (this_file, "-"))
719 {
720 while (!feof (stdin))
721 {
722 (void) readline (&filename_lb, stdin);
723 if (strlen (filename_lb.buffer) > 0)
724 process_file (filename_lb.buffer);
725 }
726 }
727 else
728 process_file (this_file);
729 }
730 }
731
732 if (emacs_tags_format)
733 {
1e134a5f
RM
734 while (nincluded_files-- > 0)
735 fprintf (outf, "\f\n%s,include\n", *included_files++);
736
c6d46f5f
JB
737 (void) fclose (outf);
738 exit (0);
739 }
740
741 if (cxref_style)
742 {
743 put_entries (head);
744 exit (GOOD);
745 }
4746118a 746 if (update)
c6d46f5f 747 {
4746118a
JB
748 /* update cannot be set under VMS, so we may assume that argc
749 and argv have not been munged. */
750 for (i = optind; i < argc; i++)
c6d46f5f
JB
751 {
752 sprintf (cmd,
753 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
754 outfile, argv[i], outfile);
755 (void) system (cmd);
756 }
757 append_to_tagfile++;
758 }
759 outf = fopen (outfile, append_to_tagfile ? "a" : "w");
760 if (outf == NULL)
761 {
762 perror (outfile);
763 exit (GOOD);
764 }
765 put_entries (head);
766 (void) fclose (outf);
767 if (update)
768 {
769 sprintf (cmd, "sort %s -o %s", outfile, outfile);
770 (void) system (cmd);
771 }
772 exit (GOOD);
773}
774
775
776/*
777 * This routine is called on each file argument.
778 */
779void
780process_file (file)
781 char *file;
782{
783 struct stat stat_buf;
784
785 stat (file, &stat_buf);
8a6c8bcf
RS
786 if (!(stat_buf.st_mode & S_IFREG)
787#ifdef S_IFLNK
788 || !(stat_buf.st_mode & S_IFLNK)
789#endif
790 )
c6d46f5f
JB
791 {
792 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
793 return;
794 }
795
796 if (streq (file, outfile) && !streq (outfile, "-"))
797 {
798 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
799 return;
800 }
c6d46f5f
JB
801 if (emacs_tags_format)
802 {
8a6c8bcf 803 char *cp = etags_rindex (file, '/');
c6d46f5f
JB
804 if (cp)
805 ++cp;
806 else
807 cp = file;
c6d46f5f
JB
808 }
809 find_entries (file);
810 if (emacs_tags_format)
811 {
812 fprintf (outf, "\f\n%s,%d\n",
813 file, total_size_of_entries (head));
814 put_entries (head);
815 free_tree (head);
816 head = NULL;
817 }
818}
819
820/*
eb8c3be9 821 * This routine sets up the boolean pseudo-functions which work
99e0a2e0 822 * by setting boolean flags dependent upon the corresponding character
c6d46f5f
JB
823 * Every char which is NOT in that string is not a white char. Therefore,
824 * all of the array "_wht" is set to FALSE, and then the elements
825 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
826 * of a char is TRUE if it is the string "white", else FALSE.
827 */
828void
829init ()
830{
13fde0cd
RS
831 register char *sp;
832 register int i;
c6d46f5f
JB
833
834 for (i = 0; i < 0177; i++)
13fde0cd 835 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
c6d46f5f
JB
836 for (sp = white; *sp; sp++)
837 _wht[*sp] = TRUE;
838 for (sp = endtk; *sp; sp++)
839 _etk[*sp] = TRUE;
840 for (sp = intk; *sp; sp++)
841 _itk[*sp] = TRUE;
842 for (sp = begtk; *sp; sp++)
843 _btk[*sp] = TRUE;
c6d46f5f
JB
844 _wht[0] = _wht['\n'];
845 _etk[0] = _etk['\n'];
846 _btk[0] = _btk['\n'];
847 _itk[0] = _itk['\n'];
c6d46f5f
JB
848}
849
850/*
851 * This routine opens the specified file and calls the function
852 * which finds the function and type definitions.
853 */
854void
855find_entries (file)
856 char *file;
857{
858 char *cp;
859 void prolog_funcs ();
860
861 inf = fopen (file, "r");
862 if (inf == NULL)
863 {
864 perror (file);
865 return;
866 }
867 curfile = savestr (file);
8a6c8bcf 868 cp = etags_rindex (file, '.');
c6d46f5f
JB
869
870 header_file = (cp && (streq (cp + 1, "h")));
871
872 /* .tex, .aux or .bbl implies LaTeX source code */
873 if (cp && (streq (cp + 1, "tex") || streq (cp + 1, "aux")
874 || streq (cp + 1, "bbl")))
875 {
876 TEX_funcs (inf);
877 goto close_and_return;
878 }
879 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
880 if (cp && (streq (cp + 1, "l")
881 || streq (cp + 1, "el")
882 || streq (cp + 1, "lsp")
883 || streq (cp + 1, "lisp")
884 || streq (cp + 1, "cl")
885 || streq (cp + 1, "clisp")))
886 {
887 L_funcs (inf);
888 goto close_and_return;
889 }
890 /* .scm or .sm or .scheme or ... implies scheme source code */
891 if (cp && (streq (cp + 1, "sm")
892 || streq (cp + 1, "scm")
893 || streq (cp + 1, "scheme")
894 || streq (cp + 1, "t")
895 || streq (cp + 1, "sch")
896 || streq (cp + 1, "SM")
897 || streq (cp + 1, "SCM")
898 /* The `SCM' or `scm' prefix with a version number */
899 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's'
900 && string_numeric_p (cp + 1))
901 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'
902 && string_numeric_p (cp + 1))))
903 {
904 Scheme_funcs (inf);
905 fclose (inf);
906 return;
907 }
13fde0cd
RS
908 /* Assume that ".s" or ".a" is assembly code. -wolfgang.
909 Or even ".sa". */
910 if (cp && (streq (cp + 1, "s")
911 || streq (cp + 1, "a")
912 || streq (cp + 1, "sa")))
c6d46f5f
JB
913 {
914 Asm_funcs (inf);
915 fclose (inf);
916 return;
917 }
918 /* .C or .H or .cxx or .hxx or .cc: a C++ file */
919 if (cp && (streq (cp + 1, "C")
920 || streq (cp + 1, "H")
921 || streq (cp + 1, "cxx")
922 || streq (cp + 1, "hxx")
923 || streq (cp + 1, "cc")))
924 {
925 C_entries (C_PLPL); /* C++ */
926 goto close_and_return;
927 }
928 /* .cs or .hs: a C* file */
13fde0cd
RS
929 if (cp && (streq (cp + 1, "cs")
930 || streq (cp + 1, "hs")))
c6d46f5f
JB
931 {
932 C_entries (C_STAR);
933 goto close_and_return;
934 }
13fde0cd
RS
935 /* .y: a yacc file */
936 if (cp && (streq (cp + 1, "y")))
937 {
938 C_entries (YACC);
939 goto close_and_return;
940 }
c6d46f5f 941 /* .pl implies prolog source code */
13fde0cd 942 if (cp && streq (cp + 1, "pl"))
c6d46f5f
JB
943 {
944 prolog_funcs (inf);
945 goto close_and_return;
946 }
947 /* .p or .pas: a Pascal file */
948 if (cp && (streq (cp + 1, "p")
949 || streq (cp + 1, "pas")))
950 {
951 PAS_funcs (inf);
952 goto close_and_return;
953 }
1e8e1162 954 /* If .f or .for, assume it is fortran or nothing. */
13fde0cd
RS
955 if (cp && (streq (cp + 1, "f")
956 || streq (cp + 1, "for")))
1e8e1162
RS
957 {
958 PF_funcs (inf);
959 goto close_and_return;
960 }
c6d46f5f 961 /* if not a .c or .h or .y file, try fortran */
1e8e1162
RS
962 if (cp && ((cp[1] != 'c'
963 && cp[1] != 'h'
964 && cp[1] != 'y')
965 || (cp[1] != 0 && cp[2] != 0)))
c6d46f5f
JB
966 {
967 if (PF_funcs (inf) != 0)
968 goto close_and_return;
969 rewind (inf); /* no fortran tags found, try C */
970 }
971 C_entries (cplusplus ? C_PLPL : 0);
972
973close_and_return:
974 (void) fclose (inf);
975}
976
977/* Nonzero if string STR is composed of digits. */
978
979int
980string_numeric_p (str)
981 char *str;
982{
983 while (*str)
984 {
985 if (*str < '0' || *str > '9')
986 return 0;
987 }
988 return 1;
989}
990\f
991/* Record a tag. */
992/* Should take a TOKEN* instead!! */
c6d46f5f
JB
993void
994pfnote (name, is_func, rewritten, linestart, linelen, lno, cno)
995 char *name; /* tag name */
996 logical is_func; /* function or type name? */
997 logical rewritten; /* tag different from text of definition? */
998 char *linestart;
999 int linelen;
1000 int lno;
1001 long cno;
1002{
1003 register char *fp;
1004 register NODE *np;
1005 char tem[51];
1006 char c;
1007
1008 np = (NODE *) malloc (sizeof (NODE));
1009 if (np == NULL)
1010 {
1011 if (!emacs_tags_format)
1012 {
1013 /* It's okay to output early in etags -- it only disrupts the
1014 * character count of the tag entries, which is no longer used
1015 * by tags.el anyway.
1016 */
1017 error ("too many entries to sort");
1018 }
1019 put_entries (head);
1020 free_tree (head);
1021 head = NULL;
1022 np = xnew (1, NODE);
1023 }
1024 /* If ctags mode, change name "main" to M<thisfilename>. */
1025 if (!emacs_tags_format && !cxref_style && streq (name, "main"))
1026 {
8a6c8bcf 1027 fp = etags_rindex (curfile, '/');
c6d46f5f 1028 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
8a6c8bcf 1029 fp = etags_rindex (name, '.');
c6d46f5f
JB
1030 if (fp && fp[1] != '\0' && fp[2] == '\0')
1031 *fp = 0;
1032 rewritten = TRUE;
1033 }
1034 np->name = savestr (name);
1035 np->file = curfile;
1036 np->is_func = is_func;
1037 np->rewritten = rewritten;
1038 np->lno = lno;
1039 /* UNCOMMENT THE +1 HERE: */
1040 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
1041 np->left = np->right = 0;
1042 if (emacs_tags_format)
1043 {
1044 c = linestart[linelen];
1045 linestart[linelen] = 0;
1046 }
1047 else if (cxref_style == 0)
1048 {
1049 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
1050 linestart = tem;
1051 }
1052 np->pat = savestr (linestart);
1053 if (emacs_tags_format)
1054 {
1055 linestart[linelen] = c;
1056 }
1057
1058 add_node (np, &head);
1059}
1060
1061/*
1062 * free_tree ()
1063 * recurse on left children, iterate on right children.
1064 */
1065void
1066free_tree (node)
1067 register NODE *node;
1068{
1069 while (node)
1070 {
1071 register NODE *node_right = node->right;
1072 free_tree (node->left);
1073 free (node->name);
1074 free (node->pat);
1075 free ((char *) node);
1076 node = node_right;
1077 }
1078}
1079
1080/*
1081 * add_node ()
1082 * Adds a node to the tree of nodes. In etags mode, we don't keep
1083 * it sorted; we just keep a linear list. In ctags mode, maintain
1084 * an ordered tree, with no attempt at balancing.
1085 *
1086 * add_node is the only function allowed to add nodes, so it can
1087 * maintain state.
1088 */
8f53e1ee
RS
1089/* Must avoid static vars within functions since some systems
1090 #define static as nothing. */
1091static NODE *last_node = NULL;
1092
c6d46f5f
JB
1093void
1094add_node (node, cur_node_p)
1095 NODE *node, **cur_node_p;
1096{
1097 register int dif;
1098 register NODE *cur_node = *cur_node_p;
c6d46f5f
JB
1099
1100 if (cur_node == NULL)
1101 {
1102 *cur_node_p = node;
1103 last_node = node;
1104 return;
1105 }
1106
1107 if (emacs_tags_format)
1108 {
1109 /* Etags Mode */
1110 if (!last_node)
1111 fatal ("internal error in add_node");
1112 last_node->right = node;
1113 last_node = node;
1114 }
1115 else
1116 {
1117 /* Ctags Mode */
1118 dif = strcmp (node->name, cur_node->name);
1119
1120 /*
1121 * If this tag name matches an existing one, then
1122 * do not add the node, but maybe print a warning.
1123 */
1124 if (!dif)
1125 {
1126 if (node->file == cur_node->file)
1127 {
1128 if (!no_warnings)
1129 {
1130 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1131 node->file, lineno, node->name);
1132 fprintf (stderr, "Second entry ignored\n");
1133 }
1134 return;
1135 }
1136 if (!cur_node->been_warned && !no_warnings)
1137 {
1138 fprintf (stderr,
1139 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1140 node->file, cur_node->file, node->name);
1141 }
1142 cur_node->been_warned = TRUE;
1143 return;
1144 }
1145
1146 /* Maybe refuse to add duplicate nodes. */
1147 if (!permit_duplicates)
1148 {
1149 if (!strcmp (node->name, cur_node->name)
1150 && !strcmp (node->file, cur_node->file))
1151 return;
1152 }
1153
1154 /* Actually add the node */
1155 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1156 }
1157}
1158\f
1159void
1160put_entries (node)
13fde0cd 1161 register NODE *node;
c6d46f5f 1162{
13fde0cd 1163 register char *sp;
c6d46f5f
JB
1164
1165 if (node == NULL)
1166 return;
1167
1168 /* Output subentries that precede this one */
1169 put_entries (node->left);
1170
1171 /* Output this entry */
1172
1173 if (emacs_tags_format)
1174 {
1175 if (node->rewritten)
1176 {
1177 fprintf (outf, "%s\177%s\001%d,%d\n",
1178 node->name, node->pat, node->lno, node->cno);
1179 }
1180 else
1181 {
1182 fprintf (outf, "%s\177%d,%d\n",
1183 node->pat, node->lno, node->cno);
1184 }
1185 }
1186 else if (!cxref_style)
1187 {
1188 fprintf (outf, "%s\t%s\t",
1189 node->name, node->file);
1190
1191 if (node->is_func)
1192 { /* a function */
1193 putc (searchar, outf);
1194 putc ('^', outf);
1195
1196 for (sp = node->pat; *sp; sp++)
1197 {
1198 if (*sp == '\\' || *sp == searchar)
1199 putc ('\\', outf);
1200 putc (*sp, outf);
1201 }
1202 putc (searchar, outf);
1203 }
1204 else
1205 { /* a typedef; text pattern inadequate */
1206 fprintf (outf, "%d", node->lno);
1207 }
1208 putc ('\n', outf);
1209 }
1210 else if (vgrind_style)
1211 fprintf (stdout, "%s %s %d\n",
1212 node->name, node->file, (node->lno + 63) / 64);
1213 else
daa37602 1214 fprintf (stdout, "%-16s %3d %-16s %s\n",
c6d46f5f
JB
1215 node->name, node->lno, node->file, node->pat);
1216
1217 /* Output subentries that follow this one */
1218 put_entries (node->right);
1219}
1220
1221/* Length of a number's decimal representation. */
1222int
1223number_len (num)
1224 long num;
1225{
1226 int len = 0;
1227 if (!num)
1228 return 1;
1229 for (; num; num /= 10)
1230 ++len;
1231 return len;
1232}
1233
1234/*
1235 * Return total number of characters that put_entries will output for
1236 * the nodes in the subtree of the specified node. Works only if emacs_tags_format
1237 * is set, but called only in that case. This count is irrelevant with
1238 * the new tags.el, but is still supplied for backward compatibility.
1239 */
1240int
1241total_size_of_entries (node)
13fde0cd 1242 register NODE *node;
c6d46f5f 1243{
13fde0cd 1244 register int total;
c6d46f5f
JB
1245
1246 if (node == NULL)
1247 return 0;
1248
1249 total = 0;
1250 for (; node; node = node->right)
1251 {
1252 /* Count left subentries. */
1253 total += total_size_of_entries (node->left);
1254
1255 /* Count this entry */
1256 total += strlen (node->pat) + 1;
1257 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1258 if (node->rewritten)
1259 total += 1 + strlen (node->name); /* \001name */
1260 }
1261
1262 return total;
1263}
1264\f
1265/*
1266 * The C symbol tables.
1267 */
1268
1269Stab *C_stab, *C_PLPL_stab, *C_STAR_stab;
1270
1271/*
1272 * SYNOPSIS
1273 * Stab *get_C_stab (int c_ext);
1274 */
13fde0cd
RS
1275#define get_C_stab(c_ext) ((c_ext & C_STAR) ? C_STAR_stab : \
1276 (c_ext & C_PLPL) ? C_PLPL_stab : \
c6d46f5f
JB
1277 C_stab)
1278
1279void
1280add_keyword (stab, sym, type)
1281 Stab *stab;
1282 char *sym;
1283 enum sym_type type;
1284{
1285 stab_search (stab, sym, strlen (sym))->type = type;
1286}
1287
1288Stab *
1289C_create_stab (c_ext)
1290 int c_ext;
1291{
1292 Stab *stab;
1293
1294 stab = stab_create ();
1295
1296 /* C, C++ and C* */
1297 if (c_ext & C_PLPL)
1298 add_keyword (stab, "class", st_C_struct);
1299 if (c_ext & C_STAR)
1300 add_keyword (stab, "domain", st_C_struct);
1301 add_keyword (stab, "union", st_C_struct);
1302 add_keyword (stab, "struct", st_C_struct);
1303 add_keyword (stab, "enum", st_C_enum);
1304 add_keyword (stab, "typedef", st_C_typedef);
1305 add_keyword (stab, "define", st_C_define);
1306 add_keyword (stab, "long", st_C_typespec);
1307 add_keyword (stab, "short", st_C_typespec);
1308 add_keyword (stab, "int", st_C_typespec);
1309 add_keyword (stab, "char", st_C_typespec);
1310 add_keyword (stab, "float", st_C_typespec);
1311 add_keyword (stab, "double", st_C_typespec);
1312 add_keyword (stab, "signed", st_C_typespec);
1313 add_keyword (stab, "unsigned", st_C_typespec);
13fde0cd
RS
1314 add_keyword (stab, "auto", st_C_typespec);
1315 add_keyword (stab, "void", st_C_typespec);
1316 add_keyword (stab, "extern", st_C_typespec);
1317 add_keyword (stab, "static", st_C_typespec);
c6d46f5f
JB
1318 add_keyword (stab, "const", st_C_typespec);
1319 add_keyword (stab, "volatile", st_C_typespec);
1320
1321 return stab;
1322}
1323
1324void
1325C_create_stabs ()
1326{
1327 C_stab = C_create_stab (0);
1328 C_PLPL_stab = C_create_stab (C_PLPL);
1329 C_STAR_stab = C_create_stab (C_STAR | C_PLPL);
1330}
1331\f
13fde0cd
RS
1332 /*
1333 * etags.c 4.2 1993/03/22 12:13:40 pot Exp
1334 * C functions are recognized using a simple finite automaton.
1335 * funcdef is its state variable.
1336 */
1337typedef enum
1338{
1339 fnone, ftagseen, finlist, flistseen
1340} FUNCST;
1341FUNCST funcdef;
1342
1343
1344 /* typedefs are recognized using a simple finite automaton.
1345 * typeddef is its state variable.
1346 */
1347typedef enum
1348{
1349 tnone, ttypedseen, tinbody, tend
1350} TYPEDST;
1351TYPEDST typdef;
1352
1353
1354 /* struct tags for C++ are recognized using another simple
1355 * finite automaton. `structdef' is its state variable.
1356 * This machinery is only invoked for C++; otherwise structdef
1357 * should remain snone. However, this machinery can easily be
1358 * adapted to find structure tags in normal C code.
1359 */
1360typedef enum
1361{
1362 snone, /* nothing seen yet */
1363 skeyseen, /* struct-like keyword seen */
1364 stagseen, /* struct-like tag seen */
1365 scolonseen, /* colon seen after struct-like tag */
591fa824 1366 sinbody /* in struct body: recognize member func defs*/
13fde0cd
RS
1367} STRUCTST;
1368STRUCTST structdef;
1369/*
1370 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1371 * struct tag, and structkey is the preceding struct-like keyword.
1372 */
1373char structtag[BUFSIZ];
1374Stab_entry *structkey;
1375
1376/*
1377 * Yet another little state machine to deal with preprocessor lines.
1378 */
1379typedef enum
1380{
1381 dnone, /* nothing seen */
1382 dsharpseen, /* '#' seen as first char on line */
1383 ddefineseen, /* '#' and 'define' seen */
1384 dignorerest /* ignore rest of line */
1385} DEFINEST;
1386DEFINEST definedef;
1387
1388/*
1389 * Set this to TRUE, and the next token considered is called a function.
1390 * Used only for GNUmacs's function-defining macros.
1391 */
1392logical next_token_is_func;
1393
1394/*
1395 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1396 */
1397logical yacc_rules;
1398
c6d46f5f
JB
1399/*
1400 * C_entries ()
13fde0cd
RS
1401 * This routine finds functions, typedefs, #define's and
1402 * struct/union/enum definitions in C syntax and adds them
c6d46f5f
JB
1403 * to the list.
1404 */
1405
13fde0cd
RS
1406#define curlb (lbs[curndx].lb)
1407#define othlb (lbs[1-curndx].lb)
1408#define newlb (lbs[newndx].lb)
1409#define curlinepos (lbs[curndx].linepos)
1410#define othlinepos (lbs[1-curndx].linepos)
1411#define newlinepos (lbs[newndx].linepos)
1412
c6d46f5f 1413#define CNL_SAVE_DEFINEDEF \
13fde0cd
RS
1414do { \
1415 SET_FILEPOS (curlinepos, inf, charno); \
c6d46f5f 1416 lineno++; \
13fde0cd
RS
1417 charno += readline (&curlb, inf); \
1418 lp = curlb.buffer; \
1419 quotednl = FALSE; \
1420 newndx = curndx; \
1421} while (FALSE)
c6d46f5f
JB
1422
1423#define CNL \
13fde0cd 1424do { \
c6d46f5f
JB
1425 CNL_SAVE_DEFINEDEF; \
1426 definedef = dnone; \
13fde0cd
RS
1427} while (FALSE)
1428
1429#define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (tokb, isfun, tok.rewritten, \
1430 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1431#define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (tokb, isfun, tok.rewritten, \
1432 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
c6d46f5f
JB
1433
1434void
1435C_entries (c_ext)
1436 int c_ext; /* extension of C? */
1437{
13fde0cd 1438 register char c; /* latest char read; '\0' for end of line */
c6d46f5f 1439 register char *lp; /* pointer one beyond the character `c' */
13fde0cd
RS
1440 int curndx, newndx; /* indices for current and new lb */
1441 TOKEN tok; /* latest token read for funcdef & structdef */
1442 char tokb[BUFSIZ]; /* latest token name for funcdef & structdef */
1443 register int tokoff; /* offset in line of start of latest token */
1444 register int toklen; /* length of latest token */
591fa824 1445 int cblev; /* current curly brace level */
13fde0cd
RS
1446 logical incomm, inquote, inchar, quotednl, midtoken;
1447 logical cplpl;
c6d46f5f 1448
13fde0cd 1449 curndx = newndx = 0;
c6d46f5f
JB
1450 lineno = 0;
1451 charno = 0;
13fde0cd 1452 lp = curlb.buffer;
c6d46f5f
JB
1453 *lp = 0;
1454
13fde0cd
RS
1455 definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
1456 next_token_is_func = yacc_rules = FALSE;
1457 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1458 cblev = 0;
13fde0cd 1459 cplpl = c_ext & C_PLPL;
c6d46f5f
JB
1460
1461 C_create_stabs ();
1462
1463 while (!feof (inf))
1464 {
1465 c = *lp++;
c6d46f5f
JB
1466 if (c == '\\')
1467 {
4746118a
JB
1468 /* If we're at the end of the line, the next character is a
1469 '\0'; don't skip it, because it's the thing that tells us
1470 to read the next line. */
13fde0cd 1471 if (*lp == '\0')
99e0a2e0 1472 {
13fde0cd 1473 quotednl = TRUE;
99e0a2e0
RS
1474 continue;
1475 }
1e134a5f 1476 lp++;
c6d46f5f
JB
1477 c = ' ';
1478 }
1479 else if (incomm)
1480 {
13fde0cd 1481 switch (c)
c6d46f5f 1482 {
13fde0cd
RS
1483 case '*':
1484 if (*lp == '/')
1485 {
1486 c = *lp++;
1487 incomm = FALSE;
1488 }
1489 break;
1490 case '\0':
1491 /* Newlines inside comments do not end macro definitions in
1492 traditional cpp. */
1493 CNL_SAVE_DEFINEDEF;
1494 break;
c6d46f5f 1495 }
13fde0cd 1496 continue;
c6d46f5f
JB
1497 }
1498 else if (inquote)
1499 {
13fde0cd
RS
1500 switch (c)
1501 {
1502 case '"':
1503 inquote = FALSE;
1504 break;
1505 case '\0':
1506 /* Newlines inside strings, do not end macro definitions
1507 in traditional cpp, even though compilers don't
1508 usually accept them. */
1509 CNL_SAVE_DEFINEDEF;
1510 break;
1511 }
1512 continue;
c6d46f5f
JB
1513 }
1514 else if (inchar)
1515 {
1516 if (c == '\'')
1517 inchar = FALSE;
1518 continue;
1519 }
13fde0cd 1520 else
c6d46f5f
JB
1521 switch (c)
1522 {
1523 case '"':
1524 inquote = TRUE;
1525 continue;
1526 case '\'':
1527 inchar = TRUE;
1528 continue;
1529 case '/':
1530 if (*lp == '*')
1531 {
1532 lp++;
1533 incomm = TRUE;
13fde0cd 1534 continue;
c6d46f5f 1535 }
13fde0cd 1536 else if (cplpl && *lp == '/')
c6d46f5f 1537 {
daa37602
JB
1538 c = 0;
1539 break;
c6d46f5f
JB
1540 }
1541 continue;
13fde0cd
RS
1542 case '%':
1543 if ((c_ext & YACC) && *lp == '%')
1544 {
1545 /* entering or exiting rules section in yacc file */
1546 lp++;
1547 definedef = dnone; funcdef = fnone;
1548 typdef= tnone; structdef= snone;
1549 next_token_is_func = FALSE;
1550 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1551 cblev = 0;
13fde0cd
RS
1552 yacc_rules = !yacc_rules;
1553 continue;
591fa824 1554 }
c6d46f5f 1555 case '#':
13fde0cd 1556 if (lp == newlb.buffer + 1 && definedef == dnone)
c6d46f5f
JB
1557 definedef = dsharpseen;
1558 continue;
13fde0cd 1559 } /* switch (c) */
c6d46f5f 1560
c6d46f5f 1561
591fa824
RS
1562 /* Consider token only if some complicated conditions are satisfied. */
1563 if (((cblev == 0 && structdef != scolonseen)
1564 || (cblev == 1 && cplpl && structdef == sinbody))
13fde0cd 1565 && definedef != dignorerest
13fde0cd 1566 && funcdef != finlist)
c6d46f5f
JB
1567 {
1568 if (midtoken)
1569 {
1570 if (endtoken (c))
1571 {
13fde0cd 1572 if (cplpl && c == ':' && *lp == ':' && intoken (*(lp + 1)))
c6d46f5f
JB
1573 {
1574 /*
1575 * This handles :: in the middle, but not at beginning
1576 * of an identifier.
1577 */
1578 lp += 2;
1579 toklen += 3;
1580 }
1581 else
1582 {
c6d46f5f 1583 logical is_func;
c6d46f5f 1584
13fde0cd
RS
1585 tok.lineno = lineno;
1586 tok.p = newlb.buffer + tokoff;
c6d46f5f
JB
1587 tok.len = toklen;
1588 tok.rewritten = FALSE;
13fde0cd
RS
1589 if (yacc_rules
1590 || consider_token (c, lp, &tok,
591fa824 1591 c_ext, cblev, &is_func))
c6d46f5f 1592 {
99e0a2e0
RS
1593 if (structdef == sinbody
1594 && definedef == dnone && is_func)
c6d46f5f
JB
1595 { /* function defined in C++ class body */
1596 sprintf (tokb, "%s::%.*s",
13fde0cd
RS
1597 ((structtag[0] == '\0')
1598 ? "_anonymous_" : structtag),
c6d46f5f
JB
1599 tok.len, tok.p);
1600 tok.rewritten = TRUE;
1601 }
1602 else
1603 {
1604 sprintf (tokb, "%.*s", tok.len, tok.p);
1605 }
13fde0cd 1606
591fa824
RS
1607 if (funcdef == ftagseen
1608 || structdef == stagseen
1609 || typdef == tend)
13fde0cd
RS
1610 {
1611 if (newndx == curndx)
1612 curndx = 1 - curndx; /* switch line buffers */
1613 }
1614 else
1615 MAKE_TAG_FROM_NEW_LB (is_func);
c6d46f5f
JB
1616 }
1617 midtoken = FALSE;
1618 }
13fde0cd 1619 } /* if (endtoken (c)) */
c6d46f5f 1620 else if (intoken (c))
13fde0cd
RS
1621 {
1622 toklen++;
1623 continue;
1624 }
1625 } /* if (midtoken) */
c6d46f5f
JB
1626 else if (begtoken (c))
1627 {
13fde0cd
RS
1628 switch (funcdef)
1629 {
1630 case flistseen:
1631 MAKE_TAG_FROM_OTH_LB (TRUE);
1632 /* FALLTHRU */
1633 case ftagseen:
1634 funcdef = fnone;
1635 break;
1636 }
1637 if (structdef == stagseen)
1638 structdef = snone;
1639 if (!yacc_rules || lp == newlb.buffer + 1)
1640 {
1641 tokoff = lp - 1 - newlb.buffer;
1642 toklen = 1;
1643 midtoken = TRUE;
1644 }
1645 continue;
c6d46f5f 1646 }
13fde0cd
RS
1647 } /* if must look at token */
1648
1649
1650 /* Detect end of line, colon, comma, semicolon and various braces
1651 after having handled the last token on the line.*/
1652 switch (c)
1e134a5f 1653 {
13fde0cd
RS
1654 case ':':
1655 if (structdef == stagseen)
1656 structdef = scolonseen;
1657 else if (yacc_rules && funcdef == ftagseen)
57e83cfe 1658 {
13fde0cd
RS
1659 MAKE_TAG_FROM_OTH_LB (FALSE);
1660 funcdef == fnone;
57e83cfe 1661 }
13fde0cd
RS
1662 break;
1663 case ';':
591fa824
RS
1664 if (cblev == 0 && typdef == tend)
1665 {
1666 typdef = tnone;
1667 MAKE_TAG_FROM_OTH_LB (FALSE);
1668 }
13fde0cd
RS
1669 funcdef = fnone;
1670 /* FALLTHRU */
1671 case ',':
13fde0cd
RS
1672 /* FALLTHRU */
1673 case '[':
1674 if (funcdef != finlist)
1675 funcdef = fnone;
1676 if (structdef == stagseen)
1677 structdef = snone;
1678 break;
1679 case '(':
1680 switch (funcdef)
57e83cfe 1681 {
13fde0cd
RS
1682 case ftagseen:
1683 funcdef = finlist;
1684 break;
1685 case finlist:
1686 case flistseen:
1687 funcdef = fnone;
1688 break;
57e83cfe 1689 }
13fde0cd
RS
1690 break;
1691 case ')':
1692 if (funcdef == finlist)
1693 funcdef = flistseen;
1694 break;
1695 case '{':
1696 if (typdef == ttypedseen)
1697 typdef = tinbody;
1698 switch (structdef)
1699 {
1700 case skeyseen: /* unnamed struct */
1701 structtag[0] = '\0';
1702 structdef = sinbody;
1703 break;
1704 case stagseen:
1705 case scolonseen: /* named struct */
1706 structdef = sinbody;
1707 MAKE_TAG_FROM_OTH_LB (FALSE);
1708 break;
1709 }
591fa824 1710 cblev++;
13fde0cd
RS
1711 /* FALLTHRU */
1712 case '*':
1713 if (funcdef == flistseen)
1714 {
1715 MAKE_TAG_FROM_OTH_LB (TRUE);
1716 funcdef = fnone;
1717 }
1718 break;
1719 case '}':
1720 if (!noindentypedefs && lp == newlb.buffer + 1)
591fa824
RS
1721 cblev = 0; /* reset curly brace level if first column */
1722 else if (cblev > 0)
1723 cblev--;
1724 if (cblev == 0)
13fde0cd
RS
1725 {
1726 if (typdef == tinbody)
1727 typdef = tend;
1728 structdef = snone;
1729 (void) strcpy (structtag, "<error 2>");
1730 }
1731 break;
1732 case '\0':
1733 /* If a macro spans multiple lines don't reset its state. */
1734 if (quotednl)
1735 CNL_SAVE_DEFINEDEF;
1736 else
1737 CNL;
1738 break;
1739 } /* switch (c) */
1740
1741 } /* while not eof */
c6d46f5f
JB
1742}
1743
1744/*
1745 * consider_token ()
1746 * checks to see if the current token is at the start of a
13fde0cd
RS
1747 * function, or corresponds to a typedef, or is a struct/union/enum
1748 * tag.
c6d46f5f 1749 *
13fde0cd 1750 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
c6d46f5f
JB
1751 * C_EXT is which language we are looking at.
1752 *
1753 * In the future we will need some way to adjust where the end of
1754 * the token is; for instance, implementing the C++ keyword
1755 * `operator' properly will adjust the end of the token to be after
1756 * whatever follows `operator'.
1757 *
1758 * Globals
13fde0cd
RS
1759 * funcdef IN OUT
1760 * structdef IN OUT
1761 * definedef IN OUT
1762 * typdef IN OUT
1763 * next_token_is_func IN OUT
c6d46f5f
JB
1764 */
1765
1766logical
591fa824 1767consider_token (c, lp, tokp, c_ext, cblev, is_func)
13fde0cd
RS
1768 register char c; /* IN: first char after the token */
1769 register char *lp; /* IN: lp points to 2nd char after the token */
591fa824
RS
1770 register TOKEN *tokp; /* IN: token pointer */
1771 int c_ext; /* IN: C extensions mask */
1772 int cblev; /* IN: curly brace level */
13fde0cd 1773 logical *is_func; /* OUT */
c6d46f5f 1774{
c6d46f5f
JB
1775 logical firsttok; /* TRUE if have seen first token in ()'s */
1776 Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
1777 enum sym_type toktype = stab_type (tokse);
1778
13fde0cd 1779 *is_func = FALSE; /* not a function */
c6d46f5f
JB
1780
1781 /*
13fde0cd 1782 * Advance the definedef state machine.
c6d46f5f
JB
1783 */
1784 switch (definedef)
1785 {
1786 case dnone:
1787 /* We're not on a preprocessor line. */
1788 break;
1789 case dsharpseen:
1790 if (toktype == st_C_define)
1791 {
1792 definedef = ddefineseen;
c6d46f5f
JB
1793 }
1794 else
1795 {
1796 definedef = dignorerest;
c6d46f5f 1797 }
13fde0cd 1798 return (FALSE);
c6d46f5f
JB
1799 case ddefineseen:
1800 /*
1801 * Make a tag for any macro.
c6d46f5f 1802 */
c6d46f5f 1803 definedef = dignorerest;
13fde0cd 1804 *is_func = (c == '(');
c6d46f5f 1805 if (!*is_func && !constantypedefs)
13fde0cd
RS
1806 return (FALSE);
1807 else
1808 return (TRUE);
c6d46f5f 1809 case dignorerest:
13fde0cd 1810 return (FALSE);
c6d46f5f
JB
1811 default:
1812 error ("internal error: definedef value");
1813 }
1814
1815 /*
13fde0cd 1816 * Now typedefs
c6d46f5f 1817 */
13fde0cd 1818 switch (typdef)
c6d46f5f 1819 {
13fde0cd
RS
1820 case tnone:
1821 if (toktype == st_C_typedef)
c6d46f5f 1822 {
13fde0cd
RS
1823 if (typedefs)
1824 typdef = ttypedseen;
1825 return (FALSE);
c6d46f5f 1826 }
13fde0cd
RS
1827 break;
1828 case ttypedseen:
1829 switch (toktype)
c6d46f5f 1830 {
13fde0cd
RS
1831 case st_none:
1832 case st_C_typespec:
1833 typdef = tend;
1834 break;
1835 case st_C_struct:
1836 case st_C_enum:
1e134a5f 1837 break;
c6d46f5f 1838 }
13fde0cd 1839 /* Do not return here, so the structdef stuff has a chance. */
c6d46f5f 1840 break;
13fde0cd
RS
1841 case tend:
1842 switch (toktype)
c6d46f5f 1843 {
13fde0cd
RS
1844 case st_C_typespec:
1845 case st_C_struct:
1846 case st_C_enum:
1847 return (FALSE);
c6d46f5f 1848 }
13fde0cd 1849 return (TRUE);
c6d46f5f
JB
1850 }
1851
1852 /*
591fa824
RS
1853 * This structdef business is currently only invoked when cblev==0.
1854 * It should be recursively invoked whatever the curly brace level,
1855 * and a stack of states kept, to allow for definitions of structs
1856 * within structs.
c6d46f5f
JB
1857 *
1858 * This structdef business is NOT invoked when we are ctags and the
1859 * file is plain C. This is because a struct tag may have the same
1860 * name as another tag, and this loses with ctags.
1861 *
13fde0cd
RS
1862 * This if statement deals with the typdef state machine as
1863 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1864 * return (FALSE). All the other code here is for the structdef
1865 * state machine.
c6d46f5f
JB
1866 */
1867 switch (toktype)
1868 {
1869 case st_C_struct:
1870 case st_C_enum:
13fde0cd 1871 if (typdef == ttypedseen
591fa824 1872 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
c6d46f5f
JB
1873 {
1874 structdef = skeyseen;
1875 structkey = tokse;
1876 }
13fde0cd 1877 return (FALSE);
c6d46f5f 1878 }
c6d46f5f
JB
1879 if (structdef == skeyseen)
1880 {
13fde0cd 1881 if (stab_type (structkey) == st_C_struct)
c6d46f5f 1882 {
13fde0cd
RS
1883 (void) strncpy (structtag, tokp->p, tokp->len);
1884 structtag[tokp->len] = '\0'; /* for struct/union/class */
c6d46f5f
JB
1885 }
1886 else
1887 {
13fde0cd 1888 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
c6d46f5f 1889 }
13fde0cd
RS
1890 structdef = stagseen;
1891 return (TRUE);
c6d46f5f 1892 }
13fde0cd
RS
1893
1894 /* Avoid entering funcdef stuff if typdef is going on. */
1895 if (typdef != tnone)
c6d46f5f 1896 {
13fde0cd
RS
1897 definedef = dnone;
1898 return (FALSE);
c6d46f5f 1899 }
13fde0cd 1900
c6d46f5f 1901 /* Detect GNUmacs's function-defining macros. */
4746118a 1902 if (definedef == dnone)
c6d46f5f 1903 {
daa37602
JB
1904 if (strneq (tokp->p, "DEF", 3)
1905 || strneq (tokp->p, "ENTRY", 5)
1906 || strneq (tokp->p, "SYSCALL", 7)
1907 || strneq (tokp->p, "PSEUDO", 6))
4746118a
JB
1908 {
1909 next_token_is_func = TRUE;
13fde0cd 1910 return (FALSE);
4746118a 1911 }
13fde0cd 1912 if (strneq (tokp->p, "EXFUN", 5))
4746118a
JB
1913 {
1914 next_token_is_func = FALSE;
13fde0cd 1915 return (FALSE);
4746118a 1916 }
c6d46f5f
JB
1917 }
1918 if (next_token_is_func)
1919 {
1920 next_token_is_func = FALSE;
591fa824 1921 *is_func = TRUE;
13fde0cd 1922 return (TRUE);
c6d46f5f 1923 }
13fde0cd
RS
1924
1925 /* A function? */
1926 switch (toktype)
c6d46f5f 1927 {
13fde0cd 1928 case st_C_typespec:
591fa824 1929 funcdef = fnone; /* should be useless */
13fde0cd
RS
1930 return (FALSE);
1931 default:
1932 funcdef = ftagseen;
1933 *is_func = TRUE;
1934 return (TRUE);
c6d46f5f 1935 }
c6d46f5f
JB
1936}
1937\f
1938/* Fortran parsing */
1939
1940char *dbp;
1941int pfcnt;
1942
1943int
1944PF_funcs (fi)
1945 FILE *fi;
1946{
1947 lineno = 0;
1948 charno = 0;
1949 pfcnt = 0;
1950
1951 while (!feof (fi))
1952 {
1953 lineno++;
1954 linecharno = charno;
1955 charno += readline (&lb, fi);
1956 dbp = lb.buffer;
1957 if (*dbp == '%')
1958 dbp++; /* Ratfor escape to fortran */
1959 while (isspace (*dbp))
1960 dbp++;
1961 if (*dbp == 0)
1962 continue;
1963 switch (*dbp | ' ')
1964 {
1965 case 'i':
1966 if (tail ("integer"))
1967 takeprec ();
1968 break;
1969 case 'r':
1970 if (tail ("real"))
1971 takeprec ();
1972 break;
1973 case 'l':
1974 if (tail ("logical"))
1975 takeprec ();
1976 break;
1977 case 'c':
1978 if (tail ("complex") || tail ("character"))
1979 takeprec ();
1980 break;
1981 case 'd':
1982 if (tail ("double"))
1983 {
1984 while (isspace (*dbp))
1985 dbp++;
1986 if (*dbp == 0)
1987 continue;
1988 if (tail ("precision"))
1989 break;
1990 continue;
1991 }
1992 break;
1993 }
1994 while (isspace (*dbp))
1995 dbp++;
1996 if (*dbp == 0)
1997 continue;
1998 switch (*dbp | ' ')
1999 {
2000 case 'f':
2001 if (tail ("function"))
2002 getit ();
2003 continue;
2004 case 's':
2005 if (tail ("subroutine"))
2006 getit ();
2007 continue;
8a6c8bcf
RS
2008 case 'e':
2009 if (tail ("entry"))
2010 getit ();
2011 continue;
c6d46f5f
JB
2012 case 'p':
2013 if (tail ("program"))
2014 {
2015 getit ();
2016 continue;
2017 }
2018 if (tail ("procedure"))
2019 getit ();
2020 continue;
2021 }
2022 }
2023 return (pfcnt);
2024}
2025
2026logical
2027tail (cp)
2028 char *cp;
2029{
2030 register int len = 0;
2031
2032 while (*cp && (*cp & ~' ') == ((*(dbp + len)) & ~' '))
2033 cp++, len++;
2034 if (*cp == 0)
2035 {
2036 dbp += len;
2037 return (1);
2038 }
2039 return (0);
2040}
2041
2042void
2043takeprec ()
2044{
2045 while (isspace (*dbp))
2046 dbp++;
2047 if (*dbp != '*')
2048 return;
2049 dbp++;
2050 while (isspace (*dbp))
2051 dbp++;
2052 if (!isdigit (*dbp))
2053 {
2054 --dbp; /* force failure */
2055 return;
2056 }
2057 do
2058 dbp++;
2059 while (isdigit (*dbp));
2060}
2061
2062void
2063getit ()
2064{
2065 register char *cp;
2066 char c;
2067 char nambuf[BUFSIZ];
2068
2069 while (isspace (*dbp))
2070 dbp++;
daa37602
JB
2071 if (*dbp == 0
2072 || (!isalpha (*dbp)
2073 && *dbp != '_'
2074 && *dbp != '$'))
c6d46f5f
JB
2075 return;
2076 for (cp = dbp + 1; *cp && (isalpha (*cp) || isdigit (*cp)
2077 || (*cp == '_') || (*cp == '$')); cp++)
2078 continue;
2079 c = cp[0];
2080 cp[0] = 0;
2081 (void) strcpy (nambuf, dbp);
2082 cp[0] = c;
2083 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2084 pfcnt++;
2085}
2086
2087/* Handle a file of assembler code. */
2088
2089void
2090Asm_funcs (fi)
2091 FILE *fi;
2092{
2093 int i;
2094 register char c;
2095
2096 lineno = 0;
2097 charno = 0;
2098 pfcnt = 0;
2099
2100 while (!feof (fi))
2101 {
2102 lineno++;
2103 linecharno = charno;
2104 charno += readline (&lb, fi);
2105 dbp = lb.buffer;
2106
2107 for (i = 0; ((c = dbp[i]) && !isspace (c)) && (c != ':'); i++)
2108 ;
2109
2110 if ((i > 0) && (c == ':'))
2111 getit ();
2112 }
2113}
2114\f
2115/* Added by Mosur Mohan, 4/22/88 */
2116/* Pascal parsing */
2117
2118#define GET_NEW_LINE \
2119{ \
2120 linecharno = charno; lineno++; \
2121 charno += 1 + readline (&lb, inf); \
2122 dbp = lb.buffer; \
2123}
2124
2125/* Locates tags for procedures & functions.
2126 * Doesn't do any type- or var-definitions.
2127 * It does look for the keyword "extern" or "forward"
2128 * immediately following the procedure statement;
2129 * if found, the tag is skipped.
2130 */
2131
2132void
2133PAS_funcs (fi)
2134 FILE *fi;
2135{
2136 struct linebuffer tline; /* mostly copied from C_entries */
2137 long save_lcno;
2138 int save_lineno;
2139 char c, *cp;
2140 char nambuf[BUFSIZ];
2141
2142 logical /* each of these flags is TRUE iff: */
2143 incomm1, /* point is inside {..} comment */
2144 incomm2, /* point is inside (*..*) comment */
2145 inquote, /* point is inside '..' string */
2146 get_tagname, /* point is after PROCEDURE/FUNCTION */
2147 /* keyword, so next item = potential tag */
2148 found_tag, /* point is after a potential tag */
2149 inparms, /* point is within parameter-list */
2150 verify_tag; /* point has passed the parm-list, so the */
2151 /* next token will determine whether */
2152 /* this is a FORWARD/EXTERN to be */
2153 /* ignored, or whether it is a real tag */
2154
2155 lineno = 0;
2156 charno = 0;
2157 dbp = lb.buffer;
2158 *dbp = 0;
2159 initbuffer (&tline);
2160
2161 incomm1 = incomm2 = inquote = FALSE;
2162 found_tag = FALSE; /* have a proc name; check if extern */
2163 get_tagname = FALSE; /* have found "procedure" keyword */
2164 inparms = FALSE; /* found '(' after "proc" */
2165 verify_tag = FALSE; /* check if "extern" is ahead */
2166
2167 /* long main loop to get next char */
2168 while (!feof (fi))
2169 {
2170 c = *dbp++;
2171 if (c == 0) /* if end of line */
2172 {
2173 GET_NEW_LINE;
2174 if (*dbp == 0)
2175 continue;
2176 if (!((found_tag && verify_tag) ||
2177 get_tagname))
2178 c = *dbp++; /* only if don't need *dbp pointing */
2179 /* to the beginning of the name of */
2180 /* the procedure or function */
2181 }
2182 if (incomm1) /* within { - } comments */
2183 {
2184 if (c == '}')
2185 incomm1 = FALSE;
2186 continue;
2187 }
2188 else if (incomm2) /* within (* - *) comments */
2189 {
2190 if (c == '*')
2191 {
2192 while ((c = *dbp++) == '*')
2193 continue;
2194 if (c == 0)
2195 GET_NEW_LINE;
2196 if (c == ')')
2197 incomm2 = FALSE;
2198 }
2199 continue;
2200 }
2201 else if (inquote)
2202 {
2203 if (c == '\'')
2204 inquote = FALSE;
2205 continue;
2206 }
2207 else
2208 switch (c)
2209 {
2210 case '\'':
2211 inquote = TRUE; /* found first quote */
2212 continue;
2213 case '{': /* found open-{-comment */
2214 incomm1 = TRUE;
2215 continue;
2216 case '(':
2217 if (*dbp == '*') /* found open-(*-comment */
2218 {
2219 incomm2 = TRUE;
2220 dbp++;
2221 }
2222 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2223 inparms = TRUE;
2224 continue;
2225 case ')': /* end of parms list */
2226 if (inparms)
2227 inparms = FALSE;
2228 continue;
2229 case ';':
2230 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2231 {
2232 verify_tag = TRUE;
2233 break;
2234 }
2235 continue;
2236 }
2237 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2238 {
2239 /* check if this is an "extern" declaration */
2240 if (*dbp == 0)
2241 continue;
2242 if ((*dbp == 'e') || (*dbp == 'E'))
2243 {
2244 if (tail ("extern")) /* superfluous, really! */
2245 {
2246 found_tag = FALSE;
2247 verify_tag = FALSE;
2248 }
2249 }
2250 else if ((*dbp == 'f') || (*dbp == 'F'))
2251 {
2252 if (tail ("forward")) /* check for forward reference */
2253 {
2254 found_tag = FALSE;
2255 verify_tag = FALSE;
2256 }
2257 }
2258 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2259 {
2260 found_tag = FALSE;
2261 verify_tag = FALSE;
2262 pfnote (nambuf, TRUE, FALSE,
2263 tline.buffer, cp - tline.buffer + 1,
2264 save_lineno, save_lcno);
2265 continue;
2266 }
2267 }
2268 if (get_tagname) /* grab name of proc or fn */
2269 {
2270 if (*dbp == 0)
2271 continue;
2272
2273 /* save all values for later tagging */
2274 tline.size = lb.size;
2275 strcpy (tline.buffer, lb.buffer);
2276 save_lineno = lineno;
2277 save_lcno = linecharno;
2278
2279 /* grab block name */
2280 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2281 continue;
2282 c = cp[0];
2283 cp[0] = 0;
2284 strcpy (nambuf, dbp);
2285 cp[0] = c;
2286 dbp = cp; /* restore dbp to e-o-token */
2287 get_tagname = FALSE;
2288 found_tag = TRUE;
2289 continue;
2290
2291 /* and proceed to check for "extern" */
2292 }
2293 if ((!incomm1) && (!incomm2) && (!inquote) &&
2294 (!found_tag) && (!get_tagname))
2295 {
2296 /* check for proc/fn keywords */
2297 switch (c | ' ')
2298 {
2299 case 'p':
2300 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2301 get_tagname = TRUE;
2302 continue;
2303 case 'f':
2304 if (tail ("unction"))
2305 get_tagname = TRUE;
2306 continue;
2307 }
2308 }
2309 } /* while not e-o-f */
2310}
2311\f
2312/*
2313 * lisp tag functions
2314 * just look for (def or (DEF
2315 */
2316
2317void
2318L_funcs (fi)
2319 FILE *fi;
2320{
2321 lineno = 0;
2322 charno = 0;
2323 pfcnt = 0;
2324
2325 while (!feof (fi))
2326 {
2327 lineno++;
2328 linecharno = charno;
2329 charno += readline (&lb, fi);
2330 dbp = lb.buffer;
2331 if (dbp[0] == '(')
2332 {
2333 if (L_isdef (dbp))
2334 {
2335 while (!isspace (*dbp))
2336 dbp++;
2337 while (isspace (*dbp))
2338 dbp++;
2339 L_getit ();
2340 }
2341 else
2342 {
2343 /* Check for (foo::defmumble name-defined ... */
2344 while (*dbp && *dbp != ':' && !isspace (*dbp)
2345 && *dbp != '(' && *dbp != ')')
2346 dbp++;
2347 if (*dbp == ':')
2348 {
2349 while (*dbp == ':')
2350 dbp++;
2351
2352 if (L_isdef (dbp))
2353 {
2354 while (!isspace (*dbp))
2355 dbp++;
2356 while (isspace (*dbp))
2357 dbp++;
2358 L_getit ();
2359 }
2360 }
2361 }
2362 }
2363 }
2364}
2365
2366int
2367L_isdef (dbp)
2368 char *dbp;
2369{
2370 return ((dbp[1] == 'D' || dbp[1] == 'd') &&
2371 (dbp[2] == 'E' || dbp[2] == 'e') &&
2372 (dbp[3] == 'F' || dbp[3] == 'f'));
2373}
2374
2375void
2376L_getit ()
2377{
2378 register char *cp;
2379 char c;
2380 char nambuf[BUFSIZ];
2381
2382 if (*dbp == 0)
2383 return;
2384 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ' '; cp++)
2385 continue;
2386 c = cp[0];
2387 cp[0] = 0;
2388 (void) strcpy (nambuf, dbp);
2389 cp[0] = c;
591fa824
RS
2390 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2391 cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f
JB
2392 pfcnt++;
2393}
2394\f
2395/*
2396 * Scheme tag functions
2397 * look for (def... xyzzy
2398 * look for (def... (xyzzy
2399 * look for (def ... ((...(xyzzy ....
2400 * look for (set! xyzzy
2401 */
2402
2403static void get_scheme ();
2404
2405void
2406Scheme_funcs (fi)
2407 FILE *fi;
2408{
2409 lineno = 0;
2410 charno = 0;
2411 pfcnt = 0;
2412
2413 while (!feof (fi))
2414 {
2415 lineno++;
2416 linecharno = charno;
2417 charno += readline (&lb, fi);
2418 dbp = lb.buffer;
2419 if (dbp[0] == '(' &&
2420 (dbp[1] == 'D' || dbp[1] == 'd') &&
2421 (dbp[2] == 'E' || dbp[2] == 'e') &&
2422 (dbp[3] == 'F' || dbp[3] == 'f'))
2423 {
2424 while (!isspace (*dbp))
2425 dbp++;
2426 /* Skip over open parens and white space */
2427 while (*dbp && (isspace (*dbp) || *dbp == '('))
2428 dbp++;
2429 get_scheme ();
2430 }
2431 if (dbp[0] == '(' &&
2432 (dbp[1] == 'S' || dbp[1] == 's') &&
2433 (dbp[2] == 'E' || dbp[2] == 'e') &&
2434 (dbp[3] == 'T' || dbp[3] == 't') &&
2435 (dbp[4] == '!' || dbp[4] == '!') &&
2436 (isspace (dbp[5])))
2437 {
2438 while (!isspace (*dbp))
2439 dbp++;
2440 /* Skip over white space */
2441 while (isspace (*dbp))
2442 dbp++;
2443 get_scheme ();
2444 }
2445 }
2446}
2447
2448static void
2449get_scheme ()
2450{
2451 register char *cp;
2452 char c;
2453 char nambuf[BUFSIZ];
2454
2455 if (*dbp == 0)
2456 return;
2457 /* Go till you get to white space or a syntactic break */
2458 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2459 continue;
2460 /* Null terminate the string there. */
2461 c = cp[0];
2462 cp[0] = 0;
2463 /* Copy the string */
2464 strcpy (nambuf, dbp);
2465 /* Unterminate the string */
2466 cp[0] = c;
2467 /* Announce the change */
2468 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2469 pfcnt++;
2470}
2471\f
2472/* Find tags in TeX and LaTeX input files. */
2473
2474/* TEX_toktab is a table of TeX control sequences that define tags.
2475 Each TEX_tabent records one such control sequence.
2476 CONVERT THIS TO USE THE Stab TYPE!! */
2477
2478struct TEX_tabent
2479{
2480 char *name;
2481 int len;
2482};
2483
2484struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2485
2486/* Default set of control sequences to put into TEX_toktab.
2487 The value of environment var TEXTAGS is prepended to this. */
2488
2489static char *TEX_defenv =
2490":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2491
2492void TEX_mode ();
2493struct TEX_tabent *TEX_decode_env ();
2494void TEX_getit ();
2495int TEX_Token ();
2496
2497static char TEX_esc = '\\';
2498static char TEX_opgrp = '{';
2499static char TEX_clgrp = '}';
2500
2501/*
2502 * TeX/LaTeX scanning loop.
2503 */
2504
2505void
2506TEX_funcs (fi)
2507 FILE *fi;
2508{
2509 char *lasthit;
2510
2511 lineno = 0;
2512 charno = 0;
2513 pfcnt = 0;
2514
2515 /* Select either \ or ! as escape character. */
2516 TEX_mode (fi);
2517
2518 /* Initialize token table once from environment. */
2519 if (!TEX_toktab)
2520 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2521
2522 while (!feof (fi))
d2729198 2523 { /* Scan each line in file */
c6d46f5f
JB
2524 lineno++;
2525 linecharno = charno;
2526 charno += readline (&lb, fi);
2527 dbp = lb.buffer;
2528 lasthit = dbp;
d2729198 2529 while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
8a6c8bcf
RS
2530 {
2531 register int i;
c6d46f5f 2532
8a6c8bcf
RS
2533 if (!*(++dbp))
2534 break;
2535 linecharno += dbp - lasthit;
c6d46f5f 2536 lasthit = dbp;
8a6c8bcf
RS
2537 i = TEX_Token (lasthit);
2538 if (0 <= i)
c6d46f5f 2539 {
8a6c8bcf 2540 TEX_getit (lasthit, TEX_toktab[i].len);
d2729198 2541 break; /* We only save a line once */
c6d46f5f
JB
2542 }
2543 }
2544 }
2545}
2546
2547#define TEX_LESC '\\'
2548#define TEX_SESC '!'
2549#define TEX_cmt '%'
2550
2551/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2552/* chars accordingly. */
2553
2554void
2555TEX_mode (f)
2556 FILE *f;
2557{
2558 int c;
2559
2560 while ((c = getc (f)) != EOF)
2561 {
2562 /* Skip to next line if we hit the TeX comment char. */
2563 if (c == TEX_cmt)
2564 while (c != '\n')
2565 c = getc (f);
2566 else if (c == TEX_LESC || c == TEX_SESC )
2567 break;
2568 }
2569
2570 if (c == TEX_LESC)
2571 {
2572 TEX_esc = TEX_LESC;
2573 TEX_opgrp = '{';
2574 TEX_clgrp = '}';
2575 }
2576 else
2577 {
2578 TEX_esc = TEX_SESC;
2579 TEX_opgrp = '<';
2580 TEX_clgrp = '>';
2581 }
2582 rewind (f);
2583}
2584
2585/* Read environment and prepend it to the default string. */
2586/* Build token table. */
2587
2588struct TEX_tabent *
2589TEX_decode_env (evarname, defenv)
2590 char *evarname;
2591 char *defenv;
2592{
2593 register char *env, *p;
c6d46f5f
JB
2594
2595 struct TEX_tabent *tab;
2596 int size, i;
2597
2598 /* Append default string to environment. */
2599 env = getenv (evarname);
2600 if (!env)
2601 env = defenv;
2602 else
2603 env = concat (env, defenv, "");
2604
2605 /* Allocate a token table */
2606 for (size = 1, p = env; p;)
8a6c8bcf 2607 if ((p = etags_index (p, ':')) && *(++p))
c6d46f5f 2608 size++;
8a6c8bcf
RS
2609 /* Add 1 to leave room for null terminator. */
2610 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
2611
2612 /* Unpack environment string into token table. Be careful about */
2613 /* zero-length strings (leading ':', "::" and trailing ':') */
2614 for (i = 0; *env;)
2615 {
8a6c8bcf 2616 p = etags_index (env, ':');
c6d46f5f
JB
2617 if (!p) /* End of environment string. */
2618 p = env + strlen (env);
2619 if (p - env > 0)
2620 { /* Only non-zero strings. */
2621 tab[i].name = savenstr (env, p - env);
2622 tab[i].len = strlen (tab[i].name);
2623 i++;
2624 }
2625 if (*p)
2626 env = p + 1;
2627 else
2628 {
2629 tab[i].name = NULL; /* Mark end of table. */
2630 tab[i].len = 0;
2631 break;
2632 }
2633 }
2634 return tab;
2635}
2636
2637/* Record a tag defined by a TeX command of length LEN and starting at NAME.
2638 The name being defined actually starts at (NAME + LEN + 1).
2639 But we seem to include the TeX command in the tag name. */
2640
2641void
2642TEX_getit (name, len)
2643 char *name;
2644 int len;
2645{
2646 char *p = name + len;
2647 char nambuf[BUFSIZ];
2648
2649 if (*name == 0)
2650 return;
2651
2652 /* Let tag name extend to next group close (or end of line) */
2653 while (*p && *p != TEX_clgrp)
2654 p++;
2655 (void) strncpy (nambuf, name, p - name);
2656 nambuf[p - name] = 0;
2657
2658 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2659 pfcnt++;
2660}
2661
2662/* If the text at CP matches one of the tag-defining TeX command names,
8a6c8bcf 2663 return the etags_index of that command in TEX_toktab.
c6d46f5f
JB
2664 Otherwise return -1. */
2665
2666/* Keep the capital `T' in `Token' for dumb truncating compilers
2667 (this distinguishes it from `TEX_toktab' */
2668int
2669TEX_Token (cp)
2670 char *cp;
2671{
2672 int i;
2673
2674 for (i = 0; TEX_toktab[i].len > 0; i++)
2675 if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
2676 return i;
2677 return -1;
2678}
2679\f
2680/* Support for Prolog. */
2681
2682/* whole head (not only functor, but also arguments)
2683 is gotten in compound term. */
2684
2685void
2686prolog_getit (s, lineno, linecharno)
2687 char *s;
2688 int lineno;
2689 long linecharno;
2690{
2691 char nambuf[BUFSIZ], *save_s, tmpc;
2692 int insquote, npar;
2693
2694 save_s = s;
2695 insquote = FALSE;
2696 npar = 0;
2697 while (1)
2698 {
2699 if (*s == '\0') /* syntax error. */
2700 return;
2701 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2702 s += 2;
2703 else if (*s == '\'')
2704 {
2705 insquote = !insquote;
2706 s++;
2707 }
2708 else if (!insquote && *s == '(')
2709 {
2710 npar++;
2711 s++;
2712 }
2713 else if (!insquote && *s == ')')
2714 {
2715 npar--;
2716 s++;
2717 if (npar == 0)
2718 break;
2719 else if (npar < 0) /* syntax error. */
2720 return;
2721 }
2722 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2723 { /* fullstop. */
2724 if (npar != 0) /* syntax error. */
2725 return;
2726 s++;
2727 break;
2728 }
2729 else
2730 s++;
2731 }
2732 tmpc = *s;
2733 *s = '\0';
2734 strcpy (nambuf, save_s);
2735 *s = tmpc;
2736 pfnote (nambuf, TRUE, save_s, strlen (nambuf), lineno, linecharno);
2737}
2738
2739/* It is assumed that prolog predicate starts from column 0. */
2740
2741void
2742prolog_funcs (fi)
2743 FILE *fi;
2744{
2745 void skip_comment (), prolog_getit ();
2746
2747 lineno = linecharno = charno = 0;
2748 while (!feof (fi))
2749 {
2750 lineno++;
2751 linecharno += charno;
2752 charno = readline (&lb, fi) + 1; /* 1 for newline. */
2753 dbp = lb.buffer;
2754 if (isspace (dbp[0])) /* not predicate header. */
2755 continue;
2756 else if (dbp[0] == '%') /* comment. */
2757 continue;
2758 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2759 skip_comment (&lb, fi, &lineno, &linecharno);
2760 else /* found. */
2761 prolog_getit (dbp, lineno, linecharno);
2762 }
2763}
2764
2765void
2766skip_comment (plb, fi, plineno, plinecharno)
2767 struct linebuffer *plb;
2768 FILE *fi;
2769 int *plineno; /* result */
2770 long *plinecharno; /* result */
2771{
2772 while (!substr ("*/", plb->buffer))
2773 {
2774 (*plineno)++;
2775 *plinecharno += readline (plb, fi) + 1;
2776 } /* 1 for newline. */
2777}
2778
2779/* Return TRUE if 'sub' exists somewhere in 's'. */
2780
2781int
2782substr (sub, s)
2783 char *sub;
2784 char *s;
2785{
8a6c8bcf 2786 while (*s && (s = etags_index (s, *sub)))
c6d46f5f
JB
2787 if (prestr (sub, s))
2788 return (TRUE);
2789 else
2790 s++;
2791 return (FALSE);
2792}
2793
2794/* Return TRUE if 'pre' is prefix of string 's'. */
2795
2796int
2797prestr (pre, s)
2798 char *pre;
2799 char *s;
2800{
2801 if (*pre == '\0')
2802 return (TRUE);
2803 else if (*pre == *s)
2804 return (prestr (pre + 1, s + 1));
2805 else
2806 return (FALSE);
2807}
2808\f
2809/* Initialize a linebuffer for use */
2810
2811void
2812initbuffer (linebuffer)
2813 struct linebuffer *linebuffer;
2814{
2815 linebuffer->size = 200;
2816 linebuffer->buffer = xnew (200, char);
2817}
2818
2819/*
2820 * Read a line of text from `stream' into `linebuffer'.
2821 * Return the number of characters read from `stream',
2822 * which is the length of the line including the newline, if any.
2823 */
2824long
2825readline (linebuffer, stream)
2826 struct linebuffer *linebuffer;
2827 register FILE *stream;
2828{
2829 char *buffer = linebuffer->buffer;
2830 register char *p = linebuffer->buffer;
2831 register char *pend;
2832 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2833
eb8c3be9 2834 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
c6d46f5f
JB
2835
2836 while (1)
2837 {
2838 register int c = getc (stream);
2839 if (p == pend)
2840 {
2841 linebuffer->size *= 2;
2842 buffer = (char *) xrealloc (buffer, linebuffer->size);
2843 p += buffer - linebuffer->buffer;
2844 pend = buffer + linebuffer->size;
2845 linebuffer->buffer = buffer;
2846 }
2847 if (c < 0 || c == '\n')
2848 {
2849 *p = 0;
2850 newline = (c == '\n' ? 1 : 0);
2851 break;
2852 }
2853 *p++ = c;
2854 }
2855
2856 return p - buffer + newline;
2857}
2858\f
2859char *
2860savestr (cp)
2861 char *cp;
2862{
2863 return savenstr (cp, strlen (cp));
2864}
2865
2866char *
2867savenstr (cp, len)
2868 char *cp;
2869 int len;
2870{
2871 register char *dp;
2872
2873 dp = xnew (len + 1, char);
2874 (void) strncpy (dp, cp, len);
2875 dp[len] = '\0';
2876 return dp;
2877}
2878
c6d46f5f
JB
2879/*
2880 * Return the ptr in sp at which the character c last
2881 * appears; NULL if not found
2882 *
2883 * Identical to v7 rindex, included for portability.
2884 */
2885
2886char *
8a6c8bcf 2887etags_rindex (sp, c)
c6d46f5f
JB
2888 register char *sp, c;
2889{
2890 register char *r;
2891
2892 r = NULL;
2893 do
2894 {
2895 if (*sp == c)
2896 r = sp;
2897 } while (*sp++);
2898 return (r);
2899}
2900
9d7ad1b3 2901
c6d46f5f
JB
2902/*
2903 * Return the ptr in sp at which the character c first
2904 * appears; NULL if not found
2905 *
2906 * Identical to v7 index, included for portability.
2907 */
2908
2909char *
8a6c8bcf 2910etags_index (sp, c)
c6d46f5f
JB
2911 register char *sp, c;
2912{
2913 do
2914 {
2915 if (*sp == c)
2916 return (sp);
2917 } while (*sp++);
2918 return (NULL);
2919}
2920
c6d46f5f
JB
2921/* Print error message and exit. */
2922
2923/* VARARGS1 */
2924void
2925fatal (s1, s2)
2926 char *s1, *s2;
2927{
2928 error (s1, s2);
2929 exit (1);
2930}
2931
2932/* Print error message. `s1' is printf control string, `s2' is arg for it. */
2933
2934/* VARARGS1 */
2935void
2936error (s1, s2)
2937 char *s1, *s2;
2938{
2939 fprintf (stderr, "%s: ", progname);
2940 fprintf (stderr, s1, s2);
2941 fprintf (stderr, "\n");
2942}
2943
2944/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
2945
2946char *
2947concat (s1, s2, s3)
2948 char *s1, *s2, *s3;
2949{
2950 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
2951 char *result = xnew (len1 + len2 + len3 + 1, char);
2952
2953 (void) strcpy (result, s1);
2954 (void) strcpy (result + len1, s2);
2955 (void) strcpy (result + len1 + len2, s3);
2956 *(result + len1 + len2 + len3) = 0;
2957
2958 return result;
2959}
2960
2961/* Like malloc but get fatal error if memory is exhausted. */
2962
2963char *
2964xmalloc (size)
2965 int size;
2966{
2967 char *result = malloc (size);
2968 if (!result)
2969 fatal ("virtual memory exhausted", 0);
2970 return result;
2971}
2972
2973char *
2974xrealloc (ptr, size)
2975 char *ptr;
2976 int size;
2977{
2978 char *result = realloc (ptr, size);
2979 if (!result)
2980 fatal ("virtual memory exhausted");
2981 return result;
2982}