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