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