Comment fixes.
[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",
cc6d6e58
RM
1178 node->pat, node->name,
1179 node->lno, node->cno);
c6d46f5f
JB
1180 }
1181 else
1182 {
1183 fprintf (outf, "%s\177%d,%d\n",
cc6d6e58
RM
1184 node->pat,
1185 node->lno, node->cno);
c6d46f5f
JB
1186 }
1187 }
1188 else if (!cxref_style)
1189 {
1190 fprintf (outf, "%s\t%s\t",
1191 node->name, node->file);
1192
1193 if (node->is_func)
1194 { /* a function */
1195 putc (searchar, outf);
1196 putc ('^', outf);
1197
1198 for (sp = node->pat; *sp; sp++)
1199 {
1200 if (*sp == '\\' || *sp == searchar)
1201 putc ('\\', outf);
1202 putc (*sp, outf);
1203 }
1204 putc (searchar, outf);
1205 }
1206 else
1207 { /* a typedef; text pattern inadequate */
1208 fprintf (outf, "%d", node->lno);
1209 }
1210 putc ('\n', outf);
1211 }
1212 else if (vgrind_style)
1213 fprintf (stdout, "%s %s %d\n",
1214 node->name, node->file, (node->lno + 63) / 64);
1215 else
daa37602 1216 fprintf (stdout, "%-16s %3d %-16s %s\n",
c6d46f5f
JB
1217 node->name, node->lno, node->file, node->pat);
1218
1219 /* Output subentries that follow this one */
1220 put_entries (node->right);
1221}
1222
1223/* Length of a number's decimal representation. */
1224int
1225number_len (num)
1226 long num;
1227{
1228 int len = 0;
1229 if (!num)
1230 return 1;
1231 for (; num; num /= 10)
1232 ++len;
1233 return len;
1234}
1235
1236/*
1237 * Return total number of characters that put_entries will output for
1238 * the nodes in the subtree of the specified node. Works only if emacs_tags_format
1239 * is set, but called only in that case. This count is irrelevant with
1240 * the new tags.el, but is still supplied for backward compatibility.
1241 */
1242int
1243total_size_of_entries (node)
13fde0cd 1244 register NODE *node;
c6d46f5f 1245{
13fde0cd 1246 register int total;
c6d46f5f
JB
1247
1248 if (node == NULL)
1249 return 0;
1250
1251 total = 0;
1252 for (; node; node = node->right)
1253 {
1254 /* Count left subentries. */
1255 total += total_size_of_entries (node->left);
1256
1257 /* Count this entry */
1258 total += strlen (node->pat) + 1;
1259 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1260 if (node->rewritten)
1261 total += 1 + strlen (node->name); /* \001name */
1262 }
1263
1264 return total;
1265}
1266\f
1267/*
1268 * The C symbol tables.
1269 */
1270
1271Stab *C_stab, *C_PLPL_stab, *C_STAR_stab;
1272
1273/*
1274 * SYNOPSIS
1275 * Stab *get_C_stab (int c_ext);
1276 */
13fde0cd
RS
1277#define get_C_stab(c_ext) ((c_ext & C_STAR) ? C_STAR_stab : \
1278 (c_ext & C_PLPL) ? C_PLPL_stab : \
c6d46f5f
JB
1279 C_stab)
1280
1281void
1282add_keyword (stab, sym, type)
1283 Stab *stab;
1284 char *sym;
1285 enum sym_type type;
1286{
1287 stab_search (stab, sym, strlen (sym))->type = type;
1288}
1289
1290Stab *
1291C_create_stab (c_ext)
1292 int c_ext;
1293{
1294 Stab *stab;
1295
1296 stab = stab_create ();
1297
1298 /* C, C++ and C* */
1299 if (c_ext & C_PLPL)
1300 add_keyword (stab, "class", st_C_struct);
1301 if (c_ext & C_STAR)
1302 add_keyword (stab, "domain", st_C_struct);
1303 add_keyword (stab, "union", st_C_struct);
1304 add_keyword (stab, "struct", st_C_struct);
1305 add_keyword (stab, "enum", st_C_enum);
1306 add_keyword (stab, "typedef", st_C_typedef);
1307 add_keyword (stab, "define", st_C_define);
1308 add_keyword (stab, "long", st_C_typespec);
1309 add_keyword (stab, "short", st_C_typespec);
1310 add_keyword (stab, "int", st_C_typespec);
1311 add_keyword (stab, "char", st_C_typespec);
1312 add_keyword (stab, "float", st_C_typespec);
1313 add_keyword (stab, "double", st_C_typespec);
1314 add_keyword (stab, "signed", st_C_typespec);
1315 add_keyword (stab, "unsigned", st_C_typespec);
13fde0cd
RS
1316 add_keyword (stab, "auto", st_C_typespec);
1317 add_keyword (stab, "void", st_C_typespec);
1318 add_keyword (stab, "extern", st_C_typespec);
1319 add_keyword (stab, "static", st_C_typespec);
c6d46f5f
JB
1320 add_keyword (stab, "const", st_C_typespec);
1321 add_keyword (stab, "volatile", st_C_typespec);
1322
1323 return stab;
1324}
1325
1326void
1327C_create_stabs ()
1328{
1329 C_stab = C_create_stab (0);
1330 C_PLPL_stab = C_create_stab (C_PLPL);
1331 C_STAR_stab = C_create_stab (C_STAR | C_PLPL);
1332}
1333\f
13fde0cd
RS
1334 /*
1335 * etags.c 4.2 1993/03/22 12:13:40 pot Exp
1336 * C functions are recognized using a simple finite automaton.
1337 * funcdef is its state variable.
1338 */
1339typedef enum
1340{
1341 fnone, ftagseen, finlist, flistseen
1342} FUNCST;
1343FUNCST funcdef;
1344
1345
1346 /* typedefs are recognized using a simple finite automaton.
1347 * typeddef is its state variable.
1348 */
1349typedef enum
1350{
1351 tnone, ttypedseen, tinbody, tend
1352} TYPEDST;
1353TYPEDST typdef;
1354
1355
1356 /* struct tags for C++ are recognized using another simple
1357 * finite automaton. `structdef' is its state variable.
1358 * This machinery is only invoked for C++; otherwise structdef
1359 * should remain snone. However, this machinery can easily be
1360 * adapted to find structure tags in normal C code.
1361 */
1362typedef enum
1363{
1364 snone, /* nothing seen yet */
1365 skeyseen, /* struct-like keyword seen */
1366 stagseen, /* struct-like tag seen */
1367 scolonseen, /* colon seen after struct-like tag */
591fa824 1368 sinbody /* in struct body: recognize member func defs*/
13fde0cd
RS
1369} STRUCTST;
1370STRUCTST structdef;
1371/*
1372 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1373 * struct tag, and structkey is the preceding struct-like keyword.
1374 */
1375char structtag[BUFSIZ];
1376Stab_entry *structkey;
1377
1378/*
1379 * Yet another little state machine to deal with preprocessor lines.
1380 */
1381typedef enum
1382{
1383 dnone, /* nothing seen */
1384 dsharpseen, /* '#' seen as first char on line */
1385 ddefineseen, /* '#' and 'define' seen */
1386 dignorerest /* ignore rest of line */
1387} DEFINEST;
1388DEFINEST definedef;
1389
1390/*
1391 * Set this to TRUE, and the next token considered is called a function.
1392 * Used only for GNUmacs's function-defining macros.
1393 */
1394logical next_token_is_func;
1395
1396/*
1397 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1398 */
1399logical yacc_rules;
1400
c6d46f5f
JB
1401/*
1402 * C_entries ()
13fde0cd
RS
1403 * This routine finds functions, typedefs, #define's and
1404 * struct/union/enum definitions in C syntax and adds them
c6d46f5f
JB
1405 * to the list.
1406 */
1407
13fde0cd
RS
1408#define curlb (lbs[curndx].lb)
1409#define othlb (lbs[1-curndx].lb)
1410#define newlb (lbs[newndx].lb)
1411#define curlinepos (lbs[curndx].linepos)
1412#define othlinepos (lbs[1-curndx].linepos)
1413#define newlinepos (lbs[newndx].linepos)
1414
c6d46f5f 1415#define CNL_SAVE_DEFINEDEF \
13fde0cd
RS
1416do { \
1417 SET_FILEPOS (curlinepos, inf, charno); \
c6d46f5f 1418 lineno++; \
13fde0cd
RS
1419 charno += readline (&curlb, inf); \
1420 lp = curlb.buffer; \
1421 quotednl = FALSE; \
1422 newndx = curndx; \
1423} while (FALSE)
c6d46f5f
JB
1424
1425#define CNL \
13fde0cd 1426do { \
c6d46f5f
JB
1427 CNL_SAVE_DEFINEDEF; \
1428 definedef = dnone; \
13fde0cd
RS
1429} while (FALSE)
1430
1431#define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (tokb, isfun, tok.rewritten, \
1432 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1433#define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (tokb, isfun, tok.rewritten, \
1434 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
c6d46f5f
JB
1435
1436void
1437C_entries (c_ext)
1438 int c_ext; /* extension of C? */
1439{
13fde0cd 1440 register char c; /* latest char read; '\0' for end of line */
c6d46f5f 1441 register char *lp; /* pointer one beyond the character `c' */
13fde0cd
RS
1442 int curndx, newndx; /* indices for current and new lb */
1443 TOKEN tok; /* latest token read for funcdef & structdef */
1444 char tokb[BUFSIZ]; /* latest token name for funcdef & structdef */
1445 register int tokoff; /* offset in line of start of latest token */
1446 register int toklen; /* length of latest token */
591fa824 1447 int cblev; /* current curly brace level */
13fde0cd
RS
1448 logical incomm, inquote, inchar, quotednl, midtoken;
1449 logical cplpl;
c6d46f5f 1450
13fde0cd 1451 curndx = newndx = 0;
c6d46f5f
JB
1452 lineno = 0;
1453 charno = 0;
13fde0cd 1454 lp = curlb.buffer;
c6d46f5f
JB
1455 *lp = 0;
1456
13fde0cd
RS
1457 definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
1458 next_token_is_func = yacc_rules = FALSE;
1459 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1460 cblev = 0;
13fde0cd 1461 cplpl = c_ext & C_PLPL;
c6d46f5f
JB
1462
1463 C_create_stabs ();
1464
1465 while (!feof (inf))
1466 {
1467 c = *lp++;
c6d46f5f
JB
1468 if (c == '\\')
1469 {
4746118a
JB
1470 /* If we're at the end of the line, the next character is a
1471 '\0'; don't skip it, because it's the thing that tells us
1472 to read the next line. */
13fde0cd 1473 if (*lp == '\0')
99e0a2e0 1474 {
13fde0cd 1475 quotednl = TRUE;
99e0a2e0
RS
1476 continue;
1477 }
1e134a5f 1478 lp++;
c6d46f5f
JB
1479 c = ' ';
1480 }
1481 else if (incomm)
1482 {
13fde0cd 1483 switch (c)
c6d46f5f 1484 {
13fde0cd
RS
1485 case '*':
1486 if (*lp == '/')
1487 {
1488 c = *lp++;
1489 incomm = FALSE;
1490 }
1491 break;
1492 case '\0':
1493 /* Newlines inside comments do not end macro definitions in
1494 traditional cpp. */
1495 CNL_SAVE_DEFINEDEF;
1496 break;
c6d46f5f 1497 }
13fde0cd 1498 continue;
c6d46f5f
JB
1499 }
1500 else if (inquote)
1501 {
13fde0cd
RS
1502 switch (c)
1503 {
1504 case '"':
1505 inquote = FALSE;
1506 break;
1507 case '\0':
1508 /* Newlines inside strings, do not end macro definitions
1509 in traditional cpp, even though compilers don't
1510 usually accept them. */
1511 CNL_SAVE_DEFINEDEF;
1512 break;
1513 }
1514 continue;
c6d46f5f
JB
1515 }
1516 else if (inchar)
1517 {
1518 if (c == '\'')
1519 inchar = FALSE;
1520 continue;
1521 }
13fde0cd 1522 else
c6d46f5f
JB
1523 switch (c)
1524 {
1525 case '"':
1526 inquote = TRUE;
1527 continue;
1528 case '\'':
1529 inchar = TRUE;
1530 continue;
1531 case '/':
1532 if (*lp == '*')
1533 {
1534 lp++;
1535 incomm = TRUE;
13fde0cd 1536 continue;
c6d46f5f 1537 }
13fde0cd 1538 else if (cplpl && *lp == '/')
c6d46f5f 1539 {
daa37602
JB
1540 c = 0;
1541 break;
c6d46f5f
JB
1542 }
1543 continue;
13fde0cd
RS
1544 case '%':
1545 if ((c_ext & YACC) && *lp == '%')
1546 {
1547 /* entering or exiting rules section in yacc file */
1548 lp++;
1549 definedef = dnone; funcdef = fnone;
1550 typdef= tnone; structdef= snone;
1551 next_token_is_func = FALSE;
1552 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1553 cblev = 0;
13fde0cd
RS
1554 yacc_rules = !yacc_rules;
1555 continue;
591fa824 1556 }
c6d46f5f 1557 case '#':
13fde0cd 1558 if (lp == newlb.buffer + 1 && definedef == dnone)
c6d46f5f
JB
1559 definedef = dsharpseen;
1560 continue;
13fde0cd 1561 } /* switch (c) */
c6d46f5f 1562
c6d46f5f 1563
591fa824
RS
1564 /* Consider token only if some complicated conditions are satisfied. */
1565 if (((cblev == 0 && structdef != scolonseen)
1566 || (cblev == 1 && cplpl && structdef == sinbody))
13fde0cd 1567 && definedef != dignorerest
13fde0cd 1568 && funcdef != finlist)
c6d46f5f
JB
1569 {
1570 if (midtoken)
1571 {
1572 if (endtoken (c))
1573 {
13fde0cd 1574 if (cplpl && c == ':' && *lp == ':' && intoken (*(lp + 1)))
c6d46f5f
JB
1575 {
1576 /*
1577 * This handles :: in the middle, but not at beginning
1578 * of an identifier.
1579 */
1580 lp += 2;
1581 toklen += 3;
1582 }
1583 else
1584 {
c6d46f5f 1585 logical is_func;
c6d46f5f 1586
13fde0cd
RS
1587 tok.lineno = lineno;
1588 tok.p = newlb.buffer + tokoff;
c6d46f5f
JB
1589 tok.len = toklen;
1590 tok.rewritten = FALSE;
13fde0cd
RS
1591 if (yacc_rules
1592 || consider_token (c, lp, &tok,
591fa824 1593 c_ext, cblev, &is_func))
c6d46f5f 1594 {
99e0a2e0
RS
1595 if (structdef == sinbody
1596 && definedef == dnone && is_func)
c6d46f5f
JB
1597 { /* function defined in C++ class body */
1598 sprintf (tokb, "%s::%.*s",
13fde0cd
RS
1599 ((structtag[0] == '\0')
1600 ? "_anonymous_" : structtag),
c6d46f5f
JB
1601 tok.len, tok.p);
1602 tok.rewritten = TRUE;
1603 }
1604 else
1605 {
1606 sprintf (tokb, "%.*s", tok.len, tok.p);
1607 }
13fde0cd 1608
591fa824
RS
1609 if (funcdef == ftagseen
1610 || structdef == stagseen
1611 || typdef == tend)
13fde0cd
RS
1612 {
1613 if (newndx == curndx)
1614 curndx = 1 - curndx; /* switch line buffers */
1615 }
1616 else
1617 MAKE_TAG_FROM_NEW_LB (is_func);
c6d46f5f
JB
1618 }
1619 midtoken = FALSE;
1620 }
13fde0cd 1621 } /* if (endtoken (c)) */
c6d46f5f 1622 else if (intoken (c))
13fde0cd
RS
1623 {
1624 toklen++;
1625 continue;
1626 }
1627 } /* if (midtoken) */
c6d46f5f
JB
1628 else if (begtoken (c))
1629 {
13fde0cd
RS
1630 switch (funcdef)
1631 {
1632 case flistseen:
1633 MAKE_TAG_FROM_OTH_LB (TRUE);
1634 /* FALLTHRU */
1635 case ftagseen:
1636 funcdef = fnone;
1637 break;
1638 }
1639 if (structdef == stagseen)
1640 structdef = snone;
1641 if (!yacc_rules || lp == newlb.buffer + 1)
1642 {
1643 tokoff = lp - 1 - newlb.buffer;
1644 toklen = 1;
1645 midtoken = TRUE;
1646 }
1647 continue;
c6d46f5f 1648 }
13fde0cd
RS
1649 } /* if must look at token */
1650
1651
1652 /* Detect end of line, colon, comma, semicolon and various braces
1653 after having handled the last token on the line.*/
1654 switch (c)
1e134a5f 1655 {
13fde0cd
RS
1656 case ':':
1657 if (structdef == stagseen)
1658 structdef = scolonseen;
1659 else if (yacc_rules && funcdef == ftagseen)
57e83cfe 1660 {
13fde0cd
RS
1661 MAKE_TAG_FROM_OTH_LB (FALSE);
1662 funcdef == fnone;
57e83cfe 1663 }
13fde0cd
RS
1664 break;
1665 case ';':
591fa824
RS
1666 if (cblev == 0 && typdef == tend)
1667 {
1668 typdef = tnone;
1669 MAKE_TAG_FROM_OTH_LB (FALSE);
1670 }
13fde0cd
RS
1671 funcdef = fnone;
1672 /* FALLTHRU */
1673 case ',':
13fde0cd
RS
1674 /* FALLTHRU */
1675 case '[':
1676 if (funcdef != finlist)
1677 funcdef = fnone;
1678 if (structdef == stagseen)
1679 structdef = snone;
1680 break;
1681 case '(':
1682 switch (funcdef)
57e83cfe 1683 {
13fde0cd
RS
1684 case ftagseen:
1685 funcdef = finlist;
1686 break;
1687 case finlist:
1688 case flistseen:
1689 funcdef = fnone;
1690 break;
57e83cfe 1691 }
13fde0cd
RS
1692 break;
1693 case ')':
1694 if (funcdef == finlist)
1695 funcdef = flistseen;
1696 break;
1697 case '{':
1698 if (typdef == ttypedseen)
1699 typdef = tinbody;
1700 switch (structdef)
1701 {
1702 case skeyseen: /* unnamed struct */
1703 structtag[0] = '\0';
1704 structdef = sinbody;
1705 break;
1706 case stagseen:
1707 case scolonseen: /* named struct */
1708 structdef = sinbody;
1709 MAKE_TAG_FROM_OTH_LB (FALSE);
1710 break;
1711 }
591fa824 1712 cblev++;
13fde0cd
RS
1713 /* FALLTHRU */
1714 case '*':
1715 if (funcdef == flistseen)
1716 {
1717 MAKE_TAG_FROM_OTH_LB (TRUE);
1718 funcdef = fnone;
1719 }
1720 break;
1721 case '}':
1722 if (!noindentypedefs && lp == newlb.buffer + 1)
591fa824
RS
1723 cblev = 0; /* reset curly brace level if first column */
1724 else if (cblev > 0)
1725 cblev--;
1726 if (cblev == 0)
13fde0cd
RS
1727 {
1728 if (typdef == tinbody)
1729 typdef = tend;
1730 structdef = snone;
1731 (void) strcpy (structtag, "<error 2>");
1732 }
1733 break;
1734 case '\0':
1735 /* If a macro spans multiple lines don't reset its state. */
1736 if (quotednl)
1737 CNL_SAVE_DEFINEDEF;
1738 else
1739 CNL;
1740 break;
1741 } /* switch (c) */
1742
1743 } /* while not eof */
c6d46f5f
JB
1744}
1745
1746/*
1747 * consider_token ()
1748 * checks to see if the current token is at the start of a
13fde0cd
RS
1749 * function, or corresponds to a typedef, or is a struct/union/enum
1750 * tag.
c6d46f5f 1751 *
13fde0cd 1752 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
c6d46f5f
JB
1753 * C_EXT is which language we are looking at.
1754 *
1755 * In the future we will need some way to adjust where the end of
1756 * the token is; for instance, implementing the C++ keyword
1757 * `operator' properly will adjust the end of the token to be after
1758 * whatever follows `operator'.
1759 *
1760 * Globals
13fde0cd
RS
1761 * funcdef IN OUT
1762 * structdef IN OUT
1763 * definedef IN OUT
1764 * typdef IN OUT
1765 * next_token_is_func IN OUT
c6d46f5f
JB
1766 */
1767
1768logical
591fa824 1769consider_token (c, lp, tokp, c_ext, cblev, is_func)
13fde0cd
RS
1770 register char c; /* IN: first char after the token */
1771 register char *lp; /* IN: lp points to 2nd char after the token */
591fa824
RS
1772 register TOKEN *tokp; /* IN: token pointer */
1773 int c_ext; /* IN: C extensions mask */
1774 int cblev; /* IN: curly brace level */
13fde0cd 1775 logical *is_func; /* OUT */
c6d46f5f 1776{
c6d46f5f
JB
1777 logical firsttok; /* TRUE if have seen first token in ()'s */
1778 Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
1779 enum sym_type toktype = stab_type (tokse);
1780
13fde0cd 1781 *is_func = FALSE; /* not a function */
c6d46f5f
JB
1782
1783 /*
13fde0cd 1784 * Advance the definedef state machine.
c6d46f5f
JB
1785 */
1786 switch (definedef)
1787 {
1788 case dnone:
1789 /* We're not on a preprocessor line. */
1790 break;
1791 case dsharpseen:
1792 if (toktype == st_C_define)
1793 {
1794 definedef = ddefineseen;
c6d46f5f
JB
1795 }
1796 else
1797 {
1798 definedef = dignorerest;
c6d46f5f 1799 }
13fde0cd 1800 return (FALSE);
c6d46f5f
JB
1801 case ddefineseen:
1802 /*
1803 * Make a tag for any macro.
c6d46f5f 1804 */
c6d46f5f 1805 definedef = dignorerest;
13fde0cd 1806 *is_func = (c == '(');
c6d46f5f 1807 if (!*is_func && !constantypedefs)
13fde0cd
RS
1808 return (FALSE);
1809 else
1810 return (TRUE);
c6d46f5f 1811 case dignorerest:
13fde0cd 1812 return (FALSE);
c6d46f5f
JB
1813 default:
1814 error ("internal error: definedef value");
1815 }
1816
1817 /*
13fde0cd 1818 * Now typedefs
c6d46f5f 1819 */
13fde0cd 1820 switch (typdef)
c6d46f5f 1821 {
13fde0cd
RS
1822 case tnone:
1823 if (toktype == st_C_typedef)
c6d46f5f 1824 {
13fde0cd
RS
1825 if (typedefs)
1826 typdef = ttypedseen;
1827 return (FALSE);
c6d46f5f 1828 }
13fde0cd
RS
1829 break;
1830 case ttypedseen:
1831 switch (toktype)
c6d46f5f 1832 {
13fde0cd
RS
1833 case st_none:
1834 case st_C_typespec:
1835 typdef = tend;
1836 break;
1837 case st_C_struct:
1838 case st_C_enum:
1e134a5f 1839 break;
c6d46f5f 1840 }
13fde0cd 1841 /* Do not return here, so the structdef stuff has a chance. */
c6d46f5f 1842 break;
13fde0cd
RS
1843 case tend:
1844 switch (toktype)
c6d46f5f 1845 {
13fde0cd
RS
1846 case st_C_typespec:
1847 case st_C_struct:
1848 case st_C_enum:
1849 return (FALSE);
c6d46f5f 1850 }
13fde0cd 1851 return (TRUE);
c6d46f5f
JB
1852 }
1853
1854 /*
591fa824
RS
1855 * This structdef business is currently only invoked when cblev==0.
1856 * It should be recursively invoked whatever the curly brace level,
1857 * and a stack of states kept, to allow for definitions of structs
1858 * within structs.
c6d46f5f
JB
1859 *
1860 * This structdef business is NOT invoked when we are ctags and the
1861 * file is plain C. This is because a struct tag may have the same
1862 * name as another tag, and this loses with ctags.
1863 *
13fde0cd
RS
1864 * This if statement deals with the typdef state machine as
1865 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1866 * return (FALSE). All the other code here is for the structdef
1867 * state machine.
c6d46f5f
JB
1868 */
1869 switch (toktype)
1870 {
1871 case st_C_struct:
1872 case st_C_enum:
13fde0cd 1873 if (typdef == ttypedseen
591fa824 1874 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
c6d46f5f
JB
1875 {
1876 structdef = skeyseen;
1877 structkey = tokse;
1878 }
13fde0cd 1879 return (FALSE);
c6d46f5f 1880 }
c6d46f5f
JB
1881 if (structdef == skeyseen)
1882 {
13fde0cd 1883 if (stab_type (structkey) == st_C_struct)
c6d46f5f 1884 {
13fde0cd
RS
1885 (void) strncpy (structtag, tokp->p, tokp->len);
1886 structtag[tokp->len] = '\0'; /* for struct/union/class */
c6d46f5f
JB
1887 }
1888 else
1889 {
13fde0cd 1890 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
c6d46f5f 1891 }
13fde0cd
RS
1892 structdef = stagseen;
1893 return (TRUE);
c6d46f5f 1894 }
13fde0cd
RS
1895
1896 /* Avoid entering funcdef stuff if typdef is going on. */
1897 if (typdef != tnone)
c6d46f5f 1898 {
13fde0cd
RS
1899 definedef = dnone;
1900 return (FALSE);
c6d46f5f 1901 }
13fde0cd 1902
c6d46f5f 1903 /* Detect GNUmacs's function-defining macros. */
4746118a 1904 if (definedef == dnone)
c6d46f5f 1905 {
daa37602
JB
1906 if (strneq (tokp->p, "DEF", 3)
1907 || strneq (tokp->p, "ENTRY", 5)
1908 || strneq (tokp->p, "SYSCALL", 7)
1909 || strneq (tokp->p, "PSEUDO", 6))
4746118a
JB
1910 {
1911 next_token_is_func = TRUE;
13fde0cd 1912 return (FALSE);
4746118a 1913 }
13fde0cd 1914 if (strneq (tokp->p, "EXFUN", 5))
4746118a
JB
1915 {
1916 next_token_is_func = FALSE;
13fde0cd 1917 return (FALSE);
4746118a 1918 }
c6d46f5f
JB
1919 }
1920 if (next_token_is_func)
1921 {
1922 next_token_is_func = FALSE;
591fa824 1923 *is_func = TRUE;
13fde0cd 1924 return (TRUE);
c6d46f5f 1925 }
13fde0cd
RS
1926
1927 /* A function? */
1928 switch (toktype)
c6d46f5f 1929 {
13fde0cd 1930 case st_C_typespec:
591fa824 1931 funcdef = fnone; /* should be useless */
13fde0cd
RS
1932 return (FALSE);
1933 default:
1934 funcdef = ftagseen;
1935 *is_func = TRUE;
1936 return (TRUE);
c6d46f5f 1937 }
c6d46f5f
JB
1938}
1939\f
1940/* Fortran parsing */
1941
1942char *dbp;
1943int pfcnt;
1944
1945int
1946PF_funcs (fi)
1947 FILE *fi;
1948{
1949 lineno = 0;
1950 charno = 0;
1951 pfcnt = 0;
1952
1953 while (!feof (fi))
1954 {
1955 lineno++;
1956 linecharno = charno;
1957 charno += readline (&lb, fi);
1958 dbp = lb.buffer;
1959 if (*dbp == '%')
1960 dbp++; /* Ratfor escape to fortran */
1961 while (isspace (*dbp))
1962 dbp++;
1963 if (*dbp == 0)
1964 continue;
1965 switch (*dbp | ' ')
1966 {
1967 case 'i':
1968 if (tail ("integer"))
1969 takeprec ();
1970 break;
1971 case 'r':
1972 if (tail ("real"))
1973 takeprec ();
1974 break;
1975 case 'l':
1976 if (tail ("logical"))
1977 takeprec ();
1978 break;
1979 case 'c':
1980 if (tail ("complex") || tail ("character"))
1981 takeprec ();
1982 break;
1983 case 'd':
1984 if (tail ("double"))
1985 {
1986 while (isspace (*dbp))
1987 dbp++;
1988 if (*dbp == 0)
1989 continue;
1990 if (tail ("precision"))
1991 break;
1992 continue;
1993 }
1994 break;
1995 }
1996 while (isspace (*dbp))
1997 dbp++;
1998 if (*dbp == 0)
1999 continue;
2000 switch (*dbp | ' ')
2001 {
2002 case 'f':
2003 if (tail ("function"))
2004 getit ();
2005 continue;
2006 case 's':
2007 if (tail ("subroutine"))
2008 getit ();
2009 continue;
8a6c8bcf
RS
2010 case 'e':
2011 if (tail ("entry"))
2012 getit ();
2013 continue;
c6d46f5f
JB
2014 case 'p':
2015 if (tail ("program"))
2016 {
2017 getit ();
2018 continue;
2019 }
2020 if (tail ("procedure"))
2021 getit ();
2022 continue;
2023 }
2024 }
2025 return (pfcnt);
2026}
2027
2028logical
2029tail (cp)
2030 char *cp;
2031{
2032 register int len = 0;
2033
2034 while (*cp && (*cp & ~' ') == ((*(dbp + len)) & ~' '))
2035 cp++, len++;
2036 if (*cp == 0)
2037 {
2038 dbp += len;
2039 return (1);
2040 }
2041 return (0);
2042}
2043
2044void
2045takeprec ()
2046{
2047 while (isspace (*dbp))
2048 dbp++;
2049 if (*dbp != '*')
2050 return;
2051 dbp++;
2052 while (isspace (*dbp))
2053 dbp++;
2054 if (!isdigit (*dbp))
2055 {
2056 --dbp; /* force failure */
2057 return;
2058 }
2059 do
2060 dbp++;
2061 while (isdigit (*dbp));
2062}
2063
2064void
2065getit ()
2066{
2067 register char *cp;
2068 char c;
2069 char nambuf[BUFSIZ];
2070
2071 while (isspace (*dbp))
2072 dbp++;
daa37602
JB
2073 if (*dbp == 0
2074 || (!isalpha (*dbp)
2075 && *dbp != '_'
2076 && *dbp != '$'))
c6d46f5f
JB
2077 return;
2078 for (cp = dbp + 1; *cp && (isalpha (*cp) || isdigit (*cp)
2079 || (*cp == '_') || (*cp == '$')); cp++)
2080 continue;
2081 c = cp[0];
2082 cp[0] = 0;
2083 (void) strcpy (nambuf, dbp);
2084 cp[0] = c;
2085 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2086 pfcnt++;
2087}
2088
2089/* Handle a file of assembler code. */
2090
2091void
2092Asm_funcs (fi)
2093 FILE *fi;
2094{
2095 int i;
2096 register char c;
2097
2098 lineno = 0;
2099 charno = 0;
2100 pfcnt = 0;
2101
2102 while (!feof (fi))
2103 {
2104 lineno++;
2105 linecharno = charno;
2106 charno += readline (&lb, fi);
2107 dbp = lb.buffer;
2108
2109 for (i = 0; ((c = dbp[i]) && !isspace (c)) && (c != ':'); i++)
2110 ;
2111
2112 if ((i > 0) && (c == ':'))
2113 getit ();
2114 }
2115}
2116\f
2117/* Added by Mosur Mohan, 4/22/88 */
2118/* Pascal parsing */
2119
2120#define GET_NEW_LINE \
2121{ \
2122 linecharno = charno; lineno++; \
2123 charno += 1 + readline (&lb, inf); \
2124 dbp = lb.buffer; \
2125}
2126
2127/* Locates tags for procedures & functions.
2128 * Doesn't do any type- or var-definitions.
2129 * It does look for the keyword "extern" or "forward"
2130 * immediately following the procedure statement;
2131 * if found, the tag is skipped.
2132 */
2133
2134void
2135PAS_funcs (fi)
2136 FILE *fi;
2137{
2138 struct linebuffer tline; /* mostly copied from C_entries */
2139 long save_lcno;
2140 int save_lineno;
2141 char c, *cp;
2142 char nambuf[BUFSIZ];
2143
2144 logical /* each of these flags is TRUE iff: */
2145 incomm1, /* point is inside {..} comment */
2146 incomm2, /* point is inside (*..*) comment */
2147 inquote, /* point is inside '..' string */
2148 get_tagname, /* point is after PROCEDURE/FUNCTION */
2149 /* keyword, so next item = potential tag */
2150 found_tag, /* point is after a potential tag */
2151 inparms, /* point is within parameter-list */
2152 verify_tag; /* point has passed the parm-list, so the */
2153 /* next token will determine whether */
2154 /* this is a FORWARD/EXTERN to be */
2155 /* ignored, or whether it is a real tag */
2156
2157 lineno = 0;
2158 charno = 0;
2159 dbp = lb.buffer;
2160 *dbp = 0;
2161 initbuffer (&tline);
2162
2163 incomm1 = incomm2 = inquote = FALSE;
2164 found_tag = FALSE; /* have a proc name; check if extern */
2165 get_tagname = FALSE; /* have found "procedure" keyword */
2166 inparms = FALSE; /* found '(' after "proc" */
2167 verify_tag = FALSE; /* check if "extern" is ahead */
2168
2169 /* long main loop to get next char */
2170 while (!feof (fi))
2171 {
2172 c = *dbp++;
2173 if (c == 0) /* if end of line */
2174 {
2175 GET_NEW_LINE;
2176 if (*dbp == 0)
2177 continue;
2178 if (!((found_tag && verify_tag) ||
2179 get_tagname))
2180 c = *dbp++; /* only if don't need *dbp pointing */
2181 /* to the beginning of the name of */
2182 /* the procedure or function */
2183 }
2184 if (incomm1) /* within { - } comments */
2185 {
2186 if (c == '}')
2187 incomm1 = FALSE;
2188 continue;
2189 }
2190 else if (incomm2) /* within (* - *) comments */
2191 {
2192 if (c == '*')
2193 {
2194 while ((c = *dbp++) == '*')
2195 continue;
2196 if (c == 0)
2197 GET_NEW_LINE;
2198 if (c == ')')
2199 incomm2 = FALSE;
2200 }
2201 continue;
2202 }
2203 else if (inquote)
2204 {
2205 if (c == '\'')
2206 inquote = FALSE;
2207 continue;
2208 }
2209 else
2210 switch (c)
2211 {
2212 case '\'':
2213 inquote = TRUE; /* found first quote */
2214 continue;
2215 case '{': /* found open-{-comment */
2216 incomm1 = TRUE;
2217 continue;
2218 case '(':
2219 if (*dbp == '*') /* found open-(*-comment */
2220 {
2221 incomm2 = TRUE;
2222 dbp++;
2223 }
2224 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2225 inparms = TRUE;
2226 continue;
2227 case ')': /* end of parms list */
2228 if (inparms)
2229 inparms = FALSE;
2230 continue;
2231 case ';':
2232 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2233 {
2234 verify_tag = TRUE;
2235 break;
2236 }
2237 continue;
2238 }
2239 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2240 {
2241 /* check if this is an "extern" declaration */
2242 if (*dbp == 0)
2243 continue;
2244 if ((*dbp == 'e') || (*dbp == 'E'))
2245 {
2246 if (tail ("extern")) /* superfluous, really! */
2247 {
2248 found_tag = FALSE;
2249 verify_tag = FALSE;
2250 }
2251 }
2252 else if ((*dbp == 'f') || (*dbp == 'F'))
2253 {
2254 if (tail ("forward")) /* check for forward reference */
2255 {
2256 found_tag = FALSE;
2257 verify_tag = FALSE;
2258 }
2259 }
2260 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2261 {
2262 found_tag = FALSE;
2263 verify_tag = FALSE;
2264 pfnote (nambuf, TRUE, FALSE,
2265 tline.buffer, cp - tline.buffer + 1,
2266 save_lineno, save_lcno);
2267 continue;
2268 }
2269 }
2270 if (get_tagname) /* grab name of proc or fn */
2271 {
2272 if (*dbp == 0)
2273 continue;
2274
2275 /* save all values for later tagging */
2276 tline.size = lb.size;
2277 strcpy (tline.buffer, lb.buffer);
2278 save_lineno = lineno;
2279 save_lcno = linecharno;
2280
2281 /* grab block name */
2282 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2283 continue;
2284 c = cp[0];
2285 cp[0] = 0;
2286 strcpy (nambuf, dbp);
2287 cp[0] = c;
2288 dbp = cp; /* restore dbp to e-o-token */
2289 get_tagname = FALSE;
2290 found_tag = TRUE;
2291 continue;
2292
2293 /* and proceed to check for "extern" */
2294 }
2295 if ((!incomm1) && (!incomm2) && (!inquote) &&
2296 (!found_tag) && (!get_tagname))
2297 {
2298 /* check for proc/fn keywords */
2299 switch (c | ' ')
2300 {
2301 case 'p':
2302 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2303 get_tagname = TRUE;
2304 continue;
2305 case 'f':
2306 if (tail ("unction"))
2307 get_tagname = TRUE;
2308 continue;
2309 }
2310 }
2311 } /* while not e-o-f */
2312}
2313\f
2314/*
2315 * lisp tag functions
2316 * just look for (def or (DEF
2317 */
2318
2319void
2320L_funcs (fi)
2321 FILE *fi;
2322{
2323 lineno = 0;
2324 charno = 0;
2325 pfcnt = 0;
2326
2327 while (!feof (fi))
2328 {
2329 lineno++;
2330 linecharno = charno;
2331 charno += readline (&lb, fi);
2332 dbp = lb.buffer;
2333 if (dbp[0] == '(')
2334 {
2335 if (L_isdef (dbp))
2336 {
2337 while (!isspace (*dbp))
2338 dbp++;
2339 while (isspace (*dbp))
2340 dbp++;
2341 L_getit ();
2342 }
2343 else
2344 {
2345 /* Check for (foo::defmumble name-defined ... */
2346 while (*dbp && *dbp != ':' && !isspace (*dbp)
2347 && *dbp != '(' && *dbp != ')')
2348 dbp++;
2349 if (*dbp == ':')
2350 {
2351 while (*dbp == ':')
2352 dbp++;
2353
2354 if (L_isdef (dbp))
2355 {
2356 while (!isspace (*dbp))
2357 dbp++;
2358 while (isspace (*dbp))
2359 dbp++;
2360 L_getit ();
2361 }
2362 }
2363 }
2364 }
2365 }
2366}
2367
2368int
2369L_isdef (dbp)
2370 char *dbp;
2371{
2372 return ((dbp[1] == 'D' || dbp[1] == 'd') &&
2373 (dbp[2] == 'E' || dbp[2] == 'e') &&
2374 (dbp[3] == 'F' || dbp[3] == 'f'));
2375}
2376
2377void
2378L_getit ()
2379{
2380 register char *cp;
2381 char c;
2382 char nambuf[BUFSIZ];
2383
2384 if (*dbp == 0)
2385 return;
2386 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ' '; cp++)
2387 continue;
2388 c = cp[0];
2389 cp[0] = 0;
2390 (void) strcpy (nambuf, dbp);
2391 cp[0] = c;
591fa824
RS
2392 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2393 cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f
JB
2394 pfcnt++;
2395}
2396\f
2397/*
2398 * Scheme tag functions
2399 * look for (def... xyzzy
2400 * look for (def... (xyzzy
2401 * look for (def ... ((...(xyzzy ....
2402 * look for (set! xyzzy
2403 */
2404
2405static void get_scheme ();
2406
2407void
2408Scheme_funcs (fi)
2409 FILE *fi;
2410{
2411 lineno = 0;
2412 charno = 0;
2413 pfcnt = 0;
2414
2415 while (!feof (fi))
2416 {
2417 lineno++;
2418 linecharno = charno;
2419 charno += readline (&lb, fi);
2420 dbp = lb.buffer;
2421 if (dbp[0] == '(' &&
2422 (dbp[1] == 'D' || dbp[1] == 'd') &&
2423 (dbp[2] == 'E' || dbp[2] == 'e') &&
2424 (dbp[3] == 'F' || dbp[3] == 'f'))
2425 {
2426 while (!isspace (*dbp))
2427 dbp++;
2428 /* Skip over open parens and white space */
2429 while (*dbp && (isspace (*dbp) || *dbp == '('))
2430 dbp++;
2431 get_scheme ();
2432 }
2433 if (dbp[0] == '(' &&
2434 (dbp[1] == 'S' || dbp[1] == 's') &&
2435 (dbp[2] == 'E' || dbp[2] == 'e') &&
2436 (dbp[3] == 'T' || dbp[3] == 't') &&
2437 (dbp[4] == '!' || dbp[4] == '!') &&
2438 (isspace (dbp[5])))
2439 {
2440 while (!isspace (*dbp))
2441 dbp++;
2442 /* Skip over white space */
2443 while (isspace (*dbp))
2444 dbp++;
2445 get_scheme ();
2446 }
2447 }
2448}
2449
2450static void
2451get_scheme ()
2452{
2453 register char *cp;
2454 char c;
2455 char nambuf[BUFSIZ];
2456
2457 if (*dbp == 0)
2458 return;
2459 /* Go till you get to white space or a syntactic break */
2460 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2461 continue;
2462 /* Null terminate the string there. */
2463 c = cp[0];
2464 cp[0] = 0;
2465 /* Copy the string */
2466 strcpy (nambuf, dbp);
2467 /* Unterminate the string */
2468 cp[0] = c;
2469 /* Announce the change */
2470 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2471 pfcnt++;
2472}
2473\f
2474/* Find tags in TeX and LaTeX input files. */
2475
2476/* TEX_toktab is a table of TeX control sequences that define tags.
2477 Each TEX_tabent records one such control sequence.
2478 CONVERT THIS TO USE THE Stab TYPE!! */
2479
2480struct TEX_tabent
2481{
2482 char *name;
2483 int len;
2484};
2485
2486struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2487
2488/* Default set of control sequences to put into TEX_toktab.
2489 The value of environment var TEXTAGS is prepended to this. */
2490
2491static char *TEX_defenv =
2492":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2493
2494void TEX_mode ();
2495struct TEX_tabent *TEX_decode_env ();
2496void TEX_getit ();
2497int TEX_Token ();
2498
2499static char TEX_esc = '\\';
2500static char TEX_opgrp = '{';
2501static char TEX_clgrp = '}';
2502
2503/*
2504 * TeX/LaTeX scanning loop.
2505 */
2506
2507void
2508TEX_funcs (fi)
2509 FILE *fi;
2510{
2511 char *lasthit;
2512
2513 lineno = 0;
2514 charno = 0;
2515 pfcnt = 0;
2516
2517 /* Select either \ or ! as escape character. */
2518 TEX_mode (fi);
2519
2520 /* Initialize token table once from environment. */
2521 if (!TEX_toktab)
2522 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2523
2524 while (!feof (fi))
d2729198 2525 { /* Scan each line in file */
c6d46f5f
JB
2526 lineno++;
2527 linecharno = charno;
2528 charno += readline (&lb, fi);
2529 dbp = lb.buffer;
2530 lasthit = dbp;
d2729198 2531 while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
8a6c8bcf
RS
2532 {
2533 register int i;
c6d46f5f 2534
8a6c8bcf
RS
2535 if (!*(++dbp))
2536 break;
2537 linecharno += dbp - lasthit;
c6d46f5f 2538 lasthit = dbp;
8a6c8bcf
RS
2539 i = TEX_Token (lasthit);
2540 if (0 <= i)
c6d46f5f 2541 {
8a6c8bcf 2542 TEX_getit (lasthit, TEX_toktab[i].len);
d2729198 2543 break; /* We only save a line once */
c6d46f5f
JB
2544 }
2545 }
2546 }
2547}
2548
2549#define TEX_LESC '\\'
2550#define TEX_SESC '!'
2551#define TEX_cmt '%'
2552
2553/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2554/* chars accordingly. */
2555
2556void
2557TEX_mode (f)
2558 FILE *f;
2559{
2560 int c;
2561
2562 while ((c = getc (f)) != EOF)
2563 {
2564 /* Skip to next line if we hit the TeX comment char. */
2565 if (c == TEX_cmt)
2566 while (c != '\n')
2567 c = getc (f);
2568 else if (c == TEX_LESC || c == TEX_SESC )
2569 break;
2570 }
2571
2572 if (c == TEX_LESC)
2573 {
2574 TEX_esc = TEX_LESC;
2575 TEX_opgrp = '{';
2576 TEX_clgrp = '}';
2577 }
2578 else
2579 {
2580 TEX_esc = TEX_SESC;
2581 TEX_opgrp = '<';
2582 TEX_clgrp = '>';
2583 }
2584 rewind (f);
2585}
2586
2587/* Read environment and prepend it to the default string. */
2588/* Build token table. */
2589
2590struct TEX_tabent *
2591TEX_decode_env (evarname, defenv)
2592 char *evarname;
2593 char *defenv;
2594{
2595 register char *env, *p;
c6d46f5f
JB
2596
2597 struct TEX_tabent *tab;
2598 int size, i;
2599
2600 /* Append default string to environment. */
2601 env = getenv (evarname);
2602 if (!env)
2603 env = defenv;
2604 else
2605 env = concat (env, defenv, "");
2606
2607 /* Allocate a token table */
2608 for (size = 1, p = env; p;)
8a6c8bcf 2609 if ((p = etags_index (p, ':')) && *(++p))
c6d46f5f 2610 size++;
8a6c8bcf
RS
2611 /* Add 1 to leave room for null terminator. */
2612 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
2613
2614 /* Unpack environment string into token table. Be careful about */
2615 /* zero-length strings (leading ':', "::" and trailing ':') */
2616 for (i = 0; *env;)
2617 {
8a6c8bcf 2618 p = etags_index (env, ':');
c6d46f5f
JB
2619 if (!p) /* End of environment string. */
2620 p = env + strlen (env);
2621 if (p - env > 0)
2622 { /* Only non-zero strings. */
2623 tab[i].name = savenstr (env, p - env);
2624 tab[i].len = strlen (tab[i].name);
2625 i++;
2626 }
2627 if (*p)
2628 env = p + 1;
2629 else
2630 {
2631 tab[i].name = NULL; /* Mark end of table. */
2632 tab[i].len = 0;
2633 break;
2634 }
2635 }
2636 return tab;
2637}
2638
2639/* Record a tag defined by a TeX command of length LEN and starting at NAME.
2640 The name being defined actually starts at (NAME + LEN + 1).
2641 But we seem to include the TeX command in the tag name. */
2642
2643void
2644TEX_getit (name, len)
2645 char *name;
2646 int len;
2647{
2648 char *p = name + len;
2649 char nambuf[BUFSIZ];
2650
2651 if (*name == 0)
2652 return;
2653
2654 /* Let tag name extend to next group close (or end of line) */
2655 while (*p && *p != TEX_clgrp)
2656 p++;
2657 (void) strncpy (nambuf, name, p - name);
2658 nambuf[p - name] = 0;
2659
2660 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2661 pfcnt++;
2662}
2663
2664/* If the text at CP matches one of the tag-defining TeX command names,
8a6c8bcf 2665 return the etags_index of that command in TEX_toktab.
c6d46f5f
JB
2666 Otherwise return -1. */
2667
2668/* Keep the capital `T' in `Token' for dumb truncating compilers
2669 (this distinguishes it from `TEX_toktab' */
2670int
2671TEX_Token (cp)
2672 char *cp;
2673{
2674 int i;
2675
2676 for (i = 0; TEX_toktab[i].len > 0; i++)
2677 if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
2678 return i;
2679 return -1;
2680}
2681\f
2682/* Support for Prolog. */
2683
2684/* whole head (not only functor, but also arguments)
2685 is gotten in compound term. */
2686
2687void
2688prolog_getit (s, lineno, linecharno)
2689 char *s;
2690 int lineno;
2691 long linecharno;
2692{
2693 char nambuf[BUFSIZ], *save_s, tmpc;
2694 int insquote, npar;
2695
2696 save_s = s;
2697 insquote = FALSE;
2698 npar = 0;
2699 while (1)
2700 {
2701 if (*s == '\0') /* syntax error. */
2702 return;
2703 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2704 s += 2;
2705 else if (*s == '\'')
2706 {
2707 insquote = !insquote;
2708 s++;
2709 }
2710 else if (!insquote && *s == '(')
2711 {
2712 npar++;
2713 s++;
2714 }
2715 else if (!insquote && *s == ')')
2716 {
2717 npar--;
2718 s++;
2719 if (npar == 0)
2720 break;
2721 else if (npar < 0) /* syntax error. */
2722 return;
2723 }
2724 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2725 { /* fullstop. */
2726 if (npar != 0) /* syntax error. */
2727 return;
2728 s++;
2729 break;
2730 }
2731 else
2732 s++;
2733 }
2734 tmpc = *s;
2735 *s = '\0';
2736 strcpy (nambuf, save_s);
2737 *s = tmpc;
2738 pfnote (nambuf, TRUE, save_s, strlen (nambuf), lineno, linecharno);
2739}
2740
2741/* It is assumed that prolog predicate starts from column 0. */
2742
2743void
2744prolog_funcs (fi)
2745 FILE *fi;
2746{
2747 void skip_comment (), prolog_getit ();
2748
2749 lineno = linecharno = charno = 0;
2750 while (!feof (fi))
2751 {
2752 lineno++;
2753 linecharno += charno;
2754 charno = readline (&lb, fi) + 1; /* 1 for newline. */
2755 dbp = lb.buffer;
2756 if (isspace (dbp[0])) /* not predicate header. */
2757 continue;
2758 else if (dbp[0] == '%') /* comment. */
2759 continue;
2760 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2761 skip_comment (&lb, fi, &lineno, &linecharno);
2762 else /* found. */
2763 prolog_getit (dbp, lineno, linecharno);
2764 }
2765}
2766
2767void
2768skip_comment (plb, fi, plineno, plinecharno)
2769 struct linebuffer *plb;
2770 FILE *fi;
2771 int *plineno; /* result */
2772 long *plinecharno; /* result */
2773{
2774 while (!substr ("*/", plb->buffer))
2775 {
2776 (*plineno)++;
2777 *plinecharno += readline (plb, fi) + 1;
2778 } /* 1 for newline. */
2779}
2780
2781/* Return TRUE if 'sub' exists somewhere in 's'. */
2782
2783int
2784substr (sub, s)
2785 char *sub;
2786 char *s;
2787{
8a6c8bcf 2788 while (*s && (s = etags_index (s, *sub)))
c6d46f5f
JB
2789 if (prestr (sub, s))
2790 return (TRUE);
2791 else
2792 s++;
2793 return (FALSE);
2794}
2795
2796/* Return TRUE if 'pre' is prefix of string 's'. */
2797
2798int
2799prestr (pre, s)
2800 char *pre;
2801 char *s;
2802{
2803 if (*pre == '\0')
2804 return (TRUE);
2805 else if (*pre == *s)
2806 return (prestr (pre + 1, s + 1));
2807 else
2808 return (FALSE);
2809}
2810\f
2811/* Initialize a linebuffer for use */
2812
2813void
2814initbuffer (linebuffer)
2815 struct linebuffer *linebuffer;
2816{
2817 linebuffer->size = 200;
2818 linebuffer->buffer = xnew (200, char);
2819}
2820
2821/*
2822 * Read a line of text from `stream' into `linebuffer'.
2823 * Return the number of characters read from `stream',
2824 * which is the length of the line including the newline, if any.
2825 */
2826long
2827readline (linebuffer, stream)
2828 struct linebuffer *linebuffer;
2829 register FILE *stream;
2830{
2831 char *buffer = linebuffer->buffer;
2832 register char *p = linebuffer->buffer;
2833 register char *pend;
2834 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2835
eb8c3be9 2836 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
c6d46f5f
JB
2837
2838 while (1)
2839 {
2840 register int c = getc (stream);
2841 if (p == pend)
2842 {
2843 linebuffer->size *= 2;
2844 buffer = (char *) xrealloc (buffer, linebuffer->size);
2845 p += buffer - linebuffer->buffer;
2846 pend = buffer + linebuffer->size;
2847 linebuffer->buffer = buffer;
2848 }
2849 if (c < 0 || c == '\n')
2850 {
2851 *p = 0;
2852 newline = (c == '\n' ? 1 : 0);
2853 break;
2854 }
2855 *p++ = c;
2856 }
2857
2858 return p - buffer + newline;
2859}
2860\f
2861char *
2862savestr (cp)
2863 char *cp;
2864{
2865 return savenstr (cp, strlen (cp));
2866}
2867
2868char *
2869savenstr (cp, len)
2870 char *cp;
2871 int len;
2872{
2873 register char *dp;
2874
2875 dp = xnew (len + 1, char);
2876 (void) strncpy (dp, cp, len);
2877 dp[len] = '\0';
2878 return dp;
2879}
2880
c6d46f5f
JB
2881/*
2882 * Return the ptr in sp at which the character c last
2883 * appears; NULL if not found
2884 *
2885 * Identical to v7 rindex, included for portability.
2886 */
2887
2888char *
8a6c8bcf 2889etags_rindex (sp, c)
c6d46f5f
JB
2890 register char *sp, c;
2891{
2892 register char *r;
2893
2894 r = NULL;
2895 do
2896 {
2897 if (*sp == c)
2898 r = sp;
2899 } while (*sp++);
2900 return (r);
2901}
2902
9d7ad1b3 2903
c6d46f5f
JB
2904/*
2905 * Return the ptr in sp at which the character c first
2906 * appears; NULL if not found
2907 *
2908 * Identical to v7 index, included for portability.
2909 */
2910
2911char *
8a6c8bcf 2912etags_index (sp, c)
c6d46f5f
JB
2913 register char *sp, c;
2914{
2915 do
2916 {
2917 if (*sp == c)
2918 return (sp);
2919 } while (*sp++);
2920 return (NULL);
2921}
2922
c6d46f5f
JB
2923/* Print error message and exit. */
2924
2925/* VARARGS1 */
2926void
2927fatal (s1, s2)
2928 char *s1, *s2;
2929{
2930 error (s1, s2);
2931 exit (1);
2932}
2933
2934/* Print error message. `s1' is printf control string, `s2' is arg for it. */
2935
2936/* VARARGS1 */
2937void
2938error (s1, s2)
2939 char *s1, *s2;
2940{
2941 fprintf (stderr, "%s: ", progname);
2942 fprintf (stderr, s1, s2);
2943 fprintf (stderr, "\n");
2944}
2945
2946/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
2947
2948char *
2949concat (s1, s2, s3)
2950 char *s1, *s2, *s3;
2951{
2952 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
2953 char *result = xnew (len1 + len2 + len3 + 1, char);
2954
2955 (void) strcpy (result, s1);
2956 (void) strcpy (result + len1, s2);
2957 (void) strcpy (result + len1 + len2, s3);
2958 *(result + len1 + len2 + len3) = 0;
2959
2960 return result;
2961}
2962
2963/* Like malloc but get fatal error if memory is exhausted. */
2964
2965char *
2966xmalloc (size)
2967 int size;
2968{
2969 char *result = malloc (size);
2970 if (!result)
2971 fatal ("virtual memory exhausted", 0);
2972 return result;
2973}
2974
2975char *
2976xrealloc (ptr, size)
2977 char *ptr;
2978 int size;
2979{
2980 char *result = realloc (ptr, size);
2981 if (!result)
2982 fatal ("virtual memory exhausted");
2983 return result;
2984}