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