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