* etags.c (prestr, substr): return a logical type.
[emacs.git] / lib-src / etags.c
blob4db10b343e5817c93bd54ce4cde845f25c689181
1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984,87,88,89,93,94 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 #include <sys/param.h>
36 #endif /* MSDOS */
38 #ifdef HAVE_CONFIG_H
39 #include <../src/config.h>
40 /* On some systems, Emacs defines static as nothing
41 for the sake of unexec. We don't want that here
42 since we don't use unexec. */
43 #undef static
44 #endif
46 #include <stdio.h>
47 #include <ctype.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
51 #if !defined (S_ISREG) && defined (S_IFREG)
52 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
53 #endif
55 #include "getopt.h"
57 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 int string_numeric_p ();
165 logical substr ();
166 logical prestr ();
167 long readline ();
169 void Asm_labels ();
170 void C_entries ();
171 int Fortran_functions ();
172 void Lisp_functions ();
173 void Pascal_functions ();
174 void Prolog_functions ();
175 void Scheme_functions ();
176 void TeX_functions ();
177 void add_node ();
178 void error ();
179 void fatal ();
180 logical find_entries ();
181 void free_tree ();
182 void getit ();
183 void init ();
184 void initbuffer ();
185 void initbuffer ();
186 void pfnote ();
187 void process_file ();
188 void put_entries ();
189 void takeprec ();
192 * MACRO
193 * xnew -- allocate storage
195 * SYNOPSIS
196 * Type *xnew (int n, Type);
198 #define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
201 * Symbol table types.
203 enum sym_type
205 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
210 typedef int LINENO;
212 typedef struct
214 char *p;
215 int len;
216 LINENO lineno;
217 logical named;
218 } TOKEN;
220 /* C extensions.
222 #define C_PLPL 0x00001 /* C++ */
223 #define C_STAR 0x00003 /* C* */
224 #define YACC 0x10000 /* yacc file */
226 char searchar = '/'; /* use /.../ searches */
228 LINENO lineno; /* line number of current line */
229 long charno; /* current character number */
231 long linecharno; /* charno of start of line; not used by C, but
232 * by every other language.
235 char *curfile, /* current input file name */
236 *tagfile, /* output file */
237 *white = " \f\t\n\013", /* white chars */
238 *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
239 /* token starting chars */
240 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
241 /* valid in-token chars */
242 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
244 int append_to_tagfile; /* -a: append to tags */
245 /* The following three default to 1 for etags, but to 0 for ctags. */
246 int typedefs; /* -t: create tags for typedefs */
247 int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
248 /* 0 struct/enum/union decls, and C++ */
249 /* member functions. */
250 int constantypedefs; /* -d: create tags for C #define and enum */
251 /* constants. Enum consts not implemented. */
252 /* -D: opposite of -d. Default under ctags. */
253 int update; /* -u: update tags */
254 int vgrind_style; /* -v: create vgrind style index output */
255 int no_warnings; /* -w: suppress warnings */
256 int cxref_style; /* -x: create cxref style output */
257 int cplusplus; /* .[hc] means C++, not C */
258 int noindentypedefs; /* -S: ignore indentation in C */
260 /* Name this program was invoked with. */
261 char *progname;
263 struct option longopts[] = {
264 { "append", no_argument, NULL, 'a' },
265 { "backward-search", no_argument, NULL, 'B' },
266 { "c++", no_argument, NULL, 'C' },
267 { "cxref", no_argument, NULL, 'x' },
268 { "defines", no_argument, NULL, 'd' },
269 { "help", no_argument, NULL, 'H' },
270 { "ignore-indentation", no_argument, NULL, 'S' },
271 { "include", required_argument, NULL, 'i' },
272 { "no-defines", no_argument, NULL, 'D' },
273 { "no-warn", no_argument, NULL, 'w' },
274 { "output", required_argument, NULL, 'o' },
275 { "typedefs", no_argument, NULL, 't' },
276 { "typedefs-and-c++", no_argument, NULL, 'T' },
277 { "update", no_argument, NULL, 'u' },
278 { "version", no_argument, NULL, 'V' },
279 { "vgrind", no_argument, NULL, 'v' },
280 { 0 }
283 FILE *tagf; /* ioptr for tags file */
284 NODE *head; /* the head of the binary tree of tags */
285 logical permit_duplicates = TRUE; /* allow duplicate tags */
287 /* A `struct linebuffer' is a structure which holds a line of text.
288 `readline' reads a line from a stream into a linebuffer
289 and works regardless of the length of the line. */
291 struct linebuffer
293 long size;
294 char *buffer;
297 struct linebuffer lb; /* the current line */
298 struct linebuffer filename_lb; /* used to read in filenames */
299 struct
301 FILEPOS linepos;
302 struct linebuffer lb; /* used by C_entries instead of lb */
303 } lbs[2];
305 void
306 print_version ()
308 #ifdef VERSION
309 printf ("%s for Emacs version %s.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
310 #else
311 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
312 #endif
314 exit (GOOD);
317 void
318 print_help ()
320 printf ("These are the options accepted by %s. You may use unambiguous\n\
321 abbreviations for the long option names. A - as file name means read file\n\
322 names from stdin.\n\n", progname);
324 puts ("-a, --append\n\
325 Append tag entries to existing tags file.");
327 if (CTAGS)
328 puts ("-B, --backward-search\n\
329 Write the search commands for the tag entries using '?', the\n\
330 backward-search command instead of '/', the forward-search command.");
332 puts ("-C, --c++\n\
333 Treat files with `.c' and `.h' extensions as C++ code, not C\n\
334 code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
335 extensions are always assumed to be C++ code.");
337 if (CTAGS)
338 puts ("-d, --defines\n\
339 Create tag entries for constant C #defines, too.");
340 else
341 puts ("-D, --no-defines\n\
342 Don't create tag entries for constant C #defines. This makes\n\
343 the tags file smaller.");
345 if (!CTAGS)
346 puts ("-i FILE, --include=FILE\n\
347 Include a note in tag file indicating that, when searching for\n\
348 a tag, one should also consult the tags file FILE after\n\
349 checking the current file.");
351 puts ("-o FILE, --output=FILE\n\
352 Write the tags to FILE.");
353 puts ("-S, --ignore-indentation\n\
354 Don't rely on indentation quite as much as normal. Currently,\n\
355 this means not to assume that a closing brace in the first\n\
356 column is the final brace of a function or structure\n\
357 definition in C and C++.");
359 if (CTAGS)
361 puts ("-t, --typedefs\n\
362 Generate tag entries for C typedefs.");
363 puts ("-T, --typedefs-and-c++\n\
364 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
365 and C++ member functions.");
366 puts ("-u, --update\n\
367 Update the tag entries for the given files, leaving tag\n\
368 entries for other files in place. Currently, this is\n\
369 implemented by deleting the existing entries for the given\n\
370 files and then rewriting the new entries at the end of the\n\
371 tags file. It is often faster to simply rebuild the entire\n\
372 tag file than to use this.");
373 puts ("-v, --vgrind\n\
374 Generates an index of items intended for human consumption,\n\
375 similar to the output of vgrind. The index is sorted, and\n\
376 gives the page number of each item.");
377 puts ("-x, --cxref\n\
378 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
379 The output uses line numbers instead of page numbers, but\n\
380 beyond that the differences are cosmetic; try both to see\n\
381 which you like.");
382 puts ("-w, --no-warn\n\
383 Suppress warning messages about entries defined in multiple\n\
384 files.");
387 puts ("-V, --version\n\
388 Print the version of the program.\n\
389 -H, --help\n\
390 Print this help message.");
392 exit (GOOD);
396 void
397 main (argc, argv)
398 int argc;
399 char *argv[];
401 char cmd[100];
402 int i;
403 unsigned int nincluded_files = 0;
404 char **included_files = xnew (argc, char *);
405 char *this_file;
406 #ifdef VMS
407 char got_err;
409 extern char *gfnames ();
410 extern char *massage_name ();
411 #endif
413 #ifdef MSDOS
414 _fmode = O_BINARY; /* all of files are treated as binary files */
415 #endif /* MSDOS */
417 progname = argv[0];
420 * If etags, always find typedefs and structure tags. Why not?
421 * Also default is to find macro constants.
423 if (!CTAGS)
424 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
426 for (;;)
428 int opt;
429 opt = getopt_long (argc, argv, "aCdDf:o:StTi:BuvxwVH", longopts, 0);
431 if (opt == EOF)
432 break;
434 switch (opt)
436 case 0:
437 /* If getopt returns 0, then it has already processed a
438 long-named option. We should do nothing. */
439 break;
441 /* Common options. */
442 case 'a':
443 append_to_tagfile++;
444 break;
445 case 'C':
446 cplusplus = 1;
447 break;
448 case 'd':
449 constantypedefs = 1;
450 break;
451 case 'D':
452 constantypedefs = 0;
453 break;
454 case 'f': /* for compatibility with old makefiles */
455 case 'o':
456 if (tagfile)
458 fprintf(stderr,
459 "%s: -%c flag may only be given once.\n", progname, opt);
460 goto usage;
462 tagfile = optarg;
463 break;
464 case 'S':
465 noindentypedefs++;
466 break;
467 case 'V':
468 print_version ();
469 break;
470 case 'H':
471 print_help ();
472 break;
473 case 't':
474 typedefs++;
475 break;
476 case 'T':
477 typedefs++;
478 typedefs_and_cplusplus++;
479 break;
481 #if (!CTAGS)
483 /* Etags options */
484 case 'i':
485 included_files[nincluded_files++] = optarg;
486 break;
488 #else /* CTAGS */
490 /* Ctags options. */
491 case 'B':
492 searchar = '?';
493 break;
494 case 'u':
495 update++;
496 break;
497 case 'v':
498 vgrind_style++;
499 /*FALLTHRU*/
500 case 'x':
501 cxref_style++;
502 break;
503 case 'w':
504 no_warnings++;
505 break;
507 #endif /* CTAGS */
509 default:
510 fprintf (stderr,
511 "%s: -%c flag not recognised.\n", progname, opt);
512 goto usage;
516 if (optind == argc && nincluded_files == 0)
518 fprintf (stderr, "%s: No input files specified.\n", progname);
520 usage:
521 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
522 progname, progname);
523 exit (BAD);
526 if (tagfile == NULL)
528 tagfile = CTAGS ? "tags" : "TAGS";
530 cwd = etags_getcwd (); /* the current working directory */
531 strcat (cwd, "/");
532 if (streq (tagfile, "-"))
534 tagfiledir = cwd;
536 else
538 tagfiledir = absolute_dirname (tagfile, cwd);
541 init (); /* set up boolean "functions" */
543 initbuffer (&lb);
544 initbuffer (&lbs[0].lb);
545 initbuffer (&lbs[1].lb);
546 initbuffer (&filename_lb);
548 * loop through files finding functions
550 if (!CTAGS)
552 if (streq (tagfile, "-"))
553 tagf = stdout;
554 else
555 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
556 if (tagf == NULL)
558 perror (tagfile);
559 exit (BAD);
563 #ifdef VMS
564 argc -= optind;
565 argv += optind;
566 while (gfnames (&argc, &argv, &got_err) != NULL)
568 if (got_err)
570 error ("Can't find file %s\n", this_file);
571 argc--, argv++;
573 else
575 this_file = massage_name (this_file);
576 #if 0
578 } /* solely to balance out the ifdef'd parens above */
579 #endif
580 #else
581 for (; optind < argc; optind++)
583 this_file = argv[optind];
584 #endif
585 /* Input file named "-" means read file names from stdin and use them. */
586 if (streq (this_file, "-"))
588 while (!feof (stdin))
590 (void) readline (&filename_lb, stdin);
591 if (strlen (filename_lb.buffer) > 0)
592 process_file (filename_lb.buffer);
595 else
596 process_file (this_file);
599 if (!CTAGS)
601 while (nincluded_files-- > 0)
602 fprintf (tagf, "\f\n%s,include\n", *included_files++);
604 (void) fclose (tagf);
605 exit (GOOD);
608 if (cxref_style)
610 put_entries (head);
611 exit (GOOD);
613 if (update)
615 /* update cannot be set under VMS, so we may assume that argc
616 and argv have not been munged. */
617 for (i = optind; i < argc; i++)
619 sprintf (cmd,
620 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
621 tagfile, argv[i], tagfile);
622 (void) system (cmd);
624 append_to_tagfile++;
626 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
627 if (tagf == NULL)
629 perror (tagfile);
630 exit (GOOD);
632 put_entries (head);
633 (void) fclose (tagf);
634 if (update)
636 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
637 (void) system (cmd);
639 exit (GOOD);
644 * This routine is called on each file argument.
646 void
647 process_file (file)
648 char *file;
650 struct stat stat_buf;
652 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
654 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
655 return;
657 if (streq (file, tagfile) && !streq (tagfile, "-"))
659 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
660 return;
662 if (!find_entries (file))
664 return;
666 if (!CTAGS)
668 char *filename;
670 if (file[0] == '/')
672 /* file is an absolute filename. Canonicalise it. */
673 filename = absolute_filename (file, cwd);
675 else
677 /* file is a filename relative to cwd. Make it relative
678 to the directory of the tags file. */
679 filename = relative_filename (file, tagfiledir);
681 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
682 put_entries (head);
683 free_tree (head);
684 head = NULL;
689 * This routine sets up the boolean pseudo-functions which work
690 * by setting boolean flags dependent upon the corresponding character
691 * Every char which is NOT in that string is not a white char. Therefore,
692 * all of the array "_wht" is set to FALSE, and then the elements
693 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
694 * of a char is TRUE if it is the string "white", else FALSE.
696 void
697 init ()
699 register char *sp;
700 register int i;
702 for (i = 0; i < 0177; i++)
703 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
704 for (sp = white; *sp; sp++)
705 _wht[*sp] = TRUE;
706 for (sp = endtk; *sp; sp++)
707 _etk[*sp] = TRUE;
708 for (sp = intk; *sp; sp++)
709 _itk[*sp] = TRUE;
710 for (sp = begtk; *sp; sp++)
711 _btk[*sp] = TRUE;
712 _wht[0] = _wht['\n'];
713 _etk[0] = _etk['\n'];
714 _btk[0] = _btk['\n'];
715 _itk[0] = _itk['\n'];
719 * This routine opens the specified file and calls the function
720 * which finds the function and type definitions.
722 logical
723 find_entries (file)
724 char *file;
726 char *cp, *cp1;
727 FILE *inf;
729 inf = fopen (file, "r");
730 if (inf == NULL)
732 perror (file);
733 return FALSE;
735 curfile = savestr (file);
736 cp = etags_strrchr (file, '.');
737 cp1 = cp + 1;
739 header_file = (cp && (streq (cp1, "h")));
741 /* .tex, .aux or .bbl implies LaTeX source code */
742 if (cp && (streq (cp1, "tex") || streq (cp1, "aux")
743 || streq (cp1, "bbl")))
745 TeX_functions (inf);
746 goto close_and_return;
748 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
749 if (cp && (streq (cp1, "l")
750 || streq (cp1, "el")
751 || streq (cp1, "lsp")
752 || streq (cp1, "lisp")
753 || streq (cp1, "cl")
754 || streq (cp1, "clisp")))
756 Lisp_functions (inf);
757 goto close_and_return;
759 /* .scm or .sm or .scheme or ... implies scheme source code */
760 if (cp && (streq (cp1, "sm")
761 || streq (cp1, "scm")
762 || streq (cp1, "scheme")
763 || streq (cp1, "t")
764 || streq (cp1, "sch")
765 || streq (cp1, "ss")
766 || streq (cp1, "SM")
767 || streq (cp1, "SCM")
768 /* The `SCM' or `scm' prefix with a version number */
769 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's'
770 && string_numeric_p (cp1))
771 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'
772 && string_numeric_p (cp1))))
774 Scheme_functions (inf);
775 goto close_and_return;
777 /* Assembly code */
778 if (cp && (streq (cp1, "s")
779 || streq (cp1, "a") /* Unix assembler */
780 || streq (cp1, "sa") /* Unix assembler */
781 || streq (cp1, "asm") /* Microcontroller assembly */
782 || streq (cp1, "src") /* BSO/Tasking C compiler output */
783 || streq (cp1, "def") /* BSO/Tasking definition includes */
784 || streq (cp1, "ins") /* Microcontroller include files */
785 || streq (cp1, "inc")))/* Microcontroller include files */
787 Asm_labels (inf);
788 goto close_and_return;
790 /* .C or .H or .cxx or .hxx or .cc or .cpp: a C++ file */
791 if (cp && (streq (cp1, "C")
792 || streq (cp1, "H")
793 || streq (cp1, "cpp")
794 || streq (cp1, "cxx")
795 || streq (cp1, "hxx")
796 || streq (cp1, "cc")))
798 C_entries (C_PLPL, inf); /* C++ */
799 goto close_and_return;
801 /* .cs or .hs: a C* file */
802 if (cp && (streq (cp1, "cs")
803 || streq (cp1, "hs")))
805 C_entries (C_STAR, inf);
806 goto close_and_return;
808 /* .y: a yacc file */
809 if (cp && (streq (cp1, "y")))
811 C_entries (YACC, inf);
812 goto close_and_return;
814 /* .pl implies prolog source code */
815 if (cp && streq (cp1, "pl"))
817 Prolog_functions (inf);
818 goto close_and_return;
820 /* .p or .pas: a Pascal file */
821 if (cp && (streq (cp1, "p")
822 || streq (cp1, "pas")))
824 Pascal_functions (inf);
825 goto close_and_return;
827 /* If .f or .for, assume it is fortran or nothing. */
828 if (cp && (streq (cp1, "f")
829 || streq (cp1, "for")))
831 (void) Fortran_functions (inf);
832 goto close_and_return;
834 /* if not a .c or .h or .y file, try fortran */
835 if (cp && ((cp[1] != 'c'
836 && cp[1] != 'h'
837 && cp[1] != 'y')
838 || (cp[1] != 0 && cp[2] != 0)))
840 if (Fortran_functions (inf) != 0)
841 goto close_and_return;
842 rewind (inf); /* no fortran tags found, try C */
844 C_entries (cplusplus ? C_PLPL : 0, inf);
846 close_and_return:
847 (void) fclose (inf);
848 return TRUE;
851 /* Nonzero if string STR is composed of digits. */
854 string_numeric_p (str)
855 char *str;
857 while (*str)
859 if (*str < '0' || *str > '9')
860 return 0;
862 return 1;
865 /* Record a tag. */
866 /* Should take a TOKEN* instead!! */
867 void
868 pfnote (name, is_func, named, linestart, linelen, lno, cno)
869 char *name; /* tag name */
870 logical is_func; /* function or type name? */
871 logical named; /* tag different from text of definition? */
872 char *linestart;
873 int linelen;
874 int lno;
875 long cno;
877 register char *fp;
878 register NODE *np;
879 char tem[51];
880 char c;
882 np = xnew (1, NODE);
883 if (np == NULL)
885 if (CTAGS)
887 /* It's okay to output early in etags -- it only disrupts the
888 * character count of the tag entries, which is no longer used
889 * by tags.el anyway.
891 error ("too many entries to sort", 0);
893 put_entries (head);
894 free_tree (head);
895 head = NULL;
896 np = xnew (1, NODE);
898 /* If ctags mode, change name "main" to M<thisfilename>. */
899 if (CTAGS && !cxref_style && streq (name, "main"))
901 fp = etags_strrchr (curfile, '/');
902 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
903 fp = etags_strrchr (name, '.');
904 if (fp && fp[1] != '\0' && fp[2] == '\0')
905 *fp = 0;
906 named = TRUE;
908 np->name = savestr (name);
909 np->file = curfile;
910 np->is_func = is_func;
911 np->named = named;
912 np->lno = lno;
913 /* UNCOMMENT THE +1 HERE: */
914 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
915 np->left = np->right = 0;
916 if (!CTAGS)
918 c = linestart[linelen];
919 linestart[linelen] = 0;
921 else if (cxref_style == 0)
923 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
924 linestart = tem;
926 np->pat = savestr (linestart);
927 if (!CTAGS)
929 linestart[linelen] = c;
932 add_node (np, &head);
936 * free_tree ()
937 * recurse on left children, iterate on right children.
939 void
940 free_tree (node)
941 register NODE *node;
943 while (node)
945 register NODE *node_right = node->right;
946 free_tree (node->left);
947 free (node->name);
948 free (node->pat);
949 free ((char *) node);
950 node = node_right;
955 * add_node ()
956 * Adds a node to the tree of nodes. In etags mode, we don't keep
957 * it sorted; we just keep a linear list. In ctags mode, maintain
958 * an ordered tree, with no attempt at balancing.
960 * add_node is the only function allowed to add nodes, so it can
961 * maintain state.
963 /* Must avoid static vars within functions since some systems
964 #define static as nothing. */
965 NODE *last_node = NULL;
967 void
968 add_node (node, cur_node_p)
969 NODE *node, **cur_node_p;
971 register int dif;
972 register NODE *cur_node = *cur_node_p;
974 if (cur_node == NULL)
976 *cur_node_p = node;
977 last_node = node;
978 return;
981 if (!CTAGS)
983 /* Etags Mode */
984 if (last_node == NULL)
985 fatal ("internal error in add_node", 0);
986 last_node->right = node;
987 last_node = node;
989 else
991 /* Ctags Mode */
992 dif = strcmp (node->name, cur_node->name);
995 * If this tag name matches an existing one, then
996 * do not add the node, but maybe print a warning.
998 if (!dif)
1000 if (node->file == cur_node->file)
1002 if (!no_warnings)
1004 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1005 node->file, lineno, node->name);
1006 fprintf (stderr, "Second entry ignored\n");
1008 return;
1010 if (!cur_node->been_warned && !no_warnings)
1012 fprintf (stderr,
1013 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1014 node->file, cur_node->file, node->name);
1016 cur_node->been_warned = TRUE;
1017 return;
1020 /* Maybe refuse to add duplicate nodes. */
1021 if (!permit_duplicates)
1023 if (streq (node->name, cur_node->name)
1024 && streq (node->file, cur_node->file))
1025 return;
1028 /* Actually add the node */
1029 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1033 void
1034 put_entries (node)
1035 register NODE *node;
1037 register char *sp;
1039 if (node == NULL)
1040 return;
1042 /* Output subentries that precede this one */
1043 put_entries (node->left);
1045 /* Output this entry */
1047 if (!CTAGS)
1049 if (node->named)
1051 fprintf (tagf, "%s\177%s\001%d,%d\n",
1052 node->pat, node->name,
1053 node->lno, node->cno);
1055 else
1057 fprintf (tagf, "%s\177%d,%d\n",
1058 node->pat,
1059 node->lno, node->cno);
1062 else if (!cxref_style)
1064 fprintf (tagf, "%s\t%s\t",
1065 node->name, node->file);
1067 if (node->is_func)
1068 { /* a function */
1069 putc (searchar, tagf);
1070 putc ('^', tagf);
1072 for (sp = node->pat; *sp; sp++)
1074 if (*sp == '\\' || *sp == searchar)
1075 putc ('\\', tagf);
1076 putc (*sp, tagf);
1078 putc (searchar, tagf);
1080 else
1081 { /* a typedef; text pattern inadequate */
1082 fprintf (tagf, "%d", node->lno);
1084 putc ('\n', tagf);
1086 else if (vgrind_style)
1087 fprintf (stdout, "%s %s %d\n",
1088 node->name, node->file, (node->lno + 63) / 64);
1089 else
1090 fprintf (stdout, "%-16s %3d %-16s %s\n",
1091 node->name, node->lno, node->file, node->pat);
1093 /* Output subentries that follow this one */
1094 put_entries (node->right);
1097 /* Length of a number's decimal representation. */
1099 number_len (num)
1100 long num;
1102 int len = 0;
1103 if (!num)
1104 return 1;
1105 for (; num; num /= 10)
1106 ++len;
1107 return len;
1111 * Return total number of characters that put_entries will output for
1112 * the nodes in the subtree of the specified node. Works only if
1113 * we are not ctags, but called only in that case. This count
1114 * is irrelevant with the new tags.el, but is still supplied for
1115 * backward compatibility.
1118 total_size_of_entries (node)
1119 register NODE *node;
1121 register int total;
1123 if (node == NULL)
1124 return 0;
1126 total = 0;
1127 for (; node; node = node->right)
1129 /* Count left subentries. */
1130 total += total_size_of_entries (node->left);
1132 /* Count this entry */
1133 total += strlen (node->pat) + 1;
1134 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1135 if (node->named)
1136 total += 1 + strlen (node->name); /* \001name */
1139 return total;
1143 * The C symbol tables.
1146 /* Feed stuff between (but not including) %[ and %] lines to:
1147 gperf -c -k1,3 -o -p -r -t
1149 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1151 class, C_PLPL, st_C_struct
1152 domain, C_STAR, st_C_struct
1153 union, 0, st_C_struct
1154 struct, 0, st_C_struct
1155 enum, 0, st_C_enum
1156 typedef, 0, st_C_typedef
1157 define, 0, st_C_define
1158 long, 0, st_C_typespec
1159 short, 0, st_C_typespec
1160 int, 0, st_C_typespec
1161 char, 0, st_C_typespec
1162 float, 0, st_C_typespec
1163 double, 0, st_C_typespec
1164 signed, 0, st_C_typespec
1165 unsigned, 0, st_C_typespec
1166 auto, 0, st_C_typespec
1167 void, 0, st_C_typespec
1168 extern, 0, st_C_typespec
1169 static, 0, st_C_typespec
1170 const, 0, st_C_typespec
1171 volatile, 0, st_C_typespec
1173 and replace lines between %< and %> with its output. */
1174 /*%<*/
1175 /* C code produced by gperf version 1.8.1 (K&R C version) */
1176 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1179 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1181 #define MIN_WORD_LENGTH 3
1182 #define MAX_WORD_LENGTH 8
1183 #define MIN_HASH_VALUE 10
1184 #define MAX_HASH_VALUE 62
1186 21 keywords
1187 53 is the maximum key range
1190 static int
1191 hash (str, len)
1192 register char *str;
1193 register int len;
1195 static unsigned char hash_table[] =
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, 62, 62, 62,
1201 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1202 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1203 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1204 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1205 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1206 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1207 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1208 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1209 62, 62, 62, 62, 62, 62, 62, 62,
1211 return len + hash_table[str[2]] + hash_table[str[0]];
1214 struct C_stab_entry *
1215 in_word_set (str, len)
1216 register char *str;
1217 register int len;
1220 static struct C_stab_entry wordlist[] =
1222 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1223 {"",},
1224 {"volatile", 0, st_C_typespec},
1225 {"",},
1226 {"long", 0, st_C_typespec},
1227 {"char", 0, st_C_typespec},
1228 {"class", C_PLPL, st_C_struct},
1229 {"",}, {"",}, {"",}, {"",},
1230 {"const", 0, st_C_typespec},
1231 {"",}, {"",}, {"",}, {"",},
1232 {"auto", 0, st_C_typespec},
1233 {"",}, {"",},
1234 {"define", 0, st_C_define},
1235 {"",},
1236 {"void", 0, st_C_typespec},
1237 {"",}, {"",}, {"",},
1238 {"extern", 0, st_C_typespec},
1239 {"static", 0, st_C_typespec},
1240 {"",},
1241 {"domain", C_STAR, st_C_struct},
1242 {"",},
1243 {"typedef", 0, st_C_typedef},
1244 {"double", 0, st_C_typespec},
1245 {"enum", 0, st_C_enum},
1246 {"",}, {"",}, {"",}, {"",},
1247 {"int", 0, st_C_typespec},
1248 {"",},
1249 {"float", 0, st_C_typespec},
1250 {"",}, {"",}, {"",},
1251 {"struct", 0, st_C_struct},
1252 {"",}, {"",}, {"",}, {"",},
1253 {"union", 0, st_C_struct},
1254 {"",},
1255 {"short", 0, st_C_typespec},
1256 {"",}, {"",},
1257 {"unsigned", 0, st_C_typespec},
1258 {"signed", 0, st_C_typespec},
1261 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1263 register int key = hash (str, len);
1265 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1267 register char *s = wordlist[key].name;
1269 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1270 return &wordlist[key];
1273 return 0;
1275 /*%>*/
1277 enum sym_type
1278 C_symtype(str, len, c_ext)
1279 char *str;
1280 int len;
1281 int c_ext;
1283 register struct C_stab_entry *se = in_word_set(str, len);
1285 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1286 return st_none;
1287 return se->type;
1291 * C functions are recognized using a simple finite automaton.
1292 * funcdef is its state variable.
1294 typedef enum
1296 fnone, /* nothing seen */
1297 ftagseen, /* function-like tag seen */
1298 fstartlist, /* just after open parenthesis */
1299 finlist, /* in parameter list */
1300 flistseen, /* after parameter list */
1301 fignore /* before open brace */
1302 } FUNCST;
1303 FUNCST funcdef;
1307 * typedefs are recognized using a simple finite automaton.
1308 * typeddef is its state variable.
1310 typedef enum
1312 tnone, /* nothing seen */
1313 ttypedseen, /* typedef keyword seen */
1314 tinbody, /* inside typedef body */
1315 tend, /* just before typedef tag */
1316 tignore /* junk after typedef tag */
1317 } TYPEDST;
1318 TYPEDST typdef;
1322 * struct-like structures (enum, struct and union) are recognized
1323 * using another simple finite automaton. `structdef' is its state
1324 * variable.
1326 typedef enum
1328 snone, /* nothing seen yet */
1329 skeyseen, /* struct-like keyword seen */
1330 stagseen, /* struct-like tag seen */
1331 scolonseen, /* colon seen after struct-like tag */
1332 sinbody /* in struct body: recognize member func defs*/
1333 } STRUCTST;
1334 STRUCTST structdef;
1337 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1338 * struct tag, and structtype is the type of the preceding struct-like
1339 * keyword.
1341 char structtag[BUFSIZ];
1342 enum sym_type structtype;
1345 * Yet another little state machine to deal with preprocessor lines.
1347 typedef enum
1349 dnone, /* nothing seen */
1350 dsharpseen, /* '#' seen as first char on line */
1351 ddefineseen, /* '#' and 'define' seen */
1352 dignorerest /* ignore rest of line */
1353 } DEFINEST;
1354 DEFINEST definedef;
1357 * Set this to TRUE, and the next token considered is called a function.
1358 * Used only for GNUmacs's function-defining macros.
1360 logical next_token_is_func;
1363 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1365 logical yacc_rules;
1368 * consider_token ()
1369 * checks to see if the current token is at the start of a
1370 * function, or corresponds to a typedef, or is a struct/union/enum
1371 * tag.
1373 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1374 * C_EXT is which language we are looking at.
1376 * In the future we will need some way to adjust where the end of
1377 * the token is; for instance, implementing the C++ keyword
1378 * `operator' properly will adjust the end of the token to be after
1379 * whatever follows `operator'.
1381 * Globals
1382 * funcdef IN OUT
1383 * structdef IN OUT
1384 * definedef IN OUT
1385 * typdef IN OUT
1386 * next_token_is_func IN OUT
1389 logical
1390 consider_token (c, tokp, c_ext, cblev, is_func)
1391 register char c; /* IN: first char after the token */
1392 register TOKEN *tokp; /* IN: token pointer */
1393 int c_ext; /* IN: C extensions mask */
1394 int cblev; /* IN: curly brace level */
1395 logical *is_func; /* OUT: function found */
1397 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1400 * Advance the definedef state machine.
1402 switch (definedef)
1404 case dnone:
1405 /* We're not on a preprocessor line. */
1406 break;
1407 case dsharpseen:
1408 if (toktype == st_C_define)
1410 definedef = ddefineseen;
1412 else
1414 definedef = dignorerest;
1416 return (FALSE);
1417 case ddefineseen:
1419 * Make a tag for any macro, unless it is a constant
1420 * and constantypedefs is FALSE.
1422 definedef = dignorerest;
1423 *is_func = (c == '(');
1424 if (!*is_func && !constantypedefs)
1425 return (FALSE);
1426 else
1427 return (TRUE);
1428 case dignorerest:
1429 return (FALSE);
1430 default:
1431 error ("internal error: definedef value.", 0);
1435 * Now typedefs
1437 switch (typdef)
1439 case tnone:
1440 if (toktype == st_C_typedef)
1442 if (typedefs)
1443 typdef = ttypedseen;
1444 funcdef = fnone;
1445 return (FALSE);
1447 break;
1448 case ttypedseen:
1449 switch (toktype)
1451 case st_none:
1452 case st_C_typespec:
1453 typdef = tend;
1454 break;
1455 case st_C_struct:
1456 case st_C_enum:
1457 break;
1459 /* Do not return here, so the structdef stuff has a chance. */
1460 break;
1461 case tend:
1462 switch (toktype)
1464 case st_C_typespec:
1465 case st_C_struct:
1466 case st_C_enum:
1467 return (FALSE);
1469 return (TRUE);
1473 * This structdef business is currently only invoked when cblev==0.
1474 * It should be recursively invoked whatever the curly brace level,
1475 * and a stack of states kept, to allow for definitions of structs
1476 * within structs.
1478 * This structdef business is NOT invoked when we are ctags and the
1479 * file is plain C. This is because a struct tag may have the same
1480 * name as another tag, and this loses with ctags.
1482 * This if statement deals with the typdef state machine as
1483 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1484 * return (FALSE). All the other code here is for the structdef
1485 * state machine.
1487 switch (toktype)
1489 case st_C_struct:
1490 case st_C_enum:
1491 if (typdef == ttypedseen
1492 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1494 structdef = skeyseen;
1495 structtype = toktype;
1497 return (FALSE);
1499 if (structdef == skeyseen)
1501 if (structtype == st_C_struct)
1503 strncpy (structtag, tokp->p, tokp->len);
1504 structtag[tokp->len] = '\0'; /* for struct/union/class */
1506 else
1508 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1510 structdef = stagseen;
1511 return (TRUE);
1514 /* Avoid entering funcdef stuff if typdef is going on. */
1515 if (typdef != tnone)
1517 definedef = dnone;
1518 return (FALSE);
1521 /* Detect GNU macros. */
1522 if (definedef == dnone)
1523 if (strneq (tokp->p, "DEFUN", 5) /* Used in emacs */
1524 #if FALSE
1525 These are defined inside C functions, so currently they
1526 are not met anyway.
1527 || strneq (tokp->p, "EXFUN", 5) /* Used in glibc */
1528 || strneq (tokp->p, "DEFVAR_", 7) /* Used in emacs */
1529 #endif
1530 || strneq (tokp->p, "SYSCALL", 7) /* Used in glibc (mach) */
1531 || strneq (tokp->p, "ENTRY", 5) /* Used in glibc */
1532 || strneq (tokp->p, "PSEUDO", 6)) /* Used in glibc */
1535 next_token_is_func = TRUE;
1536 return (FALSE);
1538 if (next_token_is_func)
1540 next_token_is_func = FALSE;
1541 funcdef = fignore;
1542 *is_func = TRUE;
1543 return (TRUE);
1546 /* A function? */
1547 switch (toktype)
1549 case st_C_typespec:
1550 if (funcdef != finlist && funcdef != fignore)
1551 funcdef = fnone; /* should be useless */
1552 return (FALSE);
1553 default:
1554 if (funcdef == fnone)
1556 funcdef = ftagseen;
1557 *is_func = TRUE;
1558 return (TRUE);
1562 return (FALSE);
1566 * C_entries ()
1567 * This routine finds functions, typedefs, #define's and
1568 * struct/union/enum definitions in C syntax and adds them
1569 * to the list.
1572 #define curlb (lbs[curndx].lb)
1573 #define othlb (lbs[1-curndx].lb)
1574 #define newlb (lbs[newndx].lb)
1575 #define curlinepos (lbs[curndx].linepos)
1576 #define othlinepos (lbs[1-curndx].linepos)
1577 #define newlinepos (lbs[newndx].linepos)
1579 /* Save and restore token state. This is used when preprocessor defines
1580 are handled, to avoid disturbing active function/typedef/struct states. */
1581 #define TOKEN_SAVED_P (savetok.lineno > 0)
1582 #define SAVE_TOKEN (savetok = tok, savetok.p = (char *) tokoff, \
1583 savetok.len = toklen, strcpy(savenameb, nameb))
1584 #define RESTORE_TOKEN (tok = savetok, tokoff = (int) tok.p, \
1585 toklen = tok.len, strcpy(nameb, savenameb), \
1586 savetok.lineno = 0)
1588 #define CNL_SAVE_DEFINEDEF \
1589 do { \
1590 SET_FILEPOS (curlinepos, inf, charno); \
1591 lineno++; \
1592 charno += readline (&curlb, inf); \
1593 lp = curlb.buffer; \
1594 quotednl = FALSE; \
1595 newndx = curndx; \
1596 } while (FALSE)
1598 #define CNL \
1599 do { \
1600 CNL_SAVE_DEFINEDEF; \
1601 if (TOKEN_SAVED_P) \
1602 RESTORE_TOKEN; \
1603 definedef = dnone; \
1604 } while (FALSE)
1606 #define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
1607 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1608 #define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
1609 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
1611 void
1612 C_entries (c_ext, inf)
1613 int c_ext; /* extension of C? */
1614 FILE *inf;
1616 register char c; /* latest char read; '\0' for end of line */
1617 register char *lp; /* pointer one beyond the character `c' */
1618 int curndx, newndx; /* indices for current and new lb */
1619 TOKEN tok; /* latest token read for funcdef & structdef */
1620 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
1621 register int tokoff; /* offset in line of start of latest token */
1622 register int toklen; /* length of latest token */
1623 int cblev; /* current curly brace level */
1624 int parlev; /* current parenthesis level */
1625 logical incomm, inquote, inchar, quotednl, midtoken;
1626 logical cplpl;
1627 TOKEN savetok; /* saved token during preprocessor handling */
1628 char savenameb[BUFSIZ]; /* ouch! */
1630 savetok.lineno = 0;
1631 curndx = newndx = 0;
1632 lineno = 0;
1633 charno = 0;
1634 lp = curlb.buffer;
1635 *lp = 0;
1637 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1638 next_token_is_func = yacc_rules = FALSE;
1639 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1640 cblev = 0;
1641 parlev = 0;
1642 cplpl = c_ext & C_PLPL;
1644 while (!feof (inf))
1646 c = *lp++;
1647 if (c == '\\')
1649 /* If we're at the end of the line, the next character is a
1650 '\0'; don't skip it, because it's the thing that tells us
1651 to read the next line. */
1652 if (*lp == '\0')
1654 quotednl = TRUE;
1655 continue;
1657 lp++;
1658 c = ' ';
1660 else if (incomm)
1662 switch (c)
1664 case '*':
1665 if (*lp == '/')
1667 c = *lp++;
1668 incomm = FALSE;
1670 break;
1671 case '\0':
1672 /* Newlines inside comments do not end macro definitions in
1673 traditional cpp. */
1674 CNL_SAVE_DEFINEDEF;
1675 break;
1677 continue;
1679 else if (inquote)
1681 switch (c)
1683 case '"':
1684 inquote = FALSE;
1685 break;
1686 case '\0':
1687 /* Newlines inside strings do not end macro definitions
1688 in traditional cpp, even though compilers don't
1689 usually accept them. */
1690 CNL_SAVE_DEFINEDEF;
1691 break;
1693 continue;
1695 else if (inchar)
1697 switch (c)
1699 case '\0':
1700 /* Hmmm, something went wrong. */
1701 CNL;
1702 /* FALLTHRU */
1703 case '\'':
1704 inchar = FALSE;
1705 break;
1707 continue;
1709 else
1710 switch (c)
1712 case '"':
1713 inquote = TRUE;
1714 if (funcdef != finlist && funcdef != fignore)
1715 funcdef = fnone;
1716 continue;
1717 case '\'':
1718 inchar = TRUE;
1719 if (funcdef != finlist && funcdef != fignore)
1720 funcdef = fnone;
1721 continue;
1722 case '/':
1723 if (*lp == '*')
1725 lp++;
1726 incomm = TRUE;
1727 continue;
1729 else if (cplpl && *lp == '/')
1731 c = 0;
1732 break;
1734 else
1735 break;
1736 case '%':
1737 if ((c_ext & YACC) && *lp == '%')
1739 /* entering or exiting rules section in yacc file */
1740 lp++;
1741 definedef = dnone; funcdef = fnone;
1742 typdef = tnone; structdef = snone;
1743 next_token_is_func = FALSE;
1744 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1745 cblev = 0;
1746 yacc_rules = !yacc_rules;
1747 continue;
1749 else
1750 break;
1751 case '#':
1752 if (definedef == dnone)
1754 char *cp;
1755 logical cpptoken = TRUE;
1757 /* Look back on this line. If all blanks, or nonblanks
1758 followed by an end of comment, this is a preprocessor
1759 token. */
1760 for (cp = newlb.buffer; cp < lp-1; cp++)
1761 if (!iswhite (*cp))
1763 if (*cp == '*' && *(cp+1) == '/')
1765 cp++;
1766 cpptoken = TRUE;
1768 else
1769 cpptoken = FALSE;
1771 if (cpptoken)
1772 definedef = dsharpseen;
1773 } /* if (definedef == dnone) */
1775 continue;
1776 } /* switch (c) */
1779 /* Consider token only if some complicated conditions are satisfied. */
1780 if ((definedef != dnone
1781 || (cblev == 0 && structdef != scolonseen)
1782 || (cblev == 1 && cplpl && structdef == sinbody))
1783 && typdef != tignore
1784 && definedef != dignorerest
1785 && funcdef != finlist)
1787 if (midtoken)
1789 if (endtoken (c))
1791 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
1794 * This handles :: in the middle, but not at the
1795 * beginning of an identifier.
1797 lp += 2;
1798 toklen += 3;
1800 else
1802 logical is_func = FALSE;
1804 tok.lineno = lineno;
1805 tok.p = newlb.buffer + tokoff;
1806 tok.len = toklen;
1807 tok.named = FALSE;
1808 if (yacc_rules
1809 || consider_token (c, &tok, c_ext, cblev, &is_func))
1811 if (structdef == sinbody
1812 && definedef == dnone
1813 && is_func)
1814 /* function defined in C++ class body */
1816 sprintf (nameb, "%s::%.*s",
1817 ((structtag[0] == '\0')
1818 ? "_anonymous_" : structtag),
1819 tok.len, tok.p);
1820 tok.named = TRUE;
1822 else
1824 sprintf (nameb, "%.*s", tok.len, tok.p);
1827 if (structdef == stagseen
1828 || typdef == tend
1829 || (is_func
1830 && definedef == dignorerest)) /* macro */
1831 tok.named = TRUE;
1833 if (definedef == dnone
1834 && (funcdef == ftagseen
1835 || structdef == stagseen
1836 || typdef == tend))
1838 if (newndx == curndx)
1839 curndx = 1 - curndx; /* switch line buffers */
1841 else
1842 MAKE_TAG_FROM_NEW_LB (is_func);
1844 midtoken = FALSE;
1846 } /* if (endtoken (c)) */
1847 else if (intoken (c))
1849 toklen++;
1850 continue;
1852 } /* if (midtoken) */
1853 else if (begtoken (c))
1855 switch (definedef)
1857 case dnone:
1858 switch (funcdef)
1860 case fstartlist:
1861 funcdef = finlist;
1862 continue;
1863 case flistseen:
1864 MAKE_TAG_FROM_OTH_LB (TRUE);
1865 funcdef = fignore;
1866 break;
1867 case ftagseen:
1868 funcdef = fnone;
1869 break;
1871 if (structdef == stagseen)
1872 structdef = snone;
1873 break;
1874 case dsharpseen:
1875 /* Take a quick peek ahead for a define directive,
1876 so we can avoid saving the token when not absolutely
1877 necessary. [This is a speed hack.] */
1878 if (c == 'd' && strneq (lp, "efine", 5)
1879 && iswhite (*(lp + 5)))
1881 SAVE_TOKEN;
1882 definedef = ddefineseen;
1883 lp += 6;
1885 else
1886 definedef = dignorerest;
1887 continue;
1889 if (!yacc_rules || lp == newlb.buffer + 1)
1891 tokoff = lp - 1 - newlb.buffer;
1892 toklen = 1;
1893 midtoken = TRUE;
1895 continue;
1897 } /* if must look at token */
1900 /* Detect end of line, colon, comma, semicolon and various braces
1901 after having handled a token.*/
1902 switch (c)
1904 case ':':
1905 if (definedef != dnone)
1906 break;
1907 if (structdef == stagseen)
1908 structdef = scolonseen;
1909 else
1910 switch (funcdef)
1912 case ftagseen:
1913 if (yacc_rules)
1915 MAKE_TAG_FROM_OTH_LB (FALSE);
1916 funcdef = fignore;
1918 break;
1919 case fstartlist:
1920 funcdef = fnone;
1921 break;
1923 break;
1924 case ';':
1925 if (definedef != dnone)
1926 break;
1927 if (cblev == 0)
1928 switch (typdef)
1930 case tend:
1931 MAKE_TAG_FROM_OTH_LB (FALSE);
1932 /* FALLTHRU */
1933 default:
1934 typdef = tnone;
1936 if (funcdef != fignore)
1937 funcdef = fnone;
1938 if (structdef == stagseen)
1939 structdef = snone;
1940 break;
1941 case ',':
1942 if (definedef != dnone)
1943 break;
1944 if (funcdef != finlist && funcdef != fignore)
1945 funcdef = fnone;
1946 if (structdef == stagseen)
1947 structdef = snone;
1948 break;
1949 case '[':
1950 if (definedef != dnone)
1951 break;
1952 if (cblev == 0 && typdef == tend)
1954 typdef = tignore;
1955 MAKE_TAG_FROM_OTH_LB (FALSE);
1956 break;
1958 if (funcdef != finlist && funcdef != fignore)
1959 funcdef = fnone;
1960 if (structdef == stagseen)
1961 structdef = snone;
1962 break;
1963 case '(':
1964 if (definedef != dnone)
1965 break;
1966 switch (funcdef)
1968 case fnone:
1969 switch (typdef)
1971 case ttypedseen:
1972 case tend:
1973 /* Make sure that the next char is not a '*'.
1974 This handles constructs like:
1975 typedef void OperatorFun (int fun); */
1976 if (*lp != '*')
1978 typdef = tignore;
1979 MAKE_TAG_FROM_OTH_LB (FALSE);
1981 break;
1982 } /* switch (typdef) */
1983 break;
1984 case ftagseen:
1985 funcdef = fstartlist;
1986 break;
1987 case flistseen:
1988 funcdef = finlist;
1989 break;
1991 parlev++;
1992 break;
1993 case ')':
1994 if (definedef != dnone)
1995 break;
1996 if (--parlev == 0)
1998 switch (funcdef)
2000 case fstartlist:
2001 case finlist:
2002 funcdef = flistseen;
2003 break;
2005 if (cblev == 0 && typdef == tend)
2007 typdef = tignore;
2008 MAKE_TAG_FROM_OTH_LB (FALSE);
2011 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2012 parlev = 0;
2013 break;
2014 case '{':
2015 if (definedef != dnone)
2016 break;
2017 if (typdef == ttypedseen)
2018 typdef = tinbody;
2019 switch (structdef)
2021 case skeyseen: /* unnamed struct */
2022 structtag[0] = '\0';
2023 structdef = sinbody;
2024 break;
2025 case stagseen:
2026 case scolonseen: /* named struct */
2027 structdef = sinbody;
2028 MAKE_TAG_FROM_OTH_LB (FALSE);
2029 break;
2031 switch (funcdef)
2033 case flistseen:
2034 MAKE_TAG_FROM_OTH_LB (TRUE);
2035 /* FALLTHRU */
2036 case fignore:
2037 funcdef = fnone;
2038 break;
2039 case fnone:
2040 /* Neutralize `extern "C" {' grot and look inside structs. */
2041 if (cblev == 0 && structdef == snone && typdef == tnone)
2042 cblev = -1;
2044 cblev++;
2045 break;
2046 case '*':
2047 if (definedef != dnone)
2048 break;
2049 if (funcdef == fstartlist)
2050 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
2051 break;
2052 case '}':
2053 if (definedef != dnone)
2054 break;
2055 if (!noindentypedefs && lp == newlb.buffer + 1)
2057 cblev = 0; /* reset curly brace level if first column */
2058 parlev = 0; /* also reset paren level, just in case... */
2060 else if (cblev > 0)
2061 cblev--;
2062 if (cblev == 0)
2064 if (typdef == tinbody)
2065 typdef = tend;
2066 structdef = snone;
2067 strcpy (structtag, "<error 2>");
2069 break;
2070 case '=':
2071 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2072 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
2073 if (definedef != dnone)
2074 break;
2075 /* These surely cannot follow a function tag. */
2076 if (funcdef != finlist && funcdef != fignore)
2077 funcdef = fnone;
2078 break;
2079 case '\0':
2080 /* If a macro spans multiple lines don't reset its state. */
2081 if (quotednl)
2082 CNL_SAVE_DEFINEDEF;
2083 else
2084 CNL;
2085 break;
2086 } /* switch (c) */
2088 } /* while not eof */
2091 /* Fortran parsing */
2093 char *dbp;
2094 int pfcnt;
2096 logical
2097 tail (cp)
2098 char *cp;
2100 register int len = 0;
2102 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2103 cp++, len++;
2104 if (*cp == 0)
2106 dbp += len;
2107 return (TRUE);
2109 return (FALSE);
2112 void
2113 takeprec ()
2115 while (isspace (*dbp))
2116 dbp++;
2117 if (*dbp != '*')
2118 return;
2119 dbp++;
2120 while (isspace (*dbp))
2121 dbp++;
2122 if (tail ("(*)"))
2123 return;
2124 if (!isdigit (*dbp))
2126 --dbp; /* force failure */
2127 return;
2130 dbp++;
2131 while (isdigit (*dbp));
2134 void
2135 getit (inf)
2136 FILE *inf;
2138 register char *cp;
2139 char c;
2140 char nambuf[BUFSIZ];
2142 while (isspace (*dbp))
2143 dbp++;
2144 if (*dbp == '\0')
2146 lineno++;
2147 linecharno = charno;
2148 charno += readline (&lb, inf);
2149 dbp = lb.buffer;
2150 if (dbp[5] != '&')
2151 return;
2152 dbp += 6;
2153 while (isspace (*dbp))
2154 dbp++;
2156 if (!isalpha (*dbp)
2157 && *dbp != '_'
2158 && *dbp != '$')
2159 return;
2160 for (cp = dbp + 1;
2161 (*cp
2162 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2163 cp++)
2164 continue;
2165 c = *cp;
2166 *cp = '\0';
2167 strcpy (nambuf, dbp);
2168 *cp = c;
2169 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2170 cp - lb.buffer + 1, lineno, linecharno);
2171 pfcnt++;
2175 Fortran_functions (inf)
2176 FILE *inf;
2178 lineno = 0;
2179 charno = 0;
2180 pfcnt = 0;
2182 while (!feof (inf))
2184 lineno++;
2185 linecharno = charno;
2186 charno += readline (&lb, inf);
2187 dbp = lb.buffer;
2188 if (*dbp == '%')
2189 dbp++; /* Ratfor escape to fortran */
2190 while (isspace (*dbp))
2191 dbp++;
2192 if (*dbp == 0)
2193 continue;
2194 switch (*dbp | ' ')
2196 case 'i':
2197 if (tail ("integer"))
2198 takeprec ();
2199 break;
2200 case 'r':
2201 if (tail ("real"))
2202 takeprec ();
2203 break;
2204 case 'l':
2205 if (tail ("logical"))
2206 takeprec ();
2207 break;
2208 case 'c':
2209 if (tail ("complex") || tail ("character"))
2210 takeprec ();
2211 break;
2212 case 'd':
2213 if (tail ("double"))
2215 while (isspace (*dbp))
2216 dbp++;
2217 if (*dbp == 0)
2218 continue;
2219 if (tail ("precision"))
2220 break;
2221 continue;
2223 break;
2225 while (isspace (*dbp))
2226 dbp++;
2227 if (*dbp == 0)
2228 continue;
2229 switch (*dbp | ' ')
2231 case 'f':
2232 if (tail ("function"))
2233 getit (inf);
2234 continue;
2235 case 's':
2236 if (tail ("subroutine"))
2237 getit (inf);
2238 continue;
2239 case 'e':
2240 if (tail ("entry"))
2241 getit (inf);
2242 continue;
2243 case 'p':
2244 if (tail ("program"))
2246 getit (inf);
2247 continue;
2249 if (tail ("procedure"))
2250 getit (inf);
2251 continue;
2254 return (pfcnt);
2258 * Bob Weiner, Motorola Inc., 4/3/94
2259 * Unix and microcontroller assembly tag handling
2260 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2262 void
2263 Asm_labels (inf)
2264 FILE *inf;
2266 char nambuf[BUFSIZ];
2267 register char *cp;
2268 char c;
2270 lineno = 0;
2271 charno = 0;
2272 pfcnt = 0;
2274 while (!feof (inf))
2276 lineno++;
2277 linecharno = charno;
2278 charno += readline (&lb, inf);
2279 cp = lb.buffer;
2281 /* If first char is alphabetic or one of [_.$], test for colon
2282 following identifier. */
2283 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2285 /* Read past label. */
2286 cp++;
2287 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2288 cp++;
2289 if (*cp == ':' || isspace (*cp))
2291 /* Found end of label, so copy it and add it to the table. */
2292 c = *cp;
2293 *cp = '\0';
2294 strcpy (nambuf, lb.buffer);
2295 *cp = c;
2296 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2297 cp - lb.buffer + 1, lineno, linecharno);
2298 pfcnt++;
2304 /* Added by Mosur Mohan, 4/22/88 */
2305 /* Pascal parsing */
2307 #define GET_NEW_LINE \
2309 linecharno = charno; lineno++; \
2310 charno += 1 + readline (&lb, inf); \
2311 dbp = lb.buffer; \
2314 /* Locates tags for procedures & functions.
2315 * Doesn't do any type- or var-definitions.
2316 * It does look for the keyword "extern" or "forward"
2317 * immediately following the procedure statement;
2318 * if found, the tag is skipped.
2321 void
2322 Pascal_functions (inf)
2323 FILE *inf;
2325 struct linebuffer tline; /* mostly copied from C_entries */
2326 long save_lcno;
2327 int save_lineno;
2328 char c, *cp;
2329 char nambuf[BUFSIZ];
2331 logical /* each of these flags is TRUE iff: */
2332 incomm1, /* point is inside {..} comment */
2333 incomm2, /* point is inside (*..*) comment */
2334 inquote, /* point is inside '..' string */
2335 get_tagname, /* point is after PROCEDURE/FUNCTION */
2336 /* keyword, so next item = potential tag */
2337 found_tag, /* point is after a potential tag */
2338 inparms, /* point is within parameter-list */
2339 verify_tag; /* point has passed the parm-list, so the */
2340 /* next token will determine whether */
2341 /* this is a FORWARD/EXTERN to be */
2342 /* ignored, or whether it is a real tag */
2344 lineno = 0;
2345 charno = 0;
2346 dbp = lb.buffer;
2347 *dbp = 0;
2348 initbuffer (&tline);
2350 incomm1 = incomm2 = inquote = FALSE;
2351 found_tag = FALSE; /* have a proc name; check if extern */
2352 get_tagname = FALSE; /* have found "procedure" keyword */
2353 inparms = FALSE; /* found '(' after "proc" */
2354 verify_tag = FALSE; /* check if "extern" is ahead */
2356 /* long main loop to get next char */
2357 while (!feof (inf))
2359 c = *dbp++;
2360 if (c == 0) /* if end of line */
2362 GET_NEW_LINE;
2363 if (*dbp == 0)
2364 continue;
2365 if (!((found_tag && verify_tag) ||
2366 get_tagname))
2367 c = *dbp++; /* only if don't need *dbp pointing */
2368 /* to the beginning of the name of */
2369 /* the procedure or function */
2371 if (incomm1) /* within { - } comments */
2373 if (c == '}')
2374 incomm1 = FALSE;
2375 continue;
2377 else if (incomm2) /* within (* - *) comments */
2379 if (c == '*')
2381 while ((c = *dbp++) == '*')
2382 continue;
2383 if (c == 0)
2384 GET_NEW_LINE;
2385 if (c == ')')
2386 incomm2 = FALSE;
2388 continue;
2390 else if (inquote)
2392 if (c == '\'')
2393 inquote = FALSE;
2394 continue;
2396 else
2397 switch (c)
2399 case '\'':
2400 inquote = TRUE; /* found first quote */
2401 continue;
2402 case '{': /* found open-{-comment */
2403 incomm1 = TRUE;
2404 continue;
2405 case '(':
2406 if (*dbp == '*') /* found open-(*-comment */
2408 incomm2 = TRUE;
2409 dbp++;
2411 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2412 inparms = TRUE;
2413 continue;
2414 case ')': /* end of parms list */
2415 if (inparms)
2416 inparms = FALSE;
2417 continue;
2418 case ';':
2419 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2421 verify_tag = TRUE;
2422 break;
2424 continue;
2426 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2428 /* check if this is an "extern" declaration */
2429 if (*dbp == 0)
2430 continue;
2431 if ((*dbp == 'e') || (*dbp == 'E'))
2433 if (tail ("extern")) /* superfluous, really! */
2435 found_tag = FALSE;
2436 verify_tag = FALSE;
2439 else if ((*dbp == 'f') || (*dbp == 'F'))
2441 if (tail ("forward")) /* check for forward reference */
2443 found_tag = FALSE;
2444 verify_tag = FALSE;
2447 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2449 found_tag = FALSE;
2450 verify_tag = FALSE;
2451 pfnote (nambuf, TRUE, FALSE,
2452 tline.buffer, cp - tline.buffer + 1,
2453 save_lineno, save_lcno);
2454 continue;
2457 if (get_tagname) /* grab name of proc or fn */
2459 if (*dbp == 0)
2460 continue;
2462 /* save all values for later tagging */
2463 tline.size = lb.size;
2464 strcpy (tline.buffer, lb.buffer);
2465 save_lineno = lineno;
2466 save_lcno = linecharno;
2468 /* grab block name */
2469 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2470 continue;
2471 c = cp[0];
2472 cp[0] = 0;
2473 strcpy (nambuf, dbp);
2474 cp[0] = c;
2475 dbp = cp; /* restore dbp to e-o-token */
2476 get_tagname = FALSE;
2477 found_tag = TRUE;
2478 continue;
2480 /* and proceed to check for "extern" */
2482 if ((!incomm1) && (!incomm2) && (!inquote) &&
2483 (!found_tag) && (!get_tagname))
2485 /* check for proc/fn keywords */
2486 switch (c | ' ')
2488 case 'p':
2489 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2490 get_tagname = TRUE;
2491 continue;
2492 case 'f':
2493 if (tail ("unction"))
2494 get_tagname = TRUE;
2495 continue;
2498 } /* while not eof */
2502 * lisp tag functions
2503 * just look for (def or (DEF
2507 L_isdef (dbp)
2508 register char *dbp;
2510 return ((dbp[1] == 'd' || dbp[1] == 'D')
2511 && (dbp[2] == 'e' || dbp[2] == 'E')
2512 && (dbp[3] == 'f' || dbp[3] == 'F'));
2516 L_isquote (dbp)
2517 register char *dbp;
2519 return ((*(++dbp) == 'q' || *dbp == 'Q')
2520 && (*(++dbp) == 'u' || *dbp == 'U')
2521 && (*(++dbp) == 'o' || *dbp == 'O')
2522 && (*(++dbp) == 't' || *dbp == 'T')
2523 && (*(++dbp) == 'e' || *dbp == 'E')
2524 && isspace(*(++dbp)));
2527 void
2528 L_getit ()
2530 register char *cp;
2531 char c;
2532 char nambuf[BUFSIZ];
2534 if (*dbp == '\'') /* Skip prefix quote */
2535 dbp++;
2536 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2538 dbp += 7;
2539 while (isspace(*dbp))
2540 dbp++;
2542 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
2543 continue;
2544 if (cp == dbp)
2545 return;
2547 c = cp[0];
2548 cp[0] = 0;
2549 strcpy (nambuf, dbp);
2550 cp[0] = c;
2551 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2552 cp - lb.buffer + 1, lineno, linecharno);
2553 pfcnt++;
2556 void
2557 Lisp_functions (inf)
2558 FILE *inf;
2560 lineno = 0;
2561 charno = 0;
2562 pfcnt = 0;
2564 while (!feof (inf))
2566 lineno++;
2567 linecharno = charno;
2568 charno += readline (&lb, inf);
2569 dbp = lb.buffer;
2570 if (dbp[0] == '(')
2572 if (L_isdef (dbp))
2574 while (!isspace (*dbp))
2575 dbp++;
2576 while (isspace (*dbp))
2577 dbp++;
2578 L_getit ();
2580 else
2582 /* Check for (foo::defmumble name-defined ... */
2584 dbp++;
2585 while (*dbp && !isspace (*dbp)
2586 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2587 if (*dbp == ':')
2590 dbp++;
2591 while (*dbp == ':');
2593 if (L_isdef (dbp - 1))
2595 while (!isspace (*dbp))
2596 dbp++;
2597 while (isspace (*dbp))
2598 dbp++;
2599 L_getit ();
2608 * Scheme tag functions
2609 * look for (def... xyzzy
2610 * look for (def... (xyzzy
2611 * look for (def ... ((...(xyzzy ....
2612 * look for (set! xyzzy
2615 void get_scheme ();
2617 void
2618 Scheme_functions (inf)
2619 FILE *inf;
2621 lineno = 0;
2622 charno = 0;
2623 pfcnt = 0;
2625 while (!feof (inf))
2627 lineno++;
2628 linecharno = charno;
2629 charno += readline (&lb, inf);
2630 dbp = lb.buffer;
2631 if (dbp[0] == '(' &&
2632 (dbp[1] == 'D' || dbp[1] == 'd') &&
2633 (dbp[2] == 'E' || dbp[2] == 'e') &&
2634 (dbp[3] == 'F' || dbp[3] == 'f'))
2636 while (!isspace (*dbp))
2637 dbp++;
2638 /* Skip over open parens and white space */
2639 while (*dbp && (isspace (*dbp) || *dbp == '('))
2640 dbp++;
2641 get_scheme ();
2643 if (dbp[0] == '(' &&
2644 (dbp[1] == 'S' || dbp[1] == 's') &&
2645 (dbp[2] == 'E' || dbp[2] == 'e') &&
2646 (dbp[3] == 'T' || dbp[3] == 't') &&
2647 (dbp[4] == '!' || dbp[4] == '!') &&
2648 (isspace (dbp[5])))
2650 while (!isspace (*dbp))
2651 dbp++;
2652 /* Skip over white space */
2653 while (isspace (*dbp))
2654 dbp++;
2655 get_scheme ();
2660 void
2661 get_scheme ()
2663 register char *cp;
2664 char c;
2665 char nambuf[BUFSIZ];
2667 if (*dbp == 0)
2668 return;
2669 /* Go till you get to white space or a syntactic break */
2670 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2671 continue;
2672 /* Null terminate the string there. */
2673 c = cp[0];
2674 cp[0] = 0;
2675 /* Copy the string */
2676 strcpy (nambuf, dbp);
2677 /* Unterminate the string */
2678 cp[0] = c;
2679 /* Announce the change */
2680 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2681 pfcnt++;
2684 /* Find tags in TeX and LaTeX input files. */
2686 /* TEX_toktab is a table of TeX control sequences that define tags.
2687 Each TEX_tabent records one such control sequence.
2688 CONVERT THIS TO USE THE Stab TYPE!! */
2690 struct TEX_tabent
2692 char *name;
2693 int len;
2696 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2698 /* Default set of control sequences to put into TEX_toktab.
2699 The value of environment var TEXTAGS is prepended to this. */
2701 char *TEX_defenv = "\
2702 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2704 void TEX_mode ();
2705 struct TEX_tabent *TEX_decode_env ();
2706 void TEX_getit ();
2707 int TEX_Token ();
2709 char TEX_esc = '\\';
2710 char TEX_opgrp = '{';
2711 char TEX_clgrp = '}';
2714 * TeX/LaTeX scanning loop.
2717 void
2718 TeX_functions (inf)
2719 FILE *inf;
2721 char *lasthit;
2723 lineno = 0;
2724 charno = 0;
2725 pfcnt = 0;
2727 /* Select either \ or ! as escape character. */
2728 TEX_mode (inf);
2730 /* Initialize token table once from environment. */
2731 if (!TEX_toktab)
2732 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2734 while (!feof (inf))
2735 { /* Scan each line in file */
2736 lineno++;
2737 linecharno = charno;
2738 charno += readline (&lb, inf);
2739 dbp = lb.buffer;
2740 lasthit = dbp;
2741 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
2743 register int i;
2745 if (!*(++dbp))
2746 break;
2747 linecharno += dbp - lasthit;
2748 lasthit = dbp;
2749 i = TEX_Token (lasthit);
2750 if (0 <= i)
2752 TEX_getit (lasthit, TEX_toktab[i].len);
2753 break; /* We only save a line once */
2759 #define TEX_LESC '\\'
2760 #define TEX_SESC '!'
2761 #define TEX_cmt '%'
2763 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2764 /* chars accordingly. */
2766 void
2767 TEX_mode (inf)
2768 FILE *inf;
2770 int c;
2772 while ((c = getc (inf)) != EOF)
2774 /* Skip to next line if we hit the TeX comment char. */
2775 if (c == TEX_cmt)
2776 while (c != '\n')
2777 c = getc (inf);
2778 else if (c == TEX_LESC || c == TEX_SESC )
2779 break;
2782 if (c == TEX_LESC)
2784 TEX_esc = TEX_LESC;
2785 TEX_opgrp = '{';
2786 TEX_clgrp = '}';
2788 else
2790 TEX_esc = TEX_SESC;
2791 TEX_opgrp = '<';
2792 TEX_clgrp = '>';
2794 rewind (inf);
2797 /* Read environment and prepend it to the default string. */
2798 /* Build token table. */
2800 struct TEX_tabent *
2801 TEX_decode_env (evarname, defenv)
2802 char *evarname;
2803 char *defenv;
2805 register char *env, *p;
2807 struct TEX_tabent *tab;
2808 int size, i;
2810 /* Append default string to environment. */
2811 env = getenv (evarname);
2812 if (!env)
2813 env = defenv;
2814 else
2815 env = concat (env, defenv, "");
2817 /* Allocate a token table */
2818 for (size = 1, p = env; p;)
2819 if ((p = etags_strchr (p, ':')) && *(++p))
2820 size++;
2821 /* Add 1 to leave room for null terminator. */
2822 tab = xnew (size + 1, struct TEX_tabent);
2824 /* Unpack environment string into token table. Be careful about */
2825 /* zero-length strings (leading ':', "::" and trailing ':') */
2826 for (i = 0; *env;)
2828 p = etags_strchr (env, ':');
2829 if (!p) /* End of environment string. */
2830 p = env + strlen (env);
2831 if (p - env > 0)
2832 { /* Only non-zero strings. */
2833 tab[i].name = savenstr (env, p - env);
2834 tab[i].len = strlen (tab[i].name);
2835 i++;
2837 if (*p)
2838 env = p + 1;
2839 else
2841 tab[i].name = NULL; /* Mark end of table. */
2842 tab[i].len = 0;
2843 break;
2846 return tab;
2849 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
2850 The name being defined actually starts at (NAME + LEN + 1).
2851 But we seem to include the TeX command in the tag name. */
2853 void
2854 TEX_getit (name, len)
2855 char *name;
2856 int len;
2858 char *p = name + len;
2859 char nambuf[BUFSIZ];
2861 if (*name == 0)
2862 return;
2864 /* Let tag name extend to next group close (or end of line) */
2865 while (*p && *p != TEX_clgrp)
2866 p++;
2867 strncpy (nambuf, name, p - name);
2868 nambuf[p - name] = 0;
2870 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2871 pfcnt++;
2874 /* If the text at CP matches one of the tag-defining TeX command names,
2875 return the pointer to the first occurrence of that command in TEX_toktab.
2876 Otherwise return -1. */
2878 /* Keep the capital `T' in `Token' for dumb truncating compilers
2879 (this distinguishes it from `TEX_toktab' */
2881 TEX_Token (cp)
2882 char *cp;
2884 int i;
2886 for (i = 0; TEX_toktab[i].len > 0; i++)
2887 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
2888 return i;
2889 return -1;
2892 /* Support for Prolog. */
2894 /* whole head (not only functor, but also arguments)
2895 is gotten in compound term. */
2897 void
2898 prolog_getit (s, lineno, linecharno)
2899 char *s;
2900 int lineno;
2901 long linecharno;
2903 char nambuf[BUFSIZ], *save_s, tmpc;
2904 int insquote, npar;
2906 save_s = s;
2907 insquote = FALSE;
2908 npar = 0;
2909 while (1)
2911 if (*s == '\0') /* syntax error. */
2912 return;
2913 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2914 s += 2;
2915 else if (*s == '\'')
2917 insquote = !insquote;
2918 s++;
2920 else if (!insquote && *s == '(')
2922 npar++;
2923 s++;
2925 else if (!insquote && *s == ')')
2927 npar--;
2928 s++;
2929 if (npar == 0)
2930 break;
2931 else if (npar < 0) /* syntax error. */
2932 return;
2934 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2935 { /* fullstop. */
2936 if (npar != 0) /* syntax error. */
2937 return;
2938 s++;
2939 break;
2941 else
2942 s++;
2944 tmpc = *s;
2945 *s = '\0';
2946 strcpy (nambuf, save_s);
2947 *s = tmpc;
2948 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
2951 /* It is assumed that prolog predicate starts from column 0. */
2953 void
2954 Prolog_functions (inf)
2955 FILE *inf;
2957 void skip_comment (), prolog_getit ();
2959 lineno = linecharno = charno = 0;
2960 while (!feof (inf))
2962 lineno++;
2963 linecharno += charno;
2964 charno = readline (&lb, inf) + 1; /* 1 for newline. */
2965 dbp = lb.buffer;
2966 if (isspace (dbp[0])) /* not predicate header. */
2967 continue;
2968 else if (dbp[0] == '%') /* comment. */
2969 continue;
2970 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2971 skip_comment (&lb, inf, &lineno, &linecharno);
2972 else /* found. */
2973 prolog_getit (dbp, lineno, linecharno);
2977 void
2978 skip_comment (plb, inf, plineno, plinecharno)
2979 struct linebuffer *plb;
2980 FILE *inf;
2981 int *plineno; /* result */
2982 long *plinecharno; /* result */
2984 while (!substr ("*/", plb->buffer))
2986 (*plineno)++;
2987 *plinecharno += readline (plb, inf) + 1;
2988 } /* 1 for newline. */
2991 /* Return TRUE if 'sub' exists somewhere in 's'. */
2993 logical
2994 substr (sub, s)
2995 char *sub;
2996 char *s;
2998 while (*s && (s = etags_strchr (s, *sub)))
2999 if (prestr (sub, s))
3000 return (TRUE);
3001 else
3002 s++;
3003 return (FALSE);
3006 /* Return TRUE if 'pre' is prefix of string 's'. */
3008 logical
3009 prestr (pre, s)
3010 char *pre;
3011 char *s;
3013 if (*pre == '\0')
3014 return (TRUE);
3015 else if (*pre == *s)
3016 return (prestr (pre + 1, s + 1));
3017 else
3018 return (FALSE);
3021 /* Initialize a linebuffer for use */
3023 void
3024 initbuffer (linebuffer)
3025 struct linebuffer *linebuffer;
3027 linebuffer->size = 200;
3028 linebuffer->buffer = xnew (200, char);
3032 * Read a line of text from `stream' into `linebuffer'.
3033 * Return the number of characters read from `stream',
3034 * which is the length of the line including the newline, if any.
3036 long
3037 readline (linebuffer, stream)
3038 struct linebuffer *linebuffer;
3039 register FILE *stream;
3041 char *buffer = linebuffer->buffer;
3042 register char *p = linebuffer->buffer;
3043 register char *pend;
3044 int newline; /* 1 if ended with newline, 0 if ended with EOF */
3046 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
3048 while (1)
3050 register int c = getc (stream);
3051 if (p == pend)
3053 linebuffer->size *= 2;
3054 buffer = (char *) xrealloc (buffer, linebuffer->size);
3055 p += buffer - linebuffer->buffer;
3056 pend = buffer + linebuffer->size;
3057 linebuffer->buffer = buffer;
3059 if (c == EOF || c == '\n')
3061 *p = 0;
3062 newline = (c == '\n') ? 1 : 0;
3063 break;
3065 *p++ = c;
3068 return p - buffer + newline;
3071 char *
3072 savestr (cp)
3073 char *cp;
3075 return savenstr (cp, strlen (cp));
3078 char *
3079 savenstr (cp, len)
3080 char *cp;
3081 int len;
3083 register char *dp;
3085 dp = xnew (len + 1, char);
3086 strncpy (dp, cp, len);
3087 dp[len] = '\0';
3088 return dp;
3092 * Return the ptr in sp at which the character c last
3093 * appears; NULL if not found
3095 * Identical to System V strrchr, included for portability.
3098 char *
3099 etags_strrchr (sp, c)
3100 register char *sp, c;
3102 register char *r;
3104 r = NULL;
3107 if (*sp == c)
3108 r = sp;
3109 } while (*sp++);
3110 return (r);
3115 * Return the ptr in sp at which the character c first
3116 * appears; NULL if not found
3118 * Identical to System V strchr, included for portability.
3121 char *
3122 etags_strchr (sp, c)
3123 register char *sp, c;
3127 if (*sp == c)
3128 return (sp);
3129 } while (*sp++);
3130 return (NULL);
3133 /* Print error message and exit. */
3135 /* VARARGS1 */
3136 void
3137 fatal (s1, s2)
3138 char *s1, *s2;
3140 error (s1, s2);
3141 exit (BAD);
3144 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3146 /* VARARGS1 */
3147 void
3148 error (s1, s2)
3149 char *s1, *s2;
3151 fprintf (stderr, "%s: ", progname);
3152 fprintf (stderr, s1, s2);
3153 fprintf (stderr, "\n");
3156 /* Return a newly-allocated string whose contents
3157 concatenate those of s1, s2, s3. */
3159 char *
3160 concat (s1, s2, s3)
3161 char *s1, *s2, *s3;
3163 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3164 char *result = xnew (len1 + len2 + len3 + 1, char);
3166 strcpy (result, s1);
3167 strcpy (result + len1, s2);
3168 strcpy (result + len1 + len2, s3);
3169 result[len1 + len2 + len3] = '\0';
3171 return result;
3174 #ifdef MSDOS
3175 char *
3176 etags_getcwd ()
3178 char *p, cwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3179 getwd (cwd);
3180 p = cwd;
3181 while (*p)
3182 if (*p == '\\')
3183 *p++ = '/';
3184 else
3185 *p++ = tolower (*p);
3186 return strdup (cwd);
3188 #else /* not MSDOS */
3189 /* Does the same work as the system V getcwd, but does not need to
3190 guess buffer size in advance. Included mostly for compatibility. */
3191 char *
3192 etags_getcwd ()
3194 char *buf;
3195 int bufsize = 256;
3197 #ifdef HAVE_GETCWD
3200 buf = xnew (bufsize, char);
3201 bufsize *= 2;
3203 while (getcwd (buf, bufsize / 2) == NULL);
3204 #else
3207 FILE *pipe;
3208 buf = xnew (bufsize, char);
3210 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
3211 if (pipe == NULL)
3213 perror ("pwd");
3214 exit (BAD);
3216 if (fgets (buf, bufsize, pipe) == NULL)
3218 perror ("pwd");
3219 exit (BAD);
3221 pclose (pipe);
3223 bufsize *= 2;
3225 } while (buf[strlen (buf) - 1] != '\n');
3226 #endif
3228 buf[strlen (buf) - 1] = '\0';
3229 return buf;
3231 #endif /* not MSDOS */
3233 /* Return a newly allocated string containing the filename
3234 of FILE relative to the absolute directory DIR (which
3235 should end with a slash). */
3237 char *
3238 relative_filename (file, dir)
3239 char *file, *dir;
3241 char *fp, *dp, *res;
3243 /* Find the common root of file and dir. */
3244 fp = absolute_filename (file, cwd);
3245 dp = dir;
3246 while (*fp++ == *dp++)
3247 continue;
3250 fp--;
3251 dp--;
3253 while (*fp != '/');
3255 /* Build a sequence of "../" strings for the resulting relative filename. */
3256 for (dp = etags_strchr (dp + 1, '/'), res = "";
3257 dp != NULL;
3258 dp = etags_strchr (dp + 1, '/'))
3260 res = concat (res, "../", "");
3263 /* Add the filename relative to the common root of file and dir. */
3264 res = concat (res, fp + 1, "");
3266 return res; /* temporary stub */
3269 /* Return a newly allocated string containing the
3270 absolute filename of FILE given CWD (which should
3271 end with a slash). */
3273 char *
3274 absolute_filename (file, cwd)
3275 char *file, *cwd;
3277 char *slashp, *cp, *res;
3279 if (file[0] == '/')
3280 res = concat (file, "", "");
3281 else
3282 res = concat (cwd, file, "");
3284 /* Delete the "/dirname/.." and "/." substrings. */
3285 slashp = etags_strchr (res, '/');
3286 while (slashp != NULL && slashp[0] != '\0')
3288 if (slashp[1] == '.')
3290 if (slashp[2] == '.'
3291 && (slashp[3] == '/' || slashp[3] == '\0'))
3293 cp = slashp;
3295 cp--;
3296 while (cp >= res && *cp != '/');
3297 if (*cp == '/')
3299 strcpy (cp, slashp + 3);
3301 else /* else (cp == res) */
3303 if (slashp[3] != '\0')
3304 strcpy (cp, slashp + 4);
3305 else
3306 return ".";
3308 slashp = cp;
3309 continue;
3311 else if (slashp[2] == '/' || slashp[2] == '\0')
3313 strcpy (slashp, slashp + 2);
3314 continue;
3318 slashp = etags_strchr (slashp + 1, '/');
3321 return res;
3324 /* Return a newly allocated string containing the absolute
3325 filename of dir where FILE resides given CWD (which should
3326 end with a slash). */
3328 char *
3329 absolute_dirname (file, cwd)
3330 char *file, *cwd;
3332 char *slashp, *res;
3333 char save;
3335 slashp = etags_strrchr (file, '/');
3336 if (slashp == NULL)
3337 return cwd;
3338 save = slashp[1];
3339 slashp[1] = '\0';
3340 res = absolute_filename (file, cwd);
3341 slashp[1] = save;
3343 return res;
3346 /* Like malloc but get fatal error if memory is exhausted. */
3348 char *
3349 xmalloc (size)
3350 unsigned int size;
3352 char *result = (char *) malloc (size);
3353 if (result == NULL)
3354 fatal ("virtual memory exhausted", 0);
3355 return result;
3358 char *
3359 xrealloc (ptr, size)
3360 char *ptr;
3361 unsigned int size;
3363 char *result = (char *) realloc (ptr, size);
3364 if (result == NULL)
3365 fatal ("virtual memory exhausted");
3366 return result;