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