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