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