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