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