2001-01-15 Francesco Potorti` <pot@pot.cnuce.cnr.it>
[bpt/emacs.git] / lib-src / etags.c
1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984, 87, 88, 89, 93, 94, 95, 98, 99, 2000
3 Free Software Foundation, Inc. and Ken Arnold
4
5 This file is not considered part of GNU Emacs.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /*
22 * Authors:
23 * Ctags originally by Ken Arnold.
24 * Fortran added by Jim Kleckner.
25 * Ed Pelegri-Llopart added C typedefs.
26 * Gnu Emacs TAGS format and modifications by RMS?
27 * Sam Kendall added C++.
28 * Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
29 * Regexp tags by Tom Tromey.
30 *
31 * Francesco Potorti` (pot@gnu.org) is the current maintainer.
32 */
33
34 char pot_etags_version[] = "@(#) pot revision number is 13.48";
35
36 #define TRUE 1
37 #define FALSE 0
38
39 #ifndef DEBUG
40 # define DEBUG FALSE
41 #endif
42
43 #if defined(__STDC__) && (__STDC__ || defined(__SUNPRO_C))
44 # define P_(proto) proto
45 #else
46 # define P_(proto) ()
47 #endif
48
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 /* On some systems, Emacs defines static as nothing for the sake
52 of unexec. We don't want that here since we don't use unexec. */
53 # undef static
54 # define ETAGS_REGEXPS /* use the regexp features */
55 # define LONG_OPTIONS /* accept long options */
56 #endif /* HAVE_CONFIG_H */
57
58 #ifndef _GNU_SOURCE
59 # define _GNU_SOURCE 1 /* enables some compiler checks on GNU */
60 #endif
61
62 #ifdef MSDOS
63 # undef MSDOS
64 # define MSDOS TRUE
65 # include <fcntl.h>
66 # include <sys/param.h>
67 # include <io.h>
68 # ifndef HAVE_CONFIG_H
69 # define DOS_NT
70 # include <sys/config.h>
71 # endif
72 #else
73 # define MSDOS FALSE
74 #endif /* MSDOS */
75
76 #ifdef WINDOWSNT
77 # include <stdlib.h>
78 # include <fcntl.h>
79 # include <string.h>
80 # include <direct.h>
81 # include <io.h>
82 # define MAXPATHLEN _MAX_PATH
83 # ifdef HAVE_CONFIG_H
84 # undef HAVE_NTGUI
85 # else
86 # define DOS_NT
87 # endif /* not HAVE_CONFIG_H */
88 # ifndef HAVE_GETCWD
89 # define HAVE_GETCWD
90 # endif /* undef HAVE_GETCWD */
91 #else /* !WINDOWSNT */
92 # ifdef STDC_HEADERS
93 # include <stdlib.h>
94 # include <string.h>
95 # else
96 extern char *getenv ();
97 # endif
98 #endif /* !WINDOWSNT */
99
100 #ifdef HAVE_UNISTD_H
101 # include <unistd.h>
102 #else
103 # if defined (HAVE_GETCWD) && !WINDOWSNT
104 extern char *getcwd (char *buf, size_t size);
105 # endif
106 #endif /* HAVE_UNISTD_H */
107
108 #include <stdio.h>
109 #include <ctype.h>
110 #include <errno.h>
111 #ifndef errno
112 extern int errno;
113 #endif
114 #include <sys/types.h>
115 #include <sys/stat.h>
116
117 #if !defined (S_ISREG) && defined (S_IFREG)
118 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
119 #endif
120
121 #ifdef LONG_OPTIONS
122 # include <getopt.h>
123 #else
124 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
125 extern char *optarg;
126 extern int optind, opterr;
127 #endif /* LONG_OPTIONS */
128
129 #ifdef ETAGS_REGEXPS
130 # include <regex.h>
131 #endif /* ETAGS_REGEXPS */
132
133 /* Define CTAGS to make the program "ctags" compatible with the usual one.
134 Leave it undefined to make the program "etags", which makes emacs-style
135 tag tables and tags typedefs, #defines and struct/union/enum by default. */
136 #ifdef CTAGS
137 # undef CTAGS
138 # define CTAGS TRUE
139 #else
140 # define CTAGS FALSE
141 #endif
142
143 /* Exit codes for success and failure. */
144 #ifdef VMS
145 # define GOOD 1
146 # define BAD 0
147 #else
148 # define GOOD 0
149 # define BAD 1
150 #endif
151
152 /* C extensions. */
153 #define C_PLPL 0x00001 /* C++ */
154 #define C_STAR 0x00003 /* C* */
155 #define C_JAVA 0x00005 /* JAVA */
156 #define YACC 0x10000 /* yacc file */
157
158 #define streq(s,t) ((DEBUG && (s) == NULL && (t) == NULL \
159 && (abort (), 1)) || !strcmp (s, t))
160 #define strneq(s,t,n) ((DEBUG && (s) == NULL && (t) == NULL \
161 && (abort (), 1)) || !strncmp (s, t, n))
162
163 #define CHARS 256 /* 2^sizeof(char) */
164 #define CHAR(x) ((unsigned int)(x) & (CHARS - 1))
165 #define iswhite(c) (_wht[CHAR(c)]) /* c is white */
166 #define notinname(c) (_nin[CHAR(c)]) /* c is not in a name */
167 #define begtoken(c) (_btk[CHAR(c)]) /* c can start token */
168 #define intoken(c) (_itk[CHAR(c)]) /* c can be in token */
169 #define endtoken(c) (_etk[CHAR(c)]) /* c ends tokens */
170
171 #define ISALNUM(c) isalnum (CHAR(c))
172 #define ISALPHA(c) isalpha (CHAR(c))
173 #define ISDIGIT(c) isdigit (CHAR(c))
174 #define ISLOWER(c) islower (CHAR(c))
175
176 #define lowcase(c) tolower (CHAR(c))
177 #define upcase(c) toupper (CHAR(c))
178
179
180 /*
181 * xnew, xrnew -- allocate, reallocate storage
182 *
183 * SYNOPSIS: Type *xnew (int n, Type);
184 * Type *xrnew (OldPointer, int n, Type);
185 */
186 #ifdef chkmalloc
187 # include "chkmalloc.h"
188 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
189 (n) * sizeof (Type)))
190 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
191 (op), (n) * sizeof (Type)))
192 #else
193 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
194 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
195 #endif
196
197 typedef int bool;
198
199 typedef void Lang_function P_((FILE *));
200
201 typedef struct
202 {
203 char *suffix;
204 char *command; /* Takes one arg and decompresses to stdout */
205 } compressor;
206
207 typedef struct
208 {
209 char *name;
210 Lang_function *function;
211 char **filenames;
212 char **suffixes;
213 char **interpreters;
214 } language;
215
216 typedef struct node_st
217 { /* sorting structure */
218 char *name; /* function or type name */
219 char *file; /* file name */
220 bool is_func; /* use pattern or line no */
221 bool been_warned; /* set if noticed dup */
222 int lno; /* line number tag is on */
223 long cno; /* character number line starts on */
224 char *pat; /* search pattern */
225 struct node_st *left, *right; /* left and right sons */
226 } node;
227
228 /*
229 * A `linebuffer' is a structure which holds a line of text.
230 * `readline_internal' reads a line from a stream into a linebuffer
231 * and works regardless of the length of the line.
232 * SIZE is the size of BUFFER, LEN is the length of the string in
233 * BUFFER after readline reads it.
234 */
235 typedef struct
236 {
237 long size;
238 int len;
239 char *buffer;
240 } linebuffer;
241
242 /* Many compilers barf on this:
243 Lang_function Ada_funcs;
244 so let's write it this way */
245 static void Ada_funcs P_((FILE *));
246 static void Asm_labels P_((FILE *));
247 static void C_entries P_((int c_ext, FILE *));
248 static void default_C_entries P_((FILE *));
249 static void plain_C_entries P_((FILE *));
250 static void Cjava_entries P_((FILE *));
251 static void Cobol_paragraphs P_((FILE *));
252 static void Cplusplus_entries P_((FILE *));
253 static void Cstar_entries P_((FILE *));
254 static void Erlang_functions P_((FILE *));
255 static void Fortran_functions P_((FILE *));
256 static void Yacc_entries P_((FILE *));
257 static void Lisp_functions P_((FILE *));
258 static void Makefile_targets P_((FILE *));
259 static void Pascal_functions P_((FILE *));
260 static void Perl_functions P_((FILE *));
261 static void Postscript_functions P_((FILE *));
262 static void Prolog_functions P_((FILE *));
263 static void Python_functions P_((FILE *));
264 static void Scheme_functions P_((FILE *));
265 static void TeX_commands P_((FILE *));
266 static void Texinfo_nodes P_((FILE *));
267 static void just_read_file P_((FILE *));
268
269 static void print_language_names P_((void));
270 static void print_version P_((void));
271 static void print_help P_((void));
272 int main P_((int, char **));
273 static int number_len P_((long));
274
275 static compressor *get_compressor_from_suffix P_((char *, char **));
276 static language *get_language_from_langname P_((char *));
277 static language *get_language_from_interpreter P_((char *));
278 static language *get_language_from_filename P_((char *));
279 static int total_size_of_entries P_((node *));
280 static long readline P_((linebuffer *, FILE *));
281 static long readline_internal P_((linebuffer *, FILE *));
282 static void get_tag P_((char *));
283
284 #ifdef ETAGS_REGEXPS
285 static void analyse_regex P_((char *, bool));
286 static void add_regex P_((char *, bool, language *));
287 static void free_patterns P_((void));
288 #endif /* ETAGS_REGEXPS */
289 static void error P_((const char *, const char *));
290 static void suggest_asking_for_help P_((void));
291 static void fatal P_((char *, char *));
292 static void pfatal P_((char *));
293 static void add_node P_((node *, node **));
294
295 static void init P_((void));
296 static void initbuffer P_((linebuffer *));
297 static void find_entries P_((char *, FILE *));
298 static void free_tree P_((node *));
299 static void pfnote P_((char *, bool, char *, int, int, long));
300 static void new_pfnote P_((char *, int, bool, char *, int, int, long));
301 static void process_file P_((char *));
302 static void put_entries P_((node *));
303 static void takeprec P_((void));
304
305 static char *concat P_((char *, char *, char *));
306 static char *skip_spaces P_((char *));
307 static char *skip_non_spaces P_((char *));
308 static char *savenstr P_((char *, int));
309 static char *savestr P_((char *));
310 static char *etags_strchr P_((const char *, int));
311 static char *etags_strrchr P_((const char *, int));
312 static char *etags_getcwd P_((void));
313 static char *relative_filename P_((char *, char *));
314 static char *absolute_filename P_((char *, char *));
315 static char *absolute_dirname P_((char *, char *));
316 static bool filename_is_absolute P_((char *f));
317 static void canonicalize_filename P_((char *));
318 static void grow_linebuffer P_((linebuffer *, int));
319 long *xmalloc P_((unsigned int));
320 long *xrealloc P_((char *, unsigned int));
321
322 \f
323 char searchar = '/'; /* use /.../ searches */
324
325 char *tagfile; /* output file */
326 char *progname; /* name this program was invoked with */
327 char *cwd; /* current working directory */
328 char *tagfiledir; /* directory of tagfile */
329 FILE *tagf; /* ioptr for tags file */
330
331 char *curfile; /* current input file name */
332 language *curlang; /* current language */
333
334 int lineno; /* line number of current line */
335 long charno; /* current character number */
336 long linecharno; /* charno of start of current line */
337 char *dbp; /* pointer to start of current tag */
338
339 node *head; /* the head of the binary tree of tags */
340
341 linebuffer lb; /* the current line */
342 linebuffer token_name; /* used by C_entries as a temporary area */
343 struct
344 {
345 long linepos;
346 linebuffer lb; /* used by C_entries instead of lb */
347 } lbs[2];
348
349 /* boolean "functions" (see init) */
350 bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
351 char
352 /* white chars */
353 *white = " \f\t\n\r\v",
354 /* not in a name */
355 *nonam = " \f\t\n\r(=,[;",
356 /* token ending chars */
357 *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
358 /* token starting chars */
359 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
360 /* valid in-token chars */
361 *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
362
363 bool append_to_tagfile; /* -a: append to tags */
364 /* The following four default to TRUE for etags, but to FALSE for ctags. */
365 bool typedefs; /* -t: create tags for C and Ada typedefs */
366 bool typedefs_and_cplusplus; /* -T: create tags for C typedefs, level */
367 /* 0 struct/enum/union decls, and C++ */
368 /* member functions. */
369 bool constantypedefs; /* -d: create tags for C #define, enum */
370 /* constants and variables. */
371 /* -D: opposite of -d. Default under ctags. */
372 bool declarations; /* --declarations: tag them and extern in C&Co*/
373 bool globals; /* create tags for global variables */
374 bool members; /* create tags for C member variables */
375 bool update; /* -u: update tags */
376 bool vgrind_style; /* -v: create vgrind style index output */
377 bool no_warnings; /* -w: suppress warnings */
378 bool cxref_style; /* -x: create cxref style output */
379 bool cplusplus; /* .[hc] means C++, not C */
380 bool noindentypedefs; /* -I: ignore indentation in C */
381 bool packages_only; /* --packages-only: in Ada, only tag packages*/
382
383 #ifdef LONG_OPTIONS
384 struct option longopts[] =
385 {
386 { "packages-only", no_argument, &packages_only, TRUE },
387 { "append", no_argument, NULL, 'a' },
388 { "backward-search", no_argument, NULL, 'B' },
389 { "c++", no_argument, NULL, 'C' },
390 { "cxref", no_argument, NULL, 'x' },
391 { "defines", no_argument, NULL, 'd' },
392 { "declarations", no_argument, &declarations, TRUE },
393 { "no-defines", no_argument, NULL, 'D' },
394 { "globals", no_argument, &globals, TRUE },
395 { "no-globals", no_argument, &globals, FALSE },
396 { "help", no_argument, NULL, 'h' },
397 { "help", no_argument, NULL, 'H' },
398 { "ignore-indentation", no_argument, NULL, 'I' },
399 { "include", required_argument, NULL, 'i' },
400 { "language", required_argument, NULL, 'l' },
401 { "members", no_argument, &members, TRUE },
402 { "no-members", no_argument, &members, FALSE },
403 { "no-warn", no_argument, NULL, 'w' },
404 { "output", required_argument, NULL, 'o' },
405 #ifdef ETAGS_REGEXPS
406 { "regex", required_argument, NULL, 'r' },
407 { "no-regex", no_argument, NULL, 'R' },
408 { "ignore-case-regex", required_argument, NULL, 'c' },
409 #endif /* ETAGS_REGEXPS */
410 { "typedefs", no_argument, NULL, 't' },
411 { "typedefs-and-c++", no_argument, NULL, 'T' },
412 { "update", no_argument, NULL, 'u' },
413 { "version", no_argument, NULL, 'V' },
414 { "vgrind", no_argument, NULL, 'v' },
415 { NULL }
416 };
417 #endif /* LONG_OPTIONS */
418
419 #ifdef ETAGS_REGEXPS
420 /* Structure defining a regular expression. Elements are
421 the compiled pattern, and the name string. */
422 typedef struct pattern
423 {
424 struct pattern *p_next;
425 language *language;
426 char *regex;
427 struct re_pattern_buffer *pattern;
428 struct re_registers regs;
429 char *name_pattern;
430 bool error_signaled;
431 } pattern;
432
433 /* List of all regexps. */
434 pattern *p_head = NULL;
435
436 /* How many characters in the character set. (From regex.c.) */
437 #define CHAR_SET_SIZE 256
438 /* Translation table for case-insensitive matching. */
439 char lc_trans[CHAR_SET_SIZE];
440 #endif /* ETAGS_REGEXPS */
441
442 compressor compressors[] =
443 {
444 { "z", "gzip -d -c"},
445 { "Z", "gzip -d -c"},
446 { "gz", "gzip -d -c"},
447 { "GZ", "gzip -d -c"},
448 { "bz2", "bzip2 -d -c" },
449 { NULL }
450 };
451
452 /*
453 * Language stuff.
454 */
455
456 /* Non-NULL if language fixed. */
457 language *forced_lang = NULL;
458
459 /* Ada code */
460 char *Ada_suffixes [] =
461 { "ads", "adb", "ada", NULL };
462
463 /* Assembly code */
464 char *Asm_suffixes [] = { "a", /* Unix assembler */
465 "asm", /* Microcontroller assembly */
466 "def", /* BSO/Tasking definition includes */
467 "inc", /* Microcontroller include files */
468 "ins", /* Microcontroller include files */
469 "s", "sa", /* Unix assembler */
470 "S", /* cpp-processed Unix assembler */
471 "src", /* BSO/Tasking C compiler output */
472 NULL
473 };
474
475 /* Note that .c and .h can be considered C++, if the --c++ flag was
476 given. That is why default_C_entries is called here. */
477 char *default_C_suffixes [] =
478 { "c", "h", NULL };
479
480 char *Cplusplus_suffixes [] =
481 { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
482 "M", /* Objective C++ */
483 "pdb", /* Postscript with C syntax */
484 NULL };
485
486 char *Cjava_suffixes [] =
487 { "java", NULL };
488
489 char *Cobol_suffixes [] =
490 { "COB", "cob", NULL };
491
492 char *Cstar_suffixes [] =
493 { "cs", "hs", NULL };
494
495 char *Erlang_suffixes [] =
496 { "erl", "hrl", NULL };
497
498 char *Fortran_suffixes [] =
499 { "F", "f", "f90", "for", NULL };
500
501 char *Lisp_suffixes [] =
502 { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
503
504 char *Makefile_filenames [] =
505 { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
506
507 char *Pascal_suffixes [] =
508 { "p", "pas", NULL };
509
510 char *Perl_suffixes [] =
511 { "pl", "pm", NULL };
512 char *Perl_interpreters [] =
513 { "perl", "@PERL@", NULL };
514
515 char *plain_C_suffixes [] =
516 { "lm", /* Objective lex file */
517 "m", /* Objective C file */
518 "pc", /* Pro*C file */
519 NULL };
520
521 char *Postscript_suffixes [] =
522 { "ps", "psw", NULL }; /* .psw is for PSWrap */
523
524 char *Prolog_suffixes [] =
525 { "prolog", NULL };
526
527 char *Python_suffixes [] =
528 { "py", NULL };
529
530 /* Can't do the `SCM' or `scm' prefix with a version number. */
531 char *Scheme_suffixes [] =
532 { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
533
534 char *TeX_suffixes [] =
535 { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
536
537 char *Texinfo_suffixes [] =
538 { "texi", "texinfo", "txi", NULL };
539
540 char *Yacc_suffixes [] =
541 { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
542
543 /*
544 * Table of languages.
545 *
546 * It is ok for a given function to be listed under more than one
547 * name. I just didn't.
548 */
549
550 language lang_names [] =
551 {
552 { "ada", Ada_funcs, NULL, Ada_suffixes, NULL },
553 { "asm", Asm_labels, NULL, Asm_suffixes, NULL },
554 { "c", default_C_entries, NULL, default_C_suffixes, NULL },
555 { "c++", Cplusplus_entries, NULL, Cplusplus_suffixes, NULL },
556 { "c*", Cstar_entries, NULL, Cstar_suffixes, NULL },
557 { "cobol", Cobol_paragraphs, NULL, Cobol_suffixes, NULL },
558 { "erlang", Erlang_functions, NULL, Erlang_suffixes, NULL },
559 { "fortran", Fortran_functions, NULL, Fortran_suffixes, NULL },
560 { "java", Cjava_entries, NULL, Cjava_suffixes, NULL },
561 { "lisp", Lisp_functions, NULL, Lisp_suffixes, NULL },
562 { "makefile", Makefile_targets, Makefile_filenames, NULL, NULL },
563 { "pascal", Pascal_functions, NULL, Pascal_suffixes, NULL },
564 { "perl", Perl_functions, NULL, Perl_suffixes, Perl_interpreters },
565 { "postscript", Postscript_functions, NULL, Postscript_suffixes, NULL },
566 { "proc", plain_C_entries, NULL, plain_C_suffixes, NULL },
567 { "prolog", Prolog_functions, NULL, Prolog_suffixes, NULL },
568 { "python", Python_functions, NULL, Python_suffixes, NULL },
569 { "scheme", Scheme_functions, NULL, Scheme_suffixes, NULL },
570 { "tex", TeX_commands, NULL, TeX_suffixes, NULL },
571 { "texinfo", Texinfo_nodes, NULL, Texinfo_suffixes, NULL },
572 { "yacc", Yacc_entries, NULL, Yacc_suffixes, NULL },
573 { "auto", NULL }, /* default guessing scheme */
574 { "none", just_read_file }, /* regexp matching only */
575 { NULL, NULL } /* end of list */
576 };
577 \f
578 static void
579 print_language_names ()
580 {
581 language *lang;
582 char **name, **ext;
583
584 puts ("\nThese are the currently supported languages, along with the\n\
585 default file names and dot suffixes:");
586 for (lang = lang_names; lang->name != NULL; lang++)
587 {
588 printf (" %-*s", 10, lang->name);
589 if (lang->filenames != NULL)
590 for (name = lang->filenames; *name != NULL; name++)
591 printf (" %s", *name);
592 if (lang->suffixes != NULL)
593 for (ext = lang->suffixes; *ext != NULL; ext++)
594 printf (" .%s", *ext);
595 puts ("");
596 }
597 puts ("Where `auto' means use default language for files based on file\n\
598 name suffix, and `none' means only do regexp processing on files.\n\
599 If no language is specified and no matching suffix is found,\n\
600 the first line of the file is read for a sharp-bang (#!) sequence\n\
601 followed by the name of an interpreter. If no such sequence is found,\n\
602 Fortran is tried first; if no tags are found, C is tried next.\n\
603 Compressed files are supported using gzip and bzip2.");
604 }
605
606 #ifndef EMACS_NAME
607 # define EMACS_NAME "GNU Emacs"
608 #endif
609 #ifndef VERSION
610 # define VERSION "21"
611 #endif
612 static void
613 print_version ()
614 {
615 printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
616 puts ("Copyright (C) 1999 Free Software Foundation, Inc. and Ken Arnold");
617 puts ("This program is distributed under the same terms as Emacs");
618
619 exit (GOOD);
620 }
621
622 static void
623 print_help ()
624 {
625 printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
626 \n\
627 These are the options accepted by %s.\n", progname, progname);
628 #ifdef LONG_OPTIONS
629 puts ("You may use unambiguous abbreviations for the long option names.");
630 #else
631 puts ("Long option names do not work with this executable, as it is not\n\
632 linked with GNU getopt.");
633 #endif /* LONG_OPTIONS */
634 puts ("A - as file name means read names from stdin (one per line).");
635 if (!CTAGS)
636 printf (" Absolute names are stored in the output file as they are.\n\
637 Relative ones are stored relative to the output file's directory.");
638 puts ("\n");
639
640 puts ("-a, --append\n\
641 Append tag entries to existing tags file.");
642
643 puts ("--packages-only\n\
644 For Ada files, only generate tags for packages .");
645
646 if (CTAGS)
647 puts ("-B, --backward-search\n\
648 Write the search commands for the tag entries using '?', the\n\
649 backward-search command instead of '/', the forward-search command.");
650
651 puts ("-C, --c++\n\
652 Treat files whose name suffix defaults to C language as C++ files.");
653
654 puts ("--declarations\n\
655 In C and derived languages, create tags for function declarations,");
656 if (CTAGS)
657 puts ("\tand create tags for extern variables if --globals is used.");
658 else
659 puts
660 ("\tand create tags for extern variables unless --no-globals is used.");
661
662 if (CTAGS)
663 puts ("-d, --defines\n\
664 Create tag entries for C #define constants and enum constants, too.");
665 else
666 puts ("-D, --no-defines\n\
667 Don't create tag entries for C #define constants and enum constants.\n\
668 This makes the tags file smaller.");
669
670 if (!CTAGS)
671 {
672 puts ("-i FILE, --include=FILE\n\
673 Include a note in tag file indicating that, when searching for\n\
674 a tag, one should also consult the tags file FILE after\n\
675 checking the current file.");
676 puts ("-l LANG, --language=LANG\n\
677 Force the following files to be considered as written in the\n\
678 named language up to the next --language=LANG option.");
679 }
680
681 if (CTAGS)
682 puts ("--globals\n\
683 Create tag entries for global variables in some languages.");
684 else
685 puts ("--no-globals\n\
686 Do not create tag entries for global variables in some\n\
687 languages. This makes the tags file smaller.");
688 puts ("--members\n\
689 Create tag entries for member variables in C and derived languages.");
690
691 #ifdef ETAGS_REGEXPS
692 puts ("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
693 Make a tag for each line matching pattern REGEXP in the following\n\
694 files. {LANGUAGE}/REGEXP/ uses REGEXP for LANGUAGE files only.\n\
695 regexfile is a file containing one REGEXP per line.\n\
696 REGEXP is anchored (as if preceded by ^).\n\
697 The form /REGEXP/NAME/ creates a named tag.\n\
698 For example Tcl named tags can be created with:\n\
699 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
700 puts ("-c /REGEXP/, --ignore-case-regex=/REGEXP/ or --ignore-case-regex=@regexfile\n\
701 Like -r, --regex but ignore case when matching expressions.");
702 puts ("-R, --no-regex\n\
703 Don't create tags from regexps for the following files.");
704 #endif /* ETAGS_REGEXPS */
705 puts ("-o FILE, --output=FILE\n\
706 Write the tags to FILE.");
707 puts ("-I, --ignore-indentation\n\
708 Don't rely on indentation quite as much as normal. Currently,\n\
709 this means not to assume that a closing brace in the first\n\
710 column is the final brace of a function or structure\n\
711 definition in C and C++.");
712
713 if (CTAGS)
714 {
715 puts ("-t, --typedefs\n\
716 Generate tag entries for C and Ada typedefs.");
717 puts ("-T, --typedefs-and-c++\n\
718 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
719 and C++ member functions.");
720 puts ("-u, --update\n\
721 Update the tag entries for the given files, leaving tag\n\
722 entries for other files in place. Currently, this is\n\
723 implemented by deleting the existing entries for the given\n\
724 files and then rewriting the new entries at the end of the\n\
725 tags file. It is often faster to simply rebuild the entire\n\
726 tag file than to use this.");
727 puts ("-v, --vgrind\n\
728 Generates an index of items intended for human consumption,\n\
729 similar to the output of vgrind. The index is sorted, and\n\
730 gives the page number of each item.");
731 puts ("-w, --no-warn\n\
732 Suppress warning messages about entries defined in multiple\n\
733 files.");
734 puts ("-x, --cxref\n\
735 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
736 The output uses line numbers instead of page numbers, but\n\
737 beyond that the differences are cosmetic; try both to see\n\
738 which you like.");
739 }
740
741 puts ("-V, --version\n\
742 Print the version of the program.\n\
743 -h, --help\n\
744 Print this help message.");
745
746 print_language_names ();
747
748 puts ("");
749 puts ("Report bugs to bug-gnu-emacs@gnu.org");
750
751 exit (GOOD);
752 }
753
754 \f
755 enum argument_type
756 {
757 at_language,
758 at_regexp,
759 at_filename,
760 at_icregexp
761 };
762
763 /* This structure helps us allow mixing of --lang and file names. */
764 typedef struct
765 {
766 enum argument_type arg_type;
767 char *what;
768 language *lang; /* language of the regexp */
769 } argument;
770
771 #ifdef VMS /* VMS specific functions */
772
773 #define EOS '\0'
774
775 /* This is a BUG! ANY arbitrary limit is a BUG!
776 Won't someone please fix this? */
777 #define MAX_FILE_SPEC_LEN 255
778 typedef struct {
779 short curlen;
780 char body[MAX_FILE_SPEC_LEN + 1];
781 } vspec;
782
783 /*
784 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
785 returning in each successive call the next file name matching the input
786 spec. The function expects that each in_spec passed
787 to it will be processed to completion; in particular, up to and
788 including the call following that in which the last matching name
789 is returned, the function ignores the value of in_spec, and will
790 only start processing a new spec with the following call.
791 If an error occurs, on return out_spec contains the value
792 of in_spec when the error occurred.
793
794 With each successive file name returned in out_spec, the
795 function's return value is one. When there are no more matching
796 names the function returns zero. If on the first call no file
797 matches in_spec, or there is any other error, -1 is returned.
798 */
799
800 #include <rmsdef.h>
801 #include <descrip.h>
802 #define OUTSIZE MAX_FILE_SPEC_LEN
803 static short
804 fn_exp (out, in)
805 vspec *out;
806 char *in;
807 {
808 static long context = 0;
809 static struct dsc$descriptor_s o;
810 static struct dsc$descriptor_s i;
811 static bool pass1 = TRUE;
812 long status;
813 short retval;
814
815 if (pass1)
816 {
817 pass1 = FALSE;
818 o.dsc$a_pointer = (char *) out;
819 o.dsc$w_length = (short)OUTSIZE;
820 i.dsc$a_pointer = in;
821 i.dsc$w_length = (short)strlen(in);
822 i.dsc$b_dtype = DSC$K_DTYPE_T;
823 i.dsc$b_class = DSC$K_CLASS_S;
824 o.dsc$b_dtype = DSC$K_DTYPE_VT;
825 o.dsc$b_class = DSC$K_CLASS_VS;
826 }
827 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
828 {
829 out->body[out->curlen] = EOS;
830 return 1;
831 }
832 else if (status == RMS$_NMF)
833 retval = 0;
834 else
835 {
836 strcpy(out->body, in);
837 retval = -1;
838 }
839 lib$find_file_end(&context);
840 pass1 = TRUE;
841 return retval;
842 }
843
844 /*
845 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
846 name of each file specified by the provided arg expanding wildcards.
847 */
848 static char *
849 gfnames (arg, p_error)
850 char *arg;
851 bool *p_error;
852 {
853 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
854
855 switch (fn_exp (&filename, arg))
856 {
857 case 1:
858 *p_error = FALSE;
859 return filename.body;
860 case 0:
861 *p_error = FALSE;
862 return NULL;
863 default:
864 *p_error = TRUE;
865 return filename.body;
866 }
867 }
868
869 #ifndef OLD /* Newer versions of VMS do provide `system'. */
870 system (cmd)
871 char *cmd;
872 {
873 error ("%s", "system() function not implemented under VMS");
874 }
875 #endif
876
877 #define VERSION_DELIM ';'
878 char *massage_name (s)
879 char *s;
880 {
881 char *start = s;
882
883 for ( ; *s; s++)
884 if (*s == VERSION_DELIM)
885 {
886 *s = EOS;
887 break;
888 }
889 else
890 *s = lowcase (*s);
891 return start;
892 }
893 #endif /* VMS */
894
895 \f
896 int
897 main (argc, argv)
898 int argc;
899 char *argv[];
900 {
901 int i;
902 unsigned int nincluded_files;
903 char **included_files;
904 char *this_file;
905 argument *argbuffer;
906 int current_arg, file_count;
907 linebuffer filename_lb;
908 #ifdef VMS
909 bool got_err;
910 #endif
911
912 #ifdef DOS_NT
913 _fmode = O_BINARY; /* all of files are treated as binary files */
914 #endif /* DOS_NT */
915
916 progname = argv[0];
917 nincluded_files = 0;
918 included_files = xnew (argc, char *);
919 current_arg = 0;
920 file_count = 0;
921
922 /* Allocate enough no matter what happens. Overkill, but each one
923 is small. */
924 argbuffer = xnew (argc, argument);
925
926 #ifdef ETAGS_REGEXPS
927 /* Set syntax for regular expression routines. */
928 re_set_syntax (RE_SYNTAX_EMACS | RE_INTERVALS);
929 /* Translation table for case-insensitive search. */
930 for (i = 0; i < CHAR_SET_SIZE; i++)
931 lc_trans[i] = lowcase (i);
932 #endif /* ETAGS_REGEXPS */
933
934 /*
935 * If etags, always find typedefs and structure tags. Why not?
936 * Also default is to find macro constants, enum constants and
937 * global variables.
938 */
939 if (!CTAGS)
940 {
941 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
942 globals = TRUE;
943 members = FALSE;
944 }
945
946 while (1)
947 {
948 int opt;
949 char *optstring;
950
951 #ifdef ETAGS_REGEXPS
952 optstring = "-aCdDf:Il:o:r:c:RStTi:BuvxwVhH";
953 #else
954 optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
955 #endif /* ETAGS_REGEXPS */
956
957 #ifndef LONG_OPTIONS
958 optstring = optstring + 1;
959 #endif /* LONG_OPTIONS */
960
961 opt = getopt_long (argc, argv, optstring, longopts, 0);
962 if (opt == EOF)
963 break;
964
965 switch (opt)
966 {
967 case 0:
968 /* If getopt returns 0, then it has already processed a
969 long-named option. We should do nothing. */
970 break;
971
972 case 1:
973 /* This means that a file name has been seen. Record it. */
974 argbuffer[current_arg].arg_type = at_filename;
975 argbuffer[current_arg].what = optarg;
976 ++current_arg;
977 ++file_count;
978 break;
979
980 /* Common options. */
981 case 'a': append_to_tagfile = TRUE; break;
982 case 'C': cplusplus = TRUE; break;
983 case 'd': constantypedefs = TRUE; break;
984 case 'D': constantypedefs = FALSE; break;
985 case 'f': /* for compatibility with old makefiles */
986 case 'o':
987 if (tagfile)
988 {
989 error ("-o option may only be given once.", (char *)NULL);
990 suggest_asking_for_help ();
991 }
992 tagfile = optarg;
993 break;
994 case 'I':
995 case 'S': /* for backward compatibility */
996 noindentypedefs = TRUE;
997 break;
998 case 'l':
999 {
1000 language *lang = get_language_from_langname (optarg);
1001 if (lang != NULL)
1002 {
1003 argbuffer[current_arg].lang = lang;
1004 argbuffer[current_arg].arg_type = at_language;
1005 ++current_arg;
1006 }
1007 }
1008 break;
1009 #ifdef ETAGS_REGEXPS
1010 case 'r':
1011 argbuffer[current_arg].arg_type = at_regexp;
1012 argbuffer[current_arg].what = optarg;
1013 ++current_arg;
1014 break;
1015 case 'R':
1016 argbuffer[current_arg].arg_type = at_regexp;
1017 argbuffer[current_arg].what = NULL;
1018 ++current_arg;
1019 break;
1020 case 'c':
1021 argbuffer[current_arg].arg_type = at_icregexp;
1022 argbuffer[current_arg].what = optarg;
1023 ++current_arg;
1024 break;
1025 #endif /* ETAGS_REGEXPS */
1026 case 'V':
1027 print_version ();
1028 break;
1029 case 'h':
1030 case 'H':
1031 print_help ();
1032 break;
1033 case 't':
1034 typedefs = TRUE;
1035 break;
1036 case 'T':
1037 typedefs = typedefs_and_cplusplus = TRUE;
1038 break;
1039 #if (!CTAGS)
1040 /* Etags options */
1041 case 'i':
1042 included_files[nincluded_files++] = optarg;
1043 break;
1044 #else /* CTAGS */
1045 /* Ctags options. */
1046 case 'B': searchar = '?'; break;
1047 case 'u': update = TRUE; break;
1048 case 'v': vgrind_style = TRUE; /*FALLTHRU*/
1049 case 'x': cxref_style = TRUE; break;
1050 case 'w': no_warnings = TRUE; break;
1051 #endif /* CTAGS */
1052 default:
1053 suggest_asking_for_help ();
1054 }
1055 }
1056
1057 for (; optind < argc; ++optind)
1058 {
1059 argbuffer[current_arg].arg_type = at_filename;
1060 argbuffer[current_arg].what = argv[optind];
1061 ++current_arg;
1062 ++file_count;
1063 }
1064
1065 if (nincluded_files == 0 && file_count == 0)
1066 {
1067 error ("no input files specified.", (char *)NULL);
1068 suggest_asking_for_help ();
1069 }
1070
1071 if (tagfile == NULL)
1072 tagfile = CTAGS ? "tags" : "TAGS";
1073 cwd = etags_getcwd (); /* the current working directory */
1074 if (cwd[strlen (cwd) - 1] != '/')
1075 {
1076 char *oldcwd = cwd;
1077 cwd = concat (oldcwd, "/", "");
1078 free (oldcwd);
1079 }
1080 if (streq (tagfile, "-"))
1081 tagfiledir = cwd;
1082 else
1083 tagfiledir = absolute_dirname (tagfile, cwd);
1084
1085 init (); /* set up boolean "functions" */
1086
1087 initbuffer (&lb);
1088 initbuffer (&token_name);
1089 initbuffer (&lbs[0].lb);
1090 initbuffer (&lbs[1].lb);
1091 initbuffer (&filename_lb);
1092
1093 if (!CTAGS)
1094 {
1095 if (streq (tagfile, "-"))
1096 {
1097 tagf = stdout;
1098 #ifdef DOS_NT
1099 /* Switch redirected `stdout' to binary mode (setting `_fmode'
1100 doesn't take effect until after `stdout' is already open). */
1101 if (!isatty (fileno (stdout)))
1102 setmode (fileno (stdout), O_BINARY);
1103 #endif /* DOS_NT */
1104 }
1105 else
1106 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1107 if (tagf == NULL)
1108 pfatal (tagfile);
1109 }
1110
1111 /*
1112 * Loop through files finding functions.
1113 */
1114 for (i = 0; i < current_arg; ++i)
1115 {
1116 switch (argbuffer[i].arg_type)
1117 {
1118 case at_language:
1119 forced_lang = argbuffer[i].lang;
1120 break;
1121 #ifdef ETAGS_REGEXPS
1122 case at_regexp:
1123 analyse_regex (argbuffer[i].what, FALSE);
1124 break;
1125 case at_icregexp:
1126 analyse_regex (argbuffer[i].what, TRUE);
1127 break;
1128 #endif
1129 case at_filename:
1130 #ifdef VMS
1131 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
1132 {
1133 if (got_err)
1134 {
1135 error ("can't find file %s\n", this_file);
1136 argc--, argv++;
1137 }
1138 else
1139 {
1140 this_file = massage_name (this_file);
1141 }
1142 #else
1143 this_file = argbuffer[i].what;
1144 #endif
1145 /* Input file named "-" means read file names from stdin
1146 (one per line) and use them. */
1147 if (streq (this_file, "-"))
1148 while (readline_internal (&filename_lb, stdin) > 0)
1149 process_file (filename_lb.buffer);
1150 else
1151 process_file (this_file);
1152 #ifdef VMS
1153 }
1154 #endif
1155 break;
1156 }
1157 }
1158
1159 #ifdef ETAGS_REGEXPS
1160 free_patterns ();
1161 #endif /* ETAGS_REGEXPS */
1162
1163 if (!CTAGS)
1164 {
1165 while (nincluded_files-- > 0)
1166 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1167
1168 fclose (tagf);
1169 exit (GOOD);
1170 }
1171
1172 /* If CTAGS, we are here. process_file did not write the tags yet,
1173 because we want them ordered. Let's do it now. */
1174 if (cxref_style)
1175 {
1176 put_entries (head);
1177 free_tree (head);
1178 head = NULL;
1179 exit (GOOD);
1180 }
1181
1182 if (update)
1183 {
1184 char cmd[BUFSIZ];
1185 for (i = 0; i < current_arg; ++i)
1186 {
1187 if (argbuffer[i].arg_type != at_filename)
1188 continue;
1189 sprintf (cmd,
1190 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1191 tagfile, argbuffer[i].what, tagfile);
1192 if (system (cmd) != GOOD)
1193 fatal ("failed to execute shell command", (char *)NULL);
1194 }
1195 append_to_tagfile = TRUE;
1196 }
1197
1198 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1199 if (tagf == NULL)
1200 pfatal (tagfile);
1201 put_entries (head);
1202 free_tree (head);
1203 head = NULL;
1204 fclose (tagf);
1205
1206 if (update)
1207 {
1208 char cmd[BUFSIZ];
1209 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
1210 exit (system (cmd));
1211 }
1212 return GOOD;
1213 }
1214
1215
1216
1217 /*
1218 * Return a compressor given the file name. If EXTPTR is non-zero,
1219 * return a pointer into FILE where the compressor-specific
1220 * extension begins. If no compressor is found, NULL is returned
1221 * and EXTPTR is not significant.
1222 * Idea by Vladimir Alexiev <vladimir@cs.ualberta.ca>
1223 */
1224 static compressor *
1225 get_compressor_from_suffix (file, extptr)
1226 char *file;
1227 char **extptr;
1228 {
1229 compressor *compr;
1230 char *slash, *suffix;
1231
1232 /* This relies on FN to be after canonicalize_filename,
1233 so we don't need to consider backslashes on DOS_NT. */
1234 slash = etags_strrchr (file, '/');
1235 suffix = etags_strrchr (file, '.');
1236 if (suffix == NULL || suffix < slash)
1237 return NULL;
1238 if (extptr != NULL)
1239 *extptr = suffix;
1240 suffix += 1;
1241 /* Let those poor souls who live with DOS 8+3 file name limits get
1242 some solace by treating foo.cgz as if it were foo.c.gz, etc.
1243 Only the first do loop is run if not MSDOS */
1244 do
1245 {
1246 for (compr = compressors; compr->suffix != NULL; compr++)
1247 if (streq (compr->suffix, suffix))
1248 return compr;
1249 if (!MSDOS)
1250 break; /* do it only once: not really a loop */
1251 if (extptr != NULL)
1252 *extptr = ++suffix;
1253 } while (*suffix != '\0');
1254 return NULL;
1255 }
1256
1257
1258
1259 /*
1260 * Return a language given the name.
1261 */
1262 static language *
1263 get_language_from_langname (name)
1264 char *name;
1265 {
1266 language *lang;
1267
1268 if (name == NULL)
1269 error ("empty language name", (char *)NULL);
1270 else
1271 {
1272 for (lang = lang_names; lang->name != NULL; lang++)
1273 if (streq (name, lang->name))
1274 return lang;
1275 error ("unknown language \"%s\"", name);
1276 }
1277
1278 return NULL;
1279 }
1280
1281
1282 /*
1283 * Return a language given the interpreter name.
1284 */
1285 static language *
1286 get_language_from_interpreter (interpreter)
1287 char *interpreter;
1288 {
1289 language *lang;
1290 char **iname;
1291
1292 if (interpreter == NULL)
1293 return NULL;
1294 for (lang = lang_names; lang->name != NULL; lang++)
1295 if (lang->interpreters != NULL)
1296 for (iname = lang->interpreters; *iname != NULL; iname++)
1297 if (streq (*iname, interpreter))
1298 return lang;
1299
1300 return NULL;
1301 }
1302
1303
1304
1305 /*
1306 * Return a language given the file name.
1307 */
1308 static language *
1309 get_language_from_filename (file)
1310 char *file;
1311 {
1312 language *lang;
1313 char **name, **ext, *suffix;
1314
1315 /* Try whole file name first. */
1316 for (lang = lang_names; lang->name != NULL; lang++)
1317 if (lang->filenames != NULL)
1318 for (name = lang->filenames; *name != NULL; name++)
1319 if (streq (*name, file))
1320 return lang;
1321
1322 /* If not found, try suffix after last dot. */
1323 suffix = etags_strrchr (file, '.');
1324 if (suffix == NULL)
1325 return NULL;
1326 suffix += 1;
1327 for (lang = lang_names; lang->name != NULL; lang++)
1328 if (lang->suffixes != NULL)
1329 for (ext = lang->suffixes; *ext != NULL; ext++)
1330 if (streq (*ext, suffix))
1331 return lang;
1332 return NULL;
1333 }
1334
1335
1336
1337 /*
1338 * This routine is called on each file argument.
1339 */
1340 static void
1341 process_file (file)
1342 char *file;
1343 {
1344 struct stat stat_buf;
1345 FILE *inf;
1346 compressor *compr;
1347 char *compressed_name, *uncompressed_name;
1348 char *ext, *real_name;
1349
1350
1351 canonicalize_filename (file);
1352 if (streq (file, tagfile) && !streq (tagfile, "-"))
1353 {
1354 error ("skipping inclusion of %s in self.", file);
1355 return;
1356 }
1357 if ((compr = get_compressor_from_suffix (file, &ext)) == NULL)
1358 {
1359 compressed_name = NULL;
1360 real_name = uncompressed_name = savestr (file);
1361 }
1362 else
1363 {
1364 real_name = compressed_name = savestr (file);
1365 uncompressed_name = savenstr (file, ext - file);
1366 }
1367
1368 /* If the canonicalised uncompressed name has already be dealt with,
1369 skip it silently, else add it to the list. */
1370 {
1371 typedef struct processed_file
1372 {
1373 char *filename;
1374 struct processed_file *next;
1375 } processed_file;
1376 static processed_file *pf_head = NULL;
1377 register processed_file *fnp;
1378
1379 for (fnp = pf_head; fnp != NULL; fnp = fnp->next)
1380 if (streq (uncompressed_name, fnp->filename))
1381 goto exit;
1382 fnp = pf_head;
1383 pf_head = xnew (1, struct processed_file);
1384 pf_head->filename = savestr (uncompressed_name);
1385 pf_head->next = fnp;
1386 }
1387
1388 if (stat (real_name, &stat_buf) != 0)
1389 {
1390 /* Reset real_name and try with a different name. */
1391 real_name = NULL;
1392 if (compressed_name != NULL) /* try with the given suffix */
1393 {
1394 if (stat (uncompressed_name, &stat_buf) == 0)
1395 real_name = uncompressed_name;
1396 }
1397 else /* try all possible suffixes */
1398 {
1399 for (compr = compressors; compr->suffix != NULL; compr++)
1400 {
1401 compressed_name = concat (file, ".", compr->suffix);
1402 if (stat (compressed_name, &stat_buf) != 0)
1403 {
1404 if (MSDOS)
1405 {
1406 char *suf = compressed_name + strlen (file);
1407 size_t suflen = strlen (compr->suffix) + 1;
1408 for ( ; suf[1]; suf++, suflen--)
1409 {
1410 memmove (suf, suf + 1, suflen);
1411 if (stat (compressed_name, &stat_buf) == 0)
1412 {
1413 real_name = compressed_name;
1414 break;
1415 }
1416 }
1417 if (real_name != NULL)
1418 break;
1419 } /* MSDOS */
1420 free (compressed_name);
1421 compressed_name = NULL;
1422 }
1423 else
1424 {
1425 real_name = compressed_name;
1426 break;
1427 }
1428 }
1429 }
1430 if (real_name == NULL)
1431 {
1432 perror (file);
1433 goto exit;
1434 }
1435 } /* try with a different name */
1436
1437 if (!S_ISREG (stat_buf.st_mode))
1438 {
1439 error ("skipping %s: it is not a regular file.", real_name);
1440 goto exit;
1441 }
1442 if (real_name == compressed_name)
1443 {
1444 char *cmd = concat (compr->command, " ", real_name);
1445 inf = popen (cmd, "r");
1446 free (cmd);
1447 }
1448 else
1449 inf = fopen (real_name, "r");
1450 if (inf == NULL)
1451 {
1452 perror (real_name);
1453 goto exit;
1454 }
1455
1456 find_entries (uncompressed_name, inf);
1457
1458 if (real_name == compressed_name)
1459 pclose (inf);
1460 else
1461 fclose (inf);
1462
1463 if (!CTAGS)
1464 {
1465 char *filename;
1466
1467 if (filename_is_absolute (uncompressed_name))
1468 {
1469 /* file is an absolute file name. Canonicalise it. */
1470 filename = absolute_filename (uncompressed_name, cwd);
1471 }
1472 else
1473 {
1474 /* file is a file name relative to cwd. Make it relative
1475 to the directory of the tags file. */
1476 filename = relative_filename (uncompressed_name, tagfiledir);
1477 }
1478 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1479 free (filename);
1480 put_entries (head);
1481 free_tree (head);
1482 head = NULL;
1483 }
1484
1485 exit:
1486 if (compressed_name) free(compressed_name);
1487 if (uncompressed_name) free(uncompressed_name);
1488 return;
1489 }
1490
1491 /*
1492 * This routine sets up the boolean pseudo-functions which work
1493 * by setting boolean flags dependent upon the corresponding character.
1494 * Every char which is NOT in that string is not a white char. Therefore,
1495 * all of the array "_wht" is set to FALSE, and then the elements
1496 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1497 * of a char is TRUE if it is the string "white", else FALSE.
1498 */
1499 static void
1500 init ()
1501 {
1502 register char *sp;
1503 register int i;
1504
1505 for (i = 0; i < CHARS; i++)
1506 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1507 for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1508 for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1509 notinname('\0') = notinname('\n');
1510 for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1511 begtoken('\0') = begtoken('\n');
1512 for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1513 intoken('\0') = intoken('\n');
1514 for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1515 endtoken('\0') = endtoken('\n');
1516 }
1517
1518 /*
1519 * This routine opens the specified file and calls the function
1520 * which finds the function and type definitions.
1521 */
1522 node *last_node = NULL;
1523
1524 static void
1525 find_entries (file, inf)
1526 char *file;
1527 FILE *inf;
1528 {
1529 char *cp;
1530 language *lang;
1531 node *old_last_node;
1532
1533 /* Memory leakage here: the string pointed by curfile is
1534 never released, because curfile is copied into np->file
1535 for each node, to be used in CTAGS mode. The amount of
1536 memory leaked here is the sum of the lengths of the
1537 file names. */
1538 curfile = savestr (file);
1539
1540 /* If user specified a language, use it. */
1541 lang = forced_lang;
1542 if (lang != NULL && lang->function != NULL)
1543 {
1544 curlang = lang;
1545 lang->function (inf);
1546 return;
1547 }
1548
1549 /* Try to guess the language given the file name. */
1550 lang = get_language_from_filename (file);
1551 if (lang != NULL && lang->function != NULL)
1552 {
1553 curlang = lang;
1554 lang->function (inf);
1555 return;
1556 }
1557
1558 /* Look for sharp-bang as the first two characters. */
1559 if (readline_internal (&lb, inf) > 0
1560 && lb.len >= 2
1561 && lb.buffer[0] == '#'
1562 && lb.buffer[1] == '!')
1563 {
1564 char *lp;
1565
1566 /* Set lp to point at the first char after the last slash in the
1567 line or, if no slashes, at the first nonblank. Then set cp to
1568 the first successive blank and terminate the string. */
1569 lp = etags_strrchr (lb.buffer+2, '/');
1570 if (lp != NULL)
1571 lp += 1;
1572 else
1573 lp = skip_spaces (lb.buffer + 2);
1574 cp = skip_non_spaces (lp);
1575 *cp = '\0';
1576
1577 if (strlen (lp) > 0)
1578 {
1579 lang = get_language_from_interpreter (lp);
1580 if (lang != NULL && lang->function != NULL)
1581 {
1582 curlang = lang;
1583 lang->function (inf);
1584 return;
1585 }
1586 }
1587 }
1588 /* We rewind here, even if inf may be a pipe. We fail if the
1589 length of the first line is longer than the pipe block size,
1590 which is unlikely. */
1591 rewind (inf);
1592
1593 /* Try Fortran. */
1594 old_last_node = last_node;
1595 curlang = get_language_from_langname ("fortran");
1596 Fortran_functions (inf);
1597
1598 /* No Fortran entries found. Try C. */
1599 if (old_last_node == last_node)
1600 {
1601 /* We do not tag if rewind fails.
1602 Only the file name will be recorded in the tags file. */
1603 rewind (inf);
1604 curlang = get_language_from_langname (cplusplus ? "c++" : "c");
1605 default_C_entries (inf);
1606 }
1607 return;
1608 }
1609 \f
1610 /* Record a tag. */
1611 static void
1612 pfnote (name, is_func, linestart, linelen, lno, cno)
1613 char *name; /* tag name, or NULL if unnamed */
1614 bool is_func; /* tag is a function */
1615 char *linestart; /* start of the line where tag is */
1616 int linelen; /* length of the line where tag is */
1617 int lno; /* line number */
1618 long cno; /* character number */
1619 {
1620 register node *np;
1621
1622 if (CTAGS && name == NULL)
1623 return;
1624
1625 np = xnew (1, node);
1626
1627 /* If ctags mode, change name "main" to M<thisfilename>. */
1628 if (CTAGS && !cxref_style && streq (name, "main"))
1629 {
1630 register char *fp = etags_strrchr (curfile, '/');
1631 np->name = concat ("M", fp == NULL ? curfile : fp + 1, "");
1632 fp = etags_strrchr (np->name, '.');
1633 if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
1634 fp[0] = '\0';
1635 }
1636 else
1637 np->name = name;
1638 np->been_warned = FALSE;
1639 np->file = curfile;
1640 np->is_func = is_func;
1641 np->lno = lno;
1642 /* Our char numbers are 0-base, because of C language tradition?
1643 ctags compatibility? old versions compatibility? I don't know.
1644 Anyway, since emacs's are 1-base we expect etags.el to take care
1645 of the difference. If we wanted to have 1-based numbers, we would
1646 uncomment the +1 below. */
1647 np->cno = cno /* + 1 */ ;
1648 np->left = np->right = NULL;
1649 if (CTAGS && !cxref_style)
1650 {
1651 if (strlen (linestart) < 50)
1652 np->pat = concat (linestart, "$", "");
1653 else
1654 np->pat = savenstr (linestart, 50);
1655 }
1656 else
1657 np->pat = savenstr (linestart, linelen);
1658
1659 add_node (np, &head);
1660 }
1661
1662 /* Date: Wed, 22 Jan 1997 02:56:31 -0500 [last amended 18 Sep 1997]
1663 * From: Sam Kendall <kendall@mv.mv.com>
1664 * Subject: Proposal for firming up the TAGS format specification
1665 * To: F.Potorti@cnuce.cnr.it
1666 *
1667 * pfnote should emit the optimized form [unnamed tag] only if:
1668 * 1. name does not contain any of the characters " \t\r\n(),;";
1669 * 2. linestart contains name as either a rightmost, or rightmost but
1670 * one character, substring;
1671 * 3. the character, if any, immediately before name in linestart must
1672 * be one of the characters " \t(),;";
1673 * 4. the character, if any, immediately after name in linestart must
1674 * also be one of the characters " \t(),;".
1675 *
1676 * The real implementation uses the notinname() macro, which recognises
1677 * characters slightly different form " \t\r\n(),;". See the variable
1678 * `nonam'.
1679 */
1680 #define traditional_tag_style TRUE
1681 static void
1682 new_pfnote (name, namelen, is_func, linestart, linelen, lno, cno)
1683 char *name; /* tag name, or NULL if unnamed */
1684 int namelen; /* tag length */
1685 bool is_func; /* tag is a function */
1686 char *linestart; /* start of the line where tag is */
1687 int linelen; /* length of the line where tag is */
1688 int lno; /* line number */
1689 long cno; /* character number */
1690 {
1691 register char *cp;
1692 bool named;
1693
1694 named = TRUE;
1695 if (!CTAGS)
1696 {
1697 for (cp = name; !notinname (*cp); cp++)
1698 continue;
1699 if (*cp == '\0') /* rule #1 */
1700 {
1701 cp = linestart + linelen - namelen;
1702 if (notinname (linestart[linelen-1]))
1703 cp -= 1; /* rule #4 */
1704 if (cp >= linestart /* rule #2 */
1705 && (cp == linestart
1706 || notinname (cp[-1])) /* rule #3 */
1707 && strneq (name, cp, namelen)) /* rule #2 */
1708 named = FALSE; /* use unnamed tag */
1709 }
1710 }
1711
1712 if (named)
1713 name = savenstr (name, namelen);
1714 else
1715 name = NULL;
1716 pfnote (name, is_func, linestart, linelen, lno, cno);
1717 }
1718
1719 /*
1720 * free_tree ()
1721 * recurse on left children, iterate on right children.
1722 */
1723 static void
1724 free_tree (np)
1725 register node *np;
1726 {
1727 while (np)
1728 {
1729 register node *node_right = np->right;
1730 free_tree (np->left);
1731 if (np->name != NULL)
1732 free (np->name);
1733 free (np->pat);
1734 free (np);
1735 np = node_right;
1736 }
1737 }
1738
1739 /*
1740 * add_node ()
1741 * Adds a node to the tree of nodes. In etags mode, we don't keep
1742 * it sorted; we just keep a linear list. In ctags mode, maintain
1743 * an ordered tree, with no attempt at balancing.
1744 *
1745 * add_node is the only function allowed to add nodes, so it can
1746 * maintain state.
1747 */
1748 static void
1749 add_node (np, cur_node_p)
1750 node *np, **cur_node_p;
1751 {
1752 register int dif;
1753 register node *cur_node = *cur_node_p;
1754
1755 if (cur_node == NULL)
1756 {
1757 *cur_node_p = np;
1758 last_node = np;
1759 return;
1760 }
1761
1762 if (!CTAGS)
1763 {
1764 /* Etags Mode */
1765 if (last_node == NULL)
1766 fatal ("internal error in add_node", (char *)NULL);
1767 last_node->right = np;
1768 last_node = np;
1769 }
1770 else
1771 {
1772 /* Ctags Mode */
1773 dif = strcmp (np->name, cur_node->name);
1774
1775 /*
1776 * If this tag name matches an existing one, then
1777 * do not add the node, but maybe print a warning.
1778 */
1779 if (!dif)
1780 {
1781 if (streq (np->file, cur_node->file))
1782 {
1783 if (!no_warnings)
1784 {
1785 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1786 np->file, lineno, np->name);
1787 fprintf (stderr, "Second entry ignored\n");
1788 }
1789 }
1790 else if (!cur_node->been_warned && !no_warnings)
1791 {
1792 fprintf
1793 (stderr,
1794 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1795 np->file, cur_node->file, np->name);
1796 cur_node->been_warned = TRUE;
1797 }
1798 return;
1799 }
1800
1801 /* Actually add the node */
1802 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
1803 }
1804 }
1805 \f
1806 static void
1807 put_entries (np)
1808 register node *np;
1809 {
1810 register char *sp;
1811
1812 if (np == NULL)
1813 return;
1814
1815 /* Output subentries that precede this one */
1816 put_entries (np->left);
1817
1818 /* Output this entry */
1819
1820 if (!CTAGS)
1821 {
1822 if (np->name != NULL)
1823 fprintf (tagf, "%s\177%s\001%d,%ld\n",
1824 np->pat, np->name, np->lno, np->cno);
1825 else
1826 fprintf (tagf, "%s\177%d,%ld\n",
1827 np->pat, np->lno, np->cno);
1828 }
1829 else
1830 {
1831 if (np->name == NULL)
1832 error ("internal error: NULL name in ctags mode.", (char *)NULL);
1833
1834 if (cxref_style)
1835 {
1836 if (vgrind_style)
1837 fprintf (stdout, "%s %s %d\n",
1838 np->name, np->file, (np->lno + 63) / 64);
1839 else
1840 fprintf (stdout, "%-16s %3d %-16s %s\n",
1841 np->name, np->lno, np->file, np->pat);
1842 }
1843 else
1844 {
1845 fprintf (tagf, "%s\t%s\t", np->name, np->file);
1846
1847 if (np->is_func)
1848 { /* a function */
1849 putc (searchar, tagf);
1850 putc ('^', tagf);
1851
1852 for (sp = np->pat; *sp; sp++)
1853 {
1854 if (*sp == '\\' || *sp == searchar)
1855 putc ('\\', tagf);
1856 putc (*sp, tagf);
1857 }
1858 putc (searchar, tagf);
1859 }
1860 else
1861 { /* a typedef; text pattern inadequate */
1862 fprintf (tagf, "%d", np->lno);
1863 }
1864 putc ('\n', tagf);
1865 }
1866 }
1867
1868 /* Output subentries that follow this one */
1869 put_entries (np->right);
1870 }
1871
1872 /* Length of a number's decimal representation. */
1873 static int
1874 number_len (num)
1875 long num;
1876 {
1877 int len = 1;
1878 while ((num /= 10) > 0)
1879 len += 1;
1880 return len;
1881 }
1882
1883 /*
1884 * Return total number of characters that put_entries will output for
1885 * the nodes in the subtree of the specified node. Works only if
1886 * we are not ctags, but called only in that case. This count
1887 * is irrelevant with the new tags.el, but is still supplied for
1888 * backward compatibility.
1889 */
1890 static int
1891 total_size_of_entries (np)
1892 register node *np;
1893 {
1894 register int total;
1895
1896 if (np == NULL)
1897 return 0;
1898
1899 for (total = 0; np != NULL; np = np->right)
1900 {
1901 /* Count left subentries. */
1902 total += total_size_of_entries (np->left);
1903
1904 /* Count this entry */
1905 total += strlen (np->pat) + 1;
1906 total += number_len ((long) np->lno) + 1 + number_len (np->cno) + 1;
1907 if (np->name != NULL)
1908 total += 1 + strlen (np->name); /* \001name */
1909 }
1910
1911 return total;
1912 }
1913 \f
1914 /*
1915 * The C symbol tables.
1916 */
1917 enum sym_type
1918 {
1919 st_none,
1920 st_C_objprot, st_C_objimpl, st_C_objend,
1921 st_C_gnumacro,
1922 st_C_ignore,
1923 st_C_javastruct,
1924 st_C_operator,
1925 st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
1926 };
1927
1928 static unsigned int hash P_((const char *, unsigned int));
1929 static struct C_stab_entry * in_word_set P_((const char *, unsigned int));
1930 static enum sym_type C_symtype P_((char *, int, int));
1931
1932 /* Feed stuff between (but not including) %[ and %] lines to:
1933 gperf -c -k 1,3 -o -p -r -t
1934 %[
1935 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1936 %%
1937 if, 0, st_C_ignore
1938 for, 0, st_C_ignore
1939 while, 0, st_C_ignore
1940 switch, 0, st_C_ignore
1941 return, 0, st_C_ignore
1942 @interface, 0, st_C_objprot
1943 @protocol, 0, st_C_objprot
1944 @implementation,0, st_C_objimpl
1945 @end, 0, st_C_objend
1946 import, C_JAVA, st_C_ignore
1947 package, C_JAVA, st_C_ignore
1948 friend, C_PLPL, st_C_ignore
1949 extends, C_JAVA, st_C_javastruct
1950 implements, C_JAVA, st_C_javastruct
1951 interface, C_JAVA, st_C_struct
1952 class, C_PLPL, st_C_struct
1953 namespace, C_PLPL, st_C_struct
1954 domain, C_STAR, st_C_struct
1955 union, 0, st_C_struct
1956 struct, 0, st_C_struct
1957 extern, 0, st_C_extern
1958 enum, 0, st_C_enum
1959 typedef, 0, st_C_typedef
1960 define, 0, st_C_define
1961 operator, C_PLPL, st_C_operator
1962 bool, C_PLPL, st_C_typespec
1963 long, 0, st_C_typespec
1964 short, 0, st_C_typespec
1965 int, 0, st_C_typespec
1966 char, 0, st_C_typespec
1967 float, 0, st_C_typespec
1968 double, 0, st_C_typespec
1969 signed, 0, st_C_typespec
1970 unsigned, 0, st_C_typespec
1971 auto, 0, st_C_typespec
1972 void, 0, st_C_typespec
1973 static, 0, st_C_typespec
1974 const, 0, st_C_typespec
1975 volatile, 0, st_C_typespec
1976 explicit, C_PLPL, st_C_typespec
1977 mutable, C_PLPL, st_C_typespec
1978 typename, C_PLPL, st_C_typespec
1979 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
1980 DEFUN, 0, st_C_gnumacro
1981 SYSCALL, 0, st_C_gnumacro
1982 ENTRY, 0, st_C_gnumacro
1983 PSEUDO, 0, st_C_gnumacro
1984 # These are defined inside C functions, so currently they are not met.
1985 # EXFUN used in glibc, DEFVAR_* in emacs.
1986 #EXFUN, 0, st_C_gnumacro
1987 #DEFVAR_, 0, st_C_gnumacro
1988 %]
1989 and replace lines between %< and %> with its output. */
1990 /*%<*/
1991 /* C code produced by gperf version 2.7.1 (19981006 egcs) */
1992 /* Command-line: gperf -c -k 1,3 -o -p -r -t */
1993 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1994
1995 #define TOTAL_KEYWORDS 46
1996 #define MIN_WORD_LENGTH 2
1997 #define MAX_WORD_LENGTH 15
1998 #define MIN_HASH_VALUE 13
1999 #define MAX_HASH_VALUE 123
2000 /* maximum key range = 111, duplicates = 0 */
2001
2002 #ifdef __GNUC__
2003 __inline
2004 #endif
2005 static unsigned int
2006 hash (str, len)
2007 register const char *str;
2008 register unsigned int len;
2009 {
2010 static unsigned char asso_values[] =
2011 {
2012 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2013 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2014 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2015 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2016 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2017 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2018 124, 124, 124, 124, 3, 124, 124, 124, 43, 6,
2019 11, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2020 11, 124, 124, 58, 7, 124, 124, 124, 124, 124,
2021 124, 124, 124, 124, 124, 124, 124, 57, 7, 42,
2022 4, 14, 52, 0, 124, 53, 124, 124, 29, 11,
2023 6, 35, 32, 124, 29, 34, 59, 58, 51, 24,
2024 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2025 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2026 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2027 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2028 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2029 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2030 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2031 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2032 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2033 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2034 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2035 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2036 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2037 124, 124, 124, 124, 124, 124
2038 };
2039 register int hval = len;
2040
2041 switch (hval)
2042 {
2043 default:
2044 case 3:
2045 hval += asso_values[(unsigned char)str[2]];
2046 case 2:
2047 case 1:
2048 hval += asso_values[(unsigned char)str[0]];
2049 break;
2050 }
2051 return hval;
2052 }
2053
2054 #ifdef __GNUC__
2055 __inline
2056 #endif
2057 static struct C_stab_entry *
2058 in_word_set (str, len)
2059 register const char *str;
2060 register unsigned int len;
2061 {
2062 static struct C_stab_entry wordlist[] =
2063 {
2064 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2065 {""}, {""}, {""}, {""},
2066 {"@end", 0, st_C_objend},
2067 {""}, {""}, {""}, {""},
2068 {"ENTRY", 0, st_C_gnumacro},
2069 {"@interface", 0, st_C_objprot},
2070 {""},
2071 {"domain", C_STAR, st_C_struct},
2072 {""},
2073 {"PSEUDO", 0, st_C_gnumacro},
2074 {""}, {""},
2075 {"namespace", C_PLPL, st_C_struct},
2076 {""}, {""},
2077 {"@implementation",0, st_C_objimpl},
2078 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2079 {"long", 0, st_C_typespec},
2080 {"signed", 0, st_C_typespec},
2081 {"@protocol", 0, st_C_objprot},
2082 {""}, {""}, {""}, {""},
2083 {"bool", C_PLPL, st_C_typespec},
2084 {""}, {""}, {""}, {""}, {""}, {""},
2085 {"const", 0, st_C_typespec},
2086 {"explicit", C_PLPL, st_C_typespec},
2087 {"if", 0, st_C_ignore},
2088 {""},
2089 {"operator", C_PLPL, st_C_operator},
2090 {""},
2091 {"DEFUN", 0, st_C_gnumacro},
2092 {""}, {""},
2093 {"define", 0, st_C_define},
2094 {""}, {""}, {""}, {""}, {""},
2095 {"double", 0, st_C_typespec},
2096 {"struct", 0, st_C_struct},
2097 {""}, {""}, {""}, {""},
2098 {"short", 0, st_C_typespec},
2099 {""},
2100 {"enum", 0, st_C_enum},
2101 {"mutable", C_PLPL, st_C_typespec},
2102 {""},
2103 {"extern", 0, st_C_extern},
2104 {"extends", C_JAVA, st_C_javastruct},
2105 {"package", C_JAVA, st_C_ignore},
2106 {"while", 0, st_C_ignore},
2107 {""},
2108 {"for", 0, st_C_ignore},
2109 {""}, {""}, {""},
2110 {"volatile", 0, st_C_typespec},
2111 {""}, {""},
2112 {"import", C_JAVA, st_C_ignore},
2113 {"float", 0, st_C_typespec},
2114 {"switch", 0, st_C_ignore},
2115 {"return", 0, st_C_ignore},
2116 {"implements", C_JAVA, st_C_javastruct},
2117 {""},
2118 {"static", 0, st_C_typespec},
2119 {"typedef", 0, st_C_typedef},
2120 {"typename", C_PLPL, st_C_typespec},
2121 {"unsigned", 0, st_C_typespec},
2122 {""}, {""},
2123 {"char", 0, st_C_typespec},
2124 {"class", C_PLPL, st_C_struct},
2125 {""}, {""}, {""},
2126 {"void", 0, st_C_typespec},
2127 {""}, {""},
2128 {"friend", C_PLPL, st_C_ignore},
2129 {""}, {""}, {""},
2130 {"int", 0, st_C_typespec},
2131 {"union", 0, st_C_struct},
2132 {""}, {""}, {""},
2133 {"auto", 0, st_C_typespec},
2134 {"interface", C_JAVA, st_C_struct},
2135 {""},
2136 {"SYSCALL", 0, st_C_gnumacro}
2137 };
2138
2139 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
2140 {
2141 register int key = hash (str, len);
2142
2143 if (key <= MAX_HASH_VALUE && key >= 0)
2144 {
2145 register const char *s = wordlist[key].name;
2146
2147 if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
2148 return &wordlist[key];
2149 }
2150 }
2151 return 0;
2152 }
2153 /*%>*/
2154
2155 static enum sym_type
2156 C_symtype (str, len, c_ext)
2157 char *str;
2158 int len;
2159 int c_ext;
2160 {
2161 register struct C_stab_entry *se = in_word_set (str, len);
2162
2163 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2164 return st_none;
2165 return se->type;
2166 }
2167 \f
2168 /*
2169 * C functions and variables are recognized using a simple
2170 * finite automaton. fvdef is its state variable.
2171 */
2172 enum
2173 {
2174 fvnone, /* nothing seen */
2175 foperator, /* func: operator keyword seen (cplpl) */
2176 fvnameseen, /* function or variable name seen */
2177 fstartlist, /* func: just after open parenthesis */
2178 finlist, /* func: in parameter list */
2179 flistseen, /* func: after parameter list */
2180 fignore, /* func: before open brace */
2181 vignore /* var-like: ignore until ';' */
2182 } fvdef;
2183
2184 bool fvextern; /* func or var: extern keyword seen; */
2185
2186 /*
2187 * typedefs are recognized using a simple finite automaton.
2188 * typdef is its state variable.
2189 */
2190 enum
2191 {
2192 tnone, /* nothing seen */
2193 tkeyseen, /* typedef keyword seen */
2194 ttypeseen, /* defined type seen */
2195 tinbody, /* inside typedef body */
2196 tend, /* just before typedef tag */
2197 tignore /* junk after typedef tag */
2198 } typdef;
2199
2200
2201 /*
2202 * struct-like structures (enum, struct and union) are recognized
2203 * using another simple finite automaton. `structdef' is its state
2204 * variable.
2205 */
2206 enum
2207 {
2208 snone, /* nothing seen yet */
2209 skeyseen, /* struct-like keyword seen */
2210 stagseen, /* struct-like tag seen */
2211 scolonseen, /* colon seen after struct-like tag */
2212 sinbody /* in struct body: recognize member func defs*/
2213 } structdef;
2214
2215 /*
2216 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
2217 * struct tag, and structtype is the type of the preceding struct-like
2218 * keyword.
2219 */
2220 char *structtag = "<uninited>";
2221 enum sym_type structtype;
2222
2223 /*
2224 * When objdef is different from onone, objtag is the name of the class.
2225 */
2226 char *objtag = "<uninited>";
2227
2228 /*
2229 * Yet another little state machine to deal with preprocessor lines.
2230 */
2231 enum
2232 {
2233 dnone, /* nothing seen */
2234 dsharpseen, /* '#' seen as first char on line */
2235 ddefineseen, /* '#' and 'define' seen */
2236 dignorerest /* ignore rest of line */
2237 } definedef;
2238
2239 /*
2240 * State machine for Objective C protocols and implementations.
2241 * Tom R.Hageman <tom@basil.icce.rug.nl>
2242 */
2243 enum
2244 {
2245 onone, /* nothing seen */
2246 oprotocol, /* @interface or @protocol seen */
2247 oimplementation, /* @implementations seen */
2248 otagseen, /* class name seen */
2249 oparenseen, /* parenthesis before category seen */
2250 ocatseen, /* category name seen */
2251 oinbody, /* in @implementation body */
2252 omethodsign, /* in @implementation body, after +/- */
2253 omethodtag, /* after method name */
2254 omethodcolon, /* after method colon */
2255 omethodparm, /* after method parameter */
2256 oignore /* wait for @end */
2257 } objdef;
2258
2259
2260 /*
2261 * Use this structure to keep info about the token read, and how it
2262 * should be tagged. Used by the make_C_tag function to build a tag.
2263 */
2264 typedef struct
2265 {
2266 bool valid;
2267 char *str;
2268 bool named;
2269 int linelen;
2270 int lineno;
2271 long linepos;
2272 char *buffer;
2273 } token;
2274
2275 token tok; /* latest token read */
2276
2277 /*
2278 * Set this to TRUE, and the next token considered is called a function.
2279 * Used only for GNU emacs's function-defining macros.
2280 */
2281 bool next_token_is_func;
2282
2283 /*
2284 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
2285 */
2286 bool yacc_rules;
2287
2288 /*
2289 * methodlen is the length of the method name stored in token_name.
2290 */
2291 int methodlen;
2292
2293 static bool consider_token P_((char *, int, int, int, int, int, bool *));
2294 static void make_C_tag P_((bool));
2295
2296 /*
2297 * consider_token ()
2298 * checks to see if the current token is at the start of a
2299 * function or variable, or corresponds to a typedef, or
2300 * is a struct/union/enum tag, or #define, or an enum constant.
2301 *
2302 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2303 * with args. C_EXT is which language we are looking at.
2304 *
2305 * Globals
2306 * fvdef IN OUT
2307 * structdef IN OUT
2308 * definedef IN OUT
2309 * typdef IN OUT
2310 * objdef IN OUT
2311 * next_token_is_func IN OUT
2312 */
2313
2314 static bool
2315 consider_token (str, len, c, c_ext, cblev, parlev, is_func_or_var)
2316 register char *str; /* IN: token pointer */
2317 register int len; /* IN: token length */
2318 register int c; /* IN: first char after the token */
2319 int c_ext; /* IN: C extensions mask */
2320 int cblev; /* IN: curly brace level */
2321 int parlev; /* IN: parenthesis level */
2322 bool *is_func_or_var; /* OUT: function or variable found */
2323 {
2324 enum sym_type toktype = C_symtype (str, len, c_ext);
2325
2326 /*
2327 * Advance the definedef state machine.
2328 */
2329 switch (definedef)
2330 {
2331 case dnone:
2332 /* We're not on a preprocessor line. */
2333 break;
2334 case dsharpseen:
2335 if (toktype == st_C_define)
2336 {
2337 definedef = ddefineseen;
2338 }
2339 else
2340 {
2341 definedef = dignorerest;
2342 }
2343 return FALSE;
2344 case ddefineseen:
2345 /*
2346 * Make a tag for any macro, unless it is a constant
2347 * and constantypedefs is FALSE.
2348 */
2349 definedef = dignorerest;
2350 *is_func_or_var = (c == '(');
2351 if (!*is_func_or_var && !constantypedefs)
2352 return FALSE;
2353 else
2354 return TRUE;
2355 case dignorerest:
2356 return FALSE;
2357 default:
2358 error ("internal error: definedef value.", (char *)NULL);
2359 }
2360
2361 /*
2362 * Now typedefs
2363 */
2364 switch (typdef)
2365 {
2366 case tnone:
2367 if (toktype == st_C_typedef)
2368 {
2369 if (typedefs)
2370 typdef = tkeyseen;
2371 fvextern = FALSE;
2372 fvdef = fvnone;
2373 return FALSE;
2374 }
2375 break;
2376 case tkeyseen:
2377 switch (toktype)
2378 {
2379 case st_none:
2380 case st_C_typespec:
2381 case st_C_struct:
2382 case st_C_enum:
2383 typdef = ttypeseen;
2384 break;
2385 }
2386 /* Do not return here, so the structdef stuff has a chance. */
2387 break;
2388 case tend:
2389 switch (toktype)
2390 {
2391 case st_C_typespec:
2392 case st_C_struct:
2393 case st_C_enum:
2394 return FALSE;
2395 }
2396 return TRUE;
2397 }
2398
2399 /*
2400 * This structdef business is currently only invoked when cblev==0.
2401 * It should be recursively invoked whatever the curly brace level,
2402 * and a stack of states kept, to allow for definitions of structs
2403 * within structs.
2404 *
2405 * This structdef business is NOT invoked when we are ctags and the
2406 * file is plain C. This is because a struct tag may have the same
2407 * name as another tag, and this loses with ctags.
2408 */
2409 switch (toktype)
2410 {
2411 case st_C_javastruct:
2412 if (structdef == stagseen)
2413 structdef = scolonseen;
2414 return FALSE;
2415 case st_C_struct:
2416 case st_C_enum:
2417 if (typdef == tkeyseen
2418 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
2419 {
2420 structdef = skeyseen;
2421 structtype = toktype;
2422 }
2423 return FALSE;
2424 }
2425
2426 if (structdef == skeyseen)
2427 {
2428 /* Save the tag for struct/union/class, for functions and variables
2429 that may be defined inside. */
2430 if (structtype == st_C_struct)
2431 structtag = savenstr (str, len);
2432 else
2433 structtag = "<enum>";
2434 structdef = stagseen;
2435 return TRUE;
2436 }
2437
2438 if (typdef != tnone)
2439 definedef = dnone;
2440
2441 /* Detect GNU macros.
2442
2443 Writers of emacs code are recommended to put the
2444 first two args of a DEFUN on the same line.
2445
2446 The DEFUN macro, used in emacs C source code, has a first arg
2447 that is a string (the lisp function name), and a second arg that
2448 is a C function name. Since etags skips strings, the second arg
2449 is tagged. This is unfortunate, as it would be better to tag the
2450 first arg. The simplest way to deal with this problem would be
2451 to name the tag with a name built from the function name, by
2452 removing the initial 'F' character and substituting '-' for '_'.
2453 Anyway, this assumes that the conventions of naming lisp
2454 functions will never change. Currently, this method is not
2455 implemented. */
2456 if (definedef == dnone && toktype == st_C_gnumacro)
2457 {
2458 next_token_is_func = TRUE;
2459 return FALSE;
2460 }
2461 if (next_token_is_func)
2462 {
2463 next_token_is_func = FALSE;
2464 fvdef = fignore;
2465 *is_func_or_var = TRUE;
2466 return TRUE;
2467 }
2468
2469 /* Detect Objective C constructs. */
2470 switch (objdef)
2471 {
2472 case onone:
2473 switch (toktype)
2474 {
2475 case st_C_objprot:
2476 objdef = oprotocol;
2477 return FALSE;
2478 case st_C_objimpl:
2479 objdef = oimplementation;
2480 return FALSE;
2481 }
2482 break;
2483 case oimplementation:
2484 /* Save the class tag for functions or variables defined inside. */
2485 objtag = savenstr (str, len);
2486 objdef = oinbody;
2487 return FALSE;
2488 case oprotocol:
2489 /* Save the class tag for categories. */
2490 objtag = savenstr (str, len);
2491 objdef = otagseen;
2492 *is_func_or_var = TRUE;
2493 return TRUE;
2494 case oparenseen:
2495 objdef = ocatseen;
2496 *is_func_or_var = TRUE;
2497 return TRUE;
2498 case oinbody:
2499 break;
2500 case omethodsign:
2501 if (parlev == 0)
2502 {
2503 objdef = omethodtag;
2504 methodlen = len;
2505 grow_linebuffer (&token_name, methodlen + 1);
2506 strncpy (token_name.buffer, str, len);
2507 token_name.buffer[methodlen] = '\0';
2508 token_name.len = methodlen;
2509 return TRUE;
2510 }
2511 return FALSE;
2512 case omethodcolon:
2513 if (parlev == 0)
2514 objdef = omethodparm;
2515 return FALSE;
2516 case omethodparm:
2517 if (parlev == 0)
2518 {
2519 objdef = omethodtag;
2520 methodlen += len;
2521 grow_linebuffer (&token_name, methodlen + 1);
2522 strncat (token_name.buffer, str, len);
2523 token_name.len = methodlen;
2524 return TRUE;
2525 }
2526 return FALSE;
2527 case oignore:
2528 if (toktype == st_C_objend)
2529 {
2530 /* Memory leakage here: the string pointed by objtag is
2531 never released, because many tests would be needed to
2532 avoid breaking on incorrect input code. The amount of
2533 memory leaked here is the sum of the lengths of the
2534 class tags.
2535 free (objtag); */
2536 objdef = onone;
2537 }
2538 return FALSE;
2539 }
2540
2541 /* A function, variable or enum constant? */
2542 switch (toktype)
2543 {
2544 case st_C_extern:
2545 fvextern = TRUE;
2546 /* FALLTHRU */
2547 case st_C_typespec:
2548 if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
2549 fvdef = fvnone; /* should be useless */
2550 return FALSE;
2551 case st_C_ignore:
2552 fvextern = FALSE;
2553 fvdef = vignore;
2554 return FALSE;
2555 case st_C_operator:
2556 fvdef = foperator;
2557 *is_func_or_var = TRUE;
2558 return TRUE;
2559 case st_none:
2560 if ((c_ext & C_PLPL) && strneq (str+len-10, "::operator", 10))
2561 {
2562 fvdef = foperator;
2563 *is_func_or_var = TRUE;
2564 return TRUE;
2565 }
2566 if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
2567 return TRUE;
2568 if (fvdef == fvnone)
2569 {
2570 fvdef = fvnameseen; /* function or variable */
2571 *is_func_or_var = TRUE;
2572 return TRUE;
2573 }
2574 break;
2575 }
2576
2577 return FALSE;
2578 }
2579
2580 /*
2581 * C_entries ()
2582 * This routine finds functions, variables, typedefs,
2583 * #define's, enum constants and struct/union/enum definitions in
2584 * C syntax and adds them to the list.
2585 */
2586 #define current_lb_is_new (newndx == curndx)
2587 #define switch_line_buffers() (curndx = 1 - curndx)
2588
2589 #define curlb (lbs[curndx].lb)
2590 #define othlb (lbs[1-curndx].lb)
2591 #define newlb (lbs[newndx].lb)
2592 #define curlinepos (lbs[curndx].linepos)
2593 #define othlinepos (lbs[1-curndx].linepos)
2594 #define newlinepos (lbs[newndx].linepos)
2595
2596 #define CNL_SAVE_DEFINEDEF() \
2597 do { \
2598 curlinepos = charno; \
2599 lineno++; \
2600 linecharno = charno; \
2601 charno += readline (&curlb, inf); \
2602 lp = curlb.buffer; \
2603 quotednl = FALSE; \
2604 newndx = curndx; \
2605 } while (0)
2606
2607 #define CNL() \
2608 do { \
2609 CNL_SAVE_DEFINEDEF(); \
2610 if (savetok.valid) \
2611 { \
2612 tok = savetok; \
2613 savetok.valid = FALSE; \
2614 } \
2615 definedef = dnone; \
2616 } while (0)
2617
2618
2619 static void
2620 make_C_tag (isfun)
2621 bool isfun;
2622 {
2623 /* This function should never be called when tok.valid is FALSE, but
2624 we must protect against invalid input or internal errors. */
2625 if (tok.valid)
2626 {
2627 if (traditional_tag_style)
2628 {
2629 /* This was the original code. Now we call new_pfnote instead,
2630 which uses the new method for naming tags (see new_pfnote). */
2631 char *name = NULL;
2632
2633 if (CTAGS || tok.named)
2634 name = savestr (token_name.buffer);
2635 pfnote (name, isfun,
2636 tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2637 }
2638 else
2639 new_pfnote (token_name.buffer, token_name.len, isfun,
2640 tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2641 tok.valid = FALSE;
2642 }
2643 else if (DEBUG)
2644 abort ();
2645 }
2646
2647
2648 static void
2649 C_entries (c_ext, inf)
2650 int c_ext; /* extension of C */
2651 FILE *inf; /* input file */
2652 {
2653 register char c; /* latest char read; '\0' for end of line */
2654 register char *lp; /* pointer one beyond the character `c' */
2655 int curndx, newndx; /* indices for current and new lb */
2656 register int tokoff; /* offset in line of start of current token */
2657 register int toklen; /* length of current token */
2658 char *qualifier; /* string used to qualify names */
2659 int qlen; /* length of qualifier */
2660 int cblev; /* current curly brace level */
2661 int parlev; /* current parenthesis level */
2662 bool incomm, inquote, inchar, quotednl, midtoken;
2663 bool purec, cplpl, cjava;
2664 token savetok; /* token saved during preprocessor handling */
2665
2666
2667 tokoff = toklen = 0; /* keep compiler quiet */
2668 curndx = newndx = 0;
2669 lineno = 0;
2670 charno = 0;
2671 lp = curlb.buffer;
2672 *lp = 0;
2673
2674 fvdef = fvnone; fvextern = FALSE; typdef = tnone;
2675 structdef = snone; definedef = dnone; objdef = onone;
2676 next_token_is_func = yacc_rules = FALSE;
2677 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2678 tok.valid = savetok.valid = FALSE;
2679 cblev = 0;
2680 parlev = 0;
2681 purec = !(c_ext & ~YACC); /* no extensions (apart from possibly yacc) */
2682 cplpl = (c_ext & C_PLPL) == C_PLPL;
2683 cjava = (c_ext & C_JAVA) == C_JAVA;
2684 if (cjava)
2685 { qualifier = "."; qlen = 1; }
2686 else
2687 { qualifier = "::"; qlen = 2; }
2688
2689 while (!feof (inf))
2690 {
2691 c = *lp++;
2692 if (c == '\\')
2693 {
2694 /* If we're at the end of the line, the next character is a
2695 '\0'; don't skip it, because it's the thing that tells us
2696 to read the next line. */
2697 if (*lp == '\0')
2698 {
2699 quotednl = TRUE;
2700 continue;
2701 }
2702 lp++;
2703 c = ' ';
2704 }
2705 else if (incomm)
2706 {
2707 switch (c)
2708 {
2709 case '*':
2710 if (*lp == '/')
2711 {
2712 c = *lp++;
2713 incomm = FALSE;
2714 }
2715 break;
2716 case '\0':
2717 /* Newlines inside comments do not end macro definitions in
2718 traditional cpp. */
2719 CNL_SAVE_DEFINEDEF ();
2720 break;
2721 }
2722 continue;
2723 }
2724 else if (inquote)
2725 {
2726 switch (c)
2727 {
2728 case '"':
2729 inquote = FALSE;
2730 break;
2731 case '\0':
2732 /* Newlines inside strings do not end macro definitions
2733 in traditional cpp, even though compilers don't
2734 usually accept them. */
2735 CNL_SAVE_DEFINEDEF ();
2736 break;
2737 }
2738 continue;
2739 }
2740 else if (inchar)
2741 {
2742 switch (c)
2743 {
2744 case '\0':
2745 /* Hmmm, something went wrong. */
2746 CNL ();
2747 /* FALLTHRU */
2748 case '\'':
2749 inchar = FALSE;
2750 break;
2751 }
2752 continue;
2753 }
2754 else
2755 switch (c)
2756 {
2757 case '"':
2758 inquote = TRUE;
2759 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
2760 {
2761 fvextern = FALSE;
2762 fvdef = fvnone;
2763 }
2764 continue;
2765 case '\'':
2766 inchar = TRUE;
2767 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
2768 {
2769 fvextern = FALSE;
2770 fvdef = fvnone;
2771 }
2772 continue;
2773 case '/':
2774 if (*lp == '*')
2775 {
2776 lp++;
2777 incomm = TRUE;
2778 continue;
2779 }
2780 else if (/* cplpl && */ *lp == '/')
2781 {
2782 c = '\0';
2783 break;
2784 }
2785 else
2786 break;
2787 case '%':
2788 if ((c_ext & YACC) && *lp == '%')
2789 {
2790 /* entering or exiting rules section in yacc file */
2791 lp++;
2792 definedef = dnone; fvdef = fvnone; fvextern = FALSE;
2793 typdef = tnone; structdef = snone;
2794 next_token_is_func = FALSE;
2795 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2796 cblev = 0;
2797 yacc_rules = !yacc_rules;
2798 continue;
2799 }
2800 else
2801 break;
2802 case '#':
2803 if (definedef == dnone)
2804 {
2805 char *cp;
2806 bool cpptoken = TRUE;
2807
2808 /* Look back on this line. If all blanks, or nonblanks
2809 followed by an end of comment, this is a preprocessor
2810 token. */
2811 for (cp = newlb.buffer; cp < lp-1; cp++)
2812 if (!iswhite (*cp))
2813 {
2814 if (*cp == '*' && *(cp+1) == '/')
2815 {
2816 cp++;
2817 cpptoken = TRUE;
2818 }
2819 else
2820 cpptoken = FALSE;
2821 }
2822 if (cpptoken)
2823 definedef = dsharpseen;
2824 } /* if (definedef == dnone) */
2825
2826 continue;
2827 } /* switch (c) */
2828
2829
2830 /* Consider token only if some complicated conditions are satisfied. */
2831 if ((definedef != dnone
2832 || (cblev == 0 && structdef != scolonseen)
2833 || (cblev == 1 && cplpl && structdef == sinbody)
2834 || (structdef == sinbody && purec))
2835 && typdef != tignore
2836 && definedef != dignorerest
2837 && fvdef != finlist)
2838 {
2839 if (midtoken)
2840 {
2841 if (endtoken (c))
2842 {
2843 bool funorvar = FALSE;
2844
2845 if (c == ':' && cplpl && *lp == ':' && begtoken (lp[1]))
2846 {
2847 /*
2848 * This handles :: in the middle, but not at the
2849 * beginning of an identifier. Also, space-separated
2850 * :: is not recognised.
2851 */
2852 lp += 2;
2853 toklen += 2;
2854 c = lp[-1];
2855 goto intok;
2856 }
2857 else
2858 {
2859 if (yacc_rules
2860 || consider_token (newlb.buffer + tokoff, toklen, c,
2861 c_ext, cblev, parlev, &funorvar))
2862 {
2863 if (fvdef == foperator)
2864 {
2865 char *oldlp = lp;
2866 lp = skip_spaces (lp-1);
2867 if (*lp != '\0')
2868 lp += 1;
2869 while (*lp != '\0'
2870 && !iswhite (*lp) && *lp != '(')
2871 lp += 1;
2872 c = *lp++;
2873 toklen += lp - oldlp;
2874 }
2875 tok.named = FALSE;
2876 if (!purec
2877 && funorvar
2878 && definedef == dnone
2879 && structdef == sinbody)
2880 /* function or var defined in C++ class body */
2881 {
2882 int len = strlen (structtag) + qlen + toklen;
2883 grow_linebuffer (&token_name, len + 1);
2884 strcpy (token_name.buffer, structtag);
2885 strcat (token_name.buffer, qualifier);
2886 strncat (token_name.buffer,
2887 newlb.buffer + tokoff, toklen);
2888 token_name.len = len;
2889 tok.named = TRUE;
2890 }
2891 else if (objdef == ocatseen)
2892 /* Objective C category */
2893 {
2894 int len = strlen (objtag) + 2 + toklen;
2895 grow_linebuffer (&token_name, len + 1);
2896 strcpy (token_name.buffer, objtag);
2897 strcat (token_name.buffer, "(");
2898 strncat (token_name.buffer,
2899 newlb.buffer + tokoff, toklen);
2900 strcat (token_name.buffer, ")");
2901 token_name.len = len;
2902 tok.named = TRUE;
2903 }
2904 else if (objdef == omethodtag
2905 || objdef == omethodparm)
2906 /* Objective C method */
2907 {
2908 tok.named = TRUE;
2909 }
2910 else
2911 {
2912 grow_linebuffer (&token_name, toklen + 1);
2913 strncpy (token_name.buffer,
2914 newlb.buffer + tokoff, toklen);
2915 token_name.buffer[toklen] = '\0';
2916 token_name.len = toklen;
2917 /* Name macros and members. */
2918 tok.named = (structdef == stagseen
2919 || typdef == ttypeseen
2920 || typdef == tend
2921 || (funorvar
2922 && definedef == dignorerest)
2923 || (funorvar
2924 && definedef == dnone
2925 && structdef == sinbody));
2926 }
2927 tok.lineno = lineno;
2928 tok.linelen = tokoff + toklen + 1;
2929 tok.buffer = newlb.buffer;
2930 tok.linepos = newlinepos;
2931 tok.valid = TRUE;
2932
2933 if (definedef == dnone
2934 && (fvdef == fvnameseen
2935 || fvdef == foperator
2936 || structdef == stagseen
2937 || typdef == tend
2938 || objdef != onone))
2939 {
2940 if (current_lb_is_new)
2941 switch_line_buffers ();
2942 }
2943 else
2944 make_C_tag (funorvar);
2945 }
2946 midtoken = FALSE;
2947 }
2948 } /* if (endtoken (c)) */
2949 else if (intoken (c))
2950 intok:
2951 {
2952 toklen++;
2953 continue;
2954 }
2955 } /* if (midtoken) */
2956 else if (begtoken (c))
2957 {
2958 switch (definedef)
2959 {
2960 case dnone:
2961 switch (fvdef)
2962 {
2963 case fstartlist:
2964 fvdef = finlist;
2965 continue;
2966 case flistseen:
2967 make_C_tag (TRUE); /* a function */
2968 fvdef = fignore;
2969 break;
2970 case fvnameseen:
2971 fvdef = fvnone;
2972 break;
2973 }
2974 if (structdef == stagseen && !cjava)
2975 structdef = snone;
2976 break;
2977 case dsharpseen:
2978 savetok = tok;
2979 }
2980 if (!yacc_rules || lp == newlb.buffer + 1)
2981 {
2982 tokoff = lp - 1 - newlb.buffer;
2983 toklen = 1;
2984 midtoken = TRUE;
2985 }
2986 continue;
2987 } /* if (begtoken) */
2988 } /* if must look at token */
2989
2990
2991 /* Detect end of line, colon, comma, semicolon and various braces
2992 after having handled a token.*/
2993 switch (c)
2994 {
2995 case ':':
2996 if (definedef != dnone)
2997 break;
2998 switch (objdef)
2999 {
3000 case otagseen:
3001 objdef = oignore;
3002 make_C_tag (TRUE); /* an Objective C class */
3003 break;
3004 case omethodtag:
3005 case omethodparm:
3006 objdef = omethodcolon;
3007 methodlen += 1;
3008 grow_linebuffer (&token_name, methodlen + 1);
3009 strcat (token_name.buffer, ":");
3010 token_name.len = methodlen;
3011 break;
3012 }
3013 if (structdef == stagseen)
3014 structdef = scolonseen;
3015 else
3016 switch (fvdef)
3017 {
3018 case fvnameseen:
3019 if (yacc_rules)
3020 {
3021 make_C_tag (FALSE); /* a yacc function */
3022 fvdef = fignore;
3023 }
3024 break;
3025 case fstartlist:
3026 fvextern = FALSE;
3027 fvdef = fvnone;
3028 break;
3029 }
3030 break;
3031 case ';':
3032 if (definedef != dnone)
3033 break;
3034 if (cblev == 0)
3035 switch (typdef)
3036 {
3037 case tend:
3038 make_C_tag (FALSE); /* a typedef */
3039 /* FALLTHRU */
3040 default:
3041 typdef = tnone;
3042 }
3043 switch (fvdef)
3044 {
3045 case fignore:
3046 break;
3047 case fvnameseen:
3048 if ((members && cblev == 1)
3049 || (globals && cblev == 0 && (!fvextern || declarations)))
3050 make_C_tag (FALSE); /* a variable */
3051 fvextern = FALSE;
3052 fvdef = fvnone;
3053 tok.valid = FALSE;
3054 break;
3055 case flistseen:
3056 if (declarations && (cblev == 0 || cblev == 1))
3057 make_C_tag (TRUE); /* a function declaration */
3058 /* FALLTHRU */
3059 default:
3060 fvextern = FALSE;
3061 fvdef = fvnone;
3062 /* The following instruction invalidates the token.
3063 Probably the token should be invalidated in all
3064 other cases where some state machine is reset. */
3065 tok.valid = FALSE;
3066 }
3067 if (structdef == stagseen)
3068 structdef = snone;
3069 break;
3070 case ',':
3071 if (definedef != dnone)
3072 break;
3073 switch (objdef)
3074 {
3075 case omethodtag:
3076 case omethodparm:
3077 make_C_tag (TRUE); /* an Objective C method */
3078 objdef = oinbody;
3079 break;
3080 }
3081 switch (fvdef)
3082 {
3083 case foperator:
3084 case finlist:
3085 case fignore:
3086 case vignore:
3087 break;
3088 case fvnameseen:
3089 if ((members && cblev == 1)
3090 || (globals && cblev == 0 && (!fvextern || declarations)))
3091 make_C_tag (FALSE); /* a variable */
3092 break;
3093 default:
3094 fvdef = fvnone;
3095 }
3096 if (structdef == stagseen)
3097 structdef = snone;
3098 break;
3099 case '[':
3100 if (definedef != dnone)
3101 break;
3102 if (cblev == 0 && typdef == tend)
3103 {
3104 typdef = tignore;
3105 make_C_tag (FALSE); /* a typedef */
3106 break;
3107 }
3108 switch (fvdef)
3109 {
3110 case foperator:
3111 case finlist:
3112 case fignore:
3113 case vignore:
3114 break;
3115 case fvnameseen:
3116 if ((members && cblev == 1)
3117 || (globals && cblev == 0 && (!fvextern || declarations)))
3118 make_C_tag (FALSE); /* a variable */
3119 /* FALLTHRU */
3120 default:
3121 fvdef = fvnone;
3122 }
3123 if (structdef == stagseen)
3124 structdef = snone;
3125 break;
3126 case '(':
3127 if (definedef != dnone)
3128 break;
3129 if (objdef == otagseen && parlev == 0)
3130 objdef = oparenseen;
3131 switch (fvdef)
3132 {
3133 case fvnameseen:
3134 if (typdef == ttypeseen
3135 && tok.valid
3136 && *lp != '*'
3137 && structdef != sinbody)
3138 {
3139 /* This handles constructs like:
3140 typedef void OperatorFun (int fun); */
3141 make_C_tag (FALSE);
3142 typdef = tignore;
3143 }
3144 /* FALLTHRU */
3145 case foperator:
3146 fvdef = fstartlist;
3147 break;
3148 case flistseen:
3149 fvdef = finlist;
3150 break;
3151 }
3152 parlev++;
3153 break;
3154 case ')':
3155 if (definedef != dnone)
3156 break;
3157 if (objdef == ocatseen && parlev == 1)
3158 {
3159 make_C_tag (TRUE); /* an Objective C category */
3160 objdef = oignore;
3161 }
3162 if (--parlev == 0)
3163 {
3164 switch (fvdef)
3165 {
3166 case fstartlist:
3167 case finlist:
3168 fvdef = flistseen;
3169 break;
3170 }
3171 if (cblev == 0 && (typdef == tend))
3172 {
3173 typdef = tignore;
3174 make_C_tag (FALSE); /* a typedef */
3175 }
3176 }
3177 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3178 parlev = 0;
3179 break;
3180 case '{':
3181 if (definedef != dnone)
3182 break;
3183 if (typdef == ttypeseen)
3184 typdef = tinbody;
3185 switch (structdef)
3186 {
3187 case skeyseen: /* unnamed struct */
3188 structdef = sinbody;
3189 structtag = "_anonymous_";
3190 break;
3191 case stagseen:
3192 case scolonseen: /* named struct */
3193 structdef = sinbody;
3194 make_C_tag (FALSE); /* a struct */
3195 break;
3196 }
3197 switch (fvdef)
3198 {
3199 case flistseen:
3200 make_C_tag (TRUE); /* a function */
3201 /* FALLTHRU */
3202 case fignore:
3203 fvdef = fvnone;
3204 break;
3205 case fvnone:
3206 switch (objdef)
3207 {
3208 case otagseen:
3209 make_C_tag (TRUE); /* an Objective C class */
3210 objdef = oignore;
3211 break;
3212 case omethodtag:
3213 case omethodparm:
3214 make_C_tag (TRUE); /* an Objective C method */
3215 objdef = oinbody;
3216 break;
3217 default:
3218 /* Neutralize `extern "C" {' grot. */
3219 if (cblev == 0 && structdef == snone && typdef == tnone)
3220 cblev = -1;
3221 }
3222 }
3223 cblev++;
3224 break;
3225 case '*':
3226 if (definedef != dnone)
3227 break;
3228 if (fvdef == fstartlist)
3229 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
3230 break;
3231 case '}':
3232 if (definedef != dnone)
3233 break;
3234 if (!noindentypedefs && lp == newlb.buffer + 1)
3235 {
3236 cblev = 0; /* reset curly brace level if first column */
3237 parlev = 0; /* also reset paren level, just in case... */
3238 }
3239 else if (cblev > 0)
3240 cblev--;
3241 if (cblev == 0)
3242 {
3243 if (typdef == tinbody)
3244 typdef = tend;
3245 /* Memory leakage here: the string pointed by structtag is
3246 never released, because I fear to miss something and
3247 break things while freeing the area. The amount of
3248 memory leaked here is the sum of the lengths of the
3249 struct tags.
3250 if (structdef == sinbody)
3251 free (structtag); */
3252
3253 structdef = snone;
3254 structtag = "<error>";
3255 }
3256 break;
3257 case '=':
3258 if (definedef != dnone)
3259 break;
3260 switch (fvdef)
3261 {
3262 case foperator:
3263 case finlist:
3264 case fignore:
3265 case vignore:
3266 break;
3267 case fvnameseen:
3268 if ((members && cblev == 1)
3269 || (globals && cblev == 0 && (!fvextern || declarations)))
3270 make_C_tag (FALSE); /* a variable */
3271 /* FALLTHRU */
3272 default:
3273 fvdef = vignore;
3274 }
3275 break;
3276 case '+':
3277 case '-':
3278 if (objdef == oinbody && cblev == 0)
3279 {
3280 objdef = omethodsign;
3281 break;
3282 }
3283 /* FALLTHRU */
3284 case '#': case '~': case '&': case '%': case '/': case '|':
3285 case '^': case '!': case '<': case '>': case '.': case '?': case ']':
3286 if (definedef != dnone)
3287 break;
3288 /* These surely cannot follow a function tag in C. */
3289 switch (fvdef)
3290 {
3291 case foperator:
3292 case finlist:
3293 case fignore:
3294 case vignore:
3295 break;
3296 default:
3297 fvdef = fvnone;
3298 }
3299 break;
3300 case '\0':
3301 if (objdef == otagseen)
3302 {
3303 make_C_tag (TRUE); /* an Objective C class */
3304 objdef = oignore;
3305 }
3306 /* If a macro spans multiple lines don't reset its state. */
3307 if (quotednl)
3308 CNL_SAVE_DEFINEDEF ();
3309 else
3310 CNL ();
3311 break;
3312 } /* switch (c) */
3313
3314 } /* while not eof */
3315 }
3316
3317 /*
3318 * Process either a C++ file or a C file depending on the setting
3319 * of a global flag.
3320 */
3321 static void
3322 default_C_entries (inf)
3323 FILE *inf;
3324 {
3325 C_entries (cplusplus ? C_PLPL : 0, inf);
3326 }
3327
3328 /* Always do plain ANSI C. */
3329 static void
3330 plain_C_entries (inf)
3331 FILE *inf;
3332 {
3333 C_entries (0, inf);
3334 }
3335
3336 /* Always do C++. */
3337 static void
3338 Cplusplus_entries (inf)
3339 FILE *inf;
3340 {
3341 C_entries (C_PLPL, inf);
3342 }
3343
3344 /* Always do Java. */
3345 static void
3346 Cjava_entries (inf)
3347 FILE *inf;
3348 {
3349 C_entries (C_JAVA, inf);
3350 }
3351
3352 /* Always do C*. */
3353 static void
3354 Cstar_entries (inf)
3355 FILE *inf;
3356 {
3357 C_entries (C_STAR, inf);
3358 }
3359
3360 /* Always do Yacc. */
3361 static void
3362 Yacc_entries (inf)
3363 FILE *inf;
3364 {
3365 C_entries (YACC, inf);
3366 }
3367 \f
3368 /* A useful macro. */
3369 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3370 for (lineno = charno = 0; /* loop initialization */ \
3371 !feof (file_pointer) /* loop test */ \
3372 && (lineno++, /* instructions at start of loop */ \
3373 linecharno = charno, \
3374 charno += readline (&line_buffer, file_pointer), \
3375 char_pointer = lb.buffer, \
3376 TRUE); \
3377 )
3378
3379
3380 /*
3381 * Read a file, but do no processing. This is used to do regexp
3382 * matching on files that have no language defined.
3383 */
3384 static void
3385 just_read_file (inf)
3386 FILE *inf;
3387 {
3388 register char *dummy;
3389
3390 LOOP_ON_INPUT_LINES (inf, lb, dummy)
3391 continue;
3392 }
3393 \f
3394 /* Fortran parsing */
3395
3396 static bool tail P_((char *));
3397 static void takeprec P_((void));
3398 static void getit P_((FILE *));
3399
3400 static bool
3401 tail (cp)
3402 char *cp;
3403 {
3404 register int len = 0;
3405
3406 while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
3407 cp++, len++;
3408 if (*cp == '\0' && !intoken (dbp[len]))
3409 {
3410 dbp += len;
3411 return TRUE;
3412 }
3413 return FALSE;
3414 }
3415
3416 static void
3417 takeprec ()
3418 {
3419 dbp = skip_spaces (dbp);
3420 if (*dbp != '*')
3421 return;
3422 dbp++;
3423 dbp = skip_spaces (dbp);
3424 if (strneq (dbp, "(*)", 3))
3425 {
3426 dbp += 3;
3427 return;
3428 }
3429 if (!ISDIGIT (*dbp))
3430 {
3431 --dbp; /* force failure */
3432 return;
3433 }
3434 do
3435 dbp++;
3436 while (ISDIGIT (*dbp));
3437 }
3438
3439 static void
3440 getit (inf)
3441 FILE *inf;
3442 {
3443 register char *cp;
3444
3445 dbp = skip_spaces (dbp);
3446 if (*dbp == '\0')
3447 {
3448 lineno++;
3449 linecharno = charno;
3450 charno += readline (&lb, inf);
3451 dbp = lb.buffer;
3452 if (dbp[5] != '&')
3453 return;
3454 dbp += 6;
3455 dbp = skip_spaces (dbp);
3456 }
3457 if (!ISALPHA (*dbp) && *dbp != '_' && *dbp != '$')
3458 return;
3459 for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
3460 continue;
3461 pfnote (savenstr (dbp, cp-dbp), TRUE,
3462 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3463 }
3464
3465
3466 static void
3467 Fortran_functions (inf)
3468 FILE *inf;
3469 {
3470 LOOP_ON_INPUT_LINES (inf, lb, dbp)
3471 {
3472 if (*dbp == '%')
3473 dbp++; /* Ratfor escape to fortran */
3474 dbp = skip_spaces (dbp);
3475 if (*dbp == '\0')
3476 continue;
3477 switch (lowcase (*dbp))
3478 {
3479 case 'i':
3480 if (tail ("integer"))
3481 takeprec ();
3482 break;
3483 case 'r':
3484 if (tail ("real"))
3485 takeprec ();
3486 break;
3487 case 'l':
3488 if (tail ("logical"))
3489 takeprec ();
3490 break;
3491 case 'c':
3492 if (tail ("complex") || tail ("character"))
3493 takeprec ();
3494 break;
3495 case 'd':
3496 if (tail ("double"))
3497 {
3498 dbp = skip_spaces (dbp);
3499 if (*dbp == '\0')
3500 continue;
3501 if (tail ("precision"))
3502 break;
3503 continue;
3504 }
3505 break;
3506 }
3507 dbp = skip_spaces (dbp);
3508 if (*dbp == '\0')
3509 continue;
3510 switch (lowcase (*dbp))
3511 {
3512 case 'f':
3513 if (tail ("function"))
3514 getit (inf);
3515 continue;
3516 case 's':
3517 if (tail ("subroutine"))
3518 getit (inf);
3519 continue;
3520 case 'e':
3521 if (tail ("entry"))
3522 getit (inf);
3523 continue;
3524 case 'b':
3525 if (tail ("blockdata") || tail ("block data"))
3526 {
3527 dbp = skip_spaces (dbp);
3528 if (*dbp == '\0') /* assume un-named */
3529 pfnote (savestr ("blockdata"), TRUE,
3530 lb.buffer, dbp - lb.buffer, lineno, linecharno);
3531 else
3532 getit (inf); /* look for name */
3533 }
3534 continue;
3535 }
3536 }
3537 }
3538 \f
3539 /*
3540 * Philippe Waroquiers <philippe.waroquiers@eurocontrol.be>, 1998-04-24
3541 * Ada parsing
3542 */
3543
3544 static void adagetit P_((FILE *, char *));
3545
3546 /* Once we are positioned after an "interesting" keyword, let's get
3547 the real tag value necessary. */
3548 static void
3549 adagetit (inf, name_qualifier)
3550 FILE *inf;
3551 char *name_qualifier;
3552 {
3553 register char *cp;
3554 char *name;
3555 char c;
3556
3557 while (!feof (inf))
3558 {
3559 dbp = skip_spaces (dbp);
3560 if (*dbp == '\0'
3561 || (dbp[0] == '-' && dbp[1] == '-'))
3562 {
3563 lineno++;
3564 linecharno = charno;
3565 charno += readline (&lb, inf);
3566 dbp = lb.buffer;
3567 }
3568 switch (*dbp)
3569 {
3570 case 'b':
3571 case 'B':
3572 if (tail ("body"))
3573 {
3574 /* Skipping body of procedure body or package body or ....
3575 resetting qualifier to body instead of spec. */
3576 name_qualifier = "/b";
3577 continue;
3578 }
3579 break;
3580 case 't':
3581 case 'T':
3582 /* Skipping type of task type or protected type ... */
3583 if (tail ("type"))
3584 continue;
3585 break;
3586 }
3587 if (*dbp == '"')
3588 {
3589 dbp += 1;
3590 for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
3591 continue;
3592 }
3593 else
3594 {
3595 dbp = skip_spaces (dbp);
3596 for (cp = dbp;
3597 (*cp != '\0'
3598 && (ISALPHA (*cp) || ISDIGIT (*cp) || *cp == '_' || *cp == '.'));
3599 cp++)
3600 continue;
3601 if (cp == dbp)
3602 return;
3603 }
3604 c = *cp;
3605 *cp = '\0';
3606 name = concat (dbp, name_qualifier, "");
3607 *cp = c;
3608 pfnote (name, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3609 if (c == '"')
3610 dbp = cp + 1;
3611 return;
3612 }
3613 }
3614
3615 static void
3616 Ada_funcs (inf)
3617 FILE *inf;
3618 {
3619 bool inquote = FALSE;
3620
3621 LOOP_ON_INPUT_LINES (inf, lb, dbp)
3622 {
3623 while (*dbp != '\0')
3624 {
3625 /* Skip a string i.e. "abcd". */
3626 if (inquote || (*dbp == '"'))
3627 {
3628 dbp = etags_strchr ((inquote) ? dbp : dbp+1, '"');
3629 if (dbp != NULL)
3630 {
3631 inquote = FALSE;
3632 dbp += 1;
3633 continue; /* advance char */
3634 }
3635 else
3636 {
3637 inquote = TRUE;
3638 break; /* advance line */
3639 }
3640 }
3641
3642 /* Skip comments. */
3643 if (dbp[0] == '-' && dbp[1] == '-')
3644 break; /* advance line */
3645
3646 /* Skip character enclosed in single quote i.e. 'a'
3647 and skip single quote starting an attribute i.e. 'Image. */
3648 if (*dbp == '\'')
3649 {
3650 dbp++ ;
3651 if (*dbp != '\0')
3652 dbp++;
3653 continue;
3654 }
3655
3656 /* Search for beginning of a token. */
3657 if (!begtoken (*dbp))
3658 {
3659 dbp++;
3660 continue; /* advance char */
3661 }
3662
3663 /* We are at the beginning of a token. */
3664 switch (*dbp)
3665 {
3666 case 'f':
3667 case 'F':
3668 if (!packages_only && tail ("function"))
3669 adagetit (inf, "/f");
3670 else
3671 break; /* from switch */
3672 continue; /* advance char */
3673 case 'p':
3674 case 'P':
3675 if (!packages_only && tail ("procedure"))
3676 adagetit (inf, "/p");
3677 else if (tail ("package"))
3678 adagetit (inf, "/s");
3679 else if (tail ("protected")) /* protected type */
3680 adagetit (inf, "/t");
3681 else
3682 break; /* from switch */
3683 continue; /* advance char */
3684 case 't':
3685 case 'T':
3686 if (!packages_only && tail ("task"))
3687 adagetit (inf, "/k");
3688 else if (typedefs && !packages_only && tail ("type"))
3689 {
3690 adagetit (inf, "/t");
3691 while (*dbp != '\0')
3692 dbp += 1;
3693 }
3694 else
3695 break; /* from switch */
3696 continue; /* advance char */
3697 }
3698
3699 /* Look for the end of the token. */
3700 while (!endtoken (*dbp))
3701 dbp++;
3702
3703 } /* advance char */
3704 } /* advance line */
3705 }
3706 \f
3707 /*
3708 * Bob Weiner, Motorola Inc., 4/3/94
3709 * Unix and microcontroller assembly tag handling
3710 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3711 */
3712 static void
3713 Asm_labels (inf)
3714 FILE *inf;
3715 {
3716 register char *cp;
3717
3718 LOOP_ON_INPUT_LINES (inf, lb, cp)
3719 {
3720 /* If first char is alphabetic or one of [_.$], test for colon
3721 following identifier. */
3722 if (ISALPHA (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3723 {
3724 /* Read past label. */
3725 cp++;
3726 while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3727 cp++;
3728 if (*cp == ':' || iswhite (*cp))
3729 {
3730 /* Found end of label, so copy it and add it to the table. */
3731 pfnote (savenstr(lb.buffer, cp-lb.buffer), TRUE,
3732 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3733 }
3734 }
3735 }
3736 }
3737 \f
3738 /*
3739 * Perl support by Bart Robinson <lomew@cs.utah.edu>
3740 * enhanced by Michael Ernst <mernst@alum.mit.edu>
3741 * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
3742 * Perl variable names: /^(my|local).../
3743 */
3744 static void
3745 Perl_functions (inf)
3746 FILE *inf;
3747 {
3748 register char *cp;
3749
3750 LOOP_ON_INPUT_LINES (inf, lb, cp)
3751 {
3752 if (*cp++ == 's'
3753 && *cp++ == 'u'
3754 && *cp++ == 'b' && iswhite (*cp++))
3755 {
3756 cp = skip_spaces (cp);
3757 if (*cp != '\0')
3758 {
3759 char *sp = cp;
3760 while (*cp != '\0'
3761 && !iswhite (*cp) && *cp != '{' && *cp != '(')
3762 cp++;
3763 pfnote (savenstr (sp, cp-sp), TRUE,
3764 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3765 }
3766 }
3767 else if (globals /* only if tagging global vars is enabled */
3768 && ((cp = lb.buffer,
3769 *cp++ == 'm'
3770 && *cp++ == 'y')
3771 || (cp = lb.buffer,
3772 *cp++ == 'l'
3773 && *cp++ == 'o'
3774 && *cp++ == 'c'
3775 && *cp++ == 'a'
3776 && *cp++ == 'l'))
3777 && (*cp == '(' || iswhite (*cp)))
3778 {
3779 /* After "my" or "local", but before any following paren or space. */
3780 char *varname = NULL;
3781
3782 cp = skip_spaces (cp);
3783 if (*cp == '$' || *cp == '@' || *cp == '%')
3784 {
3785 char* varstart = ++cp;
3786 while (ISALNUM (*cp) || *cp == '_')
3787 cp++;
3788 varname = savenstr (varstart, cp-varstart);
3789 }
3790 else
3791 {
3792 /* Should be examining a variable list at this point;
3793 could insist on seeing an open parenthesis. */
3794 while (*cp != '\0' && *cp != ';' && *cp != '=' && *cp != ')')
3795 cp++;
3796 }
3797
3798 /* Perhaps I should back cp up one character, so the TAGS table
3799 doesn't mention (and so depend upon) the following char. */
3800 pfnote ((CTAGS) ? savenstr (lb.buffer, cp-lb.buffer) : varname,
3801 FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3802 }
3803 }
3804 }
3805 \f
3806 /*
3807 * Python support by Eric S. Raymond <esr@thyrsus.com>
3808 * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3809 */
3810 static void
3811 Python_functions (inf)
3812 FILE *inf;
3813 {
3814 register char *cp;
3815
3816 LOOP_ON_INPUT_LINES (inf, lb, cp)
3817 {
3818 if (*cp++ == 'd'
3819 && *cp++ == 'e'
3820 && *cp++ == 'f' && iswhite (*cp++))
3821 {
3822 cp = skip_spaces (cp);
3823 while (*cp != '\0' && !iswhite (*cp) && *cp != '(' && *cp != ':')
3824 cp++;
3825 pfnote (NULL, TRUE,
3826 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3827 }
3828
3829 cp = lb.buffer;
3830 if (*cp++ == 'c'
3831 && *cp++ == 'l'
3832 && *cp++ == 'a'
3833 && *cp++ == 's'
3834 && *cp++ == 's' && iswhite (*cp++))
3835 {
3836 cp = skip_spaces (cp);
3837 while (*cp != '\0' && !iswhite (*cp) && *cp != '(' && *cp != ':')
3838 cp++;
3839 pfnote (NULL, TRUE,
3840 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3841 }
3842 }
3843 }
3844 \f
3845 /* Idea by Corny de Souza
3846 * Cobol tag functions
3847 * We could look for anything that could be a paragraph name.
3848 * i.e. anything that starts in column 8 is one word and ends in a full stop.
3849 */
3850 static void
3851 Cobol_paragraphs (inf)
3852 FILE *inf;
3853 {
3854 register char *bp, *ep;
3855
3856 LOOP_ON_INPUT_LINES (inf, lb, bp)
3857 {
3858 if (lb.len < 9)
3859 continue;
3860 bp += 8;
3861
3862 /* If eoln, compiler option or comment ignore whole line. */
3863 if (bp[-1] != ' ' || !ISALNUM (bp[0]))
3864 continue;
3865
3866 for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
3867 continue;
3868 if (*ep++ == '.')
3869 pfnote (savenstr (bp, ep-bp), TRUE,
3870 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
3871 }
3872 }
3873 \f
3874 /*
3875 * Makefile support
3876 */
3877 static void
3878 Makefile_targets (inf)
3879 FILE *inf;
3880 {
3881 register char *bp;
3882
3883 LOOP_ON_INPUT_LINES (inf, lb, bp)
3884 {
3885 if (*bp == '\t' || *bp == '#')
3886 continue;
3887 while (*bp != '\0' && *bp != '=' && *bp != ':')
3888 bp++;
3889 if (*bp == ':')
3890 pfnote (savenstr (lb.buffer, bp - lb.buffer), TRUE,
3891 lb.buffer, bp - lb.buffer + 1, lineno, linecharno);
3892 }
3893 }
3894 \f
3895 /* Added by Mosur Mohan, 4/22/88 */
3896 /* Pascal parsing */
3897
3898 /*
3899 * Locates tags for procedures & functions. Doesn't do any type- or
3900 * var-definitions. It does look for the keyword "extern" or
3901 * "forward" immediately following the procedure statement; if found,
3902 * the tag is skipped.
3903 */
3904 static void
3905 Pascal_functions (inf)
3906 FILE *inf;
3907 {
3908 linebuffer tline; /* mostly copied from C_entries */
3909 long save_lcno;
3910 int save_lineno, save_len;
3911 char c, *cp, *namebuf;
3912
3913 bool /* each of these flags is TRUE iff: */
3914 incomment, /* point is inside a comment */
3915 inquote, /* point is inside '..' string */
3916 get_tagname, /* point is after PROCEDURE/FUNCTION
3917 keyword, so next item = potential tag */
3918 found_tag, /* point is after a potential tag */
3919 inparms, /* point is within parameter-list */
3920 verify_tag; /* point has passed the parm-list, so the
3921 next token will determine whether this
3922 is a FORWARD/EXTERN to be ignored, or
3923 whether it is a real tag */
3924
3925 save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3926 namebuf = NULL; /* keep compiler quiet */
3927 lineno = 0;
3928 charno = 0;
3929 dbp = lb.buffer;
3930 *dbp = '\0';
3931 initbuffer (&tline);
3932
3933 incomment = inquote = FALSE;
3934 found_tag = FALSE; /* have a proc name; check if extern */
3935 get_tagname = FALSE; /* have found "procedure" keyword */
3936 inparms = FALSE; /* found '(' after "proc" */
3937 verify_tag = FALSE; /* check if "extern" is ahead */
3938
3939
3940 while (!feof (inf)) /* long main loop to get next char */
3941 {
3942 c = *dbp++;
3943 if (c == '\0') /* if end of line */
3944 {
3945 lineno++;
3946 linecharno = charno;
3947 charno += readline (&lb, inf);
3948 dbp = lb.buffer;
3949 if (*dbp == '\0')
3950 continue;
3951 if (!((found_tag && verify_tag)
3952 || get_tagname))
3953 c = *dbp++; /* only if don't need *dbp pointing
3954 to the beginning of the name of
3955 the procedure or function */
3956 }
3957 if (incomment)
3958 {
3959 if (c == '}') /* within { } comments */
3960 incomment = FALSE;
3961 else if (c == '*' && *dbp == ')') /* within (* *) comments */
3962 {
3963 dbp++;
3964 incomment = FALSE;
3965 }
3966 continue;
3967 }
3968 else if (inquote)
3969 {
3970 if (c == '\'')
3971 inquote = FALSE;
3972 continue;
3973 }
3974 else
3975 switch (c)
3976 {
3977 case '\'':
3978 inquote = TRUE; /* found first quote */
3979 continue;
3980 case '{': /* found open { comment */
3981 incomment = TRUE;
3982 continue;
3983 case '(':
3984 if (*dbp == '*') /* found open (* comment */
3985 {
3986 incomment = TRUE;
3987 dbp++;
3988 }
3989 else if (found_tag) /* found '(' after tag, i.e., parm-list */
3990 inparms = TRUE;
3991 continue;
3992 case ')': /* end of parms list */
3993 if (inparms)
3994 inparms = FALSE;
3995 continue;
3996 case ';':
3997 if (found_tag && !inparms) /* end of proc or fn stmt */
3998 {
3999 verify_tag = TRUE;
4000 break;
4001 }
4002 continue;
4003 }
4004 if (found_tag && verify_tag && (*dbp != ' '))
4005 {
4006 /* check if this is an "extern" declaration */
4007 if (*dbp == '\0')
4008 continue;
4009 if (lowcase (*dbp == 'e'))
4010 {
4011 if (tail ("extern")) /* superfluous, really! */
4012 {
4013 found_tag = FALSE;
4014 verify_tag = FALSE;
4015 }
4016 }
4017 else if (lowcase (*dbp) == 'f')
4018 {
4019 if (tail ("forward")) /* check for forward reference */
4020 {
4021 found_tag = FALSE;
4022 verify_tag = FALSE;
4023 }
4024 }
4025 if (found_tag && verify_tag) /* not external proc, so make tag */
4026 {
4027 found_tag = FALSE;
4028 verify_tag = FALSE;
4029 pfnote (namebuf, TRUE,
4030 tline.buffer, save_len, save_lineno, save_lcno);
4031 continue;
4032 }
4033 }
4034 if (get_tagname) /* grab name of proc or fn */
4035 {
4036 if (*dbp == '\0')
4037 continue;
4038
4039 /* save all values for later tagging */
4040 grow_linebuffer (&tline, lb.len + 1);
4041 strcpy (tline.buffer, lb.buffer);
4042 save_lineno = lineno;
4043 save_lcno = linecharno;
4044
4045 /* grab block name */
4046 for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
4047 continue;
4048 namebuf = savenstr (dbp, cp-dbp);
4049 dbp = cp; /* set dbp to e-o-token */
4050 save_len = dbp - lb.buffer + 1;
4051 get_tagname = FALSE;
4052 found_tag = TRUE;
4053 continue;
4054
4055 /* and proceed to check for "extern" */
4056 }
4057 else if (!incomment && !inquote && !found_tag)
4058 {
4059 /* check for proc/fn keywords */
4060 switch (lowcase (c))
4061 {
4062 case 'p':
4063 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
4064 get_tagname = TRUE;
4065 continue;
4066 case 'f':
4067 if (tail ("unction"))
4068 get_tagname = TRUE;
4069 continue;
4070 }
4071 }
4072 } /* while not eof */
4073
4074 free (tline.buffer);
4075 }
4076 \f
4077 /*
4078 * lisp tag functions
4079 * look for (def or (DEF, quote or QUOTE
4080 */
4081
4082 static int L_isdef P_((char *));
4083 static int L_isquote P_((char *));
4084 static void L_getit P_((void));
4085
4086 static int
4087 L_isdef (strp)
4088 register char *strp;
4089 {
4090 return ((strp[1] == 'd' || strp[1] == 'D')
4091 && (strp[2] == 'e' || strp[2] == 'E')
4092 && (strp[3] == 'f' || strp[3] == 'F'));
4093 }
4094
4095 static int
4096 L_isquote (strp)
4097 register char *strp;
4098 {
4099 return ((*++strp == 'q' || *strp == 'Q')
4100 && (*++strp == 'u' || *strp == 'U')
4101 && (*++strp == 'o' || *strp == 'O')
4102 && (*++strp == 't' || *strp == 'T')
4103 && (*++strp == 'e' || *strp == 'E')
4104 && iswhite (*++strp));
4105 }
4106
4107 static void
4108 L_getit ()
4109 {
4110 register char *cp;
4111
4112 if (*dbp == '\'') /* Skip prefix quote */
4113 dbp++;
4114 else if (*dbp == '(')
4115 {
4116 if (L_isquote (dbp))
4117 dbp += 7; /* Skip "(quote " */
4118 else
4119 dbp += 1; /* Skip "(" before name in (defstruct (foo)) */
4120 dbp = skip_spaces (dbp);
4121 }
4122
4123 for (cp = dbp /*+1*/;
4124 *cp != '\0' && *cp != '(' && !iswhite(*cp) && *cp != ')';
4125 cp++)
4126 continue;
4127 if (cp == dbp)
4128 return;
4129
4130 pfnote (savenstr (dbp, cp-dbp), TRUE,
4131 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4132 }
4133
4134 static void
4135 Lisp_functions (inf)
4136 FILE *inf;
4137 {
4138 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4139 {
4140 if (dbp[0] == '(')
4141 {
4142 if (L_isdef (dbp))
4143 {
4144 dbp = skip_non_spaces (dbp);
4145 dbp = skip_spaces (dbp);
4146 L_getit ();
4147 }
4148 else
4149 {
4150 /* Check for (foo::defmumble name-defined ... */
4151 do
4152 dbp++;
4153 while (*dbp != '\0' && !iswhite (*dbp)
4154 && *dbp != ':' && *dbp != '(' && *dbp != ')');
4155 if (*dbp == ':')
4156 {
4157 do
4158 dbp++;
4159 while (*dbp == ':');
4160
4161 if (L_isdef (dbp - 1))
4162 {
4163 dbp = skip_non_spaces (dbp);
4164 dbp = skip_spaces (dbp);
4165 L_getit ();
4166 }
4167 }
4168 }
4169 }
4170 }
4171 }
4172 \f
4173 /*
4174 * Postscript tag functions
4175 * Just look for lines where the first character is '/'
4176 * Richard Mlynarik <mly@adoc.xerox.com>
4177 * Also look at "defineps" for PSWrap
4178 * suggested by Masatake YAMATO <masata-y@is.aist-nara.ac.jp>
4179 */
4180 static void
4181 Postscript_functions (inf)
4182 FILE *inf;
4183 {
4184 register char *bp, *ep;
4185
4186 LOOP_ON_INPUT_LINES (inf, lb, bp)
4187 {
4188 if (bp[0] == '/')
4189 {
4190 for (ep = bp+1;
4191 *ep != '\0' && *ep != ' ' && *ep != '{';
4192 ep++)
4193 continue;
4194 pfnote (savenstr (bp, ep-bp), TRUE,
4195 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4196 }
4197 else if (strneq (bp, "defineps", 8))
4198 {
4199 bp = skip_non_spaces (bp);
4200 bp = skip_spaces (bp);
4201 get_tag (bp);
4202 }
4203 }
4204 }
4205
4206 \f
4207 /*
4208 * Scheme tag functions
4209 * look for (def... xyzzy
4210 * look for (def... (xyzzy
4211 * look for (def ... ((...(xyzzy ....
4212 * look for (set! xyzzy
4213 */
4214
4215 static void
4216 Scheme_functions (inf)
4217 FILE *inf;
4218 {
4219 register char *bp;
4220
4221 LOOP_ON_INPUT_LINES (inf, lb, bp)
4222 {
4223 if (bp[0] == '('
4224 && (bp[1] == 'D' || bp[1] == 'd')
4225 && (bp[2] == 'E' || bp[2] == 'e')
4226 && (bp[3] == 'F' || bp[3] == 'f'))
4227 {
4228 bp = skip_non_spaces (bp);
4229 /* Skip over open parens and white space */
4230 while (iswhite (*bp) || *bp == '(')
4231 bp++;
4232 get_tag (bp);
4233 }
4234 if (bp[0] == '('
4235 && (bp[1] == 'S' || bp[1] == 's')
4236 && (bp[2] == 'E' || bp[2] == 'e')
4237 && (bp[3] == 'T' || bp[3] == 't')
4238 && (bp[4] == '!' || bp[4] == '!')
4239 && (iswhite (bp[5])))
4240 {
4241 bp = skip_non_spaces (bp);
4242 bp = skip_spaces (bp);
4243 get_tag (bp);
4244 }
4245 }
4246 }
4247 \f
4248 /* Find tags in TeX and LaTeX input files. */
4249
4250 /* TEX_toktab is a table of TeX control sequences that define tags.
4251 Each TEX_tabent records one such control sequence.
4252 CONVERT THIS TO USE THE Stab TYPE!! */
4253 struct TEX_tabent
4254 {
4255 char *name;
4256 int len;
4257 };
4258
4259 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
4260
4261 /* Default set of control sequences to put into TEX_toktab.
4262 The value of environment var TEXTAGS is prepended to this. */
4263
4264 char *TEX_defenv = "\
4265 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4266 :part:appendix:entry:index";
4267
4268 static void TEX_mode P_((FILE *));
4269 static struct TEX_tabent *TEX_decode_env P_((char *, char *));
4270 static int TEX_Token P_((char *));
4271
4272 char TEX_esc = '\\';
4273 char TEX_opgrp = '{';
4274 char TEX_clgrp = '}';
4275
4276 /*
4277 * TeX/LaTeX scanning loop.
4278 */
4279 static void
4280 TeX_commands (inf)
4281 FILE *inf;
4282 {
4283 char *cp, *lasthit;
4284 register int i;
4285
4286 /* Select either \ or ! as escape character. */
4287 TEX_mode (inf);
4288
4289 /* Initialize token table once from environment. */
4290 if (!TEX_toktab)
4291 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
4292
4293 LOOP_ON_INPUT_LINES (inf, lb, cp)
4294 {
4295 lasthit = cp;
4296 /* Look at each esc in line. */
4297 while ((cp = etags_strchr (cp, TEX_esc)) != NULL)
4298 {
4299 if (*++cp == '\0')
4300 break;
4301 linecharno += cp - lasthit;
4302 lasthit = cp;
4303 i = TEX_Token (lasthit);
4304 if (i >= 0)
4305 {
4306 /* We seem to include the TeX command in the tag name.
4307 register char *p;
4308 for (p = lasthit + TEX_toktab[i].len;
4309 *p != '\0' && *p != TEX_clgrp;
4310 p++)
4311 continue; */
4312 pfnote (/*savenstr (lasthit, p-lasthit)*/ (char *)NULL, TRUE,
4313 lb.buffer, lb.len, lineno, linecharno);
4314 break; /* We only tag a line once */
4315 }
4316 }
4317 }
4318 }
4319
4320 #define TEX_LESC '\\'
4321 #define TEX_SESC '!'
4322 #define TEX_cmt '%'
4323
4324 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4325 chars accordingly. */
4326 static void
4327 TEX_mode (inf)
4328 FILE *inf;
4329 {
4330 int c;
4331
4332 while ((c = getc (inf)) != EOF)
4333 {
4334 /* Skip to next line if we hit the TeX comment char. */
4335 if (c == TEX_cmt)
4336 while (c != '\n')
4337 c = getc (inf);
4338 else if (c == TEX_LESC || c == TEX_SESC )
4339 break;
4340 }
4341
4342 if (c == TEX_LESC)
4343 {
4344 TEX_esc = TEX_LESC;
4345 TEX_opgrp = '{';
4346 TEX_clgrp = '}';
4347 }
4348 else
4349 {
4350 TEX_esc = TEX_SESC;
4351 TEX_opgrp = '<';
4352 TEX_clgrp = '>';
4353 }
4354 /* If the input file is compressed, inf is a pipe, and rewind may fail.
4355 No attempt is made to correct the situation. */
4356 rewind (inf);
4357 }
4358
4359 /* Read environment and prepend it to the default string.
4360 Build token table. */
4361 static struct TEX_tabent *
4362 TEX_decode_env (evarname, defenv)
4363 char *evarname;
4364 char *defenv;
4365 {
4366 register char *env, *p;
4367
4368 struct TEX_tabent *tab;
4369 int size, i;
4370
4371 /* Append default string to environment. */
4372 env = getenv (evarname);
4373 if (!env)
4374 env = defenv;
4375 else
4376 {
4377 char *oldenv = env;
4378 env = concat (oldenv, defenv, "");
4379 }
4380
4381 /* Allocate a token table */
4382 for (size = 1, p = env; p;)
4383 if ((p = etags_strchr (p, ':')) && *++p != '\0')
4384 size++;
4385 /* Add 1 to leave room for null terminator. */
4386 tab = xnew (size + 1, struct TEX_tabent);
4387
4388 /* Unpack environment string into token table. Be careful about */
4389 /* zero-length strings (leading ':', "::" and trailing ':') */
4390 for (i = 0; *env;)
4391 {
4392 p = etags_strchr (env, ':');
4393 if (!p) /* End of environment string. */
4394 p = env + strlen (env);
4395 if (p - env > 0)
4396 { /* Only non-zero strings. */
4397 tab[i].name = savenstr (env, p - env);
4398 tab[i].len = strlen (tab[i].name);
4399 i++;
4400 }
4401 if (*p)
4402 env = p + 1;
4403 else
4404 {
4405 tab[i].name = NULL; /* Mark end of table. */
4406 tab[i].len = 0;
4407 break;
4408 }
4409 }
4410 return tab;
4411 }
4412
4413 /* If the text at CP matches one of the tag-defining TeX command names,
4414 return the pointer to the first occurrence of that command in TEX_toktab.
4415 Otherwise return -1.
4416 Keep the capital `T' in `token' for dumb truncating compilers
4417 (this distinguishes it from `TEX_toktab' */
4418 static int
4419 TEX_Token (cp)
4420 char *cp;
4421 {
4422 int i;
4423
4424 for (i = 0; TEX_toktab[i].len > 0; i++)
4425 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
4426 return i;
4427 return -1;
4428 }
4429 \f
4430 /* Texinfo support. Dave Love, Mar. 2000. */
4431 static void
4432 Texinfo_nodes (inf)
4433 FILE * inf;
4434 {
4435 char *cp, *start;
4436 LOOP_ON_INPUT_LINES (inf, lb, cp)
4437 {
4438 if ((*cp++ == '@'
4439 && *cp++ == 'n'
4440 && *cp++ == 'o'
4441 && *cp++ == 'd'
4442 && *cp++ == 'e' && iswhite (*cp++)))
4443 {
4444 start = cp = skip_spaces(cp);
4445 while (*cp != '\0' && *cp != ',')
4446 cp++;
4447 pfnote (savenstr (start, cp - start), TRUE,
4448 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4449 }
4450 }
4451 }
4452 \f
4453 /*
4454 * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4455 *
4456 * Assumes that the predicate starts at column 0.
4457 * Only the first clause of a predicate is added.
4458 */
4459 static int prolog_pred P_((char *, char *));
4460 static void prolog_skip_comment P_((linebuffer *, FILE *));
4461 static int prolog_atom P_((char *, int));
4462
4463 static void
4464 Prolog_functions (inf)
4465 FILE *inf;
4466 {
4467 char *cp, *last;
4468 int len;
4469 int allocated;
4470
4471 allocated = 0;
4472 len = 0;
4473 last = NULL;
4474
4475 LOOP_ON_INPUT_LINES (inf, lb, cp)
4476 {
4477 if (cp[0] == '\0') /* Empty line */
4478 continue;
4479 else if (iswhite (cp[0])) /* Not a predicate */
4480 continue;
4481 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
4482 prolog_skip_comment (&lb, inf);
4483 else if ((len = prolog_pred (cp, last)) > 0)
4484 {
4485 /* Predicate. Store the function name so that we only
4486 generate a tag for the first clause. */
4487 if (last == NULL)
4488 last = xnew(len + 1, char);
4489 else if (len + 1 > allocated)
4490 last = xrnew (last, len + 1, char);
4491 allocated = len + 1;
4492 strncpy (last, cp, len);
4493 last[len] = '\0';
4494 }
4495 }
4496 }
4497
4498
4499 static void
4500 prolog_skip_comment (plb, inf)
4501 linebuffer *plb;
4502 FILE *inf;
4503 {
4504 char *cp;
4505
4506 do
4507 {
4508 for (cp = plb->buffer; *cp != '\0'; cp++)
4509 if (cp[0] == '*' && cp[1] == '/')
4510 return;
4511 lineno++;
4512 linecharno += readline (plb, inf);
4513 }
4514 while (!feof(inf));
4515 }
4516
4517 /*
4518 * A predicate definition is added if it matches:
4519 * <beginning of line><Prolog Atom><whitespace>(
4520 *
4521 * It is added to the tags database if it doesn't match the
4522 * name of the previous clause header.
4523 *
4524 * Return the size of the name of the predicate, or 0 if no header
4525 * was found.
4526 */
4527 static int
4528 prolog_pred (s, last)
4529 char *s;
4530 char *last; /* Name of last clause. */
4531 {
4532 int pos;
4533 int len;
4534
4535 pos = prolog_atom (s, 0);
4536 if (pos < 1)
4537 return 0;
4538
4539 len = pos;
4540 pos = skip_spaces (s + pos) - s;
4541
4542 if ((s[pos] == '(') || (s[pos] == '.'))
4543 {
4544 if (s[pos] == '(')
4545 pos++;
4546
4547 /* Save only the first clause. */
4548 if (last == NULL
4549 || len != (int)strlen (last)
4550 || !strneq (s, last, len))
4551 {
4552 pfnote (savenstr (s, len), TRUE, s, pos, lineno, linecharno);
4553 return len;
4554 }
4555 }
4556 return 0;
4557 }
4558
4559 /*
4560 * Consume a Prolog atom.
4561 * Return the number of bytes consumed, or -1 if there was an error.
4562 *
4563 * A prolog atom, in this context, could be one of:
4564 * - An alphanumeric sequence, starting with a lower case letter.
4565 * - A quoted arbitrary string. Single quotes can escape themselves.
4566 * Backslash quotes everything.
4567 */
4568 static int
4569 prolog_atom (s, pos)
4570 char *s;
4571 int pos;
4572 {
4573 int origpos;
4574
4575 origpos = pos;
4576
4577 if (ISLOWER(s[pos]) || (s[pos] == '_'))
4578 {
4579 /* The atom is unquoted. */
4580 pos++;
4581 while (ISALNUM(s[pos]) || (s[pos] == '_'))
4582 {
4583 pos++;
4584 }
4585 return pos - origpos;
4586 }
4587 else if (s[pos] == '\'')
4588 {
4589 pos++;
4590
4591 while (1)
4592 {
4593 if (s[pos] == '\'')
4594 {
4595 pos++;
4596 if (s[pos] != '\'')
4597 break;
4598 pos++; /* A double quote */
4599 }
4600 else if (s[pos] == '\0')
4601 /* Multiline quoted atoms are ignored. */
4602 return -1;
4603 else if (s[pos] == '\\')
4604 {
4605 if (s[pos+1] == '\0')
4606 return -1;
4607 pos += 2;
4608 }
4609 else
4610 pos++;
4611 }
4612 return pos - origpos;
4613 }
4614 else
4615 return -1;
4616 }
4617 \f
4618 /*
4619 * Support for Erlang -- Anders Lindgren, Feb 1996.
4620 *
4621 * Generates tags for functions, defines, and records.
4622 *
4623 * Assumes that Erlang functions start at column 0.
4624 */
4625 static int erlang_func P_((char *, char *));
4626 static void erlang_attribute P_((char *));
4627 static int erlang_atom P_((char *, int));
4628
4629 static void
4630 Erlang_functions (inf)
4631 FILE *inf;
4632 {
4633 char *cp, *last;
4634 int len;
4635 int allocated;
4636
4637 allocated = 0;
4638 len = 0;
4639 last = NULL;
4640
4641 LOOP_ON_INPUT_LINES (inf, lb, cp)
4642 {
4643 if (cp[0] == '\0') /* Empty line */
4644 continue;
4645 else if (iswhite (cp[0])) /* Not function nor attribute */
4646 continue;
4647 else if (cp[0] == '%') /* comment */
4648 continue;
4649 else if (cp[0] == '"') /* Sometimes, strings start in column one */
4650 continue;
4651 else if (cp[0] == '-') /* attribute, e.g. "-define" */
4652 {
4653 erlang_attribute (cp);
4654 last = NULL;
4655 }
4656 else if ((len = erlang_func (cp, last)) > 0)
4657 {
4658 /*
4659 * Function. Store the function name so that we only
4660 * generates a tag for the first clause.
4661 */
4662 if (last == NULL)
4663 last = xnew (len + 1, char);
4664 else if (len + 1 > allocated)
4665 last = xrnew (last, len + 1, char);
4666 allocated = len + 1;
4667 strncpy (last, cp, len);
4668 last[len] = '\0';
4669 }
4670 }
4671 }
4672
4673
4674 /*
4675 * A function definition is added if it matches:
4676 * <beginning of line><Erlang Atom><whitespace>(
4677 *
4678 * It is added to the tags database if it doesn't match the
4679 * name of the previous clause header.
4680 *
4681 * Return the size of the name of the function, or 0 if no function
4682 * was found.
4683 */
4684 static int
4685 erlang_func (s, last)
4686 char *s;
4687 char *last; /* Name of last clause. */
4688 {
4689 int pos;
4690 int len;
4691
4692 pos = erlang_atom (s, 0);
4693 if (pos < 1)
4694 return 0;
4695
4696 len = pos;
4697 pos = skip_spaces (s + pos) - s;
4698
4699 /* Save only the first clause. */
4700 if (s[pos++] == '('
4701 && (last == NULL
4702 || len != (int)strlen (last)
4703 || !strneq (s, last, len)))
4704 {
4705 pfnote (savenstr (s, len), TRUE, s, pos, lineno, linecharno);
4706 return len;
4707 }
4708
4709 return 0;
4710 }
4711
4712
4713 /*
4714 * Handle attributes. Currently, tags are generated for defines
4715 * and records.
4716 *
4717 * They are on the form:
4718 * -define(foo, bar).
4719 * -define(Foo(M, N), M+N).
4720 * -record(graph, {vtab = notable, cyclic = true}).
4721 */
4722 static void
4723 erlang_attribute (s)
4724 char *s;
4725 {
4726 int pos;
4727 int len;
4728
4729 if (strneq (s, "-define", 7) || strneq (s, "-record", 7))
4730 {
4731 pos = skip_spaces (s + 7) - s;
4732 if (s[pos++] == '(')
4733 {
4734 pos = skip_spaces (s + pos) - s;
4735 len = erlang_atom (s, pos);
4736 if (len != 0)
4737 pfnote (savenstr (& s[pos], len), TRUE,
4738 s, pos + len, lineno, linecharno);
4739 }
4740 }
4741 return;
4742 }
4743
4744
4745 /*
4746 * Consume an Erlang atom (or variable).
4747 * Return the number of bytes consumed, or -1 if there was an error.
4748 */
4749 static int
4750 erlang_atom (s, pos)
4751 char *s;
4752 int pos;
4753 {
4754 int origpos;
4755
4756 origpos = pos;
4757
4758 if (ISALPHA (s[pos]) || s[pos] == '_')
4759 {
4760 /* The atom is unquoted. */
4761 pos++;
4762 while (ISALNUM (s[pos]) || s[pos] == '_')
4763 pos++;
4764 return pos - origpos;
4765 }
4766 else if (s[pos] == '\'')
4767 {
4768 pos++;
4769
4770 while (1)
4771 {
4772 if (s[pos] == '\'')
4773 {
4774 pos++;
4775 break;
4776 }
4777 else if (s[pos] == '\0')
4778 /* Multiline quoted atoms are ignored. */
4779 return -1;
4780 else if (s[pos] == '\\')
4781 {
4782 if (s[pos+1] == '\0')
4783 return -1;
4784 pos += 2;
4785 }
4786 else
4787 pos++;
4788 }
4789 return pos - origpos;
4790 }
4791 else
4792 return -1;
4793 }
4794 \f
4795 #ifdef ETAGS_REGEXPS
4796
4797 static char *scan_separators P_((char *));
4798 static void analyse_regex P_((char *, bool));
4799 static void add_regex P_((char *, bool, language *));
4800 static char *substitute P_((char *, char *, struct re_registers *));
4801
4802 /* Take a string like "/blah/" and turn it into "blah", making sure
4803 that the first and last characters are the same, and handling
4804 quoted separator characters. Actually, stops on the occurrence of
4805 an unquoted separator. Also turns "\t" into a Tab character.
4806 Returns pointer to terminating separator. Works in place. Null
4807 terminates name string. */
4808 static char *
4809 scan_separators (name)
4810 char *name;
4811 {
4812 char sep = name[0];
4813 char *copyto = name;
4814 bool quoted = FALSE;
4815
4816 for (++name; *name != '\0'; ++name)
4817 {
4818 if (quoted)
4819 {
4820 if (*name == 't')
4821 *copyto++ = '\t';
4822 else if (*name == sep)
4823 *copyto++ = sep;
4824 else
4825 {
4826 /* Something else is quoted, so preserve the quote. */
4827 *copyto++ = '\\';
4828 *copyto++ = *name;
4829 }
4830 quoted = FALSE;
4831 }
4832 else if (*name == '\\')
4833 quoted = TRUE;
4834 else if (*name == sep)
4835 break;
4836 else
4837 *copyto++ = *name;
4838 }
4839
4840 /* Terminate copied string. */
4841 *copyto = '\0';
4842 return name;
4843 }
4844
4845 /* Look at the argument of --regex or --no-regex and do the right
4846 thing. Same for each line of a regexp file. */
4847 static void
4848 analyse_regex (regex_arg, ignore_case)
4849 char *regex_arg;
4850 bool ignore_case;
4851 {
4852 if (regex_arg == NULL)
4853 free_patterns (); /* --no-regex: remove existing regexps */
4854
4855 /* A real --regexp option or a line in a regexp file. */
4856 switch (regex_arg[0])
4857 {
4858 /* Comments in regexp file or null arg to --regex. */
4859 case '\0':
4860 case ' ':
4861 case '\t':
4862 break;
4863
4864 /* Read a regex file. This is recursive and may result in a
4865 loop, which will stop when the file descriptors are exhausted. */
4866 case '@':
4867 {
4868 FILE *regexfp;
4869 linebuffer regexbuf;
4870 char *regexfile = regex_arg + 1;
4871
4872 /* regexfile is a file containing regexps, one per line. */
4873 regexfp = fopen (regexfile, "r");
4874 if (regexfp == NULL)
4875 {
4876 pfatal (regexfile);
4877 return;
4878 }
4879 initbuffer (&regexbuf);
4880 while (readline_internal (&regexbuf, regexfp) > 0)
4881 analyse_regex (regexbuf.buffer, ignore_case);
4882 free (regexbuf.buffer);
4883 fclose (regexfp);
4884 }
4885 break;
4886
4887 /* Regexp to be used for a specific language only. */
4888 case '{':
4889 {
4890 language *lang;
4891 char *lang_name = regex_arg + 1;
4892 char *cp;
4893
4894 for (cp = lang_name; *cp != '}'; cp++)
4895 if (*cp == '\0')
4896 {
4897 error ("unterminated language name in regex: %s", regex_arg);
4898 return;
4899 }
4900 *cp = '\0';
4901 lang = get_language_from_langname (lang_name);
4902 if (lang == NULL)
4903 return;
4904 add_regex (cp + 1, ignore_case, lang);
4905 }
4906 break;
4907
4908 /* Regexp to be used for any language. */
4909 default:
4910 add_regex (regex_arg, ignore_case, NULL);
4911 break;
4912 }
4913 }
4914
4915 /* Turn a name, which is an ed-style (but Emacs syntax) regular
4916 expression, into a real regular expression by compiling it. */
4917 static void
4918 add_regex (regexp_pattern, ignore_case, lang)
4919 char *regexp_pattern;
4920 bool ignore_case;
4921 language *lang;
4922 {
4923 char *name;
4924 const char *err;
4925 struct re_pattern_buffer *patbuf;
4926 pattern *pp;
4927
4928
4929 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
4930 {
4931 error ("%s: unterminated regexp", regexp_pattern);
4932 return;
4933 }
4934 name = scan_separators (regexp_pattern);
4935 if (regexp_pattern[0] == '\0')
4936 {
4937 error ("null regexp", (char *)NULL);
4938 return;
4939 }
4940 (void) scan_separators (name);
4941
4942 patbuf = xnew (1, struct re_pattern_buffer);
4943 /* Translation table to fold case if appropriate. */
4944 patbuf->translate = (ignore_case) ? lc_trans : NULL;
4945 patbuf->fastmap = NULL;
4946 patbuf->buffer = NULL;
4947 patbuf->allocated = 0;
4948
4949 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
4950 if (err != NULL)
4951 {
4952 error ("%s while compiling pattern", err);
4953 return;
4954 }
4955
4956 pp = p_head;
4957 p_head = xnew (1, pattern);
4958 p_head->regex = savestr (regexp_pattern);
4959 p_head->p_next = pp;
4960 p_head->language = lang;
4961 p_head->pattern = patbuf;
4962 p_head->name_pattern = savestr (name);
4963 p_head->error_signaled = FALSE;
4964 }
4965
4966 /*
4967 * Do the substitutions indicated by the regular expression and
4968 * arguments.
4969 */
4970 static char *
4971 substitute (in, out, regs)
4972 char *in, *out;
4973 struct re_registers *regs;
4974 {
4975 char *result, *t;
4976 int size, dig, diglen;
4977
4978 result = NULL;
4979 size = strlen (out);
4980
4981 /* Pass 1: figure out how much to allocate by finding all \N strings. */
4982 if (out[size - 1] == '\\')
4983 fatal ("pattern error in \"%s\"", out);
4984 for (t = etags_strchr (out, '\\');
4985 t != NULL;
4986 t = etags_strchr (t + 2, '\\'))
4987 if (ISDIGIT (t[1]))
4988 {
4989 dig = t[1] - '0';
4990 diglen = regs->end[dig] - regs->start[dig];
4991 size += diglen - 2;
4992 }
4993 else
4994 size -= 1;
4995
4996 /* Allocate space and do the substitutions. */
4997 result = xnew (size + 1, char);
4998
4999 for (t = result; *out != '\0'; out++)
5000 if (*out == '\\' && ISDIGIT (*++out))
5001 {
5002 /* Using "dig2" satisfies my debugger. Bleah. */
5003 dig = *out - '0';
5004 diglen = regs->end[dig] - regs->start[dig];
5005 strncpy (t, in + regs->start[dig], diglen);
5006 t += diglen;
5007 }
5008 else
5009 *t++ = *out;
5010 *t = '\0';
5011
5012 if (DEBUG && (t > result + size || t - result != (int)strlen (result)))
5013 abort ();
5014
5015 return result;
5016 }
5017
5018 /* Deallocate all patterns. */
5019 static void
5020 free_patterns ()
5021 {
5022 pattern *pp;
5023 while (p_head != NULL)
5024 {
5025 pp = p_head->p_next;
5026 free (p_head->regex);
5027 free (p_head->name_pattern);
5028 free (p_head);
5029 p_head = pp;
5030 }
5031 return;
5032 }
5033 \f
5034 static void
5035 get_tag (bp)
5036 register char *bp;
5037 {
5038 register char *cp;
5039
5040 if (*bp == '\0')
5041 return;
5042 /* Go till you get to white space or a syntactic break */
5043 for (cp = bp + 1;
5044 *cp != '\0' && *cp != '(' && *cp != ')' && !iswhite (*cp);
5045 cp++)
5046 continue;
5047 pfnote (savenstr (bp, cp-bp), TRUE,
5048 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5049 }
5050
5051 #endif /* ETAGS_REGEXPS */
5052 /* Initialize a linebuffer for use */
5053 static void
5054 initbuffer (lbp)
5055 linebuffer *lbp;
5056 {
5057 lbp->size = 200;
5058 lbp->buffer = xnew (200, char);
5059 }
5060
5061 /*
5062 * Read a line of text from `stream' into `lbp', excluding the
5063 * newline or CR-NL, if any. Return the number of characters read from
5064 * `stream', which is the length of the line including the newline.
5065 *
5066 * On DOS or Windows we do not count the CR character, if any, before the
5067 * NL, in the returned length; this mirrors the behavior of emacs on those
5068 * platforms (for text files, it translates CR-NL to NL as it reads in the
5069 * file).
5070 */
5071 static long
5072 readline_internal (lbp, stream)
5073 linebuffer *lbp;
5074 register FILE *stream;
5075 {
5076 char *buffer = lbp->buffer;
5077 register char *p = lbp->buffer;
5078 register char *pend;
5079 int chars_deleted;
5080
5081 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
5082
5083 while (1)
5084 {
5085 register int c = getc (stream);
5086 if (p == pend)
5087 {
5088 /* We're at the end of linebuffer: expand it. */
5089 lbp->size *= 2;
5090 buffer = xrnew (buffer, lbp->size, char);
5091 p += buffer - lbp->buffer;
5092 pend = buffer + lbp->size;
5093 lbp->buffer = buffer;
5094 }
5095 if (c == EOF)
5096 {
5097 *p = '\0';
5098 chars_deleted = 0;
5099 break;
5100 }
5101 if (c == '\n')
5102 {
5103 if (p > buffer && p[-1] == '\r')
5104 {
5105 p -= 1;
5106 #ifdef DOS_NT
5107 /* Assume CRLF->LF translation will be performed by Emacs
5108 when loading this file, so CRs won't appear in the buffer.
5109 It would be cleaner to compensate within Emacs;
5110 however, Emacs does not know how many CRs were deleted
5111 before any given point in the file. */
5112 chars_deleted = 1;
5113 #else
5114 chars_deleted = 2;
5115 #endif
5116 }
5117 else
5118 {
5119 chars_deleted = 1;
5120 }
5121 *p = '\0';
5122 break;
5123 }
5124 *p++ = c;
5125 }
5126 lbp->len = p - buffer;
5127
5128 return lbp->len + chars_deleted;
5129 }
5130
5131 /*
5132 * Like readline_internal, above, but in addition try to match the
5133 * input line against relevant regular expressions.
5134 */
5135 static long
5136 readline (lbp, stream)
5137 linebuffer *lbp;
5138 FILE *stream;
5139 {
5140 /* Read new line. */
5141 long result = readline_internal (lbp, stream);
5142 #ifdef ETAGS_REGEXPS
5143 int match;
5144 pattern *pp;
5145
5146 /* Match against relevant patterns. */
5147 if (lbp->len > 0)
5148 for (pp = p_head; pp != NULL; pp = pp->p_next)
5149 {
5150 /* Only use generic regexps or those for the current language. */
5151 if (pp->language != NULL && pp->language != curlang)
5152 continue;
5153
5154 match = re_match (pp->pattern, lbp->buffer, lbp->len, 0, &pp->regs);
5155 switch (match)
5156 {
5157 case -2:
5158 /* Some error. */
5159 if (!pp->error_signaled)
5160 {
5161 error ("error while matching \"%s\"", pp->regex);
5162 pp->error_signaled = TRUE;
5163 }
5164 break;
5165 case -1:
5166 /* No match. */
5167 break;
5168 default:
5169 /* Match occurred. Construct a tag. */
5170 if (pp->name_pattern[0] != '\0')
5171 {
5172 /* Make a named tag. */
5173 char *name = substitute (lbp->buffer,
5174 pp->name_pattern, &pp->regs);
5175 if (name != NULL)
5176 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
5177 }
5178 else
5179 {
5180 /* Make an unnamed tag. */
5181 pfnote ((char *)NULL, TRUE,
5182 lbp->buffer, match, lineno, linecharno);
5183 }
5184 break;
5185 }
5186 }
5187 #endif /* ETAGS_REGEXPS */
5188
5189 return result;
5190 }
5191 \f
5192 /*
5193 * Return a pointer to a space of size strlen(cp)+1 allocated
5194 * with xnew where the string CP has been copied.
5195 */
5196 static char *
5197 savestr (cp)
5198 char *cp;
5199 {
5200 return savenstr (cp, strlen (cp));
5201 }
5202
5203 /*
5204 * Return a pointer to a space of size LEN+1 allocated with xnew where
5205 * the string CP has been copied for at most the first LEN characters.
5206 */
5207 static char *
5208 savenstr (cp, len)
5209 char *cp;
5210 int len;
5211 {
5212 register char *dp;
5213
5214 dp = xnew (len + 1, char);
5215 strncpy (dp, cp, len);
5216 dp[len] = '\0';
5217 return dp;
5218 }
5219
5220 /*
5221 * Return the ptr in sp at which the character c last
5222 * appears; NULL if not found
5223 *
5224 * Identical to POSIX strrchr, included for portability.
5225 */
5226 static char *
5227 etags_strrchr (sp, c)
5228 register const char *sp;
5229 register int c;
5230 {
5231 register const char *r;
5232
5233 r = NULL;
5234 do
5235 {
5236 if (*sp == c)
5237 r = sp;
5238 } while (*sp++);
5239 return (char *)r;
5240 }
5241
5242
5243 /*
5244 * Return the ptr in sp at which the character c first
5245 * appears; NULL if not found
5246 *
5247 * Identical to POSIX strchr, included for portability.
5248 */
5249 static char *
5250 etags_strchr (sp, c)
5251 register const char *sp;
5252 register int c;
5253 {
5254 do
5255 {
5256 if (*sp == c)
5257 return (char *)sp;
5258 } while (*sp++);
5259 return NULL;
5260 }
5261
5262 /* Skip spaces, return new pointer. */
5263 static char *
5264 skip_spaces (cp)
5265 char *cp;
5266 {
5267 while (iswhite (*cp))
5268 cp++;
5269 return cp;
5270 }
5271
5272 /* Skip non spaces, return new pointer. */
5273 static char *
5274 skip_non_spaces (cp)
5275 char *cp;
5276 {
5277 while (*cp != '\0' && !iswhite (*cp))
5278 cp++;
5279 return cp;
5280 }
5281
5282 /* Print error message and exit. */
5283 static void
5284 fatal (s1, s2)
5285 char *s1, *s2;
5286 {
5287 error (s1, s2);
5288 exit (BAD);
5289 }
5290
5291 static void
5292 pfatal (s1)
5293 char *s1;
5294 {
5295 perror (s1);
5296 exit (BAD);
5297 }
5298
5299 static void
5300 suggest_asking_for_help ()
5301 {
5302 fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
5303 progname,
5304 #ifdef LONG_OPTIONS
5305 "--help"
5306 #else
5307 "-h"
5308 #endif
5309 );
5310 exit (BAD);
5311 }
5312
5313 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
5314 static void
5315 error (s1, s2)
5316 const char *s1, *s2;
5317 {
5318 fprintf (stderr, "%s: ", progname);
5319 fprintf (stderr, s1, s2);
5320 fprintf (stderr, "\n");
5321 }
5322
5323 /* Return a newly-allocated string whose contents
5324 concatenate those of s1, s2, s3. */
5325 static char *
5326 concat (s1, s2, s3)
5327 char *s1, *s2, *s3;
5328 {
5329 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
5330 char *result = xnew (len1 + len2 + len3 + 1, char);
5331
5332 strcpy (result, s1);
5333 strcpy (result + len1, s2);
5334 strcpy (result + len1 + len2, s3);
5335 result[len1 + len2 + len3] = '\0';
5336
5337 return result;
5338 }
5339 \f
5340 /* Does the same work as the system V getcwd, but does not need to
5341 guess the buffer size in advance. */
5342 static char *
5343 etags_getcwd ()
5344 {
5345 #ifdef HAVE_GETCWD
5346 int bufsize = 200;
5347 char *path = xnew (bufsize, char);
5348
5349 while (getcwd (path, bufsize) == NULL)
5350 {
5351 if (errno != ERANGE)
5352 pfatal ("getcwd");
5353 bufsize *= 2;
5354 free (path);
5355 path = xnew (bufsize, char);
5356 }
5357
5358 canonicalize_filename (path);
5359 return path;
5360
5361 #else /* not HAVE_GETCWD */
5362 #ifdef MSDOS
5363 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
5364
5365 getwd (path);
5366
5367 for (p = path; *p != '\0'; p++)
5368 if (*p == '\\')
5369 *p = '/';
5370 else
5371 *p = lowcase (*p);
5372
5373 return strdup (path);
5374 #else /* not MSDOS */
5375 linebuffer path;
5376 FILE *pipe;
5377
5378 initbuffer (&path);
5379 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
5380 if (pipe == NULL || readline_internal (&path, pipe) == 0)
5381 pfatal ("pwd");
5382 pclose (pipe);
5383
5384 return path.buffer;
5385 #endif /* not MSDOS */
5386 #endif /* not HAVE_GETCWD */
5387 }
5388
5389 /* Return a newly allocated string containing the file name of FILE
5390 relative to the absolute directory DIR (which should end with a slash). */
5391 static char *
5392 relative_filename (file, dir)
5393 char *file, *dir;
5394 {
5395 char *fp, *dp, *afn, *res;
5396 int i;
5397
5398 /* Find the common root of file and dir (with a trailing slash). */
5399 afn = absolute_filename (file, cwd);
5400 fp = afn;
5401 dp = dir;
5402 while (*fp++ == *dp++)
5403 continue;
5404 fp--, dp--; /* back to the first differing char */
5405 #ifdef DOS_NT
5406 if (fp == afn && afn[0] != '/') /* cannot build a relative name */
5407 return afn;
5408 #endif
5409 do /* look at the equal chars until '/' */
5410 fp--, dp--;
5411 while (*fp != '/');
5412
5413 /* Build a sequence of "../" strings for the resulting relative file name. */
5414 i = 0;
5415 while ((dp = etags_strchr (dp + 1, '/')) != NULL)
5416 i += 1;
5417 res = xnew (3*i + strlen (fp + 1) + 1, char);
5418 res[0] = '\0';
5419 while (i-- > 0)
5420 strcat (res, "../");
5421
5422 /* Add the file name relative to the common root of file and dir. */
5423 strcat (res, fp + 1);
5424 free (afn);
5425
5426 return res;
5427 }
5428
5429 /* Return a newly allocated string containing the absolute file name
5430 of FILE given DIR (which should end with a slash). */
5431 static char *
5432 absolute_filename (file, dir)
5433 char *file, *dir;
5434 {
5435 char *slashp, *cp, *res;
5436
5437 if (filename_is_absolute (file))
5438 res = savestr (file);
5439 #ifdef DOS_NT
5440 /* We don't support non-absolute file names with a drive
5441 letter, like `d:NAME' (it's too much hassle). */
5442 else if (file[1] == ':')
5443 fatal ("%s: relative file names with drive letters not supported", file);
5444 #endif
5445 else
5446 res = concat (dir, file, "");
5447
5448 /* Delete the "/dirname/.." and "/." substrings. */
5449 slashp = etags_strchr (res, '/');
5450 while (slashp != NULL && slashp[0] != '\0')
5451 {
5452 if (slashp[1] == '.')
5453 {
5454 if (slashp[2] == '.'
5455 && (slashp[3] == '/' || slashp[3] == '\0'))
5456 {
5457 cp = slashp;
5458 do
5459 cp--;
5460 while (cp >= res && !filename_is_absolute (cp));
5461 if (cp < res)
5462 cp = slashp; /* the absolute name begins with "/.." */
5463 #ifdef DOS_NT
5464 /* Under MSDOS and NT we get `d:/NAME' as absolute
5465 file name, so the luser could say `d:/../NAME'.
5466 We silently treat this as `d:/NAME'. */
5467 else if (cp[0] != '/')
5468 cp = slashp;
5469 #endif
5470 strcpy (cp, slashp + 3);
5471 slashp = cp;
5472 continue;
5473 }
5474 else if (slashp[2] == '/' || slashp[2] == '\0')
5475 {
5476 strcpy (slashp, slashp + 2);
5477 continue;
5478 }
5479 }
5480
5481 slashp = etags_strchr (slashp + 1, '/');
5482 }
5483
5484 if (res[0] == '\0')
5485 return savestr ("/");
5486 else
5487 return res;
5488 }
5489
5490 /* Return a newly allocated string containing the absolute
5491 file name of dir where FILE resides given DIR (which should
5492 end with a slash). */
5493 static char *
5494 absolute_dirname (file, dir)
5495 char *file, *dir;
5496 {
5497 char *slashp, *res;
5498 char save;
5499
5500 canonicalize_filename (file);
5501 slashp = etags_strrchr (file, '/');
5502 if (slashp == NULL)
5503 return savestr (dir);
5504 save = slashp[1];
5505 slashp[1] = '\0';
5506 res = absolute_filename (file, dir);
5507 slashp[1] = save;
5508
5509 return res;
5510 }
5511
5512 /* Whether the argument string is an absolute file name. The argument
5513 string must have been canonicalized with canonicalize_filename. */
5514 static bool
5515 filename_is_absolute (fn)
5516 char *fn;
5517 {
5518 return (fn[0] == '/'
5519 #ifdef DOS_NT
5520 || (ISALPHA(fn[0]) && fn[1] == ':' && fn[2] == '/')
5521 #endif
5522 );
5523 }
5524
5525 /* Translate backslashes into slashes. Works in place. */
5526 static void
5527 canonicalize_filename (fn)
5528 register char *fn;
5529 {
5530 #ifdef DOS_NT
5531 /* Canonicalize drive letter case. */
5532 if (fn[0] != '\0' && fn[1] == ':' && ISLOWER (fn[0]))
5533 fn[0] = upcase (fn[0]);
5534 /* Convert backslashes to slashes. */
5535 for (; *fn != '\0'; fn++)
5536 if (*fn == '\\')
5537 *fn = '/';
5538 #else
5539 /* No action. */
5540 fn = NULL; /* shut up the compiler */
5541 #endif
5542 }
5543
5544 /* Increase the size of a linebuffer. */
5545 static void
5546 grow_linebuffer (lbp, toksize)
5547 linebuffer *lbp;
5548 int toksize;
5549 {
5550 while (lbp->size < toksize)
5551 lbp->size *= 2;
5552 lbp->buffer = xrnew (lbp->buffer, lbp->size, char);
5553 }
5554
5555 /* Like malloc but get fatal error if memory is exhausted. */
5556 long *
5557 xmalloc (size)
5558 unsigned int size;
5559 {
5560 long *result = (long *) malloc (size);
5561 if (result == NULL)
5562 fatal ("virtual memory exhausted", (char *)NULL);
5563 return result;
5564 }
5565
5566 long *
5567 xrealloc (ptr, size)
5568 char *ptr;
5569 unsigned int size;
5570 {
5571 long *result = (long *) realloc (ptr, size);
5572 if (result == NULL)
5573 fatal ("virtual memory exhausted", (char *)NULL);
5574 return result;
5575 }