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