(PURESIZE) [!MULTI_FRAME]: Increase to 200000.
[emacs.git] / lib-src / etags.c
blobd05b35e8d2eb6a1dbab76a24ec772e89f0d6b764
1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
4 This file is not considered part of GNU Emacs.
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.
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.
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. */
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++.
28 * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
31 char pot_etags_version[] = "@(#) pot revision number is 10.32";
33 #ifdef MSDOS
34 #include <fcntl.h>
35 #endif /* MSDOS */
37 #ifdef HAVE_CONFIG_H
38 #include <../src/config.h>
39 /* On some systems, Emacs defines static as nothing
40 for the sake of unexec. We don't want that here
41 since we don't use unexec. */
42 #undef static
43 #endif
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
50 #if !defined (S_ISREG) && defined (S_IFREG)
51 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
52 #endif
54 #include "getopt.h"
56 extern char *getenv ();
59 /* Define CTAGS to make the program "ctags" compatible with the usual one.
60 Let it undefined to make the program "etags", which makes emacs-style
61 tag tables and tags typedefs, #defines and struct/union/enum by default. */
62 #ifdef CTAGS
63 # undef CTAGS
64 # define CTAGS TRUE
65 #else
66 # define CTAGS FALSE
67 #endif
69 /* Exit codes for success and failure. */
70 #ifdef VMS
71 #define GOOD 1
72 #define BAD 0
73 #else
74 #define GOOD 0
75 #define BAD 1
76 #endif
79 * The FILEPOS abstract type, which represents a position in a file,
80 * plus the following accessor functions:
82 * long GET_CHARNO (pos)
83 * returns absolute char number.
84 * void SET_FILEPOS (pos, fp, charno)
85 * FILE *fp; long charno;
86 * sets `pos' from the current file
87 * position of `fp' and from `charno',
88 * which must be the absolute character
89 * number corresponding to the current
90 * position of `fp'.
92 * The `pos' parameter is an lvalue expression of type FILEPOS.
93 * Parameters to the accessor functions are evaluated 0 or more times,
94 * and so must have no side effects.
96 * FILEPOS objects can also be assigned and passed to and from
97 * functions in the normal C manner.
99 * Implementation notes: the `+ 0' is to enforce rvalue-ness.
102 #ifndef DEBUG
103 /* real implementation */
104 typedef long FILEPOS;
105 #define GET_CHARNO(pos) ((pos) + 0)
106 #define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))
107 #else
108 /* debugging implementation */
109 typedef struct
111 long charno;
112 } FILEPOS;
114 #define GET_CHARNO(pos) ((pos).charno + 0)
115 #define SET_FILEPOS(pos, fp, cno) \
116 ((void) ((pos).charno = (cno), \
117 (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
118 : 0))
119 #endif
121 #define streq(s, t) (strcmp (s, t) == 0)
122 #define strneq(s, t, n) (strncmp (s, t, n) == 0)
123 #define logical int
125 #define TRUE 1
126 #define FALSE 0
128 #define iswhite(arg) (_wht[arg]) /* T if char is white */
129 #define begtoken(arg) (_btk[arg]) /* T if char can start token */
130 #define intoken(arg) (_itk[arg]) /* T if char can be in token */
131 #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
133 #define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
135 struct nd_st
136 { /* sorting structure */
137 char *name; /* function or type name */
138 char *file; /* file name */
139 logical is_func; /* use pattern or line no */
140 logical named; /* list name separately */
141 logical been_warned; /* set if noticed dup */
142 int lno; /* line number tag is on */
143 long cno; /* character number line starts on */
144 char *pat; /* search pattern */
145 struct nd_st *left, *right; /* left and right sons */
148 typedef struct nd_st NODE;
150 logical header_file; /* TRUE if .h file, FALSE o.w. */
151 /* boolean "functions" (see init) */
152 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
154 char *cwd; /* current working directory */
155 char *tagfiledir; /* directory of tagfile */
157 char *concat ();
158 char *savenstr (), *savestr ();
159 char *etags_strchr (), *etags_strrchr ();
160 char *etags_getcwd ();
161 char *relative_filename (), *absolute_filename (), *absolute_dirname ();
162 char *xmalloc (), *xrealloc ();
163 int total_size_of_entries ();
164 long readline ();
166 void Asm_labels ();
167 void C_entries ();
168 int Fortran_functions ();
169 void Lisp_functions ();
170 void Pascal_functions ();
171 void Prolog_functions ();
172 void Scheme_functions ();
173 void TeX_functions ();
174 void add_node ();
175 void error ();
176 void fatal ();
177 logical find_entries ();
178 void free_tree ();
179 void getit ();
180 void init ();
181 void initbuffer ();
182 void initbuffer ();
183 void pfnote ();
184 void process_file ();
185 void put_entries ();
186 void takeprec ();
189 * MACRO
190 * xnew -- allocate storage
192 * SYNOPSIS
193 * Type *xnew (int n, Type);
195 #define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
198 * Symbol table types.
200 enum sym_type
202 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
207 typedef int LINENO;
209 typedef struct
211 char *p;
212 int len;
213 LINENO lineno;
214 logical named;
215 } TOKEN;
217 /* C extensions.
219 #define C_PLPL 0x00001 /* C++ */
220 #define C_STAR 0x00003 /* C* */
221 #define YACC 0x10000 /* yacc file */
223 char searchar = '/'; /* use /.../ searches */
225 LINENO lineno; /* line number of current line */
226 long charno; /* current character number */
228 long linecharno; /* charno of start of line; not used by C, but
229 * by every other language.
232 char *curfile, /* current input file name */
233 *tagfile, /* output file */
234 *white = " \f\t\n", /* white chars */
235 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
236 /* token starting chars */
237 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
238 /* valid in-token chars */
239 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
241 int append_to_tagfile; /* -a: append to tags */
242 /* The following three default to 1 for etags, but to 0 for ctags. */
243 int typedefs; /* -t: create tags for typedefs */
244 int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
245 /* 0 struct/enum/union decls, and C++ */
246 /* member functions. */
247 int constantypedefs; /* -d: create tags for C #define and enum */
248 /* constants. Enum consts not implemented. */
249 /* -D: opposite of -d. Default under ctags. */
250 int update; /* -u: update tags */
251 int vgrind_style; /* -v: create vgrind style index output */
252 int no_warnings; /* -w: suppress warnings */
253 int cxref_style; /* -x: create cxref style output */
254 int cplusplus; /* .[hc] means C++, not C */
255 int noindentypedefs; /* -S: ignore indentation in C */
257 /* Name this program was invoked with. */
258 char *progname;
260 struct option longopts[] = {
261 { "append", no_argument, NULL, 'a' },
262 { "backward-search", no_argument, NULL, 'B' },
263 { "c++", no_argument, NULL, 'C' },
264 { "cxref", no_argument, NULL, 'x' },
265 { "defines", no_argument, NULL, 'd' },
266 { "help", no_argument, NULL, 'H' },
267 { "ignore-indentation", no_argument, NULL, 'S' },
268 { "include", required_argument, NULL, 'i' },
269 { "no-defines", no_argument, NULL, 'D' },
270 { "no-warn", no_argument, NULL, 'w' },
271 { "output", required_argument, NULL, 'o' },
272 { "typedefs", no_argument, NULL, 't' },
273 { "typedefs-and-c++", no_argument, NULL, 'T' },
274 { "update", no_argument, NULL, 'u' },
275 { "version", no_argument, NULL, 'V' },
276 { "vgrind", no_argument, NULL, 'v' },
277 { 0 }
280 FILE *tagf; /* ioptr for tags file */
281 NODE *head; /* the head of the binary tree of tags */
282 logical permit_duplicates = TRUE; /* allow duplicate tags */
284 /* A `struct linebuffer' is a structure which holds a line of text.
285 `readline' reads a line from a stream into a linebuffer
286 and works regardless of the length of the line. */
288 struct linebuffer
290 long size;
291 char *buffer;
294 struct linebuffer lb; /* the current line */
295 struct linebuffer filename_lb; /* used to read in filenames */
296 struct
298 FILEPOS linepos;
299 struct linebuffer lb; /* used by C_entries instead of lb */
300 } lbs[2];
302 void
303 print_version ()
305 #ifdef VERSION
306 printf ("%s for Emacs version %g.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
307 #else
308 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
309 #endif
311 exit (GOOD);
314 void
315 print_help ()
317 printf ("These are the options accepted by %s. You may use unambiguous\n\
318 abbreviations for the long option names. A - as file name means read file\n\
319 names from stdin.\n\n", progname);
321 puts ("-a, --append\n\
322 Append tag entries to existing tags file.");
324 if (CTAGS)
325 puts ("-B, --backward-search\n\
326 Write the search commands for the tag entries using '?', the\n\
327 backward-search command instead of '/', the forward-search command.");
329 puts ("-C, --c++\n\
330 Treat files with `.c' and `.h' extensions as C++ code, not C\n\
331 code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
332 extensions are always assumed to be C++ code.");
334 if (CTAGS)
335 puts ("-d, --defines\n\
336 Create tag entries for C #defines, too.");
337 else
338 puts ("-D, --no-defines\n\
339 Don't create tag entries for C #defines. This makes the tags\n\
340 file smaller.");
342 if (!CTAGS)
343 puts ("-i FILE, --include=FILE\n\
344 Include a note in tag file indicating that, when searching for\n\
345 a tag, one should also consult the tags file FILE after\n\
346 checking the current file.");
348 puts ("-o FILE, --output=FILE\n\
349 Write the tags to FILE.");
350 puts ("-S, --ignore-indentation\n\
351 Don't rely on indentation quite as much as normal. Currently,\n\
352 this means not to assume that a closing brace in the first\n\
353 column is the final brace of a function or structure\n\
354 definition in C and C++.");
356 if (CTAGS)
358 puts ("-t, --typedefs\n\
359 Generate tag entries for C typedefs.");
360 puts ("-T, --typedefs-and-c++\n\
361 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
362 and C++ member functions.");
363 puts ("-u, --update\n\
364 Update the tag entries for the given files, leaving tag\n\
365 entries for other files in place. Currently, this is\n\
366 implemented by deleting the existing entries for the given\n\
367 files and then rewriting the new entries at the end of the\n\
368 tags file. It is often faster to simply rebuild the entire\n\
369 tag file than to use this.");
370 puts ("-v, --vgrind\n\
371 Generates an index of items intended for human consumption,\n\
372 similar to the output of vgrind. The index is sorted, and\n\
373 gives the page number of each item.");
374 puts ("-x, --cxref\n\
375 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
376 The output uses line numbers instead of page numbers, but\n\
377 beyond that the differences are cosmetic; try both to see\n\
378 which you like.");
379 puts ("-w, --no-warn\n\
380 Suppress warning messages about entries defined in multiple\n\
381 files.");
384 puts ("-V, --version\n\
385 Print the version of the program.\n\
386 -H, --help\n\
387 Print this help message.");
389 exit (GOOD);
393 void
394 main (argc, argv)
395 int argc;
396 char *argv[];
398 char cmd[100];
399 int i;
400 unsigned int nincluded_files = 0;
401 char **included_files = xnew (argc, char *);
402 char *this_file;
403 #ifdef VMS
404 char got_err;
406 extern char *gfnames ();
407 extern char *massage_name ();
408 #endif
410 #ifdef MSDOS
411 _fmode = O_BINARY; /* all of files are treated as binary files */
412 #endif /* MSDOS */
414 progname = argv[0];
417 * If etags, always find typedefs and structure tags. Why not?
418 * Also default is to find macro constants.
420 if (!CTAGS)
421 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
423 for (;;)
425 int opt;
426 opt = getopt_long (argc, argv, "aCdDf:o:StTi:BuvxwVH", longopts, 0);
428 if (opt == EOF)
429 break;
431 switch (opt)
433 case 0:
434 /* If getopt returns 0, then it has already processed a
435 long-named option. We should do nothing. */
436 break;
438 /* Common options. */
439 case 'a':
440 append_to_tagfile++;
441 break;
442 case 'C':
443 cplusplus = 1;
444 break;
445 case 'd':
446 constantypedefs = 1;
447 break;
448 case 'D':
449 constantypedefs = 0;
450 break;
451 case 'f': /* for compatibility with old makefiles */
452 case 'o':
453 if (tagfile)
455 fprintf (stderr,
456 "%s: -%c flag may only be given once\n", progname, opt);
457 goto usage;
459 tagfile = optarg;
460 break;
461 case 'S':
462 noindentypedefs++;
463 break;
464 case 'V':
465 print_version ();
466 break;
467 case 'H':
468 print_help ();
469 break;
471 #if (!CTAGS)
473 /* Etags options */
474 case 'i':
475 included_files[nincluded_files++] = optarg;
476 break;
478 #else /* CTAGS */
480 /* Ctags options. */
481 case 'B':
482 searchar = '?';
483 break;
484 case 't':
485 typedefs++;
486 break;
487 case 'T':
488 typedefs++;
489 typedefs_and_cplusplus++;
490 break;
491 case 'u':
492 update++;
493 break;
494 case 'v':
495 vgrind_style++;
496 /*FALLTHRU*/
497 case 'x':
498 cxref_style++;
499 break;
500 case 'w':
501 no_warnings++;
502 break;
504 #endif /* CTAGS */
506 default:
507 goto usage;
511 if (optind == argc && nincluded_files == 0)
513 fprintf (stderr, "%s: No input files specified.\n", progname);
515 usage:
516 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
517 progname, progname);
518 exit (BAD);
521 if (tagfile == NULL)
523 tagfile = CTAGS ? "tags" : "TAGS";
525 cwd = etags_getcwd (); /* the current working directory */
526 strcat (cwd, "/");
527 if (streq (tagfile, "-"))
529 tagfiledir = cwd;
531 else
533 tagfiledir = absolute_dirname (tagfile, cwd);
536 init (); /* set up boolean "functions" */
538 initbuffer (&lb);
539 initbuffer (&lbs[0].lb);
540 initbuffer (&lbs[1].lb);
541 initbuffer (&filename_lb);
543 * loop through files finding functions
545 if (!CTAGS)
547 if (streq (tagfile, "-"))
548 tagf = stdout;
549 else
550 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
551 if (tagf == NULL)
553 perror (tagfile);
554 exit (BAD);
558 #ifdef VMS
559 argc -= optind;
560 argv += optind;
561 while (gfnames (&argc, &argv, &got_err) != NULL)
563 if (got_err)
565 error ("Can't find file %s\n", this_file);
566 argc--, argv++;
568 else
570 this_file = massage_name (this_file);
571 #if 0
573 } /* solely to balance out the ifdef'd parens above */
574 #endif
575 #else
576 for (; optind < argc; optind++)
578 this_file = argv[optind];
579 #endif
580 /* Input file named "-" means read file names from stdin and use them. */
581 if (streq (this_file, "-"))
583 while (!feof (stdin))
585 (void) readline (&filename_lb, stdin);
586 if (strlen (filename_lb.buffer) > 0)
587 process_file (filename_lb.buffer);
590 else
591 process_file (this_file);
594 if (!CTAGS)
596 while (nincluded_files-- > 0)
597 fprintf (tagf, "\f\n%s,include\n", *included_files++);
599 (void) fclose (tagf);
600 exit (GOOD);
603 if (cxref_style)
605 put_entries (head);
606 exit (GOOD);
608 if (update)
610 /* update cannot be set under VMS, so we may assume that argc
611 and argv have not been munged. */
612 for (i = optind; i < argc; i++)
614 sprintf (cmd,
615 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
616 tagfile, argv[i], tagfile);
617 (void) system (cmd);
619 append_to_tagfile++;
621 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
622 if (tagf == NULL)
624 perror (tagfile);
625 exit (GOOD);
627 put_entries (head);
628 (void) fclose (tagf);
629 if (update)
631 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
632 (void) system (cmd);
634 exit (GOOD);
639 * This routine is called on each file argument.
641 void
642 process_file (file)
643 char *file;
645 struct stat stat_buf;
647 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
649 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
650 return;
652 if (streq (file, tagfile) && !streq (tagfile, "-"))
654 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
655 return;
657 if (!find_entries (file))
659 return;
661 if (!CTAGS)
663 char *filename;
665 if (file[0] == '/')
667 /* file is an absolute filename. Canonicalise it. */
668 filename = absolute_filename (file, cwd);
670 else
672 /* file is a filename relative to cwd. Make it relative
673 to the directory of the tags file. */
674 filename = relative_filename (file, tagfiledir);
676 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
677 put_entries (head);
678 free_tree (head);
679 head = NULL;
684 * This routine sets up the boolean pseudo-functions which work
685 * by setting boolean flags dependent upon the corresponding character
686 * Every char which is NOT in that string is not a white char. Therefore,
687 * all of the array "_wht" is set to FALSE, and then the elements
688 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
689 * of a char is TRUE if it is the string "white", else FALSE.
691 void
692 init ()
694 register char *sp;
695 register int i;
697 for (i = 0; i < 0177; i++)
698 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
699 for (sp = white; *sp; sp++)
700 _wht[*sp] = TRUE;
701 for (sp = endtk; *sp; sp++)
702 _etk[*sp] = TRUE;
703 for (sp = intk; *sp; sp++)
704 _itk[*sp] = TRUE;
705 for (sp = begtk; *sp; sp++)
706 _btk[*sp] = TRUE;
707 _wht[0] = _wht['\n'];
708 _etk[0] = _etk['\n'];
709 _btk[0] = _btk['\n'];
710 _itk[0] = _itk['\n'];
714 * This routine opens the specified file and calls the function
715 * which finds the function and type definitions.
717 logical
718 find_entries (file)
719 char *file;
721 char *cp, *cp1;
722 FILE *inf;
724 inf = fopen (file, "r");
725 if (inf == NULL)
727 perror (file);
728 return FALSE;
730 curfile = savestr (file);
731 cp = etags_strrchr (file, '.');
732 cp1 = cp + 1;
734 header_file = (cp && (streq (cp1, "h")));
736 /* .tex, .aux or .bbl implies LaTeX source code */
737 if (cp && (streq (cp1, "tex") || streq (cp1, "aux")
738 || streq (cp1, "bbl")))
740 TeX_functions (inf);
741 goto close_and_return;
743 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
744 if (cp && (streq (cp1, "l")
745 || streq (cp1, "el")
746 || streq (cp1, "lsp")
747 || streq (cp1, "lisp")
748 || streq (cp1, "cl")
749 || streq (cp1, "clisp")))
751 Lisp_functions (inf);
752 goto close_and_return;
754 /* .scm or .sm or .scheme or ... implies scheme source code */
755 if (cp && (streq (cp1, "sm")
756 || streq (cp1, "scm")
757 || streq (cp1, "scheme")
758 || streq (cp1, "t")
759 || streq (cp1, "sch")
760 || streq (cp1, "ss")
761 || streq (cp1, "SM")
762 || streq (cp1, "SCM")
763 /* The `SCM' or `scm' prefix with a version number */
764 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's'
765 && string_numeric_p (cp1))
766 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'
767 && string_numeric_p (cp1))))
769 Scheme_functions (inf);
770 goto close_and_return;
772 /* Assembly code */
773 if (cp && (streq (cp1, "s")
774 || streq (cp1, "a") /* Unix assembler */
775 || streq (cp1, "sa") /* Unix assembler */
776 || streq (cp1, "asm") /* Microcontroller assembly */
777 || streq (cp1, "src") /* BSO/Tasking C compiler output */
778 || streq (cp1, "def") /* BSO/Tasking definition includes */
779 || streq (cp1, "ins") /* Microcontroller include files */
780 || streq (cp1, "inc")))/* Microcontroller include files */
782 Asm_labels (inf);
783 goto close_and_return;
785 /* .C or .H or .cxx or .hxx or .cc: a C++ file */
786 if (cp && (streq (cp1, "C")
787 || streq (cp1, "H")
788 || streq (cp1, "cxx")
789 || streq (cp1, "hxx")
790 || streq (cp1, "cc")))
792 C_entries (C_PLPL, inf); /* C++ */
793 goto close_and_return;
795 /* .cs or .hs: a C* file */
796 if (cp && (streq (cp1, "cs")
797 || streq (cp1, "hs")))
799 C_entries (C_STAR, inf);
800 goto close_and_return;
802 /* .y: a yacc file */
803 if (cp && (streq (cp1, "y")))
805 C_entries (YACC, inf);
806 goto close_and_return;
808 /* .pl implies prolog source code */
809 if (cp && streq (cp1, "pl"))
811 Prolog_functions (inf);
812 goto close_and_return;
814 /* .p or .pas: a Pascal file */
815 if (cp && (streq (cp1, "p")
816 || streq (cp1, "pas")))
818 Pascal_functions (inf);
819 goto close_and_return;
821 /* If .f or .for, assume it is fortran or nothing. */
822 if (cp && (streq (cp1, "f")
823 || streq (cp1, "for")))
825 (void) Fortran_functions (inf);
826 goto close_and_return;
828 /* if not a .c or .h or .y file, try fortran */
829 if (cp && ((cp[1] != 'c'
830 && cp[1] != 'h'
831 && cp[1] != 'y')
832 || (cp[1] != 0 && cp[2] != 0)))
834 if (Fortran_functions (inf) != 0)
835 goto close_and_return;
836 rewind (inf); /* no fortran tags found, try C */
838 C_entries (cplusplus ? C_PLPL : 0, inf);
840 close_and_return:
841 (void) fclose (inf);
842 return TRUE;
845 /* Nonzero if string STR is composed of digits. */
848 string_numeric_p (str)
849 char *str;
851 while (*str)
853 if (*str < '0' || *str > '9')
854 return 0;
856 return 1;
859 /* Record a tag. */
860 /* Should take a TOKEN* instead!! */
861 void
862 pfnote (name, is_func, named, linestart, linelen, lno, cno)
863 char *name; /* tag name */
864 logical is_func; /* function or type name? */
865 logical named; /* tag different from text of definition? */
866 char *linestart;
867 int linelen;
868 int lno;
869 long cno;
871 register char *fp;
872 register NODE *np;
873 char tem[51];
874 char c;
876 np = xnew (1, NODE);
877 if (np == NULL)
879 if (CTAGS)
881 /* It's okay to output early in etags -- it only disrupts the
882 * character count of the tag entries, which is no longer used
883 * by tags.el anyway.
885 error ("too many entries to sort", 0);
887 put_entries (head);
888 free_tree (head);
889 head = NULL;
890 np = xnew (1, NODE);
892 /* If ctags mode, change name "main" to M<thisfilename>. */
893 if (CTAGS && !cxref_style && streq (name, "main"))
895 fp = etags_strrchr (curfile, '/');
896 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
897 fp = etags_strrchr (name, '.');
898 if (fp && fp[1] != '\0' && fp[2] == '\0')
899 *fp = 0;
900 named = TRUE;
902 np->name = savestr (name);
903 np->file = curfile;
904 np->is_func = is_func;
905 np->named = named;
906 np->lno = lno;
907 /* UNCOMMENT THE +1 HERE: */
908 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
909 np->left = np->right = 0;
910 if (!CTAGS)
912 c = linestart[linelen];
913 linestart[linelen] = 0;
915 else if (cxref_style == 0)
917 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
918 linestart = tem;
920 np->pat = savestr (linestart);
921 if (!CTAGS)
923 linestart[linelen] = c;
926 add_node (np, &head);
930 * free_tree ()
931 * recurse on left children, iterate on right children.
933 void
934 free_tree (node)
935 register NODE *node;
937 while (node)
939 register NODE *node_right = node->right;
940 free_tree (node->left);
941 free (node->name);
942 free (node->pat);
943 free ((char *) node);
944 node = node_right;
949 * add_node ()
950 * Adds a node to the tree of nodes. In etags mode, we don't keep
951 * it sorted; we just keep a linear list. In ctags mode, maintain
952 * an ordered tree, with no attempt at balancing.
954 * add_node is the only function allowed to add nodes, so it can
955 * maintain state.
957 /* Must avoid static vars within functions since some systems
958 #define static as nothing. */
959 NODE *last_node = NULL;
961 void
962 add_node (node, cur_node_p)
963 NODE *node, **cur_node_p;
965 register int dif;
966 register NODE *cur_node = *cur_node_p;
968 if (cur_node == NULL)
970 *cur_node_p = node;
971 last_node = node;
972 return;
975 if (!CTAGS)
977 /* Etags Mode */
978 if (last_node == NULL)
979 fatal ("internal error in add_node", 0);
980 last_node->right = node;
981 last_node = node;
983 else
985 /* Ctags Mode */
986 dif = strcmp (node->name, cur_node->name);
989 * If this tag name matches an existing one, then
990 * do not add the node, but maybe print a warning.
992 if (!dif)
994 if (node->file == cur_node->file)
996 if (!no_warnings)
998 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
999 node->file, lineno, node->name);
1000 fprintf (stderr, "Second entry ignored\n");
1002 return;
1004 if (!cur_node->been_warned && !no_warnings)
1006 fprintf (stderr,
1007 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1008 node->file, cur_node->file, node->name);
1010 cur_node->been_warned = TRUE;
1011 return;
1014 /* Maybe refuse to add duplicate nodes. */
1015 if (!permit_duplicates)
1017 if (streq (node->name, cur_node->name)
1018 && streq (node->file, cur_node->file))
1019 return;
1022 /* Actually add the node */
1023 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1027 void
1028 put_entries (node)
1029 register NODE *node;
1031 register char *sp;
1033 if (node == NULL)
1034 return;
1036 /* Output subentries that precede this one */
1037 put_entries (node->left);
1039 /* Output this entry */
1041 if (!CTAGS)
1043 if (node->named)
1045 fprintf (tagf, "%s\177%s\001%d,%d\n",
1046 node->pat, node->name,
1047 node->lno, node->cno);
1049 else
1051 fprintf (tagf, "%s\177%d,%d\n",
1052 node->pat,
1053 node->lno, node->cno);
1056 else if (!cxref_style)
1058 fprintf (tagf, "%s\t%s\t",
1059 node->name, node->file);
1061 if (node->is_func)
1062 { /* a function */
1063 putc (searchar, tagf);
1064 putc ('^', tagf);
1066 for (sp = node->pat; *sp; sp++)
1068 if (*sp == '\\' || *sp == searchar)
1069 putc ('\\', tagf);
1070 putc (*sp, tagf);
1072 putc (searchar, tagf);
1074 else
1075 { /* a typedef; text pattern inadequate */
1076 fprintf (tagf, "%d", node->lno);
1078 putc ('\n', tagf);
1080 else if (vgrind_style)
1081 fprintf (stdout, "%s %s %d\n",
1082 node->name, node->file, (node->lno + 63) / 64);
1083 else
1084 fprintf (stdout, "%-16s %3d %-16s %s\n",
1085 node->name, node->lno, node->file, node->pat);
1087 /* Output subentries that follow this one */
1088 put_entries (node->right);
1091 /* Length of a number's decimal representation. */
1093 number_len (num)
1094 long num;
1096 int len = 0;
1097 if (!num)
1098 return 1;
1099 for (; num; num /= 10)
1100 ++len;
1101 return len;
1105 * Return total number of characters that put_entries will output for
1106 * the nodes in the subtree of the specified node. Works only if
1107 * we are not ctags, but called only in that case. This count
1108 * is irrelevant with the new tags.el, but is still supplied for
1109 * backward compatibility.
1112 total_size_of_entries (node)
1113 register NODE *node;
1115 register int total;
1117 if (node == NULL)
1118 return 0;
1120 total = 0;
1121 for (; node; node = node->right)
1123 /* Count left subentries. */
1124 total += total_size_of_entries (node->left);
1126 /* Count this entry */
1127 total += strlen (node->pat) + 1;
1128 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1129 if (node->named)
1130 total += 1 + strlen (node->name); /* \001name */
1133 return total;
1137 * The C symbol tables.
1140 /* Feed stuff between (but not including) %[ and %] lines to:
1141 gperf -c -k1,3 -o -p -r -t
1143 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1145 class, C_PLPL, st_C_struct
1146 domain, C_STAR, st_C_struct
1147 union, 0, st_C_struct
1148 struct, 0, st_C_struct
1149 enum, 0, st_C_enum
1150 typedef, 0, st_C_typedef
1151 define, 0, st_C_define
1152 long, 0, st_C_typespec
1153 short, 0, st_C_typespec
1154 int, 0, st_C_typespec
1155 char, 0, st_C_typespec
1156 float, 0, st_C_typespec
1157 double, 0, st_C_typespec
1158 signed, 0, st_C_typespec
1159 unsigned, 0, st_C_typespec
1160 auto, 0, st_C_typespec
1161 void, 0, st_C_typespec
1162 extern, 0, st_C_typespec
1163 static, 0, st_C_typespec
1164 const, 0, st_C_typespec
1165 volatile, 0, st_C_typespec
1167 and replace lines between %< and %> with its output. */
1168 /*%<*/
1169 /* C code produced by gperf version 1.8.1 (K&R C version) */
1170 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1173 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1175 #define MIN_WORD_LENGTH 3
1176 #define MAX_WORD_LENGTH 8
1177 #define MIN_HASH_VALUE 10
1178 #define MAX_HASH_VALUE 62
1180 21 keywords
1181 53 is the maximum key range
1184 static int
1185 hash (str, len)
1186 register char *str;
1187 register int len;
1189 static unsigned char hash_table[] =
1191 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1192 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1193 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1194 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1195 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1196 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1197 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1198 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1199 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1200 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1201 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1202 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1203 62, 62, 62, 62, 62, 62, 62, 62,
1205 return len + hash_table[str[2]] + hash_table[str[0]];
1208 struct C_stab_entry *
1209 in_word_set (str, len)
1210 register char *str;
1211 register int len;
1214 static struct C_stab_entry wordlist[] =
1216 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1217 {"",},
1218 {"volatile", 0, st_C_typespec},
1219 {"",},
1220 {"long", 0, st_C_typespec},
1221 {"char", 0, st_C_typespec},
1222 {"class", C_PLPL, st_C_struct},
1223 {"",}, {"",}, {"",}, {"",},
1224 {"const", 0, st_C_typespec},
1225 {"",}, {"",}, {"",}, {"",},
1226 {"auto", 0, st_C_typespec},
1227 {"",}, {"",},
1228 {"define", 0, st_C_define},
1229 {"",},
1230 {"void", 0, st_C_typespec},
1231 {"",}, {"",}, {"",},
1232 {"extern", 0, st_C_typespec},
1233 {"static", 0, st_C_typespec},
1234 {"",},
1235 {"domain", C_STAR, st_C_struct},
1236 {"",},
1237 {"typedef", 0, st_C_typedef},
1238 {"double", 0, st_C_typespec},
1239 {"enum", 0, st_C_enum},
1240 {"",}, {"",}, {"",}, {"",},
1241 {"int", 0, st_C_typespec},
1242 {"",},
1243 {"float", 0, st_C_typespec},
1244 {"",}, {"",}, {"",},
1245 {"struct", 0, st_C_struct},
1246 {"",}, {"",}, {"",}, {"",},
1247 {"union", 0, st_C_struct},
1248 {"",},
1249 {"short", 0, st_C_typespec},
1250 {"",}, {"",},
1251 {"unsigned", 0, st_C_typespec},
1252 {"signed", 0, st_C_typespec},
1255 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1257 register int key = hash (str, len);
1259 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1261 register char *s = wordlist[key].name;
1263 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1264 return &wordlist[key];
1267 return 0;
1269 /*%>*/
1271 enum sym_type
1272 C_symtype(str, len, c_ext)
1273 char *str;
1274 int len;
1275 int c_ext;
1277 register struct C_stab_entry *se = in_word_set(str, len);
1279 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1280 return st_none;
1281 return se->type;
1285 * C functions are recognized using a simple finite automaton.
1286 * funcdef is its state variable.
1288 typedef enum
1290 fnone, /* nothing seen */
1291 ftagseen, /* function-like tag seen */
1292 fstartlist, /* just after open parenthesis */
1293 finlist, /* in parameter list */
1294 flistseen, /* after parameter list */
1295 fignore /* before open brace */
1296 } FUNCST;
1297 FUNCST funcdef;
1301 * typedefs are recognized using a simple finite automaton.
1302 * typeddef is its state variable.
1304 typedef enum
1306 tnone, /* nothing seen */
1307 ttypedseen, /* typedef keyword seen */
1308 tinbody, /* inside typedef body */
1309 tend, /* just before typedef tag */
1310 tignore /* junk after typedef tag */
1311 } TYPEDST;
1312 TYPEDST typdef;
1316 * struct-like structures (enum, struct and union) are recognized
1317 * using another simple finite automaton. `structdef' is its state
1318 * variable.
1320 typedef enum
1322 snone, /* nothing seen yet */
1323 skeyseen, /* struct-like keyword seen */
1324 stagseen, /* struct-like tag seen */
1325 scolonseen, /* colon seen after struct-like tag */
1326 sinbody /* in struct body: recognize member func defs*/
1327 } STRUCTST;
1328 STRUCTST structdef;
1331 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1332 * struct tag, and structtype is the type of the preceding struct-like
1333 * keyword.
1335 char structtag[BUFSIZ];
1336 enum sym_type structtype;
1339 * Yet another little state machine to deal with preprocessor lines.
1341 typedef enum
1343 dnone, /* nothing seen */
1344 dsharpseen, /* '#' seen as first char on line */
1345 ddefineseen, /* '#' and 'define' seen */
1346 dignorerest /* ignore rest of line */
1347 } DEFINEST;
1348 DEFINEST definedef;
1351 * Set this to TRUE, and the next token considered is called a function.
1352 * Used only for GNUmacs's function-defining macros.
1354 logical next_token_is_func;
1357 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1359 logical yacc_rules;
1362 * consider_token ()
1363 * checks to see if the current token is at the start of a
1364 * function, or corresponds to a typedef, or is a struct/union/enum
1365 * tag.
1367 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1368 * C_EXT is which language we are looking at.
1370 * In the future we will need some way to adjust where the end of
1371 * the token is; for instance, implementing the C++ keyword
1372 * `operator' properly will adjust the end of the token to be after
1373 * whatever follows `operator'.
1375 * Globals
1376 * funcdef IN OUT
1377 * structdef IN OUT
1378 * definedef IN OUT
1379 * typdef IN OUT
1380 * next_token_is_func IN OUT
1383 logical
1384 consider_token (c, tokp, c_ext, cblev, is_func)
1385 register char c; /* IN: first char after the token */
1386 register TOKEN *tokp; /* IN: token pointer */
1387 int c_ext; /* IN: C extensions mask */
1388 int cblev; /* IN: curly brace level */
1389 logical *is_func; /* OUT */
1391 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1394 * Advance the definedef state machine.
1396 switch (definedef)
1398 case dnone:
1399 /* We're not on a preprocessor line. */
1400 break;
1401 case dsharpseen:
1402 if (toktype == st_C_define)
1404 definedef = ddefineseen;
1406 else
1408 definedef = dignorerest;
1410 return (FALSE);
1411 case ddefineseen:
1413 * Make a tag for any macro.
1415 definedef = dignorerest;
1416 *is_func = (c == '(');
1417 if (!*is_func && !constantypedefs)
1418 return (FALSE);
1419 else
1420 return (TRUE);
1421 case dignorerest:
1422 return (FALSE);
1423 default:
1424 error ("internal error: definedef value.", 0);
1428 * Now typedefs
1430 switch (typdef)
1432 case tnone:
1433 if (toktype == st_C_typedef)
1435 if (typedefs)
1436 typdef = ttypedseen;
1437 funcdef = fnone;
1438 return (FALSE);
1440 break;
1441 case ttypedseen:
1442 switch (toktype)
1444 case st_none:
1445 case st_C_typespec:
1446 typdef = tend;
1447 break;
1448 case st_C_struct:
1449 case st_C_enum:
1450 break;
1452 /* Do not return here, so the structdef stuff has a chance. */
1453 break;
1454 case tend:
1455 switch (toktype)
1457 case st_C_typespec:
1458 case st_C_struct:
1459 case st_C_enum:
1460 return (FALSE);
1462 return (TRUE);
1466 * This structdef business is currently only invoked when cblev==0.
1467 * It should be recursively invoked whatever the curly brace level,
1468 * and a stack of states kept, to allow for definitions of structs
1469 * within structs.
1471 * This structdef business is NOT invoked when we are ctags and the
1472 * file is plain C. This is because a struct tag may have the same
1473 * name as another tag, and this loses with ctags.
1475 * This if statement deals with the typdef state machine as
1476 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1477 * return (FALSE). All the other code here is for the structdef
1478 * state machine.
1480 switch (toktype)
1482 case st_C_struct:
1483 case st_C_enum:
1484 if (typdef == ttypedseen
1485 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1487 structdef = skeyseen;
1488 structtype = toktype;
1490 return (FALSE);
1492 if (structdef == skeyseen)
1494 if (structtype == st_C_struct)
1496 strncpy (structtag, tokp->p, tokp->len);
1497 structtag[tokp->len] = '\0'; /* for struct/union/class */
1499 else
1501 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1503 structdef = stagseen;
1504 return (TRUE);
1507 /* Avoid entering funcdef stuff if typdef is going on. */
1508 if (typdef != tnone)
1510 definedef = dnone;
1511 return (FALSE);
1514 /* Detect GNUmacs's function-defining macros. */
1515 if (definedef == dnone)
1517 if (strneq (tokp->p, "DEF", 3)
1518 || strneq (tokp->p, "ENTRY", 5)
1519 || strneq (tokp->p, "SYSCALL", 7)
1520 || strneq (tokp->p, "PSEUDO", 6))
1522 next_token_is_func = TRUE;
1523 return (FALSE);
1525 if (strneq (tokp->p, "EXFUN", 5))
1527 next_token_is_func = FALSE;
1528 return (FALSE);
1531 if (next_token_is_func)
1533 next_token_is_func = FALSE;
1534 funcdef = fnone;
1535 *is_func = TRUE; /* to force search string in ctags */
1536 return (TRUE);
1539 /* A function? */
1540 switch (toktype)
1542 case st_C_typespec:
1543 if (funcdef != finlist && funcdef != fignore)
1544 funcdef = fnone; /* should be useless */
1545 return (FALSE);
1546 default:
1547 if (funcdef == fnone)
1549 funcdef = ftagseen;
1550 *is_func = TRUE;
1551 return (TRUE);
1555 return (FALSE);
1559 * C_entries ()
1560 * This routine finds functions, typedefs, #define's and
1561 * struct/union/enum definitions in C syntax and adds them
1562 * to the list.
1565 #define curlb (lbs[curndx].lb)
1566 #define othlb (lbs[1-curndx].lb)
1567 #define newlb (lbs[newndx].lb)
1568 #define curlinepos (lbs[curndx].linepos)
1569 #define othlinepos (lbs[1-curndx].linepos)
1570 #define newlinepos (lbs[newndx].linepos)
1572 /* Save and restore token state. This is used when preprocessor defines
1573 are handled, to avoid disturbing active function/typedef/struct states. */
1574 #define TOKEN_SAVED_P (savetok.lineno > 0)
1575 #define SAVE_TOKEN (savetok = tok, savetok.p = (char *) tokoff, \
1576 savetok.len = toklen, strcpy(savenameb, nameb))
1577 #define RESTORE_TOKEN (tok = savetok, tokoff = (int) tok.p, \
1578 toklen = tok.len, strcpy(nameb, savenameb), \
1579 savetok.lineno = 0)
1581 #define CNL_SAVE_DEFINEDEF \
1582 do { \
1583 SET_FILEPOS (curlinepos, inf, charno); \
1584 lineno++; \
1585 charno += readline (&curlb, inf); \
1586 lp = curlb.buffer; \
1587 quotednl = FALSE; \
1588 newndx = curndx; \
1589 } while (FALSE)
1591 #define CNL \
1592 do { \
1593 CNL_SAVE_DEFINEDEF; \
1594 if (TOKEN_SAVED_P) \
1595 RESTORE_TOKEN; \
1596 definedef = dnone; \
1597 } while (FALSE)
1599 #define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
1600 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1601 #define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
1602 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
1604 void
1605 C_entries (c_ext, inf)
1606 int c_ext; /* extension of C? */
1607 FILE *inf;
1609 register char c; /* latest char read; '\0' for end of line */
1610 register char *lp; /* pointer one beyond the character `c' */
1611 int curndx, newndx; /* indices for current and new lb */
1612 TOKEN tok; /* latest token read for funcdef & structdef */
1613 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
1614 register int tokoff; /* offset in line of start of latest token */
1615 register int toklen; /* length of latest token */
1616 int cblev; /* current curly brace level */
1617 int parlev; /* current parenthesis level */
1618 logical incomm, inquote, inchar, quotednl, midtoken;
1619 logical cplpl;
1620 TOKEN savetok; /* saved token during preprocessor handling */
1621 char savenameb[BUFSIZ]; /* ouch! */
1623 savetok.lineno = 0;
1624 curndx = newndx = 0;
1625 lineno = 0;
1626 charno = 0;
1627 lp = curlb.buffer;
1628 *lp = 0;
1630 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1631 next_token_is_func = yacc_rules = FALSE;
1632 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1633 cblev = 0;
1634 parlev = 0;
1635 cplpl = c_ext & C_PLPL;
1637 while (!feof (inf))
1639 c = *lp++;
1640 if (c == '\\')
1642 /* If we're at the end of the line, the next character is a
1643 '\0'; don't skip it, because it's the thing that tells us
1644 to read the next line. */
1645 if (*lp == '\0')
1647 quotednl = TRUE;
1648 continue;
1650 lp++;
1651 c = ' ';
1653 else if (incomm)
1655 switch (c)
1657 case '*':
1658 if (*lp == '/')
1660 c = *lp++;
1661 incomm = FALSE;
1663 break;
1664 case '\0':
1665 /* Newlines inside comments do not end macro definitions in
1666 traditional cpp. */
1667 CNL_SAVE_DEFINEDEF;
1668 break;
1670 continue;
1672 else if (inquote)
1674 switch (c)
1676 case '"':
1677 inquote = FALSE;
1678 break;
1679 case '\0':
1680 /* Newlines inside strings do not end macro definitions
1681 in traditional cpp, even though compilers don't
1682 usually accept them. */
1683 CNL_SAVE_DEFINEDEF;
1684 break;
1686 continue;
1688 else if (inchar)
1690 switch (c)
1692 case '\0':
1693 /* Hmmm, something went wrong. */
1694 CNL;
1695 /* FALLTHRU */
1696 case '\'':
1697 inchar = FALSE;
1698 break;
1700 continue;
1702 else
1703 switch (c)
1705 case '"':
1706 inquote = TRUE;
1707 if (funcdef != finlist && funcdef != fignore)
1708 funcdef = fnone;
1709 continue;
1710 case '\'':
1711 inchar = TRUE;
1712 if (funcdef != finlist && funcdef != fignore)
1713 funcdef = fnone;
1714 continue;
1715 case '/':
1716 if (*lp == '*')
1718 lp++;
1719 incomm = TRUE;
1720 continue;
1722 else if (cplpl && *lp == '/')
1724 c = 0;
1725 break;
1727 else
1728 break;
1729 case '%':
1730 if ((c_ext & YACC) && *lp == '%')
1732 /* entering or exiting rules section in yacc file */
1733 lp++;
1734 definedef = dnone; funcdef = fnone;
1735 typdef = tnone; structdef = snone;
1736 next_token_is_func = FALSE;
1737 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1738 cblev = 0;
1739 yacc_rules = !yacc_rules;
1740 continue;
1742 else
1743 break;
1744 case '#':
1745 if (lp == newlb.buffer + 1 && definedef == dnone)
1746 definedef = dsharpseen;
1747 continue;
1748 } /* switch (c) */
1751 /* Consider token only if some complicated conditions are satisfied. */
1752 if (((cblev == 0 && structdef != scolonseen)
1753 || (cblev == 1 && cplpl && structdef == sinbody))
1754 && typdef != tignore
1755 && definedef != dignorerest
1756 && (funcdef != finlist
1757 || definedef != dnone))
1759 if (midtoken)
1761 if (endtoken (c))
1763 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
1766 * This handles :: in the middle, but not at beginning
1767 * of an identifier.
1769 lp += 2;
1770 toklen += 3;
1772 else
1774 logical is_func = FALSE;
1776 tok.lineno = lineno;
1777 tok.p = newlb.buffer + tokoff;
1778 tok.len = toklen;
1779 tok.named = FALSE;
1780 if (yacc_rules
1781 || consider_token (c, &tok, c_ext, cblev, &is_func))
1783 if (structdef == sinbody
1784 && definedef == dnone
1785 && is_func)
1786 /* function defined in C++ class body */
1788 tok.named = TRUE;
1789 sprintf (nameb, "%s::%.*s",
1790 ((structtag[0] == '\0')
1791 ? "_anonymous_" : structtag),
1792 tok.len, tok.p);
1794 else
1796 sprintf (nameb, "%.*s", tok.len, tok.p);
1799 if (structdef == stagseen
1800 || typdef == tend)
1801 tok.named = TRUE;
1803 if (definedef == dnone
1804 && (funcdef == ftagseen
1805 || structdef == stagseen
1806 || typdef == tend))
1808 if (newndx == curndx)
1809 curndx = 1 - curndx; /* switch line buffers */
1811 else
1812 MAKE_TAG_FROM_NEW_LB (is_func);
1814 midtoken = FALSE;
1816 } /* if (endtoken (c)) */
1817 else if (intoken (c))
1819 toklen++;
1820 continue;
1822 } /* if (midtoken) */
1823 else if (begtoken (c))
1825 switch (definedef)
1827 case dnone:
1828 switch (funcdef)
1830 case fstartlist:
1831 funcdef = finlist;
1832 continue;
1833 case flistseen:
1834 MAKE_TAG_FROM_OTH_LB (TRUE);
1835 funcdef = fignore;
1836 break;
1837 case ftagseen:
1838 funcdef = fnone;
1839 break;
1841 if (structdef == stagseen)
1842 structdef = snone;
1843 break;
1844 case dsharpseen:
1845 /* Take a quick peek ahead for define directive,
1846 so we can avoid saving the token when not absolutely
1847 necessary. [This is a speed hack.] */
1848 if (c == 'd' && strneq(lp, "efine", 5)
1849 && iswhite(*(lp + 5)))
1851 SAVE_TOKEN;
1852 definedef = ddefineseen;
1853 lp += 6;
1855 else
1856 definedef = dignorerest;
1857 continue;
1859 if (!yacc_rules || lp == newlb.buffer + 1)
1861 tokoff = lp - 1 - newlb.buffer;
1862 toklen = 1;
1863 midtoken = TRUE;
1865 continue;
1867 } /* if must look at token */
1870 /* Detect end of line, colon, comma, semicolon and various braces
1871 after having handled a token.*/
1872 switch (c)
1874 case ':':
1875 if (definedef != dnone)
1876 break;
1877 if (structdef == stagseen)
1878 structdef = scolonseen;
1879 else
1880 switch (funcdef)
1882 case ftagseen:
1883 if (yacc_rules)
1885 MAKE_TAG_FROM_OTH_LB (FALSE);
1886 funcdef = fignore;
1888 break;
1889 case fstartlist:
1890 funcdef = fnone;
1891 break;
1893 break;
1894 case ';':
1895 if (definedef != dnone)
1896 break;
1897 if (cblev == 0)
1898 switch (typdef)
1900 case tend:
1901 MAKE_TAG_FROM_OTH_LB (FALSE);
1902 /* FALLTHRU */
1903 default:
1904 typdef = tnone;
1906 if (funcdef != fignore)
1907 funcdef = fnone;
1908 if (structdef == stagseen)
1909 structdef = snone;
1910 break;
1911 case ',':
1912 if (definedef != dnone)
1913 break;
1914 if (funcdef != finlist && funcdef != fignore)
1915 funcdef = fnone;
1916 if (structdef == stagseen)
1917 structdef = snone;
1918 break;
1919 case '[':
1920 if (definedef != dnone)
1921 break;
1922 if (cblev == 0 && typdef == tend)
1924 typdef = tignore;
1925 MAKE_TAG_FROM_OTH_LB (FALSE);
1926 break;
1928 if (funcdef != finlist && funcdef != fignore)
1929 funcdef = fnone;
1930 if (structdef == stagseen)
1931 structdef = snone;
1932 break;
1933 case '(':
1934 if (definedef != dnone)
1935 break;
1936 switch (funcdef)
1938 case ftagseen:
1939 funcdef = fstartlist;
1940 break;
1941 case flistseen:
1942 funcdef = finlist;
1943 break;
1945 parlev++;
1946 break;
1947 case ')':
1948 if (definedef != dnone)
1949 break;
1950 if (--parlev == 0)
1952 switch (funcdef)
1954 case fstartlist:
1955 case finlist:
1956 funcdef = flistseen;
1957 break;
1959 if (cblev == 0 && typdef == tend)
1961 typdef = tignore;
1962 MAKE_TAG_FROM_OTH_LB (FALSE);
1965 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
1966 parlev = 0;
1967 break;
1968 case '{':
1969 if (definedef != dnone)
1970 break;
1971 if (typdef == ttypedseen)
1972 typdef = tinbody;
1973 switch (structdef)
1975 case skeyseen: /* unnamed struct */
1976 structtag[0] = '\0';
1977 structdef = sinbody;
1978 break;
1979 case stagseen:
1980 case scolonseen: /* named struct */
1981 structdef = sinbody;
1982 MAKE_TAG_FROM_OTH_LB (FALSE);
1983 break;
1985 switch (funcdef)
1987 case flistseen:
1988 MAKE_TAG_FROM_OTH_LB (TRUE);
1989 /* FALLTHRU */
1990 case fignore:
1991 funcdef = fnone;
1992 break;
1993 case fnone:
1994 /* Neutralize `extern "C" {' grot.
1995 if (cblev == 0 && structdef == snone && typdef == tnone)
1996 cblev--; */;
1998 cblev++;
1999 break;
2000 case '*':
2001 if (definedef != dnone)
2002 break;
2003 if (funcdef == fstartlist)
2004 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
2005 break;
2006 case '}':
2007 if (definedef != dnone)
2008 break;
2009 if (!noindentypedefs && lp == newlb.buffer + 1)
2011 cblev = 0; /* reset curly brace level if first column */
2012 parlev = 0; /* also reset paren level, just in case... */
2014 else if (cblev > 0)
2015 cblev--;
2016 if (cblev == 0)
2018 if (typdef == tinbody)
2019 typdef = tend;
2020 structdef = snone;
2021 strcpy (structtag, "<error 2>");
2023 break;
2024 case '=':
2025 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2026 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
2027 if (definedef != dnone)
2028 break;
2029 /* These surely cannot follow a function tag. */
2030 if (funcdef != finlist && funcdef != fignore)
2031 funcdef = fnone;
2032 break;
2033 case '\0':
2034 /* If a macro spans multiple lines don't reset its state. */
2035 if (quotednl)
2036 CNL_SAVE_DEFINEDEF;
2037 else
2038 CNL;
2039 break;
2040 } /* switch (c) */
2042 } /* while not eof */
2045 /* Fortran parsing */
2047 char *dbp;
2048 int pfcnt;
2050 logical
2051 tail (cp)
2052 char *cp;
2054 register int len = 0;
2056 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2057 cp++, len++;
2058 if (*cp == 0)
2060 dbp += len;
2061 return (TRUE);
2063 return (FALSE);
2066 void
2067 takeprec ()
2069 while (isspace (*dbp))
2070 dbp++;
2071 if (*dbp != '*')
2072 return;
2073 dbp++;
2074 while (isspace (*dbp))
2075 dbp++;
2076 if (!isdigit (*dbp))
2078 --dbp; /* force failure */
2079 return;
2082 dbp++;
2083 while (isdigit (*dbp));
2086 void
2087 getit (inf)
2088 FILE *inf;
2090 register char *cp;
2091 char c;
2092 char nambuf[BUFSIZ];
2094 while (isspace (*dbp))
2095 dbp++;
2096 if (*dbp == '\0')
2098 lineno++;
2099 linecharno = charno;
2100 charno += readline (&lb, inf);
2101 dbp = lb.buffer;
2102 if (dbp[5] != '&')
2103 return;
2104 dbp += 6;
2105 while (isspace (*dbp))
2106 dbp++;
2108 if (!isalpha (*dbp)
2109 && *dbp != '_'
2110 && *dbp != '$')
2111 return;
2112 for (cp = dbp + 1;
2113 (*cp
2114 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2115 cp++)
2116 continue;
2117 c = *cp;
2118 *cp = '\0';
2119 strcpy (nambuf, dbp);
2120 *cp = c;
2121 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2122 cp - lb.buffer + 1, lineno, linecharno);
2123 pfcnt++;
2127 Fortran_functions (inf)
2128 FILE *inf;
2130 lineno = 0;
2131 charno = 0;
2132 pfcnt = 0;
2134 while (!feof (inf))
2136 lineno++;
2137 linecharno = charno;
2138 charno += readline (&lb, inf);
2139 dbp = lb.buffer;
2140 if (*dbp == '%')
2141 dbp++; /* Ratfor escape to fortran */
2142 while (isspace (*dbp))
2143 dbp++;
2144 if (*dbp == 0)
2145 continue;
2146 switch (*dbp | ' ')
2148 case 'i':
2149 if (tail ("integer"))
2150 takeprec ();
2151 break;
2152 case 'r':
2153 if (tail ("real"))
2154 takeprec ();
2155 break;
2156 case 'l':
2157 if (tail ("logical"))
2158 takeprec ();
2159 break;
2160 case 'c':
2161 if (tail ("complex") || tail ("character"))
2162 takeprec ();
2163 break;
2164 case 'd':
2165 if (tail ("double"))
2167 while (isspace (*dbp))
2168 dbp++;
2169 if (*dbp == 0)
2170 continue;
2171 if (tail ("precision"))
2172 break;
2173 continue;
2175 break;
2177 while (isspace (*dbp))
2178 dbp++;
2179 if (*dbp == 0)
2180 continue;
2181 switch (*dbp | ' ')
2183 case 'f':
2184 if (tail ("function"))
2185 getit (inf);
2186 continue;
2187 case 's':
2188 if (tail ("subroutine"))
2189 getit (inf);
2190 continue;
2191 case 'e':
2192 if (tail ("entry"))
2193 getit (inf);
2194 continue;
2195 case 'p':
2196 if (tail ("program"))
2198 getit (inf);
2199 continue;
2201 if (tail ("procedure"))
2202 getit (inf);
2203 continue;
2206 return (pfcnt);
2210 * Bob Weiner, Motorola Inc., 4/3/94
2211 * Unix and microcontroller assembly tag handling
2212 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2214 void
2215 Asm_labels (inf)
2216 FILE *inf;
2218 char nambuf[BUFSIZ];
2219 register char *cp;
2220 char c;
2222 lineno = 0;
2223 charno = 0;
2224 pfcnt = 0;
2226 while (!feof (inf))
2228 lineno++;
2229 linecharno = charno;
2230 charno += readline (&lb, inf);
2231 cp = lb.buffer;
2233 /* If first char is alphabetic or one of [_.$], test for colon
2234 following identifier. */
2235 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2237 /* Read past label. */
2238 cp++;
2239 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2240 cp++;
2241 if (*cp == ':' || isspace (*cp))
2243 /* Found end of label, so copy it and add it to the table. */
2244 c = *cp;
2245 *cp = '\0';
2246 strcpy (nambuf, lb.buffer);
2247 *cp = c;
2248 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2249 cp - lb.buffer + 1, lineno, linecharno);
2250 pfcnt++;
2256 /* Added by Mosur Mohan, 4/22/88 */
2257 /* Pascal parsing */
2259 #define GET_NEW_LINE \
2261 linecharno = charno; lineno++; \
2262 charno += 1 + readline (&lb, inf); \
2263 dbp = lb.buffer; \
2266 /* Locates tags for procedures & functions.
2267 * Doesn't do any type- or var-definitions.
2268 * It does look for the keyword "extern" or "forward"
2269 * immediately following the procedure statement;
2270 * if found, the tag is skipped.
2273 void
2274 Pascal_functions (inf)
2275 FILE *inf;
2277 struct linebuffer tline; /* mostly copied from C_entries */
2278 long save_lcno;
2279 int save_lineno;
2280 char c, *cp;
2281 char nambuf[BUFSIZ];
2283 logical /* each of these flags is TRUE iff: */
2284 incomm1, /* point is inside {..} comment */
2285 incomm2, /* point is inside (*..*) comment */
2286 inquote, /* point is inside '..' string */
2287 get_tagname, /* point is after PROCEDURE/FUNCTION */
2288 /* keyword, so next item = potential tag */
2289 found_tag, /* point is after a potential tag */
2290 inparms, /* point is within parameter-list */
2291 verify_tag; /* point has passed the parm-list, so the */
2292 /* next token will determine whether */
2293 /* this is a FORWARD/EXTERN to be */
2294 /* ignored, or whether it is a real tag */
2296 lineno = 0;
2297 charno = 0;
2298 dbp = lb.buffer;
2299 *dbp = 0;
2300 initbuffer (&tline);
2302 incomm1 = incomm2 = inquote = FALSE;
2303 found_tag = FALSE; /* have a proc name; check if extern */
2304 get_tagname = FALSE; /* have found "procedure" keyword */
2305 inparms = FALSE; /* found '(' after "proc" */
2306 verify_tag = FALSE; /* check if "extern" is ahead */
2308 /* long main loop to get next char */
2309 while (!feof (inf))
2311 c = *dbp++;
2312 if (c == 0) /* if end of line */
2314 GET_NEW_LINE;
2315 if (*dbp == 0)
2316 continue;
2317 if (!((found_tag && verify_tag) ||
2318 get_tagname))
2319 c = *dbp++; /* only if don't need *dbp pointing */
2320 /* to the beginning of the name of */
2321 /* the procedure or function */
2323 if (incomm1) /* within { - } comments */
2325 if (c == '}')
2326 incomm1 = FALSE;
2327 continue;
2329 else if (incomm2) /* within (* - *) comments */
2331 if (c == '*')
2333 while ((c = *dbp++) == '*')
2334 continue;
2335 if (c == 0)
2336 GET_NEW_LINE;
2337 if (c == ')')
2338 incomm2 = FALSE;
2340 continue;
2342 else if (inquote)
2344 if (c == '\'')
2345 inquote = FALSE;
2346 continue;
2348 else
2349 switch (c)
2351 case '\'':
2352 inquote = TRUE; /* found first quote */
2353 continue;
2354 case '{': /* found open-{-comment */
2355 incomm1 = TRUE;
2356 continue;
2357 case '(':
2358 if (*dbp == '*') /* found open-(*-comment */
2360 incomm2 = TRUE;
2361 dbp++;
2363 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2364 inparms = TRUE;
2365 continue;
2366 case ')': /* end of parms list */
2367 if (inparms)
2368 inparms = FALSE;
2369 continue;
2370 case ';':
2371 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2373 verify_tag = TRUE;
2374 break;
2376 continue;
2378 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2380 /* check if this is an "extern" declaration */
2381 if (*dbp == 0)
2382 continue;
2383 if ((*dbp == 'e') || (*dbp == 'E'))
2385 if (tail ("extern")) /* superfluous, really! */
2387 found_tag = FALSE;
2388 verify_tag = FALSE;
2391 else if ((*dbp == 'f') || (*dbp == 'F'))
2393 if (tail ("forward")) /* check for forward reference */
2395 found_tag = FALSE;
2396 verify_tag = FALSE;
2399 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2401 found_tag = FALSE;
2402 verify_tag = FALSE;
2403 pfnote (nambuf, TRUE, FALSE,
2404 tline.buffer, cp - tline.buffer + 1,
2405 save_lineno, save_lcno);
2406 continue;
2409 if (get_tagname) /* grab name of proc or fn */
2411 if (*dbp == 0)
2412 continue;
2414 /* save all values for later tagging */
2415 tline.size = lb.size;
2416 strcpy (tline.buffer, lb.buffer);
2417 save_lineno = lineno;
2418 save_lcno = linecharno;
2420 /* grab block name */
2421 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2422 continue;
2423 c = cp[0];
2424 cp[0] = 0;
2425 strcpy (nambuf, dbp);
2426 cp[0] = c;
2427 dbp = cp; /* restore dbp to e-o-token */
2428 get_tagname = FALSE;
2429 found_tag = TRUE;
2430 continue;
2432 /* and proceed to check for "extern" */
2434 if ((!incomm1) && (!incomm2) && (!inquote) &&
2435 (!found_tag) && (!get_tagname))
2437 /* check for proc/fn keywords */
2438 switch (c | ' ')
2440 case 'p':
2441 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2442 get_tagname = TRUE;
2443 continue;
2444 case 'f':
2445 if (tail ("unction"))
2446 get_tagname = TRUE;
2447 continue;
2450 } /* while not eof */
2454 * lisp tag functions
2455 * just look for (def or (DEF
2459 L_isdef (dbp)
2460 register char *dbp;
2462 return ((dbp[1] == 'd' || dbp[1] == 'D')
2463 && (dbp[2] == 'e' || dbp[2] == 'E')
2464 && (dbp[3] == 'f' || dbp[3] == 'F'));
2468 L_isquote (dbp)
2469 register char *dbp;
2471 return ((*(++dbp) == 'q' || *dbp == 'Q')
2472 && (*(++dbp) == 'u' || *dbp == 'U')
2473 && (*(++dbp) == 'o' || *dbp == 'O')
2474 && (*(++dbp) == 't' || *dbp == 'T')
2475 && (*(++dbp) == 'e' || *dbp == 'E')
2476 && isspace(*(++dbp)));
2479 void
2480 L_getit ()
2482 register char *cp;
2483 char c;
2484 char nambuf[BUFSIZ];
2486 if (*dbp == '\'') /* Skip prefix quote */
2487 dbp++;
2488 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2490 dbp += 7;
2491 while (isspace(*dbp))
2492 dbp++;
2494 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
2495 continue;
2496 if (cp == dbp)
2497 return;
2499 c = cp[0];
2500 cp[0] = 0;
2501 strcpy (nambuf, dbp);
2502 cp[0] = c;
2503 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2504 cp - lb.buffer + 1, lineno, linecharno);
2505 pfcnt++;
2508 void
2509 Lisp_functions (inf)
2510 FILE *inf;
2512 lineno = 0;
2513 charno = 0;
2514 pfcnt = 0;
2516 while (!feof (inf))
2518 lineno++;
2519 linecharno = charno;
2520 charno += readline (&lb, inf);
2521 dbp = lb.buffer;
2522 if (dbp[0] == '(')
2524 if (L_isdef (dbp))
2526 while (!isspace (*dbp))
2527 dbp++;
2528 while (isspace (*dbp))
2529 dbp++;
2530 L_getit ();
2532 else
2534 /* Check for (foo::defmumble name-defined ... */
2536 dbp++;
2537 while (*dbp && !isspace (*dbp)
2538 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2539 if (*dbp == ':')
2542 dbp++;
2543 while (*dbp == ':');
2545 if (L_isdef (dbp - 1))
2547 while (!isspace (*dbp))
2548 dbp++;
2549 while (isspace (*dbp))
2550 dbp++;
2551 L_getit ();
2560 * Scheme tag functions
2561 * look for (def... xyzzy
2562 * look for (def... (xyzzy
2563 * look for (def ... ((...(xyzzy ....
2564 * look for (set! xyzzy
2567 void get_scheme ();
2569 void
2570 Scheme_functions (inf)
2571 FILE *inf;
2573 lineno = 0;
2574 charno = 0;
2575 pfcnt = 0;
2577 while (!feof (inf))
2579 lineno++;
2580 linecharno = charno;
2581 charno += readline (&lb, inf);
2582 dbp = lb.buffer;
2583 if (dbp[0] == '(' &&
2584 (dbp[1] == 'D' || dbp[1] == 'd') &&
2585 (dbp[2] == 'E' || dbp[2] == 'e') &&
2586 (dbp[3] == 'F' || dbp[3] == 'f'))
2588 while (!isspace (*dbp))
2589 dbp++;
2590 /* Skip over open parens and white space */
2591 while (*dbp && (isspace (*dbp) || *dbp == '('))
2592 dbp++;
2593 get_scheme ();
2595 if (dbp[0] == '(' &&
2596 (dbp[1] == 'S' || dbp[1] == 's') &&
2597 (dbp[2] == 'E' || dbp[2] == 'e') &&
2598 (dbp[3] == 'T' || dbp[3] == 't') &&
2599 (dbp[4] == '!' || dbp[4] == '!') &&
2600 (isspace (dbp[5])))
2602 while (!isspace (*dbp))
2603 dbp++;
2604 /* Skip over white space */
2605 while (isspace (*dbp))
2606 dbp++;
2607 get_scheme ();
2612 void
2613 get_scheme ()
2615 register char *cp;
2616 char c;
2617 char nambuf[BUFSIZ];
2619 if (*dbp == 0)
2620 return;
2621 /* Go till you get to white space or a syntactic break */
2622 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2623 continue;
2624 /* Null terminate the string there. */
2625 c = cp[0];
2626 cp[0] = 0;
2627 /* Copy the string */
2628 strcpy (nambuf, dbp);
2629 /* Unterminate the string */
2630 cp[0] = c;
2631 /* Announce the change */
2632 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2633 pfcnt++;
2636 /* Find tags in TeX and LaTeX input files. */
2638 /* TEX_toktab is a table of TeX control sequences that define tags.
2639 Each TEX_tabent records one such control sequence.
2640 CONVERT THIS TO USE THE Stab TYPE!! */
2642 struct TEX_tabent
2644 char *name;
2645 int len;
2648 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2650 /* Default set of control sequences to put into TEX_toktab.
2651 The value of environment var TEXTAGS is prepended to this. */
2653 char *TEX_defenv = "\
2654 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2656 void TEX_mode ();
2657 struct TEX_tabent *TEX_decode_env ();
2658 void TEX_getit ();
2659 int TEX_Token ();
2661 char TEX_esc = '\\';
2662 char TEX_opgrp = '{';
2663 char TEX_clgrp = '}';
2666 * TeX/LaTeX scanning loop.
2669 void
2670 TeX_functions (inf)
2671 FILE *inf;
2673 char *lasthit;
2675 lineno = 0;
2676 charno = 0;
2677 pfcnt = 0;
2679 /* Select either \ or ! as escape character. */
2680 TEX_mode (inf);
2682 /* Initialize token table once from environment. */
2683 if (!TEX_toktab)
2684 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2686 while (!feof (inf))
2687 { /* Scan each line in file */
2688 lineno++;
2689 linecharno = charno;
2690 charno += readline (&lb, inf);
2691 dbp = lb.buffer;
2692 lasthit = dbp;
2693 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
2695 register int i;
2697 if (!*(++dbp))
2698 break;
2699 linecharno += dbp - lasthit;
2700 lasthit = dbp;
2701 i = TEX_Token (lasthit);
2702 if (0 <= i)
2704 TEX_getit (lasthit, TEX_toktab[i].len);
2705 break; /* We only save a line once */
2711 #define TEX_LESC '\\'
2712 #define TEX_SESC '!'
2713 #define TEX_cmt '%'
2715 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2716 /* chars accordingly. */
2718 void
2719 TEX_mode (inf)
2720 FILE *inf;
2722 int c;
2724 while ((c = getc (inf)) != EOF)
2726 /* Skip to next line if we hit the TeX comment char. */
2727 if (c == TEX_cmt)
2728 while (c != '\n')
2729 c = getc (inf);
2730 else if (c == TEX_LESC || c == TEX_SESC )
2731 break;
2734 if (c == TEX_LESC)
2736 TEX_esc = TEX_LESC;
2737 TEX_opgrp = '{';
2738 TEX_clgrp = '}';
2740 else
2742 TEX_esc = TEX_SESC;
2743 TEX_opgrp = '<';
2744 TEX_clgrp = '>';
2746 rewind (inf);
2749 /* Read environment and prepend it to the default string. */
2750 /* Build token table. */
2752 struct TEX_tabent *
2753 TEX_decode_env (evarname, defenv)
2754 char *evarname;
2755 char *defenv;
2757 register char *env, *p;
2759 struct TEX_tabent *tab;
2760 int size, i;
2762 /* Append default string to environment. */
2763 env = getenv (evarname);
2764 if (!env)
2765 env = defenv;
2766 else
2767 env = concat (env, defenv, "");
2769 /* Allocate a token table */
2770 for (size = 1, p = env; p;)
2771 if ((p = etags_strchr (p, ':')) && *(++p))
2772 size++;
2773 /* Add 1 to leave room for null terminator. */
2774 tab = xnew (size + 1, struct TEX_tabent);
2776 /* Unpack environment string into token table. Be careful about */
2777 /* zero-length strings (leading ':', "::" and trailing ':') */
2778 for (i = 0; *env;)
2780 p = etags_strchr (env, ':');
2781 if (!p) /* End of environment string. */
2782 p = env + strlen (env);
2783 if (p - env > 0)
2784 { /* Only non-zero strings. */
2785 tab[i].name = savenstr (env, p - env);
2786 tab[i].len = strlen (tab[i].name);
2787 i++;
2789 if (*p)
2790 env = p + 1;
2791 else
2793 tab[i].name = NULL; /* Mark end of table. */
2794 tab[i].len = 0;
2795 break;
2798 return tab;
2801 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
2802 The name being defined actually starts at (NAME + LEN + 1).
2803 But we seem to include the TeX command in the tag name. */
2805 void
2806 TEX_getit (name, len)
2807 char *name;
2808 int len;
2810 char *p = name + len;
2811 char nambuf[BUFSIZ];
2813 if (*name == 0)
2814 return;
2816 /* Let tag name extend to next group close (or end of line) */
2817 while (*p && *p != TEX_clgrp)
2818 p++;
2819 strncpy (nambuf, name, p - name);
2820 nambuf[p - name] = 0;
2822 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2823 pfcnt++;
2826 /* If the text at CP matches one of the tag-defining TeX command names,
2827 return the pointer to the first occurrence of that command in TEX_toktab.
2828 Otherwise return -1. */
2830 /* Keep the capital `T' in `Token' for dumb truncating compilers
2831 (this distinguishes it from `TEX_toktab' */
2833 TEX_Token (cp)
2834 char *cp;
2836 int i;
2838 for (i = 0; TEX_toktab[i].len > 0; i++)
2839 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
2840 return i;
2841 return -1;
2844 /* Support for Prolog. */
2846 /* whole head (not only functor, but also arguments)
2847 is gotten in compound term. */
2849 void
2850 prolog_getit (s, lineno, linecharno)
2851 char *s;
2852 int lineno;
2853 long linecharno;
2855 char nambuf[BUFSIZ], *save_s, tmpc;
2856 int insquote, npar;
2858 save_s = s;
2859 insquote = FALSE;
2860 npar = 0;
2861 while (1)
2863 if (*s == '\0') /* syntax error. */
2864 return;
2865 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2866 s += 2;
2867 else if (*s == '\'')
2869 insquote = !insquote;
2870 s++;
2872 else if (!insquote && *s == '(')
2874 npar++;
2875 s++;
2877 else if (!insquote && *s == ')')
2879 npar--;
2880 s++;
2881 if (npar == 0)
2882 break;
2883 else if (npar < 0) /* syntax error. */
2884 return;
2886 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2887 { /* fullstop. */
2888 if (npar != 0) /* syntax error. */
2889 return;
2890 s++;
2891 break;
2893 else
2894 s++;
2896 tmpc = *s;
2897 *s = '\0';
2898 strcpy (nambuf, save_s);
2899 *s = tmpc;
2900 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
2903 /* It is assumed that prolog predicate starts from column 0. */
2905 void
2906 Prolog_functions (inf)
2907 FILE *inf;
2909 void skip_comment (), prolog_getit ();
2911 lineno = linecharno = charno = 0;
2912 while (!feof (inf))
2914 lineno++;
2915 linecharno += charno;
2916 charno = readline (&lb, inf) + 1; /* 1 for newline. */
2917 dbp = lb.buffer;
2918 if (isspace (dbp[0])) /* not predicate header. */
2919 continue;
2920 else if (dbp[0] == '%') /* comment. */
2921 continue;
2922 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2923 skip_comment (&lb, inf, &lineno, &linecharno);
2924 else /* found. */
2925 prolog_getit (dbp, lineno, linecharno);
2929 void
2930 skip_comment (plb, inf, plineno, plinecharno)
2931 struct linebuffer *plb;
2932 FILE *inf;
2933 int *plineno; /* result */
2934 long *plinecharno; /* result */
2936 while (!substr ("*/", plb->buffer))
2938 (*plineno)++;
2939 *plinecharno += readline (plb, inf) + 1;
2940 } /* 1 for newline. */
2943 /* Return TRUE if 'sub' exists somewhere in 's'. */
2946 substr (sub, s)
2947 char *sub;
2948 char *s;
2950 while (*s && (s = etags_strchr (s, *sub)))
2951 if (prestr (sub, s))
2952 return (TRUE);
2953 else
2954 s++;
2955 return (FALSE);
2958 /* Return TRUE if 'pre' is prefix of string 's'. */
2961 prestr (pre, s)
2962 char *pre;
2963 char *s;
2965 if (*pre == '\0')
2966 return (TRUE);
2967 else if (*pre == *s)
2968 return (prestr (pre + 1, s + 1));
2969 else
2970 return (FALSE);
2973 /* Initialize a linebuffer for use */
2975 void
2976 initbuffer (linebuffer)
2977 struct linebuffer *linebuffer;
2979 linebuffer->size = 200;
2980 linebuffer->buffer = xnew (200, char);
2984 * Read a line of text from `stream' into `linebuffer'.
2985 * Return the number of characters read from `stream',
2986 * which is the length of the line including the newline, if any.
2988 long
2989 readline (linebuffer, stream)
2990 struct linebuffer *linebuffer;
2991 register FILE *stream;
2993 char *buffer = linebuffer->buffer;
2994 register char *p = linebuffer->buffer;
2995 register char *pend;
2996 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2998 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
3000 while (1)
3002 register int c = getc (stream);
3003 if (p == pend)
3005 linebuffer->size *= 2;
3006 buffer = (char *) xrealloc (buffer, linebuffer->size);
3007 p += buffer - linebuffer->buffer;
3008 pend = buffer + linebuffer->size;
3009 linebuffer->buffer = buffer;
3011 if (c == EOF || c == '\n')
3013 *p = 0;
3014 newline = (c == '\n') ? 1 : 0;
3015 break;
3017 *p++ = c;
3020 return p - buffer + newline;
3023 char *
3024 savestr (cp)
3025 char *cp;
3027 return savenstr (cp, strlen (cp));
3030 char *
3031 savenstr (cp, len)
3032 char *cp;
3033 int len;
3035 register char *dp;
3037 dp = xnew (len + 1, char);
3038 strncpy (dp, cp, len);
3039 dp[len] = '\0';
3040 return dp;
3044 * Return the ptr in sp at which the character c last
3045 * appears; NULL if not found
3047 * Identical to System V strrchr, included for portability.
3050 char *
3051 etags_strrchr (sp, c)
3052 register char *sp, c;
3054 register char *r;
3056 r = NULL;
3059 if (*sp == c)
3060 r = sp;
3061 } while (*sp++);
3062 return (r);
3067 * Return the ptr in sp at which the character c first
3068 * appears; NULL if not found
3070 * Identical to System V strchr, included for portability.
3073 char *
3074 etags_strchr (sp, c)
3075 register char *sp, c;
3079 if (*sp == c)
3080 return (sp);
3081 } while (*sp++);
3082 return (NULL);
3085 /* Print error message and exit. */
3087 /* VARARGS1 */
3088 void
3089 fatal (s1, s2)
3090 char *s1, *s2;
3092 error (s1, s2);
3093 exit (BAD);
3096 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3098 /* VARARGS1 */
3099 void
3100 error (s1, s2)
3101 char *s1, *s2;
3103 fprintf (stderr, "%s: ", progname);
3104 fprintf (stderr, s1, s2);
3105 fprintf (stderr, "\n");
3108 /* Return a newly-allocated string whose contents
3109 concatenate those of s1, s2, s3. */
3111 char *
3112 concat (s1, s2, s3)
3113 char *s1, *s2, *s3;
3115 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3116 char *result = xnew (len1 + len2 + len3 + 1, char);
3118 strcpy (result, s1);
3119 strcpy (result + len1, s2);
3120 strcpy (result + len1 + len2, s3);
3121 result[len1 + len2 + len3] = '\0';
3123 return result;
3126 /* Does the same work as the system V getcwd, but does not need to
3127 guess buffer size in advance. Included mostly for compatibility. */
3128 char *
3129 etags_getcwd ()
3131 FILE *pipe;
3132 char *buf;
3133 int bufsize = 256;
3137 buf = xnew (bufsize, char);
3139 pipe = popen ("pwd 2>/dev/null", "r");
3140 if (pipe == NULL)
3142 perror ("pwd");
3143 exit (BAD);
3145 if (fgets (buf, bufsize, pipe) == NULL)
3147 perror ("pwd");
3148 exit (BAD);
3150 pclose (pipe);
3152 bufsize *= 2;
3154 } while (buf[strlen (buf) - 1] != '\n');
3156 return buf;
3159 /* Return a newly allocated string containing the filename
3160 of FILE relative to the absolute directory DIR (which
3161 should end with a slash). */
3163 char *
3164 relative_filename (file, dir)
3165 char *file, *dir;
3167 char *fp, *dp, *res;
3169 /* Find the common root of file and dir. */
3170 fp = absolute_filename (file, cwd);
3171 dp = dir;
3172 while (*fp++ == *dp++)
3173 continue;
3176 fp--;
3177 dp--;
3179 while (*fp != '/');
3181 /* Build a sequence of "../" strings for the resulting relative filename. */
3182 for (dp = etags_strchr (dp + 1, '/'), res = "";
3183 dp != NULL;
3184 dp = etags_strchr (dp + 1, '/'))
3186 res = concat (res, "../", "");
3189 /* Add the filename relative to the common root of file and dir. */
3190 res = concat (res, fp + 1, "");
3192 return res; /* temporary stub */
3195 /* Return a newly allocated string containing the
3196 absolute filename of FILE given CWD (which should
3197 end with a slash). */
3199 char *
3200 absolute_filename (file, cwd)
3201 char *file, *cwd;
3203 char *slashp, *cp, *res;
3205 if (file[0] == '/')
3206 res = concat (file, "", "");
3207 else
3208 res = concat (cwd, file, "");
3210 /* Delete the "/dirname/.." and "/." substrings. */
3211 slashp = etags_strchr (res, '/');
3212 while (slashp != NULL && slashp[0] != '\0')
3214 if (slashp[1] == '.')
3216 if (slashp[2] == '.'
3217 && (slashp[3] == '/' || slashp[3] == '\0'))
3219 cp = slashp;
3221 cp--;
3222 while (cp >= res && *cp != '/');
3223 if (*cp == '/')
3225 strcpy (cp, slashp + 3);
3227 else /* else (cp == res) */
3229 if (slashp[3] != '\0')
3230 strcpy (cp, slashp + 4);
3231 else
3232 return ".";
3234 slashp = cp;
3236 else if (slashp[2] == '/' || slashp[2] == '\0')
3238 strcpy (slashp, slashp + 2);
3241 else
3243 slashp = etags_strchr (slashp + 1, '/');
3247 return res;
3250 /* Return a newly allocated string containing the absolute
3251 filename of dir where FILE resides given CWD (which should
3252 end with a slash). */
3254 char *
3255 absolute_dirname (file, cwd)
3256 char *file, *cwd;
3258 char *slashp, *res;
3259 char save;
3261 slashp = etags_strrchr (file, '/');
3262 if (slashp == NULL)
3263 return cwd;
3264 save = slashp[1];
3265 slashp[1] = '\0';
3266 res = absolute_filename (file, cwd);
3267 slashp[1] = save;
3269 return res;
3272 /* Like malloc but get fatal error if memory is exhausted. */
3274 char *
3275 xmalloc (size)
3276 unsigned int size;
3278 char *result = (char *) malloc (size);
3279 if (result == NULL)
3280 fatal ("virtual memory exhausted", 0);
3281 return result;
3284 char *
3285 xrealloc (ptr, size)
3286 char *ptr;
3287 unsigned int size;
3289 char *result = (char *) realloc (ptr, size);
3290 if (result == NULL)
3291 fatal ("virtual memory exhausted");
3292 return result;