* etags.c (process_file): free (filename) after using it.
[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.26";
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 free (filename);
1048 put_entries (head);
1049 free_tree (head);
1050 head = NULL;
1051 }
1052 }
1053
1054 /*
1055 * This routine sets up the boolean pseudo-functions which work
1056 * by setting boolean flags dependent upon the corresponding character
1057 * Every char which is NOT in that string is not a white char. Therefore,
1058 * all of the array "_wht" is set to FALSE, and then the elements
1059 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1060 * of a char is TRUE if it is the string "white", else FALSE.
1061 */
1062 void
1063 init ()
1064 {
1065 register char *sp;
1066 register int i;
1067
1068 for (i = 0; i < 0177; i++)
1069 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
1070 for (sp = white; *sp; sp++)
1071 _wht[*sp] = TRUE;
1072 for (sp = endtk; *sp; sp++)
1073 _etk[*sp] = TRUE;
1074 for (sp = intk; *sp; sp++)
1075 _itk[*sp] = TRUE;
1076 for (sp = begtk; *sp; sp++)
1077 _btk[*sp] = TRUE;
1078 _wht[0] = _wht['\n'];
1079 _etk[0] = _etk['\n'];
1080 _btk[0] = _btk['\n'];
1081 _itk[0] = _itk['\n'];
1082 }
1083
1084 /*
1085 * This routine opens the specified file and calls the function
1086 * which finds the function and type definitions.
1087 */
1088 void
1089 find_entries (file, inf)
1090 char *file;
1091 FILE *inf;
1092 {
1093 char *cp;
1094 struct lang_entry *lang;
1095 NODE *old_last_node;
1096 extern NODE *last_node;
1097
1098 curfile = savestr (file);
1099 cp = etags_strrchr (file, '.');
1100
1101 /* If user specified a language, use it. */
1102 if (lang_func != NULL)
1103 {
1104 lang_func (inf);
1105 fclose (inf);
1106 return;
1107 }
1108
1109 if (cp)
1110 {
1111 ++cp;
1112 for (lang = lang_extensions; lang->extension; ++lang)
1113 {
1114 if (streq (cp, lang->extension))
1115 {
1116 lang->function (inf);
1117 fclose (inf);
1118 return;
1119 }
1120 }
1121 }
1122
1123 /* Try Fortran. */
1124 old_last_node = last_node;
1125 Fortran_functions (inf);
1126
1127 /* No Fortran entries found. Try C. */
1128 if (old_last_node == last_node)
1129 default_C_entries (inf);
1130 fclose (inf);
1131 }
1132 \f
1133 /* Record a tag. */
1134 void
1135 pfnote (name, is_func, named, linestart, linelen, lno, cno)
1136 char *name; /* tag name */
1137 logical is_func; /* tag is a function */
1138 logical named; /* tag different from text of definition */
1139 char *linestart; /* start of the line where tag is */
1140 int linelen; /* length of the line where tag is */
1141 int lno; /* line number */
1142 long cno; /* character number */
1143 {
1144 register NODE *np = xnew (1, NODE);
1145 register char *fp;
1146
1147 /* If ctags mode, change name "main" to M<thisfilename>. */
1148 if (CTAGS && !cxref_style && streq (name, "main"))
1149 {
1150 fp = etags_strrchr (curfile, '/');
1151 np->name = concat ("M", fp == 0 ? curfile : fp + 1, "");
1152 fp = etags_strrchr (np->name, '.');
1153 if (fp && fp[1] != '\0' && fp[2] == '\0')
1154 fp[0] = 0;
1155 np->named = TRUE;
1156 }
1157 else
1158 {
1159 np->name = name;
1160 np->named = named;
1161 }
1162 np->been_warned = FALSE;
1163 np->file = curfile;
1164 np->is_func = is_func;
1165 np->lno = lno;
1166 /* Our char numbers are 0-base, because of C language tradition?
1167 ctags compatibility? old versions compatibility? I don't know.
1168 Anyway, since emacs's are 1-base we espect etags.el to take care
1169 of the difference. If we wanted to have 1-based numbers, we would
1170 uncomment the +1 below. */
1171 np->cno = cno /* + 1 */ ;
1172 np->left = np->right = NULL;
1173 np->pat = savenstr (linestart, ((CTAGS && !cxref_style) ? 50 : linelen));
1174
1175 add_node (np, &head);
1176 }
1177
1178 /*
1179 * free_tree ()
1180 * recurse on left children, iterate on right children.
1181 */
1182 void
1183 free_tree (node)
1184 register NODE *node;
1185 {
1186 while (node)
1187 {
1188 register NODE *node_right = node->right;
1189 free_tree (node->left);
1190 if (node->named)
1191 free (node->name);
1192 free (node->pat);
1193 free ((char *) node);
1194 node = node_right;
1195 }
1196 }
1197
1198 /*
1199 * add_node ()
1200 * Adds a node to the tree of nodes. In etags mode, we don't keep
1201 * it sorted; we just keep a linear list. In ctags mode, maintain
1202 * an ordered tree, with no attempt at balancing.
1203 *
1204 * add_node is the only function allowed to add nodes, so it can
1205 * maintain state.
1206 */
1207 NODE *last_node = NULL;
1208 void
1209 add_node (node, cur_node_p)
1210 NODE *node, **cur_node_p;
1211 {
1212 register int dif;
1213 register NODE *cur_node = *cur_node_p;
1214
1215 if (cur_node == NULL)
1216 {
1217 *cur_node_p = node;
1218 last_node = node;
1219 return;
1220 }
1221
1222 if (!CTAGS)
1223 {
1224 /* Etags Mode */
1225 if (last_node == NULL)
1226 fatal ("internal error in add_node", 0);
1227 last_node->right = node;
1228 last_node = node;
1229 }
1230 else
1231 {
1232 /* Ctags Mode */
1233 dif = strcmp (node->name, cur_node->name);
1234
1235 /*
1236 * If this tag name matches an existing one, then
1237 * do not add the node, but maybe print a warning.
1238 */
1239 if (!dif)
1240 {
1241 if (node->file == cur_node->file)
1242 {
1243 if (!no_warnings)
1244 {
1245 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1246 node->file, lineno, node->name);
1247 fprintf (stderr, "Second entry ignored\n");
1248 }
1249 return;
1250 }
1251 if (!cur_node->been_warned && !no_warnings)
1252 {
1253 fprintf (stderr,
1254 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1255 node->file, cur_node->file, node->name);
1256 }
1257 cur_node->been_warned = TRUE;
1258 return;
1259 }
1260
1261 /* Maybe refuse to add duplicate nodes. */
1262 if (!permit_duplicates)
1263 {
1264 if (streq (node->name, cur_node->name)
1265 && streq (node->file, cur_node->file))
1266 return;
1267 }
1268
1269 /* Actually add the node */
1270 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1271 }
1272 }
1273 \f
1274 void
1275 put_entries (node)
1276 register NODE *node;
1277 {
1278 register char *sp;
1279
1280 if (node == NULL)
1281 return;
1282
1283 /* Output subentries that precede this one */
1284 put_entries (node->left);
1285
1286 /* Output this entry */
1287
1288 if (!CTAGS)
1289 {
1290 if (node->named)
1291 {
1292 fprintf (tagf, "%s\177%s\001%d,%d\n",
1293 node->pat, node->name,
1294 node->lno, node->cno);
1295 }
1296 else
1297 {
1298 fprintf (tagf, "%s\177%d,%d\n",
1299 node->pat,
1300 node->lno, node->cno);
1301 }
1302 }
1303 else if (!cxref_style)
1304 {
1305 fprintf (tagf, "%s\t%s\t",
1306 node->name, node->file);
1307
1308 if (node->is_func)
1309 { /* a function */
1310 putc (searchar, tagf);
1311 putc ('^', tagf);
1312
1313 for (sp = node->pat; *sp; sp++)
1314 {
1315 if (*sp == '\\' || *sp == searchar)
1316 putc ('\\', tagf);
1317 putc (*sp, tagf);
1318 }
1319 putc (searchar, tagf);
1320 }
1321 else
1322 { /* a typedef; text pattern inadequate */
1323 fprintf (tagf, "%d", node->lno);
1324 }
1325 putc ('\n', tagf);
1326 }
1327 else if (vgrind_style)
1328 fprintf (stdout, "%s %s %d\n",
1329 node->name, node->file, (node->lno + 63) / 64);
1330 else
1331 fprintf (stdout, "%-16s %3d %-16s %s\n",
1332 node->name, node->lno, node->file, node->pat);
1333
1334 /* Output subentries that follow this one */
1335 put_entries (node->right);
1336 }
1337
1338 /* Length of a number's decimal representation. */
1339 int
1340 number_len (num)
1341 long num;
1342 {
1343 int len = 0;
1344 if (!num)
1345 return 1;
1346 for (; num; num /= 10)
1347 ++len;
1348 return len;
1349 }
1350
1351 /*
1352 * Return total number of characters that put_entries will output for
1353 * the nodes in the subtree of the specified node. Works only if
1354 * we are not ctags, but called only in that case. This count
1355 * is irrelevant with the new tags.el, but is still supplied for
1356 * backward compatibility.
1357 */
1358 int
1359 total_size_of_entries (node)
1360 register NODE *node;
1361 {
1362 register int total;
1363
1364 if (node == NULL)
1365 return 0;
1366
1367 total = 0;
1368 for (; node; node = node->right)
1369 {
1370 /* Count left subentries. */
1371 total += total_size_of_entries (node->left);
1372
1373 /* Count this entry */
1374 total += strlen (node->pat) + 1;
1375 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1376 if (node->named)
1377 total += 1 + strlen (node->name); /* \001name */
1378 }
1379
1380 return total;
1381 }
1382 \f
1383 /*
1384 * The C symbol tables.
1385 */
1386 enum sym_type
1387 {
1388 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
1389 };
1390
1391 /* Feed stuff between (but not including) %[ and %] lines to:
1392 gperf -c -k1,3 -o -p -r -t
1393 %[
1394 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1395 %%
1396 class, C_PLPL, st_C_struct
1397 domain, C_STAR, st_C_struct
1398 union, 0, st_C_struct
1399 struct, 0, st_C_struct
1400 enum, 0, st_C_enum
1401 typedef, 0, st_C_typedef
1402 define, 0, st_C_define
1403 long, 0, st_C_typespec
1404 short, 0, st_C_typespec
1405 int, 0, st_C_typespec
1406 char, 0, st_C_typespec
1407 float, 0, st_C_typespec
1408 double, 0, st_C_typespec
1409 signed, 0, st_C_typespec
1410 unsigned, 0, st_C_typespec
1411 auto, 0, st_C_typespec
1412 void, 0, st_C_typespec
1413 extern, 0, st_C_typespec
1414 static, 0, st_C_typespec
1415 const, 0, st_C_typespec
1416 volatile, 0, st_C_typespec
1417 %]
1418 and replace lines between %< and %> with its output. */
1419 /*%<*/
1420 /* C code produced by gperf version 1.8.1 (K&R C version) */
1421 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1422
1423
1424 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1425
1426 #define MIN_WORD_LENGTH 3
1427 #define MAX_WORD_LENGTH 8
1428 #define MIN_HASH_VALUE 10
1429 #define MAX_HASH_VALUE 62
1430 /*
1431 21 keywords
1432 53 is the maximum key range
1433 */
1434
1435 static int
1436 hash (str, len)
1437 register char *str;
1438 register int len;
1439 {
1440 static unsigned char hash_table[] =
1441 {
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, 62, 62, 62,
1451 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1452 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1453 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1454 62, 62, 62, 62, 62, 62, 62, 62,
1455 };
1456 return len + hash_table[str[2]] + hash_table[str[0]];
1457 }
1458
1459 struct C_stab_entry *
1460 in_word_set (str, len)
1461 register char *str;
1462 register int len;
1463 {
1464
1465 static struct C_stab_entry wordlist[] =
1466 {
1467 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1468 {"",},
1469 {"volatile", 0, st_C_typespec},
1470 {"",},
1471 {"long", 0, st_C_typespec},
1472 {"char", 0, st_C_typespec},
1473 {"class", C_PLPL, st_C_struct},
1474 {"",}, {"",}, {"",}, {"",},
1475 {"const", 0, st_C_typespec},
1476 {"",}, {"",}, {"",}, {"",},
1477 {"auto", 0, st_C_typespec},
1478 {"",}, {"",},
1479 {"define", 0, st_C_define},
1480 {"",},
1481 {"void", 0, st_C_typespec},
1482 {"",}, {"",}, {"",},
1483 {"extern", 0, st_C_typespec},
1484 {"static", 0, st_C_typespec},
1485 {"",},
1486 {"domain", C_STAR, st_C_struct},
1487 {"",},
1488 {"typedef", 0, st_C_typedef},
1489 {"double", 0, st_C_typespec},
1490 {"enum", 0, st_C_enum},
1491 {"",}, {"",}, {"",}, {"",},
1492 {"int", 0, st_C_typespec},
1493 {"",},
1494 {"float", 0, st_C_typespec},
1495 {"",}, {"",}, {"",},
1496 {"struct", 0, st_C_struct},
1497 {"",}, {"",}, {"",}, {"",},
1498 {"union", 0, st_C_struct},
1499 {"",},
1500 {"short", 0, st_C_typespec},
1501 {"",}, {"",},
1502 {"unsigned", 0, st_C_typespec},
1503 {"signed", 0, st_C_typespec},
1504 };
1505
1506 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1507 {
1508 register int key = hash (str, len);
1509
1510 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1511 {
1512 register char *s = wordlist[key].name;
1513
1514 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1515 return &wordlist[key];
1516 }
1517 }
1518 return 0;
1519 }
1520 /*%>*/
1521
1522 enum sym_type
1523 C_symtype(str, len, c_ext)
1524 char *str;
1525 int len;
1526 int c_ext;
1527 {
1528 register struct C_stab_entry *se = in_word_set(str, len);
1529
1530 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1531 return st_none;
1532 return se->type;
1533 }
1534 \f
1535 /*
1536 * C functions are recognized using a simple finite automaton.
1537 * funcdef is its state variable.
1538 */
1539 typedef enum
1540 {
1541 fnone, /* nothing seen */
1542 ftagseen, /* function-like tag seen */
1543 fstartlist, /* just after open parenthesis */
1544 finlist, /* in parameter list */
1545 flistseen, /* after parameter list */
1546 fignore /* before open brace */
1547 } FUNCST;
1548 FUNCST funcdef;
1549
1550
1551 /*
1552 * typedefs are recognized using a simple finite automaton.
1553 * typeddef is its state variable.
1554 */
1555 typedef enum
1556 {
1557 tnone, /* nothing seen */
1558 ttypedseen, /* typedef keyword seen */
1559 tinbody, /* inside typedef body */
1560 tend, /* just before typedef tag */
1561 tignore /* junk after typedef tag */
1562 } TYPEDST;
1563 TYPEDST typdef;
1564
1565
1566 /*
1567 * struct-like structures (enum, struct and union) are recognized
1568 * using another simple finite automaton. `structdef' is its state
1569 * variable.
1570 */
1571 typedef enum
1572 {
1573 snone, /* nothing seen yet */
1574 skeyseen, /* struct-like keyword seen */
1575 stagseen, /* struct-like tag seen */
1576 scolonseen, /* colon seen after struct-like tag */
1577 sinbody /* in struct body: recognize member func defs*/
1578 } STRUCTST;
1579 STRUCTST structdef;
1580
1581 /*
1582 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1583 * struct tag, and structtype is the type of the preceding struct-like
1584 * keyword.
1585 */
1586 char *structtag = "<uninited>";
1587 enum sym_type structtype;
1588
1589 /*
1590 * Yet another little state machine to deal with preprocessor lines.
1591 */
1592 typedef enum
1593 {
1594 dnone, /* nothing seen */
1595 dsharpseen, /* '#' seen as first char on line */
1596 ddefineseen, /* '#' and 'define' seen */
1597 dignorerest /* ignore rest of line */
1598 } DEFINEST;
1599 DEFINEST definedef;
1600
1601 /*
1602 * Set this to TRUE, and the next token considered is called a function.
1603 * Used only for GNU emacs's function-defining macros.
1604 */
1605 logical next_token_is_func;
1606
1607 /*
1608 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1609 */
1610 logical yacc_rules;
1611
1612 /*
1613 * consider_token ()
1614 * checks to see if the current token is at the start of a
1615 * function, or corresponds to a typedef, or is a struct/union/enum
1616 * tag.
1617 *
1618 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1619 * C_EXT is which language we are looking at.
1620 *
1621 * In the future we will need some way to adjust where the end of
1622 * the token is; for instance, implementing the C++ keyword
1623 * `operator' properly will adjust the end of the token to be after
1624 * whatever follows `operator'.
1625 *
1626 * Globals
1627 * funcdef IN OUT
1628 * structdef IN OUT
1629 * definedef IN OUT
1630 * typdef IN OUT
1631 * next_token_is_func IN OUT
1632 */
1633
1634 logical
1635 consider_token (str, len, c, c_ext, cblev, is_func)
1636 register char *str; /* IN: token pointer */
1637 register int len; /* IN: token length */
1638 register char c; /* IN: first char after the token */
1639 int c_ext; /* IN: C extensions mask */
1640 int cblev; /* IN: curly brace level */
1641 logical *is_func; /* OUT: function found */
1642 {
1643 enum sym_type toktype = C_symtype (str, len, c_ext);
1644
1645 /*
1646 * Advance the definedef state machine.
1647 */
1648 switch (definedef)
1649 {
1650 case dnone:
1651 /* We're not on a preprocessor line. */
1652 break;
1653 case dsharpseen:
1654 if (toktype == st_C_define)
1655 {
1656 definedef = ddefineseen;
1657 }
1658 else
1659 {
1660 definedef = dignorerest;
1661 }
1662 return FALSE;
1663 case ddefineseen:
1664 /*
1665 * Make a tag for any macro, unless it is a constant
1666 * and constantypedefs is FALSE.
1667 */
1668 definedef = dignorerest;
1669 *is_func = (c == '(');
1670 if (!*is_func && !constantypedefs)
1671 return FALSE;
1672 else
1673 return TRUE;
1674 case dignorerest:
1675 return FALSE;
1676 default:
1677 error ("internal error: definedef value.", 0);
1678 }
1679
1680 /*
1681 * Now typedefs
1682 */
1683 switch (typdef)
1684 {
1685 case tnone:
1686 if (toktype == st_C_typedef)
1687 {
1688 if (typedefs)
1689 typdef = ttypedseen;
1690 funcdef = fnone;
1691 return FALSE;
1692 }
1693 break;
1694 case ttypedseen:
1695 switch (toktype)
1696 {
1697 case st_none:
1698 case st_C_typespec:
1699 typdef = tend;
1700 break;
1701 case st_C_struct:
1702 case st_C_enum:
1703 break;
1704 }
1705 /* Do not return here, so the structdef stuff has a chance. */
1706 break;
1707 case tend:
1708 switch (toktype)
1709 {
1710 case st_C_typespec:
1711 case st_C_struct:
1712 case st_C_enum:
1713 return FALSE;
1714 }
1715 return TRUE;
1716 }
1717
1718 /*
1719 * This structdef business is currently only invoked when cblev==0.
1720 * It should be recursively invoked whatever the curly brace level,
1721 * and a stack of states kept, to allow for definitions of structs
1722 * within structs.
1723 *
1724 * This structdef business is NOT invoked when we are ctags and the
1725 * file is plain C. This is because a struct tag may have the same
1726 * name as another tag, and this loses with ctags.
1727 *
1728 * This if statement deals with the typdef state machine as
1729 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1730 * return FALSE. All the other code here is for the structdef
1731 * state machine.
1732 */
1733 switch (toktype)
1734 {
1735 case st_C_struct:
1736 case st_C_enum:
1737 if (typdef == ttypedseen
1738 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1739 {
1740 structdef = skeyseen;
1741 structtype = toktype;
1742 }
1743 return FALSE;
1744 }
1745 if (structdef == skeyseen)
1746 {
1747 /* Save the tag for struct/union/class, for functions that may be
1748 defined inside. */
1749 if (structtype == st_C_struct)
1750 structtag = savenstr (str, len);
1751 else
1752 structtag = "<enum>";
1753 structdef = stagseen;
1754 return TRUE;
1755 }
1756
1757 /* Avoid entering funcdef stuff if typdef is going on. */
1758 if (typdef != tnone)
1759 {
1760 definedef = dnone;
1761 return FALSE;
1762 }
1763
1764 /* Detect GNU macros. */
1765 if (definedef == dnone)
1766 if (strneq (str, "DEFUN", 5) /* Used in emacs */
1767 #if FALSE
1768 These are defined inside C functions, so currently they
1769 are not met anyway.
1770 || strneq (str, "EXFUN", 5) /* Used in glibc */
1771 || strneq (str, "DEFVAR_", 7) /* Used in emacs */
1772 #endif
1773 || strneq (str, "SYSCALL", 7) /* Used in glibc (mach) */
1774 || strneq (str, "ENTRY", 5) /* Used in glibc */
1775 || strneq (str, "PSEUDO", 6)) /* Used in glibc */
1776
1777 {
1778 next_token_is_func = TRUE;
1779 return FALSE;
1780 }
1781 if (next_token_is_func)
1782 {
1783 next_token_is_func = FALSE;
1784 funcdef = fignore;
1785 *is_func = TRUE;
1786 return TRUE;
1787 }
1788
1789 /* A function? */
1790 switch (toktype)
1791 {
1792 case st_C_typespec:
1793 if (funcdef != finlist && funcdef != fignore)
1794 funcdef = fnone; /* should be useless */
1795 return FALSE;
1796 default:
1797 if (funcdef == fnone)
1798 {
1799 funcdef = ftagseen;
1800 *is_func = TRUE;
1801 return TRUE;
1802 }
1803 }
1804
1805 return FALSE;
1806 }
1807
1808 /*
1809 * C_entries ()
1810 * This routine finds functions, typedefs, #define's and
1811 * struct/union/enum definitions in C syntax and adds them
1812 * to the list.
1813 */
1814 typedef struct
1815 {
1816 logical valid;
1817 char *str;
1818 logical named;
1819 int linelen;
1820 int lineno;
1821 long linepos;
1822 char *buffer;
1823 } TOKEN;
1824
1825 #define current_lb_is_new (newndx == curndx)
1826 #define switch_line_buffers() (curndx = 1 - curndx)
1827
1828 #define curlb (lbs[curndx].lb)
1829 #define othlb (lbs[1-curndx].lb)
1830 #define newlb (lbs[newndx].lb)
1831 #define curlinepos (lbs[curndx].linepos)
1832 #define othlinepos (lbs[1-curndx].linepos)
1833 #define newlinepos (lbs[newndx].linepos)
1834
1835 #define CNL_SAVE_DEFINEDEF \
1836 do { \
1837 curlinepos = charno; \
1838 lineno++; \
1839 charno += readline (&curlb, inf); \
1840 lp = curlb.buffer; \
1841 quotednl = FALSE; \
1842 newndx = curndx; \
1843 } while (0)
1844
1845 #define CNL \
1846 do { \
1847 CNL_SAVE_DEFINEDEF; \
1848 if (savetok.valid) \
1849 { \
1850 tok = savetok; \
1851 savetok.valid = FALSE; \
1852 } \
1853 definedef = dnone; \
1854 } while (0)
1855
1856 #define make_tag(isfun) do \
1857 { \
1858 if (tok.valid) \
1859 pfnote (savestr (token_name.buffer), isfun, tok.named, \
1860 tok.buffer, tok.linelen, tok.lineno, tok.linepos); \
1861 else if (DEBUG) abort (); \
1862 tok.valid = FALSE; \
1863 } while (0)
1864
1865 void
1866 C_entries (c_ext, inf)
1867 int c_ext; /* extension of C */
1868 FILE *inf; /* input file */
1869 {
1870 register char c; /* latest char read; '\0' for end of line */
1871 register char *lp; /* pointer one beyond the character `c' */
1872 int curndx, newndx; /* indices for current and new lb */
1873 TOKEN tok; /* latest token read */
1874 register int tokoff; /* offset in line of start of current token */
1875 register int toklen; /* length of current token */
1876 int cblev; /* current curly brace level */
1877 int parlev; /* current parenthesis level */
1878 logical incomm, inquote, inchar, quotednl, midtoken;
1879 logical cplpl;
1880 TOKEN savetok; /* token saved during preprocessor handling */
1881
1882
1883 curndx = newndx = 0;
1884 lineno = 0;
1885 charno = 0;
1886 lp = curlb.buffer;
1887 *lp = 0;
1888
1889 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1890 next_token_is_func = yacc_rules = FALSE;
1891 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1892 tok.valid = savetok.valid = FALSE;
1893 cblev = 0;
1894 parlev = 0;
1895 cplpl = c_ext & C_PLPL;
1896
1897 while (!feof (inf))
1898 {
1899 c = *lp++;
1900 if (c == '\\')
1901 {
1902 /* If we're at the end of the line, the next character is a
1903 '\0'; don't skip it, because it's the thing that tells us
1904 to read the next line. */
1905 if (*lp == '\0')
1906 {
1907 quotednl = TRUE;
1908 continue;
1909 }
1910 lp++;
1911 c = ' ';
1912 }
1913 else if (incomm)
1914 {
1915 switch (c)
1916 {
1917 case '*':
1918 if (*lp == '/')
1919 {
1920 c = *lp++;
1921 incomm = FALSE;
1922 }
1923 break;
1924 case '\0':
1925 /* Newlines inside comments do not end macro definitions in
1926 traditional cpp. */
1927 CNL_SAVE_DEFINEDEF;
1928 break;
1929 }
1930 continue;
1931 }
1932 else if (inquote)
1933 {
1934 switch (c)
1935 {
1936 case '"':
1937 inquote = FALSE;
1938 break;
1939 case '\0':
1940 /* Newlines inside strings do not end macro definitions
1941 in traditional cpp, even though compilers don't
1942 usually accept them. */
1943 CNL_SAVE_DEFINEDEF;
1944 break;
1945 }
1946 continue;
1947 }
1948 else if (inchar)
1949 {
1950 switch (c)
1951 {
1952 case '\0':
1953 /* Hmmm, something went wrong. */
1954 CNL;
1955 /* FALLTHRU */
1956 case '\'':
1957 inchar = FALSE;
1958 break;
1959 }
1960 continue;
1961 }
1962 else
1963 switch (c)
1964 {
1965 case '"':
1966 inquote = TRUE;
1967 if (funcdef != finlist && funcdef != fignore)
1968 funcdef = fnone;
1969 continue;
1970 case '\'':
1971 inchar = TRUE;
1972 if (funcdef != finlist && funcdef != fignore)
1973 funcdef = fnone;
1974 continue;
1975 case '/':
1976 if (*lp == '*')
1977 {
1978 lp++;
1979 incomm = TRUE;
1980 continue;
1981 }
1982 else if (cplpl && *lp == '/')
1983 {
1984 c = 0;
1985 break;
1986 }
1987 else
1988 break;
1989 case '%':
1990 if ((c_ext & YACC) && *lp == '%')
1991 {
1992 /* entering or exiting rules section in yacc file */
1993 lp++;
1994 definedef = dnone; funcdef = fnone;
1995 typdef = tnone; structdef = snone;
1996 next_token_is_func = FALSE;
1997 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1998 cblev = 0;
1999 yacc_rules = !yacc_rules;
2000 continue;
2001 }
2002 else
2003 break;
2004 case '#':
2005 if (definedef == dnone)
2006 {
2007 char *cp;
2008 logical cpptoken = TRUE;
2009
2010 /* Look back on this line. If all blanks, or nonblanks
2011 followed by an end of comment, this is a preprocessor
2012 token. */
2013 for (cp = newlb.buffer; cp < lp-1; cp++)
2014 if (!iswhite (*cp))
2015 {
2016 if (*cp == '*' && *(cp+1) == '/')
2017 {
2018 cp++;
2019 cpptoken = TRUE;
2020 }
2021 else
2022 cpptoken = FALSE;
2023 }
2024 if (cpptoken)
2025 definedef = dsharpseen;
2026 } /* if (definedef == dnone) */
2027
2028 continue;
2029 } /* switch (c) */
2030
2031
2032 /* Consider token only if some complicated conditions are satisfied. */
2033 if ((definedef != dnone
2034 || (cblev == 0 && structdef != scolonseen)
2035 || (cblev == 1 && cplpl && structdef == sinbody))
2036 && typdef != tignore
2037 && definedef != dignorerest
2038 && funcdef != finlist)
2039 {
2040 if (midtoken)
2041 {
2042 if (endtoken (c))
2043 {
2044 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
2045 {
2046 /*
2047 * This handles :: in the middle, but not at the
2048 * beginning of an identifier.
2049 */
2050 lp += 2;
2051 toklen += 3;
2052 }
2053 else
2054 {
2055 logical is_func = FALSE;
2056
2057 if (yacc_rules
2058 || consider_token (newlb.buffer + tokoff, toklen,
2059 c, c_ext, cblev, &is_func))
2060 {
2061 if (structdef == sinbody
2062 && definedef == dnone
2063 && is_func)
2064 /* function defined in C++ class body */
2065 {
2066 int strsize = strlen(structtag) + 2 + toklen + 1;
2067 while (token_name.size < strsize)
2068 {
2069 token_name.size *= 2;
2070 token_name.buffer=xrealloc(token_name.buffer,
2071 token_name.size);
2072 }
2073 strcpy (token_name.buffer, structtag);
2074 strcat (token_name.buffer, "::");
2075 strncat (token_name.buffer,
2076 newlb.buffer+tokoff, toklen);
2077 tok.named = TRUE;
2078 }
2079 else
2080 {
2081 while (token_name.size < toklen + 1)
2082 {
2083 token_name.size *= 2;
2084 token_name.buffer=xrealloc(token_name.buffer,
2085 token_name.size);
2086 }
2087 strncpy (token_name.buffer,
2088 newlb.buffer+tokoff, toklen);
2089 token_name.buffer[toklen] = '\0';
2090 if (structdef == stagseen
2091 || typdef == tend
2092 || (is_func
2093 && definedef == dignorerest)) /* macro */
2094 tok.named = TRUE;
2095 else
2096 tok.named = FALSE;
2097 }
2098 tok.lineno = lineno;
2099 tok.linelen = tokoff + toklen + 1;
2100 tok.buffer = newlb.buffer;
2101 tok.linepos = newlinepos;
2102 tok.valid = TRUE;
2103
2104 if (definedef == dnone
2105 && (funcdef == ftagseen
2106 || structdef == stagseen
2107 || typdef == tend))
2108 {
2109 if (current_lb_is_new)
2110 switch_line_buffers ();
2111 }
2112 else
2113 make_tag (is_func);
2114 }
2115 midtoken = FALSE;
2116 }
2117 } /* if (endtoken (c)) */
2118 else if (intoken (c))
2119 {
2120 toklen++;
2121 continue;
2122 }
2123 } /* if (midtoken) */
2124 else if (begtoken (c))
2125 {
2126 switch (definedef)
2127 {
2128 case dnone:
2129 switch (funcdef)
2130 {
2131 case fstartlist:
2132 funcdef = finlist;
2133 continue;
2134 case flistseen:
2135 make_tag (TRUE);
2136 funcdef = fignore;
2137 break;
2138 case ftagseen:
2139 funcdef = fnone;
2140 break;
2141 }
2142 if (structdef == stagseen)
2143 structdef = snone;
2144 break;
2145 case dsharpseen:
2146 savetok = tok;
2147 }
2148 if (!yacc_rules || lp == newlb.buffer + 1)
2149 {
2150 tokoff = lp - 1 - newlb.buffer;
2151 toklen = 1;
2152 midtoken = TRUE;
2153 }
2154 continue;
2155 } /* if (begtoken) */
2156 } /* if must look at token */
2157
2158
2159 /* Detect end of line, colon, comma, semicolon and various braces
2160 after having handled a token.*/
2161 switch (c)
2162 {
2163 case ':':
2164 if (definedef != dnone)
2165 break;
2166 if (structdef == stagseen)
2167 structdef = scolonseen;
2168 else
2169 switch (funcdef)
2170 {
2171 case ftagseen:
2172 if (yacc_rules)
2173 {
2174 make_tag (FALSE);
2175 funcdef = fignore;
2176 }
2177 break;
2178 case fstartlist:
2179 funcdef = fnone;
2180 break;
2181 }
2182 break;
2183 case ';':
2184 if (definedef != dnone)
2185 break;
2186 if (cblev == 0)
2187 switch (typdef)
2188 {
2189 case tend:
2190 make_tag (FALSE);
2191 /* FALLTHRU */
2192 default:
2193 typdef = tnone;
2194 }
2195 if (funcdef != fignore)
2196 funcdef = fnone;
2197 if (structdef == stagseen)
2198 structdef = snone;
2199 break;
2200 case ',':
2201 if (definedef != dnone)
2202 break;
2203 if (funcdef != finlist && funcdef != fignore)
2204 funcdef = fnone;
2205 if (structdef == stagseen)
2206 structdef = snone;
2207 break;
2208 case '[':
2209 if (definedef != dnone)
2210 break;
2211 if (cblev == 0 && typdef == tend)
2212 {
2213 typdef = tignore;
2214 make_tag (FALSE);
2215 break;
2216 }
2217 if (funcdef != finlist && funcdef != fignore)
2218 funcdef = fnone;
2219 if (structdef == stagseen)
2220 structdef = snone;
2221 break;
2222 case '(':
2223 if (definedef != dnone)
2224 break;
2225 switch (funcdef)
2226 {
2227 case fnone:
2228 switch (typdef)
2229 {
2230 case ttypedseen:
2231 case tend:
2232 /* Make sure that the next char is not a '*'.
2233 This handles constructs like:
2234 typedef void OperatorFun (int fun); */
2235 if (*lp != '*')
2236 {
2237 typdef = tignore;
2238 make_tag (FALSE);
2239 }
2240 break;
2241 } /* switch (typdef) */
2242 break;
2243 case ftagseen:
2244 funcdef = fstartlist;
2245 break;
2246 case flistseen:
2247 funcdef = finlist;
2248 break;
2249 }
2250 parlev++;
2251 break;
2252 case ')':
2253 if (definedef != dnone)
2254 break;
2255 if (--parlev == 0)
2256 {
2257 switch (funcdef)
2258 {
2259 case fstartlist:
2260 case finlist:
2261 funcdef = flistseen;
2262 break;
2263 }
2264 if (cblev == 0 && typdef == tend)
2265 {
2266 typdef = tignore;
2267 make_tag (FALSE);
2268 }
2269 }
2270 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2271 parlev = 0;
2272 break;
2273 case '{':
2274 if (definedef != dnone)
2275 break;
2276 if (typdef == ttypedseen)
2277 typdef = tinbody;
2278 switch (structdef)
2279 {
2280 case skeyseen: /* unnamed struct */
2281 structtag = "_anonymous_";
2282 structdef = sinbody;
2283 break;
2284 case stagseen:
2285 case scolonseen: /* named struct */
2286 structdef = sinbody;
2287 make_tag (FALSE);
2288 break;
2289 }
2290 switch (funcdef)
2291 {
2292 case flistseen:
2293 make_tag (TRUE);
2294 /* FALLTHRU */
2295 case fignore:
2296 funcdef = fnone;
2297 break;
2298 case fnone:
2299 /* Neutralize `extern "C" {' grot and look inside structs. */
2300 if (cblev == 0 && structdef == snone && typdef == tnone)
2301 cblev = -1;
2302 }
2303 cblev++;
2304 break;
2305 case '*':
2306 if (definedef != dnone)
2307 break;
2308 if (funcdef == fstartlist)
2309 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
2310 break;
2311 case '}':
2312 if (definedef != dnone)
2313 break;
2314 if (!noindentypedefs && lp == newlb.buffer + 1)
2315 {
2316 cblev = 0; /* reset curly brace level if first column */
2317 parlev = 0; /* also reset paren level, just in case... */
2318 }
2319 else if (cblev > 0)
2320 cblev--;
2321 if (cblev == 0)
2322 {
2323 if (typdef == tinbody)
2324 typdef = tend;
2325 #if FALSE /* too risky */
2326 if (structdef == sinbody)
2327 free (structtag);
2328 #endif
2329
2330 structdef = snone;
2331 structtag = "<error>";
2332 }
2333 break;
2334 case '=':
2335 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2336 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
2337 if (definedef != dnone)
2338 break;
2339 /* These surely cannot follow a function tag. */
2340 if (funcdef != finlist && funcdef != fignore)
2341 funcdef = fnone;
2342 break;
2343 case '\0':
2344 /* If a macro spans multiple lines don't reset its state. */
2345 if (quotednl)
2346 CNL_SAVE_DEFINEDEF;
2347 else
2348 CNL;
2349 break;
2350 } /* switch (c) */
2351
2352 } /* while not eof */
2353 }
2354
2355 /*
2356 * Process either a C++ file or a C file depending on the setting
2357 * of a global flag.
2358 */
2359 void
2360 default_C_entries (inf)
2361 FILE *inf;
2362 {
2363 C_entries (cplusplus ? C_PLPL : 0, inf);
2364 }
2365
2366 /* Always do C++. */
2367 void
2368 Cplusplus_entries (inf)
2369 FILE *inf;
2370 {
2371 C_entries (C_PLPL, inf);
2372 }
2373
2374 /* Always do C*. */
2375 void
2376 Cstar_entries (inf)
2377 FILE *inf;
2378 {
2379 C_entries (C_STAR, inf);
2380 }
2381
2382 /* Always do Yacc. */
2383 void
2384 Yacc_entries (inf)
2385 FILE *inf;
2386 {
2387 C_entries (YACC, inf);
2388 }
2389 \f
2390 /* Fortran parsing */
2391
2392 char *dbp;
2393
2394 logical
2395 tail (cp)
2396 char *cp;
2397 {
2398 register int len = 0;
2399
2400 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2401 cp++, len++;
2402 if (*cp == 0)
2403 {
2404 dbp += len;
2405 return TRUE;
2406 }
2407 return FALSE;
2408 }
2409
2410 void
2411 takeprec ()
2412 {
2413 while (isspace (*dbp))
2414 dbp++;
2415 if (*dbp != '*')
2416 return;
2417 dbp++;
2418 while (isspace (*dbp))
2419 dbp++;
2420 if (tail ("(*)"))
2421 return;
2422 if (!isdigit (*dbp))
2423 {
2424 --dbp; /* force failure */
2425 return;
2426 }
2427 do
2428 dbp++;
2429 while (isdigit (*dbp));
2430 }
2431
2432 void
2433 getit (inf)
2434 FILE *inf;
2435 {
2436 register char *cp;
2437
2438 while (isspace (*dbp))
2439 dbp++;
2440 if (*dbp == '\0')
2441 {
2442 lineno++;
2443 linecharno = charno;
2444 charno += readline (&lb, inf);
2445 dbp = lb.buffer;
2446 if (dbp[5] != '&')
2447 return;
2448 dbp += 6;
2449 while (isspace (*dbp))
2450 dbp++;
2451 }
2452 if (!isalpha (*dbp)
2453 && *dbp != '_'
2454 && *dbp != '$')
2455 return;
2456 for (cp = dbp + 1;
2457 (*cp
2458 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2459 cp++)
2460 continue;
2461 pfnote (savenstr (dbp, cp-dbp), TRUE, FALSE, lb.buffer,
2462 cp - lb.buffer + 1, lineno, linecharno);
2463 }
2464
2465 void
2466 Fortran_functions (inf)
2467 FILE *inf;
2468 {
2469 lineno = 0;
2470 charno = 0;
2471
2472 while (!feof (inf))
2473 {
2474 lineno++;
2475 linecharno = charno;
2476 charno += readline (&lb, inf);
2477 dbp = lb.buffer;
2478 if (*dbp == '%')
2479 dbp++; /* Ratfor escape to fortran */
2480 while (isspace (*dbp))
2481 dbp++;
2482 if (*dbp == 0)
2483 continue;
2484 switch (*dbp | ' ')
2485 {
2486 case 'i':
2487 if (tail ("integer"))
2488 takeprec ();
2489 break;
2490 case 'r':
2491 if (tail ("real"))
2492 takeprec ();
2493 break;
2494 case 'l':
2495 if (tail ("logical"))
2496 takeprec ();
2497 break;
2498 case 'c':
2499 if (tail ("complex") || tail ("character"))
2500 takeprec ();
2501 break;
2502 case 'd':
2503 if (tail ("double"))
2504 {
2505 while (isspace (*dbp))
2506 dbp++;
2507 if (*dbp == 0)
2508 continue;
2509 if (tail ("precision"))
2510 break;
2511 continue;
2512 }
2513 break;
2514 }
2515 while (isspace (*dbp))
2516 dbp++;
2517 if (*dbp == 0)
2518 continue;
2519 switch (*dbp | ' ')
2520 {
2521 case 'f':
2522 if (tail ("function"))
2523 getit (inf);
2524 continue;
2525 case 's':
2526 if (tail ("subroutine"))
2527 getit (inf);
2528 continue;
2529 case 'e':
2530 if (tail ("entry"))
2531 getit (inf);
2532 continue;
2533 case 'p':
2534 if (tail ("program"))
2535 {
2536 getit (inf);
2537 continue;
2538 }
2539 if (tail ("procedure"))
2540 getit (inf);
2541 continue;
2542 }
2543 }
2544 }
2545 \f
2546 /*
2547 * Bob Weiner, Motorola Inc., 4/3/94
2548 * Unix and microcontroller assembly tag handling
2549 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2550 */
2551 void
2552 Asm_labels (inf)
2553 FILE *inf;
2554 {
2555 register char *cp;
2556
2557 lineno = 0;
2558 charno = 0;
2559
2560 while (!feof (inf))
2561 {
2562 lineno++;
2563 linecharno = charno;
2564 charno += readline (&lb, inf);
2565 cp = lb.buffer;
2566
2567 /* If first char is alphabetic or one of [_.$], test for colon
2568 following identifier. */
2569 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2570 {
2571 /* Read past label. */
2572 cp++;
2573 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2574 cp++;
2575 if (*cp == ':' || isspace (*cp))
2576 {
2577 /* Found end of label, so copy it and add it to the table. */
2578 pfnote (savenstr (lb.buffer, cp-lb.buffer), TRUE, FALSE,
2579 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2580 }
2581 }
2582 }
2583 }
2584 \f
2585 /* Added by Mosur Mohan, 4/22/88 */
2586 /* Pascal parsing */
2587
2588 #define GET_NEW_LINE \
2589 { \
2590 linecharno = charno; lineno++; \
2591 charno += 1 + readline (&lb, inf); \
2592 dbp = lb.buffer; \
2593 }
2594
2595 /*
2596 * Locates tags for procedures & functions. Doesn't do any type- or
2597 * var-definitions. It does look for the keyword "extern" or
2598 * "forward" immediately following the procedure statement; if found,
2599 * the tag is skipped.
2600 */
2601 void
2602 Pascal_functions (inf)
2603 FILE *inf;
2604 {
2605 struct linebuffer tline; /* mostly copied from C_entries */
2606 long save_lcno;
2607 int save_lineno;
2608 char c, *cp;
2609 char *nambuf;
2610
2611 logical /* each of these flags is TRUE iff: */
2612 incomment, /* point is inside a comment */
2613 inquote, /* point is inside '..' string */
2614 get_tagname, /* point is after PROCEDURE/FUNCTION */
2615 /* keyword, so next item = potential tag */
2616 found_tag, /* point is after a potential tag */
2617 inparms, /* point is within parameter-list */
2618 verify_tag; /* point has passed the parm-list, so the */
2619 /* next token will determine whether */
2620 /* this is a FORWARD/EXTERN to be */
2621 /* ignored, or whether it is a real tag */
2622
2623 lineno = 0;
2624 charno = 0;
2625 dbp = lb.buffer;
2626 *dbp = 0;
2627 initbuffer (&tline);
2628
2629 incomment = inquote = FALSE;
2630 found_tag = FALSE; /* have a proc name; check if extern */
2631 get_tagname = FALSE; /* have found "procedure" keyword */
2632 inparms = FALSE; /* found '(' after "proc" */
2633 verify_tag = FALSE; /* check if "extern" is ahead */
2634
2635 /* long main loop to get next char */
2636 while (!feof (inf))
2637 {
2638 c = *dbp++;
2639 if (c == '\0') /* if end of line */
2640 {
2641 GET_NEW_LINE;
2642 if (*dbp == '\0')
2643 continue;
2644 if (!((found_tag && verify_tag) ||
2645 get_tagname))
2646 c = *dbp++; /* only if don't need *dbp pointing */
2647 /* to the beginning of the name of */
2648 /* the procedure or function */
2649 }
2650 if (incomment)
2651 {
2652 if (c == '}') /* within { - } comments */
2653 incomment = FALSE;
2654 else if (c == '*' && dbp[1] == ')') /* within (* - *) comments */
2655 {
2656 dbp++;
2657 incomment = FALSE;
2658 }
2659 continue;
2660 }
2661 else if (inquote)
2662 {
2663 if (c == '\'')
2664 inquote = FALSE;
2665 continue;
2666 }
2667 else
2668 switch (c)
2669 {
2670 case '\'':
2671 inquote = TRUE; /* found first quote */
2672 continue;
2673 case '{': /* found open-{-comment */
2674 incomment = TRUE;
2675 continue;
2676 case '(':
2677 if (*dbp == '*') /* found open-(*-comment */
2678 {
2679 incomment = TRUE;
2680 dbp++;
2681 }
2682 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2683 inparms = TRUE;
2684 continue;
2685 case ')': /* end of parms list */
2686 if (inparms)
2687 inparms = FALSE;
2688 continue;
2689 case ';':
2690 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2691 {
2692 verify_tag = TRUE;
2693 break;
2694 }
2695 continue;
2696 }
2697 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2698 {
2699 /* check if this is an "extern" declaration */
2700 if (*dbp == 0)
2701 continue;
2702 if ((*dbp == 'e') || (*dbp == 'E'))
2703 {
2704 if (tail ("extern")) /* superfluous, really! */
2705 {
2706 found_tag = FALSE;
2707 verify_tag = FALSE;
2708 }
2709 }
2710 else if ((*dbp == 'f') || (*dbp == 'F'))
2711 {
2712 if (tail ("forward")) /* check for forward reference */
2713 {
2714 found_tag = FALSE;
2715 verify_tag = FALSE;
2716 }
2717 }
2718 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2719 {
2720 found_tag = FALSE;
2721 verify_tag = FALSE;
2722 pfnote (nambuf, TRUE, FALSE, tline.buffer,
2723 cp - tline.buffer + 1, save_lineno, save_lcno);
2724 continue;
2725 }
2726 }
2727 if (get_tagname) /* grab name of proc or fn */
2728 {
2729 if (*dbp == 0)
2730 continue;
2731
2732 /* save all values for later tagging */
2733 tline.size = lb.size;
2734 strcpy (tline.buffer, lb.buffer);
2735 save_lineno = lineno;
2736 save_lcno = linecharno;
2737
2738 /* grab block name */
2739 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2740 continue;
2741 nambuf = savenstr (dbp, cp-dbp);
2742 dbp = cp; /* restore dbp to e-o-token */
2743 get_tagname = FALSE;
2744 found_tag = TRUE;
2745 continue;
2746
2747 /* and proceed to check for "extern" */
2748 }
2749 else if (!incomment && !inquote && !found_tag)
2750 {
2751 /* check for proc/fn keywords */
2752 switch (c | ' ')
2753 {
2754 case 'p':
2755 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2756 get_tagname = TRUE;
2757 continue;
2758 case 'f':
2759 if (tail ("unction"))
2760 get_tagname = TRUE;
2761 continue;
2762 }
2763 }
2764 } /* while not eof */
2765 }
2766 \f
2767 /*
2768 * lisp tag functions
2769 * look for (def or (DEF, quote or QUOTE
2770 */
2771 int
2772 L_isdef (strp)
2773 register char *strp;
2774 {
2775 return ((strp[1] == 'd' || strp[1] == 'D')
2776 && (strp[2] == 'e' || strp[2] == 'E')
2777 && (strp[3] == 'f' || strp[3] == 'F'));
2778 }
2779
2780 int
2781 L_isquote (strp)
2782 register char *strp;
2783 {
2784 return ((*(++strp) == 'q' || *strp == 'Q')
2785 && (*(++strp) == 'u' || *strp == 'U')
2786 && (*(++strp) == 'o' || *strp == 'O')
2787 && (*(++strp) == 't' || *strp == 'T')
2788 && (*(++strp) == 'e' || *strp == 'E')
2789 && isspace(*(++strp)));
2790 }
2791
2792 void
2793 L_getit ()
2794 {
2795 register char *cp;
2796
2797 if (*dbp == '\'') /* Skip prefix quote */
2798 dbp++;
2799 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2800 {
2801 dbp += 7;
2802 while (isspace(*dbp))
2803 dbp++;
2804 }
2805 for (cp = dbp /*+1*/;
2806 *cp && *cp != '(' && *cp != ' ' && *cp != ')';
2807 cp++)
2808 continue;
2809 if (cp == dbp)
2810 return;
2811
2812 pfnote (savenstr (dbp, cp-dbp), TRUE, FALSE, lb.buffer,
2813 cp - lb.buffer + 1, lineno, linecharno);
2814 }
2815
2816 void
2817 Lisp_functions (inf)
2818 FILE *inf;
2819 {
2820 lineno = 0;
2821 charno = 0;
2822
2823 while (!feof (inf))
2824 {
2825 lineno++;
2826 linecharno = charno;
2827 charno += readline (&lb, inf);
2828 dbp = lb.buffer;
2829 if (dbp[0] == '(')
2830 {
2831 if (L_isdef (dbp))
2832 {
2833 while (!isspace (*dbp))
2834 dbp++;
2835 while (isspace (*dbp))
2836 dbp++;
2837 L_getit ();
2838 }
2839 else
2840 {
2841 /* Check for (foo::defmumble name-defined ... */
2842 do
2843 dbp++;
2844 while (*dbp && !isspace (*dbp)
2845 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2846 if (*dbp == ':')
2847 {
2848 do
2849 dbp++;
2850 while (*dbp == ':');
2851
2852 if (L_isdef (dbp - 1))
2853 {
2854 while (!isspace (*dbp))
2855 dbp++;
2856 while (isspace (*dbp))
2857 dbp++;
2858 L_getit ();
2859 }
2860 }
2861 }
2862 }
2863 }
2864 }
2865 \f
2866 /*
2867 * Scheme tag functions
2868 * look for (def... xyzzy
2869 * look for (def... (xyzzy
2870 * look for (def ... ((...(xyzzy ....
2871 * look for (set! xyzzy
2872 */
2873
2874 void get_scheme ();
2875
2876 void
2877 Scheme_functions (inf)
2878 FILE *inf;
2879 {
2880 lineno = 0;
2881 charno = 0;
2882
2883 while (!feof (inf))
2884 {
2885 lineno++;
2886 linecharno = charno;
2887 charno += readline (&lb, inf);
2888 dbp = lb.buffer;
2889 if (dbp[0] == '(' &&
2890 (dbp[1] == 'D' || dbp[1] == 'd') &&
2891 (dbp[2] == 'E' || dbp[2] == 'e') &&
2892 (dbp[3] == 'F' || dbp[3] == 'f'))
2893 {
2894 while (!isspace (*dbp))
2895 dbp++;
2896 /* Skip over open parens and white space */
2897 while (*dbp && (isspace (*dbp) || *dbp == '('))
2898 dbp++;
2899 get_scheme ();
2900 }
2901 if (dbp[0] == '(' &&
2902 (dbp[1] == 'S' || dbp[1] == 's') &&
2903 (dbp[2] == 'E' || dbp[2] == 'e') &&
2904 (dbp[3] == 'T' || dbp[3] == 't') &&
2905 (dbp[4] == '!' || dbp[4] == '!') &&
2906 (isspace (dbp[5])))
2907 {
2908 while (!isspace (*dbp))
2909 dbp++;
2910 /* Skip over white space */
2911 while (isspace (*dbp))
2912 dbp++;
2913 get_scheme ();
2914 }
2915 }
2916 }
2917
2918 void
2919 get_scheme ()
2920 {
2921 register char *cp;
2922
2923 if (*dbp == 0)
2924 return;
2925 /* Go till you get to white space or a syntactic break */
2926 for (cp = dbp + 1;
2927 *cp && *cp != '(' && *cp != ')' && !isspace (*cp);
2928 cp++)
2929 continue;
2930 pfnote (savenstr (dbp, cp-dbp), TRUE, FALSE,
2931 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2932 }
2933 \f
2934 /* Find tags in TeX and LaTeX input files. */
2935
2936 /* TEX_toktab is a table of TeX control sequences that define tags.
2937 Each TEX_tabent records one such control sequence.
2938 CONVERT THIS TO USE THE Stab TYPE!! */
2939 struct TEX_tabent
2940 {
2941 char *name;
2942 int len;
2943 };
2944
2945 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2946
2947 /* Default set of control sequences to put into TEX_toktab.
2948 The value of environment var TEXTAGS is prepended to this. */
2949
2950 char *TEX_defenv = "\
2951 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2952
2953 void TEX_mode ();
2954 struct TEX_tabent *TEX_decode_env ();
2955 void TEX_getit ();
2956 int TEX_Token ();
2957
2958 char TEX_esc = '\\';
2959 char TEX_opgrp = '{';
2960 char TEX_clgrp = '}';
2961
2962 /*
2963 * TeX/LaTeX scanning loop.
2964 */
2965 void
2966 TeX_functions (inf)
2967 FILE *inf;
2968 {
2969 char *lasthit;
2970
2971 lineno = 0;
2972 charno = 0;
2973
2974 /* Select either \ or ! as escape character. */
2975 TEX_mode (inf);
2976
2977 /* Initialize token table once from environment. */
2978 if (!TEX_toktab)
2979 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2980
2981 while (!feof (inf))
2982 { /* Scan each line in file */
2983 lineno++;
2984 linecharno = charno;
2985 charno += readline (&lb, inf);
2986 dbp = lb.buffer;
2987 lasthit = dbp;
2988 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
2989 {
2990 register int i;
2991
2992 if (!*(++dbp))
2993 break;
2994 linecharno += dbp - lasthit;
2995 lasthit = dbp;
2996 i = TEX_Token (lasthit);
2997 if (0 <= i)
2998 {
2999 TEX_getit (lasthit, TEX_toktab[i].len);
3000 break; /* We only save a line once */
3001 }
3002 }
3003 }
3004 }
3005
3006 #define TEX_LESC '\\'
3007 #define TEX_SESC '!'
3008 #define TEX_cmt '%'
3009
3010 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
3011 chars accordingly. */
3012 void
3013 TEX_mode (inf)
3014 FILE *inf;
3015 {
3016 int c;
3017
3018 while ((c = getc (inf)) != EOF)
3019 {
3020 /* Skip to next line if we hit the TeX comment char. */
3021 if (c == TEX_cmt)
3022 while (c != '\n')
3023 c = getc (inf);
3024 else if (c == TEX_LESC || c == TEX_SESC )
3025 break;
3026 }
3027
3028 if (c == TEX_LESC)
3029 {
3030 TEX_esc = TEX_LESC;
3031 TEX_opgrp = '{';
3032 TEX_clgrp = '}';
3033 }
3034 else
3035 {
3036 TEX_esc = TEX_SESC;
3037 TEX_opgrp = '<';
3038 TEX_clgrp = '>';
3039 }
3040 rewind (inf);
3041 }
3042
3043 /* Read environment and prepend it to the default string.
3044 Build token table. */
3045 struct TEX_tabent *
3046 TEX_decode_env (evarname, defenv)
3047 char *evarname;
3048 char *defenv;
3049 {
3050 register char *env, *p;
3051
3052 struct TEX_tabent *tab;
3053 int size, i;
3054
3055 /* Append default string to environment. */
3056 env = getenv (evarname);
3057 if (!env)
3058 env = defenv;
3059 else
3060 env = concat (env, defenv, "");
3061
3062 /* Allocate a token table */
3063 for (size = 1, p = env; p;)
3064 if ((p = etags_strchr (p, ':')) && *(++p))
3065 size++;
3066 /* Add 1 to leave room for null terminator. */
3067 tab = xnew (size + 1, struct TEX_tabent);
3068
3069 /* Unpack environment string into token table. Be careful about */
3070 /* zero-length strings (leading ':', "::" and trailing ':') */
3071 for (i = 0; *env;)
3072 {
3073 p = etags_strchr (env, ':');
3074 if (!p) /* End of environment string. */
3075 p = env + strlen (env);
3076 if (p - env > 0)
3077 { /* Only non-zero strings. */
3078 tab[i].name = savenstr (env, p - env);
3079 tab[i].len = strlen (tab[i].name);
3080 i++;
3081 }
3082 if (*p)
3083 env = p + 1;
3084 else
3085 {
3086 tab[i].name = NULL; /* Mark end of table. */
3087 tab[i].len = 0;
3088 break;
3089 }
3090 }
3091 return tab;
3092 }
3093
3094 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
3095 The name being defined actually starts at (NAME + LEN + 1).
3096 But we seem to include the TeX command in the tag name. */
3097 void
3098 TEX_getit (name, len)
3099 char *name;
3100 int len;
3101 {
3102 char *p = name + len;
3103
3104 if (*name == 0)
3105 return;
3106
3107 /* Let tag name extend to next group close (or end of line) */
3108 while (*p && *p != TEX_clgrp)
3109 p++;
3110 pfnote (savenstr (name, p-name), TRUE, FALSE, lb.buffer,
3111 strlen (lb.buffer), lineno, linecharno);
3112 }
3113
3114 /* If the text at CP matches one of the tag-defining TeX command names,
3115 return the pointer to the first occurrence of that command in TEX_toktab.
3116 Otherwise return -1.
3117 Keep the capital `T' in `Token' for dumb truncating compilers
3118 (this distinguishes it from `TEX_toktab' */
3119 int
3120 TEX_Token (cp)
3121 char *cp;
3122 {
3123 int i;
3124
3125 for (i = 0; TEX_toktab[i].len > 0; i++)
3126 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
3127 return i;
3128 return -1;
3129 }
3130 \f
3131 /* Support for Prolog. */
3132
3133 /* Whole head (not only functor, but also arguments)
3134 is gotten in compound term. */
3135 void
3136 prolog_getit (s)
3137 char *s;
3138 {
3139 char *save_s;
3140 int insquote, npar;
3141
3142 save_s = s;
3143 insquote = FALSE;
3144 npar = 0;
3145 while (1)
3146 {
3147 if (s[0] == '\0') /* syntax error. */
3148 return;
3149 else if (insquote && s[0] == '\'' && s[1] == '\'')
3150 s += 2;
3151 else if (s[0] == '\'')
3152 {
3153 insquote = !insquote;
3154 s++;
3155 }
3156 else if (!insquote && s[0] == '(')
3157 {
3158 npar++;
3159 s++;
3160 }
3161 else if (!insquote && s[0] == ')')
3162 {
3163 npar--;
3164 s++;
3165 if (npar == 0)
3166 break;
3167 else if (npar < 0) /* syntax error. */
3168 return;
3169 }
3170 else if (!insquote && s[0] == '.'
3171 && (isspace (s[1]) || s[1] == '\0'))
3172 { /* fullstop. */
3173 if (npar != 0) /* syntax error. */
3174 return;
3175 s++;
3176 break;
3177 }
3178 else
3179 s++;
3180 }
3181 pfnote (savenstr (save_s, s-save_s), TRUE, FALSE,
3182 save_s, s-save_s, lineno, linecharno);
3183 }
3184
3185 /* It is assumed that prolog predicate starts from column 0. */
3186 void
3187 Prolog_functions (inf)
3188 FILE *inf;
3189 {
3190 void skip_comment (), prolog_getit ();
3191
3192 lineno = linecharno = charno = 0;
3193 while (!feof (inf))
3194 {
3195 lineno++;
3196 linecharno += charno;
3197 charno = readline (&lb, inf) + 1; /* 1 for newline. */
3198 dbp = lb.buffer;
3199 if (isspace (dbp[0])) /* not predicate header. */
3200 continue;
3201 else if (dbp[0] == '%') /* comment. */
3202 continue;
3203 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
3204 skip_comment (&lb, inf, &lineno, &linecharno);
3205 else /* found. */
3206 prolog_getit (dbp);
3207 }
3208 }
3209
3210 void
3211 skip_comment (plb, inf, plineno, plinecharno)
3212 struct linebuffer *plb;
3213 FILE *inf;
3214 int *plineno; /* result */
3215 long *plinecharno; /* result */
3216 {
3217 char *cp;
3218
3219 do
3220 {
3221 for (cp = plb->buffer; *cp != '\0'; cp++)
3222 if (cp[0] == '*' && cp[1] == '/')
3223 return;
3224 (*plineno)++;
3225 *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
3226 }
3227 while (!feof(inf));
3228 }
3229 \f
3230 #ifdef ETAGS_REGEXPS
3231 /* Take a string like "/blah/" and turn it into "blah", making sure
3232 that the first and last characters are the same, and handling
3233 quoted separator characters. Actually, stops on the occurence of
3234 an unquoted separator. Also turns "\t" into a Tab character.
3235 Returns pointer to terminating separator. Works in place. Null
3236 terminates name string. */
3237 char *
3238 scan_separators (name)
3239 char *name;
3240 {
3241 char sep = name[0];
3242 char *copyto = name;
3243 logical quoted = FALSE;
3244
3245 for (++name; *name != '\0'; ++name)
3246 {
3247 if (quoted)
3248 {
3249 if (*name == 't')
3250 *copyto++ = '\t';
3251 else if (*name == sep)
3252 *copyto++ = sep;
3253 else
3254 {
3255 /* Something else is quoted, so preserve the quote. */
3256 *copyto++ = '\\';
3257 *copyto++ = *name;
3258 }
3259 quoted = FALSE;
3260 }
3261 else if (*name == '\\')
3262 quoted = TRUE;
3263 else if (*name == sep)
3264 break;
3265 else
3266 *copyto++ = *name;
3267 }
3268
3269 /* Terminate copied string. */
3270 *copyto = '\0';
3271 return name;
3272 }
3273
3274 /* Turn a name, which is an ed-style (but Emacs syntax) regular
3275 expression, into a real regular expression by compiling it. */
3276 void
3277 add_regex (regexp_pattern)
3278 char *regexp_pattern;
3279 {
3280 char *name;
3281 const char *err;
3282 struct re_pattern_buffer *patbuf;
3283
3284 if (regexp_pattern == NULL)
3285 {
3286 /* Remove existing regexps. */
3287 num_patterns = 0;
3288 patterns = NULL;
3289 return;
3290 }
3291
3292 if (regexp_pattern[0] == '\0')
3293 {
3294 error ("missing regexp", 0);
3295 return;
3296 }
3297 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
3298 {
3299 error ("%s: unterminated regexp", regexp_pattern);
3300 return;
3301 }
3302 name = scan_separators (regexp_pattern);
3303 if (regexp_pattern[0] == '\0')
3304 {
3305 error ("null regexp", 0);
3306 return;
3307 }
3308 (void) scan_separators (name);
3309
3310 patbuf = xnew (1, struct re_pattern_buffer);
3311 patbuf->translate = NULL;
3312 patbuf->fastmap = NULL;
3313 patbuf->buffer = NULL;
3314 patbuf->allocated = 0;
3315
3316 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
3317 if (err != NULL)
3318 {
3319 error ("%s while compiling pattern", err);
3320 return;
3321 }
3322
3323 num_patterns += 1;
3324 if (num_patterns == 1)
3325 patterns = xnew (1, struct pattern);
3326 else
3327 patterns = ((struct pattern *)
3328 xrealloc (patterns,
3329 (num_patterns * sizeof (struct pattern))));
3330 patterns[num_patterns - 1].pattern = patbuf;
3331 patterns[num_patterns - 1].name_pattern = savestr (name);
3332 patterns[num_patterns - 1].error_signaled = FALSE;
3333 }
3334
3335 /*
3336 * Do the subtitutions indicated by the regular expression and
3337 * arguments.
3338 */
3339 char *
3340 substitute (in, out, regs)
3341 char *in, *out;
3342 struct re_registers *regs;
3343 {
3344 char *result = NULL, *t;
3345 int size = 0;
3346
3347 /* Pass 1: figure out how much size to allocate. */
3348 for (t = out; *t; ++t)
3349 {
3350 if (*t == '\\')
3351 {
3352 ++t;
3353 if (!*t)
3354 {
3355 fprintf (stderr, "%s: pattern subtitution ends prematurely\n",
3356 progname);
3357 return NULL;
3358 }
3359 if (isdigit (*t))
3360 {
3361 int dig = *t - '0';
3362 size += regs->end[dig] - regs->start[dig];
3363 }
3364 }
3365 }
3366
3367 /* Allocate space and do the substitutions. */
3368 result = xnew (size + 1, char);
3369 size = 0;
3370 for (; *out; ++out)
3371 {
3372 if (*out == '\\')
3373 {
3374 ++out;
3375 if (isdigit (*out))
3376 {
3377 /* Using "dig2" satisfies my debugger. Bleah. */
3378 int dig2 = *out - '0';
3379 strncpy (result + size, in + regs->start[dig2],
3380 regs->end[dig2] - regs->start[dig2]);
3381 size += regs->end[dig2] - regs->start[dig2];
3382 }
3383 else
3384 {
3385 switch (*out)
3386 {
3387 case '\t':
3388 result[size++] = '\t';
3389 break;
3390 case '\\':
3391 *out = '\\';
3392 break;
3393 default:
3394 result[size++] = *out;
3395 break;
3396 }
3397 }
3398 }
3399 else
3400 result[size++] = *out;
3401 }
3402 result[size] = '\0';
3403
3404 return result;
3405 }
3406 \f
3407 #endif /* ETAGS_REGEXPS */
3408 /* Initialize a linebuffer for use */
3409 void
3410 initbuffer (linebuffer)
3411 struct linebuffer *linebuffer;
3412 {
3413 linebuffer->size = 200;
3414 linebuffer->buffer = xnew (200, char);
3415 }
3416
3417 /*
3418 * Read a line of text from `stream' into `linebuffer'.
3419 * Return the number of characters read from `stream',
3420 * which is the length of the line including the newline, if any.
3421 */
3422 long
3423 readline_internal (linebuffer, stream)
3424 struct linebuffer *linebuffer;
3425 register FILE *stream;
3426 {
3427 char *buffer = linebuffer->buffer;
3428 register char *p = linebuffer->buffer;
3429 register char *pend;
3430 int chars_deleted;
3431
3432 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
3433
3434 while (1)
3435 {
3436 register int c = getc (stream);
3437 if (p == pend)
3438 {
3439 linebuffer->size *= 2;
3440 buffer = (char *) xrealloc (buffer, linebuffer->size);
3441 p += buffer - linebuffer->buffer;
3442 pend = buffer + linebuffer->size;
3443 linebuffer->buffer = buffer;
3444 }
3445 if (c == EOF)
3446 {
3447 chars_deleted = 0;
3448 break;
3449 }
3450 if (c == '\n')
3451 {
3452 if (p > buffer && p[-1] == '\r')
3453 {
3454 *--p = '\0';
3455 chars_deleted = 2;
3456 }
3457 else
3458 {
3459 *p = '\0';
3460 chars_deleted = 1;
3461 }
3462 break;
3463 }
3464 *p++ = c;
3465 }
3466
3467 return p - buffer + chars_deleted;
3468 }
3469
3470 /*
3471 * Like readline_internal, above, but try to match the input
3472 * line against any existing regular expressions.
3473 */
3474 long
3475 readline (linebuffer, stream)
3476 struct linebuffer *linebuffer;
3477 FILE *stream;
3478 {
3479 /* Read new line. */
3480 int i;
3481 long result = readline_internal (linebuffer, stream);
3482
3483 #ifdef ETAGS_REGEXPS
3484 /* Match against all listed patterns. */
3485 for (i = 0; i < num_patterns; ++i)
3486 {
3487 int match = re_match (patterns[i].pattern, linebuffer->buffer,
3488 (int)result, 0, &patterns[i].regs);
3489 switch (match)
3490 {
3491 case -2:
3492 /* Some error. */
3493 if (!patterns[i].error_signaled)
3494 {
3495 error ("error while matching pattern %d", i);
3496 patterns[i].error_signaled = TRUE;
3497 }
3498 break;
3499 case -1:
3500 /* No match. */
3501 break;
3502 default:
3503 /* Match occurred. Construct a tag. */
3504 if (patterns[i].name_pattern[0] != '\0')
3505 {
3506 /* Make a named tag. */
3507 char *name = substitute (linebuffer->buffer,
3508 patterns[i].name_pattern,
3509 &patterns[i].regs);
3510 if (name != NULL)
3511 pfnote (name, TRUE, TRUE, linebuffer->buffer,
3512 match, lineno, linecharno);
3513 }
3514 else
3515 {
3516 /* Make an unnamed tag. */
3517 pfnote (NULL, TRUE, FALSE, linebuffer->buffer,
3518 match, lineno, linecharno);
3519 }
3520 break;
3521 }
3522 }
3523 #endif /* ETAGS_REGEXPS */
3524
3525 return result;
3526 }
3527
3528 /*
3529 * Read a file, but do no processing. This is used to do regexp
3530 * matching on files that have no language defined.
3531 */
3532 void
3533 just_read_file (inf)
3534 FILE *inf;
3535 {
3536 while (!feof (inf))
3537 {
3538 ++lineno;
3539 linecharno = charno;
3540 charno += readline (&lb, inf) + 1;
3541 }
3542 }
3543
3544 \f
3545 /*
3546 * Return a pointer to a space of size strlen(cp)+1 allocated
3547 * with xnew where the string CP has been copied.
3548 */
3549 char *
3550 savestr (cp)
3551 char *cp;
3552 {
3553 return savenstr (cp, strlen (cp));
3554 }
3555
3556 /*
3557 * Return a pointer to a space of size LEN+1 allocated with xnew where
3558 * the string CP has been copied for at most the first LEN characters.
3559 */
3560 char *
3561 savenstr (cp, len)
3562 char *cp;
3563 int len;
3564 {
3565 register char *dp;
3566
3567 dp = xnew (len + 1, char);
3568 strncpy (dp, cp, len);
3569 dp[len] = '\0';
3570 return dp;
3571 }
3572
3573 /*
3574 * Return the ptr in sp at which the character c last
3575 * appears; NULL if not found
3576 *
3577 * Identical to System V strrchr, included for portability.
3578 */
3579 char *
3580 etags_strrchr (sp, c)
3581 register char *sp, c;
3582 {
3583 register char *r;
3584
3585 r = NULL;
3586 do
3587 {
3588 if (*sp == c)
3589 r = sp;
3590 } while (*sp++);
3591 return r;
3592 }
3593
3594
3595 /*
3596 * Return the ptr in sp at which the character c first
3597 * appears; NULL if not found
3598 *
3599 * Identical to System V strchr, included for portability.
3600 */
3601 char *
3602 etags_strchr (sp, c)
3603 register char *sp, c;
3604 {
3605 do
3606 {
3607 if (*sp == c)
3608 return sp;
3609 } while (*sp++);
3610 return NULL;
3611 }
3612
3613 /* Print error message and exit. */
3614 void
3615 fatal (s1, s2)
3616 char *s1, *s2;
3617 {
3618 error (s1, s2);
3619 exit (BAD);
3620 }
3621
3622 void
3623 pfatal (s1)
3624 char *s1;
3625 {
3626 perror (s1);
3627 exit (BAD);
3628 }
3629
3630 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3631 void
3632 error (s1, s2)
3633 char *s1, *s2;
3634 {
3635 fprintf (stderr, "%s: ", progname);
3636 fprintf (stderr, s1, s2);
3637 fprintf (stderr, "\n");
3638 }
3639
3640 /* Return a newly-allocated string whose contents
3641 concatenate those of s1, s2, s3. */
3642 char *
3643 concat (s1, s2, s3)
3644 char *s1, *s2, *s3;
3645 {
3646 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3647 char *result = xnew (len1 + len2 + len3 + 1, char);
3648
3649 strcpy (result, s1);
3650 strcpy (result + len1, s2);
3651 strcpy (result + len1 + len2, s3);
3652 result[len1 + len2 + len3] = '\0';
3653
3654 return result;
3655 }
3656 \f
3657 /* Does the same work as the system V getcwd, but does not need to
3658 guess buffer size in advance. */
3659 char *
3660 etags_getcwd ()
3661 #ifdef DOS_NT
3662 {
3663 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3664
3665 getwd (path);
3666 p = path;
3667 while (*p)
3668 if (*p == '\\')
3669 *p++ = '/';
3670 else
3671 *p++ = tolower (*p);
3672
3673 return strdup (path);
3674 }
3675 #elif HAVE_GETCWD /* not DOS_NT */
3676 {
3677 int bufsize = 200;
3678 char *path = xnew (bufsize, char);
3679
3680 while (getcwd (path, bufsize) == NULL)
3681 {
3682 if (errno != ERANGE)
3683 pfatal ("pwd");
3684 bufsize *= 2;
3685 path = xnew (bufsize, char);
3686 }
3687
3688 return path;
3689 }
3690 #else /* not DOS_NT and not HAVE_GETCWD */
3691 {
3692 struct linebuffer path;
3693 FILE *pipe;
3694
3695 initbuffer (&path);
3696 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
3697 if (pipe == NULL || readline_internal (&path, pipe) == 0)
3698 pfatal ("pwd");
3699 pclose (pipe);
3700
3701 return path.buffer;
3702 }
3703 #endif /* not DOS_NT and not HAVE_GETCWD */
3704
3705 /* Return a newly allocated string containing the filename
3706 of FILE relative to the absolute directory DIR (which
3707 should end with a slash). */
3708 char *
3709 relative_filename (file, dir)
3710 char *file, *dir;
3711 {
3712 char *fp, *dp, *res;
3713
3714 /* Find the common root of file and dir. */
3715 fp = absolute_filename (file, cwd);
3716 dp = dir;
3717 while (*fp++ == *dp++)
3718 continue;
3719 do
3720 {
3721 fp--;
3722 dp--;
3723 }
3724 while (*fp != '/');
3725
3726 /* Build a sequence of "../" strings for the resulting relative filename. */
3727 for (dp = etags_strchr (dp + 1, '/'), res = "";
3728 dp != NULL;
3729 dp = etags_strchr (dp + 1, '/'))
3730 {
3731 res = concat (res, "../", "");
3732 }
3733
3734 /* Add the filename relative to the common root of file and dir. */
3735 res = concat (res, fp + 1, "");
3736
3737 return res; /* temporary stub */
3738 }
3739
3740 /* Return a newly allocated string containing the
3741 absolute filename of FILE given CWD (which should
3742 end with a slash). */
3743 char *
3744 absolute_filename (file, cwd)
3745 char *file, *cwd;
3746 {
3747 char *slashp, *cp, *res;
3748
3749 if (file[0] == '/')
3750 res = concat (file, "", "");
3751 else
3752 res = concat (cwd, file, "");
3753
3754 /* Delete the "/dirname/.." and "/." substrings. */
3755 slashp = etags_strchr (res, '/');
3756 while (slashp != NULL && slashp[0] != '\0')
3757 {
3758 if (slashp[1] == '.')
3759 {
3760 if (slashp[2] == '.'
3761 && (slashp[3] == '/' || slashp[3] == '\0'))
3762 {
3763 cp = slashp;
3764 do
3765 cp--;
3766 while (cp >= res && *cp != '/');
3767 if (*cp == '/')
3768 {
3769 strcpy (cp, slashp + 3);
3770 }
3771 else /* else (cp == res) */
3772 {
3773 if (slashp[3] != '\0')
3774 strcpy (cp, slashp + 4);
3775 else
3776 return ".";
3777 }
3778 slashp = cp;
3779 continue;
3780 }
3781 else if (slashp[2] == '/' || slashp[2] == '\0')
3782 {
3783 strcpy (slashp, slashp + 2);
3784 continue;
3785 }
3786 }
3787
3788 slashp = etags_strchr (slashp + 1, '/');
3789 }
3790
3791 return res;
3792 }
3793
3794 /* Return a newly allocated string containing the absolute
3795 filename of dir where FILE resides given CWD (which should
3796 end with a slash). */
3797 char *
3798 absolute_dirname (file, cwd)
3799 char *file, *cwd;
3800 {
3801 char *slashp, *res;
3802 char save;
3803
3804 slashp = etags_strrchr (file, '/');
3805 if (slashp == NULL)
3806 return cwd;
3807 save = slashp[1];
3808 slashp[1] = '\0';
3809 res = absolute_filename (file, cwd);
3810 slashp[1] = save;
3811
3812 return res;
3813 }
3814
3815 /* Like malloc but get fatal error if memory is exhausted. */
3816 char *
3817 xmalloc (size)
3818 unsigned int size;
3819 {
3820 char *result = (char *) malloc (size);
3821 if (result == NULL)
3822 fatal ("virtual memory exhausted", 0);
3823 return result;
3824 }
3825
3826 char *
3827 xrealloc (ptr, size)
3828 char *ptr;
3829 unsigned int size;
3830 {
3831 char *result = (char *) realloc (ptr, size);
3832 if (result == NULL)
3833 fatal ("virtual memory exhausted");
3834 return result;
3835 }