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