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