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