(split-window-vertically): If size is negative, measure from bottom.
[emacs.git] / lib-src / etags.c
blobb6481bb475b6691e6579959426bf37971bca2443
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.21";
33 #ifdef MSDOS
34 #include <fcntl.h>
35 #endif /* MSDOS */
37 #ifdef HAVE_CONFIG_H
38 #include <../src/config.h>
39 #endif
41 #include <stdio.h>
42 #include <ctype.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
46 #if !defined (S_ISREG) && defined (S_IFREG)
47 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
48 #endif
50 #include "getopt.h"
52 extern char *getenv ();
55 /* Define CTAGS to make the program "ctags" compatible with the usual one.
56 Let it undefined to make the program "etags", which makes emacs-style
57 tag tables and tags typedefs, #defines and struct/union/enum by default. */
58 #ifdef CTAGS
59 # undef CTAGS
60 # define CTAGS TRUE
61 #else
62 # define CTAGS FALSE
63 #endif
65 /* Exit codes for success and failure. */
66 #ifdef VMS
67 #define GOOD 1
68 #define BAD 0
69 #else
70 #define GOOD 0
71 #define BAD 1
72 #endif
75 * The FILEPOS abstract type, which represents a position in a file,
76 * plus the following accessor functions:
78 * long GET_CHARNO (pos)
79 * returns absolute char number.
80 * void SET_FILEPOS (pos, fp, charno)
81 * FILE *fp; long charno;
82 * sets `pos' from the current file
83 * position of `fp' and from `charno',
84 * which must be the absolute character
85 * number corresponding to the current
86 * position of `fp'.
88 * The `pos' parameter is an lvalue expression of type FILEPOS.
89 * Parameters to the accessor functions are evaluated 0 or more times,
90 * and so must have no side effects.
92 * FILEPOS objects can also be assigned and passed to and from
93 * functions in the normal C manner.
95 * Implementation notes: the `+ 0' is to enforce rvalue-ness.
98 #ifndef DEBUG
99 /* real implementation */
100 typedef long FILEPOS;
101 #define GET_CHARNO(pos) ((pos) + 0)
102 #define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))
103 #else
104 /* debugging implementation */
105 typedef struct
107 long charno;
108 } FILEPOS;
110 #define GET_CHARNO(pos) ((pos).charno + 0)
111 #define SET_FILEPOS(pos, fp, cno) \
112 ((void) ((pos).charno = (cno), \
113 (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
114 : 0))
115 #endif
117 #define streq(s, t) (strcmp (s, t) == 0)
118 #define strneq(s, t, n) (strncmp (s, t, n) == 0)
119 #define logical int
121 #define TRUE 1
122 #define FALSE 0
124 #define iswhite(arg) (_wht[arg]) /* T if char is white */
125 #define begtoken(arg) (_btk[arg]) /* T if char can start token */
126 #define intoken(arg) (_itk[arg]) /* T if char can be in token */
127 #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
129 #define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
131 struct nd_st
132 { /* sorting structure */
133 char *name; /* function or type name */
134 char *file; /* file name */
135 logical is_func; /* use pattern or line no */
136 logical named; /* list name separately */
137 logical been_warned; /* set if noticed dup */
138 int lno; /* line number tag is on */
139 long cno; /* character number line starts on */
140 char *pat; /* search pattern */
141 struct nd_st *left, *right; /* left and right sons */
144 typedef struct nd_st NODE;
146 logical header_file; /* TRUE if .h file, FALSE o.w. */
147 /* boolean "functions" (see init) */
148 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
150 char *cwd; /* current working directory */
151 char *outfiledir; /* directory of tagfile */
153 char *concat ();
154 char *savenstr (), *savestr ();
155 char *etags_strchr (), *etags_strrchr ();
156 char *etags_getcwd ();
157 char *relative_filename (), *absolute_filename (), *absolute_dirname ();
158 char *xmalloc (), *xrealloc ();
159 int L_isdef (), L_isquote ();
160 int PF_funcs ();
161 int total_size_of_entries ();
162 logical consider_token ();
163 logical tail ();
164 long readline ();
165 void Asm_funcs ();
166 void C_entries ();
167 void L_funcs ();
168 void L_getit ();
169 void PAS_funcs ();
170 void Scheme_funcs ();
171 void TEX_funcs ();
172 void add_node ();
173 void error ();
174 void fatal ();
175 logical find_entries ();
176 void free_tree ();
177 void getit ();
178 void init ();
179 void initbuffer ();
180 void initbuffer ();
181 void pfnote ();
182 void process_file ();
183 void put_entries ();
184 void takeprec ();
187 * MACRO
188 * xnew -- allocate storage
190 * SYNOPSIS
191 * Type *xnew (int n, Type);
193 #define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
196 * Symbol table types.
198 enum sym_type
200 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
205 typedef int LINENO;
207 typedef struct
209 char *p;
210 int len;
211 LINENO lineno;
212 logical named;
213 } TOKEN;
215 /* C extensions.
217 #define C_PLPL 0x00001 /* C++ */
218 #define C_STAR 0x00003 /* C* */
219 #define YACC 0x10000 /* yacc file */
221 char searchar = '/'; /* use /.../ searches */
223 LINENO lineno; /* line number of current line */
224 long charno; /* current character number */
226 long linecharno; /* charno of start of line; not used by C, but
227 * by every other language.
230 char *curfile, /* current input file name */
231 *outfile, /* output file */
232 *white = " \f\t\n", /* white chars */
233 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
234 /* token starting chars */
235 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
236 /* valid in-token chars */
237 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
239 int append_to_tagfile; /* -a: append to tags */
240 /* The following three default to 1 for etags, but to 0 for ctags. */
241 int typedefs; /* -t: create tags for typedefs */
242 int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
243 /* 0 struct/enum/union decls, and C++ */
244 /* member functions. */
245 int constantypedefs; /* -d: create tags for C #define and enum */
246 /* constants. Enum consts not implemented. */
247 /* -D: opposite of -d. Default under ctags. */
248 int update; /* -u: update tags */
249 int vgrind_style; /* -v: create vgrind style index output */
250 int no_warnings; /* -w: suppress warnings */
251 int cxref_style; /* -x: create cxref style output */
252 int cplusplus; /* .[hc] means C++, not C */
253 int noindentypedefs; /* -S: ignore indentation in C */
255 /* Name this program was invoked with. */
256 char *progname;
258 struct option longopts[] = {
259 { "append", no_argument, NULL, 'a' },
260 { "backward-search", no_argument, NULL, 'B' },
261 { "c++", no_argument, NULL, 'C' },
262 { "cxref", no_argument, NULL, 'x' },
263 { "defines", no_argument, NULL, 'd' },
264 { "forward-search", no_argument, NULL, 'F' },
265 { "help", no_argument, NULL, 'H' },
266 { "ignore-indentation", no_argument, NULL, 'S' },
267 { "include", required_argument, NULL, 'i' },
268 { "no-defines", no_argument, NULL, 'D' },
269 { "no-warn", no_argument, NULL, 'w' },
270 { "output", required_argument, NULL, 'o' },
271 { "typedefs", no_argument, NULL, 't' },
272 { "typedefs-and-c++", no_argument, NULL, 'T' },
273 { "update", no_argument, NULL, 'u' },
274 { "version", no_argument, NULL, 'V' },
275 { "vgrind", no_argument, NULL, 'v' },
276 { 0 }
279 FILE *inf, /* ioptr for current input file */
280 *outf; /* ioptr for tags file */
282 NODE *head; /* the head of the binary tree of tags */
284 int permit_duplicates = 1; /* Nonzero means allow duplicate tags. */
286 /* A `struct linebuffer' is a structure which holds a line of text.
287 `readline' reads a line from a stream into a linebuffer
288 and works regardless of the length of the line. */
290 struct linebuffer
292 long size;
293 char *buffer;
296 struct linebuffer lb; /* the current line */
297 struct linebuffer filename_lb; /* used to read in filenames */
298 struct
300 FILEPOS linepos;
301 struct linebuffer lb; /* used by C_entries instead of lb */
302 } lbs[2];
304 void
305 print_version ()
307 #ifdef VERSION
308 printf ("%s for Emacs version %g.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
309 #else
310 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
311 #endif
313 exit (GOOD);
316 void
317 print_help ()
319 printf ("These are the options accepted by %s. You may use unambiguous\n\
320 abbreviations for the long option names. A - as file name means read file\n\
321 names from stdin.\n\n", progname);
323 puts ("-a, --append\n\
324 Append tag entries to existing tags file.");
326 if (CTAGS)
327 puts ("-B, --backward-search\n\
328 Write the search commands for the tag entries using '?', the\n\
329 backward-search command.");
331 puts ("-C, --c++\n\
332 Treat files with `.c' and `.h' extensions as C++ code, not C\n\
333 code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
334 extensions are always assumed to be C++ code.");
336 if (CTAGS)
337 puts ("-d, --defines\n\
338 Create tag entries for C #defines, too.");
339 else
340 puts ("-D, --no-defines\n\
341 Don't create tag entries for C #defines. This makes the tags\n\
342 file smaller.");
344 if (CTAGS)
345 puts ("-F, --forward-search\n\
346 Write the search commands for the tag entries using '/', the\n\
347 forward-search command.");
349 if (!CTAGS)
350 puts ("-i FILE, --include=FILE\n\
351 Include a note in tag file indicating that, when searching for\n\
352 a tag, one should also consult the tags file FILE after\n\
353 checking the current file.");
355 puts ("-o FILE, --output=FILE\n\
356 Write the tags to FILE.");
357 puts ("-S, --ignore-indentation\n\
358 Don't rely on indentation quite as much as normal. Currently,\n\
359 this means not to assume that a closing brace in the first\n\
360 column is the final brace of a function or structure\n\
361 definition in C and C++.");
363 if (CTAGS)
365 puts ("-t, --typedefs\n\
366 Generate tag entries for C typedefs.");
367 puts ("-T, --typedefs-and-c++\n\
368 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
369 and C++ member functions.");
370 puts ("-u, --update\n\
371 Update the tag entries for the given files, leaving tag\n\
372 entries for other files in place. Currently, this is\n\
373 implemented by deleting the existing entries for the given\n\
374 files and then rewriting the new entries at the end of the\n\
375 tags file. It is often faster to simply rebuild the entire\n\
376 tag file than to use this.");
377 puts ("-v, --vgrind\n\
378 Generates an index of items intended for human consumption,\n\
379 similar to the output of vgrind. The index is sorted, and\n\
380 gives the page number of each item.");
381 puts ("-x, --cxref\n\
382 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
383 The output uses line numbers instead of page numbers, but\n\
384 beyond that the differences are cosmetic; try both to see\n\
385 which you like.");
386 puts ("-w, --no-warn\n\
387 Suppress warning messages about entries defined in multiple\n\
388 files.");
391 puts ("-V, --version\n\
392 Print the version of the program.\n\
393 -H, --help\n\
394 Print this help message.");
396 exit (GOOD);
400 void
401 main (argc, argv)
402 int argc;
403 char *argv[];
405 char cmd[100];
406 int i;
407 unsigned int nincluded_files = 0;
408 char **included_files = xnew (argc, char *);
409 char *this_file;
410 #ifdef VMS
411 char got_err;
413 extern char *gfnames ();
414 extern char *massage_name ();
415 #endif
417 #ifdef MSDOS
418 _fmode = O_BINARY; /* all of files are treated as binary files */
419 #endif /* MSDOS */
421 progname = argv[0];
424 * If etags, always find typedefs and structure tags. Why not?
425 * Also default is to find macro constants.
427 if (!CTAGS)
428 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
430 for (;;)
432 int opt;
433 opt = getopt_long (argc, argv, "aCdDf:o:StTi:BFuvxwVH", longopts, 0);
435 if (opt == EOF)
436 break;
438 switch (opt)
440 case 0:
441 /* If getopt returns 0, then it has already processed a
442 long-named option. We should do nothing. */
443 break;
445 /* Common options. */
446 case 'a':
447 append_to_tagfile++;
448 break;
449 case 'C':
450 cplusplus = 1;
451 break;
452 case 'd':
453 constantypedefs = 1;
454 break;
455 case 'D':
456 constantypedefs = 0;
457 break;
458 case 'f': /* for compatibility with old makefiles */
459 case 'o':
460 if (outfile)
462 fprintf (stderr,
463 "%s: -%c flag may only be given once\n", progname, opt);
464 goto usage;
466 outfile = optarg;
467 break;
468 case 'S':
469 noindentypedefs++;
470 break;
471 case 'V':
472 print_version ();
473 break;
474 case 'H':
475 print_help ();
476 break;
478 #if (!CTAGS)
480 /* Etags options */
481 case 'i':
482 included_files[nincluded_files++] = optarg;
483 break;
485 #else /* CTAGS */
487 /* Ctags options. */
488 case 'B':
489 searchar = '?';
490 break;
491 case 'F':
492 searchar = '/';
493 break;
494 case 't':
495 typedefs++;
496 break;
497 case 'T':
498 typedefs++;
499 typedefs_and_cplusplus++;
500 break;
501 case 'u':
502 update++;
503 break;
504 case 'v':
505 vgrind_style++;
506 /*FALLTHRU*/
507 case 'x':
508 cxref_style++;
509 break;
510 case 'w':
511 no_warnings++;
512 break;
514 #endif /* CTAGS */
516 default:
517 goto usage;
521 if (optind == argc && nincluded_files == 0)
523 fprintf (stderr, "%s: No input files specified.\n", progname);
525 usage:
526 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
527 progname, progname);
528 exit (BAD);
531 if (outfile == NULL)
533 outfile = CTAGS ? "tags" : "TAGS";
535 cwd = etags_getcwd (); /* the current working directory */
536 strcat (cwd, "/");
537 if (streq (outfile, "-"))
539 outfiledir = cwd;
541 else
543 outfiledir = absolute_dirname (outfile, cwd);
546 init (); /* set up boolean "functions" */
548 initbuffer (&lb);
549 initbuffer (&lbs[0].lb);
550 initbuffer (&lbs[1].lb);
551 initbuffer (&filename_lb);
553 * loop through files finding functions
555 if (!CTAGS)
557 if (streq (outfile, "-"))
558 outf = stdout;
559 else
560 outf = fopen (outfile, append_to_tagfile ? "a" : "w");
561 if (outf == NULL)
563 perror (outfile);
564 exit (BAD);
568 #ifdef VMS
569 argc -= optind;
570 argv += optind;
571 while (gfnames (&argc, &argv, &got_err) != NULL)
573 if (got_err)
575 error ("Can't find file %s\n", this_file);
576 argc--, argv++;
578 else
580 this_file = massage_name (this_file);
581 #if 0
583 } /* solely to balance out the ifdef'd parens above */
584 #endif
585 #else
586 for (; optind < argc; optind++)
588 this_file = argv[optind];
589 #endif
590 /* Input file named "-" means read file names from stdin and use them. */
591 if (streq (this_file, "-"))
593 while (!feof (stdin))
595 (void) readline (&filename_lb, stdin);
596 if (strlen (filename_lb.buffer) > 0)
597 process_file (filename_lb.buffer);
600 else
601 process_file (this_file);
604 if (!CTAGS)
606 while (nincluded_files-- > 0)
607 fprintf (outf, "\f\n%s,include\n", *included_files++);
609 (void) fclose (outf);
610 exit (GOOD);
613 if (cxref_style)
615 put_entries (head);
616 exit (GOOD);
618 if (update)
620 /* update cannot be set under VMS, so we may assume that argc
621 and argv have not been munged. */
622 for (i = optind; i < argc; i++)
624 sprintf (cmd,
625 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
626 outfile, argv[i], outfile);
627 (void) system (cmd);
629 append_to_tagfile++;
631 outf = fopen (outfile, append_to_tagfile ? "a" : "w");
632 if (outf == NULL)
634 perror (outfile);
635 exit (GOOD);
637 put_entries (head);
638 (void) fclose (outf);
639 if (update)
641 sprintf (cmd, "sort %s -o %s", outfile, outfile);
642 (void) system (cmd);
644 exit (GOOD);
649 * This routine is called on each file argument.
651 void
652 process_file (file)
653 char *file;
655 struct stat stat_buf;
657 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
659 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
660 return;
662 if (streq (file, outfile) && !streq (outfile, "-"))
664 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
665 return;
667 if (!find_entries (file))
669 return;
671 if (!CTAGS)
673 char *filename;
675 if (file[0] == '/')
677 /* file is an absolute filename. Canonicalise it. */
678 filename = absolute_filename (file, cwd);
680 else
682 /* file is a filename relative to cwd. Make it relative
683 to the directory of the tags file. */
684 filename = relative_filename (file, outfiledir);
686 fprintf (outf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
687 put_entries (head);
688 free_tree (head);
689 head = NULL;
694 * This routine sets up the boolean pseudo-functions which work
695 * by setting boolean flags dependent upon the corresponding character
696 * Every char which is NOT in that string is not a white char. Therefore,
697 * all of the array "_wht" is set to FALSE, and then the elements
698 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
699 * of a char is TRUE if it is the string "white", else FALSE.
701 void
702 init ()
704 register char *sp;
705 register int i;
707 for (i = 0; i < 0177; i++)
708 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
709 for (sp = white; *sp; sp++)
710 _wht[*sp] = TRUE;
711 for (sp = endtk; *sp; sp++)
712 _etk[*sp] = TRUE;
713 for (sp = intk; *sp; sp++)
714 _itk[*sp] = TRUE;
715 for (sp = begtk; *sp; sp++)
716 _btk[*sp] = TRUE;
717 _wht[0] = _wht['\n'];
718 _etk[0] = _etk['\n'];
719 _btk[0] = _btk['\n'];
720 _itk[0] = _itk['\n'];
724 * This routine opens the specified file and calls the function
725 * which finds the function and type definitions.
727 logical
728 find_entries (file)
729 char *file;
731 char *cp;
732 void prolog_funcs ();
734 inf = fopen (file, "r");
735 if (inf == NULL)
737 perror (file);
738 return FALSE;
740 curfile = savestr (file);
741 cp = etags_strrchr (file, '.');
743 header_file = (cp && (streq (cp + 1, "h")));
745 /* .tex, .aux or .bbl implies LaTeX source code */
746 if (cp && (streq (cp + 1, "tex") || streq (cp + 1, "aux")
747 || streq (cp + 1, "bbl")))
749 TEX_funcs (inf);
750 goto close_and_return;
752 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
753 if (cp && (streq (cp + 1, "l")
754 || streq (cp + 1, "el")
755 || streq (cp + 1, "lsp")
756 || streq (cp + 1, "lisp")
757 || streq (cp + 1, "cl")
758 || streq (cp + 1, "clisp")))
760 L_funcs (inf);
761 goto close_and_return;
763 /* .scm or .sm or .scheme or ... implies scheme source code */
764 if (cp && (streq (cp + 1, "sm")
765 || streq (cp + 1, "scm")
766 || streq (cp + 1, "scheme")
767 || streq (cp + 1, "t")
768 || streq (cp + 1, "sch")
769 || streq (cp + 1, "ss")
770 || streq (cp + 1, "SM")
771 || streq (cp + 1, "SCM")
772 /* The `SCM' or `scm' prefix with a version number */
773 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's'
774 && string_numeric_p (cp + 1))
775 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'
776 && string_numeric_p (cp + 1))))
778 Scheme_funcs (inf);
779 goto close_and_return;
781 /* Assume that ".s" or ".a" is assembly code. -wolfgang.
782 Or even ".sa". */
783 if (cp && (streq (cp + 1, "s")
784 || streq (cp + 1, "a")
785 || streq (cp + 1, "sa")))
787 Asm_funcs (inf);
788 goto close_and_return;
790 /* .C or .H or .cxx or .hxx or .cc: a C++ file */
791 if (cp && (streq (cp + 1, "C")
792 || streq (cp + 1, "H")
793 || streq (cp + 1, "cxx")
794 || streq (cp + 1, "hxx")
795 || streq (cp + 1, "cc")))
797 C_entries (C_PLPL); /* C++ */
798 goto close_and_return;
800 /* .cs or .hs: a C* file */
801 if (cp && (streq (cp + 1, "cs")
802 || streq (cp + 1, "hs")))
804 C_entries (C_STAR);
805 goto close_and_return;
807 /* .y: a yacc file */
808 if (cp && (streq (cp + 1, "y")))
810 C_entries (YACC);
811 goto close_and_return;
813 /* .pl implies prolog source code */
814 if (cp && streq (cp + 1, "pl"))
816 prolog_funcs (inf);
817 goto close_and_return;
819 /* .p or .pas: a Pascal file */
820 if (cp && (streq (cp + 1, "p")
821 || streq (cp + 1, "pas")))
823 PAS_funcs (inf);
824 goto close_and_return;
826 /* If .f or .for, assume it is fortran or nothing. */
827 if (cp && (streq (cp + 1, "f")
828 || streq (cp + 1, "for")))
830 (void) PF_funcs (inf);
831 goto close_and_return;
833 /* if not a .c or .h or .y file, try fortran */
834 if (cp && ((cp[1] != 'c'
835 && cp[1] != 'h'
836 && cp[1] != 'y')
837 || (cp[1] != 0 && cp[2] != 0)))
839 if (PF_funcs (inf) != 0)
840 goto close_and_return;
841 rewind (inf); /* no fortran tags found, try C */
843 C_entries (cplusplus ? C_PLPL : 0);
845 close_and_return:
846 (void) fclose (inf);
847 return TRUE;
850 /* Nonzero if string STR is composed of digits. */
853 string_numeric_p (str)
854 char *str;
856 while (*str)
858 if (*str < '0' || *str > '9')
859 return 0;
861 return 1;
864 /* Record a tag. */
865 /* Should take a TOKEN* instead!! */
866 void
867 pfnote (name, is_func, named, linestart, linelen, lno, cno)
868 char *name; /* tag name */
869 logical is_func; /* function or type name? */
870 logical named; /* tag different from text of definition? */
871 char *linestart;
872 int linelen;
873 int lno;
874 long cno;
876 register char *fp;
877 register NODE *np;
878 char tem[51];
879 char c;
881 np = xnew (1, NODE);
882 if (np == NULL)
884 if (CTAGS)
886 /* It's okay to output early in etags -- it only disrupts the
887 * character count of the tag entries, which is no longer used
888 * by tags.el anyway.
890 error ("too many entries to sort", 0);
892 put_entries (head);
893 free_tree (head);
894 head = NULL;
895 np = xnew (1, NODE);
897 /* If ctags mode, change name "main" to M<thisfilename>. */
898 if (CTAGS && !cxref_style && streq (name, "main"))
900 fp = etags_strrchr (curfile, '/');
901 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
902 fp = etags_strrchr (name, '.');
903 if (fp && fp[1] != '\0' && fp[2] == '\0')
904 *fp = 0;
905 named = TRUE;
907 np->name = savestr (name);
908 np->file = curfile;
909 np->is_func = is_func;
910 np->named = named;
911 np->lno = lno;
912 /* UNCOMMENT THE +1 HERE: */
913 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
914 np->left = np->right = 0;
915 if (!CTAGS)
917 c = linestart[linelen];
918 linestart[linelen] = 0;
920 else if (cxref_style == 0)
922 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
923 linestart = tem;
925 np->pat = savestr (linestart);
926 if (!CTAGS)
928 linestart[linelen] = c;
931 add_node (np, &head);
935 * free_tree ()
936 * recurse on left children, iterate on right children.
938 void
939 free_tree (node)
940 register NODE *node;
942 while (node)
944 register NODE *node_right = node->right;
945 free_tree (node->left);
946 free (node->name);
947 free (node->pat);
948 free ((char *) node);
949 node = node_right;
954 * add_node ()
955 * Adds a node to the tree of nodes. In etags mode, we don't keep
956 * it sorted; we just keep a linear list. In ctags mode, maintain
957 * an ordered tree, with no attempt at balancing.
959 * add_node is the only function allowed to add nodes, so it can
960 * maintain state.
962 /* Must avoid static vars within functions since some systems
963 #define static as nothing. */
964 static NODE *last_node = NULL;
966 void
967 add_node (node, cur_node_p)
968 NODE *node, **cur_node_p;
970 register int dif;
971 register NODE *cur_node = *cur_node_p;
973 if (cur_node == NULL)
975 *cur_node_p = node;
976 last_node = node;
977 return;
980 if (!CTAGS)
982 /* Etags Mode */
983 if (last_node == NULL)
984 fatal ("internal error in add_node", 0);
985 last_node->right = node;
986 last_node = node;
988 else
990 /* Ctags Mode */
991 dif = strcmp (node->name, cur_node->name);
994 * If this tag name matches an existing one, then
995 * do not add the node, but maybe print a warning.
997 if (!dif)
999 if (node->file == cur_node->file)
1001 if (!no_warnings)
1003 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1004 node->file, lineno, node->name);
1005 fprintf (stderr, "Second entry ignored\n");
1007 return;
1009 if (!cur_node->been_warned && !no_warnings)
1011 fprintf (stderr,
1012 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1013 node->file, cur_node->file, node->name);
1015 cur_node->been_warned = TRUE;
1016 return;
1019 /* Maybe refuse to add duplicate nodes. */
1020 if (!permit_duplicates)
1022 if (streq (node->name, cur_node->name)
1023 && streq (node->file, cur_node->file))
1024 return;
1027 /* Actually add the node */
1028 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1032 void
1033 put_entries (node)
1034 register NODE *node;
1036 register char *sp;
1038 if (node == NULL)
1039 return;
1041 /* Output subentries that precede this one */
1042 put_entries (node->left);
1044 /* Output this entry */
1046 if (!CTAGS)
1048 if (node->named)
1050 fprintf (outf, "%s\177%s\001%d,%d\n",
1051 node->pat, node->name,
1052 node->lno, node->cno);
1054 else
1056 fprintf (outf, "%s\177%d,%d\n",
1057 node->pat,
1058 node->lno, node->cno);
1061 else if (!cxref_style)
1063 fprintf (outf, "%s\t%s\t",
1064 node->name, node->file);
1066 if (node->is_func)
1067 { /* a function */
1068 putc (searchar, outf);
1069 putc ('^', outf);
1071 for (sp = node->pat; *sp; sp++)
1073 if (*sp == '\\' || *sp == searchar)
1074 putc ('\\', outf);
1075 putc (*sp, outf);
1077 putc (searchar, outf);
1079 else
1080 { /* a typedef; text pattern inadequate */
1081 fprintf (outf, "%d", node->lno);
1083 putc ('\n', outf);
1085 else if (vgrind_style)
1086 fprintf (stdout, "%s %s %d\n",
1087 node->name, node->file, (node->lno + 63) / 64);
1088 else
1089 fprintf (stdout, "%-16s %3d %-16s %s\n",
1090 node->name, node->lno, node->file, node->pat);
1092 /* Output subentries that follow this one */
1093 put_entries (node->right);
1096 /* Length of a number's decimal representation. */
1098 number_len (num)
1099 long num;
1101 int len = 0;
1102 if (!num)
1103 return 1;
1104 for (; num; num /= 10)
1105 ++len;
1106 return len;
1110 * Return total number of characters that put_entries will output for
1111 * the nodes in the subtree of the specified node. Works only if
1112 * we are not ctags, but called only in that case. This count
1113 * is irrelevant with the new tags.el, but is still supplied for
1114 * backward compatibility.
1117 total_size_of_entries (node)
1118 register NODE *node;
1120 register int total;
1122 if (node == NULL)
1123 return 0;
1125 total = 0;
1126 for (; node; node = node->right)
1128 /* Count left subentries. */
1129 total += total_size_of_entries (node->left);
1131 /* Count this entry */
1132 total += strlen (node->pat) + 1;
1133 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1134 if (node->named)
1135 total += 1 + strlen (node->name); /* \001name */
1138 return total;
1142 * The C symbol tables.
1145 /* Feed stuff between (but not including) %[ and %] lines to:
1146 gperf -c -k1,3 -o -p -r -t
1148 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1150 class, C_PLPL, st_C_struct
1151 domain, C_STAR, st_C_struct
1152 union, 0, st_C_struct
1153 struct, 0, st_C_struct
1154 enum, 0, st_C_enum
1155 typedef, 0, st_C_typedef
1156 define, 0, st_C_define
1157 long, 0, st_C_typespec
1158 short, 0, st_C_typespec
1159 int, 0, st_C_typespec
1160 char, 0, st_C_typespec
1161 float, 0, st_C_typespec
1162 double, 0, st_C_typespec
1163 signed, 0, st_C_typespec
1164 unsigned, 0, st_C_typespec
1165 auto, 0, st_C_typespec
1166 void, 0, st_C_typespec
1167 extern, 0, st_C_typespec
1168 static, 0, st_C_typespec
1169 const, 0, st_C_typespec
1170 volatile, 0, st_C_typespec
1172 and replace lines between %< and %> with its output. */
1173 /*%<*/
1174 /* C code produced by gperf version 1.8.1 (K&R C version) */
1175 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1178 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1180 #define MIN_WORD_LENGTH 3
1181 #define MAX_WORD_LENGTH 8
1182 #define MIN_HASH_VALUE 10
1183 #define MAX_HASH_VALUE 62
1185 21 keywords
1186 53 is the maximum key range
1189 static int
1190 hash (str, len)
1191 register char *str;
1192 register int len;
1194 static unsigned char hash_table[] =
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, 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, 2, 62, 7,
1206 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1207 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1208 62, 62, 62, 62, 62, 62, 62, 62,
1210 return len + hash_table[str[2]] + hash_table[str[0]];
1213 struct C_stab_entry *
1214 in_word_set (str, len)
1215 register char *str;
1216 register int len;
1219 static struct C_stab_entry wordlist[] =
1221 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1222 {"",},
1223 {"volatile", 0, st_C_typespec},
1224 {"",},
1225 {"long", 0, st_C_typespec},
1226 {"char", 0, st_C_typespec},
1227 {"class", C_PLPL, st_C_struct},
1228 {"",}, {"",}, {"",}, {"",},
1229 {"const", 0, st_C_typespec},
1230 {"",}, {"",}, {"",}, {"",},
1231 {"auto", 0, st_C_typespec},
1232 {"",}, {"",},
1233 {"define", 0, st_C_define},
1234 {"",},
1235 {"void", 0, st_C_typespec},
1236 {"",}, {"",}, {"",},
1237 {"extern", 0, st_C_typespec},
1238 {"static", 0, st_C_typespec},
1239 {"",},
1240 {"domain", C_STAR, st_C_struct},
1241 {"",},
1242 {"typedef", 0, st_C_typedef},
1243 {"double", 0, st_C_typespec},
1244 {"enum", 0, st_C_enum},
1245 {"",}, {"",}, {"",}, {"",},
1246 {"int", 0, st_C_typespec},
1247 {"",},
1248 {"float", 0, st_C_typespec},
1249 {"",}, {"",}, {"",},
1250 {"struct", 0, st_C_struct},
1251 {"",}, {"",}, {"",}, {"",},
1252 {"union", 0, st_C_struct},
1253 {"",},
1254 {"short", 0, st_C_typespec},
1255 {"",}, {"",},
1256 {"unsigned", 0, st_C_typespec},
1257 {"signed", 0, st_C_typespec},
1260 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1262 register int key = hash (str, len);
1264 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1266 register char *s = wordlist[key].name;
1268 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1269 return &wordlist[key];
1272 return 0;
1274 /*%>*/
1276 enum sym_type
1277 C_symtype(str, len, c_ext)
1278 char *str;
1279 int len;
1280 int c_ext;
1282 register struct C_stab_entry *se = in_word_set(str, len);
1284 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1285 return st_none;
1286 return se->type;
1290 * C functions are recognized using a simple finite automaton.
1291 * funcdef is its state variable.
1293 typedef enum
1295 fnone, /* nothing seen */
1296 ftagseen, /* function-like tag seen */
1297 fstartlist, /* just after open parenthesis */
1298 finlist, /* in parameter list */
1299 flistseen, /* after parameter list */
1300 fignore /* before open brace */
1301 } FUNCST;
1302 FUNCST funcdef;
1306 * typedefs are recognized using a simple finite automaton.
1307 * typeddef is its state variable.
1309 typedef enum
1311 tnone, /* nothing seen */
1312 ttypedseen, /* typedef keyword seen */
1313 tinbody, /* inside typedef body */
1314 tend, /* just before typedef tag */
1315 tignore /* junk after typedef tag */
1316 } TYPEDST;
1317 TYPEDST typdef;
1321 * struct-like structures (enum, struct and union) are recognized
1322 * using another simple finite automaton. `structdef' is its state
1323 * variable.
1325 typedef enum
1327 snone, /* nothing seen yet */
1328 skeyseen, /* struct-like keyword seen */
1329 stagseen, /* struct-like tag seen */
1330 scolonseen, /* colon seen after struct-like tag */
1331 sinbody /* in struct body: recognize member func defs*/
1332 } STRUCTST;
1333 STRUCTST structdef;
1336 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1337 * struct tag, and structtype is the type of the preceding struct-like
1338 * keyword.
1340 char structtag[BUFSIZ];
1341 enum sym_type structtype;
1344 * Yet another little state machine to deal with preprocessor lines.
1346 typedef enum
1348 dnone, /* nothing seen */
1349 dsharpseen, /* '#' seen as first char on line */
1350 ddefineseen, /* '#' and 'define' seen */
1351 dignorerest /* ignore rest of line */
1352 } DEFINEST;
1353 DEFINEST definedef;
1356 * Set this to TRUE, and the next token considered is called a function.
1357 * Used only for GNUmacs's function-defining macros.
1359 logical next_token_is_func;
1362 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1364 logical yacc_rules;
1367 * C_entries ()
1368 * This routine finds functions, typedefs, #define's and
1369 * struct/union/enum definitions in C syntax and adds them
1370 * to the list.
1373 #define curlb (lbs[curndx].lb)
1374 #define othlb (lbs[1-curndx].lb)
1375 #define newlb (lbs[newndx].lb)
1376 #define curlinepos (lbs[curndx].linepos)
1377 #define othlinepos (lbs[1-curndx].linepos)
1378 #define newlinepos (lbs[newndx].linepos)
1380 /* Save and restore token state. This is used when preprocessor defines
1381 are handled, to avoid disturbing active function/typedef/struct states. */
1382 #define TOKEN_SAVED_P (savetok.lineno > 0)
1383 #define SAVE_TOKEN (savetok = tok, savetok.p = (char *) tokoff, \
1384 savetok.len = toklen, strcpy(savenameb, nameb))
1385 #define RESTORE_TOKEN (tok = savetok, tokoff = (int) tok.p, \
1386 toklen = tok.len, strcpy(nameb, savenameb), \
1387 savetok.lineno = 0)
1389 #define CNL_SAVE_DEFINEDEF \
1390 do { \
1391 SET_FILEPOS (curlinepos, inf, charno); \
1392 lineno++; \
1393 charno += readline (&curlb, inf); \
1394 lp = curlb.buffer; \
1395 quotednl = FALSE; \
1396 newndx = curndx; \
1397 } while (FALSE)
1399 #define CNL \
1400 do { \
1401 CNL_SAVE_DEFINEDEF; \
1402 if (TOKEN_SAVED_P) \
1403 RESTORE_TOKEN; \
1404 definedef = dnone; \
1405 } while (FALSE)
1407 #define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
1408 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1409 #define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
1410 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
1412 void
1413 C_entries (c_ext)
1414 int c_ext; /* extension of C? */
1416 register char c; /* latest char read; '\0' for end of line */
1417 register char *lp; /* pointer one beyond the character `c' */
1418 int curndx, newndx; /* indices for current and new lb */
1419 TOKEN tok; /* latest token read for funcdef & structdef */
1420 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
1421 register int tokoff; /* offset in line of start of latest token */
1422 register int toklen; /* length of latest token */
1423 int cblev; /* current curly brace level */
1424 int parlev; /* current parenthesis level */
1425 logical incomm, inquote, inchar, quotednl, midtoken;
1426 logical cplpl;
1427 TOKEN savetok; /* saved token during preprocessor handling */
1428 char savenameb[BUFSIZ]; /* ouch! */
1430 savetok.lineno = 0;
1431 curndx = newndx = 0;
1432 lineno = 0;
1433 charno = 0;
1434 lp = curlb.buffer;
1435 *lp = 0;
1437 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1438 next_token_is_func = yacc_rules = FALSE;
1439 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1440 cblev = 0;
1441 parlev = 0;
1442 cplpl = c_ext & C_PLPL;
1444 while (!feof (inf))
1446 c = *lp++;
1447 if (c == '\\')
1449 /* If we're at the end of the line, the next character is a
1450 '\0'; don't skip it, because it's the thing that tells us
1451 to read the next line. */
1452 if (*lp == '\0')
1454 quotednl = TRUE;
1455 continue;
1457 lp++;
1458 c = ' ';
1460 else if (incomm)
1462 switch (c)
1464 case '*':
1465 if (*lp == '/')
1467 c = *lp++;
1468 incomm = FALSE;
1470 break;
1471 case '\0':
1472 /* Newlines inside comments do not end macro definitions in
1473 traditional cpp. */
1474 CNL_SAVE_DEFINEDEF;
1475 break;
1477 continue;
1479 else if (inquote)
1481 switch (c)
1483 case '"':
1484 inquote = FALSE;
1485 break;
1486 case '\0':
1487 /* Newlines inside strings do not end macro definitions
1488 in traditional cpp, even though compilers don't
1489 usually accept them. */
1490 CNL_SAVE_DEFINEDEF;
1491 break;
1493 continue;
1495 else if (inchar)
1497 switch (c)
1499 case '\0':
1500 /* Hmmm, something went wrong. */
1501 CNL;
1502 /* FALLTHRU */
1503 case '\'':
1504 inchar = FALSE;
1505 break;
1507 continue;
1509 else
1510 switch (c)
1512 case '"':
1513 inquote = TRUE;
1514 if (funcdef != finlist && funcdef != fignore)
1515 funcdef = fnone;
1516 continue;
1517 case '\'':
1518 inchar = TRUE;
1519 if (funcdef != finlist && funcdef != fignore)
1520 funcdef = fnone;
1521 continue;
1522 case '/':
1523 if (*lp == '*')
1525 lp++;
1526 incomm = TRUE;
1527 continue;
1529 else if (cplpl && *lp == '/')
1531 c = 0;
1532 break;
1534 else
1535 break;
1536 case '%':
1537 if ((c_ext & YACC) && *lp == '%')
1539 /* entering or exiting rules section in yacc file */
1540 lp++;
1541 definedef = dnone; funcdef = fnone;
1542 typdef = tnone; structdef = snone;
1543 next_token_is_func = FALSE;
1544 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1545 cblev = 0;
1546 yacc_rules = !yacc_rules;
1547 continue;
1549 else
1550 break;
1551 case '#':
1552 if (lp == newlb.buffer + 1 && definedef == dnone)
1553 definedef = dsharpseen;
1554 continue;
1555 } /* switch (c) */
1558 /* Consider token only if some complicated conditions are satisfied. */
1559 if (((cblev == 0 && structdef != scolonseen)
1560 || (cblev == 1 && cplpl && structdef == sinbody))
1561 && typdef != tignore
1562 && definedef != dignorerest
1563 && (funcdef != finlist
1564 || definedef != dnone))
1566 if (midtoken)
1568 if (endtoken (c))
1570 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
1573 * This handles :: in the middle, but not at beginning
1574 * of an identifier.
1576 lp += 2;
1577 toklen += 3;
1579 else
1581 logical is_func = FALSE;
1583 tok.lineno = lineno;
1584 tok.p = newlb.buffer + tokoff;
1585 tok.len = toklen;
1586 tok.named = FALSE;
1587 if (yacc_rules
1588 || consider_token (c, &tok, c_ext, cblev, &is_func))
1590 if (structdef == sinbody
1591 && definedef == dnone
1592 && is_func)
1593 /* function defined in C++ class body */
1595 tok.named = TRUE;
1596 sprintf (nameb, "%s::%.*s",
1597 ((structtag[0] == '\0')
1598 ? "_anonymous_" : structtag),
1599 tok.len, tok.p);
1601 else
1603 sprintf (nameb, "%.*s", tok.len, tok.p);
1606 if (structdef == stagseen
1607 || typdef == tend)
1608 tok.named = TRUE;
1610 if (definedef == dnone
1611 && (funcdef == ftagseen
1612 || structdef == stagseen
1613 || typdef == tend))
1615 if (newndx == curndx)
1616 curndx = 1 - curndx; /* switch line buffers */
1618 else
1619 MAKE_TAG_FROM_NEW_LB (is_func);
1621 midtoken = FALSE;
1623 } /* if (endtoken (c)) */
1624 else if (intoken (c))
1626 toklen++;
1627 continue;
1629 } /* if (midtoken) */
1630 else if (begtoken (c))
1632 switch (definedef)
1634 case dnone:
1635 switch (funcdef)
1637 case fstartlist:
1638 funcdef = finlist;
1639 continue;
1640 case flistseen:
1641 MAKE_TAG_FROM_OTH_LB (TRUE);
1642 funcdef = fignore;
1643 break;
1644 case ftagseen:
1645 funcdef = fnone;
1646 break;
1648 if (structdef == stagseen)
1649 structdef = snone;
1650 break;
1651 case dsharpseen:
1652 /* Take a quick peek ahead for define directive,
1653 so we can avoid saving the token when not absolutely
1654 necessary. [This is a speed hack.] */
1655 if (c == 'd' && strneq(lp, "efine", 5)
1656 && iswhite(*(lp + 5)))
1658 SAVE_TOKEN;
1659 definedef = ddefineseen;
1660 lp += 6;
1662 else
1663 definedef = dignorerest;
1664 continue;
1666 if (!yacc_rules || lp == newlb.buffer + 1)
1668 tokoff = lp - 1 - newlb.buffer;
1669 toklen = 1;
1670 midtoken = TRUE;
1672 continue;
1674 } /* if must look at token */
1677 /* Detect end of line, colon, comma, semicolon and various braces
1678 after having handled a token.*/
1679 switch (c)
1681 case ':':
1682 if (definedef != dnone)
1683 break;
1684 if (structdef == stagseen)
1685 structdef = scolonseen;
1686 else
1687 switch (funcdef)
1689 case ftagseen:
1690 if (yacc_rules)
1692 MAKE_TAG_FROM_OTH_LB (FALSE);
1693 funcdef = fignore;
1695 break;
1696 case fstartlist:
1697 funcdef = fnone;
1698 break;
1700 break;
1701 case ';':
1702 if (definedef != dnone)
1703 break;
1704 if (cblev == 0)
1705 switch (typdef)
1707 case tend:
1708 MAKE_TAG_FROM_OTH_LB (FALSE);
1709 /* FALLTHRU */
1710 default:
1711 typdef = tnone;
1713 if (funcdef != fignore)
1714 funcdef = fnone;
1715 if (structdef == stagseen)
1716 structdef = snone;
1717 break;
1718 case ',':
1719 if (definedef != dnone)
1720 break;
1721 if (funcdef != finlist && funcdef != fignore)
1722 funcdef = fnone;
1723 if (structdef == stagseen)
1724 structdef = snone;
1725 break;
1726 case '[':
1727 if (definedef != dnone)
1728 break;
1729 if (cblev == 0 && typdef == tend)
1731 typdef = tignore;
1732 MAKE_TAG_FROM_OTH_LB (FALSE);
1733 break;
1735 if (funcdef != finlist && funcdef != fignore)
1736 funcdef = fnone;
1737 if (structdef == stagseen)
1738 structdef = snone;
1739 break;
1740 case '(':
1741 if (definedef != dnone)
1742 break;
1743 switch (funcdef)
1745 case ftagseen:
1746 funcdef = fstartlist;
1747 break;
1748 case flistseen:
1749 funcdef = finlist;
1750 break;
1752 parlev++;
1753 break;
1754 case ')':
1755 if (definedef != dnone)
1756 break;
1757 if (--parlev == 0)
1759 switch (funcdef)
1761 case fstartlist:
1762 case finlist:
1763 funcdef = flistseen;
1764 break;
1766 if (cblev == 0 && typdef == tend)
1768 typdef = tignore;
1769 MAKE_TAG_FROM_OTH_LB (FALSE);
1772 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
1773 parlev = 0;
1774 break;
1775 case '{':
1776 if (definedef != dnone)
1777 break;
1778 if (typdef == ttypedseen)
1779 typdef = tinbody;
1780 switch (structdef)
1782 case skeyseen: /* unnamed struct */
1783 structtag[0] = '\0';
1784 structdef = sinbody;
1785 break;
1786 case stagseen:
1787 case scolonseen: /* named struct */
1788 structdef = sinbody;
1789 MAKE_TAG_FROM_OTH_LB (FALSE);
1790 break;
1792 switch (funcdef)
1794 case flistseen:
1795 MAKE_TAG_FROM_OTH_LB (TRUE);
1796 /* FALLTHRU */
1797 case fignore:
1798 funcdef = fnone;
1799 break;
1800 case fnone:
1801 /* Neutralize `extern "C" {' grot.
1802 if (cblev == 0 && structdef == snone && typdef == tnone)
1803 cblev--; */;
1805 cblev++;
1806 break;
1807 case '*':
1808 if (definedef != dnone)
1809 break;
1810 if (funcdef == fstartlist)
1811 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
1812 break;
1813 case '}':
1814 if (definedef != dnone)
1815 break;
1816 if (!noindentypedefs && lp == newlb.buffer + 1)
1818 cblev = 0; /* reset curly brace level if first column */
1819 parlev = 0; /* also reset paren level, just in case... */
1821 else if (cblev > 0)
1822 cblev--;
1823 if (cblev == 0)
1825 if (typdef == tinbody)
1826 typdef = tend;
1827 structdef = snone;
1828 strcpy (structtag, "<error 2>");
1830 break;
1831 case '=':
1832 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
1833 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
1834 if (definedef != dnone)
1835 break;
1836 /* These surely cannot follow a function tag. */
1837 if (funcdef != finlist && funcdef != fignore)
1838 funcdef = fnone;
1839 break;
1840 case '\0':
1841 /* If a macro spans multiple lines don't reset its state. */
1842 if (quotednl)
1843 CNL_SAVE_DEFINEDEF;
1844 else
1845 CNL;
1846 break;
1847 } /* switch (c) */
1849 } /* while not eof */
1853 * consider_token ()
1854 * checks to see if the current token is at the start of a
1855 * function, or corresponds to a typedef, or is a struct/union/enum
1856 * tag.
1858 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1859 * C_EXT is which language we are looking at.
1861 * In the future we will need some way to adjust where the end of
1862 * the token is; for instance, implementing the C++ keyword
1863 * `operator' properly will adjust the end of the token to be after
1864 * whatever follows `operator'.
1866 * Globals
1867 * funcdef IN OUT
1868 * structdef IN OUT
1869 * definedef IN OUT
1870 * typdef IN OUT
1871 * next_token_is_func IN OUT
1874 logical
1875 consider_token (c, tokp, c_ext, cblev, is_func)
1876 register char c; /* IN: first char after the token */
1877 register TOKEN *tokp; /* IN: token pointer */
1878 int c_ext; /* IN: C extensions mask */
1879 int cblev; /* IN: curly brace level */
1880 logical *is_func; /* OUT */
1882 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1885 * Advance the definedef state machine.
1887 switch (definedef)
1889 case dnone:
1890 /* We're not on a preprocessor line. */
1891 break;
1892 case dsharpseen:
1893 if (toktype == st_C_define)
1895 definedef = ddefineseen;
1897 else
1899 definedef = dignorerest;
1901 return (FALSE);
1902 case ddefineseen:
1904 * Make a tag for any macro.
1906 definedef = dignorerest;
1907 *is_func = (c == '(');
1908 if (!*is_func && !constantypedefs)
1909 return (FALSE);
1910 else
1911 return (TRUE);
1912 case dignorerest:
1913 return (FALSE);
1914 default:
1915 error ("internal error: definedef value.", 0);
1919 * Now typedefs
1921 switch (typdef)
1923 case tnone:
1924 if (toktype == st_C_typedef)
1926 if (typedefs)
1927 typdef = ttypedseen;
1928 funcdef = fnone;
1929 return (FALSE);
1931 break;
1932 case ttypedseen:
1933 switch (toktype)
1935 case st_none:
1936 case st_C_typespec:
1937 typdef = tend;
1938 break;
1939 case st_C_struct:
1940 case st_C_enum:
1941 break;
1943 /* Do not return here, so the structdef stuff has a chance. */
1944 break;
1945 case tend:
1946 switch (toktype)
1948 case st_C_typespec:
1949 case st_C_struct:
1950 case st_C_enum:
1951 return (FALSE);
1953 return (TRUE);
1957 * This structdef business is currently only invoked when cblev==0.
1958 * It should be recursively invoked whatever the curly brace level,
1959 * and a stack of states kept, to allow for definitions of structs
1960 * within structs.
1962 * This structdef business is NOT invoked when we are ctags and the
1963 * file is plain C. This is because a struct tag may have the same
1964 * name as another tag, and this loses with ctags.
1966 * This if statement deals with the typdef state machine as
1967 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1968 * return (FALSE). All the other code here is for the structdef
1969 * state machine.
1971 switch (toktype)
1973 case st_C_struct:
1974 case st_C_enum:
1975 if (typdef == ttypedseen
1976 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1978 structdef = skeyseen;
1979 structtype = toktype;
1981 return (FALSE);
1983 if (structdef == skeyseen)
1985 if (structtype == st_C_struct)
1987 strncpy (structtag, tokp->p, tokp->len);
1988 structtag[tokp->len] = '\0'; /* for struct/union/class */
1990 else
1992 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1994 structdef = stagseen;
1995 return (TRUE);
1998 /* Avoid entering funcdef stuff if typdef is going on. */
1999 if (typdef != tnone)
2001 definedef = dnone;
2002 return (FALSE);
2005 /* Detect GNUmacs's function-defining macros. */
2006 if (definedef == dnone)
2008 if (strneq (tokp->p, "DEF", 3)
2009 || strneq (tokp->p, "ENTRY", 5)
2010 || strneq (tokp->p, "SYSCALL", 7)
2011 || strneq (tokp->p, "PSEUDO", 6))
2013 next_token_is_func = TRUE;
2014 return (FALSE);
2016 if (strneq (tokp->p, "EXFUN", 5))
2018 next_token_is_func = FALSE;
2019 return (FALSE);
2022 if (next_token_is_func)
2024 next_token_is_func = FALSE;
2025 funcdef = fnone;
2026 *is_func = TRUE; /* to force search string in ctags */
2027 return (TRUE);
2030 /* A function? */
2031 switch (toktype)
2033 case st_C_typespec:
2034 if (funcdef != finlist && funcdef != fignore)
2035 funcdef = fnone; /* should be useless */
2036 return (FALSE);
2037 default:
2038 if (funcdef == fnone)
2040 funcdef = ftagseen;
2041 *is_func = TRUE;
2042 return (TRUE);
2046 return (FALSE);
2049 /* Fortran parsing */
2051 char *dbp;
2052 int pfcnt;
2055 PF_funcs (fi)
2056 FILE *fi;
2058 lineno = 0;
2059 charno = 0;
2060 pfcnt = 0;
2062 while (!feof (fi))
2064 lineno++;
2065 linecharno = charno;
2066 charno += readline (&lb, fi);
2067 dbp = lb.buffer;
2068 if (*dbp == '%')
2069 dbp++; /* Ratfor escape to fortran */
2070 while (isspace (*dbp))
2071 dbp++;
2072 if (*dbp == 0)
2073 continue;
2074 switch (*dbp | ' ')
2076 case 'i':
2077 if (tail ("integer"))
2078 takeprec ();
2079 break;
2080 case 'r':
2081 if (tail ("real"))
2082 takeprec ();
2083 break;
2084 case 'l':
2085 if (tail ("logical"))
2086 takeprec ();
2087 break;
2088 case 'c':
2089 if (tail ("complex") || tail ("character"))
2090 takeprec ();
2091 break;
2092 case 'd':
2093 if (tail ("double"))
2095 while (isspace (*dbp))
2096 dbp++;
2097 if (*dbp == 0)
2098 continue;
2099 if (tail ("precision"))
2100 break;
2101 continue;
2103 break;
2105 while (isspace (*dbp))
2106 dbp++;
2107 if (*dbp == 0)
2108 continue;
2109 switch (*dbp | ' ')
2111 case 'f':
2112 if (tail ("function"))
2113 getit (fi);
2114 continue;
2115 case 's':
2116 if (tail ("subroutine"))
2117 getit (fi);
2118 continue;
2119 case 'e':
2120 if (tail ("entry"))
2121 getit (fi);
2122 continue;
2123 case 'p':
2124 if (tail ("program"))
2126 getit (fi);
2127 continue;
2129 if (tail ("procedure"))
2130 getit (fi);
2131 continue;
2134 return (pfcnt);
2137 logical
2138 tail (cp)
2139 char *cp;
2141 register int len = 0;
2143 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2144 cp++, len++;
2145 if (*cp == 0)
2147 dbp += len;
2148 return (TRUE);
2150 return (FALSE);
2153 void
2154 takeprec ()
2156 while (isspace (*dbp))
2157 dbp++;
2158 if (*dbp != '*')
2159 return;
2160 dbp++;
2161 while (isspace (*dbp))
2162 dbp++;
2163 if (!isdigit (*dbp))
2165 --dbp; /* force failure */
2166 return;
2169 dbp++;
2170 while (isdigit (*dbp));
2173 void
2174 getit (fi)
2175 FILE *fi;
2177 register char *cp;
2178 char c;
2179 char nambuf[BUFSIZ];
2181 while (isspace (*dbp))
2182 dbp++;
2183 if (*dbp == '\0')
2185 lineno++;
2186 linecharno = charno;
2187 charno += readline (&lb, fi);
2188 dbp = lb.buffer;
2189 if (dbp[5] != '&')
2190 return;
2191 dbp += 6;
2192 while (isspace (*dbp))
2193 dbp++;
2195 if (!isalpha (*dbp)
2196 && *dbp != '_'
2197 && *dbp != '$')
2198 return;
2199 for (cp = dbp + 1;
2200 (*cp
2201 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2202 cp++)
2203 continue;
2204 c = *cp;
2205 *cp = '\0';
2206 strcpy (nambuf, dbp);
2207 *cp = c;
2208 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2209 cp - lb.buffer + 1, lineno, linecharno);
2210 pfcnt++;
2213 /* Handle a file of assembler code. */
2215 void
2216 Asm_funcs (fi)
2217 FILE *fi;
2219 int i;
2220 register char c;
2222 lineno = 0;
2223 charno = 0;
2224 pfcnt = 0;
2226 while (!feof (fi))
2228 lineno++;
2229 linecharno = charno;
2230 charno += readline (&lb, fi);
2231 dbp = lb.buffer;
2233 for (i = 0; ((c = dbp[i]) && !isspace (c)) && (c != ':'); i++)
2236 if ((i > 0) && (c == ':'))
2237 getit (fi);
2241 /* Added by Mosur Mohan, 4/22/88 */
2242 /* Pascal parsing */
2244 #define GET_NEW_LINE \
2246 linecharno = charno; lineno++; \
2247 charno += 1 + readline (&lb, inf); \
2248 dbp = lb.buffer; \
2251 /* Locates tags for procedures & functions.
2252 * Doesn't do any type- or var-definitions.
2253 * It does look for the keyword "extern" or "forward"
2254 * immediately following the procedure statement;
2255 * if found, the tag is skipped.
2258 void
2259 PAS_funcs (fi)
2260 FILE *fi;
2262 struct linebuffer tline; /* mostly copied from C_entries */
2263 long save_lcno;
2264 int save_lineno;
2265 char c, *cp;
2266 char nambuf[BUFSIZ];
2268 logical /* each of these flags is TRUE iff: */
2269 incomm1, /* point is inside {..} comment */
2270 incomm2, /* point is inside (*..*) comment */
2271 inquote, /* point is inside '..' string */
2272 get_tagname, /* point is after PROCEDURE/FUNCTION */
2273 /* keyword, so next item = potential tag */
2274 found_tag, /* point is after a potential tag */
2275 inparms, /* point is within parameter-list */
2276 verify_tag; /* point has passed the parm-list, so the */
2277 /* next token will determine whether */
2278 /* this is a FORWARD/EXTERN to be */
2279 /* ignored, or whether it is a real tag */
2281 lineno = 0;
2282 charno = 0;
2283 dbp = lb.buffer;
2284 *dbp = 0;
2285 initbuffer (&tline);
2287 incomm1 = incomm2 = inquote = FALSE;
2288 found_tag = FALSE; /* have a proc name; check if extern */
2289 get_tagname = FALSE; /* have found "procedure" keyword */
2290 inparms = FALSE; /* found '(' after "proc" */
2291 verify_tag = FALSE; /* check if "extern" is ahead */
2293 /* long main loop to get next char */
2294 while (!feof (fi))
2296 c = *dbp++;
2297 if (c == 0) /* if end of line */
2299 GET_NEW_LINE;
2300 if (*dbp == 0)
2301 continue;
2302 if (!((found_tag && verify_tag) ||
2303 get_tagname))
2304 c = *dbp++; /* only if don't need *dbp pointing */
2305 /* to the beginning of the name of */
2306 /* the procedure or function */
2308 if (incomm1) /* within { - } comments */
2310 if (c == '}')
2311 incomm1 = FALSE;
2312 continue;
2314 else if (incomm2) /* within (* - *) comments */
2316 if (c == '*')
2318 while ((c = *dbp++) == '*')
2319 continue;
2320 if (c == 0)
2321 GET_NEW_LINE;
2322 if (c == ')')
2323 incomm2 = FALSE;
2325 continue;
2327 else if (inquote)
2329 if (c == '\'')
2330 inquote = FALSE;
2331 continue;
2333 else
2334 switch (c)
2336 case '\'':
2337 inquote = TRUE; /* found first quote */
2338 continue;
2339 case '{': /* found open-{-comment */
2340 incomm1 = TRUE;
2341 continue;
2342 case '(':
2343 if (*dbp == '*') /* found open-(*-comment */
2345 incomm2 = TRUE;
2346 dbp++;
2348 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2349 inparms = TRUE;
2350 continue;
2351 case ')': /* end of parms list */
2352 if (inparms)
2353 inparms = FALSE;
2354 continue;
2355 case ';':
2356 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2358 verify_tag = TRUE;
2359 break;
2361 continue;
2363 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2365 /* check if this is an "extern" declaration */
2366 if (*dbp == 0)
2367 continue;
2368 if ((*dbp == 'e') || (*dbp == 'E'))
2370 if (tail ("extern")) /* superfluous, really! */
2372 found_tag = FALSE;
2373 verify_tag = FALSE;
2376 else if ((*dbp == 'f') || (*dbp == 'F'))
2378 if (tail ("forward")) /* check for forward reference */
2380 found_tag = FALSE;
2381 verify_tag = FALSE;
2384 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2386 found_tag = FALSE;
2387 verify_tag = FALSE;
2388 pfnote (nambuf, TRUE, FALSE,
2389 tline.buffer, cp - tline.buffer + 1,
2390 save_lineno, save_lcno);
2391 continue;
2394 if (get_tagname) /* grab name of proc or fn */
2396 if (*dbp == 0)
2397 continue;
2399 /* save all values for later tagging */
2400 tline.size = lb.size;
2401 strcpy (tline.buffer, lb.buffer);
2402 save_lineno = lineno;
2403 save_lcno = linecharno;
2405 /* grab block name */
2406 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2407 continue;
2408 c = cp[0];
2409 cp[0] = 0;
2410 strcpy (nambuf, dbp);
2411 cp[0] = c;
2412 dbp = cp; /* restore dbp to e-o-token */
2413 get_tagname = FALSE;
2414 found_tag = TRUE;
2415 continue;
2417 /* and proceed to check for "extern" */
2419 if ((!incomm1) && (!incomm2) && (!inquote) &&
2420 (!found_tag) && (!get_tagname))
2422 /* check for proc/fn keywords */
2423 switch (c | ' ')
2425 case 'p':
2426 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2427 get_tagname = TRUE;
2428 continue;
2429 case 'f':
2430 if (tail ("unction"))
2431 get_tagname = TRUE;
2432 continue;
2435 } /* while not e-o-f */
2439 * lisp tag functions
2440 * just look for (def or (DEF
2443 void
2444 L_funcs (fi)
2445 FILE *fi;
2447 lineno = 0;
2448 charno = 0;
2449 pfcnt = 0;
2451 while (!feof (fi))
2453 lineno++;
2454 linecharno = charno;
2455 charno += readline (&lb, fi);
2456 dbp = lb.buffer;
2457 if (dbp[0] == '(')
2459 if (L_isdef (dbp))
2461 while (!isspace (*dbp))
2462 dbp++;
2463 while (isspace (*dbp))
2464 dbp++;
2465 L_getit ();
2467 else
2469 /* Check for (foo::defmumble name-defined ... */
2471 dbp++;
2472 while (*dbp && !isspace (*dbp)
2473 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2474 if (*dbp == ':')
2477 dbp++;
2478 while (*dbp == ':');
2480 if (L_isdef (dbp - 1))
2482 while (!isspace (*dbp))
2483 dbp++;
2484 while (isspace (*dbp))
2485 dbp++;
2486 L_getit ();
2495 L_isdef (dbp)
2496 register char *dbp;
2498 return ((dbp[1] == 'd' || dbp[1] == 'D')
2499 && (dbp[2] == 'e' || dbp[2] == 'E')
2500 && (dbp[3] == 'f' || dbp[3] == 'F'));
2504 L_isquote (dbp)
2505 register char *dbp;
2507 return ((*(++dbp) == 'q' || *dbp == 'Q')
2508 && (*(++dbp) == 'u' || *dbp == 'U')
2509 && (*(++dbp) == 'o' || *dbp == 'O')
2510 && (*(++dbp) == 't' || *dbp == 'T')
2511 && (*(++dbp) == 'e' || *dbp == 'E')
2512 && isspace(*(++dbp)));
2515 void
2516 L_getit ()
2518 register char *cp;
2519 char c;
2520 char nambuf[BUFSIZ];
2522 if (*dbp == '\'') /* Skip prefix quote */
2523 dbp++;
2524 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2526 dbp += 7;
2527 while (isspace(*dbp))
2528 dbp++;
2530 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
2531 continue;
2532 if (cp == dbp)
2533 return;
2535 c = cp[0];
2536 cp[0] = 0;
2537 strcpy (nambuf, dbp);
2538 cp[0] = c;
2539 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2540 cp - lb.buffer + 1, lineno, linecharno);
2541 pfcnt++;
2545 * Scheme tag functions
2546 * look for (def... xyzzy
2547 * look for (def... (xyzzy
2548 * look for (def ... ((...(xyzzy ....
2549 * look for (set! xyzzy
2552 static void get_scheme ();
2554 void
2555 Scheme_funcs (fi)
2556 FILE *fi;
2558 lineno = 0;
2559 charno = 0;
2560 pfcnt = 0;
2562 while (!feof (fi))
2564 lineno++;
2565 linecharno = charno;
2566 charno += readline (&lb, fi);
2567 dbp = lb.buffer;
2568 if (dbp[0] == '(' &&
2569 (dbp[1] == 'D' || dbp[1] == 'd') &&
2570 (dbp[2] == 'E' || dbp[2] == 'e') &&
2571 (dbp[3] == 'F' || dbp[3] == 'f'))
2573 while (!isspace (*dbp))
2574 dbp++;
2575 /* Skip over open parens and white space */
2576 while (*dbp && (isspace (*dbp) || *dbp == '('))
2577 dbp++;
2578 get_scheme ();
2580 if (dbp[0] == '(' &&
2581 (dbp[1] == 'S' || dbp[1] == 's') &&
2582 (dbp[2] == 'E' || dbp[2] == 'e') &&
2583 (dbp[3] == 'T' || dbp[3] == 't') &&
2584 (dbp[4] == '!' || dbp[4] == '!') &&
2585 (isspace (dbp[5])))
2587 while (!isspace (*dbp))
2588 dbp++;
2589 /* Skip over white space */
2590 while (isspace (*dbp))
2591 dbp++;
2592 get_scheme ();
2597 static void
2598 get_scheme ()
2600 register char *cp;
2601 char c;
2602 char nambuf[BUFSIZ];
2604 if (*dbp == 0)
2605 return;
2606 /* Go till you get to white space or a syntactic break */
2607 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2608 continue;
2609 /* Null terminate the string there. */
2610 c = cp[0];
2611 cp[0] = 0;
2612 /* Copy the string */
2613 strcpy (nambuf, dbp);
2614 /* Unterminate the string */
2615 cp[0] = c;
2616 /* Announce the change */
2617 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2618 pfcnt++;
2621 /* Find tags in TeX and LaTeX input files. */
2623 /* TEX_toktab is a table of TeX control sequences that define tags.
2624 Each TEX_tabent records one such control sequence.
2625 CONVERT THIS TO USE THE Stab TYPE!! */
2627 struct TEX_tabent
2629 char *name;
2630 int len;
2633 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2635 /* Default set of control sequences to put into TEX_toktab.
2636 The value of environment var TEXTAGS is prepended to this. */
2638 static char *TEX_defenv =
2639 ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2641 void TEX_mode ();
2642 struct TEX_tabent *TEX_decode_env ();
2643 void TEX_getit ();
2644 int TEX_Token ();
2646 static char TEX_esc = '\\';
2647 static char TEX_opgrp = '{';
2648 static char TEX_clgrp = '}';
2651 * TeX/LaTeX scanning loop.
2654 void
2655 TEX_funcs (fi)
2656 FILE *fi;
2658 char *lasthit;
2660 lineno = 0;
2661 charno = 0;
2662 pfcnt = 0;
2664 /* Select either \ or ! as escape character. */
2665 TEX_mode (fi);
2667 /* Initialize token table once from environment. */
2668 if (!TEX_toktab)
2669 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2671 while (!feof (fi))
2672 { /* Scan each line in file */
2673 lineno++;
2674 linecharno = charno;
2675 charno += readline (&lb, fi);
2676 dbp = lb.buffer;
2677 lasthit = dbp;
2678 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
2680 register int i;
2682 if (!*(++dbp))
2683 break;
2684 linecharno += dbp - lasthit;
2685 lasthit = dbp;
2686 i = TEX_Token (lasthit);
2687 if (0 <= i)
2689 TEX_getit (lasthit, TEX_toktab[i].len);
2690 break; /* We only save a line once */
2696 #define TEX_LESC '\\'
2697 #define TEX_SESC '!'
2698 #define TEX_cmt '%'
2700 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2701 /* chars accordingly. */
2703 void
2704 TEX_mode (f)
2705 FILE *f;
2707 int c;
2709 while ((c = getc (f)) != EOF)
2711 /* Skip to next line if we hit the TeX comment char. */
2712 if (c == TEX_cmt)
2713 while (c != '\n')
2714 c = getc (f);
2715 else if (c == TEX_LESC || c == TEX_SESC )
2716 break;
2719 if (c == TEX_LESC)
2721 TEX_esc = TEX_LESC;
2722 TEX_opgrp = '{';
2723 TEX_clgrp = '}';
2725 else
2727 TEX_esc = TEX_SESC;
2728 TEX_opgrp = '<';
2729 TEX_clgrp = '>';
2731 rewind (f);
2734 /* Read environment and prepend it to the default string. */
2735 /* Build token table. */
2737 struct TEX_tabent *
2738 TEX_decode_env (evarname, defenv)
2739 char *evarname;
2740 char *defenv;
2742 register char *env, *p;
2744 struct TEX_tabent *tab;
2745 int size, i;
2747 /* Append default string to environment. */
2748 env = getenv (evarname);
2749 if (!env)
2750 env = defenv;
2751 else
2752 env = concat (env, defenv, "");
2754 /* Allocate a token table */
2755 for (size = 1, p = env; p;)
2756 if ((p = etags_strchr (p, ':')) && *(++p))
2757 size++;
2758 /* Add 1 to leave room for null terminator. */
2759 tab = xnew (size + 1, struct TEX_tabent);
2761 /* Unpack environment string into token table. Be careful about */
2762 /* zero-length strings (leading ':', "::" and trailing ':') */
2763 for (i = 0; *env;)
2765 p = etags_strchr (env, ':');
2766 if (!p) /* End of environment string. */
2767 p = env + strlen (env);
2768 if (p - env > 0)
2769 { /* Only non-zero strings. */
2770 tab[i].name = savenstr (env, p - env);
2771 tab[i].len = strlen (tab[i].name);
2772 i++;
2774 if (*p)
2775 env = p + 1;
2776 else
2778 tab[i].name = NULL; /* Mark end of table. */
2779 tab[i].len = 0;
2780 break;
2783 return tab;
2786 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
2787 The name being defined actually starts at (NAME + LEN + 1).
2788 But we seem to include the TeX command in the tag name. */
2790 void
2791 TEX_getit (name, len)
2792 char *name;
2793 int len;
2795 char *p = name + len;
2796 char nambuf[BUFSIZ];
2798 if (*name == 0)
2799 return;
2801 /* Let tag name extend to next group close (or end of line) */
2802 while (*p && *p != TEX_clgrp)
2803 p++;
2804 strncpy (nambuf, name, p - name);
2805 nambuf[p - name] = 0;
2807 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2808 pfcnt++;
2811 /* If the text at CP matches one of the tag-defining TeX command names,
2812 return the pointer to the first occurrence of that command in TEX_toktab.
2813 Otherwise return -1. */
2815 /* Keep the capital `T' in `Token' for dumb truncating compilers
2816 (this distinguishes it from `TEX_toktab' */
2818 TEX_Token (cp)
2819 char *cp;
2821 int i;
2823 for (i = 0; TEX_toktab[i].len > 0; i++)
2824 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
2825 return i;
2826 return -1;
2829 /* Support for Prolog. */
2831 /* whole head (not only functor, but also arguments)
2832 is gotten in compound term. */
2834 void
2835 prolog_getit (s, lineno, linecharno)
2836 char *s;
2837 int lineno;
2838 long linecharno;
2840 char nambuf[BUFSIZ], *save_s, tmpc;
2841 int insquote, npar;
2843 save_s = s;
2844 insquote = FALSE;
2845 npar = 0;
2846 while (1)
2848 if (*s == '\0') /* syntax error. */
2849 return;
2850 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2851 s += 2;
2852 else if (*s == '\'')
2854 insquote = !insquote;
2855 s++;
2857 else if (!insquote && *s == '(')
2859 npar++;
2860 s++;
2862 else if (!insquote && *s == ')')
2864 npar--;
2865 s++;
2866 if (npar == 0)
2867 break;
2868 else if (npar < 0) /* syntax error. */
2869 return;
2871 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2872 { /* fullstop. */
2873 if (npar != 0) /* syntax error. */
2874 return;
2875 s++;
2876 break;
2878 else
2879 s++;
2881 tmpc = *s;
2882 *s = '\0';
2883 strcpy (nambuf, save_s);
2884 *s = tmpc;
2885 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
2888 /* It is assumed that prolog predicate starts from column 0. */
2890 void
2891 prolog_funcs (fi)
2892 FILE *fi;
2894 void skip_comment (), prolog_getit ();
2896 lineno = linecharno = charno = 0;
2897 while (!feof (fi))
2899 lineno++;
2900 linecharno += charno;
2901 charno = readline (&lb, fi) + 1; /* 1 for newline. */
2902 dbp = lb.buffer;
2903 if (isspace (dbp[0])) /* not predicate header. */
2904 continue;
2905 else if (dbp[0] == '%') /* comment. */
2906 continue;
2907 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2908 skip_comment (&lb, fi, &lineno, &linecharno);
2909 else /* found. */
2910 prolog_getit (dbp, lineno, linecharno);
2914 void
2915 skip_comment (plb, fi, plineno, plinecharno)
2916 struct linebuffer *plb;
2917 FILE *fi;
2918 int *plineno; /* result */
2919 long *plinecharno; /* result */
2921 while (!substr ("*/", plb->buffer))
2923 (*plineno)++;
2924 *plinecharno += readline (plb, fi) + 1;
2925 } /* 1 for newline. */
2928 /* Return TRUE if 'sub' exists somewhere in 's'. */
2931 substr (sub, s)
2932 char *sub;
2933 char *s;
2935 while (*s && (s = etags_strchr (s, *sub)))
2936 if (prestr (sub, s))
2937 return (TRUE);
2938 else
2939 s++;
2940 return (FALSE);
2943 /* Return TRUE if 'pre' is prefix of string 's'. */
2946 prestr (pre, s)
2947 char *pre;
2948 char *s;
2950 if (*pre == '\0')
2951 return (TRUE);
2952 else if (*pre == *s)
2953 return (prestr (pre + 1, s + 1));
2954 else
2955 return (FALSE);
2958 /* Initialize a linebuffer for use */
2960 void
2961 initbuffer (linebuffer)
2962 struct linebuffer *linebuffer;
2964 linebuffer->size = 200;
2965 linebuffer->buffer = xnew (200, char);
2969 * Read a line of text from `stream' into `linebuffer'.
2970 * Return the number of characters read from `stream',
2971 * which is the length of the line including the newline, if any.
2973 long
2974 readline (linebuffer, stream)
2975 struct linebuffer *linebuffer;
2976 register FILE *stream;
2978 char *buffer = linebuffer->buffer;
2979 register char *p = linebuffer->buffer;
2980 register char *pend;
2981 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2983 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
2985 while (1)
2987 register int c = getc (stream);
2988 if (p == pend)
2990 linebuffer->size *= 2;
2991 buffer = (char *) xrealloc (buffer, linebuffer->size);
2992 p += buffer - linebuffer->buffer;
2993 pend = buffer + linebuffer->size;
2994 linebuffer->buffer = buffer;
2996 if (c == EOF || c == '\n')
2998 *p = 0;
2999 newline = (c == '\n') ? 1 : 0;
3000 break;
3002 *p++ = c;
3005 return p - buffer + newline;
3008 char *
3009 savestr (cp)
3010 char *cp;
3012 return savenstr (cp, strlen (cp));
3015 char *
3016 savenstr (cp, len)
3017 char *cp;
3018 int len;
3020 register char *dp;
3022 dp = xnew (len + 1, char);
3023 strncpy (dp, cp, len);
3024 dp[len] = '\0';
3025 return dp;
3029 * Return the ptr in sp at which the character c last
3030 * appears; NULL if not found
3032 * Identical to System V strrchr, included for portability.
3035 char *
3036 etags_strrchr (sp, c)
3037 register char *sp, c;
3039 register char *r;
3041 r = NULL;
3044 if (*sp == c)
3045 r = sp;
3046 } while (*sp++);
3047 return (r);
3052 * Return the ptr in sp at which the character c first
3053 * appears; NULL if not found
3055 * Identical to System V strchr, included for portability.
3058 char *
3059 etags_strchr (sp, c)
3060 register char *sp, c;
3064 if (*sp == c)
3065 return (sp);
3066 } while (*sp++);
3067 return (NULL);
3070 /* Print error message and exit. */
3072 /* VARARGS1 */
3073 void
3074 fatal (s1, s2)
3075 char *s1, *s2;
3077 error (s1, s2);
3078 exit (BAD);
3081 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3083 /* VARARGS1 */
3084 void
3085 error (s1, s2)
3086 char *s1, *s2;
3088 fprintf (stderr, "%s: ", progname);
3089 fprintf (stderr, s1, s2);
3090 fprintf (stderr, "\n");
3093 /* Return a newly-allocated string whose contents
3094 concatenate those of s1, s2, s3. */
3096 char *
3097 concat (s1, s2, s3)
3098 char *s1, *s2, *s3;
3100 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3101 char *result = xnew (len1 + len2 + len3 + 1, char);
3103 strcpy (result, s1);
3104 strcpy (result + len1, s2);
3105 strcpy (result + len1 + len2, s3);
3106 result[len1 + len2 + len3] = '\0';
3108 return result;
3111 /* Identical to system V getcwd, but does not need to guess
3112 buffer size in advance. Included mostly for compatibility. */
3113 char *
3114 etags_getcwd ()
3116 FILE *pipe;
3117 char *buf;
3118 int bufsize;
3122 buf = xnew (bufsize, char);
3124 pipe = popen ("pwd 2>/dev/null", "r");
3125 if (pipe == NULL)
3127 perror ("pwd");
3128 exit (BAD);
3130 if (fgets (buf, bufsize, pipe) == NULL)
3132 perror ("pwd");
3133 exit (BAD);
3135 pclose (pipe);
3137 bufsize *= 2;
3139 } while (buf[strlen (buf) - 1] != '\n');
3141 return buf;
3144 /* Return a newly allocated string containing the filename
3145 of FILE relative to the absolute directory DIR (which
3146 should end with a slash). */
3148 char *
3149 relative_filename (file, dir)
3150 char *file, *dir;
3152 char *fp, *dp, *res;
3154 /* Find the common root of file and dir. */
3155 fp = absolute_filename (file, cwd);
3156 dp = dir;
3157 while (*fp++ == *dp++)
3158 continue;
3161 fp--;
3162 dp--;
3164 while (*fp != '/');
3166 /* Build a sequence of "../" strings for the resulting relative filename. */
3167 for (dp = etags_strchr (dp + 1, '/'), res = "";
3168 dp != NULL;
3169 dp = etags_strchr (dp + 1, '/'))
3171 res = concat (res, "../", "");
3174 /* Add the filename relative to the common root of file and dir. */
3175 res = concat (res, fp + 1, "");
3177 return res; /* temporary stub */
3180 /* Return a newly allocated string containing the
3181 absolute filename of FILE given CWD (which should
3182 end with a slash). */
3184 char *
3185 absolute_filename (file, cwd)
3186 char *file, *cwd;
3188 char *slashp, *cp, *res;
3190 if (file[0] == '/')
3191 res = concat (file, "", "");
3192 else
3193 res = concat (cwd, file, "");
3195 /* Delete the "/dirname/.." and "/." substrings. */
3196 slashp = etags_strchr (res, '/');
3197 while (slashp != NULL && slashp[0] != '\0')
3199 if (slashp[1] == '.')
3201 if (slashp[2] == '.'
3202 && (slashp[3] == '/' || slashp[3] == '\0'))
3204 cp = slashp;
3206 cp--;
3207 while (cp >= res && *cp != '/');
3208 if (*cp == '/')
3210 strcpy (cp, slashp + 3);
3212 else /* else (cp == res) */
3214 if (slashp[3] != NULL)
3215 strcpy (cp, slashp + 4);
3216 else
3217 return ".";
3219 slashp = cp;
3221 else if (slashp[2] == '/' || slashp[2] == '\0')
3223 strcpy (slashp, slashp + 2);
3226 else
3228 slashp = etags_strchr (slashp + 1, '/');
3232 return res;
3235 /* Return a newly allocated string containing the absolute
3236 filename of dir where FILE resides given CWD (which should
3237 end with a slash). */
3239 char *
3240 absolute_dirname (file, cwd)
3241 char *file, *cwd;
3243 char *slashp, *res;
3244 char save;
3246 slashp = etags_strrchr (file, '/');
3247 if (slashp == NULL)
3248 return cwd;
3249 save = slashp[1];
3250 slashp[1] = '\0';
3251 res = absolute_filename (file, cwd);
3252 slashp[1] = save;
3254 return res;
3257 /* Like malloc but get fatal error if memory is exhausted. */
3259 char *
3260 xmalloc (size)
3261 unsigned int size;
3263 char *result = (char *) malloc (size);
3264 if (result == NULL)
3265 fatal ("virtual memory exhausted", 0);
3266 return result;
3269 char *
3270 xrealloc (ptr, size)
3271 char *ptr;
3272 unsigned int size;
3274 char *result = (char *) realloc (ptr, size);
3275 if (result == NULL)
3276 fatal ("virtual memory exhausted");
3277 return result;