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