The shell comment char is #, not ;.
[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
909 * by seting boolean flags dependent upon the corresponding character
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 }
1037 /* if not a .c or .h or .y file, try fortran */
4746118a
JB
1038 else if (cp && ((cp[1] != 'c'
1039 && cp[1] != 'h'
1040 && cp[1] != 'y')
c6d46f5f
JB
1041 || (cp[1] != 0 && cp[2] != 0)))
1042 {
1043 if (PF_funcs (inf) != 0)
1044 goto close_and_return;
1045 rewind (inf); /* no fortran tags found, try C */
1046 }
1047 C_entries (cplusplus ? C_PLPL : 0);
1048
1049close_and_return:
1050 (void) fclose (inf);
1051}
1052
1053/* Nonzero if string STR is composed of digits. */
1054
1055int
1056string_numeric_p (str)
1057 char *str;
1058{
1059 while (*str)
1060 {
1061 if (*str < '0' || *str > '9')
1062 return 0;
1063 }
1064 return 1;
1065}
1066\f
1067/* Record a tag. */
1068/* Should take a TOKEN* instead!! */
1069
1070void
1071pfnote (name, is_func, rewritten, linestart, linelen, lno, cno)
1072 char *name; /* tag name */
1073 logical is_func; /* function or type name? */
1074 logical rewritten; /* tag different from text of definition? */
1075 char *linestart;
1076 int linelen;
1077 int lno;
1078 long cno;
1079{
1080 register char *fp;
1081 register NODE *np;
1082 char tem[51];
1083 char c;
1084
1085 np = (NODE *) malloc (sizeof (NODE));
1086 if (np == NULL)
1087 {
1088 if (!emacs_tags_format)
1089 {
1090 /* It's okay to output early in etags -- it only disrupts the
1091 * character count of the tag entries, which is no longer used
1092 * by tags.el anyway.
1093 */
1094 error ("too many entries to sort");
1095 }
1096 put_entries (head);
1097 free_tree (head);
1098 head = NULL;
1099 np = xnew (1, NODE);
1100 }
1101 /* If ctags mode, change name "main" to M<thisfilename>. */
1102 if (!emacs_tags_format && !cxref_style && streq (name, "main"))
1103 {
8a6c8bcf 1104 fp = etags_rindex (curfile, '/');
c6d46f5f 1105 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
8a6c8bcf 1106 fp = etags_rindex (name, '.');
c6d46f5f
JB
1107 if (fp && fp[1] != '\0' && fp[2] == '\0')
1108 *fp = 0;
1109 rewritten = TRUE;
1110 }
1111 np->name = savestr (name);
1112 np->file = curfile;
1113 np->is_func = is_func;
1114 np->rewritten = rewritten;
1115 np->lno = lno;
1116 /* UNCOMMENT THE +1 HERE: */
1117 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
1118 np->left = np->right = 0;
1119 if (emacs_tags_format)
1120 {
1121 c = linestart[linelen];
1122 linestart[linelen] = 0;
1123 }
1124 else if (cxref_style == 0)
1125 {
1126 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
1127 linestart = tem;
1128 }
1129 np->pat = savestr (linestart);
1130 if (emacs_tags_format)
1131 {
1132 linestart[linelen] = c;
1133 }
1134
1135 add_node (np, &head);
1136}
1137
1138/*
1139 * free_tree ()
1140 * recurse on left children, iterate on right children.
1141 */
1142void
1143free_tree (node)
1144 register NODE *node;
1145{
1146 while (node)
1147 {
1148 register NODE *node_right = node->right;
1149 free_tree (node->left);
1150 free (node->name);
1151 free (node->pat);
1152 free ((char *) node);
1153 node = node_right;
1154 }
1155}
1156
1157/*
1158 * add_node ()
1159 * Adds a node to the tree of nodes. In etags mode, we don't keep
1160 * it sorted; we just keep a linear list. In ctags mode, maintain
1161 * an ordered tree, with no attempt at balancing.
1162 *
1163 * add_node is the only function allowed to add nodes, so it can
1164 * maintain state.
1165 */
1166void
1167add_node (node, cur_node_p)
1168 NODE *node, **cur_node_p;
1169{
1170 register int dif;
1171 register NODE *cur_node = *cur_node_p;
1172 static NODE *last_node = NULL;/* careful */
1173
1174 if (cur_node == NULL)
1175 {
1176 *cur_node_p = node;
1177 last_node = node;
1178 return;
1179 }
1180
1181 if (emacs_tags_format)
1182 {
1183 /* Etags Mode */
1184 if (!last_node)
1185 fatal ("internal error in add_node");
1186 last_node->right = node;
1187 last_node = node;
1188 }
1189 else
1190 {
1191 /* Ctags Mode */
1192 dif = strcmp (node->name, cur_node->name);
1193
1194 /*
1195 * If this tag name matches an existing one, then
1196 * do not add the node, but maybe print a warning.
1197 */
1198 if (!dif)
1199 {
1200 if (node->file == cur_node->file)
1201 {
1202 if (!no_warnings)
1203 {
1204 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1205 node->file, lineno, node->name);
1206 fprintf (stderr, "Second entry ignored\n");
1207 }
1208 return;
1209 }
1210 if (!cur_node->been_warned && !no_warnings)
1211 {
1212 fprintf (stderr,
1213 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1214 node->file, cur_node->file, node->name);
1215 }
1216 cur_node->been_warned = TRUE;
1217 return;
1218 }
1219
1220 /* Maybe refuse to add duplicate nodes. */
1221 if (!permit_duplicates)
1222 {
1223 if (!strcmp (node->name, cur_node->name)
1224 && !strcmp (node->file, cur_node->file))
1225 return;
1226 }
1227
1228 /* Actually add the node */
1229 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1230 }
1231}
1232\f
1233void
1234put_entries (node)
1235 reg NODE *node;
1236{
1237 reg char *sp;
1238
1239 if (node == NULL)
1240 return;
1241
1242 /* Output subentries that precede this one */
1243 put_entries (node->left);
1244
1245 /* Output this entry */
1246
1247 if (emacs_tags_format)
1248 {
1249 if (node->rewritten)
1250 {
1251 fprintf (outf, "%s\177%s\001%d,%d\n",
1252 node->name, node->pat, node->lno, node->cno);
1253 }
1254 else
1255 {
1256 fprintf (outf, "%s\177%d,%d\n",
1257 node->pat, node->lno, node->cno);
1258 }
1259 }
1260 else if (!cxref_style)
1261 {
1262 fprintf (outf, "%s\t%s\t",
1263 node->name, node->file);
1264
1265 if (node->is_func)
1266 { /* a function */
1267 putc (searchar, outf);
1268 putc ('^', outf);
1269
1270 for (sp = node->pat; *sp; sp++)
1271 {
1272 if (*sp == '\\' || *sp == searchar)
1273 putc ('\\', outf);
1274 putc (*sp, outf);
1275 }
1276 putc (searchar, outf);
1277 }
1278 else
1279 { /* a typedef; text pattern inadequate */
1280 fprintf (outf, "%d", node->lno);
1281 }
1282 putc ('\n', outf);
1283 }
1284 else if (vgrind_style)
1285 fprintf (stdout, "%s %s %d\n",
1286 node->name, node->file, (node->lno + 63) / 64);
1287 else
daa37602 1288 fprintf (stdout, "%-16s %3d %-16s %s\n",
c6d46f5f
JB
1289 node->name, node->lno, node->file, node->pat);
1290
1291 /* Output subentries that follow this one */
1292 put_entries (node->right);
1293}
1294
1295/* Length of a number's decimal representation. */
1296int
1297number_len (num)
1298 long num;
1299{
1300 int len = 0;
1301 if (!num)
1302 return 1;
1303 for (; num; num /= 10)
1304 ++len;
1305 return len;
1306}
1307
1308/*
1309 * Return total number of characters that put_entries will output for
1310 * the nodes in the subtree of the specified node. Works only if emacs_tags_format
1311 * is set, but called only in that case. This count is irrelevant with
1312 * the new tags.el, but is still supplied for backward compatibility.
1313 */
1314int
1315total_size_of_entries (node)
1316 reg NODE *node;
1317{
1318 reg int total;
1319
1320 if (node == NULL)
1321 return 0;
1322
1323 total = 0;
1324 for (; node; node = node->right)
1325 {
1326 /* Count left subentries. */
1327 total += total_size_of_entries (node->left);
1328
1329 /* Count this entry */
1330 total += strlen (node->pat) + 1;
1331 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1332 if (node->rewritten)
1333 total += 1 + strlen (node->name); /* \001name */
1334 }
1335
1336 return total;
1337}
1338\f
1339/*
1340 * The C symbol tables.
1341 */
1342
1343Stab *C_stab, *C_PLPL_stab, *C_STAR_stab;
1344
1345/*
1346 * SYNOPSIS
1347 * Stab *get_C_stab (int c_ext);
1348 */
1349#define get_C_stab(c_ext) ((c_ext&C_STAR) ? C_STAR_stab : \
1350 c_ext ? C_PLPL_stab : \
1351 C_stab)
1352
1353void
1354add_keyword (stab, sym, type)
1355 Stab *stab;
1356 char *sym;
1357 enum sym_type type;
1358{
1359 stab_search (stab, sym, strlen (sym))->type = type;
1360}
1361
1362Stab *
1363C_create_stab (c_ext)
1364 int c_ext;
1365{
1366 Stab *stab;
1367
1368 stab = stab_create ();
1369
1370 /* C, C++ and C* */
1371 if (c_ext & C_PLPL)
1372 add_keyword (stab, "class", st_C_struct);
1373 if (c_ext & C_STAR)
1374 add_keyword (stab, "domain", st_C_struct);
1375 add_keyword (stab, "union", st_C_struct);
1376 add_keyword (stab, "struct", st_C_struct);
1377 add_keyword (stab, "enum", st_C_enum);
1378 add_keyword (stab, "typedef", st_C_typedef);
1379 add_keyword (stab, "define", st_C_define);
1380 add_keyword (stab, "long", st_C_typespec);
1381 add_keyword (stab, "short", st_C_typespec);
1382 add_keyword (stab, "int", st_C_typespec);
1383 add_keyword (stab, "char", st_C_typespec);
1384 add_keyword (stab, "float", st_C_typespec);
1385 add_keyword (stab, "double", st_C_typespec);
1386 add_keyword (stab, "signed", st_C_typespec);
1387 add_keyword (stab, "unsigned", st_C_typespec);
1388 add_keyword (stab, "const", st_C_typespec);
1389 add_keyword (stab, "volatile", st_C_typespec);
1390
1391 return stab;
1392}
1393
1394void
1395C_create_stabs ()
1396{
1397 C_stab = C_create_stab (0);
1398 C_PLPL_stab = C_create_stab (C_PLPL);
1399 C_STAR_stab = C_create_stab (C_STAR | C_PLPL);
1400}
1401\f
1402/*
1403 * C_entries ()
1404 * This routine finds functions and typedefs in C syntax and adds them
1405 * to the list.
1406 */
1407
1408#define CNL_SAVE_DEFINEDEF \
1409{ \
1410 prev_linepos = linepos; \
1411 SET_FILEPOS (linepos, inf, charno); \
1412 lineno++; \
1413 charno += readline (&lb, inf); \
1414 lp = lb.buffer; \
1415}
1416
1417#define CNL \
1418{ \
1419 CNL_SAVE_DEFINEDEF; \
1420 definedef = dnone; \
1421}
1422
1423void
1424C_entries (c_ext)
1425 int c_ext; /* extension of C? */
1426{
1427 register int c; /* latest char read; '\0' for end of line */
1428 register int tokoff; /* offset in line of beginning of latest token */
1429 register int toklen; /* length of latest token */
1430 register char *lp; /* pointer one beyond the character `c' */
1431 logical incomm, inquote, inchar, midtoken;
1432 int level; /* current curly brace level */
1433 char tokb[BUFSIZ];
1434
1435 lineno = 0;
1436 charno = 0;
1437 lp = lb.buffer;
1438 *lp = 0;
1439
1440 definedef = dnone;
1441 gotone = midtoken = inquote = inchar = incomm = FALSE;
1442 level = 0;
4746118a
JB
1443 tydef = none;
1444 next_token_is_func = 0;
c6d46f5f
JB
1445
1446 C_create_stabs ();
1447
1448 while (!feof (inf))
1449 {
1450 c = *lp++;
c6d46f5f
JB
1451 if (c == '\\')
1452 {
4746118a
JB
1453 /* If we're at the end of the line, the next character is a
1454 '\0'; don't skip it, because it's the thing that tells us
1455 to read the next line. */
1e134a5f
RM
1456 if (*lp == 0)
1457 continue;
1458 lp++;
c6d46f5f
JB
1459 c = ' ';
1460 }
1461 else if (incomm)
1462 {
1e134a5f 1463 if (c == '*' && *lp == '/')
c6d46f5f 1464 {
1e134a5f
RM
1465 c = *lp++;
1466 incomm = FALSE;
c6d46f5f
JB
1467 }
1468 }
1469 else if (inquote)
1470 {
c6d46f5f
JB
1471 if (c == '"')
1472 inquote = FALSE;
daa37602
JB
1473 else if (c == '\\')
1474 c = *lp++;
c6d46f5f
JB
1475 }
1476 else if (inchar)
1477 {
1478 if (c == '\'')
1479 inchar = FALSE;
1480 continue;
1481 }
1482 else
1483 switch (c)
1484 {
1485 case '"':
1486 inquote = TRUE;
1487 continue;
1488 case '\'':
1489 inchar = TRUE;
1490 continue;
1491 case '/':
1492 if (*lp == '*')
1493 {
1494 lp++;
1495 incomm = TRUE;
1496 }
1497 else if (c_ext && *lp == '/')
1498 {
daa37602
JB
1499 c = 0;
1500 break;
c6d46f5f
JB
1501 }
1502 continue;
1503 case '#':
1504 if (lp == lb.buffer + 1 && definedef == dnone)
1505 definedef = dsharpseen;
1506 continue;
1507
1508 /*
1509 * The next two are to help the strucdef state machine.
1510 * They break when they are finished, so they don't interfere
1511 * with anything else that is going on.
1512 */
1513 case ':':
1514 if (structdef == stagseen)
1515 structdef = scolonseen;
1516 break;
1517 /* Not a struct definition when semicolon seen in non-sinbody context. */
1518 case ';':
1519 if (structdef != snone && structdef != sinbody)
1520 {
1521 structdef = snone;
1522 (void) strcpy (structtag, "<error 1>");
1523 }
1524 break;
1525
1526 case '{':
1527 if (tydef == begin)
1528 {
1529 tydef = middle;
1530 }
1531 switch (structdef)
1532 {
1533 case skeyseen: /* unnamed struct */
1534 structtag[0] = '\0';
1535 /* FALLTHRU */
1536 case stagseen:
1537 case scolonseen: /* named struct */
1538 structdef = sinbody;
1539 break;
1540 }
1541 level++;
1542 continue;
1543 case '}':
1544 if (!noindentypedefs && lp == lb.buffer + 1)
1545 level = 0; /* reset level if first column */
1546 else if (level > 0)
1547 level--;
1548 if (level == 0 && tydef == middle)
1549 {
1550 tydef = end;
1551 }
1552 if (level == 0)
1553 {
1554 structdef = snone;
1555 (void) strcpy (structtag, "<error 2>");
1556 }
1557 continue;
1558 }
1559 if (LEVEL_OK_FOR_FUNCDEF () && !inquote && !incomm && gotone == FALSE)
1560 {
1561 if (midtoken)
1562 {
1563 if (endtoken (c))
1564 {
1565 if (c_ext && c == ':' && *lp == ':' && intoken (*(lp + 1)))
1566 {
1567 /*
1568 * This handles :: in the middle, but not at beginning
1569 * of an identifier.
1570 */
1571 lp += 2;
1572 toklen += 3;
1573 }
1574 else
1575 {
1e134a5f
RM
1576 /* The following is no longer true,
1577 now that we advance to the next line
1578 at the end of processing the character. */
c6d46f5f
JB
1579 /*
1580 * We've just finished lexing an identifier.
1581 * Note that if `c' is '\0', `lb' is the NEXT
1582 * line, `lp' points to the beginning of it, and
1583 * old pointers into `lb.buffer' may no longer be
1584 * valid, since `lb.buffer' may have been
1585 * reallocated. In this case (which corresponds
1586 * to an identifier followed immediately by a
1587 * newline), we re-read the line into lb1.
1588 *
1589 * This would be faster if the previous line's
1590 * buffer were always saved.
1591 */
1592 logical is_func;
1593 char *tok_linebuf;
1594 TOKEN tok;
1595 logical bingo, tok_at_end_of_line;
1596 char *lp_tmp; /* addressable */
1597
1e134a5f 1598#if 0
c6d46f5f
JB
1599 if (c == '\0')
1600 {
1601 getline (GET_COOKIE (prev_linepos));
1602 tok_linebuf = lb1.buffer;
1603 tok_at_end_of_line = TRUE;
1604 tok.linestart = prev_linepos;
1605 tok.lineno = lineno - 1;
1606 }
1607 else
1e134a5f 1608#endif
c6d46f5f
JB
1609 {
1610 tok_linebuf = lb.buffer;
1611 tok_at_end_of_line = FALSE;
1612 tok.linestart = linepos;
1613 tok.lineno = lineno;
1614 }
1615 tok.p = tok_linebuf + tokoff;
1616 tok.len = toklen;
1617 tok.rewritten = FALSE;
1618 lp_tmp = lp;
1619 bingo = consider_token (c, &lp_tmp, &tok,
1620 &is_func, c_ext, level);
1621 lp = lp_tmp;
1622 if (bingo)
1623 {
1624 if (GET_CHARNO (tok.linestart) != GET_CHARNO (linepos)
1625 && !tok_at_end_of_line)
1626 {
1627 /*
1628 * Resynchronize tok.p to point into the right
1629 * linebuffer.
1630 */
1631 getline (GET_COOKIE (tok.linestart));
1632 if (!tok.rewritten)
1633 tok.p = lb1.buffer + (tok.p - tok_linebuf);
1634 tok_linebuf = lb1.buffer;
1635 }
1636 if (structdef == sinbody && definedef == dnone && is_func)
1637 { /* function defined in C++ class body */
1638 sprintf (tokb, "%s::%.*s",
1639 structtag[0] == '\0' ? "_anonymous_"
1640 : structtag,
1641 tok.len, tok.p);
1642 tok.rewritten = TRUE;
1643 }
1644 else
1645 {
1646 sprintf (tokb, "%.*s", tok.len, tok.p);
1647 }
1648 pfnote (tokb, is_func, tok.rewritten, tok_linebuf,
1649 tokoff + toklen + (tok_at_end_of_line ? 0 : 1),
1650 tok.lineno, GET_CHARNO (tok.linestart));
1651 gotone = is_func; /* function */
1652 }
1653 midtoken = FALSE;
1654 }
1655 }
1656 else if (intoken (c))
1657 toklen++;
1658 }
1659 else if (begtoken (c))
1660 {
1661 tokoff = lp - 1 - lb.buffer;
1662 toklen = 1;
1663 midtoken = TRUE;
1664 }
1665 }
1e134a5f
RM
1666 /* Detect end of line, after having handled the last token on the line. */
1667 if (c == 0)
1668 {
1669 CNL;
1670 gotone = FALSE;
1671 }
c6d46f5f
JB
1672 if (c == ';' && tydef == end) /* clean with typedefs */
1673 tydef = none;
1674 }
1675}
1676
1677/*
1678 * consider_token ()
1679 * checks to see if the current token is at the start of a
1680 * function, or corresponds to a typedef. It updates the input
1681 * line pointer *LPP so that the '(' will be in it when it returns.
1682 *
1683 * *IS_FUNC gets TRUE iff the token is a function.
1684 * C_EXT is which language we are looking at.
1685 *
1686 * In the future we will need some way to adjust where the end of
1687 * the token is; for instance, implementing the C++ keyword
1688 * `operator' properly will adjust the end of the token to be after
1689 * whatever follows `operator'.
1690 *
1691 * Globals
1692 * structdef IN OUT
1693 * definedef IN OUT
1694 * tydef IN OUT
1695 */
1696
1697logical
1698consider_token (c, lpp, tokp, is_func, c_ext, level)
1699 reg char c; /* IN: first char after the token */
1700 char **lpp; /* IN OUT: *lpp points to 2nd char after the token */
1701 reg TOKEN *tokp; /* IN */
1702 logical *is_func; /* OUT */
1703 int c_ext; /* IN */
1704 int level; /* IN */
1705{
1706 reg char *lp = *lpp;
c6d46f5f
JB
1707 logical firsttok; /* TRUE if have seen first token in ()'s */
1708 Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
1709 enum sym_type toktype = stab_type (tokse);
1710
1711 *is_func = TRUE; /* a function */
1712
1713 /*
1714 * Advance the definedef state machine. We set `gotone' for good measure;
1715 * it's redundant.
1716 */
1717 switch (definedef)
1718 {
1719 case dnone:
1720 /* We're not on a preprocessor line. */
1721 break;
1722 case dsharpseen:
1723 if (toktype == st_C_define)
1724 {
1725 definedef = ddefineseen;
1726 gotone = FALSE;
1727 }
1728 else
1729 {
1730 definedef = dignorerest;
1731 gotone = TRUE;
1732 }
1733 goto badone;
1734 case ddefineseen:
1735 /*
1736 * Make a tag for any macro.
1737 * This will flub up if there is a newline immediately following
1738 * the macro name.
1739 */
1740 *is_func = (c == '(');
1741 definedef = dignorerest;
1742 gotone = TRUE;
1743 if (!*is_func && !constantypedefs)
1744 goto badone;
1745 goto goodone;
1746 case dignorerest:
1747 goto badone;
1748 default:
1749 error ("internal error: definedef value");
1750 }
1751
1752 /*
1753 * Skip whitespace and comments after the token. This loop should
1754 * also skip C++ comments.
1755 */
1756 while (1)
1757 {
1758 /* At whitespace => skip it. */
1759 if (iswhite (c))
1760 {
1761 c = *lp++;
1762 }
1763 /* At a comment => skip to end of comment. */
1764 else if (c == '/' && *lp == '*')
1765 {
1766 /* If we find a comment, skip it. */
1767 while (!(c == '*' && *lp == '/'))
1768 {
1769 c = *lp++;
1770 if (c == 0)
1771 {
1e134a5f
RM
1772 lp--;
1773 break;
c6d46f5f
JB
1774 }
1775 }
1776 if (c == '*' && *lp == '/')
1777 {
1778 lp++; /* lp now points past the '/' */
1779 c = *lp++; /* c is now the --whatever-- after the '/' */
1780 }
1781 }
1782 else
1783 break;
1784
1785 /* If we arrived at eof or eol, decide which one it is.
1786 If it's eol, advance to the next line. */
1787
1788 if (c == 0)
1789 {
1e134a5f
RM
1790 lp--;
1791 break;
c6d46f5f
JB
1792 }
1793 }
1794
1795 /*
1796 * If you have custom token types, or when configuration files can
1797 * define custom token types, this switch will be larger.
1798 */
1799 switch (toktype)
1800 {
1801 case st_C_typedef:
1802 if (typedefs)
1803 {
1804 tydef = begin;
1805 goto badone;
1806 }
1807 break;
1808 case st_C_typespec:
1809 if (tydef == begin || tydef == end)
1810 {
1811 tydef = end;
1812 goto badone;
1813 }
1814 break;
1815 }
1816
1817 /*
1818 * This structdef business is currently only invoked when level==0.
1819 * It should be recursively invoked whatever the level, and a stack of
1820 * states kept, to allow for definitions of structs within structs.
1821 *
1822 * This structdef business is NOT invoked when we are ctags and the
1823 * file is plain C. This is because a struct tag may have the same
1824 * name as another tag, and this loses with ctags.
1825 *
1826 * This if statement deals with the tydef state machine as follows: if
1827 * tydef==begin and token is struct/union/class/enum, goto badone.
1828 * All the other code here is for the structdef state machine.
1829 */
1830 switch (toktype)
1831 {
1832 case st_C_struct:
1833 case st_C_enum:
1834 if (tydef == begin || (typedefs_and_cplusplus && level == 0 && structdef == snone))
1835 {
1836 structdef = skeyseen;
1837 structkey = tokse;
1838 }
1839 goto badone;
1840 }
1841
1842 if (structdef == skeyseen)
1843 {
1844 /* If next char is '{' or (for C++) ':', found a structure tag. */
1845 if (c == '{' || (c_ext && c == ':'))
1846 {
1847 /*
1848 * We should do this slightly differently for straight C:
1849 * instead of defining `tag', as we now do, we should define
1850 * `struct tag'. (Do this only if the find-tag defaulting is
1851 * done on a sophisticated per-mode basis, so that if the user
1852 * says meta-. anywhere in `struct foo', the default comes out
1853 * `struct foo', not `struct' or `foo'.) This will require
1854 * remembering which keyword (struct/union/class/enum) we saw, as a
1855 * Stab_entry* -- this will also make it possible to merge the
1856 * skeyseen and senumseen states, if we want.
1857 */
1858 if (stab_type (structkey) == st_C_struct)
1859 {
1860 (void) strncpy (structtag, tokp->p, tokp->len);
1861 structtag[tokp->len] = '\0'; /* for struct/union/class */
1862 structdef = stagseen;
1863 }
1864 else
1865 {
1866 structtag[0] = '\0'; /* for enum */
1867 }
1868 *is_func = FALSE; /* not a function */
1869 goto goodone;
1870 }
1871 else
1872 {
1873 /* Not a definition: reset structdef */
1874 structdef = snone;
1875 (void) strcpy (structtag, "<error 3>");
1876 }
1877 /* Now what? And how does/should this stuff interact with tydef?? */
1878 /* Also maybe reset lp to *lpp for benefit of the function finding code. */
1879 }
1880 if (tydef == begin)
1881 {
1882 tydef = end;
1883 goto badone;
1884 }
1885 if (tydef == end)
1886 {
1887 *is_func = 0;
1888 goto goodone;
1889 }
1890 /* Detect GNUmacs's function-defining macros. */
4746118a 1891 if (definedef == dnone)
c6d46f5f 1892 {
daa37602
JB
1893 if (strneq (tokp->p, "DEF", 3)
1894 || strneq (tokp->p, "ENTRY", 5)
1895 || strneq (tokp->p, "SYSCALL", 7)
1896 || strneq (tokp->p, "PSEUDO", 6))
4746118a
JB
1897 {
1898 next_token_is_func = TRUE;
1899 goto badone;
1900 }
1901 else if (strneq (tokp->p, "EXFUN", 5))
1902 {
1903 next_token_is_func = FALSE;
1904 goto badone;
1905 }
c6d46f5f
JB
1906 }
1907 if (next_token_is_func)
1908 {
1909 next_token_is_func = FALSE;
1910 goto goodone;
1911 }
1912 if (c != '(')
1913 goto badone;
1914 firsttok = FALSE;
1915 while ((c = *lp++) != ')')
1916 {
1917 if (c == 0)
1918 {
1e134a5f
RM
1919 lp--;
1920 break;
c6d46f5f
JB
1921 }
1922 /*
1923 * This line used to confuse ctags:
1924 * int (*oldhup)();
1925 * This fixes it. A nonwhite char before the first
1926 * token, other than a / (in case of a comment in there)
1927 * makes this not a declaration.
1928 */
1929 if (begtoken (c) || c == '/')
1930 firsttok++;
1931 else if (!iswhite (c) && !firsttok)
1932 goto badone;
1933 }
1934 while (iswhite (c = *lp++))
1935 {
1936 if (c == 0)
1937 {
1e134a5f
RM
1938 lp--;
1939 break;
c6d46f5f
JB
1940 }
1941 }
1942 if (!isgood (c))
1943 goto badone;
1944
1945goodone:
1946 *lpp = lp - 1;
1947 return TRUE;
1948
1949badone:
1950 *lpp = lp - 1;
1951 return FALSE;
1952}
1953
1954void
1955getline (atcookie)
1956 long atcookie;
1957{
1958 long saveftell = ftell (inf);
1959
1960 (void) fseek (inf, atcookie, 0);
1961 (void) readline (&lb1, inf);
1962 (void) fseek (inf, saveftell, 0);
1963}
1964\f
1965/* Fortran parsing */
1966
1967char *dbp;
1968int pfcnt;
1969
1970int
1971PF_funcs (fi)
1972 FILE *fi;
1973{
1974 lineno = 0;
1975 charno = 0;
1976 pfcnt = 0;
1977
1978 while (!feof (fi))
1979 {
1980 lineno++;
1981 linecharno = charno;
1982 charno += readline (&lb, fi);
1983 dbp = lb.buffer;
1984 if (*dbp == '%')
1985 dbp++; /* Ratfor escape to fortran */
1986 while (isspace (*dbp))
1987 dbp++;
1988 if (*dbp == 0)
1989 continue;
1990 switch (*dbp | ' ')
1991 {
1992 case 'i':
1993 if (tail ("integer"))
1994 takeprec ();
1995 break;
1996 case 'r':
1997 if (tail ("real"))
1998 takeprec ();
1999 break;
2000 case 'l':
2001 if (tail ("logical"))
2002 takeprec ();
2003 break;
2004 case 'c':
2005 if (tail ("complex") || tail ("character"))
2006 takeprec ();
2007 break;
2008 case 'd':
2009 if (tail ("double"))
2010 {
2011 while (isspace (*dbp))
2012 dbp++;
2013 if (*dbp == 0)
2014 continue;
2015 if (tail ("precision"))
2016 break;
2017 continue;
2018 }
2019 break;
2020 }
2021 while (isspace (*dbp))
2022 dbp++;
2023 if (*dbp == 0)
2024 continue;
2025 switch (*dbp | ' ')
2026 {
2027 case 'f':
2028 if (tail ("function"))
2029 getit ();
2030 continue;
2031 case 's':
2032 if (tail ("subroutine"))
2033 getit ();
2034 continue;
8a6c8bcf
RS
2035 case 'e':
2036 if (tail ("entry"))
2037 getit ();
2038 continue;
c6d46f5f
JB
2039 case 'p':
2040 if (tail ("program"))
2041 {
2042 getit ();
2043 continue;
2044 }
2045 if (tail ("procedure"))
2046 getit ();
2047 continue;
2048 }
2049 }
2050 return (pfcnt);
2051}
2052
2053logical
2054tail (cp)
2055 char *cp;
2056{
2057 register int len = 0;
2058
2059 while (*cp && (*cp & ~' ') == ((*(dbp + len)) & ~' '))
2060 cp++, len++;
2061 if (*cp == 0)
2062 {
2063 dbp += len;
2064 return (1);
2065 }
2066 return (0);
2067}
2068
2069void
2070takeprec ()
2071{
2072 while (isspace (*dbp))
2073 dbp++;
2074 if (*dbp != '*')
2075 return;
2076 dbp++;
2077 while (isspace (*dbp))
2078 dbp++;
2079 if (!isdigit (*dbp))
2080 {
2081 --dbp; /* force failure */
2082 return;
2083 }
2084 do
2085 dbp++;
2086 while (isdigit (*dbp));
2087}
2088
2089void
2090getit ()
2091{
2092 register char *cp;
2093 char c;
2094 char nambuf[BUFSIZ];
2095
2096 while (isspace (*dbp))
2097 dbp++;
daa37602
JB
2098 if (*dbp == 0
2099 || (!isalpha (*dbp)
2100 && *dbp != '_'
2101 && *dbp != '$'))
c6d46f5f
JB
2102 return;
2103 for (cp = dbp + 1; *cp && (isalpha (*cp) || isdigit (*cp)
2104 || (*cp == '_') || (*cp == '$')); cp++)
2105 continue;
2106 c = cp[0];
2107 cp[0] = 0;
2108 (void) strcpy (nambuf, dbp);
2109 cp[0] = c;
2110 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2111 pfcnt++;
2112}
2113
2114/* Handle a file of assembler code. */
2115
2116void
2117Asm_funcs (fi)
2118 FILE *fi;
2119{
2120 int i;
2121 register char c;
2122
2123 lineno = 0;
2124 charno = 0;
2125 pfcnt = 0;
2126
2127 while (!feof (fi))
2128 {
2129 lineno++;
2130 linecharno = charno;
2131 charno += readline (&lb, fi);
2132 dbp = lb.buffer;
2133
2134 for (i = 0; ((c = dbp[i]) && !isspace (c)) && (c != ':'); i++)
2135 ;
2136
2137 if ((i > 0) && (c == ':'))
2138 getit ();
2139 }
2140}
2141\f
2142/* Added by Mosur Mohan, 4/22/88 */
2143/* Pascal parsing */
2144
2145#define GET_NEW_LINE \
2146{ \
2147 linecharno = charno; lineno++; \
2148 charno += 1 + readline (&lb, inf); \
2149 dbp = lb.buffer; \
2150}
2151
2152/* Locates tags for procedures & functions.
2153 * Doesn't do any type- or var-definitions.
2154 * It does look for the keyword "extern" or "forward"
2155 * immediately following the procedure statement;
2156 * if found, the tag is skipped.
2157 */
2158
2159void
2160PAS_funcs (fi)
2161 FILE *fi;
2162{
2163 struct linebuffer tline; /* mostly copied from C_entries */
2164 long save_lcno;
2165 int save_lineno;
2166 char c, *cp;
2167 char nambuf[BUFSIZ];
2168
2169 logical /* each of these flags is TRUE iff: */
2170 incomm1, /* point is inside {..} comment */
2171 incomm2, /* point is inside (*..*) comment */
2172 inquote, /* point is inside '..' string */
2173 get_tagname, /* point is after PROCEDURE/FUNCTION */
2174 /* keyword, so next item = potential tag */
2175 found_tag, /* point is after a potential tag */
2176 inparms, /* point is within parameter-list */
2177 verify_tag; /* point has passed the parm-list, so the */
2178 /* next token will determine whether */
2179 /* this is a FORWARD/EXTERN to be */
2180 /* ignored, or whether it is a real tag */
2181
2182 lineno = 0;
2183 charno = 0;
2184 dbp = lb.buffer;
2185 *dbp = 0;
2186 initbuffer (&tline);
2187
2188 incomm1 = incomm2 = inquote = FALSE;
2189 found_tag = FALSE; /* have a proc name; check if extern */
2190 get_tagname = FALSE; /* have found "procedure" keyword */
2191 inparms = FALSE; /* found '(' after "proc" */
2192 verify_tag = FALSE; /* check if "extern" is ahead */
2193
2194 /* long main loop to get next char */
2195 while (!feof (fi))
2196 {
2197 c = *dbp++;
2198 if (c == 0) /* if end of line */
2199 {
2200 GET_NEW_LINE;
2201 if (*dbp == 0)
2202 continue;
2203 if (!((found_tag && verify_tag) ||
2204 get_tagname))
2205 c = *dbp++; /* only if don't need *dbp pointing */
2206 /* to the beginning of the name of */
2207 /* the procedure or function */
2208 }
2209 if (incomm1) /* within { - } comments */
2210 {
2211 if (c == '}')
2212 incomm1 = FALSE;
2213 continue;
2214 }
2215 else if (incomm2) /* within (* - *) comments */
2216 {
2217 if (c == '*')
2218 {
2219 while ((c = *dbp++) == '*')
2220 continue;
2221 if (c == 0)
2222 GET_NEW_LINE;
2223 if (c == ')')
2224 incomm2 = FALSE;
2225 }
2226 continue;
2227 }
2228 else if (inquote)
2229 {
2230 if (c == '\'')
2231 inquote = FALSE;
2232 continue;
2233 }
2234 else
2235 switch (c)
2236 {
2237 case '\'':
2238 inquote = TRUE; /* found first quote */
2239 continue;
2240 case '{': /* found open-{-comment */
2241 incomm1 = TRUE;
2242 continue;
2243 case '(':
2244 if (*dbp == '*') /* found open-(*-comment */
2245 {
2246 incomm2 = TRUE;
2247 dbp++;
2248 }
2249 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2250 inparms = TRUE;
2251 continue;
2252 case ')': /* end of parms list */
2253 if (inparms)
2254 inparms = FALSE;
2255 continue;
2256 case ';':
2257 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2258 {
2259 verify_tag = TRUE;
2260 break;
2261 }
2262 continue;
2263 }
2264 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2265 {
2266 /* check if this is an "extern" declaration */
2267 if (*dbp == 0)
2268 continue;
2269 if ((*dbp == 'e') || (*dbp == 'E'))
2270 {
2271 if (tail ("extern")) /* superfluous, really! */
2272 {
2273 found_tag = FALSE;
2274 verify_tag = FALSE;
2275 }
2276 }
2277 else if ((*dbp == 'f') || (*dbp == 'F'))
2278 {
2279 if (tail ("forward")) /* check for forward reference */
2280 {
2281 found_tag = FALSE;
2282 verify_tag = FALSE;
2283 }
2284 }
2285 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2286 {
2287 found_tag = FALSE;
2288 verify_tag = FALSE;
2289 pfnote (nambuf, TRUE, FALSE,
2290 tline.buffer, cp - tline.buffer + 1,
2291 save_lineno, save_lcno);
2292 continue;
2293 }
2294 }
2295 if (get_tagname) /* grab name of proc or fn */
2296 {
2297 if (*dbp == 0)
2298 continue;
2299
2300 /* save all values for later tagging */
2301 tline.size = lb.size;
2302 strcpy (tline.buffer, lb.buffer);
2303 save_lineno = lineno;
2304 save_lcno = linecharno;
2305
2306 /* grab block name */
2307 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2308 continue;
2309 c = cp[0];
2310 cp[0] = 0;
2311 strcpy (nambuf, dbp);
2312 cp[0] = c;
2313 dbp = cp; /* restore dbp to e-o-token */
2314 get_tagname = FALSE;
2315 found_tag = TRUE;
2316 continue;
2317
2318 /* and proceed to check for "extern" */
2319 }
2320 if ((!incomm1) && (!incomm2) && (!inquote) &&
2321 (!found_tag) && (!get_tagname))
2322 {
2323 /* check for proc/fn keywords */
2324 switch (c | ' ')
2325 {
2326 case 'p':
2327 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2328 get_tagname = TRUE;
2329 continue;
2330 case 'f':
2331 if (tail ("unction"))
2332 get_tagname = TRUE;
2333 continue;
2334 }
2335 }
2336 } /* while not e-o-f */
2337}
2338\f
2339/*
2340 * lisp tag functions
2341 * just look for (def or (DEF
2342 */
2343
2344void
2345L_funcs (fi)
2346 FILE *fi;
2347{
2348 lineno = 0;
2349 charno = 0;
2350 pfcnt = 0;
2351
2352 while (!feof (fi))
2353 {
2354 lineno++;
2355 linecharno = charno;
2356 charno += readline (&lb, fi);
2357 dbp = lb.buffer;
2358 if (dbp[0] == '(')
2359 {
2360 if (L_isdef (dbp))
2361 {
2362 while (!isspace (*dbp))
2363 dbp++;
2364 while (isspace (*dbp))
2365 dbp++;
2366 L_getit ();
2367 }
2368 else
2369 {
2370 /* Check for (foo::defmumble name-defined ... */
2371 while (*dbp && *dbp != ':' && !isspace (*dbp)
2372 && *dbp != '(' && *dbp != ')')
2373 dbp++;
2374 if (*dbp == ':')
2375 {
2376 while (*dbp == ':')
2377 dbp++;
2378
2379 if (L_isdef (dbp))
2380 {
2381 while (!isspace (*dbp))
2382 dbp++;
2383 while (isspace (*dbp))
2384 dbp++;
2385 L_getit ();
2386 }
2387 }
2388 }
2389 }
2390 }
2391}
2392
2393int
2394L_isdef (dbp)
2395 char *dbp;
2396{
2397 return ((dbp[1] == 'D' || dbp[1] == 'd') &&
2398 (dbp[2] == 'E' || dbp[2] == 'e') &&
2399 (dbp[3] == 'F' || dbp[3] == 'f'));
2400}
2401
2402void
2403L_getit ()
2404{
2405 register char *cp;
2406 char c;
2407 char nambuf[BUFSIZ];
2408
2409 if (*dbp == 0)
2410 return;
2411 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ' '; cp++)
2412 continue;
2413 c = cp[0];
2414 cp[0] = 0;
2415 (void) strcpy (nambuf, dbp);
2416 cp[0] = c;
2417 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2418 pfcnt++;
2419}
2420\f
2421/*
2422 * Scheme tag functions
2423 * look for (def... xyzzy
2424 * look for (def... (xyzzy
2425 * look for (def ... ((...(xyzzy ....
2426 * look for (set! xyzzy
2427 */
2428
2429static void get_scheme ();
2430
2431void
2432Scheme_funcs (fi)
2433 FILE *fi;
2434{
2435 lineno = 0;
2436 charno = 0;
2437 pfcnt = 0;
2438
2439 while (!feof (fi))
2440 {
2441 lineno++;
2442 linecharno = charno;
2443 charno += readline (&lb, fi);
2444 dbp = lb.buffer;
2445 if (dbp[0] == '(' &&
2446 (dbp[1] == 'D' || dbp[1] == 'd') &&
2447 (dbp[2] == 'E' || dbp[2] == 'e') &&
2448 (dbp[3] == 'F' || dbp[3] == 'f'))
2449 {
2450 while (!isspace (*dbp))
2451 dbp++;
2452 /* Skip over open parens and white space */
2453 while (*dbp && (isspace (*dbp) || *dbp == '('))
2454 dbp++;
2455 get_scheme ();
2456 }
2457 if (dbp[0] == '(' &&
2458 (dbp[1] == 'S' || dbp[1] == 's') &&
2459 (dbp[2] == 'E' || dbp[2] == 'e') &&
2460 (dbp[3] == 'T' || dbp[3] == 't') &&
2461 (dbp[4] == '!' || dbp[4] == '!') &&
2462 (isspace (dbp[5])))
2463 {
2464 while (!isspace (*dbp))
2465 dbp++;
2466 /* Skip over white space */
2467 while (isspace (*dbp))
2468 dbp++;
2469 get_scheme ();
2470 }
2471 }
2472}
2473
2474static void
2475get_scheme ()
2476{
2477 register char *cp;
2478 char c;
2479 char nambuf[BUFSIZ];
2480
2481 if (*dbp == 0)
2482 return;
2483 /* Go till you get to white space or a syntactic break */
2484 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2485 continue;
2486 /* Null terminate the string there. */
2487 c = cp[0];
2488 cp[0] = 0;
2489 /* Copy the string */
2490 strcpy (nambuf, dbp);
2491 /* Unterminate the string */
2492 cp[0] = c;
2493 /* Announce the change */
2494 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2495 pfcnt++;
2496}
2497\f
2498/* Find tags in TeX and LaTeX input files. */
2499
2500/* TEX_toktab is a table of TeX control sequences that define tags.
2501 Each TEX_tabent records one such control sequence.
2502 CONVERT THIS TO USE THE Stab TYPE!! */
2503
2504struct TEX_tabent
2505{
2506 char *name;
2507 int len;
2508};
2509
2510struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2511
2512/* Default set of control sequences to put into TEX_toktab.
2513 The value of environment var TEXTAGS is prepended to this. */
2514
2515static char *TEX_defenv =
2516":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2517
2518void TEX_mode ();
2519struct TEX_tabent *TEX_decode_env ();
2520void TEX_getit ();
2521int TEX_Token ();
2522
2523static char TEX_esc = '\\';
2524static char TEX_opgrp = '{';
2525static char TEX_clgrp = '}';
2526
2527/*
2528 * TeX/LaTeX scanning loop.
2529 */
2530
2531void
2532TEX_funcs (fi)
2533 FILE *fi;
2534{
2535 char *lasthit;
2536
2537 lineno = 0;
2538 charno = 0;
2539 pfcnt = 0;
2540
2541 /* Select either \ or ! as escape character. */
2542 TEX_mode (fi);
2543
2544 /* Initialize token table once from environment. */
2545 if (!TEX_toktab)
2546 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2547
2548 while (!feof (fi))
d2729198 2549 { /* Scan each line in file */
c6d46f5f
JB
2550 lineno++;
2551 linecharno = charno;
2552 charno += readline (&lb, fi);
2553 dbp = lb.buffer;
2554 lasthit = dbp;
d2729198 2555 while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
8a6c8bcf
RS
2556 {
2557 register int i;
c6d46f5f 2558
8a6c8bcf
RS
2559 if (!*(++dbp))
2560 break;
2561 linecharno += dbp - lasthit;
c6d46f5f 2562 lasthit = dbp;
8a6c8bcf
RS
2563 i = TEX_Token (lasthit);
2564 if (0 <= i)
c6d46f5f 2565 {
8a6c8bcf 2566 TEX_getit (lasthit, TEX_toktab[i].len);
d2729198 2567 break; /* We only save a line once */
c6d46f5f
JB
2568 }
2569 }
2570 }
2571}
2572
2573#define TEX_LESC '\\'
2574#define TEX_SESC '!'
2575#define TEX_cmt '%'
2576
2577/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2578/* chars accordingly. */
2579
2580void
2581TEX_mode (f)
2582 FILE *f;
2583{
2584 int c;
2585
2586 while ((c = getc (f)) != EOF)
2587 {
2588 /* Skip to next line if we hit the TeX comment char. */
2589 if (c == TEX_cmt)
2590 while (c != '\n')
2591 c = getc (f);
2592 else if (c == TEX_LESC || c == TEX_SESC )
2593 break;
2594 }
2595
2596 if (c == TEX_LESC)
2597 {
2598 TEX_esc = TEX_LESC;
2599 TEX_opgrp = '{';
2600 TEX_clgrp = '}';
2601 }
2602 else
2603 {
2604 TEX_esc = TEX_SESC;
2605 TEX_opgrp = '<';
2606 TEX_clgrp = '>';
2607 }
2608 rewind (f);
2609}
2610
2611/* Read environment and prepend it to the default string. */
2612/* Build token table. */
2613
2614struct TEX_tabent *
2615TEX_decode_env (evarname, defenv)
2616 char *evarname;
2617 char *defenv;
2618{
2619 register char *env, *p;
c6d46f5f
JB
2620
2621 struct TEX_tabent *tab;
2622 int size, i;
2623
2624 /* Append default string to environment. */
2625 env = getenv (evarname);
2626 if (!env)
2627 env = defenv;
2628 else
2629 env = concat (env, defenv, "");
2630
2631 /* Allocate a token table */
2632 for (size = 1, p = env; p;)
8a6c8bcf 2633 if ((p = etags_index (p, ':')) && *(++p))
c6d46f5f 2634 size++;
8a6c8bcf
RS
2635 /* Add 1 to leave room for null terminator. */
2636 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
2637
2638 /* Unpack environment string into token table. Be careful about */
2639 /* zero-length strings (leading ':', "::" and trailing ':') */
2640 for (i = 0; *env;)
2641 {
8a6c8bcf 2642 p = etags_index (env, ':');
c6d46f5f
JB
2643 if (!p) /* End of environment string. */
2644 p = env + strlen (env);
2645 if (p - env > 0)
2646 { /* Only non-zero strings. */
2647 tab[i].name = savenstr (env, p - env);
2648 tab[i].len = strlen (tab[i].name);
2649 i++;
2650 }
2651 if (*p)
2652 env = p + 1;
2653 else
2654 {
2655 tab[i].name = NULL; /* Mark end of table. */
2656 tab[i].len = 0;
2657 break;
2658 }
2659 }
2660 return tab;
2661}
2662
2663/* Record a tag defined by a TeX command of length LEN and starting at NAME.
2664 The name being defined actually starts at (NAME + LEN + 1).
2665 But we seem to include the TeX command in the tag name. */
2666
2667void
2668TEX_getit (name, len)
2669 char *name;
2670 int len;
2671{
2672 char *p = name + len;
2673 char nambuf[BUFSIZ];
2674
2675 if (*name == 0)
2676 return;
2677
2678 /* Let tag name extend to next group close (or end of line) */
2679 while (*p && *p != TEX_clgrp)
2680 p++;
2681 (void) strncpy (nambuf, name, p - name);
2682 nambuf[p - name] = 0;
2683
2684 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2685 pfcnt++;
2686}
2687
2688/* If the text at CP matches one of the tag-defining TeX command names,
8a6c8bcf 2689 return the etags_index of that command in TEX_toktab.
c6d46f5f
JB
2690 Otherwise return -1. */
2691
2692/* Keep the capital `T' in `Token' for dumb truncating compilers
2693 (this distinguishes it from `TEX_toktab' */
2694int
2695TEX_Token (cp)
2696 char *cp;
2697{
2698 int i;
2699
2700 for (i = 0; TEX_toktab[i].len > 0; i++)
2701 if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
2702 return i;
2703 return -1;
2704}
2705\f
2706/* Support for Prolog. */
2707
2708/* whole head (not only functor, but also arguments)
2709 is gotten in compound term. */
2710
2711void
2712prolog_getit (s, lineno, linecharno)
2713 char *s;
2714 int lineno;
2715 long linecharno;
2716{
2717 char nambuf[BUFSIZ], *save_s, tmpc;
2718 int insquote, npar;
2719
2720 save_s = s;
2721 insquote = FALSE;
2722 npar = 0;
2723 while (1)
2724 {
2725 if (*s == '\0') /* syntax error. */
2726 return;
2727 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2728 s += 2;
2729 else if (*s == '\'')
2730 {
2731 insquote = !insquote;
2732 s++;
2733 }
2734 else if (!insquote && *s == '(')
2735 {
2736 npar++;
2737 s++;
2738 }
2739 else if (!insquote && *s == ')')
2740 {
2741 npar--;
2742 s++;
2743 if (npar == 0)
2744 break;
2745 else if (npar < 0) /* syntax error. */
2746 return;
2747 }
2748 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2749 { /* fullstop. */
2750 if (npar != 0) /* syntax error. */
2751 return;
2752 s++;
2753 break;
2754 }
2755 else
2756 s++;
2757 }
2758 tmpc = *s;
2759 *s = '\0';
2760 strcpy (nambuf, save_s);
2761 *s = tmpc;
2762 pfnote (nambuf, TRUE, save_s, strlen (nambuf), lineno, linecharno);
2763}
2764
2765/* It is assumed that prolog predicate starts from column 0. */
2766
2767void
2768prolog_funcs (fi)
2769 FILE *fi;
2770{
2771 void skip_comment (), prolog_getit ();
2772
2773 lineno = linecharno = charno = 0;
2774 while (!feof (fi))
2775 {
2776 lineno++;
2777 linecharno += charno;
2778 charno = readline (&lb, fi) + 1; /* 1 for newline. */
2779 dbp = lb.buffer;
2780 if (isspace (dbp[0])) /* not predicate header. */
2781 continue;
2782 else if (dbp[0] == '%') /* comment. */
2783 continue;
2784 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2785 skip_comment (&lb, fi, &lineno, &linecharno);
2786 else /* found. */
2787 prolog_getit (dbp, lineno, linecharno);
2788 }
2789}
2790
2791void
2792skip_comment (plb, fi, plineno, plinecharno)
2793 struct linebuffer *plb;
2794 FILE *fi;
2795 int *plineno; /* result */
2796 long *plinecharno; /* result */
2797{
2798 while (!substr ("*/", plb->buffer))
2799 {
2800 (*plineno)++;
2801 *plinecharno += readline (plb, fi) + 1;
2802 } /* 1 for newline. */
2803}
2804
2805/* Return TRUE if 'sub' exists somewhere in 's'. */
2806
2807int
2808substr (sub, s)
2809 char *sub;
2810 char *s;
2811{
8a6c8bcf 2812 while (*s && (s = etags_index (s, *sub)))
c6d46f5f
JB
2813 if (prestr (sub, s))
2814 return (TRUE);
2815 else
2816 s++;
2817 return (FALSE);
2818}
2819
2820/* Return TRUE if 'pre' is prefix of string 's'. */
2821
2822int
2823prestr (pre, s)
2824 char *pre;
2825 char *s;
2826{
2827 if (*pre == '\0')
2828 return (TRUE);
2829 else if (*pre == *s)
2830 return (prestr (pre + 1, s + 1));
2831 else
2832 return (FALSE);
2833}
2834\f
2835/* Initialize a linebuffer for use */
2836
2837void
2838initbuffer (linebuffer)
2839 struct linebuffer *linebuffer;
2840{
2841 linebuffer->size = 200;
2842 linebuffer->buffer = xnew (200, char);
2843}
2844
2845/*
2846 * Read a line of text from `stream' into `linebuffer'.
2847 * Return the number of characters read from `stream',
2848 * which is the length of the line including the newline, if any.
2849 */
2850long
2851readline (linebuffer, stream)
2852 struct linebuffer *linebuffer;
2853 register FILE *stream;
2854{
2855 char *buffer = linebuffer->buffer;
2856 register char *p = linebuffer->buffer;
2857 register char *pend;
2858 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2859
2860 pend = p + linebuffer->size; /* Separate to avoind 386/IX compiler bug. */
2861
2862 while (1)
2863 {
2864 register int c = getc (stream);
2865 if (p == pend)
2866 {
2867 linebuffer->size *= 2;
2868 buffer = (char *) xrealloc (buffer, linebuffer->size);
2869 p += buffer - linebuffer->buffer;
2870 pend = buffer + linebuffer->size;
2871 linebuffer->buffer = buffer;
2872 }
2873 if (c < 0 || c == '\n')
2874 {
2875 *p = 0;
2876 newline = (c == '\n' ? 1 : 0);
2877 break;
2878 }
2879 *p++ = c;
2880 }
2881
2882 return p - buffer + newline;
2883}
2884\f
2885char *
2886savestr (cp)
2887 char *cp;
2888{
2889 return savenstr (cp, strlen (cp));
2890}
2891
2892char *
2893savenstr (cp, len)
2894 char *cp;
2895 int len;
2896{
2897 register char *dp;
2898
2899 dp = xnew (len + 1, char);
2900 (void) strncpy (dp, cp, len);
2901 dp[len] = '\0';
2902 return dp;
2903}
2904
c6d46f5f
JB
2905/*
2906 * Return the ptr in sp at which the character c last
2907 * appears; NULL if not found
2908 *
2909 * Identical to v7 rindex, included for portability.
2910 */
2911
2912char *
8a6c8bcf 2913etags_rindex (sp, c)
c6d46f5f
JB
2914 register char *sp, c;
2915{
2916 register char *r;
2917
2918 r = NULL;
2919 do
2920 {
2921 if (*sp == c)
2922 r = sp;
2923 } while (*sp++);
2924 return (r);
2925}
2926
9d7ad1b3 2927
c6d46f5f
JB
2928/*
2929 * Return the ptr in sp at which the character c first
2930 * appears; NULL if not found
2931 *
2932 * Identical to v7 index, included for portability.
2933 */
2934
2935char *
8a6c8bcf 2936etags_index (sp, c)
c6d46f5f
JB
2937 register char *sp, c;
2938{
2939 do
2940 {
2941 if (*sp == c)
2942 return (sp);
2943 } while (*sp++);
2944 return (NULL);
2945}
2946
c6d46f5f
JB
2947/* Print error message and exit. */
2948
2949/* VARARGS1 */
2950void
2951fatal (s1, s2)
2952 char *s1, *s2;
2953{
2954 error (s1, s2);
2955 exit (1);
2956}
2957
2958/* Print error message. `s1' is printf control string, `s2' is arg for it. */
2959
2960/* VARARGS1 */
2961void
2962error (s1, s2)
2963 char *s1, *s2;
2964{
2965 fprintf (stderr, "%s: ", progname);
2966 fprintf (stderr, s1, s2);
2967 fprintf (stderr, "\n");
2968}
2969
2970/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
2971
2972char *
2973concat (s1, s2, s3)
2974 char *s1, *s2, *s3;
2975{
2976 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
2977 char *result = xnew (len1 + len2 + len3 + 1, char);
2978
2979 (void) strcpy (result, s1);
2980 (void) strcpy (result + len1, s2);
2981 (void) strcpy (result + len1 + len2, s3);
2982 *(result + len1 + len2 + len3) = 0;
2983
2984 return result;
2985}
2986
2987/* Like malloc but get fatal error if memory is exhausted. */
2988
2989char *
2990xmalloc (size)
2991 int size;
2992{
2993 char *result = malloc (size);
2994 if (!result)
2995 fatal ("virtual memory exhausted", 0);
2996 return result;
2997}
2998
2999char *
3000xrealloc (ptr, size)
3001 char *ptr;
3002 int size;
3003{
3004 char *result = realloc (ptr, size);
3005 if (!result)
3006 fatal ("virtual memory exhausted");
3007 return result;
3008}