* etags.c (pfatal): New function.
[bpt/emacs.git] / lib-src / etags.c
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
3 This file is not considered part of GNU Emacs.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18
19 /*
20 * Authors:
21 * Ctags originally by Ken Arnold.
22 * Fortran added by Jim Kleckner.
23 * Ed Pelegri-Llopart added C typedefs.
24 * Gnu Emacs TAGS format and modifications by RMS?
25 * Sam Kendall added C++.
26 * Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
27 #ifdef ETAGS_REGEXPS
28 * Regexp tags by Tom Tromey.
29 #endif
30 *
31 * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
32 */
33
34 char pot_etags_version[] = "@(#) pot revision number is 11.14";
35
36 #ifdef MSDOS
37 #include <fcntl.h>
38 #include <sys/param.h>
39 #endif /* MSDOS */
40
41 #ifdef WINDOWSNT
42 #include <stdlib.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #define MAXPATHLEN _MAX_PATH
46 #endif
47
48 #ifdef HAVE_CONFIG_H
49 #include <config.h>
50 /* On some systems, Emacs defines static as nothing for the sake
51 of unexec. We don't want that here since we don't use unexec. */
52 #undef static
53 #endif
54
55 #include <stdio.h>
56 #include <ctype.h>
57 #include <errno.h>
58 #ifndef errno
59 extern int errno;
60 #endif
61 #include <sys/types.h>
62 #include <sys/stat.h>
63
64 #if !defined (S_ISREG) && defined (S_IFREG)
65 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
66 #endif
67
68 #include <getopt.h>
69
70 #ifdef ETAGS_REGEXPS
71 #include <regex.h>
72 #endif /* ETAGS_REGEXPS */
73
74 extern char *getenv ();
75
76 /* Define CTAGS to make the program "ctags" compatible with the usual one.
77 Let it undefined to make the program "etags", which makes emacs-style
78 tag tables and tags typedefs, #defines and struct/union/enum by default. */
79 #ifdef CTAGS
80 # undef CTAGS
81 # define CTAGS TRUE
82 #else
83 # define CTAGS FALSE
84 #endif
85
86 /* Exit codes for success and failure. */
87 #ifdef VMS
88 #define GOOD 1
89 #define BAD 0
90 #else
91 #define GOOD 0
92 #define BAD 1
93 #endif
94
95 /*
96 * The FILEPOS abstract type, which represents a position in a file,
97 * plus the following accessor functions:
98 *
99 * long GET_CHARNO (pos)
100 * returns absolute char number.
101 * void SET_FILEPOS (pos, fp, charno)
102 * FILE *fp; long charno;
103 * sets `pos' from the current file
104 * position of `fp' and from `charno',
105 * which must be the absolute character
106 * number corresponding to the current
107 * position of `fp'.
108 *
109 * The `pos' parameter is an lvalue expression of type FILEPOS.
110 * Parameters to the accessor functions are evaluated 0 or more times,
111 * and so must have no side effects.
112 *
113 * FILEPOS objects can also be assigned and passed to and from
114 * functions in the normal C manner.
115 *
116 * Implementation notes: the `+ 0' is to enforce rvalue-ness.
117 */
118
119 #ifndef DEBUG
120 #define DEBUG FALSE
121
122 /* real implementation */
123 typedef long FILEPOS;
124 #define GET_CHARNO(pos) ((pos) + 0)
125 #define SET_FILEPOS(pos,fp,cno) ((void) ((pos) = (cno)))
126
127 #else
128 #undef DEBUG
129 #define DEBUG TRUE
130
131 /* debugging implementation */
132 typedef struct
133 {
134 long charno;
135 } FILEPOS;
136
137 #define GET_CHARNO(pos) ((pos).charno + 0)
138 #define SET_FILEPOS(pos,fp,cno) \
139 ((void) ((pos).charno = (cno), \
140 (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
141 : 0))
142 #endif
143
144 #define streq(s,t) (strcmp (s, t) == 0)
145 #define strneq(s,t,n) (strncmp (s, t, n) == 0)
146
147 #define TRUE 1
148 #define FALSE 0
149
150 #define iswhite(arg) (_wht[arg]) /* T if char is white */
151 #define begtoken(arg) (_btk[arg]) /* T if char can start token */
152 #define intoken(arg) (_itk[arg]) /* T if char can be in token */
153 #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
154
155 #define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
156
157 typedef int logical;
158
159 struct nd_st
160 { /* sorting structure */
161 char *name; /* function or type name */
162 char *file; /* file name */
163 logical is_func; /* use pattern or line no */
164 logical named; /* list name separately */
165 logical been_warned; /* set if noticed dup */
166 int lno; /* line number tag is on */
167 long cno; /* character number line starts on */
168 char *pat; /* search pattern */
169 struct nd_st *left, *right; /* left and right sons */
170 };
171
172 typedef struct nd_st NODE;
173
174 /* boolean "functions" (see init) */
175 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
176
177 char *cwd; /* current working directory */
178 char *tagfiledir; /* directory of tagfile */
179
180 char *concat ();
181 char *savenstr (), *savestr ();
182 char *etags_strchr (), *etags_strrchr ();
183 char *etags_getcwd ();
184 char *relative_filename (), *absolute_filename (), *absolute_dirname ();
185 char *xmalloc (), *xrealloc ();
186
187 typedef void Lang_function ();
188 #if FALSE /* many compilers barf on this */
189 Lang_function Asm_labels;
190 Lang_function default_C_entries;
191 Lang_function C_entries;
192 Lang_function Cplusplus_entries;
193 Lang_function Cstar_entries;
194 Lang_function Fortran_functions;
195 Lang_function Yacc_entries;
196 Lang_function Lisp_functions;
197 Lang_function Pascal_functions;
198 Lang_function Prolog_functions;
199 Lang_function Scheme_functions;
200 Lang_function TeX_functions;
201 Lang_function just_read_file;
202 #else /* so let's write it this way */
203 void Asm_labels ();
204 void default_C_entries ();
205 void C_entries ();
206 void Cplusplus_entries ();
207 void Cstar_entries ();
208 void Fortran_functions ();
209 void Yacc_entries ();
210 void Lisp_functions ();
211 void Pascal_functions ();
212 void Prolog_functions ();
213 void Scheme_functions ();
214 void TeX_functions ();
215 void just_read_file ();
216 #endif
217
218 logical get_language ();
219 int total_size_of_entries ();
220 long readline ();
221 long readline_internal ();
222 #ifdef ETAGS_REGEXPS
223 void add_regex ();
224 #endif
225 void add_node ();
226 void error ();
227 void fatal (), pfatal ();
228 logical find_entries ();
229 void free_tree ();
230 void getit ();
231 void init ();
232 void initbuffer ();
233 void pfnote ();
234 void process_file ();
235 void put_entries ();
236 void takeprec ();
237
238 /*
239 * MACRO
240 * xnew -- allocate storage
241 *
242 * SYNOPSIS
243 * Type *xnew (int n, Type);
244 */
245 #define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
246
247 /*
248 * Symbol table types.
249 */
250 enum sym_type
251 {
252 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
253 };
254 \f
255
256
257 typedef int LINENO;
258
259 typedef struct
260 {
261 char *p;
262 int len;
263 LINENO lineno;
264 logical named;
265 } TOKEN;
266
267 /* C extensions.
268 */
269 #define C_PLPL 0x00001 /* C++ */
270 #define C_STAR 0x00003 /* C* */
271 #define YACC 0x10000 /* yacc file */
272
273 char searchar = '/'; /* use /.../ searches */
274
275 LINENO lineno; /* line number of current line */
276 long charno; /* current character number */
277
278 long linecharno; /* charno of start of line; not used by C, but
279 * by every other language.
280 */
281
282 char *curfile, /* current input file name */
283 *tagfile, /* output file */
284 *white = " \f\t\n\013", /* white chars */
285 *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
286 /* token starting chars */
287 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
288 /* valid in-token chars */
289 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
290
291 int append_to_tagfile; /* -a: append to tags */
292 /* The following three default to 1 for etags, but to 0 for ctags. */
293 int typedefs; /* -t: create tags for typedefs */
294 int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
295 /* 0 struct/enum/union decls, and C++ */
296 /* member functions. */
297 int constantypedefs; /* -d: create tags for C #define and enum */
298 /* constants. Enum consts not implemented. */
299 /* -D: opposite of -d. Default under ctags. */
300 int update; /* -u: update tags */
301 int vgrind_style; /* -v: create vgrind style index output */
302 int no_warnings; /* -w: suppress warnings */
303 int cxref_style; /* -x: create cxref style output */
304 int cplusplus; /* .[hc] means C++, not C */
305 int noindentypedefs; /* -S: ignore indentation in C */
306
307 /* Name this program was invoked with. */
308 char *progname;
309
310 struct option longopts[] =
311 {
312 { "append", no_argument, NULL, 'a' },
313 { "backward-search", no_argument, NULL, 'B' },
314 { "c++", no_argument, NULL, 'C' },
315 { "cxref", no_argument, NULL, 'x' },
316 { "defines", no_argument, NULL, 'd' },
317 { "help", no_argument, NULL, 'h' },
318 { "help", no_argument, NULL, 'H' },
319 { "ignore-indentation", no_argument, NULL, 'S' },
320 { "include", required_argument, NULL, 'i' },
321 { "language", required_argument, NULL, 'l' },
322 { "no-defines", no_argument, NULL, 'D' },
323 { "no-regex", no_argument, NULL, 'R' },
324 { "no-warn", no_argument, NULL, 'w' },
325 { "output", required_argument, NULL, 'o' },
326 { "regex", required_argument, NULL, 'r' },
327 { "typedefs", no_argument, NULL, 't' },
328 { "typedefs-and-c++", no_argument, NULL, 'T' },
329 { "update", no_argument, NULL, 'u' },
330 { "version", no_argument, NULL, 'V' },
331 { "vgrind", no_argument, NULL, 'v' },
332 { 0 }
333 };
334
335 FILE *tagf; /* ioptr for tags file */
336 NODE *head; /* the head of the binary tree of tags */
337 logical permit_duplicates = TRUE; /* allow duplicate tags */
338
339 /*
340 * A `struct linebuffer' is a structure which holds a line of text.
341 * `readline' reads a line from a stream into a linebuffer and works
342 * regardless of the length of the line.
343 */
344 struct linebuffer
345 {
346 long size;
347 char *buffer;
348 };
349
350 struct linebuffer lb; /* the current line */
351 struct linebuffer filename_lb; /* used to read in filenames */
352 struct
353 {
354 FILEPOS linepos;
355 struct linebuffer lb; /* used by C_entries instead of lb */
356 } lbs[2];
357
358 #ifdef ETAGS_REGEXPS
359 /* Structure defining a regular expression. Elements are
360 the compiled pattern, and the name string. */
361 struct pattern
362 {
363 struct re_pattern_buffer *pattern;
364 struct re_registers regs;
365 char *name_pattern;
366 logical error_signaled;
367 };
368
369 /* Number of regexps found. */
370 int num_patterns = 0;
371
372 /* Array of all regexps. */
373 struct pattern *patterns = NULL;
374 #endif /* ETAGS_REGEXPS */
375
376 /* Language stuff. */
377 struct lang_entry
378 {
379 char *extension;
380 Lang_function *function;
381 };
382
383 /* Table of language names and corresponding functions. */
384 /* It is ok for a given function to be listed under more than one
385 name. I just didn't. */
386 /* "auto" language reverts to default behavior. */
387 struct lang_entry lang_names[] =
388 {
389 { "asm", Asm_labels },
390 { "c", default_C_entries },
391 { "c++", Cplusplus_entries },
392 { "c*", Cstar_entries },
393 { "fortran", Fortran_functions },
394 { "lisp", Lisp_functions },
395 { "none", just_read_file },
396 { "pascal", Pascal_functions },
397 { "scheme" , Scheme_functions },
398 { "tex", TeX_functions },
399 { "auto", NULL },
400 { NULL, NULL }
401 };
402
403 /* Table of file extensions and corresponding language functions. */
404 struct lang_entry lang_extensions[] =
405 {
406 /* Assume that ".s" or ".a" is assembly code. -wolfgang.
407 Or even ".sa". */
408 { "a", Asm_labels }, /* Unix assembler */
409 { "asm", Asm_labels }, /* Microcontroller assembly */
410 { "def", Asm_labels }, /* BSO/Tasking definition includes */
411 { "inc", Asm_labels }, /* Microcontroller include files */
412 { "ins", Asm_labels }, /* Microcontroller include files */
413 { "s", Asm_labels },
414 { "sa", Asm_labels }, /* Unix assembler */
415 { "src", Asm_labels }, /* BSO/Tasking C compiler output */
416
417 /* .aux, .bbl, .clo, .cls, .dtx or .tex implies LaTeX source code. */
418 { "aux", TeX_functions },
419 { "bbl", TeX_functions },
420 { "clo", TeX_functions },
421 { "cls", TeX_functions },
422 { "dtx", TeX_functions },
423 { "sty", TeX_functions },
424 { "tex", TeX_functions },
425
426 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
427 { "cl", Lisp_functions },
428 { "clisp", Lisp_functions },
429 { "el", Lisp_functions },
430 { "l", Lisp_functions },
431 { "lisp", Lisp_functions },
432 { "lsp", Lisp_functions },
433
434 /* .scm or .sm or .scheme implies scheme source code */
435 { "SCM", Scheme_functions },
436 { "SM", Scheme_functions },
437 { "oak", Scheme_functions },
438 { "sch", Scheme_functions },
439 { "scheme", Scheme_functions },
440 { "scm", Scheme_functions },
441 { "sm", Scheme_functions },
442 { "t", Scheme_functions },
443 /* FIXME Can't do the `SCM' or `scm' prefix with a version number */
444
445 /* Note that ".c" and ".h" can be considered C++, if the --c++
446 flag was given. That is why default_C_entries is called here. */
447 { "c", default_C_entries },
448 { "h", default_C_entries },
449
450 /* .C or .H or .cpp or .cxx or .hxx or .hh or .cc or .cpp: a C++ file */
451 { "C", Cplusplus_entries },
452 { "H", Cplusplus_entries },
453 { "cc", Cplusplus_entries },
454 { "cpp", Cplusplus_entries },
455 { "cxx", Cplusplus_entries },
456 { "hh", Cplusplus_entries },
457 { "hxx", Cplusplus_entries },
458
459 /* .y: a yacc file */
460 { "y", Yacc_entries },
461
462 /* .cs or .hs: a C* file */
463 { "cs", Cstar_entries },
464 { "hs", Cstar_entries },
465
466 /* .f and .for are FORTRAN. */
467 { "F", Fortran_functions },
468 { "f", Fortran_functions },
469 { "for", Fortran_functions },
470
471 /* .pl implies prolog source code */
472 { "pl", Prolog_functions },
473
474 /* .p or .pas: a Pascal file */
475 { "p", Pascal_functions },
476 { "pas", Pascal_functions },
477
478 { NULL, NULL }
479 };
480
481 /* Non-NULL if language fixed. */
482 Lang_function *lang_func = NULL;
483
484 \f
485 void
486 print_language_names ()
487 {
488 struct lang_entry *name, *ext;
489
490 puts ("\nThese are the currently supported languages, along with the\n\
491 default extensions for files:");
492 for (name = lang_names; name->extension; ++name)
493 {
494 printf ("\t%s\t", name->extension);
495 for (ext = lang_extensions; ext->extension; ++ext)
496 if (name->function == ext->function)
497 printf (" .%s", ext->extension);
498 puts ("");
499 }
500 puts ("Where `auto' means use default language for files based on filename\n\
501 extension, and `none' means only do regexp processing on files.\n\
502 If no language is specified and no extension is found for some file,\n\
503 Fortran is tried first; if no tags are found, C is tried next.");
504 }
505
506 void
507 print_version ()
508 {
509 #ifdef VERSION
510 printf ("%s for Emacs version %s.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
511 #else
512 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
513 #endif
514
515 exit (GOOD);
516 }
517
518 void
519 print_help ()
520 {
521 printf ("These are the options accepted by %s. You may use unambiguous\n\
522 abbreviations for the long option names. A - as file name means read\n\
523 names from stdin.\n\n", progname);
524
525 puts ("-a, --append\n\
526 Append tag entries to existing tags file.");
527
528 if (CTAGS)
529 puts ("-B, --backward-search\n\
530 Write the search commands for the tag entries using '?', the\n\
531 backward-search command instead of '/', the forward-search command.");
532
533 puts ("-C, --c++\n\
534 Treat files whose extension defaults to C language as C++ files.");
535
536 if (CTAGS)
537 puts ("-d, --defines\n\
538 Create tag entries for constant C #defines, too.");
539 else
540 puts ("-D, --no-defines\n\
541 Don't create tag entries for constant C #defines. This makes\n\
542 the tags file smaller.");
543
544 if (!CTAGS)
545 {
546 puts ("-i FILE, --include=FILE\n\
547 Include a note in tag file indicating that, when searching for\n\
548 a tag, one should also consult the tags file FILE after\n\
549 checking the current file.");
550 puts ("-l LANG, --language=LANG\n\
551 Force the following files to be considered as written in the\n\
552 named language up to the next --language=LANG option.");
553 }
554
555 #ifdef ETAGS_REGEXPS
556 puts ("-r /REGEXP/, --regex=/REGEXP/\n\
557 Make a tag for each line matching pattern REGEXP in the\n\
558 following files. REGEXP is anchored (as if preceded by ^).\n\
559 The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
560 named tags can be created with:\n\
561 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
562 puts ("-R, --no-regex\n\
563 Don't create tags from regexps for the following files.");
564 #endif /* ETAGS_REGEXPS */
565 puts ("-o FILE, --output=FILE\n\
566 Write the tags to FILE.");
567 puts ("-S, --ignore-indentation\n\
568 Don't rely on indentation quite as much as normal. Currently,\n\
569 this means not to assume that a closing brace in the first\n\
570 column is the final brace of a function or structure\n\
571 definition in C and C++.");
572
573 if (CTAGS)
574 {
575 puts ("-t, --typedefs\n\
576 Generate tag entries for C typedefs.");
577 puts ("-T, --typedefs-and-c++\n\
578 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
579 and C++ member functions.");
580 puts ("-u, --update\n\
581 Update the tag entries for the given files, leaving tag\n\
582 entries for other files in place. Currently, this is\n\
583 implemented by deleting the existing entries for the given\n\
584 files and then rewriting the new entries at the end of the\n\
585 tags file. It is often faster to simply rebuild the entire\n\
586 tag file than to use this.");
587 puts ("-v, --vgrind\n\
588 Generates an index of items intended for human consumption,\n\
589 similar to the output of vgrind. The index is sorted, and\n\
590 gives the page number of each item.");
591 puts ("-w, --no-warn\n\
592 Suppress warning messages about entries defined in multiple\n\
593 files.");
594 puts ("-x, --cxref\n\
595 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
596 The output uses line numbers instead of page numbers, but\n\
597 beyond that the differences are cosmetic; try both to see\n\
598 which you like.");
599 }
600
601 puts ("-V, --version\n\
602 Print the version of the program.\n\
603 -h, --help\n\
604 Print this help message.");
605
606 print_language_names ();
607
608 exit (GOOD);
609 }
610
611 \f
612 enum argument_type
613 {
614 at_language,
615 at_regexp,
616 at_filename
617 };
618
619 /* This structure helps us allow mixing of --lang and filenames. */
620 typedef struct
621 {
622 enum argument_type arg_type;
623 char *what;
624 Lang_function *function;
625 } ARGUMENT;
626
627 #ifdef VMS /* VMS specific functions */
628
629 #define EOS '\0'
630
631 /* This is a BUG! ANY arbitrary limit is a BUG!
632 Won't someone please fix this? */
633 #define MAX_FILE_SPEC_LEN 255
634 typedef struct {
635 short curlen;
636 char body[MAX_FILE_SPEC_LEN + 1];
637 } vspec;
638
639 /*
640 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
641 returning in each successive call the next filename matching the input
642 spec. The function expects that each in_spec passed
643 to it will be processed to completion; in particular, up to and
644 including the call following that in which the last matching name
645 is returned, the function ignores the value of in_spec, and will
646 only start processing a new spec with the following call.
647 If an error occurs, on return out_spec contains the value
648 of in_spec when the error occurred.
649
650 With each successive filename returned in out_spec, the
651 function's return value is one. When there are no more matching
652 names the function returns zero. If on the first call no file
653 matches in_spec, or there is any other error, -1 is returned.
654 */
655
656 #include <rmsdef.h>
657 #include <descrip.h>
658 #define OUTSIZE MAX_FILE_SPEC_LEN
659 short
660 fn_exp (out, in)
661 vspec *out;
662 char *in;
663 {
664 static long context = 0;
665 static struct dsc$descriptor_s o;
666 static struct dsc$descriptor_s i;
667 static logical pass1 = TRUE;
668 long status;
669 short retval;
670
671 if (pass1)
672 {
673 pass1 = FALSE;
674 o.dsc$a_pointer = (char *) out;
675 o.dsc$w_length = (short)OUTSIZE;
676 i.dsc$a_pointer = in;
677 i.dsc$w_length = (short)strlen(in);
678 i.dsc$b_dtype = DSC$K_DTYPE_T;
679 i.dsc$b_class = DSC$K_CLASS_S;
680 o.dsc$b_dtype = DSC$K_DTYPE_VT;
681 o.dsc$b_class = DSC$K_CLASS_VS;
682 }
683 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
684 {
685 out->body[out->curlen] = EOS;
686 return 1;
687 }
688 else if (status == RMS$_NMF)
689 retval = 0;
690 else
691 {
692 strcpy(out->body, in);
693 retval = -1;
694 }
695 lib$find_file_end(&context);
696 pass1 = TRUE;
697 return retval;
698 }
699
700 /*
701 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
702 name of each file specified by the provided arg expanding wildcards.
703 */
704 char *
705 gfnames (arg, p_error)
706 char *arg;
707 logical *p_error;
708 {
709 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
710
711 switch (fn_exp (&filename, arg))
712 {
713 case 1:
714 *p_error = FALSE;
715 return filename.body;
716 case 0:
717 *p_error = FALSE;
718 return NULL;
719 default:
720 *p_error = TRUE;
721 return filename.body;
722 }
723 }
724
725 #ifndef OLD /* Newer versions of VMS do provide `system'. */
726 system (cmd)
727 char *cmd;
728 {
729 fprintf (stderr, "system() function not implemented under VMS\n");
730 }
731 #endif
732
733 #define VERSION_DELIM ';'
734 char *massage_name (s)
735 char *s;
736 {
737 char *start = s;
738
739 for ( ; *s; s++)
740 if (*s == VERSION_DELIM)
741 {
742 *s = EOS;
743 break;
744 }
745 else
746 *s = tolower(*s);
747 return start;
748 }
749 #endif /* VMS */
750
751 \f
752 void
753 main (argc, argv)
754 int argc;
755 char *argv[];
756 {
757 char cmd[100];
758 int i;
759 unsigned int nincluded_files = 0;
760 char **included_files = xnew (argc, char *);
761 char *this_file;
762 ARGUMENT *argbuffer;
763 int current_arg = 0, file_count = 0;
764 #ifdef VMS
765 logical got_err;
766 #endif
767
768 #ifdef DOS_NT
769 _fmode = O_BINARY; /* all of files are treated as binary files */
770 #endif /* DOS_NT */
771
772 progname = argv[0];
773
774 /* Allocate enough no matter what happens. Overkill, but each one
775 is small. */
776 argbuffer = xnew (argc, ARGUMENT);
777
778 #ifdef ETAGS_REGEXPS
779 /* Set syntax for regular expression routines. */
780 re_set_syntax (RE_SYNTAX_EMACS);
781 #endif /* ETAGS_REGEXPS */
782
783 /*
784 * If etags, always find typedefs and structure tags. Why not?
785 * Also default is to find macro constants.
786 */
787 if (!CTAGS)
788 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
789
790 while (1)
791 {
792 int opt = getopt_long (argc, argv,
793 "-aCdDf:l:o:r:RStTi:BuvxwVhH", longopts, 0);
794
795 if (opt == EOF)
796 break;
797
798 switch (opt)
799 {
800 case 0:
801 /* If getopt returns 0, then it has already processed a
802 long-named option. We should do nothing. */
803 break;
804
805 case 1:
806 /* This means that a filename has been seen. Record it. */
807 argbuffer[current_arg].arg_type = at_filename;
808 argbuffer[current_arg].what = optarg;
809 ++current_arg;
810 ++file_count;
811 break;
812
813 /* Common options. */
814 case 'a':
815 append_to_tagfile++;
816 break;
817 case 'C':
818 cplusplus = 1;
819 break;
820 case 'd':
821 constantypedefs = 1;
822 break;
823 case 'D':
824 constantypedefs = 0;
825 break;
826 case 'f': /* for compatibility with old makefiles */
827 case 'o':
828 if (tagfile)
829 {
830 fprintf(stderr,
831 "%s: -%c flag may only be given once.\n", progname, opt);
832 goto usage;
833 }
834 tagfile = optarg;
835 break;
836 case 'l':
837 if (!get_language (optarg, &argbuffer[current_arg].function))
838 {
839 fprintf (stderr, "%s: language \"%s\" not recognized.\n",
840 progname, optarg);
841 goto usage;
842 }
843 argbuffer[current_arg].arg_type = at_language;
844 ++current_arg;
845 break;
846 #ifdef ETAGS_REGEXPS
847 case 'r':
848 argbuffer[current_arg].arg_type = at_regexp;
849 argbuffer[current_arg].what = optarg;
850 ++current_arg;
851 break;
852 case 'R':
853 argbuffer[current_arg].arg_type = at_regexp;
854 argbuffer[current_arg].what = NULL;
855 ++current_arg;
856 break;
857 #endif /* ETAGS_REGEXPS */
858 case 'S':
859 noindentypedefs++;
860 break;
861 case 'V':
862 print_version ();
863 break;
864 case 'h':
865 case 'H':
866 print_help ();
867 break;
868 case 't':
869 typedefs++;
870 break;
871 case 'T':
872 typedefs++;
873 typedefs_and_cplusplus++;
874 break;
875 #if (!CTAGS)
876 /* Etags options */
877 case 'i':
878 included_files[nincluded_files++] = optarg;
879 break;
880 #else /* CTAGS */
881 /* Ctags options. */
882 case 'B':
883 searchar = '?';
884 break;
885 case 'u':
886 update++;
887 break;
888 case 'v':
889 vgrind_style++;
890 /*FALLTHRU*/
891 case 'x':
892 cxref_style++;
893 break;
894 case 'w':
895 no_warnings++;
896 break;
897 #endif /* CTAGS */
898 default:
899 fprintf (stderr,
900 "%s: -%c flag not recognised.\n", progname, opt);
901 goto usage;
902 }
903 }
904
905 for (; optind < argc; ++optind)
906 {
907 argbuffer[current_arg].arg_type = at_filename;
908 argbuffer[current_arg].what = argv[optind];
909 ++current_arg;
910 ++file_count;
911 }
912
913 if (nincluded_files == 0 && file_count == 0)
914 {
915 fprintf (stderr, "%s: No input files specified.\n", progname);
916
917 usage:
918 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
919 progname, progname);
920 exit (BAD);
921 }
922
923 if (tagfile == NULL)
924 {
925 tagfile = CTAGS ? "tags" : "TAGS";
926 }
927 cwd = etags_getcwd (); /* the current working directory */
928 strcat (cwd, "/");
929 if (streq (tagfile, "-"))
930 {
931 tagfiledir = cwd;
932 }
933 else
934 {
935 tagfiledir = absolute_dirname (tagfile, cwd);
936 }
937
938 init (); /* set up boolean "functions" */
939
940 initbuffer (&lb);
941 initbuffer (&lbs[0].lb);
942 initbuffer (&lbs[1].lb);
943 initbuffer (&filename_lb);
944
945 if (!CTAGS)
946 {
947 if (streq (tagfile, "-"))
948 tagf = stdout;
949 else
950 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
951 if (tagf == NULL)
952 pfatal (tagfile);
953 }
954
955 /*
956 * Loop through files finding functions.
957 */
958 for (i = 0; i < current_arg; ++i)
959 {
960 switch (argbuffer[i].arg_type)
961 {
962 case at_language:
963 lang_func = argbuffer[i].function;
964 break;
965 #ifdef ETAGS_REGEXPS
966 case at_regexp:
967 add_regex (argbuffer[i].what);
968 break;
969 #endif
970 case at_filename:
971 #ifdef VMS
972 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
973 {
974 if (got_err)
975 {
976 error ("Can't find file %s\n", this_file);
977 argc--, argv++;
978 }
979 else
980 {
981 this_file = massage_name (this_file);
982 }
983 #else
984 this_file = argbuffer[i].what;
985 #endif
986 /* Input file named "-" means read file names from stdin
987 and use them. */
988 if (streq (this_file, "-"))
989 {
990 while (!feof (stdin))
991 {
992 /* Use readline_internal so that regexp matching */
993 /* is not done on filenames. */
994 (void) readline_internal (&filename_lb, stdin);
995 if (strlen (filename_lb.buffer) > 0)
996 process_file (filename_lb.buffer);
997 }
998 }
999 else
1000 process_file (this_file);
1001 #ifdef VMS
1002 }
1003 #endif
1004 break;
1005 }
1006 }
1007
1008 if (!CTAGS)
1009 {
1010 while (nincluded_files-- > 0)
1011 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1012
1013 (void) fclose (tagf);
1014 exit (GOOD);
1015 }
1016
1017 if (cxref_style)
1018 {
1019 put_entries (head);
1020 exit (GOOD);
1021 }
1022 if (update)
1023 {
1024 for (i = 0; i < current_arg; ++i)
1025 {
1026 if (argbuffer[i].arg_type == at_language)
1027 continue;
1028 sprintf (cmd,
1029 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1030 tagfile, argbuffer[i].what, tagfile);
1031 (void) system (cmd);
1032 }
1033 append_to_tagfile++;
1034 }
1035 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1036 if (tagf == NULL)
1037 {
1038 perror (tagfile);
1039 exit (GOOD);
1040 }
1041 put_entries (head);
1042 (void) fclose (tagf);
1043 if (update)
1044 {
1045 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
1046 (void) system (cmd);
1047 }
1048 exit (GOOD);
1049 }
1050
1051
1052 /*
1053 * Set the language, given the name.
1054 */
1055 logical
1056 get_language (language, func)
1057 char *language;
1058 Lang_function **func;
1059 {
1060 struct lang_entry *lang;
1061
1062 for (lang = lang_names; lang->extension; ++lang)
1063 {
1064 if (streq (language, lang->extension))
1065 {
1066 *func = lang->function;
1067 return TRUE;
1068 }
1069 }
1070
1071 return FALSE;
1072 }
1073
1074
1075 /*
1076 * This routine is called on each file argument.
1077 */
1078 void
1079 process_file (file)
1080 char *file;
1081 {
1082 struct stat stat_buf;
1083
1084 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
1085 {
1086 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
1087 return;
1088 }
1089 if (streq (file, tagfile) && !streq (tagfile, "-"))
1090 {
1091 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
1092 return;
1093 }
1094 if (!find_entries (file))
1095 {
1096 return;
1097 }
1098 if (!CTAGS)
1099 {
1100 char *filename;
1101
1102 if (file[0] == '/')
1103 {
1104 /* file is an absolute filename. Canonicalise it. */
1105 filename = absolute_filename (file, cwd);
1106 }
1107 else
1108 {
1109 /* file is a filename relative to cwd. Make it relative
1110 to the directory of the tags file. */
1111 filename = relative_filename (file, tagfiledir);
1112 }
1113 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1114 put_entries (head);
1115 free_tree (head);
1116 head = NULL;
1117 }
1118 }
1119
1120 /*
1121 * This routine sets up the boolean pseudo-functions which work
1122 * by setting boolean flags dependent upon the corresponding character
1123 * Every char which is NOT in that string is not a white char. Therefore,
1124 * all of the array "_wht" is set to FALSE, and then the elements
1125 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1126 * of a char is TRUE if it is the string "white", else FALSE.
1127 */
1128 void
1129 init ()
1130 {
1131 register char *sp;
1132 register int i;
1133
1134 for (i = 0; i < 0177; i++)
1135 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
1136 for (sp = white; *sp; sp++)
1137 _wht[*sp] = TRUE;
1138 for (sp = endtk; *sp; sp++)
1139 _etk[*sp] = TRUE;
1140 for (sp = intk; *sp; sp++)
1141 _itk[*sp] = TRUE;
1142 for (sp = begtk; *sp; sp++)
1143 _btk[*sp] = TRUE;
1144 _wht[0] = _wht['\n'];
1145 _etk[0] = _etk['\n'];
1146 _btk[0] = _btk['\n'];
1147 _itk[0] = _itk['\n'];
1148 }
1149
1150 /*
1151 * This routine opens the specified file and calls the function
1152 * which finds the function and type definitions.
1153 */
1154 logical
1155 find_entries (file)
1156 char *file;
1157 {
1158 FILE *inf;
1159 char *cp;
1160 struct lang_entry *lang;
1161 NODE *old_last_node;
1162 extern NODE *last_node;
1163
1164 inf = fopen (file, "r");
1165 if (inf == NULL)
1166 {
1167 perror (file);
1168 return FALSE;
1169 }
1170 curfile = savestr (file);
1171 cp = etags_strrchr (file, '.');
1172
1173 /* If user specified a language, use it. */
1174 if (lang_func != NULL)
1175 {
1176 lang_func (inf);
1177 fclose (inf);
1178 return TRUE;
1179 }
1180
1181 if (cp)
1182 {
1183 ++cp;
1184 for (lang = lang_extensions; lang->extension; ++lang)
1185 {
1186 if (streq (cp, lang->extension))
1187 {
1188 lang->function (inf);
1189 fclose (inf);
1190 return TRUE;
1191 }
1192 }
1193 }
1194
1195 /* Try Fortran. */
1196 old_last_node = last_node;
1197 Fortran_functions (inf);
1198
1199 /* No Fortran entries found. Try C. */
1200 if (old_last_node == last_node)
1201 default_C_entries (inf);
1202 fclose (inf);
1203 return TRUE;
1204 }
1205 \f
1206 /* Record a tag. */
1207 /* Should take a TOKEN* instead!! */
1208 void
1209 pfnote (name, is_func, named, linestart, linelen, lno, cno)
1210 char *name; /* tag name */
1211 logical is_func; /* function or type name? */
1212 logical named; /* tag different from text of definition? */
1213 char *linestart;
1214 int linelen;
1215 int lno;
1216 long cno;
1217 {
1218 register char *fp;
1219 register NODE *np;
1220 char tem[51];
1221 char c;
1222
1223 np = xnew (1, NODE);
1224 if (np == NULL)
1225 {
1226 if (CTAGS)
1227 {
1228 /* It's okay to output early in etags -- it only disrupts the
1229 * character count of the tag entries, which is no longer used
1230 * by tags.el anyway.
1231 */
1232 error ("too many entries to sort", 0);
1233 }
1234 put_entries (head);
1235 free_tree (head);
1236 head = NULL;
1237 np = xnew (1, NODE);
1238 }
1239 /* If ctags mode, change name "main" to M<thisfilename>. */
1240 if (CTAGS && !cxref_style && streq (name, "main"))
1241 {
1242 fp = etags_strrchr (curfile, '/');
1243 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
1244 fp = etags_strrchr (name, '.');
1245 if (fp && fp[1] != '\0' && fp[2] == '\0')
1246 *fp = 0;
1247 named = TRUE;
1248 }
1249 np->name = savestr (name);
1250 np->file = curfile;
1251 np->is_func = is_func;
1252 np->named = named;
1253 np->lno = lno;
1254 /* Our char numbers are 0-base, because of C language tradition?
1255 ctags compatibility? old versions compatibility? I don't know.
1256 Anyway, since emacs's are 1-base we espect etags.el to take care
1257 of the difference. If we wanted to have 1-based numbers, we would
1258 uncomment the +1 below. */
1259 np->cno = cno /* + 1 */ ;
1260 np->left = np->right = 0;
1261 if (!CTAGS)
1262 {
1263 c = linestart[linelen];
1264 linestart[linelen] = 0;
1265 }
1266 else if (cxref_style == 0)
1267 {
1268 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
1269 linestart = tem;
1270 }
1271 np->pat = savestr (linestart);
1272 if (!CTAGS)
1273 {
1274 linestart[linelen] = c;
1275 }
1276
1277 add_node (np, &head);
1278 }
1279
1280 /*
1281 * free_tree ()
1282 * recurse on left children, iterate on right children.
1283 */
1284 void
1285 free_tree (node)
1286 register NODE *node;
1287 {
1288 while (node)
1289 {
1290 register NODE *node_right = node->right;
1291 free_tree (node->left);
1292 free (node->name);
1293 free (node->pat);
1294 free ((char *) node);
1295 node = node_right;
1296 }
1297 }
1298
1299 /*
1300 * add_node ()
1301 * Adds a node to the tree of nodes. In etags mode, we don't keep
1302 * it sorted; we just keep a linear list. In ctags mode, maintain
1303 * an ordered tree, with no attempt at balancing.
1304 *
1305 * add_node is the only function allowed to add nodes, so it can
1306 * maintain state.
1307 */
1308 NODE *last_node = NULL;
1309 void
1310 add_node (node, cur_node_p)
1311 NODE *node, **cur_node_p;
1312 {
1313 register int dif;
1314 register NODE *cur_node = *cur_node_p;
1315
1316 if (cur_node == NULL)
1317 {
1318 *cur_node_p = node;
1319 last_node = node;
1320 return;
1321 }
1322
1323 if (!CTAGS)
1324 {
1325 /* Etags Mode */
1326 if (last_node == NULL)
1327 fatal ("internal error in add_node", 0);
1328 last_node->right = node;
1329 last_node = node;
1330 }
1331 else
1332 {
1333 /* Ctags Mode */
1334 dif = strcmp (node->name, cur_node->name);
1335
1336 /*
1337 * If this tag name matches an existing one, then
1338 * do not add the node, but maybe print a warning.
1339 */
1340 if (!dif)
1341 {
1342 if (node->file == cur_node->file)
1343 {
1344 if (!no_warnings)
1345 {
1346 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1347 node->file, lineno, node->name);
1348 fprintf (stderr, "Second entry ignored\n");
1349 }
1350 return;
1351 }
1352 if (!cur_node->been_warned && !no_warnings)
1353 {
1354 fprintf (stderr,
1355 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1356 node->file, cur_node->file, node->name);
1357 }
1358 cur_node->been_warned = TRUE;
1359 return;
1360 }
1361
1362 /* Maybe refuse to add duplicate nodes. */
1363 if (!permit_duplicates)
1364 {
1365 if (streq (node->name, cur_node->name)
1366 && streq (node->file, cur_node->file))
1367 return;
1368 }
1369
1370 /* Actually add the node */
1371 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1372 }
1373 }
1374 \f
1375 void
1376 put_entries (node)
1377 register NODE *node;
1378 {
1379 register char *sp;
1380
1381 if (node == NULL)
1382 return;
1383
1384 /* Output subentries that precede this one */
1385 put_entries (node->left);
1386
1387 /* Output this entry */
1388
1389 if (!CTAGS)
1390 {
1391 if (node->named)
1392 {
1393 fprintf (tagf, "%s\177%s\001%d,%d\n",
1394 node->pat, node->name,
1395 node->lno, node->cno);
1396 }
1397 else
1398 {
1399 fprintf (tagf, "%s\177%d,%d\n",
1400 node->pat,
1401 node->lno, node->cno);
1402 }
1403 }
1404 else if (!cxref_style)
1405 {
1406 fprintf (tagf, "%s\t%s\t",
1407 node->name, node->file);
1408
1409 if (node->is_func)
1410 { /* a function */
1411 putc (searchar, tagf);
1412 putc ('^', tagf);
1413
1414 for (sp = node->pat; *sp; sp++)
1415 {
1416 if (*sp == '\\' || *sp == searchar)
1417 putc ('\\', tagf);
1418 putc (*sp, tagf);
1419 }
1420 putc (searchar, tagf);
1421 }
1422 else
1423 { /* a typedef; text pattern inadequate */
1424 fprintf (tagf, "%d", node->lno);
1425 }
1426 putc ('\n', tagf);
1427 }
1428 else if (vgrind_style)
1429 fprintf (stdout, "%s %s %d\n",
1430 node->name, node->file, (node->lno + 63) / 64);
1431 else
1432 fprintf (stdout, "%-16s %3d %-16s %s\n",
1433 node->name, node->lno, node->file, node->pat);
1434
1435 /* Output subentries that follow this one */
1436 put_entries (node->right);
1437 }
1438
1439 /* Length of a number's decimal representation. */
1440 int
1441 number_len (num)
1442 long num;
1443 {
1444 int len = 0;
1445 if (!num)
1446 return 1;
1447 for (; num; num /= 10)
1448 ++len;
1449 return len;
1450 }
1451
1452 /*
1453 * Return total number of characters that put_entries will output for
1454 * the nodes in the subtree of the specified node. Works only if
1455 * we are not ctags, but called only in that case. This count
1456 * is irrelevant with the new tags.el, but is still supplied for
1457 * backward compatibility.
1458 */
1459 int
1460 total_size_of_entries (node)
1461 register NODE *node;
1462 {
1463 register int total;
1464
1465 if (node == NULL)
1466 return 0;
1467
1468 total = 0;
1469 for (; node; node = node->right)
1470 {
1471 /* Count left subentries. */
1472 total += total_size_of_entries (node->left);
1473
1474 /* Count this entry */
1475 total += strlen (node->pat) + 1;
1476 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1477 if (node->named)
1478 total += 1 + strlen (node->name); /* \001name */
1479 }
1480
1481 return total;
1482 }
1483 \f
1484 /*
1485 * The C symbol tables.
1486 */
1487
1488 /* Feed stuff between (but not including) %[ and %] lines to:
1489 gperf -c -k1,3 -o -p -r -t
1490 %[
1491 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1492 %%
1493 class, C_PLPL, st_C_struct
1494 domain, C_STAR, st_C_struct
1495 union, 0, st_C_struct
1496 struct, 0, st_C_struct
1497 enum, 0, st_C_enum
1498 typedef, 0, st_C_typedef
1499 define, 0, st_C_define
1500 long, 0, st_C_typespec
1501 short, 0, st_C_typespec
1502 int, 0, st_C_typespec
1503 char, 0, st_C_typespec
1504 float, 0, st_C_typespec
1505 double, 0, st_C_typespec
1506 signed, 0, st_C_typespec
1507 unsigned, 0, st_C_typespec
1508 auto, 0, st_C_typespec
1509 void, 0, st_C_typespec
1510 extern, 0, st_C_typespec
1511 static, 0, st_C_typespec
1512 const, 0, st_C_typespec
1513 volatile, 0, st_C_typespec
1514 %]
1515 and replace lines between %< and %> with its output. */
1516 /*%<*/
1517 /* C code produced by gperf version 1.8.1 (K&R C version) */
1518 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1519
1520
1521 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1522
1523 #define MIN_WORD_LENGTH 3
1524 #define MAX_WORD_LENGTH 8
1525 #define MIN_HASH_VALUE 10
1526 #define MAX_HASH_VALUE 62
1527 /*
1528 21 keywords
1529 53 is the maximum key range
1530 */
1531
1532 static int
1533 hash (str, len)
1534 register char *str;
1535 register int len;
1536 {
1537 static unsigned char hash_table[] =
1538 {
1539 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1540 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1541 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1542 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1543 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1544 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1545 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1546 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1547 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1548 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1549 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1550 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1551 62, 62, 62, 62, 62, 62, 62, 62,
1552 };
1553 return len + hash_table[str[2]] + hash_table[str[0]];
1554 }
1555
1556 struct C_stab_entry *
1557 in_word_set (str, len)
1558 register char *str;
1559 register int len;
1560 {
1561
1562 static struct C_stab_entry wordlist[] =
1563 {
1564 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1565 {"",},
1566 {"volatile", 0, st_C_typespec},
1567 {"",},
1568 {"long", 0, st_C_typespec},
1569 {"char", 0, st_C_typespec},
1570 {"class", C_PLPL, st_C_struct},
1571 {"",}, {"",}, {"",}, {"",},
1572 {"const", 0, st_C_typespec},
1573 {"",}, {"",}, {"",}, {"",},
1574 {"auto", 0, st_C_typespec},
1575 {"",}, {"",},
1576 {"define", 0, st_C_define},
1577 {"",},
1578 {"void", 0, st_C_typespec},
1579 {"",}, {"",}, {"",},
1580 {"extern", 0, st_C_typespec},
1581 {"static", 0, st_C_typespec},
1582 {"",},
1583 {"domain", C_STAR, st_C_struct},
1584 {"",},
1585 {"typedef", 0, st_C_typedef},
1586 {"double", 0, st_C_typespec},
1587 {"enum", 0, st_C_enum},
1588 {"",}, {"",}, {"",}, {"",},
1589 {"int", 0, st_C_typespec},
1590 {"",},
1591 {"float", 0, st_C_typespec},
1592 {"",}, {"",}, {"",},
1593 {"struct", 0, st_C_struct},
1594 {"",}, {"",}, {"",}, {"",},
1595 {"union", 0, st_C_struct},
1596 {"",},
1597 {"short", 0, st_C_typespec},
1598 {"",}, {"",},
1599 {"unsigned", 0, st_C_typespec},
1600 {"signed", 0, st_C_typespec},
1601 };
1602
1603 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1604 {
1605 register int key = hash (str, len);
1606
1607 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1608 {
1609 register char *s = wordlist[key].name;
1610
1611 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1612 return &wordlist[key];
1613 }
1614 }
1615 return 0;
1616 }
1617 /*%>*/
1618
1619 enum sym_type
1620 C_symtype(str, len, c_ext)
1621 char *str;
1622 int len;
1623 int c_ext;
1624 {
1625 register struct C_stab_entry *se = in_word_set(str, len);
1626
1627 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1628 return st_none;
1629 return se->type;
1630 }
1631 \f
1632 /*
1633 * C functions are recognized using a simple finite automaton.
1634 * funcdef is its state variable.
1635 */
1636 typedef enum
1637 {
1638 fnone, /* nothing seen */
1639 ftagseen, /* function-like tag seen */
1640 fstartlist, /* just after open parenthesis */
1641 finlist, /* in parameter list */
1642 flistseen, /* after parameter list */
1643 fignore /* before open brace */
1644 } FUNCST;
1645 FUNCST funcdef;
1646
1647
1648 /*
1649 * typedefs are recognized using a simple finite automaton.
1650 * typeddef is its state variable.
1651 */
1652 typedef enum
1653 {
1654 tnone, /* nothing seen */
1655 ttypedseen, /* typedef keyword seen */
1656 tinbody, /* inside typedef body */
1657 tend, /* just before typedef tag */
1658 tignore /* junk after typedef tag */
1659 } TYPEDST;
1660 TYPEDST typdef;
1661
1662
1663 /*
1664 * struct-like structures (enum, struct and union) are recognized
1665 * using another simple finite automaton. `structdef' is its state
1666 * variable.
1667 */
1668 typedef enum
1669 {
1670 snone, /* nothing seen yet */
1671 skeyseen, /* struct-like keyword seen */
1672 stagseen, /* struct-like tag seen */
1673 scolonseen, /* colon seen after struct-like tag */
1674 sinbody /* in struct body: recognize member func defs*/
1675 } STRUCTST;
1676 STRUCTST structdef;
1677
1678 /*
1679 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1680 * struct tag, and structtype is the type of the preceding struct-like
1681 * keyword.
1682 */
1683 char structtag[BUFSIZ];
1684 enum sym_type structtype;
1685
1686 /*
1687 * Yet another little state machine to deal with preprocessor lines.
1688 */
1689 typedef enum
1690 {
1691 dnone, /* nothing seen */
1692 dsharpseen, /* '#' seen as first char on line */
1693 ddefineseen, /* '#' and 'define' seen */
1694 dignorerest /* ignore rest of line */
1695 } DEFINEST;
1696 DEFINEST definedef;
1697
1698 /*
1699 * Set this to TRUE, and the next token considered is called a function.
1700 * Used only for GNU emacs's function-defining macros.
1701 */
1702 logical next_token_is_func;
1703
1704 /*
1705 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1706 */
1707 logical yacc_rules;
1708
1709 /*
1710 * consider_token ()
1711 * checks to see if the current token is at the start of a
1712 * function, or corresponds to a typedef, or is a struct/union/enum
1713 * tag.
1714 *
1715 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1716 * C_EXT is which language we are looking at.
1717 *
1718 * In the future we will need some way to adjust where the end of
1719 * the token is; for instance, implementing the C++ keyword
1720 * `operator' properly will adjust the end of the token to be after
1721 * whatever follows `operator'.
1722 *
1723 * Globals
1724 * funcdef IN OUT
1725 * structdef IN OUT
1726 * definedef IN OUT
1727 * typdef IN OUT
1728 * next_token_is_func IN OUT
1729 */
1730
1731 logical
1732 consider_token (c, tokp, c_ext, cblev, is_func)
1733 register char c; /* IN: first char after the token */
1734 register TOKEN *tokp; /* IN: token pointer */
1735 int c_ext; /* IN: C extensions mask */
1736 int cblev; /* IN: curly brace level */
1737 logical *is_func; /* OUT: function found */
1738 {
1739 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1740
1741 /*
1742 * Advance the definedef state machine.
1743 */
1744 switch (definedef)
1745 {
1746 case dnone:
1747 /* We're not on a preprocessor line. */
1748 break;
1749 case dsharpseen:
1750 if (toktype == st_C_define)
1751 {
1752 definedef = ddefineseen;
1753 }
1754 else
1755 {
1756 definedef = dignorerest;
1757 }
1758 return FALSE;
1759 case ddefineseen:
1760 /*
1761 * Make a tag for any macro, unless it is a constant
1762 * and constantypedefs is FALSE.
1763 */
1764 definedef = dignorerest;
1765 *is_func = (c == '(');
1766 if (!*is_func && !constantypedefs)
1767 return FALSE;
1768 else
1769 return TRUE;
1770 case dignorerest:
1771 return FALSE;
1772 default:
1773 error ("internal error: definedef value.", 0);
1774 }
1775
1776 /*
1777 * Now typedefs
1778 */
1779 switch (typdef)
1780 {
1781 case tnone:
1782 if (toktype == st_C_typedef)
1783 {
1784 if (typedefs)
1785 typdef = ttypedseen;
1786 funcdef = fnone;
1787 return FALSE;
1788 }
1789 break;
1790 case ttypedseen:
1791 switch (toktype)
1792 {
1793 case st_none:
1794 case st_C_typespec:
1795 typdef = tend;
1796 break;
1797 case st_C_struct:
1798 case st_C_enum:
1799 break;
1800 }
1801 /* Do not return here, so the structdef stuff has a chance. */
1802 break;
1803 case tend:
1804 switch (toktype)
1805 {
1806 case st_C_typespec:
1807 case st_C_struct:
1808 case st_C_enum:
1809 return FALSE;
1810 }
1811 return TRUE;
1812 }
1813
1814 /*
1815 * This structdef business is currently only invoked when cblev==0.
1816 * It should be recursively invoked whatever the curly brace level,
1817 * and a stack of states kept, to allow for definitions of structs
1818 * within structs.
1819 *
1820 * This structdef business is NOT invoked when we are ctags and the
1821 * file is plain C. This is because a struct tag may have the same
1822 * name as another tag, and this loses with ctags.
1823 *
1824 * This if statement deals with the typdef state machine as
1825 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1826 * return FALSE. All the other code here is for the structdef
1827 * state machine.
1828 */
1829 switch (toktype)
1830 {
1831 case st_C_struct:
1832 case st_C_enum:
1833 if (typdef == ttypedseen
1834 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1835 {
1836 structdef = skeyseen;
1837 structtype = toktype;
1838 }
1839 return FALSE;
1840 }
1841 if (structdef == skeyseen)
1842 {
1843 if (structtype == st_C_struct)
1844 {
1845 strncpy (structtag, tokp->p, tokp->len);
1846 structtag[tokp->len] = '\0'; /* for struct/union/class */
1847 }
1848 else
1849 {
1850 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1851 }
1852 structdef = stagseen;
1853 return TRUE;
1854 }
1855
1856 /* Avoid entering funcdef stuff if typdef is going on. */
1857 if (typdef != tnone)
1858 {
1859 definedef = dnone;
1860 return FALSE;
1861 }
1862
1863 /* Detect GNU macros. */
1864 if (definedef == dnone)
1865 if (strneq (tokp->p, "DEFUN", 5) /* Used in emacs */
1866 #if FALSE
1867 These are defined inside C functions, so currently they
1868 are not met anyway.
1869 || strneq (tokp->p, "EXFUN", 5) /* Used in glibc */
1870 || strneq (tokp->p, "DEFVAR_", 7) /* Used in emacs */
1871 #endif
1872 || strneq (tokp->p, "SYSCALL", 7) /* Used in glibc (mach) */
1873 || strneq (tokp->p, "ENTRY", 5) /* Used in glibc */
1874 || strneq (tokp->p, "PSEUDO", 6)) /* Used in glibc */
1875
1876 {
1877 next_token_is_func = TRUE;
1878 return FALSE;
1879 }
1880 if (next_token_is_func)
1881 {
1882 next_token_is_func = FALSE;
1883 funcdef = fignore;
1884 *is_func = TRUE;
1885 return TRUE;
1886 }
1887
1888 /* A function? */
1889 switch (toktype)
1890 {
1891 case st_C_typespec:
1892 if (funcdef != finlist && funcdef != fignore)
1893 funcdef = fnone; /* should be useless */
1894 return FALSE;
1895 default:
1896 if (funcdef == fnone)
1897 {
1898 funcdef = ftagseen;
1899 *is_func = TRUE;
1900 return TRUE;
1901 }
1902 }
1903
1904 return FALSE;
1905 }
1906
1907 /*
1908 * C_entries ()
1909 * This routine finds functions, typedefs, #define's and
1910 * struct/union/enum definitions in C syntax and adds them
1911 * to the list.
1912 */
1913
1914 #define curlb (lbs[curndx].lb)
1915 #define othlb (lbs[1-curndx].lb)
1916 #define newlb (lbs[newndx].lb)
1917 #define curlinepos (lbs[curndx].linepos)
1918 #define othlinepos (lbs[1-curndx].linepos)
1919 #define newlinepos (lbs[newndx].linepos)
1920
1921 /* Save and restore token state. This is used when preprocessor defines
1922 are handled, to avoid disturbing active function/typedef/struct states. */
1923 #define TOKEN_SAVED_P (savetok.lineno > 0)
1924 #define SAVE_TOKEN (savetok = tok, savetok.p = (char *) tokoff, \
1925 savetok.len = toklen, strcpy(savenameb, nameb))
1926 #define RESTORE_TOKEN (tok = savetok, tokoff = (int) tok.p, \
1927 toklen = tok.len, strcpy(nameb, savenameb), \
1928 savetok.lineno = 0)
1929
1930 #define CNL_SAVE_DEFINEDEF \
1931 do { \
1932 SET_FILEPOS (curlinepos, inf, charno); \
1933 lineno++; \
1934 charno += readline (&curlb, inf); \
1935 lp = curlb.buffer; \
1936 quotednl = FALSE; \
1937 newndx = curndx; \
1938 } while (0)
1939
1940 #define CNL \
1941 do { \
1942 CNL_SAVE_DEFINEDEF; \
1943 if (TOKEN_SAVED_P) \
1944 RESTORE_TOKEN; \
1945 definedef = dnone; \
1946 } while (0)
1947
1948 #define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
1949 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1950 #define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
1951 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
1952
1953 void
1954 C_entries (c_ext, inf)
1955 int c_ext; /* extension of C */
1956 FILE *inf; /* input file */
1957 {
1958 register char c; /* latest char read; '\0' for end of line */
1959 register char *lp; /* pointer one beyond the character `c' */
1960 int curndx, newndx; /* indices for current and new lb */
1961 TOKEN tok; /* latest token read for funcdef & structdef */
1962 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
1963 register int tokoff; /* offset in line of start of latest token */
1964 register int toklen; /* length of latest token */
1965 int cblev; /* current curly brace level */
1966 int parlev; /* current parenthesis level */
1967 logical incomm, inquote, inchar, quotednl, midtoken;
1968 logical cplpl;
1969 TOKEN savetok; /* saved token during preprocessor handling */
1970 char savenameb[BUFSIZ]; /* ouch! */
1971
1972 savetok.lineno = 0;
1973 curndx = newndx = 0;
1974 lineno = 0;
1975 charno = 0;
1976 lp = curlb.buffer;
1977 *lp = 0;
1978
1979 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1980 next_token_is_func = yacc_rules = FALSE;
1981 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1982 cblev = 0;
1983 parlev = 0;
1984 cplpl = c_ext & C_PLPL;
1985
1986 while (!feof (inf))
1987 {
1988 c = *lp++;
1989 if (c == '\\')
1990 {
1991 /* If we're at the end of the line, the next character is a
1992 '\0'; don't skip it, because it's the thing that tells us
1993 to read the next line. */
1994 if (*lp == '\0')
1995 {
1996 quotednl = TRUE;
1997 continue;
1998 }
1999 lp++;
2000 c = ' ';
2001 }
2002 else if (incomm)
2003 {
2004 switch (c)
2005 {
2006 case '*':
2007 if (*lp == '/')
2008 {
2009 c = *lp++;
2010 incomm = FALSE;
2011 }
2012 break;
2013 case '\0':
2014 /* Newlines inside comments do not end macro definitions in
2015 traditional cpp. */
2016 CNL_SAVE_DEFINEDEF;
2017 break;
2018 }
2019 continue;
2020 }
2021 else if (inquote)
2022 {
2023 switch (c)
2024 {
2025 case '"':
2026 inquote = FALSE;
2027 break;
2028 case '\0':
2029 /* Newlines inside strings do not end macro definitions
2030 in traditional cpp, even though compilers don't
2031 usually accept them. */
2032 CNL_SAVE_DEFINEDEF;
2033 break;
2034 }
2035 continue;
2036 }
2037 else if (inchar)
2038 {
2039 switch (c)
2040 {
2041 case '\0':
2042 /* Hmmm, something went wrong. */
2043 CNL;
2044 /* FALLTHRU */
2045 case '\'':
2046 inchar = FALSE;
2047 break;
2048 }
2049 continue;
2050 }
2051 else
2052 switch (c)
2053 {
2054 case '"':
2055 inquote = TRUE;
2056 if (funcdef != finlist && funcdef != fignore)
2057 funcdef = fnone;
2058 continue;
2059 case '\'':
2060 inchar = TRUE;
2061 if (funcdef != finlist && funcdef != fignore)
2062 funcdef = fnone;
2063 continue;
2064 case '/':
2065 if (*lp == '*')
2066 {
2067 lp++;
2068 incomm = TRUE;
2069 continue;
2070 }
2071 else if (cplpl && *lp == '/')
2072 {
2073 c = 0;
2074 break;
2075 }
2076 else
2077 break;
2078 case '%':
2079 if ((c_ext & YACC) && *lp == '%')
2080 {
2081 /* entering or exiting rules section in yacc file */
2082 lp++;
2083 definedef = dnone; funcdef = fnone;
2084 typdef = tnone; structdef = snone;
2085 next_token_is_func = FALSE;
2086 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2087 cblev = 0;
2088 yacc_rules = !yacc_rules;
2089 continue;
2090 }
2091 else
2092 break;
2093 case '#':
2094 if (definedef == dnone)
2095 {
2096 char *cp;
2097 logical cpptoken = TRUE;
2098
2099 /* Look back on this line. If all blanks, or nonblanks
2100 followed by an end of comment, this is a preprocessor
2101 token. */
2102 for (cp = newlb.buffer; cp < lp-1; cp++)
2103 if (!iswhite (*cp))
2104 {
2105 if (*cp == '*' && *(cp+1) == '/')
2106 {
2107 cp++;
2108 cpptoken = TRUE;
2109 }
2110 else
2111 cpptoken = FALSE;
2112 }
2113 if (cpptoken)
2114 definedef = dsharpseen;
2115 } /* if (definedef == dnone) */
2116
2117 continue;
2118 } /* switch (c) */
2119
2120
2121 /* Consider token only if some complicated conditions are satisfied. */
2122 if ((definedef != dnone
2123 || (cblev == 0 && structdef != scolonseen)
2124 || (cblev == 1 && cplpl && structdef == sinbody))
2125 && typdef != tignore
2126 && definedef != dignorerest
2127 && funcdef != finlist)
2128 {
2129 if (midtoken)
2130 {
2131 if (endtoken (c))
2132 {
2133 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
2134 {
2135 /*
2136 * This handles :: in the middle, but not at the
2137 * beginning of an identifier.
2138 */
2139 lp += 2;
2140 toklen += 3;
2141 }
2142 else
2143 {
2144 logical is_func = FALSE;
2145
2146 tok.lineno = lineno;
2147 tok.p = newlb.buffer + tokoff;
2148 tok.len = toklen;
2149 tok.named = FALSE;
2150 if (yacc_rules
2151 || consider_token (c, &tok, c_ext, cblev, &is_func))
2152 {
2153 if (structdef == sinbody
2154 && definedef == dnone
2155 && is_func)
2156 /* function defined in C++ class body */
2157 {
2158 sprintf (nameb, "%s::%.*s",
2159 ((structtag[0] == '\0')
2160 ? "_anonymous_" : structtag),
2161 tok.len, tok.p);
2162 tok.named = TRUE;
2163 }
2164 else
2165 {
2166 sprintf (nameb, "%.*s", tok.len, tok.p);
2167 }
2168
2169 if (structdef == stagseen
2170 || typdef == tend
2171 || (is_func
2172 && definedef == dignorerest)) /* macro */
2173 tok.named = TRUE;
2174
2175 if (definedef == dnone
2176 && (funcdef == ftagseen
2177 || structdef == stagseen
2178 || typdef == tend))
2179 {
2180 if (newndx == curndx)
2181 curndx = 1 - curndx; /* switch line buffers */
2182 }
2183 else
2184 MAKE_TAG_FROM_NEW_LB (is_func);
2185 }
2186 midtoken = FALSE;
2187 }
2188 } /* if (endtoken (c)) */
2189 else if (intoken (c))
2190 {
2191 toklen++;
2192 continue;
2193 }
2194 } /* if (midtoken) */
2195 else if (begtoken (c))
2196 {
2197 switch (definedef)
2198 {
2199 case dnone:
2200 switch (funcdef)
2201 {
2202 case fstartlist:
2203 funcdef = finlist;
2204 continue;
2205 case flistseen:
2206 MAKE_TAG_FROM_OTH_LB (TRUE);
2207 funcdef = fignore;
2208 break;
2209 case ftagseen:
2210 funcdef = fnone;
2211 break;
2212 }
2213 if (structdef == stagseen)
2214 structdef = snone;
2215 break;
2216 case dsharpseen:
2217 /* Take a quick peek ahead for a define directive,
2218 so we can avoid saving the token when not absolutely
2219 necessary. [This is a speed hack.] */
2220 if (c == 'd' && strneq (lp, "efine", 5)
2221 && iswhite (*(lp + 5)))
2222 {
2223 SAVE_TOKEN;
2224 definedef = ddefineseen;
2225 lp += 6;
2226 }
2227 else
2228 definedef = dignorerest;
2229 continue;
2230 }
2231 if (!yacc_rules || lp == newlb.buffer + 1)
2232 {
2233 tokoff = lp - 1 - newlb.buffer;
2234 toklen = 1;
2235 midtoken = TRUE;
2236 }
2237 continue;
2238 }
2239 } /* if must look at token */
2240
2241
2242 /* Detect end of line, colon, comma, semicolon and various braces
2243 after having handled a token.*/
2244 switch (c)
2245 {
2246 case ':':
2247 if (definedef != dnone)
2248 break;
2249 if (structdef == stagseen)
2250 structdef = scolonseen;
2251 else
2252 switch (funcdef)
2253 {
2254 case ftagseen:
2255 if (yacc_rules)
2256 {
2257 MAKE_TAG_FROM_OTH_LB (FALSE);
2258 funcdef = fignore;
2259 }
2260 break;
2261 case fstartlist:
2262 funcdef = fnone;
2263 break;
2264 }
2265 break;
2266 case ';':
2267 if (definedef != dnone)
2268 break;
2269 if (cblev == 0)
2270 switch (typdef)
2271 {
2272 case tend:
2273 MAKE_TAG_FROM_OTH_LB (FALSE);
2274 /* FALLTHRU */
2275 default:
2276 typdef = tnone;
2277 }
2278 if (funcdef != fignore)
2279 funcdef = fnone;
2280 if (structdef == stagseen)
2281 structdef = snone;
2282 break;
2283 case ',':
2284 if (definedef != dnone)
2285 break;
2286 if (funcdef != finlist && funcdef != fignore)
2287 funcdef = fnone;
2288 if (structdef == stagseen)
2289 structdef = snone;
2290 break;
2291 case '[':
2292 if (definedef != dnone)
2293 break;
2294 if (cblev == 0 && typdef == tend)
2295 {
2296 typdef = tignore;
2297 MAKE_TAG_FROM_OTH_LB (FALSE);
2298 break;
2299 }
2300 if (funcdef != finlist && funcdef != fignore)
2301 funcdef = fnone;
2302 if (structdef == stagseen)
2303 structdef = snone;
2304 break;
2305 case '(':
2306 if (definedef != dnone)
2307 break;
2308 switch (funcdef)
2309 {
2310 case fnone:
2311 switch (typdef)
2312 {
2313 case ttypedseen:
2314 case tend:
2315 /* Make sure that the next char is not a '*'.
2316 This handles constructs like:
2317 typedef void OperatorFun (int fun); */
2318 if (*lp != '*')
2319 {
2320 typdef = tignore;
2321 MAKE_TAG_FROM_OTH_LB (FALSE);
2322 }
2323 break;
2324 } /* switch (typdef) */
2325 break;
2326 case ftagseen:
2327 funcdef = fstartlist;
2328 break;
2329 case flistseen:
2330 funcdef = finlist;
2331 break;
2332 }
2333 parlev++;
2334 break;
2335 case ')':
2336 if (definedef != dnone)
2337 break;
2338 if (--parlev == 0)
2339 {
2340 switch (funcdef)
2341 {
2342 case fstartlist:
2343 case finlist:
2344 funcdef = flistseen;
2345 break;
2346 }
2347 if (cblev == 0 && typdef == tend)
2348 {
2349 typdef = tignore;
2350 MAKE_TAG_FROM_OTH_LB (FALSE);
2351 }
2352 }
2353 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2354 parlev = 0;
2355 break;
2356 case '{':
2357 if (definedef != dnone)
2358 break;
2359 if (typdef == ttypedseen)
2360 typdef = tinbody;
2361 switch (structdef)
2362 {
2363 case skeyseen: /* unnamed struct */
2364 structtag[0] = '\0';
2365 structdef = sinbody;
2366 break;
2367 case stagseen:
2368 case scolonseen: /* named struct */
2369 structdef = sinbody;
2370 MAKE_TAG_FROM_OTH_LB (FALSE);
2371 break;
2372 }
2373 switch (funcdef)
2374 {
2375 case flistseen:
2376 MAKE_TAG_FROM_OTH_LB (TRUE);
2377 /* FALLTHRU */
2378 case fignore:
2379 funcdef = fnone;
2380 break;
2381 case fnone:
2382 /* Neutralize `extern "C" {' grot and look inside structs. */
2383 if (cblev == 0 && structdef == snone && typdef == tnone)
2384 cblev = -1;
2385 }
2386 cblev++;
2387 break;
2388 case '*':
2389 if (definedef != dnone)
2390 break;
2391 if (funcdef == fstartlist)
2392 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
2393 break;
2394 case '}':
2395 if (definedef != dnone)
2396 break;
2397 if (!noindentypedefs && lp == newlb.buffer + 1)
2398 {
2399 cblev = 0; /* reset curly brace level if first column */
2400 parlev = 0; /* also reset paren level, just in case... */
2401 }
2402 else if (cblev > 0)
2403 cblev--;
2404 if (cblev == 0)
2405 {
2406 if (typdef == tinbody)
2407 typdef = tend;
2408 structdef = snone;
2409 strcpy (structtag, "<error 2>");
2410 }
2411 break;
2412 case '=':
2413 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2414 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
2415 if (definedef != dnone)
2416 break;
2417 /* These surely cannot follow a function tag. */
2418 if (funcdef != finlist && funcdef != fignore)
2419 funcdef = fnone;
2420 break;
2421 case '\0':
2422 /* If a macro spans multiple lines don't reset its state. */
2423 if (quotednl)
2424 CNL_SAVE_DEFINEDEF;
2425 else
2426 CNL;
2427 break;
2428 } /* switch (c) */
2429
2430 } /* while not eof */
2431 }
2432
2433 /*
2434 * Process either a C++ file or a C file depending on the setting
2435 * of a global flag.
2436 */
2437 void
2438 default_C_entries (inf)
2439 FILE *inf;
2440 {
2441 C_entries (cplusplus ? C_PLPL : 0, inf);
2442 }
2443
2444 /* Always do C++. */
2445 void
2446 Cplusplus_entries (inf)
2447 FILE *inf;
2448 {
2449 C_entries (C_PLPL, inf);
2450 }
2451
2452 /* Always do C*. */
2453 void
2454 Cstar_entries (inf)
2455 FILE *inf;
2456 {
2457 C_entries (C_STAR, inf);
2458 }
2459
2460 /* Always do Yacc. */
2461 void
2462 Yacc_entries (inf)
2463 FILE *inf;
2464 {
2465 C_entries (YACC, inf);
2466 }
2467 \f
2468 /* Fortran parsing */
2469
2470 char *dbp;
2471 int pfcnt;
2472
2473 logical
2474 tail (cp)
2475 char *cp;
2476 {
2477 register int len = 0;
2478
2479 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2480 cp++, len++;
2481 if (*cp == 0)
2482 {
2483 dbp += len;
2484 return TRUE;
2485 }
2486 return FALSE;
2487 }
2488
2489 void
2490 takeprec ()
2491 {
2492 while (isspace (*dbp))
2493 dbp++;
2494 if (*dbp != '*')
2495 return;
2496 dbp++;
2497 while (isspace (*dbp))
2498 dbp++;
2499 if (tail ("(*)"))
2500 return;
2501 if (!isdigit (*dbp))
2502 {
2503 --dbp; /* force failure */
2504 return;
2505 }
2506 do
2507 dbp++;
2508 while (isdigit (*dbp));
2509 }
2510
2511 void
2512 getit (inf)
2513 FILE *inf;
2514 {
2515 register char *cp;
2516 char c;
2517 char nambuf[BUFSIZ];
2518
2519 while (isspace (*dbp))
2520 dbp++;
2521 if (*dbp == '\0')
2522 {
2523 lineno++;
2524 linecharno = charno;
2525 charno += readline (&lb, inf);
2526 dbp = lb.buffer;
2527 if (dbp[5] != '&')
2528 return;
2529 dbp += 6;
2530 while (isspace (*dbp))
2531 dbp++;
2532 }
2533 if (!isalpha (*dbp)
2534 && *dbp != '_'
2535 && *dbp != '$')
2536 return;
2537 for (cp = dbp + 1;
2538 (*cp
2539 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2540 cp++)
2541 continue;
2542 c = *cp;
2543 *cp = '\0';
2544 strcpy (nambuf, dbp);
2545 *cp = c;
2546 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2547 cp - lb.buffer + 1, lineno, linecharno);
2548 pfcnt++;
2549 }
2550
2551 void
2552 Fortran_functions (inf)
2553 FILE *inf;
2554 {
2555 lineno = 0;
2556 charno = 0;
2557 pfcnt = 0;
2558
2559 while (!feof (inf))
2560 {
2561 lineno++;
2562 linecharno = charno;
2563 charno += readline (&lb, inf);
2564 dbp = lb.buffer;
2565 if (*dbp == '%')
2566 dbp++; /* Ratfor escape to fortran */
2567 while (isspace (*dbp))
2568 dbp++;
2569 if (*dbp == 0)
2570 continue;
2571 switch (*dbp | ' ')
2572 {
2573 case 'i':
2574 if (tail ("integer"))
2575 takeprec ();
2576 break;
2577 case 'r':
2578 if (tail ("real"))
2579 takeprec ();
2580 break;
2581 case 'l':
2582 if (tail ("logical"))
2583 takeprec ();
2584 break;
2585 case 'c':
2586 if (tail ("complex") || tail ("character"))
2587 takeprec ();
2588 break;
2589 case 'd':
2590 if (tail ("double"))
2591 {
2592 while (isspace (*dbp))
2593 dbp++;
2594 if (*dbp == 0)
2595 continue;
2596 if (tail ("precision"))
2597 break;
2598 continue;
2599 }
2600 break;
2601 }
2602 while (isspace (*dbp))
2603 dbp++;
2604 if (*dbp == 0)
2605 continue;
2606 switch (*dbp | ' ')
2607 {
2608 case 'f':
2609 if (tail ("function"))
2610 getit (inf);
2611 continue;
2612 case 's':
2613 if (tail ("subroutine"))
2614 getit (inf);
2615 continue;
2616 case 'e':
2617 if (tail ("entry"))
2618 getit (inf);
2619 continue;
2620 case 'p':
2621 if (tail ("program"))
2622 {
2623 getit (inf);
2624 continue;
2625 }
2626 if (tail ("procedure"))
2627 getit (inf);
2628 continue;
2629 }
2630 }
2631 }
2632 \f
2633 /*
2634 * Bob Weiner, Motorola Inc., 4/3/94
2635 * Unix and microcontroller assembly tag handling
2636 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2637 */
2638 void
2639 Asm_labels (inf)
2640 FILE *inf;
2641 {
2642 char nambuf[BUFSIZ];
2643 register char *cp;
2644 char c;
2645
2646 lineno = 0;
2647 charno = 0;
2648 pfcnt = 0;
2649
2650 while (!feof (inf))
2651 {
2652 lineno++;
2653 linecharno = charno;
2654 charno += readline (&lb, inf);
2655 cp = lb.buffer;
2656
2657 /* If first char is alphabetic or one of [_.$], test for colon
2658 following identifier. */
2659 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2660 {
2661 /* Read past label. */
2662 cp++;
2663 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2664 cp++;
2665 if (*cp == ':' || isspace (*cp))
2666 {
2667 /* Found end of label, so copy it and add it to the table. */
2668 c = *cp;
2669 *cp = '\0';
2670 strcpy (nambuf, lb.buffer);
2671 *cp = c;
2672 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2673 cp - lb.buffer + 1, lineno, linecharno);
2674 pfcnt++;
2675 }
2676 }
2677 }
2678 }
2679 \f
2680 /* Added by Mosur Mohan, 4/22/88 */
2681 /* Pascal parsing */
2682
2683 #define GET_NEW_LINE \
2684 { \
2685 linecharno = charno; lineno++; \
2686 charno += 1 + readline (&lb, inf); \
2687 dbp = lb.buffer; \
2688 }
2689
2690 /*
2691 * Locates tags for procedures & functions. Doesn't do any type- or
2692 * var-definitions. It does look for the keyword "extern" or
2693 * "forward" immediately following the procedure statement; if found,
2694 * the tag is skipped.
2695 */
2696 void
2697 Pascal_functions (inf)
2698 FILE *inf;
2699 {
2700 struct linebuffer tline; /* mostly copied from C_entries */
2701 long save_lcno;
2702 int save_lineno;
2703 char c, *cp;
2704 char nambuf[BUFSIZ];
2705
2706 logical /* each of these flags is TRUE iff: */
2707 incomment, /* point is inside a comment */
2708 inquote, /* point is inside '..' string */
2709 get_tagname, /* point is after PROCEDURE/FUNCTION */
2710 /* keyword, so next item = potential tag */
2711 found_tag, /* point is after a potential tag */
2712 inparms, /* point is within parameter-list */
2713 verify_tag; /* point has passed the parm-list, so the */
2714 /* next token will determine whether */
2715 /* this is a FORWARD/EXTERN to be */
2716 /* ignored, or whether it is a real tag */
2717
2718 lineno = 0;
2719 charno = 0;
2720 dbp = lb.buffer;
2721 *dbp = 0;
2722 initbuffer (&tline);
2723
2724 incomment = inquote = FALSE;
2725 found_tag = FALSE; /* have a proc name; check if extern */
2726 get_tagname = FALSE; /* have found "procedure" keyword */
2727 inparms = FALSE; /* found '(' after "proc" */
2728 verify_tag = FALSE; /* check if "extern" is ahead */
2729
2730 /* long main loop to get next char */
2731 while (!feof (inf))
2732 {
2733 c = *dbp++;
2734 if (c == 0) /* if end of line */
2735 {
2736 GET_NEW_LINE;
2737 if (*dbp == 0)
2738 continue;
2739 if (!((found_tag && verify_tag) ||
2740 get_tagname))
2741 c = *dbp++; /* only if don't need *dbp pointing */
2742 /* to the beginning of the name of */
2743 /* the procedure or function */
2744 }
2745 if (incomment)
2746 {
2747 if (c == '}') /* within { - } comments */
2748 incomment = FALSE;
2749 else if (c == '*' && dbp[1] == ')') /* within (* - *) comments */
2750 {
2751 dbp++;
2752 incomment = FALSE;
2753 }
2754 continue;
2755 }
2756 else if (inquote)
2757 {
2758 if (c == '\'')
2759 inquote = FALSE;
2760 continue;
2761 }
2762 else
2763 switch (c)
2764 {
2765 case '\'':
2766 inquote = TRUE; /* found first quote */
2767 continue;
2768 case '{': /* found open-{-comment */
2769 incomment = TRUE;
2770 continue;
2771 case '(':
2772 if (*dbp == '*') /* found open-(*-comment */
2773 {
2774 incomment = TRUE;
2775 dbp++;
2776 }
2777 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2778 inparms = TRUE;
2779 continue;
2780 case ')': /* end of parms list */
2781 if (inparms)
2782 inparms = FALSE;
2783 continue;
2784 case ';':
2785 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2786 {
2787 verify_tag = TRUE;
2788 break;
2789 }
2790 continue;
2791 }
2792 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2793 {
2794 /* check if this is an "extern" declaration */
2795 if (*dbp == 0)
2796 continue;
2797 if ((*dbp == 'e') || (*dbp == 'E'))
2798 {
2799 if (tail ("extern")) /* superfluous, really! */
2800 {
2801 found_tag = FALSE;
2802 verify_tag = FALSE;
2803 }
2804 }
2805 else if ((*dbp == 'f') || (*dbp == 'F'))
2806 {
2807 if (tail ("forward")) /* check for forward reference */
2808 {
2809 found_tag = FALSE;
2810 verify_tag = FALSE;
2811 }
2812 }
2813 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2814 {
2815 found_tag = FALSE;
2816 verify_tag = FALSE;
2817 pfnote (nambuf, TRUE, FALSE,
2818 tline.buffer, cp - tline.buffer + 1,
2819 save_lineno, save_lcno);
2820 continue;
2821 }
2822 }
2823 if (get_tagname) /* grab name of proc or fn */
2824 {
2825 if (*dbp == 0)
2826 continue;
2827
2828 /* save all values for later tagging */
2829 tline.size = lb.size;
2830 strcpy (tline.buffer, lb.buffer);
2831 save_lineno = lineno;
2832 save_lcno = linecharno;
2833
2834 /* grab block name */
2835 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2836 continue;
2837 c = cp[0];
2838 cp[0] = 0;
2839 strcpy (nambuf, dbp);
2840 cp[0] = c;
2841 dbp = cp; /* restore dbp to e-o-token */
2842 get_tagname = FALSE;
2843 found_tag = TRUE;
2844 continue;
2845
2846 /* and proceed to check for "extern" */
2847 }
2848 if (!incomment && !inquote && !found_tag && !get_tagname)
2849 {
2850 /* check for proc/fn keywords */
2851 switch (c | ' ')
2852 {
2853 case 'p':
2854 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2855 get_tagname = TRUE;
2856 continue;
2857 case 'f':
2858 if (tail ("unction"))
2859 get_tagname = TRUE;
2860 continue;
2861 }
2862 }
2863 } /* while not eof */
2864 }
2865 \f
2866 /*
2867 * lisp tag functions
2868 * just look for (def or (DEF
2869 */
2870
2871 int
2872 L_isdef (tokp)
2873 register char *tokp;
2874 {
2875 return ((tokp[1] == 'd' || tokp[1] == 'D')
2876 && (tokp[2] == 'e' || tokp[2] == 'E')
2877 && (tokp[3] == 'f' || tokp[3] == 'F'));
2878 }
2879
2880 int
2881 L_isquote (tokp)
2882 register char *tokp;
2883 {
2884 return ((*(++tokp) == 'q' || *tokp == 'Q')
2885 && (*(++tokp) == 'u' || *tokp == 'U')
2886 && (*(++tokp) == 'o' || *tokp == 'O')
2887 && (*(++tokp) == 't' || *tokp == 'T')
2888 && (*(++tokp) == 'e' || *tokp == 'E')
2889 && isspace(*(++tokp)));
2890 }
2891
2892 void
2893 L_getit ()
2894 {
2895 register char *cp;
2896 char c;
2897 char nambuf[BUFSIZ];
2898
2899 if (*dbp == '\'') /* Skip prefix quote */
2900 dbp++;
2901 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2902 {
2903 dbp += 7;
2904 while (isspace(*dbp))
2905 dbp++;
2906 }
2907 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
2908 continue;
2909 if (cp == dbp)
2910 return;
2911
2912 c = cp[0];
2913 cp[0] = 0;
2914 strcpy (nambuf, dbp);
2915 cp[0] = c;
2916 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2917 cp - lb.buffer + 1, lineno, linecharno);
2918 pfcnt++;
2919 }
2920
2921 void
2922 Lisp_functions (inf)
2923 FILE *inf;
2924 {
2925 lineno = 0;
2926 charno = 0;
2927 pfcnt = 0;
2928
2929 while (!feof (inf))
2930 {
2931 lineno++;
2932 linecharno = charno;
2933 charno += readline (&lb, inf);
2934 dbp = lb.buffer;
2935 if (dbp[0] == '(')
2936 {
2937 if (L_isdef (dbp))
2938 {
2939 while (!isspace (*dbp))
2940 dbp++;
2941 while (isspace (*dbp))
2942 dbp++;
2943 L_getit ();
2944 }
2945 else
2946 {
2947 /* Check for (foo::defmumble name-defined ... */
2948 do
2949 dbp++;
2950 while (*dbp && !isspace (*dbp)
2951 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2952 if (*dbp == ':')
2953 {
2954 do
2955 dbp++;
2956 while (*dbp == ':');
2957
2958 if (L_isdef (dbp - 1))
2959 {
2960 while (!isspace (*dbp))
2961 dbp++;
2962 while (isspace (*dbp))
2963 dbp++;
2964 L_getit ();
2965 }
2966 }
2967 }
2968 }
2969 }
2970 }
2971 \f
2972 /*
2973 * Scheme tag functions
2974 * look for (def... xyzzy
2975 * look for (def... (xyzzy
2976 * look for (def ... ((...(xyzzy ....
2977 * look for (set! xyzzy
2978 */
2979
2980 void get_scheme ();
2981
2982 void
2983 Scheme_functions (inf)
2984 FILE *inf;
2985 {
2986 lineno = 0;
2987 charno = 0;
2988 pfcnt = 0;
2989
2990 while (!feof (inf))
2991 {
2992 lineno++;
2993 linecharno = charno;
2994 charno += readline (&lb, inf);
2995 dbp = lb.buffer;
2996 if (dbp[0] == '(' &&
2997 (dbp[1] == 'D' || dbp[1] == 'd') &&
2998 (dbp[2] == 'E' || dbp[2] == 'e') &&
2999 (dbp[3] == 'F' || dbp[3] == 'f'))
3000 {
3001 while (!isspace (*dbp))
3002 dbp++;
3003 /* Skip over open parens and white space */
3004 while (*dbp && (isspace (*dbp) || *dbp == '('))
3005 dbp++;
3006 get_scheme ();
3007 }
3008 if (dbp[0] == '(' &&
3009 (dbp[1] == 'S' || dbp[1] == 's') &&
3010 (dbp[2] == 'E' || dbp[2] == 'e') &&
3011 (dbp[3] == 'T' || dbp[3] == 't') &&
3012 (dbp[4] == '!' || dbp[4] == '!') &&
3013 (isspace (dbp[5])))
3014 {
3015 while (!isspace (*dbp))
3016 dbp++;
3017 /* Skip over white space */
3018 while (isspace (*dbp))
3019 dbp++;
3020 get_scheme ();
3021 }
3022 }
3023 }
3024
3025 void
3026 get_scheme ()
3027 {
3028 register char *cp;
3029 char c;
3030 char nambuf[BUFSIZ];
3031
3032 if (*dbp == 0)
3033 return;
3034 /* Go till you get to white space or a syntactic break */
3035 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
3036 continue;
3037 /* Null terminate the string there. */
3038 c = cp[0];
3039 cp[0] = 0;
3040 /* Copy the string */
3041 strcpy (nambuf, dbp);
3042 /* Unterminate the string */
3043 cp[0] = c;
3044 /* Announce the change */
3045 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3046 pfcnt++;
3047 }
3048 \f
3049 /* Find tags in TeX and LaTeX input files. */
3050
3051 /* TEX_toktab is a table of TeX control sequences that define tags.
3052 Each TEX_tabent records one such control sequence.
3053 CONVERT THIS TO USE THE Stab TYPE!! */
3054 struct TEX_tabent
3055 {
3056 char *name;
3057 int len;
3058 };
3059
3060 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
3061
3062 /* Default set of control sequences to put into TEX_toktab.
3063 The value of environment var TEXTAGS is prepended to this. */
3064
3065 char *TEX_defenv = "\
3066 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
3067
3068 void TEX_mode ();
3069 struct TEX_tabent *TEX_decode_env ();
3070 void TEX_getit ();
3071 int TEX_Token ();
3072
3073 char TEX_esc = '\\';
3074 char TEX_opgrp = '{';
3075 char TEX_clgrp = '}';
3076
3077 /*
3078 * TeX/LaTeX scanning loop.
3079 */
3080 void
3081 TeX_functions (inf)
3082 FILE *inf;
3083 {
3084 char *lasthit;
3085
3086 lineno = 0;
3087 charno = 0;
3088 pfcnt = 0;
3089
3090 /* Select either \ or ! as escape character. */
3091 TEX_mode (inf);
3092
3093 /* Initialize token table once from environment. */
3094 if (!TEX_toktab)
3095 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
3096
3097 while (!feof (inf))
3098 { /* Scan each line in file */
3099 lineno++;
3100 linecharno = charno;
3101 charno += readline (&lb, inf);
3102 dbp = lb.buffer;
3103 lasthit = dbp;
3104 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
3105 {
3106 register int i;
3107
3108 if (!*(++dbp))
3109 break;
3110 linecharno += dbp - lasthit;
3111 lasthit = dbp;
3112 i = TEX_Token (lasthit);
3113 if (0 <= i)
3114 {
3115 TEX_getit (lasthit, TEX_toktab[i].len);
3116 break; /* We only save a line once */
3117 }
3118 }
3119 }
3120 }
3121
3122 #define TEX_LESC '\\'
3123 #define TEX_SESC '!'
3124 #define TEX_cmt '%'
3125
3126 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
3127 chars accordingly. */
3128 void
3129 TEX_mode (inf)
3130 FILE *inf;
3131 {
3132 int c;
3133
3134 while ((c = getc (inf)) != EOF)
3135 {
3136 /* Skip to next line if we hit the TeX comment char. */
3137 if (c == TEX_cmt)
3138 while (c != '\n')
3139 c = getc (inf);
3140 else if (c == TEX_LESC || c == TEX_SESC )
3141 break;
3142 }
3143
3144 if (c == TEX_LESC)
3145 {
3146 TEX_esc = TEX_LESC;
3147 TEX_opgrp = '{';
3148 TEX_clgrp = '}';
3149 }
3150 else
3151 {
3152 TEX_esc = TEX_SESC;
3153 TEX_opgrp = '<';
3154 TEX_clgrp = '>';
3155 }
3156 rewind (inf);
3157 }
3158
3159 /* Read environment and prepend it to the default string.
3160 Build token table. */
3161 struct TEX_tabent *
3162 TEX_decode_env (evarname, defenv)
3163 char *evarname;
3164 char *defenv;
3165 {
3166 register char *env, *p;
3167
3168 struct TEX_tabent *tab;
3169 int size, i;
3170
3171 /* Append default string to environment. */
3172 env = getenv (evarname);
3173 if (!env)
3174 env = defenv;
3175 else
3176 env = concat (env, defenv, "");
3177
3178 /* Allocate a token table */
3179 for (size = 1, p = env; p;)
3180 if ((p = etags_strchr (p, ':')) && *(++p))
3181 size++;
3182 /* Add 1 to leave room for null terminator. */
3183 tab = xnew (size + 1, struct TEX_tabent);
3184
3185 /* Unpack environment string into token table. Be careful about */
3186 /* zero-length strings (leading ':', "::" and trailing ':') */
3187 for (i = 0; *env;)
3188 {
3189 p = etags_strchr (env, ':');
3190 if (!p) /* End of environment string. */
3191 p = env + strlen (env);
3192 if (p - env > 0)
3193 { /* Only non-zero strings. */
3194 tab[i].name = savenstr (env, p - env);
3195 tab[i].len = strlen (tab[i].name);
3196 i++;
3197 }
3198 if (*p)
3199 env = p + 1;
3200 else
3201 {
3202 tab[i].name = NULL; /* Mark end of table. */
3203 tab[i].len = 0;
3204 break;
3205 }
3206 }
3207 return tab;
3208 }
3209
3210 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
3211 The name being defined actually starts at (NAME + LEN + 1).
3212 But we seem to include the TeX command in the tag name. */
3213 void
3214 TEX_getit (name, len)
3215 char *name;
3216 int len;
3217 {
3218 char *p = name + len;
3219 char nambuf[BUFSIZ];
3220
3221 if (*name == 0)
3222 return;
3223
3224 /* Let tag name extend to next group close (or end of line) */
3225 while (*p && *p != TEX_clgrp)
3226 p++;
3227 strncpy (nambuf, name, p - name);
3228 nambuf[p - name] = 0;
3229
3230 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
3231 pfcnt++;
3232 }
3233
3234 /* If the text at CP matches one of the tag-defining TeX command names,
3235 return the pointer to the first occurrence of that command in TEX_toktab.
3236 Otherwise return -1.
3237 Keep the capital `T' in `Token' for dumb truncating compilers
3238 (this distinguishes it from `TEX_toktab' */
3239 int
3240 TEX_Token (cp)
3241 char *cp;
3242 {
3243 int i;
3244
3245 for (i = 0; TEX_toktab[i].len > 0; i++)
3246 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
3247 return i;
3248 return -1;
3249 }
3250 \f
3251 /* Support for Prolog. */
3252
3253 /* Whole head (not only functor, but also arguments)
3254 is gotten in compound term. */
3255 void
3256 prolog_getit (s)
3257 char *s;
3258 {
3259 char nambuf[BUFSIZ], *save_s, tmpc;
3260 int insquote, npar;
3261
3262 save_s = s;
3263 insquote = FALSE;
3264 npar = 0;
3265 while (1)
3266 {
3267 if (*s == '\0') /* syntax error. */
3268 return;
3269 else if (insquote && *s == '\'' && *(s + 1) == '\'')
3270 s += 2;
3271 else if (*s == '\'')
3272 {
3273 insquote = !insquote;
3274 s++;
3275 }
3276 else if (!insquote && *s == '(')
3277 {
3278 npar++;
3279 s++;
3280 }
3281 else if (!insquote && *s == ')')
3282 {
3283 npar--;
3284 s++;
3285 if (npar == 0)
3286 break;
3287 else if (npar < 0) /* syntax error. */
3288 return;
3289 }
3290 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
3291 { /* fullstop. */
3292 if (npar != 0) /* syntax error. */
3293 return;
3294 s++;
3295 break;
3296 }
3297 else
3298 s++;
3299 }
3300 tmpc = *s;
3301 *s = '\0';
3302 strcpy (nambuf, save_s);
3303 *s = tmpc;
3304 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
3305 }
3306
3307 /* It is assumed that prolog predicate starts from column 0. */
3308 void
3309 Prolog_functions (inf)
3310 FILE *inf;
3311 {
3312 void skip_comment (), prolog_getit ();
3313
3314 lineno = linecharno = charno = 0;
3315 while (!feof (inf))
3316 {
3317 lineno++;
3318 linecharno += charno;
3319 charno = readline (&lb, inf) + 1; /* 1 for newline. */
3320 dbp = lb.buffer;
3321 if (isspace (dbp[0])) /* not predicate header. */
3322 continue;
3323 else if (dbp[0] == '%') /* comment. */
3324 continue;
3325 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
3326 skip_comment (&lb, inf, &lineno, &linecharno);
3327 else /* found. */
3328 prolog_getit (dbp);
3329 }
3330 }
3331
3332 void
3333 skip_comment (plb, inf, plineno, plinecharno)
3334 struct linebuffer *plb;
3335 FILE *inf;
3336 int *plineno; /* result */
3337 long *plinecharno; /* result */
3338 {
3339 char *cp;
3340
3341 do
3342 {
3343 for (cp = plb->buffer; *cp != '\0'; cp++)
3344 if (cp[0] == '*' && cp[1] == '/')
3345 return;
3346 (*plineno)++;
3347 *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
3348 }
3349 while (!feof(inf));
3350 }
3351 \f
3352 #ifdef ETAGS_REGEXPS
3353 /* Take a string like "/blah/" and turn it into "blah", making sure
3354 that the first and last characters are the same, and handling
3355 quoted separator characters. Actually, stops on the occurence of
3356 an unquoted separator. Also turns "\t" into a Tab character.
3357 Returns pointer to terminating separator. Works in place. Null
3358 terminates name string. */
3359 char *
3360 scan_separators (name)
3361 char *name;
3362 {
3363 char sep = name[0];
3364 char *copyto = name;
3365 logical quoted = FALSE;
3366
3367 for (++name; *name != '\0'; ++name)
3368 {
3369 if (quoted)
3370 {
3371 if (*name == 't')
3372 *copyto++ = '\t';
3373 else if (*name == sep)
3374 *copyto++ = sep;
3375 else
3376 {
3377 /* Something else is quoted, so preserve the quote. */
3378 *copyto++ = '\\';
3379 *copyto++ = *name;
3380 }
3381 quoted = FALSE;
3382 }
3383 else if (*name == '\\')
3384 quoted = TRUE;
3385 else if (*name == sep)
3386 break;
3387 else
3388 *copyto++ = *name;
3389 }
3390
3391 /* Terminate copied string. */
3392 *copyto = '\0';
3393 return name;
3394 }
3395
3396 /* Turn a name, which is an ed-style (but Emacs syntax) regular
3397 expression, into a real regular expression by compiling it. */
3398 void
3399 add_regex (regexp_pattern)
3400 char *regexp_pattern;
3401 {
3402 char *name;
3403 const char *err;
3404 struct re_pattern_buffer *patbuf;
3405
3406 if (regexp_pattern == NULL)
3407 {
3408 /* Remove existing regexps. */
3409 num_patterns = 0;
3410 patterns = NULL;
3411 return;
3412 }
3413
3414 if (regexp_pattern[0] == '\0')
3415 {
3416 error ("missing regexp", 0);
3417 return;
3418 }
3419 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
3420 {
3421 error ("%s: unterminated regexp", regexp_pattern);
3422 return;
3423 }
3424 name = scan_separators (regexp_pattern);
3425 if (regexp_pattern[0] == '\0')
3426 {
3427 error ("null regexp", 0);
3428 return;
3429 }
3430 (void) scan_separators (name);
3431
3432 patbuf = xnew (1, struct re_pattern_buffer);
3433 patbuf->translate = NULL;
3434 patbuf->fastmap = NULL;
3435 patbuf->buffer = NULL;
3436 patbuf->allocated = 0;
3437
3438 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
3439 if (err != NULL)
3440 {
3441 error ("%s while compiling pattern", err);
3442 return;
3443 }
3444
3445 num_patterns += 1;
3446 if (num_patterns == 1)
3447 patterns = xnew (1, struct pattern);
3448 else
3449 patterns = ((struct pattern *)
3450 xrealloc (patterns,
3451 (num_patterns * sizeof (struct pattern))));
3452 patterns[num_patterns - 1].pattern = patbuf;
3453 patterns[num_patterns - 1].name_pattern = savestr (name);
3454 patterns[num_patterns - 1].error_signaled = FALSE;
3455 }
3456
3457 /*
3458 * Do the subtitutions indicated by the regular expression and
3459 * arguments.
3460 */
3461 char *
3462 substitute (in, out, regs)
3463 char *in, *out;
3464 struct re_registers *regs;
3465 {
3466 char *result = NULL, *t;
3467 int size = 0;
3468
3469 /* Pass 1: figure out how much size to allocate. */
3470 for (t = out; *t; ++t)
3471 {
3472 if (*t == '\\')
3473 {
3474 ++t;
3475 if (!*t)
3476 {
3477 fprintf (stderr, "%s: pattern subtitution ends prematurely\n",
3478 progname);
3479 return NULL;
3480 }
3481 if (isdigit (*t))
3482 {
3483 int dig = *t - '0';
3484 size += regs->end[dig] - regs->start[dig];
3485 }
3486 }
3487 }
3488
3489 /* Allocate space and do the substitutions. */
3490 result = xnew (size + 1, char);
3491 size = 0;
3492 for (; *out; ++out)
3493 {
3494 if (*out == '\\')
3495 {
3496 ++out;
3497 if (isdigit (*out))
3498 {
3499 /* Using "dig2" satisfies my debugger. Bleah. */
3500 int dig2 = *out - '0';
3501 strncpy (result + size, in + regs->start[dig2],
3502 regs->end[dig2] - regs->start[dig2]);
3503 size += regs->end[dig2] - regs->start[dig2];
3504 }
3505 else
3506 {
3507 switch (*out)
3508 {
3509 case '\t':
3510 result[size++] = '\t';
3511 break;
3512 case '\\':
3513 *out = '\\';
3514 break;
3515 default:
3516 result[size++] = *out;
3517 break;
3518 }
3519 }
3520 }
3521 else
3522 result[size++] = *out;
3523 }
3524 result[size] = '\0';
3525
3526 return result;
3527 }
3528 \f
3529 #endif /* ETAGS_REGEXPS */
3530 /* Initialize a linebuffer for use */
3531 void
3532 initbuffer (linebuffer)
3533 struct linebuffer *linebuffer;
3534 {
3535 linebuffer->size = 200;
3536 linebuffer->buffer = xnew (200, char);
3537 }
3538
3539 /*
3540 * Read a line of text from `stream' into `linebuffer'.
3541 * Return the number of characters read from `stream',
3542 * which is the length of the line including the newline, if any.
3543 */
3544 long
3545 readline_internal (linebuffer, stream)
3546 struct linebuffer *linebuffer;
3547 register FILE *stream;
3548 {
3549 char *buffer = linebuffer->buffer;
3550 register char *p = linebuffer->buffer;
3551 register char *pend;
3552 int chars_deleted;
3553
3554 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
3555
3556 while (1)
3557 {
3558 register int c = getc (stream);
3559 if (p == pend)
3560 {
3561 linebuffer->size *= 2;
3562 buffer = (char *) xrealloc (buffer, linebuffer->size);
3563 p += buffer - linebuffer->buffer;
3564 pend = buffer + linebuffer->size;
3565 linebuffer->buffer = buffer;
3566 }
3567 if (c == EOF)
3568 {
3569 chars_deleted = 0;
3570 break;
3571 }
3572 if (c == '\n')
3573 {
3574 if (p[-1] == '\r' && p > buffer)
3575 {
3576 *--p = '\0';
3577 chars_deleted = 2;
3578 }
3579 else
3580 {
3581 *p = '\0';
3582 chars_deleted = 1;
3583 }
3584 break;
3585 }
3586 *p++ = c;
3587 }
3588
3589 return p - buffer + chars_deleted;
3590 }
3591
3592 /*
3593 * Like readline_internal, above, but try to match the input
3594 * line against any existing regular expressions.
3595 */
3596 long
3597 readline (linebuffer, stream)
3598 struct linebuffer *linebuffer;
3599 FILE *stream;
3600 {
3601 /* Read new line. */
3602 int i;
3603 long result = readline_internal (linebuffer, stream);
3604
3605 #ifdef ETAGS_REGEXPS
3606 /* Match against all listed patterns. */
3607 for (i = 0; i < num_patterns; ++i)
3608 {
3609 int match = re_match (patterns[i].pattern, linebuffer->buffer,
3610 (int)result, 0, &patterns[i].regs);
3611 switch (match)
3612 {
3613 case -2:
3614 /* Some error. */
3615 if (!patterns[i].error_signaled)
3616 {
3617 error ("error while matching pattern %d", i);
3618 patterns[i].error_signaled = TRUE;
3619 }
3620 break;
3621 case -1:
3622 /* No match. */
3623 break;
3624 default:
3625 /* Match occurred. Construct a tag. */
3626 if (patterns[i].name_pattern[0] != '\0')
3627 {
3628 /* Make a named tag. */
3629 char *name = substitute (linebuffer->buffer,
3630 patterns[i].name_pattern,
3631 &patterns[i].regs);
3632 if (name != NULL)
3633 pfnote (name, TRUE, TRUE, linebuffer->buffer,
3634 match, lineno, linecharno);
3635 }
3636 else
3637 {
3638 /* Make an unnamed tag. */
3639 pfnote (NULL, TRUE, FALSE, linebuffer->buffer,
3640 match, lineno, linecharno);
3641 }
3642 break;
3643 }
3644 }
3645 #endif /* ETAGS_REGEXPS */
3646
3647 return result;
3648 }
3649
3650 /*
3651 * Read a file, but do no processing. This is used to do regexp
3652 * matching on files that have no language defined.
3653 */
3654 void
3655 just_read_file (inf)
3656 FILE *inf;
3657 {
3658 while (!feof (inf))
3659 {
3660 ++lineno;
3661 linecharno = charno;
3662 charno += readline (&lb, inf) + 1;
3663 }
3664 }
3665
3666 \f
3667 char *
3668 savestr (cp)
3669 char *cp;
3670 {
3671 return savenstr (cp, strlen (cp));
3672 }
3673
3674 char *
3675 savenstr (cp, len)
3676 char *cp;
3677 int len;
3678 {
3679 register char *dp;
3680
3681 dp = xnew (len + 1, char);
3682 strncpy (dp, cp, len);
3683 dp[len] = '\0';
3684 return dp;
3685 }
3686
3687 /*
3688 * Return the ptr in sp at which the character c last
3689 * appears; NULL if not found
3690 *
3691 * Identical to System V strrchr, included for portability.
3692 */
3693 char *
3694 etags_strrchr (sp, c)
3695 register char *sp, c;
3696 {
3697 register char *r;
3698
3699 r = NULL;
3700 do
3701 {
3702 if (*sp == c)
3703 r = sp;
3704 } while (*sp++);
3705 return r;
3706 }
3707
3708
3709 /*
3710 * Return the ptr in sp at which the character c first
3711 * appears; NULL if not found
3712 *
3713 * Identical to System V strchr, included for portability.
3714 */
3715 char *
3716 etags_strchr (sp, c)
3717 register char *sp, c;
3718 {
3719 do
3720 {
3721 if (*sp == c)
3722 return sp;
3723 } while (*sp++);
3724 return NULL;
3725 }
3726
3727 /* Print error message and exit. */
3728 void
3729 fatal (s1, s2)
3730 char *s1, *s2;
3731 {
3732 error (s1, s2);
3733 exit (BAD);
3734 }
3735
3736 void
3737 pfatal (s1)
3738 char *s1;
3739 {
3740 perror (s1);
3741 exit (BAD);
3742 }
3743
3744 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3745 void
3746 error (s1, s2)
3747 char *s1, *s2;
3748 {
3749 fprintf (stderr, "%s: ", progname);
3750 fprintf (stderr, s1, s2);
3751 fprintf (stderr, "\n");
3752 }
3753
3754 /* Return a newly-allocated string whose contents
3755 concatenate those of s1, s2, s3. */
3756 char *
3757 concat (s1, s2, s3)
3758 char *s1, *s2, *s3;
3759 {
3760 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3761 char *result = xnew (len1 + len2 + len3 + 1, char);
3762
3763 strcpy (result, s1);
3764 strcpy (result + len1, s2);
3765 strcpy (result + len1 + len2, s3);
3766 result[len1 + len2 + len3] = '\0';
3767
3768 return result;
3769 }
3770 \f
3771 /* Does the same work as the system V getcwd, but does not need to
3772 guess buffer size in advance. */
3773 char *
3774 etags_getcwd ()
3775 #ifdef DOS_NT
3776 {
3777 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3778
3779 getwd (path);
3780 p = path;
3781 while (*p)
3782 if (*p == '\\')
3783 *p++ = '/';
3784 else
3785 *p++ = tolower (*p);
3786
3787 return strdup (path);
3788 }
3789 #elif HAVE_GETCWD /* not DOS_NT */
3790 {
3791 int bufsize = 200;
3792 char *path = xnew (bufsize, char);
3793
3794 while (getcwd (path, bufsize) == NULL)
3795 {
3796 if (errno != ERANGE)
3797 pfatal ("pwd");
3798 bufsize *= 2;
3799 path = xnew (bufsize, char);
3800 }
3801
3802 return path;
3803 }
3804 #else /* not DOS_NT and not HAVE_GETCWD */
3805 {
3806 struct linebuffer path;
3807 FILE *pipe;
3808
3809 initbuffer (&path);
3810 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
3811 if (pipe == NULL || readline_internal (&path, pipe) == 0)
3812 pfatal ("pwd");
3813 pclose (pipe);
3814
3815 return path.buffer;
3816 }
3817 #endif /* not DOS_NT and not HAVE_GETCWD */
3818
3819 /* Return a newly allocated string containing the filename
3820 of FILE relative to the absolute directory DIR (which
3821 should end with a slash). */
3822 char *
3823 relative_filename (file, dir)
3824 char *file, *dir;
3825 {
3826 char *fp, *dp, *res;
3827
3828 /* Find the common root of file and dir. */
3829 fp = absolute_filename (file, cwd);
3830 dp = dir;
3831 while (*fp++ == *dp++)
3832 continue;
3833 do
3834 {
3835 fp--;
3836 dp--;
3837 }
3838 while (*fp != '/');
3839
3840 /* Build a sequence of "../" strings for the resulting relative filename. */
3841 for (dp = etags_strchr (dp + 1, '/'), res = "";
3842 dp != NULL;
3843 dp = etags_strchr (dp + 1, '/'))
3844 {
3845 res = concat (res, "../", "");
3846 }
3847
3848 /* Add the filename relative to the common root of file and dir. */
3849 res = concat (res, fp + 1, "");
3850
3851 return res; /* temporary stub */
3852 }
3853
3854 /* Return a newly allocated string containing the
3855 absolute filename of FILE given CWD (which should
3856 end with a slash). */
3857 char *
3858 absolute_filename (file, cwd)
3859 char *file, *cwd;
3860 {
3861 char *slashp, *cp, *res;
3862
3863 if (file[0] == '/')
3864 res = concat (file, "", "");
3865 else
3866 res = concat (cwd, file, "");
3867
3868 /* Delete the "/dirname/.." and "/." substrings. */
3869 slashp = etags_strchr (res, '/');
3870 while (slashp != NULL && slashp[0] != '\0')
3871 {
3872 if (slashp[1] == '.')
3873 {
3874 if (slashp[2] == '.'
3875 && (slashp[3] == '/' || slashp[3] == '\0'))
3876 {
3877 cp = slashp;
3878 do
3879 cp--;
3880 while (cp >= res && *cp != '/');
3881 if (*cp == '/')
3882 {
3883 strcpy (cp, slashp + 3);
3884 }
3885 else /* else (cp == res) */
3886 {
3887 if (slashp[3] != '\0')
3888 strcpy (cp, slashp + 4);
3889 else
3890 return ".";
3891 }
3892 slashp = cp;
3893 continue;
3894 }
3895 else if (slashp[2] == '/' || slashp[2] == '\0')
3896 {
3897 strcpy (slashp, slashp + 2);
3898 continue;
3899 }
3900 }
3901
3902 slashp = etags_strchr (slashp + 1, '/');
3903 }
3904
3905 return res;
3906 }
3907
3908 /* Return a newly allocated string containing the absolute
3909 filename of dir where FILE resides given CWD (which should
3910 end with a slash). */
3911 char *
3912 absolute_dirname (file, cwd)
3913 char *file, *cwd;
3914 {
3915 char *slashp, *res;
3916 char save;
3917
3918 slashp = etags_strrchr (file, '/');
3919 if (slashp == NULL)
3920 return cwd;
3921 save = slashp[1];
3922 slashp[1] = '\0';
3923 res = absolute_filename (file, cwd);
3924 slashp[1] = save;
3925
3926 return res;
3927 }
3928
3929 /* Like malloc but get fatal error if memory is exhausted. */
3930 char *
3931 xmalloc (size)
3932 unsigned int size;
3933 {
3934 char *result = (char *) malloc (size);
3935 if (result == NULL)
3936 fatal ("virtual memory exhausted", 0);
3937 return result;
3938 }
3939
3940 char *
3941 xrealloc (ptr, size)
3942 char *ptr;
3943 unsigned int size;
3944 {
3945 char *result = (char *) realloc (ptr, size);
3946 if (result == NULL)
3947 fatal ("virtual memory exhausted");
3948 return result;
3949 }