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