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