Fix if/else scope in yow.c from Rudi
[sxemacs] / lib-src / etags.c
1 /* Tags file maker to go with GNU Emacs           -*- coding: latin-1 -*-
2
3 Copyright (C) 1984 The Regents of the University of California
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the
13    distribution.
14 3. Neither the name of the University nor the names of its
15    contributors may be used to endorse or promote products derived
16    from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
19 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
31 Copyright (C) 1984, 1987, 1988, 1989, 1993, 1994, 1995, 1998, 1999,
32   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
33   Free Software Foundation, Inc.
34
35 This file is not considered part of GNU Emacs.
36
37 This program is free software: you can redistribute it and/or modify
38 it under the terms of the GNU General Public License as published by
39 the Free Software Foundation, either version 3 of the License, or
40 (at your option) any later version.
41
42 This program is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45 GNU General Public License for more details.
46
47 You should have received a copy of the GNU General Public License
48 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
49
50
51 /* NB To comply with the above BSD license, copyright information is
52 reproduced in etc/ETAGS.README.  That file should be updated when the
53 above notices are.
54
55 To the best of our knowledge, this code was originally based on the
56 ctags.c distributed with BSD4.2, which was copyrighted by the
57 University of California, as described above. */
58
59
60 /*
61  * Authors:
62  * 1983 Ctags originally by Ken Arnold.
63  * 1984 Fortran added by Jim Kleckner.
64  * 1984 Ed Pelegri-Llopart added C typedefs.
65  * 1985 Emacs TAGS format by Richard Stallman.
66  * 1989 Sam Kendall added C++.
67  * 1992 Joseph B. Wells improved C and C++ parsing.
68  * 1993 Francesco Potortì reorganized C and C++.
69  * 1994 Line-by-line regexp tags by Tom Tromey.
70  * 2001 Nested classes by Francesco Potortì (concept by Mykola Dzyuba).
71  * 2002 #line directives by Francesco Potortì.
72  *
73  * Francesco Potortì <pot@gnu.org> has maintained and improved it since 1993.
74  */
75
76 /*
77  * If you want to add support for a new language, start by looking at the LUA
78  * language, which is the simplest.  Alternatively, consider distributing etags
79  * together with a configuration file containing regexp definitions for etags.
80  */
81
82 char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
83
84 #define TRUE    1
85 #define FALSE   0
86
87 #ifdef DEBUG
88 #  undef DEBUG
89 #  define DEBUG TRUE
90 #else
91 #  define DEBUG  FALSE
92 #  define NDEBUG                /* disable assert */
93 #endif
94
95 #ifdef HAVE_CONFIG_H
96 # include "config.h"
97 /* On some systems, Emacs defines static as nothing for the sake
98    of unexec.  We don't want that here since we don't use unexec. */
99 # undef static
100 # ifndef PTR                    /* for XEmacs */
101 #   define PTR void *
102 # endif
103 # ifndef __P                    /* for XEmacs */
104 #   define __P(args) args
105 # endif
106 #else  /* no config.h */
107 # if defined(__STDC__) && (__STDC__ || defined(__SUNPRO_C))
108 #   define __P(args) args       /* use prototypes */
109 #   define PTR void *           /* for generic pointers */
110 # else /* not standard C */
111 #   define __P(args) ()         /* no prototypes */
112 #   define const                /* remove const for old compilers' sake */
113 #   define PTR long *           /* don't use void* */
114 # endif
115 #endif /* !HAVE_CONFIG_H */
116
117 #ifndef _GNU_SOURCE
118 # define _GNU_SOURCE 1          /* enables some compiler checks on GNU */
119 #endif
120
121 #define MSDOS FALSE
122
123 #ifdef STDC_HEADERS
124 # include <stdlib.h>
125 # include <string.h>
126 #else /* no standard C headers */
127 extern char *getenv __P((const char *));
128 extern char *strcpy __P((char *, const char *));
129 extern char *strncpy __P((char *, const char *, unsigned long));
130 extern char *strcat __P((char *, const char *));
131 extern char *strncat __P((char *, const char *, unsigned long));
132 extern int strcmp __P((const char *, const char *));
133 extern int strncmp __P((const char *, const char *, unsigned long));
134 extern int system __P((const char *));
135 extern unsigned long strlen __P((const char *));
136 extern void *malloc __P((unsigned long));
137 extern void *realloc __P((void *, unsigned long));
138 extern void exit __P((int));
139 extern void free __P((void *));
140 extern void *memmove __P((void *, const void *, unsigned long));
141 # define EXIT_SUCCESS   0
142 # define EXIT_FAILURE   1
143 #endif  /* STDC_HEADERS */
144
145 #ifdef HAVE_UNISTD_H
146 # include <unistd.h>
147 #else
148 # ifdef HAVE_GETCWD
149 extern char *getcwd (char *buf, size_t size);
150 # endif
151 #endif /* HAVE_UNISTD_H */
152
153 #include <stdio.h>
154 #include <ctype.h>
155 #include <errno.h>
156 #ifndef errno
157 extern int errno;
158 #endif
159 #include <sys/types.h>
160 #include <sys/stat.h>
161
162 #include <assert.h>
163 #ifdef NDEBUG
164 # undef  assert                 /* some systems have a buggy assert.h */
165 # define assert(x) ((void) 0)
166 #endif
167
168 #if !defined (S_ISREG) && defined (S_IFREG)
169 # define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG)
170 #endif
171
172 #ifndef HAVE_GETOPT_LONG
173 # define NO_LONG_OPTIONS TRUE
174 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
175 extern char *optarg;
176 extern int optind, opterr;
177 #else
178 # define NO_LONG_OPTIONS FALSE
179 # include <getopt.h>
180 #endif /* HAVE_GETOPT_LONG */
181
182 #include <regex.h>
183
184 /* Define CTAGS to make the program "ctags" compatible with the usual one.
185    Leave it undefined to make the program "etags", which makes emacs-style
186    tag tables and tags typedefs, #defines and struct/union/enum by default. */
187 #ifdef CTAGS
188 # undef  CTAGS
189 # define CTAGS TRUE
190 #else
191 # define CTAGS FALSE
192 #endif
193
194 #define streq(s,t)      (assert((s)!=NULL || (t)!=NULL), !strcmp (s, t))
195 #define strcaseeq(s,t)  (assert((s)!=NULL && (t)!=NULL), !etags_strcasecmp (s, t))
196 #define strneq(s,t,n)   (assert((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
197 #define strncaseeq(s,t,n) (assert((s)!=NULL && (t)!=NULL), !etags_strncasecmp (s, t, n))
198
199 #define CHARS 256               /* 2^sizeof(char) */
200 #define CHAR(x)         ((unsigned int)(x) & (CHARS - 1))
201 #define iswhite(c)      (_wht[CHAR(c)]) /* c is white (see white) */
202 #define notinname(c)    (_nin[CHAR(c)]) /* c is not in a name (see nonam) */
203 #define begtoken(c)     (_btk[CHAR(c)]) /* c can start token (see begtk) */
204 #define intoken(c)      (_itk[CHAR(c)]) /* c can be in token (see midtk) */
205 #define endtoken(c)     (_etk[CHAR(c)]) /* c ends tokens (see endtk) */
206
207 #define ISALNUM(c)      isalnum (CHAR(c))
208 #define ISALPHA(c)      isalpha (CHAR(c))
209 #define ISDIGIT(c)      isdigit (CHAR(c))
210 #define ISLOWER(c)      islower (CHAR(c))
211
212 #define lowcase(c)      tolower (CHAR(c))
213 #define upcase(c)       toupper (CHAR(c))
214
215
216 /*
217  *      xnew, xrnew -- allocate, reallocate storage
218  *
219  * SYNOPSIS:    Type *xnew (int n, Type);
220  *              void xrnew (OldPointer, int n, Type);
221  */
222 #if DEBUG
223 # include "chkmalloc.h"
224 # define xnew(n,Type)     ((Type *) trace_malloc (__FILE__, __LINE__,   \
225                                                   (n) * sizeof (Type)))
226 # define xrnew(op,n,Type) ((op) = (Type *) trace_realloc (__FILE__, __LINE__, \
227                                                           (char *) (op), (n) * sizeof (Type)))
228 #else
229 # define xnew(n,Type)     ((Type *) xmalloc ((n) * sizeof (Type)))
230 # define xrnew(op,n,Type) ((op) = (Type *) xrealloc (                   \
231                                    (char *) (op), (n) * sizeof (Type)))
232 #endif
233
234 #define bool int
235
236 typedef void Lang_function __P((FILE *));
237
238 typedef struct
239 {
240         char *suffix;                   /* file name suffix for this compressor */
241         char *command;          /* takes one arg and decompresses to stdout */
242 } compressor;
243
244 typedef struct
245 {
246         char *name;                     /* language name */
247         char *help;                   /* detailed help for the language */
248         Lang_function *function;        /* parse function */
249         char **suffixes;                /* name suffixes of this language's files */
250         char **filenames;               /* names of this language's files */
251         char **interpreters;            /* interpreters for this language */
252         bool metasource;                /* source used to generate other sources */
253 } language;
254
255 typedef struct fdesc
256 {
257         struct fdesc *next;             /* for the linked list */
258         char *infname;          /* uncompressed input file name */
259         char *infabsname;               /* absolute uncompressed input file name */
260         char *infabsdir;                /* absolute dir of input file */
261         char *taggedfname;              /* file name to write in tagfile */
262         language *lang;         /* language of file */
263         char *prop;                     /* file properties to write in tagfile */
264         bool usecharno;         /* etags tags shall contain char number */
265         bool written;                   /* entry written in the tags file */
266 } fdesc;
267
268 typedef struct node_st
269 {                               /* sorting structure */
270         struct node_st *left, *right;   /* left and right sons */
271         fdesc *fdp;                     /* description of file to whom tag belongs */
272         char *name;                     /* tag name */
273         char *regex;                    /* search regexp */
274         bool valid;                     /* write this tag on the tag file */
275         bool is_func;                   /* function tag: use regexp in CTAGS mode */
276         bool been_warned;               /* warning already given for duplicated tag */
277         int lno;                        /* line number tag is on */
278         long cno;                       /* character number line starts on */
279 } node;
280
281 /*
282  * A `linebuffer' is a structure which holds a line of text.
283  * `readline_internal' reads a line from a stream into a linebuffer
284  * and works regardless of the length of the line.
285  * SIZE is the size of BUFFER, LEN is the length of the string in
286  * BUFFER after readline reads it.
287  */
288 typedef struct
289 {
290         long size;
291         int len;
292         char *buffer;
293 } linebuffer;
294
295 /* Used to support mixing of --lang and file names. */
296 typedef struct
297 {
298         enum {
299                 at_language,            /* a language specification */
300                 at_regexp,                      /* a regular expression */
301                 at_filename,            /* a file name */
302                 at_stdin,                       /* read from stdin here */
303                 at_end                  /* stop parsing the list */
304         } arg_type;                     /* argument type */
305         language *lang;         /* language associated with the argument */
306         char *what;                     /* the argument itself */
307 } argument;
308
309 /* Structure defining a regular expression. */
310 typedef struct regexp
311 {
312         struct regexp *p_next;  /* pointer to next in list */
313         language *lang;         /* if set, use only for this language */
314         char *pattern;          /* the regexp pattern */
315         char *name;                     /* tag name */
316         struct re_pattern_buffer *pat; /* the compiled pattern */
317         struct re_registers regs;       /* re registers */
318         bool error_signaled;            /* already signaled for this regexp */
319         bool force_explicit_name;       /* do not allow implict tag name */
320         bool ignore_case;               /* ignore case when matching */
321         bool multi_line;                /* do a multi-line match on the whole file */
322 } regexp;
323
324
325 /* Many compilers barf on this:
326    Lang_function Ada_funcs;
327    so let's write it this way */
328 static void Ada_funcs __P((FILE *));
329 static void Asm_labels __P((FILE *));
330 static void C_entries __P((int c_ext, FILE *));
331 static void default_C_entries __P((FILE *));
332 static void plain_C_entries __P((FILE *));
333 static void Cjava_entries __P((FILE *));
334 static void Cobol_paragraphs __P((FILE *));
335 static void Cplusplus_entries __P((FILE *));
336 static void Cstar_entries __P((FILE *));
337 static void Erlang_functions __P((FILE *));
338 static void Forth_words __P((FILE *));
339 static void Fortran_functions __P((FILE *));
340 static void HTML_labels __P((FILE *));
341 static void Lisp_functions __P((FILE *));
342 static void Lua_functions __P((FILE *));
343 static void Makefile_targets __P((FILE *));
344 static void Pascal_functions __P((FILE *));
345 static void Perl_functions __P((FILE *));
346 static void PHP_functions __P((FILE *));
347 static void PS_functions __P((FILE *));
348 static void Prolog_functions __P((FILE *));
349 static void Python_functions __P((FILE *));
350 static void Scheme_functions __P((FILE *));
351 static void TeX_commands __P((FILE *));
352 static void Texinfo_nodes __P((FILE *));
353 static void Yacc_entries __P((FILE *));
354 static void just_read_file __P((FILE *));
355
356 static void print_language_names __P((void));
357 static void print_version __P((void));
358 static void print_help __P((argument *));
359 int main __P((int, char **));
360
361 static compressor *get_compressor_from_suffix __P((char *, char **));
362 static language *get_language_from_langname __P((const char *));
363 static language *get_language_from_interpreter __P((char *));
364 static language *get_language_from_filename __P((char *, bool));
365 static void readline __P((linebuffer *, FILE *));
366 static long readline_internal __P((linebuffer *, FILE *));
367 static bool nocase_tail __P((char *));
368 static void get_tag __P((char *, char **));
369
370 static void analyse_regex __P((char *));
371 static void free_regexps __P((void));
372 static void regex_tag_multiline __P((void));
373 static void error __P((const char *, const char *));
374 static void suggest_asking_for_help __P((void));
375 void fatal __P((char *, char *));
376 static void pfatal __P((char *));
377 static void add_node __P((node *, node **));
378
379 static void init __P((void));
380 static void process_file_name __P((char *, language *));
381 static void process_file __P((FILE *, char *, language *));
382 static void find_entries __P((FILE *));
383 static void free_tree __P((node *));
384 static void free_fdesc __P((fdesc *));
385 static void pfnote __P((char *, bool, char *, int, int, long));
386 static void make_tag __P((char *, int, bool, char *, int, int, long));
387 static void invalidate_nodes __P((fdesc *, node **));
388 static void put_entries __P((node *));
389
390 static char *concat __P((char *, char *, char *));
391 static char *skip_spaces __P((char *));
392 static char *skip_non_spaces __P((char *));
393 static char *savenstr __P((char *, int));
394 static char *savestr __P((char *));
395 static char *etags_strchr __P((const char *, int));
396 static char *etags_strrchr __P((const char *, int));
397 static int etags_strcasecmp __P((const char *, const char *));
398 static int etags_strncasecmp __P((const char *, const char *, int));
399 static char *etags_getcwd __P((void));
400 static char *relative_filename __P((char *, char *));
401 static char *absolute_filename __P((char *, char *));
402 static char *absolute_dirname __P((char *, char *));
403 static bool filename_is_absolute __P((char *f));
404 static void canonicalize_filename __P((char *));
405 static void linebuffer_init __P((linebuffer *));
406 static void linebuffer_setlen __P((linebuffer *, int));
407 static PTR xmalloc __P((unsigned int));
408 static PTR xrealloc __P((char *, unsigned int));
409
410 \f
411 static char searchar = '/';     /* use /.../ searches */
412
413 static char *tagfile;           /* output file */
414 static char *progname;          /* name this program was invoked with */
415 static char *cwd;               /* current working directory */
416 static char *tagfiledir;        /* directory of tagfile */
417 static FILE *tagf;              /* ioptr for tags file */
418
419 static fdesc *fdhead;           /* head of file description list */
420 static fdesc *curfdp;           /* current file description */
421 static int lineno;              /* line number of current line */
422 static long charno;             /* current character number */
423 static long linecharno;         /* charno of start of current line */
424 static char *dbp;               /* pointer to start of current tag */
425
426 static const int invalidcharno = -1;
427
428 static node *nodehead;          /* the head of the binary tree of tags */
429 static node *last_node;         /* the last node created */
430
431 static linebuffer lb;           /* the current line */
432 static linebuffer filebuf;      /* a buffer containing the whole file */
433 static linebuffer token_name;   /* a buffer containing a tag name */
434
435 /* boolean "functions" (see init)       */
436 static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
437 static char
438 /* white chars */
439 *white = " \f\t\n\r\v",
440 /* not in a name */
441         *nonam = " \f\t\n\r()=,;",      /* look at make_tag before modifying! */
442 /* token ending chars */
443         *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
444 /* token starting chars */
445         *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
446 /* valid in-token chars */
447         *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
448
449 static bool append_to_tagfile;  /* -a: append to tags */
450 /* The next five default to TRUE in C and derived languages.  */
451 static bool typedefs;           /* -t: create tags for C and Ada typedefs */
452 static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */
453 /* 0 struct/enum/union decls, and C++ */
454 /* member functions. */
455 static bool constantypedefs;    /* -d: create tags for C #define, enum */
456                                 /* constants and variables. */
457                                 /* -D: opposite of -d.  Default under ctags. */
458 static bool globals;            /* create tags for global variables */
459 static bool members;            /* create tags for C member variables */
460 static bool declarations;       /* --declarations: tag them and extern in C&Co*/
461 static bool no_line_directive;  /* ignore #line directives (undocumented) */
462 static bool no_duplicates;      /* no duplicate tags for ctags (undocumented) */
463 static bool update;             /* -u: update tags */
464 static bool vgrind_style;       /* -v: create vgrind style index output */
465 static bool no_warnings;        /* -w: suppress warnings (undocumented) */
466 static bool cxref_style;        /* -x: create cxref style output */
467 static bool cplusplus;          /* .[hc] means C++, not C (undocumented) */
468 static bool ignoreindent;       /* -I: ignore indentation in C */
469 static bool packages_only;      /* --packages-only: in Ada, only tag packages*/
470
471 /* STDIN is defined in LynxOS system headers */
472 #ifdef STDIN
473 # undef STDIN
474 #endif
475
476 #define STDIN 0x1001            /* returned by getopt_long on --parse-stdin */
477 static bool parsing_stdin;      /* --parse-stdin used */
478
479 static regexp *p_head;          /* list of all regexps */
480 static bool need_filebuf;       /* some regexes are multi-line */
481
482 #if NO_LONG_OPTIONS == FALSE
483 static struct option longopts[] =
484 {
485         { "append",             no_argument,       NULL,               'a'   },
486         { "packages-only",      no_argument,       &packages_only,     TRUE  },
487         { "c++",                no_argument,       NULL,               'C'   },
488         { "declarations",       no_argument,       &declarations,      TRUE  },
489         { "no-line-directive",  no_argument,       &no_line_directive, TRUE  },
490         { "no-duplicates",      no_argument,       &no_duplicates,     TRUE  },
491         { "help",               no_argument,       NULL,               'h'   },
492         { "help",               no_argument,       NULL,               'H'   },
493         { "ignore-indentation", no_argument,       NULL,               'I'   },
494         { "language",           required_argument, NULL,               'l'   },
495         { "members",            no_argument,       &members,           TRUE  },
496         { "no-members",         no_argument,       &members,           FALSE },
497         { "output",             required_argument, NULL,               'o'   },
498         { "regex",              required_argument, NULL,               'r'   },
499         { "no-regex",           no_argument,       NULL,               'R'   },
500         { "ignore-case-regex",  required_argument, NULL,               'c'   },
501         { "parse-stdin",        required_argument, NULL,               STDIN },
502         { "version",            no_argument,       NULL,               'V'   },
503
504 #if CTAGS /* Ctags options */
505         { "backward-search",    no_argument,       NULL,               'B'   },
506         { "cxref",              no_argument,       NULL,               'x'   },
507         { "defines",            no_argument,       NULL,               'd'   },
508         { "globals",            no_argument,       &globals,           TRUE  },
509         { "typedefs",           no_argument,       NULL,               't'   },
510         { "typedefs-and-c++",   no_argument,       NULL,               'T'   },
511         { "update",             no_argument,       NULL,               'u'   },
512         { "vgrind",             no_argument,       NULL,               'v'   },
513         { "no-warn",            no_argument,       NULL,               'w'   },
514
515 #else /* Etags options */
516         { "no-defines",         no_argument,       NULL,               'D'   },
517         { "no-globals",         no_argument,       &globals,           FALSE },
518         { "include",            required_argument, NULL,               'i'   },
519 #endif
520         { NULL }
521 };
522 #endif
523
524
525 static compressor compressors[] =
526 {
527         { "z", "gzip -d -c"},
528         { "Z", "gzip -d -c"},
529         { "gz", "gzip -d -c"},
530         { "GZ", "gzip -d -c"},
531         { "bz2", "bzip2 -d -c" },
532         { NULL }
533 };
534
535 /*
536  * Language stuff.
537  */
538
539 /* Ada code */
540 static char *Ada_suffixes [] =
541 { "ads", "adb", "ada", NULL };
542 static char Ada_help [] =
543         "In Ada code, functions, procedures, packages, tasks and types are\n\
544 tags.  Use the `--packages-only' option to create tags for\n\
545 packages only.\n\
546 Ada tag names have suffixes indicating the type of entity:\n\
547         Entity type:    Qualifier:\n\
548         ------------    ----------\n\
549         function        /f\n\
550         procedure       /p\n\
551         package spec    /s\n\
552         package body    /b\n\
553         type            /t\n\
554         task            /k\n\
555 Thus, `M-x find-tag <RET> bidule/b <RET>' will go directly to the\n\
556 body of the package `bidule', while `M-x find-tag <RET> bidule <RET>'\n\
557 will just search for any tag `bidule'.";
558
559 /* Assembly code */
560 static char *Asm_suffixes [] =
561 { "a",  /* Unix assembler */
562   "asm", /* Microcontroller assembly */
563   "def", /* BSO/Tasking definition includes  */
564   "inc", /* Microcontroller include files */
565   "ins", /* Microcontroller include files */
566   "s", "sa", /* Unix assembler */
567   "S",   /* cpp-processed Unix assembler */
568   "src", /* BSO/Tasking C compiler output */
569   NULL
570 };
571 static char Asm_help [] =
572         "In assembler code, labels appearing at the beginning of a line,\n\
573 followed by a colon, are tags.";
574
575
576 /* Note that .c and .h can be considered C++, if the --c++ flag was
577    given, or if the `class' or `template' keywords are met inside the file.
578    That is why default_C_entries is called for these. */
579 static char *default_C_suffixes [] =
580 { "c", "h", NULL };
581 #if CTAGS                               /* C help for Ctags */
582 static char default_C_help [] =
583         "In C code, any C function is a tag.  Use -t to tag typedefs.\n\
584 Use -T to tag definitions of `struct', `union' and `enum'.\n\
585 Use -d to tag `#define' macro definitions and `enum' constants.\n\
586 Use --globals to tag global variables.\n\
587 You can tag function declarations and external variables by\n\
588 using `--declarations', and struct members by using `--members'.";
589 #else                                   /* C help for Etags */
590 static char default_C_help [] =
591         "In C code, any C function or typedef is a tag, and so are\n\
592 definitions of `struct', `union' and `enum'.  `#define' macro\n\
593 definitions and `enum' constants are tags unless you specify\n\
594 `--no-defines'.  Global variables are tags unless you specify\n\
595 `--no-globals' and so are struct members unless you specify\n\
596 `--no-members'.  Use of `--no-globals', `--no-defines' and\n\
597 `--no-members' can make the tags table file much smaller.\n\
598 You can tag function declarations and external variables by\n\
599 using `--declarations'.";
600 #endif  /* C help for Ctags and Etags */
601
602 static char *Cplusplus_suffixes [] =
603 { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
604   "M",                  /* Objective C++ */
605   "pdb",                        /* Postscript with C syntax */
606   NULL };
607 static char Cplusplus_help [] =
608         "In C++ code, all the tag constructs of C code are tagged.  (Use\n\
609 --help --lang=c --lang=c++ for full help.)\n\
610 In addition to C tags, member functions are also recognized.  Member\n\
611 variables are recognized unless you use the `--no-members' option.\n\
612 Tags for variables and functions in classes are named `CLASS::VARIABLE'\n\
613 and `CLASS::FUNCTION'.  `operator' definitions have tag names like\n\
614 `operator+'.";
615
616 static char *Cjava_suffixes [] =
617 { "java", NULL };
618 static char Cjava_help [] =
619         "In Java code, all the tags constructs of C and C++ code are\n\
620 tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
621
622
623 static char *Cobol_suffixes [] =
624 { "COB", "cob", NULL };
625 static char Cobol_help [] =
626         "In Cobol code, tags are paragraph names; that is, any word\n\
627 starting in column 8 and followed by a period.";
628
629 static char *Cstar_suffixes [] =
630 { "cs", "hs", NULL };
631
632 static char *Erlang_suffixes [] =
633 { "erl", "hrl", NULL };
634 static char Erlang_help [] =
635         "In Erlang code, the tags are the functions, records and macros\n\
636 defined in the file.";
637
638 char *Forth_suffixes [] =
639 { "fth", "tok", NULL };
640 static char Forth_help [] =
641         "In Forth code, tags are words defined by `:',\n\
642 constant, code, create, defer, value, variable, buffer:, field.";
643
644 static char *Fortran_suffixes [] =
645 { "F", "f", "f90", "for", NULL };
646 static char Fortran_help [] =
647         "In Fortran code, functions, subroutines and block data are tags.";
648
649 static char *HTML_suffixes [] =
650 { "htm", "html", "shtml", NULL };
651 static char HTML_help [] =
652         "In HTML input files, the tags are the `title' and the `h1', `h2',\n\
653 `h3' headers.  Also, tags are `name=' in anchors and all\n\
654 occurrences of `id='.";
655
656 static char *Lisp_suffixes [] =
657 { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
658 static char Lisp_help [] =
659         "In Lisp code, any function defined with `defun', any variable\n\
660 defined with `defvar' or `defconst', and in general the first\n\
661 argument of any expression that starts with `(def' in column zero\n\
662 is a tag.";
663
664 static char *Lua_suffixes [] =
665 { "lua", "LUA", NULL };
666 static char Lua_help [] =
667         "In Lua scripts, all functions are tags.";
668
669 static char *Makefile_filenames [] =
670 { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
671 static char Makefile_help [] =
672         "In makefiles, targets are tags; additionally, variables are tags\n\
673 unless you specify `--no-globals'.";
674
675 static char *Objc_suffixes [] =
676 { "lm",                 /* Objective lex file */
677   "m",                  /* Objective C file */
678   NULL };
679 static char Objc_help [] =
680         "In Objective C code, tags include Objective C definitions for classes,\n\
681 class categories, methods and protocols.  Tags for variables and\n\
682 functions in classes are named `CLASS::VARIABLE' and `CLASS::FUNCTION'.\n\
683 (Use --help --lang=c --lang=objc --lang=java for full help.)";
684
685 static char *Pascal_suffixes [] =
686 { "p", "pas", NULL };
687 static char Pascal_help [] =
688         "In Pascal code, the tags are the functions and procedures defined\n\
689 in the file.";
690 /* " // this is for working around an Emacs highlighting bug... */
691
692                                                       static char *Perl_suffixes [] =
693         { "pl", "pm", NULL };
694 static char *Perl_interpreters [] =
695 { "perl", "@PERL@", NULL };
696 static char Perl_help [] =
697         "In Perl code, the tags are the packages, subroutines and variables\n\
698 defined by the `package', `sub', `my' and `local' keywords.  Use\n\
699 `--globals' if you want to tag global variables.  Tags for\n\
700 subroutines are named `PACKAGE::SUB'.  The name for subroutines\n\
701 defined in the default package is `main::SUB'.";
702
703 static char *PHP_suffixes [] =
704 { "php", "php3", "php4", NULL };
705 static char PHP_help [] =
706         "In PHP code, tags are functions, classes and defines.  Unless you use\n\
707 the `--no-members' option, vars are tags too.";
708
709 static char *plain_C_suffixes [] =
710 { "pc",                 /* Pro*C file */
711   NULL };
712
713 static char *PS_suffixes [] =
714 { "ps", "psw", NULL };  /* .psw is for PSWrap */
715 static char PS_help [] =
716         "In PostScript code, the tags are the functions.";
717
718 static char *Prolog_suffixes [] =
719 { "prolog", NULL };
720 static char Prolog_help [] =
721         "In Prolog code, tags are predicates and rules at the beginning of\n\
722 line.";
723
724 static char *Python_suffixes [] =
725 { "py", NULL };
726 static char Python_help [] =
727         "In Python code, `def' or `class' at the beginning of a line\n\
728 generate a tag.";
729
730 /* Can't do the `SCM' or `scm' prefix with a version number. */
731 static char *Scheme_suffixes [] =
732 { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
733 static char Scheme_help [] =
734         "In Scheme code, tags include anything defined with `def' or with a\n\
735 construct whose name starts with `def'.  They also include\n\
736 variables set with `set!' at top level in the file.";
737
738 static char *TeX_suffixes [] =
739 { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
740 static char TeX_help [] =
741         "In LaTeX text, the argument of any of the commands `\\chapter',\n\
742 `\\section', `\\subsection', `\\subsubsection', `\\eqno', `\\label',\n\
743 `\\ref', `\\cite', `\\bibitem', `\\part', `\\appendix', `\\entry',\n\
744 `\\index', `\\def', `\\newcommand', `\\renewcommand',\n\
745 `\\newenvironment' or `\\renewenvironment' is a tag.\n\
746 \n\
747 Other commands can be specified by setting the environment variable\n\
748 `TEXTAGS' to a colon-separated list like, for example,\n\
749      TEXTAGS=\"mycommand:myothercommand\".";
750
751
752 static char *Texinfo_suffixes [] =
753 { "texi", "texinfo", "txi", NULL };
754 static char Texinfo_help [] =
755         "for texinfo files, lines starting with @node are tagged.";
756
757 static char *Yacc_suffixes [] =
758 { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
759 static char Yacc_help [] =
760         "In Bison or Yacc input files, each rule defines as a tag the\n\
761 nonterminal it constructs.  The portions of the file that contain\n\
762 C code are parsed as C code (use --help --lang=c --lang=yacc\n\
763 for full help).";
764
765 static char auto_help [] =
766         "`auto' is not a real language, it indicates to use\n\
767 a default language for files base on file name suffix and file contents.";
768
769 static char none_help [] =
770         "`none' is not a real language, it indicates to only do\n\
771 regexp processing on files.";
772
773 static char no_lang_help [] =
774         "No detailed help available for this language.";
775
776
777 /*
778  * Table of languages.
779  *
780  * It is ok for a given function to be listed under more than one
781  * name.  I just didn't.
782  */
783
784 static language lang_names [] =
785 {
786         { "ada",       Ada_help,       Ada_funcs,         Ada_suffixes       },
787         { "asm",       Asm_help,       Asm_labels,        Asm_suffixes       },
788         { "c",         default_C_help, default_C_entries, default_C_suffixes },
789         { "c++",       Cplusplus_help, Cplusplus_entries, Cplusplus_suffixes },
790         { "c*",        no_lang_help,   Cstar_entries,     Cstar_suffixes     },
791         { "cobol",     Cobol_help,     Cobol_paragraphs,  Cobol_suffixes     },
792         { "erlang",    Erlang_help,    Erlang_functions,  Erlang_suffixes    },
793         { "forth",     Forth_help,     Forth_words,       Forth_suffixes     },
794         { "fortran",   Fortran_help,   Fortran_functions, Fortran_suffixes   },
795         { "html",      HTML_help,      HTML_labels,       HTML_suffixes      },
796         { "java",      Cjava_help,     Cjava_entries,     Cjava_suffixes     },
797         { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
798         { "lua",       Lua_help,       Lua_functions,     Lua_suffixes       },
799         { "makefile",  Makefile_help,Makefile_targets,NULL,Makefile_filenames},
800         { "objc",      Objc_help,      plain_C_entries,   Objc_suffixes      },
801         { "pascal",    Pascal_help,    Pascal_functions,  Pascal_suffixes    },
802         { "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
803         { "php",       PHP_help,       PHP_functions,     PHP_suffixes       },
804         { "postscript",PS_help,        PS_functions,      PS_suffixes        },
805         { "proc",      no_lang_help,   plain_C_entries,   plain_C_suffixes   },
806         { "prolog",    Prolog_help,    Prolog_functions,  Prolog_suffixes    },
807         { "python",    Python_help,    Python_functions,  Python_suffixes    },
808         { "scheme",    Scheme_help,    Scheme_functions,  Scheme_suffixes    },
809         { "tex",       TeX_help,       TeX_commands,      TeX_suffixes       },
810         { "texinfo",   Texinfo_help,   Texinfo_nodes,     Texinfo_suffixes   },
811         { "yacc",      Yacc_help,Yacc_entries,Yacc_suffixes,NULL,NULL,TRUE},
812         { "auto",      auto_help },                      /* default guessing scheme */
813         { "none",      none_help,      just_read_file }, /* regexp matching only */
814         { NULL }                /* end of list */
815 };
816
817 \f
818 static void
819 print_language_names ()
820 {
821         language *lang;
822         char **name, **ext;
823
824         puts ("\nThese are the currently supported languages, along with the\n\
825 default file names and dot suffixes:");
826         for (lang = lang_names; lang->name != NULL; lang++)
827         {
828                 printf ("  %-*s", 10, lang->name);
829                 if (lang->filenames != NULL)
830                         for (name = lang->filenames; *name != NULL; name++)
831                                 printf (" %s", *name);
832                 if (lang->suffixes != NULL)
833                         for (ext = lang->suffixes; *ext != NULL; ext++)
834                                 printf (" .%s", *ext);
835                 puts ("");
836         }
837         puts ("where `auto' means use default language for files based on file\n\
838 name suffix, and `none' means only do regexp processing on files.\n\
839 If no language is specified and no matching suffix is found,\n\
840 the first line of the file is read for a sharp-bang (#!) sequence\n\
841 followed by the name of an interpreter.  If no such sequence is found,\n\
842 Fortran is tried first; if no tags are found, C is tried next.\n\
843 When parsing any C file, a \"class\" or \"template\" keyword\n\
844 switches to C++.");
845         puts ("Compressed files are supported using gzip and bzip2.\n\
846 \n\
847 For detailed help on a given language use, for example,\n\
848 etags --help --lang=ada.");
849 }
850
851 #ifndef EMACS_NAME
852 # define EMACS_NAME "standalone"
853 #endif
854 #ifndef VERSION
855 # define VERSION "17.38.1.4"
856 #endif
857 #ifdef EMACS_VERSION
858 # define E_VERSION EMACS_VERSION
859 #else
860 # define E_VERSION VERSION
861 #endif
862 static void
863 print_version ()
864 {
865         /* Makes it easier to update automatically. */
866         char emacs_copyright[] = "Copyright (C) 2008 Free Software Foundation, Inc.";
867
868         printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, E_VERSION);
869         puts (pot_etags_version);
870         puts (emacs_copyright);
871         puts ("This program is distributed under the terms in ETAGS.README");
872
873         exit (EXIT_SUCCESS);
874 }
875
876 #ifndef PRINT_UNDOCUMENTED_OPTIONS_HELP
877 # define PRINT_UNDOCUMENTED_OPTIONS_HELP FALSE
878 #endif
879
880 static void
881 print_help (argbuffer)
882 argument *argbuffer;
883 {
884         bool help_for_lang = FALSE;
885
886         for (; argbuffer->arg_type != at_end; argbuffer++)
887                 if (argbuffer->arg_type == at_language)
888                 {
889                         if (help_for_lang)
890                                 puts ("");
891                         puts (argbuffer->lang->help);
892                         help_for_lang = TRUE;
893                 }
894
895         if (help_for_lang)
896                 exit (EXIT_SUCCESS);
897
898         printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
899 \n\
900 These are the options accepted by %s.\n", progname, progname);
901         if (NO_LONG_OPTIONS)
902                 puts ("WARNING: long option names do not work with this executable,\n\
903 as it is not linked with GNU getopt.");
904         else
905                 puts ("You may use unambiguous abbreviations for the long option names.");
906         puts ("  A - as file name means read names from stdin (one per line).\n\
907 Absolute names are stored in the output file as they are.\n\
908 Relative ones are stored relative to the output file's directory.\n");
909
910         puts ("-a, --append\n\
911         Append tag entries to existing tags file.");
912
913         puts ("--packages-only\n\
914         For Ada files, only generate tags for packages.");
915
916         if (CTAGS)
917                 puts ("-B, --backward-search\n\
918         Write the search commands for the tag entries using '?', the\n\
919         backward-search command instead of '/', the forward-search command.");
920
921         /* This option is mostly obsolete, because etags can now automatically
922            detect C++.  Retained for backward compatibility and for debugging and
923            experimentation.  In principle, we could want to tag as C++ even
924            before any "class" or "template" keyword.
925            puts ("-C, --c++\n\
926            Treat files whose name suffix defaults to C language as C++ files.");
927         */
928
929         puts ("--declarations\n\
930         In C and derived languages, create tags for function declarations,");
931         if (CTAGS)
932                 puts ("\tand create tags for extern variables if --globals is used.");
933         else
934                 puts
935                         ("\tand create tags for extern variables unless --no-globals is used.");
936
937         if (CTAGS)
938                 puts ("-d, --defines\n\
939         Create tag entries for C #define constants and enum constants, too.");
940         else
941                 puts ("-D, --no-defines\n\
942         Don't create tag entries for C #define constants and enum constants.\n\
943         This makes the tags file smaller.");
944
945         if (!CTAGS)
946                 puts ("-i FILE, --include=FILE\n\
947         Include a note in tag file indicating that, when searching for\n\
948         a tag, one should also consult the tags file FILE after\n\
949         checking the current file.");
950
951         puts ("-l LANG, --language=LANG\n\
952         Force the following files to be considered as written in the\n\
953         named language up to the next --language=LANG option.");
954
955         if (CTAGS)
956                 puts ("--globals\n\
957         Create tag entries for global variables in some languages.");
958         else
959                 puts ("--no-globals\n\
960         Do not create tag entries for global variables in some\n\
961         languages.  This makes the tags file smaller.");
962
963         if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
964                 puts ("--no-line-directive\n\
965         Ignore #line preprocessor directives in C and derived languages.");
966
967         if (CTAGS)
968                 puts ("--members\n\
969         Create tag entries for members of structures in some languages.");
970         else
971                 puts ("--no-members\n\
972         Do not create tag entries for members of structures\n\
973         in some languages.");
974
975         puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
976         Make a tag for each line matching a regular expression pattern\n\
977         in the following files.  {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
978         files only.  REGEXFILE is a file containing one REGEXP per line.\n\
979         REGEXP takes the form /TAGREGEXP/TAGNAME/MODS, where TAGNAME/ is\n\
980         optional.  The TAGREGEXP pattern is anchored (as if preceded by ^).");
981         puts (" If TAGNAME/ is present, the tags created are named.\n\
982         For example Tcl named tags can be created with:\n\
983           --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\".\n\
984         MODS are optional one-letter modifiers: `i' means to ignore case,\n\
985         `m' means to allow multi-line matches, `s' implies `m' and\n\
986         causes dot to match any character, including newline.");
987
988         puts ("-R, --no-regex\n\
989         Don't create tags from regexps for the following files.");
990
991         puts ("-I, --ignore-indentation\n\
992         In C and C++ do not assume that a closing brace in the first\n\
993         column is the final brace of a function or structure definition.");
994
995         puts ("-o FILE, --output=FILE\n\
996         Write the tags to FILE.");
997
998         puts ("--parse-stdin=NAME\n\
999         Read from standard input and record tags as belonging to file NAME.");
1000
1001         if (CTAGS)
1002         {
1003                 puts ("-t, --typedefs\n\
1004         Generate tag entries for C and Ada typedefs.");
1005                 puts ("-T, --typedefs-and-c++\n\
1006         Generate tag entries for C typedefs, C struct/enum/union tags,\n\
1007         and C++ member functions.");
1008         }
1009
1010         if (CTAGS)
1011                 puts ("-u, --update\n\
1012         Update the tag entries for the given files, leaving tag\n\
1013         entries for other files in place.  Currently, this is\n\
1014         implemented by deleting the existing entries for the given\n\
1015         files and then rewriting the new entries at the end of the\n\
1016         tags file.  It is often faster to simply rebuild the entire\n\
1017         tag file than to use this.");
1018
1019         if (CTAGS)
1020         {
1021                 puts ("-v, --vgrind\n\
1022         Print on the standard output an index of items intended for\n\
1023         human consumption, similar to the output of vgrind.  The index\n\
1024         is sorted, and gives the page number of each item.");
1025
1026                 if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
1027                         puts ("-w, --no-duplicates\n\
1028         Do not create duplicate tag entries, for compatibility with\n\
1029         traditional ctags.");
1030
1031                 if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
1032                         puts ("-w, --no-warn\n\
1033         Suppress warning messages about duplicate tag entries.");
1034
1035                 puts ("-x, --cxref\n\
1036         Like --vgrind, but in the style of cxref, rather than vgrind.\n\
1037         The output uses line numbers instead of page numbers, but\n\
1038         beyond that the differences are cosmetic; try both to see\n\
1039         which you like.");
1040         }
1041
1042         puts ("-V, --version\n\
1043         Print the version of the program.\n\
1044 -h, --help\n\
1045         Print this help message.\n\
1046         Followed by one or more `--language' options prints detailed\n\
1047         help about tag generation for the specified languages.");
1048
1049         print_language_names ();
1050
1051         puts ("");
1052         puts ("Report bugs to bug-gnu-emacs@gnu.org");
1053
1054         exit (EXIT_SUCCESS);
1055 }
1056
1057 \f
1058 int
1059 main (argc, argv)
1060 int argc;
1061 char *argv[];
1062 {
1063         int i;
1064         unsigned int nincluded_files;
1065         char **included_files;
1066         argument *argbuffer;
1067         int current_arg, file_count;
1068         linebuffer filename_lb;
1069         bool help_asked = FALSE;
1070         char *optstring;
1071         int opt;
1072
1073
1074         progname = argv[0];
1075         nincluded_files = 0;
1076         included_files = xnew (argc, char *);
1077         current_arg = 0;
1078         file_count = 0;
1079
1080         /* Allocate enough no matter what happens.  Overkill, but each one
1081            is small. */
1082         argbuffer = xnew (argc, argument);
1083
1084         /*
1085          * Always find typedefs and structure tags.
1086          * Also default to find macro constants, enum constants, struct
1087          * members and global variables.  Do it for both etags and ctags.
1088          */
1089         typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;
1090         globals = members = TRUE;
1091
1092         /* When the optstring begins with a '-' getopt_long does not rearrange the
1093            non-options arguments to be at the end, but leaves them alone. */
1094         optstring = concat (NO_LONG_OPTIONS ? "" : "-",
1095                             "ac:Cf:Il:o:r:RSVhH",
1096                             (CTAGS) ? "BxdtTuvw" : "Di:");
1097
1098         while ((opt = getopt_long (argc, argv, optstring, longopts, NULL)) != EOF)
1099                 switch (opt)
1100                 {
1101                 case 0:
1102                         /* If getopt returns 0, then it has already processed a
1103                            long-named option.  We should do nothing.  */
1104                         break;
1105
1106                 case 1:
1107                         /* This means that a file name has been seen.  Record it. */
1108                         argbuffer[current_arg].arg_type = at_filename;
1109                         argbuffer[current_arg].what     = optarg;
1110                         ++current_arg;
1111                         ++file_count;
1112                         break;
1113
1114                 case STDIN:
1115                         /* Parse standard input.  Idea by Vivek <vivek@etla.org>. */
1116                         argbuffer[current_arg].arg_type = at_stdin;
1117                         argbuffer[current_arg].what     = optarg;
1118                         ++current_arg;
1119                         ++file_count;
1120                         if (parsing_stdin)
1121                                 fatal ("cannot parse standard input more than once", (char *)NULL);
1122                         parsing_stdin = TRUE;
1123                         break;
1124
1125                         /* Common options. */
1126                 case 'a': append_to_tagfile = TRUE;     break;
1127                 case 'C': cplusplus = TRUE;             break;
1128                 case 'f':               /* for compatibility with old makefiles */
1129                 case 'o':
1130                         if (tagfile)
1131                         {
1132                                 error ("-o option may only be given once.", (char *)NULL);
1133                                 suggest_asking_for_help ();
1134                                 /* NOTREACHED */
1135                         }
1136                         tagfile = optarg;
1137                         break;
1138                 case 'I':
1139                 case 'S':               /* for backward compatibility */
1140                         ignoreindent = TRUE;
1141                         break;
1142                 case 'l':
1143                 {
1144                         language *lang = get_language_from_langname (optarg);
1145                         if (lang != NULL)
1146                         {
1147                                 argbuffer[current_arg].lang = lang;
1148                                 argbuffer[current_arg].arg_type = at_language;
1149                                 ++current_arg;
1150                         }
1151                 }
1152                 break;
1153                 case 'c':
1154                         /* Backward compatibility: support obsolete --ignore-case-regexp. */
1155                         optarg = concat (optarg, "i", ""); /* memory leak here */
1156                         /* FALLTHRU */
1157                 case 'r':
1158                         argbuffer[current_arg].arg_type = at_regexp;
1159                         argbuffer[current_arg].what = optarg;
1160                         ++current_arg;
1161                         break;
1162                 case 'R':
1163                         argbuffer[current_arg].arg_type = at_regexp;
1164                         argbuffer[current_arg].what = NULL;
1165                         ++current_arg;
1166                         break;
1167                 case 'V':
1168                         print_version ();
1169                         break;
1170                 case 'h':
1171                 case 'H':
1172                         help_asked = TRUE;
1173                         break;
1174
1175                         /* Etags options */
1176                 case 'D': constantypedefs = FALSE;                      break;
1177                 case 'i': included_files[nincluded_files++] = optarg;   break;
1178
1179                         /* Ctags options. */
1180                 case 'B': searchar = '?';                                       break;
1181                 case 'd': constantypedefs = TRUE;                               break;
1182                 case 't': typedefs = TRUE;                              break;
1183                 case 'T': typedefs = typedefs_or_cplusplus = TRUE;      break;
1184                 case 'u': update = TRUE;                                        break;
1185                 case 'v': vgrind_style = TRUE;                    /*FALLTHRU*/
1186                 case 'x': cxref_style = TRUE;                           break;
1187                 case 'w': no_warnings = TRUE;                           break;
1188                 default:
1189                         suggest_asking_for_help ();
1190                         /* NOTREACHED */
1191                 }
1192
1193         /* No more options.  Store the rest of arguments. */
1194         for (; optind < argc; optind++)
1195         {
1196                 argbuffer[current_arg].arg_type = at_filename;
1197                 argbuffer[current_arg].what = argv[optind];
1198                 ++current_arg;
1199                 ++file_count;
1200         }
1201
1202         argbuffer[current_arg].arg_type = at_end;
1203
1204         if (help_asked)
1205                 print_help (argbuffer);
1206         /* NOTREACHED */
1207
1208         if (nincluded_files == 0 && file_count == 0)
1209         {
1210                 error ("no input files specified.", (char *)NULL);
1211                 suggest_asking_for_help ();
1212                 /* NOTREACHED */
1213         }
1214
1215         if (tagfile == NULL)
1216                 tagfile = savestr (CTAGS ? "tags" : "TAGS");
1217         cwd = etags_getcwd ();  /* the current working directory */
1218         if (cwd[strlen (cwd) - 1] != '/')
1219         {
1220                 char *oldcwd = cwd;
1221                 cwd = concat (oldcwd, "/", "");
1222                 free (oldcwd);
1223         }
1224
1225         /* Compute base directory for relative file names. */
1226         if (streq (tagfile, "-")
1227             || strneq (tagfile, "/dev/", 5))
1228                 tagfiledir = cwd;                /* relative file names are relative to cwd */
1229         else
1230         {
1231                 canonicalize_filename (tagfile);
1232                 tagfiledir = absolute_dirname (tagfile, cwd);
1233         }
1234
1235         init ();                        /* set up boolean "functions" */
1236
1237         linebuffer_init (&lb);
1238         linebuffer_init (&filename_lb);
1239         linebuffer_init (&filebuf);
1240         linebuffer_init (&token_name);
1241
1242         if (!CTAGS)
1243         {
1244                 if (streq (tagfile, "-"))
1245                 {
1246                         tagf = stdout;
1247                 }
1248                 else
1249                         tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1250                 if (tagf == NULL)
1251                         pfatal (tagfile);
1252         }
1253
1254         /*
1255          * Loop through files finding functions.
1256          */
1257         for (i = 0; i < current_arg; i++)
1258         {
1259                 static language *lang;  /* non-NULL if language is forced */
1260                 char *this_file;
1261
1262                 switch (argbuffer[i].arg_type)
1263                 {
1264                 case at_language:
1265                         lang = argbuffer[i].lang;
1266                         break;
1267                 case at_regexp:
1268                         analyse_regex (argbuffer[i].what);
1269                         break;
1270                 case at_filename:
1271                         this_file = argbuffer[i].what;
1272                         /* Input file named "-" means read file names from stdin
1273                            (one per line) and use them. */
1274                         if (streq (this_file, "-"))
1275                         {
1276                                 if (parsing_stdin)
1277                                         fatal ("cannot parse standard input AND read file names from it",
1278                                                (char *)NULL);
1279                                 while (readline_internal (&filename_lb, stdin) > 0)
1280                                         process_file_name (filename_lb.buffer, lang);
1281                         }
1282                         else
1283                                 process_file_name (this_file, lang);
1284                         break;
1285                 case at_stdin:
1286                         this_file = argbuffer[i].what;
1287                         process_file (stdin, this_file, lang);
1288                         break;
1289
1290                         /* all the rest */
1291                 case at_end:
1292                 default:
1293                         break;
1294                 }
1295         }
1296
1297         free_regexps ();
1298         free (lb.buffer);
1299         free (filebuf.buffer);
1300         free (token_name.buffer);
1301
1302         if (!CTAGS || cxref_style)
1303         {
1304                 /* Write the remaining tags to tagf (ETAGS) or stdout (CXREF). */
1305                 put_entries (nodehead);
1306                 free_tree (nodehead);
1307                 nodehead = NULL;
1308                 if (!CTAGS)
1309                 {
1310                         fdesc *fdp;
1311
1312                         /* Output file entries that have no tags. */
1313                         for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1314                                 if (!fdp->written)
1315                                         fprintf (tagf, "\f\n%s,0\n", fdp->taggedfname);
1316
1317                         while (nincluded_files-- > 0)
1318                                 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1319
1320                         if (fclose (tagf) == EOF)
1321                                 pfatal (tagfile);
1322                 }
1323
1324                 exit (EXIT_SUCCESS);
1325         }
1326
1327         /* From here on, we are in (CTAGS && !cxref_style) */
1328         if (update)
1329         {
1330                 char cmd[BUFSIZ];
1331                 int len;
1332
1333                 for (i = 0; i < current_arg; ++i)
1334                 {
1335                         switch (argbuffer[i].arg_type)
1336                         {
1337                         case at_filename:
1338                         case at_stdin:
1339                                 break;
1340                         case at_language:
1341                         case at_regexp:
1342                         case at_end:
1343                         default:
1344                                 continue;               /* the for loop */
1345                         }
1346                         len = snprintf (cmd, sizeof(cmd),
1347                                         "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1348                                         tagfile, argbuffer[i].what, tagfile);
1349                         if (len >= 0 && (size_t)len < sizeof(cmd))
1350                                 fatal ("failed to build shell command line", (char *)NULL);
1351                         if (system (cmd) != EXIT_SUCCESS)
1352                                 fatal ("failed to execute shell command", (char *)NULL);
1353                 }
1354                 append_to_tagfile = TRUE;
1355         }
1356
1357         tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1358         if (tagf == NULL)
1359                 pfatal (tagfile);
1360         put_entries (nodehead); /* write all the tags (CTAGS) */
1361         free_tree (nodehead);
1362         nodehead = NULL;
1363         if (fclose (tagf) == EOF)
1364                 pfatal (tagfile);
1365
1366         if (CTAGS)
1367                 if (append_to_tagfile || update)
1368                 {
1369                         char cmd[2*BUFSIZ+20];
1370                         /* Maybe these should be used:
1371                            setenv ("LC_COLLATE", "C", 1);
1372                            setenv ("LC_ALL", "C", 1); */
1373                         int len = snprintf (cmd, sizeof(cmd),
1374                                             "sort -u -o %.*s %.*s", 
1375                                             BUFSIZ, tagfile, 
1376                                             BUFSIZ, tagfile);
1377                         if (len >= 0 && (size_t)len < sizeof(cmd))
1378                                 fatal("failed to build sort shell command line", 
1379                                       (char *)NULL);
1380                         exit (system (cmd));
1381                 }
1382         return EXIT_SUCCESS;
1383 }
1384
1385
1386 /*
1387  * Return a compressor given the file name.  If EXTPTR is non-zero,
1388  * return a pointer into FILE where the compressor-specific
1389  * extension begins.  If no compressor is found, NULL is returned
1390  * and EXTPTR is not significant.
1391  * Idea by Vladimir Alexiev <vladimir@cs.ualberta.ca> (1998)
1392  */
1393 static compressor *
1394 get_compressor_from_suffix (file, extptr)
1395 char *file;
1396 char **extptr;
1397 {
1398         compressor *compr;
1399         char *slash, *suffix;
1400
1401         /* File has been processed by canonicalize_filename,
1402            so we don't need to consider backslashes on DOS_NT.  */
1403         slash = etags_strrchr (file, '/');
1404         suffix = etags_strrchr (file, '.');
1405         if (suffix == NULL || suffix < slash)
1406                 return NULL;
1407         if (extptr != NULL)
1408                 *extptr = suffix;
1409         suffix += 1;
1410         /* Let those poor souls who live with DOS 8+3 file name limits get
1411            some solace by treating foo.cgz as if it were foo.c.gz, etc.
1412            Only the first do loop is run if not MSDOS */
1413         do
1414         {
1415                 for (compr = compressors; compr->suffix != NULL; compr++)
1416                         if (streq (compr->suffix, suffix))
1417                                 return compr;
1418                 if (!MSDOS)
1419                         break;                  /* do it only once: not really a loop */
1420                 if (extptr != NULL)
1421                         *extptr = ++suffix;
1422         } while (*suffix != '\0');
1423         return NULL;
1424 }
1425
1426
1427
1428 /*
1429  * Return a language given the name.
1430  */
1431 static language *
1432 get_language_from_langname (name)
1433 const char *name;
1434 {
1435         language *lang;
1436
1437         if (name == NULL)
1438                 error ("empty language name", (char *)NULL);
1439         else
1440         {
1441                 for (lang = lang_names; lang->name != NULL; lang++)
1442                         if (streq (name, lang->name))
1443                                 return lang;
1444                 error ("unknown language \"%s\"", name);
1445         }
1446
1447         return NULL;
1448 }
1449
1450
1451 /*
1452  * Return a language given the interpreter name.
1453  */
1454 static language *
1455 get_language_from_interpreter (interpreter)
1456 char *interpreter;
1457 {
1458         language *lang;
1459         char **iname;
1460
1461         if (interpreter == NULL)
1462                 return NULL;
1463         for (lang = lang_names; lang->name != NULL; lang++)
1464                 if (lang->interpreters != NULL)
1465                         for (iname = lang->interpreters; *iname != NULL; iname++)
1466                                 if (streq (*iname, interpreter))
1467                                         return lang;
1468
1469         return NULL;
1470 }
1471
1472
1473
1474 /*
1475  * Return a language given the file name.
1476  */
1477 static language *
1478 get_language_from_filename (file, case_sensitive)
1479 char *file;
1480 bool case_sensitive;
1481 {
1482         language *lang;
1483         char **name, **ext, *suffix;
1484
1485         /* Try whole file name first. */
1486         for (lang = lang_names; lang->name != NULL; lang++)
1487                 if (lang->filenames != NULL)
1488                         for (name = lang->filenames; *name != NULL; name++)
1489                                 if ((case_sensitive)
1490                                     ? streq (*name, file)
1491                                     : strcaseeq (*name, file))
1492                                         return lang;
1493
1494         /* If not found, try suffix after last dot. */
1495         suffix = etags_strrchr (file, '.');
1496         if (suffix == NULL)
1497                 return NULL;
1498         suffix += 1;
1499         for (lang = lang_names; lang->name != NULL; lang++)
1500                 if (lang->suffixes != NULL)
1501                         for (ext = lang->suffixes; *ext != NULL; ext++)
1502                                 if ((case_sensitive)
1503                                     ? streq (*ext, suffix)
1504                                     : strcaseeq (*ext, suffix))
1505                                         return lang;
1506         return NULL;
1507 }
1508
1509 \f
1510 /*
1511  * This routine is called on each file argument.
1512  */
1513 static void
1514 process_file_name (file, lang)
1515 char *file;
1516 language *lang;
1517 {
1518         struct stat stat_buf;
1519         FILE *inf;
1520         fdesc *fdp;
1521         compressor *compr;
1522         char *compressed_name, *uncompressed_name;
1523         char *ext, *real_name;
1524         int retval;
1525
1526         canonicalize_filename (file);
1527         if (streq (file, tagfile) && !streq (tagfile, "-"))
1528         {
1529                 error ("skipping inclusion of %s in self.", file);
1530                 return;
1531         }
1532         if ((compr = get_compressor_from_suffix (file, &ext)) == NULL)
1533         {
1534                 compressed_name = NULL;
1535                 real_name = uncompressed_name = savestr (file);
1536         }
1537         else
1538         {
1539                 real_name = compressed_name = savestr (file);
1540                 uncompressed_name = savenstr (file, ext - file);
1541         }
1542
1543         /* If the canonicalized uncompressed name
1544            has already been dealt with, skip it silently. */
1545         for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1546         {
1547                 assert (fdp->infname != NULL);
1548                 if (streq (uncompressed_name, fdp->infname))
1549                         goto cleanup;
1550         }
1551
1552         if (stat (real_name, &stat_buf) != 0)
1553         {
1554                 /* Reset real_name and try with a different name. */
1555                 real_name = NULL;
1556                 if (compressed_name != NULL) /* try with the given suffix */
1557                 {
1558                         if (stat (uncompressed_name, &stat_buf) == 0)
1559                                 real_name = uncompressed_name;
1560                 }
1561                 else                    /* try all possible suffixes */
1562                 {
1563                         for (compr = compressors; compr->suffix != NULL; compr++)
1564                         {
1565                                 compressed_name = concat (file, ".", compr->suffix);
1566                                 if (stat (compressed_name, &stat_buf) != 0)
1567                                 {
1568                                         free (compressed_name);
1569                                         compressed_name = NULL;
1570                                 }
1571                                 else
1572                                 {
1573                                         real_name = compressed_name;
1574                                         break;
1575                                 }
1576                         }
1577                 }
1578                 if (real_name == NULL)
1579                 {
1580                         perror (file);
1581                         goto cleanup;
1582                 }
1583         } /* try with a different name */
1584
1585         if (!S_ISREG (stat_buf.st_mode))
1586         {
1587                 error ("skipping %s: it is not a regular file.", real_name);
1588                 goto cleanup;
1589         }
1590         if (real_name == compressed_name)
1591         {
1592                 char *cmd = concat (compr->command, " ", real_name);
1593                 inf = (FILE *) popen (cmd, "r");
1594                 free (cmd);
1595         }
1596         else
1597                 inf = fopen (real_name, "r");
1598         if (inf == NULL)
1599         {
1600                 perror (real_name);
1601                 goto cleanup;
1602         }
1603
1604         process_file (inf, uncompressed_name, lang);
1605
1606         if (real_name == compressed_name)
1607                 retval = pclose (inf);
1608         else
1609                 retval = fclose (inf);
1610         if (retval < 0)
1611                 pfatal (file);
1612
1613 cleanup:
1614         free (compressed_name);
1615         free (uncompressed_name);
1616         last_node = NULL;
1617         curfdp = NULL;
1618         return;
1619 }
1620
1621 static void
1622 process_file (fh, fn, lang)
1623 FILE *fh;
1624 char *fn;
1625 language *lang;
1626 {
1627         static const fdesc emptyfdesc;
1628         fdesc *fdp;
1629
1630         /* Create a new input file description entry. */
1631         fdp = xnew (1, fdesc);
1632         *fdp = emptyfdesc;
1633         fdp->next = fdhead;
1634         fdp->infname = savestr (fn);
1635         fdp->lang = lang;
1636         fdp->infabsname = absolute_filename (fn, cwd);
1637         fdp->infabsdir = absolute_dirname (fn, cwd);
1638         if (filename_is_absolute (fn))
1639         {
1640                 /* An absolute file name.  Canonicalize it. */
1641                 fdp->taggedfname = absolute_filename (fn, NULL);
1642         }
1643         else
1644         {
1645                 /* A file name relative to cwd.  Make it relative
1646                    to the directory of the tags file. */
1647                 fdp->taggedfname = relative_filename (fn, tagfiledir);
1648         }
1649         fdp->usecharno = TRUE;  /* use char position when making tags */
1650         fdp->prop = NULL;
1651         fdp->written = FALSE;           /* not written on tags file yet */
1652
1653         fdhead = fdp;
1654         curfdp = fdhead;                /* the current file description */
1655
1656         find_entries (fh);
1657
1658         /* If not Ctags, and if this is not metasource and if it contained no #line
1659            directives, we can write the tags and free all nodes pointing to
1660            curfdp. */
1661         if (!CTAGS
1662             && curfdp->usecharno        /* no #line directives in this file */
1663             && !curfdp->lang->metasource)
1664         {
1665                 node *np, *prev;
1666
1667                 /* Look for the head of the sublist relative to this file.  See add_node
1668                    for the structure of the node tree. */
1669                 prev = NULL;
1670                 for (np = nodehead; np != NULL; prev = np, np = np->left)
1671                         if (np->fdp == curfdp)
1672                                 break;
1673
1674                 /* If we generated tags for this file, write and delete them. */
1675                 if (np != NULL)
1676                 {
1677                         /* This is the head of the last sublist, if any.  The following
1678                            instructions depend on this being true. */
1679                         assert (np->left == NULL);
1680
1681                         assert (fdhead == curfdp);
1682                         assert (last_node->fdp == curfdp);
1683                         put_entries (np);       /* write tags for file curfdp->taggedfname */
1684                         free_tree (np); /* remove the written nodes */
1685                         if (prev == NULL)
1686                                 nodehead = NULL;        /* no nodes left */
1687                         else
1688                                 prev->left = NULL;      /* delete the pointer to the sublist */
1689                 }
1690         }
1691 }
1692
1693 /*
1694  * This routine sets up the boolean pseudo-functions which work
1695  * by setting boolean flags dependent upon the corresponding character.
1696  * Every char which is NOT in that string is not a white char.  Therefore,
1697  * all of the array "_wht" is set to FALSE, and then the elements
1698  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
1699  * of a char is TRUE if it is the string "white", else FALSE.
1700  */
1701 static void
1702 init ()
1703 {
1704         register char *sp;
1705         register int i;
1706
1707         for (i = 0; i < CHARS; i++)
1708                 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1709         for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1710         for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1711         notinname('\0') = notinname('\n');
1712         for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1713         begtoken('\0') = begtoken('\n');
1714         for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1715         intoken('\0') = intoken('\n');
1716         for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1717         endtoken('\0') = endtoken('\n');
1718 }
1719
1720 /*
1721  * This routine opens the specified file and calls the function
1722  * which finds the function and type definitions.
1723  */
1724 static void
1725 find_entries (inf)
1726 FILE *inf;
1727 {
1728         char *cp;
1729         language *lang = curfdp->lang;
1730         Lang_function *parser = NULL;
1731
1732         /* If user specified a language, use it. */
1733         if (lang != NULL && lang->function != NULL)
1734         {
1735                 parser = lang->function;
1736         }
1737
1738         /* Else try to guess the language given the file name. */
1739         if (parser == NULL)
1740         {
1741                 lang = get_language_from_filename (curfdp->infname, TRUE);
1742                 if (lang != NULL && lang->function != NULL)
1743                 {
1744                         curfdp->lang = lang;
1745                         parser = lang->function;
1746                 }
1747         }
1748
1749         /* Else look for sharp-bang as the first two characters. */
1750         if (parser == NULL
1751             && readline_internal (&lb, inf) > 0
1752             && lb.len >= 2
1753             && lb.buffer[0] == '#'
1754             && lb.buffer[1] == '!')
1755         {
1756                 char *lp;
1757
1758                 /* Set lp to point at the first char after the last slash in the
1759                    line or, if no slashes, at the first nonblank.  Then set cp to
1760                    the first successive blank and terminate the string. */
1761                 lp = etags_strrchr (lb.buffer+2, '/');
1762                 if (lp != NULL)
1763                         lp += 1;
1764                 else
1765                         lp = skip_spaces (lb.buffer + 2);
1766                 cp = skip_non_spaces (lp);
1767                 *cp = '\0';
1768
1769                 if (strlen (lp) > 0)
1770                 {
1771                         lang = get_language_from_interpreter (lp);
1772                         if (lang != NULL && lang->function != NULL)
1773                         {
1774                                 curfdp->lang = lang;
1775                                 parser = lang->function;
1776                         }
1777                 }
1778         }
1779
1780         /* We rewind here, even if inf may be a pipe.  We fail if the
1781            length of the first line is longer than the pipe block size,
1782            which is unlikely. */
1783         rewind (inf);
1784
1785         /* Else try to guess the language given the case insensitive file name. */
1786         if (parser == NULL)
1787         {
1788                 lang = get_language_from_filename (curfdp->infname, FALSE);
1789                 if (lang != NULL && lang->function != NULL)
1790                 {
1791                         curfdp->lang = lang;
1792                         parser = lang->function;
1793                 }
1794         }
1795
1796         /* Else try Fortran or C. */
1797         if (parser == NULL)
1798         {
1799                 node *old_last_node = last_node;
1800
1801                 curfdp->lang = get_language_from_langname ("fortran");
1802                 find_entries (inf);
1803
1804                 if (old_last_node == last_node)
1805                         /* No Fortran entries found.  Try C. */
1806                 {
1807                         /* We do not tag if rewind fails.
1808                            Only the file name will be recorded in the tags file. */
1809                         rewind (inf);
1810                         curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
1811                         find_entries (inf);
1812                 }
1813                 return;
1814         }
1815
1816         if (!no_line_directive
1817             && curfdp->lang != NULL && curfdp->lang->metasource)
1818                 /* It may be that this is a bingo.y file, and we already parsed a bingo.c
1819                    file, or anyway we parsed a file that is automatically generated from
1820                    this one.  If this is the case, the bingo.c file contained #line
1821                    directives that generated tags pointing to this file.  Let's delete
1822                    them all before parsing this file, which is the real source. */
1823         {
1824                 fdesc **fdpp = &fdhead;
1825                 while (*fdpp != NULL)
1826                         if (*fdpp != curfdp
1827                             && streq ((*fdpp)->taggedfname, curfdp->taggedfname))
1828                                 /* We found one of those!  We must delete both the file description
1829                                    and all tags referring to it. */
1830                         {
1831                                 fdesc *badfdp = *fdpp;
1832
1833                                 /* Delete the tags referring to badfdp->taggedfname
1834                                    that were obtained from badfdp->infname. */
1835                                 invalidate_nodes (badfdp, &nodehead);
1836
1837                                 *fdpp = badfdp->next; /* remove the bad description from the list */
1838                                 free_fdesc (badfdp);
1839                         }
1840                         else
1841                                 fdpp = &(*fdpp)->next; /* advance the list pointer */
1842         }
1843
1844         assert (parser != NULL);
1845
1846         /* Generic initialisations before reading from file. */
1847         linebuffer_setlen (&filebuf, 0); /* reset the file buffer */
1848
1849         /* Generic initialisations before parsing file with readline. */
1850         lineno = 0;                    /* reset global line number */
1851         charno = 0;                    /* reset global char number */
1852         linecharno = 0;        /* reset global char number of line start */
1853
1854         parser (inf);
1855
1856         regex_tag_multiline ();
1857 }
1858
1859 \f
1860 /*
1861  * Check whether an implicitly named tag should be created,
1862  * then call `pfnote'.
1863  * NAME is a string that is internally copied by this function.
1864  *
1865  * TAGS format specification
1866  * Idea by Sam Kendall <kendall@mv.mv.com> (1997)
1867  * The following is explained in some more detail in etc/ETAGS.EBNF.
1868  *
1869  * make_tag creates tags with "implicit tag names" (unnamed tags)
1870  * if the following are all true, assuming NONAM=" \f\t\n\r()=,;":
1871  *  1. NAME does not contain any of the characters in NONAM;
1872  *  2. LINESTART contains name as either a rightmost, or rightmost but
1873  *     one character, substring;
1874  *  3. the character, if any, immediately before NAME in LINESTART must
1875  *     be a character in NONAM;
1876  *  4. the character, if any, immediately after NAME in LINESTART must
1877  *     also be a character in NONAM.
1878  *
1879  * The implementation uses the notinname() macro, which recognises the
1880  * characters stored in the string `nonam'.
1881  * etags.el needs to use the same characters that are in NONAM.
1882  */
1883 static void
1884 make_tag (name, namelen, is_func, linestart, linelen, lno, cno)
1885 char *name;             /* tag name, or NULL if unnamed */
1886 int namelen;            /* tag length */
1887 bool is_func;           /* tag is a function */
1888 char *linestart;                /* start of the line where tag is */
1889 int linelen;            /* length of the line where tag is */
1890 int lno;                        /* line number */
1891 long cno;                       /* character number */
1892 {
1893         bool named = (name != NULL && namelen > 0);
1894
1895         if (!CTAGS && named)            /* maybe set named to false */
1896                 /* Let's try to make an implicit tag name, that is, create an unnamed tag
1897                    such that etags.el can guess a name from it. */
1898         {
1899                 int i;
1900                 register char *cp = name;
1901
1902                 for (i = 0; i < namelen; i++)
1903                         if (notinname (*cp++))
1904                                 break;
1905                 if (i == namelen)                               /* rule #1 */
1906                 {
1907                         cp = linestart + linelen - namelen;
1908                         if (notinname (linestart[linelen-1]))
1909                                 cp -= 1;                                /* rule #4 */
1910                         if (cp >= linestart                     /* rule #2 */
1911                             && (cp == linestart
1912                                 || notinname (cp[-1]))  /* rule #3 */
1913                             && strneq (name, cp, namelen))      /* rule #2 */
1914                                 named = FALSE;  /* use implicit tag name */
1915                 }
1916         }
1917
1918         if (named)
1919                 name = savenstr (name, namelen);
1920         else
1921                 name = NULL;
1922         pfnote (name, is_func, linestart, linelen, lno, cno);
1923 }
1924
1925 /* Record a tag. */
1926 static void
1927 pfnote (name, is_func, linestart, linelen, lno, cno)
1928 char *name;             /* tag name, or NULL if unnamed */
1929 bool is_func;           /* tag is a function */
1930 char *linestart;                /* start of the line where tag is */
1931 int linelen;            /* length of the line where tag is */
1932 int lno;                        /* line number */
1933 long cno;                       /* character number */
1934 {
1935         register node *np;
1936
1937         assert (name == NULL || name[0] != '\0');
1938         if (CTAGS && name == NULL)
1939                 return;
1940
1941         np = xnew (1, node);
1942
1943         /* If ctags mode, change name "main" to M<thisfilename>. */
1944         if (CTAGS && !cxref_style && streq (name, "main"))
1945         {
1946                 register char *fp = etags_strrchr (curfdp->taggedfname, '/');
1947                 np->name = concat ("M", fp == NULL ? curfdp->taggedfname : fp + 1, "");
1948                 fp = etags_strrchr (np->name, '.');
1949                 if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
1950                         fp[0] = '\0';
1951         }
1952         else
1953                 np->name = name;
1954         np->valid = TRUE;
1955         np->been_warned = FALSE;
1956         np->fdp = curfdp;
1957         np->is_func = is_func;
1958         np->lno = lno;
1959         if (np->fdp->usecharno)
1960                 /* Our char numbers are 0-base, because of C language tradition?
1961                    ctags compatibility?  old versions compatibility?   I don't know.
1962                    Anyway, since emacs's are 1-base we expect etags.el to take care
1963                    of the difference.  If we wanted to have 1-based numbers, we would
1964                    uncomment the +1 below. */
1965                 np->cno = cno /* + 1 */ ;
1966         else
1967                 np->cno = invalidcharno;
1968         np->left = np->right = NULL;
1969         if (CTAGS && !cxref_style)
1970         {
1971                 if (strlen (linestart) < 50)
1972                         np->regex = concat (linestart, "$", "");
1973                 else
1974                         np->regex = savenstr (linestart, 50);
1975         }
1976         else
1977                 np->regex = savenstr (linestart, linelen);
1978
1979         add_node (np, &nodehead);
1980 }
1981
1982 /*
1983  * free_tree ()
1984  *      recurse on left children, iterate on right children.
1985  */
1986 static void
1987 free_tree (np)
1988 register node *np;
1989 {
1990         while (np)
1991         {
1992                 register node *node_right = np->right;
1993                 free_tree (np->left);
1994                 free (np->name);
1995                 free (np->regex);
1996                 free (np);
1997                 np = node_right;
1998         }
1999 }
2000
2001 /*
2002  * free_fdesc ()
2003  *      delete a file description
2004  */
2005 static void
2006 free_fdesc (fdp)
2007 register fdesc *fdp;
2008 {
2009         free (fdp->infname);
2010         free (fdp->infabsname);
2011         free (fdp->infabsdir);
2012         free (fdp->taggedfname);
2013         free (fdp->prop);
2014         free (fdp);
2015 }
2016
2017 /*
2018  * add_node ()
2019  *      Adds a node to the tree of nodes.  In etags mode, sort by file
2020  *      name.  In ctags mode, sort by tag name.  Make no attempt at
2021  *      balancing.
2022  *
2023  *      add_node is the only function allowed to add nodes, so it can
2024  *      maintain state.
2025  */
2026 static void
2027 add_node (np, cur_node_p)
2028 node *np, **cur_node_p;
2029 {
2030         register int dif;
2031         register node *cur_node = *cur_node_p;
2032
2033         if (cur_node == NULL)
2034         {
2035                 *cur_node_p = np;
2036                 last_node = np;
2037                 return;
2038         }
2039
2040         if (!CTAGS)
2041                 /* Etags Mode */
2042         {
2043                 /* For each file name, tags are in a linked sublist on the right
2044                    pointer.  The first tags of different files are a linked list
2045                    on the left pointer.  last_node points to the end of the last
2046                    used sublist. */
2047                 if (last_node != NULL && last_node->fdp == np->fdp)
2048                 {
2049                         /* Let's use the same sublist as the last added node. */
2050                         assert (last_node->right == NULL);
2051                         last_node->right = np;
2052                         last_node = np;
2053                 }
2054                 else if (cur_node->fdp == np->fdp)
2055                 {
2056                         /* Scanning the list we found the head of a sublist which is
2057                            good for us.  Let's scan this sublist. */
2058                         add_node (np, &cur_node->right);
2059                 }
2060                 else
2061                         /* The head of this sublist is not good for us.  Let's try the
2062                            next one. */
2063                         add_node (np, &cur_node->left);
2064         } /* if ETAGS mode */
2065
2066         else
2067         {
2068                 /* Ctags Mode */
2069                 dif = strcmp (np->name, cur_node->name);
2070
2071                 /*
2072                  * If this tag name matches an existing one, then
2073                  * do not add the node, but maybe print a warning.
2074                  */
2075                 if (no_duplicates && !dif)
2076                 {
2077                         if (np->fdp == cur_node->fdp)
2078                         {
2079                                 if (!no_warnings)
2080                                 {
2081                                         fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
2082                                                  np->fdp->infname, lineno, np->name);
2083                                         fprintf (stderr, "Second entry ignored\n");
2084                                 }
2085                         }
2086                         else if (!cur_node->been_warned && !no_warnings)
2087                         {
2088                                 fprintf
2089                                         (stderr,
2090                                          "Duplicate entry in files %s and %s: %s (Warning only)\n",
2091                                          np->fdp->infname, cur_node->fdp->infname, np->name);
2092                                 cur_node->been_warned = TRUE;
2093                         }
2094                         return;
2095                 }
2096
2097                 /* Actually add the node */
2098                 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
2099         } /* if CTAGS mode */
2100 }
2101
2102 /*
2103  * invalidate_nodes ()
2104  *      Scan the node tree and invalidate all nodes pointing to the
2105  *      given file description (CTAGS case) or free them (ETAGS case).
2106  */
2107 static void
2108 invalidate_nodes (badfdp, npp)
2109 fdesc *badfdp;
2110 node **npp;
2111 {
2112         node *np = *npp;
2113
2114         if (np == NULL)
2115                 return;
2116
2117         if (CTAGS)
2118         {
2119                 if (np->left != NULL)
2120                         invalidate_nodes (badfdp, &np->left);
2121                 if (np->fdp == badfdp)
2122                         np->valid = FALSE;
2123                 if (np->right != NULL)
2124                         invalidate_nodes (badfdp, &np->right);
2125         }
2126         else
2127         {
2128                 assert (np->fdp != NULL);
2129                 if (np->fdp == badfdp)
2130                 {
2131                         *npp = np->left;        /* detach the sublist from the list */
2132                         np->left = NULL;        /* isolate it */
2133                         free_tree (np); /* free it */
2134                         invalidate_nodes (badfdp, npp);
2135                 }
2136                 else
2137                         invalidate_nodes (badfdp, &np->left);
2138         }
2139 }
2140
2141 \f
2142 static int total_size_of_entries __P((node *));
2143 static int number_len __P((long));
2144
2145 /* Length of a non-negative number's decimal representation. */
2146 static int
2147 number_len (num)
2148 long num;
2149 {
2150         int len = 1;
2151         while ((num /= 10) > 0)
2152                 len += 1;
2153         return len;
2154 }
2155
2156 /*
2157  * Return total number of characters that put_entries will output for
2158  * the nodes in the linked list at the right of the specified node.
2159  * This count is irrelevant with etags.el since emacs 19.34 at least,
2160  * but is still supplied for backward compatibility.
2161  */
2162 static int
2163 total_size_of_entries (np)
2164 register node *np;
2165 {
2166         register int total = 0;
2167
2168         for (; np != NULL; np = np->right)
2169                 if (np->valid)
2170                 {
2171                         total += strlen (np->regex) + 1;                /* pat\177 */
2172                         if (np->name != NULL)
2173                                 total += strlen (np->name) + 1;         /* name\001 */
2174                         total += number_len ((long) np->lno) + 1;       /* lno, */
2175                         if (np->cno != invalidcharno)                   /* cno */
2176                                 total += number_len (np->cno);
2177                         total += 1;                                     /* newline */
2178                 }
2179
2180         return total;
2181 }
2182
2183 static void
2184 put_entries (np)
2185 register node *np;
2186 {
2187         register char *sp;
2188         static fdesc *fdp = NULL;
2189
2190         if (np == NULL)
2191                 return;
2192
2193         /* Output subentries that precede this one */
2194         if (CTAGS)
2195                 put_entries (np->left);
2196
2197         /* Output this entry */
2198         if (np->valid)
2199         {
2200                 if (!CTAGS)
2201                 {
2202                         /* Etags mode */
2203                         if (fdp != np->fdp)
2204                         {
2205                                 fdp = np->fdp;
2206                                 fprintf (tagf, "\f\n%s,%d\n",
2207                                          fdp->taggedfname, total_size_of_entries (np));
2208                                 fdp->written = TRUE;
2209                         }
2210                         fputs (np->regex, tagf);
2211                         fputc ('\177', tagf);
2212                         if (np->name != NULL)
2213                         {
2214                                 fputs (np->name, tagf);
2215                                 fputc ('\001', tagf);
2216                         }
2217                         fprintf (tagf, "%d,", np->lno);
2218                         if (np->cno != invalidcharno)
2219                                 fprintf (tagf, "%ld", np->cno);
2220                         fputs ("\n", tagf);
2221                 }
2222                 else
2223                 {
2224                         /* Ctags mode */
2225                         if (np->name == NULL)
2226                                 error ("internal error: NULL name in ctags mode.", (char *)NULL);
2227
2228                         if (cxref_style)
2229                         {
2230                                 if (vgrind_style)
2231                                         fprintf (stdout, "%s %s %d\n",
2232                                                  np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
2233                                 else
2234                                         fprintf (stdout, "%-16s %3d %-16s %s\n",
2235                                                  np->name, np->lno, np->fdp->taggedfname, np->regex);
2236                         }
2237                         else
2238                         {
2239                                 fprintf (tagf, "%s\t%s\t", np->name, np->fdp->taggedfname);
2240
2241                                 if (np->is_func)
2242                                 {               /* function or #define macro with args */
2243                                         putc (searchar, tagf);
2244                                         putc ('^', tagf);
2245
2246                                         for (sp = np->regex; *sp; sp++)
2247                                         {
2248                                                 if (*sp == '\\' || *sp == searchar)
2249                                                         putc ('\\', tagf);
2250                                                 putc (*sp, tagf);
2251                                         }
2252                                         putc (searchar, tagf);
2253                                 }
2254                                 else
2255                                 {               /* anything else; text pattern inadequate */
2256                                         fprintf (tagf, "%d", np->lno);
2257                                 }
2258                                 putc ('\n', tagf);
2259                         }
2260                 }
2261         } /* if this node contains a valid tag */
2262
2263         /* Output subentries that follow this one */
2264         put_entries (np->right);
2265         if (!CTAGS)
2266                 put_entries (np->left);
2267 }
2268
2269 \f
2270 /* C extensions. */
2271 #define C_EXT   0x00fff         /* C extensions */
2272 #define C_PLAIN 0x00000         /* C */
2273 #define C_PLPL  0x00001         /* C++ */
2274 #define C_STAR  0x00003         /* C* */
2275 #define C_JAVA  0x00005         /* JAVA */
2276 #define C_AUTO  0x01000         /* C, but switch to C++ if `class' is met */
2277 #define YACC    0x10000         /* yacc file */
2278
2279 /*
2280  * The C symbol tables.
2281  */
2282 enum sym_type
2283 {
2284         st_none,
2285         st_C_objprot, st_C_objimpl, st_C_objend,
2286         st_C_gnumacro,
2287         st_C_ignore, st_C_attribute,
2288         st_C_javastruct,
2289         st_C_operator,
2290         st_C_class, st_C_template,
2291         st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef
2292 };
2293
2294 static unsigned int hash __P((const char *, unsigned int));
2295 static struct C_stab_entry * in_word_set __P((const char *, unsigned int));
2296 static enum sym_type C_symtype __P((char *, int, int));
2297
2298 /* Feed stuff between (but not including) %[ and %] lines to:
2299    gperf -m 5
2300    %[
2301    %compare-strncmp
2302    %enum
2303    %struct-type
2304    struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
2305    %%
2306    if,                  0,                      st_C_ignore
2307    for,                 0,                      st_C_ignore
2308    while,               0,                      st_C_ignore
2309    switch,              0,                      st_C_ignore
2310    return,              0,                      st_C_ignore
2311    __attribute__,       0,                      st_C_attribute
2312    GTY,                 0,                      st_C_attribute
2313    @interface,          0,                      st_C_objprot
2314    @protocol,           0,                      st_C_objprot
2315    @implementation,     0,                      st_C_objimpl
2316    @end,                0,                      st_C_objend
2317    import,              (C_JAVA & ~C_PLPL),     st_C_ignore
2318    package,             (C_JAVA & ~C_PLPL),     st_C_ignore
2319    friend,              C_PLPL,                 st_C_ignore
2320    extends,             (C_JAVA & ~C_PLPL),     st_C_javastruct
2321    implements,          (C_JAVA & ~C_PLPL),     st_C_javastruct
2322    interface,           (C_JAVA & ~C_PLPL),     st_C_struct
2323    class,               0,                      st_C_class
2324    namespace,           C_PLPL,                 st_C_struct
2325    domain,              C_STAR,                 st_C_struct
2326    union,               0,                      st_C_struct
2327    struct,              0,                      st_C_struct
2328    extern,              0,                      st_C_extern
2329    enum,                0,                      st_C_enum
2330    typedef,             0,                      st_C_typedef
2331    define,              0,                      st_C_define
2332    undef,               0,                      st_C_define
2333    operator,            C_PLPL,                 st_C_operator
2334    template,            0,                      st_C_template
2335    # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
2336    DEFUN,               0,                      st_C_gnumacro
2337    SYSCALL,             0,                      st_C_gnumacro
2338    ENTRY,               0,                      st_C_gnumacro
2339    PSEUDO,              0,                      st_C_gnumacro
2340    # These are defined inside C functions, so currently they are not met.
2341    # EXFUN used in glibc, DEFVAR_* in emacs.
2342    #EXFUN,              0,                      st_C_gnumacro
2343    #DEFVAR_,            0,                      st_C_gnumacro
2344    %]
2345    and replace lines between %< and %> with its output, then:
2346    - remove the #if characterset check
2347    - make in_word_set static and not inline. */
2348 /*%<*/
2349 /* C code produced by gperf version 3.0.1 */
2350 /* Command-line: gperf -m 5  */
2351 /* Computed positions: -k'2-3' */
2352
2353 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
2354 /* maximum key range = 33, duplicates = 0 */
2355
2356 #ifdef __GNUC__
2357 __inline
2358 #else
2359 #ifdef __cplusplus
2360 inline
2361 #endif
2362 #endif
2363 static unsigned int
2364 hash (str, len)
2365 register const char *str;
2366 register unsigned int len;
2367 {
2368         static unsigned char asso_values[] =
2369                 {
2370                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2371                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2372                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2373                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2374                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2375                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2376                         35, 35, 35, 35, 35, 35, 35, 35, 35,  3,
2377                         26, 35, 35, 35, 35, 35, 35, 35, 27, 35,
2378                         35, 35, 35, 24,  0, 35, 35, 35, 35,  0,
2379                         35, 35, 35, 35, 35,  1, 35, 16, 35,  6,
2380                         23,  0,  0, 35, 22,  0, 35, 35,  5,  0,
2381                         0, 15,  1, 35,  6, 35,  8, 19, 35, 16,
2382                         4,  5, 35, 35, 35, 35, 35, 35, 35, 35,
2383                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2384                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2385                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2386                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2387                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2388                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2389                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2390                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2391                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2392                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2393                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2394                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
2395                         35, 35, 35, 35, 35, 35
2396                 };
2397         register int hval = len;
2398
2399         switch (hval)
2400         {
2401         default:
2402                 hval += asso_values[(unsigned char)str[2]];
2403                 /*FALLTHROUGH*/
2404         case 2:
2405                 hval += asso_values[(unsigned char)str[1]];
2406                 break;
2407         }
2408         return hval;
2409 }
2410
2411 static struct C_stab_entry *
2412 in_word_set (str, len)
2413 register const char *str;
2414 register unsigned int len;
2415 {
2416         enum
2417         {
2418                 TOTAL_KEYWORDS = 33,
2419                 MIN_WORD_LENGTH = 2,
2420                 MAX_WORD_LENGTH = 15,
2421                 MIN_HASH_VALUE = 2,
2422                 MAX_HASH_VALUE = 34
2423         };
2424
2425         static struct C_stab_entry wordlist[] =
2426                 {
2427                         {""}, {""},
2428                         {"if",          0,                      st_C_ignore},
2429                         {"GTY",           0,                      st_C_attribute},
2430                         {"@end",                0,                      st_C_objend},
2431                         {"union",               0,                      st_C_struct},
2432                         {"define",              0,                      st_C_define},
2433                         {"import",              (C_JAVA & ~C_PLPL),     st_C_ignore},
2434                         {"template",    0,                      st_C_template},
2435                         {"operator",    C_PLPL,                 st_C_operator},
2436                         {"@interface",  0,                      st_C_objprot},
2437                         {"implements",  (C_JAVA & ~C_PLPL),     st_C_javastruct},
2438                         {"friend",              C_PLPL,                 st_C_ignore},
2439                         {"typedef",     0,                      st_C_typedef},
2440                         {"return",              0,                      st_C_ignore},
2441                         {"@implementation",0,                   st_C_objimpl},
2442                         {"@protocol",   0,                      st_C_objprot},
2443                         {"interface",   (C_JAVA & ~C_PLPL),     st_C_struct},
2444                         {"extern",              0,                      st_C_extern},
2445                         {"extends",     (C_JAVA & ~C_PLPL),     st_C_javastruct},
2446                         {"struct",              0,                      st_C_struct},
2447                         {"domain",              C_STAR,                 st_C_struct},
2448                         {"switch",              0,                      st_C_ignore},
2449                         {"enum",                0,                      st_C_enum},
2450                         {"for",         0,                      st_C_ignore},
2451                         {"namespace",   C_PLPL,                 st_C_struct},
2452                         {"class",               0,                      st_C_class},
2453                         {"while",               0,                      st_C_ignore},
2454                         {"undef",               0,                      st_C_define},
2455                         {"package",     (C_JAVA & ~C_PLPL),     st_C_ignore},
2456                         {"__attribute__",       0,                      st_C_attribute},
2457                         {"SYSCALL",     0,                      st_C_gnumacro},
2458                         {"ENTRY",               0,                      st_C_gnumacro},
2459                         {"PSEUDO",              0,                      st_C_gnumacro},
2460                         {"DEFUN",               0,                      st_C_gnumacro}
2461                 };
2462
2463         if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
2464         {
2465                 register int key = hash (str, len);
2466
2467                 if (key <= MAX_HASH_VALUE && key >= 0)
2468                 {
2469                         register const char *s = wordlist[key].name;
2470
2471                         if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
2472                                 return &wordlist[key];
2473                 }
2474         }
2475         return 0;
2476 }
2477 /*%>*/
2478
2479 static enum sym_type
2480 C_symtype (str, len, c_ext)
2481 char *str;
2482 int len;
2483 int c_ext;
2484 {
2485         register struct C_stab_entry *se = in_word_set (str, len);
2486
2487         if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2488                 return st_none;
2489         return se->type;
2490 }
2491
2492 \f
2493 /*
2494  * Ignoring __attribute__ ((list))
2495  */
2496 static bool inattribute;        /* looking at an __attribute__ construct */
2497
2498 /*
2499  * C functions and variables are recognized using a simple
2500  * finite automaton.  fvdef is its state variable.
2501  */
2502 static enum
2503 {
2504         fvnone,                 /* nothing seen */
2505         fdefunkey,                      /* Emacs DEFUN keyword seen */
2506         fdefunname,                     /* Emacs DEFUN name seen */
2507         foperator,                      /* func: operator keyword seen (cplpl) */
2508         fvnameseen,                     /* function or variable name seen */
2509         fstartlist,                     /* func: just after open parenthesis */
2510         finlist,                        /* func: in parameter list */
2511         flistseen,                      /* func: after parameter list */
2512         fignore,                        /* func: before open brace */
2513         vignore                 /* var-like: ignore until ';' */
2514 } fvdef;
2515
2516 static bool fvextern;           /* func or var: extern keyword seen; */
2517
2518 /*
2519  * typedefs are recognized using a simple finite automaton.
2520  * typdef is its state variable.
2521  */
2522 static enum
2523 {
2524         tnone,                  /* nothing seen */
2525         tkeyseen,                       /* typedef keyword seen */
2526         ttypeseen,                      /* defined type seen */
2527         tinbody,                        /* inside typedef body */
2528         tend,                           /* just before typedef tag */
2529         tignore                 /* junk after typedef tag */
2530 } typdef;
2531
2532 /*
2533  * struct-like structures (enum, struct and union) are recognized
2534  * using another simple finite automaton.  `structdef' is its state
2535  * variable.
2536  */
2537 static enum
2538 {
2539         snone,                  /* nothing seen yet,
2540                                    or in struct body if bracelev > 0 */
2541         skeyseen,                       /* struct-like keyword seen */
2542         stagseen,                       /* struct-like tag seen */
2543         scolonseen                      /* colon seen after struct-like tag */
2544 } structdef;
2545
2546 /*
2547  * When objdef is different from onone, objtag is the name of the class.
2548  */
2549 static char *objtag = "<uninited>";
2550
2551 /*
2552  * Yet another little state machine to deal with preprocessor lines.
2553  */
2554 static enum
2555 {
2556         dnone,                  /* nothing seen */
2557         dsharpseen,                     /* '#' seen as first char on line */
2558         ddefineseen,                    /* '#' and 'define' seen */
2559         dignorerest                     /* ignore rest of line */
2560 } definedef;
2561
2562 /*
2563  * State machine for Objective C protocols and implementations.
2564  * Idea by Tom R.Hageman <tom@basil.icce.rug.nl> (1995)
2565  */
2566 static enum
2567 {
2568         onone,                  /* nothing seen */
2569         oprotocol,                      /* @interface or @protocol seen */
2570         oimplementation,                /* @implementations seen */
2571         otagseen,                       /* class name seen */
2572         oparenseen,                     /* parenthesis before category seen */
2573         ocatseen,                       /* category name seen */
2574         oinbody,                        /* in @implementation body */
2575         omethodsign,                    /* in @implementation body, after +/- */
2576         omethodtag,                     /* after method name */
2577         omethodcolon,                   /* after method colon */
2578         omethodparm,                    /* after method parameter */
2579         oignore                 /* wait for @end */
2580 } objdef;
2581
2582
2583 /*
2584  * Use this structure to keep info about the token read, and how it
2585  * should be tagged.  Used by the make_C_tag function to build a tag.
2586  */
2587 static struct tok
2588 {
2589         char *line;                     /* string containing the token */
2590         int offset;                     /* where the token starts in LINE */
2591         int length;                     /* token length */
2592         /*
2593           The previous members can be used to pass strings around for generic
2594           purposes.  The following ones specifically refer to creating tags.  In this
2595           case the token contained here is the pattern that will be used to create a
2596           tag.
2597         */
2598         bool valid;                     /* do not create a tag; the token should be
2599                                            invalidated whenever a state machine is
2600                                            reset prematurely */
2601         bool named;                     /* create a named tag */
2602         int lineno;                     /* source line number of tag */
2603         long linepos;                   /* source char number of tag */
2604 } token;                        /* latest token read */
2605
2606 /*
2607  * Variables and functions for dealing with nested structures.
2608  * Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001)
2609  */
2610 static void pushclass_above __P((int, char *, int));
2611 static void popclass_above __P((int));
2612 static void write_classname __P((linebuffer *, char *qualifier));
2613
2614 static struct {
2615         char **cname;                   /* nested class names */
2616         int *bracelev;          /* nested class brace level */
2617         int nl;                 /* class nesting level (elements used) */
2618         int size;                       /* length of the array */
2619 } cstack;                       /* stack for nested declaration tags */
2620 /* Current struct nesting depth (namespace, class, struct, union, enum). */
2621 #define nestlev         (cstack.nl)
2622 /* After struct keyword or in struct body, not inside a nested function. */
2623 #define instruct        (structdef == snone && nestlev > 0              \
2624                          && bracelev == cstack.bracelev[nestlev-1] + 1)
2625
2626 static void
2627 pushclass_above (bracelev, str, len)
2628 int bracelev;
2629 char *str;
2630 int len;
2631 {
2632         int nl;
2633
2634         popclass_above (bracelev);
2635         nl = cstack.nl;
2636         if (nl >= cstack.size)
2637         {
2638                 int size = cstack.size *= 2;
2639                 xrnew (cstack.cname, size, char *);
2640                 xrnew (cstack.bracelev, size, int);
2641         }
2642         assert (nl == 0 || cstack.bracelev[nl-1] < bracelev);
2643         cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
2644         cstack.bracelev[nl] = bracelev;
2645         cstack.nl = nl + 1;
2646 }
2647
2648 static void
2649 popclass_above (bracelev)
2650 int bracelev;
2651 {
2652         int nl;
2653
2654         for (nl = cstack.nl - 1;
2655              nl >= 0 && cstack.bracelev[nl] >= bracelev;
2656              nl--)
2657         {
2658                 free (cstack.cname[nl]);
2659                 cstack.nl = nl;
2660         }
2661 }
2662
2663 static void
2664 write_classname (cn, qualifier)
2665 linebuffer *cn;
2666 char *qualifier;
2667 {
2668         int i, len;
2669         int qlen = strlen (qualifier);
2670
2671         if (cstack.nl == 0 || cstack.cname[0] == NULL)
2672         {
2673                 len = 0;
2674                 cn->len = 0;
2675                 cn->buffer[0] = '\0';
2676         }
2677         else
2678         {
2679                 len = strlen (cstack.cname[0]);
2680                 linebuffer_setlen (cn, len+1);
2681                 strncpy (cn->buffer, cstack.cname[0],len+1);
2682         }
2683         for (i = 1; i < cstack.nl; i++)
2684         {
2685                 char *s;
2686                 int slen;
2687
2688                 s = cstack.cname[i];
2689                 if (s == NULL)
2690                         continue;
2691                 slen = strlen (s);
2692                 len += slen + qlen;
2693                 linebuffer_setlen (cn, len);
2694                 strncat (cn->buffer, qualifier, qlen);
2695                 strncat (cn->buffer, s, slen);
2696         }
2697 }
2698
2699 \f
2700 static bool consider_token __P((char *, int, int, int *, int, int, bool *));
2701 static void make_C_tag __P((bool));
2702
2703 /*
2704  * consider_token ()
2705  *      checks to see if the current token is at the start of a
2706  *      function or variable, or corresponds to a typedef, or
2707  *      is a struct/union/enum tag, or #define, or an enum constant.
2708  *
2709  *      *IS_FUNC gets TRUE if the token is a function or #define macro
2710  *      with args.  C_EXTP points to which language we are looking at.
2711  *
2712  * Globals
2713  *      fvdef                   IN OUT
2714  *      structdef               IN OUT
2715  *      definedef               IN OUT
2716  *      typdef                  IN OUT
2717  *      objdef                  IN OUT
2718  */
2719
2720 static bool
2721 consider_token (str, len, c, c_extp, bracelev, parlev, is_func_or_var)
2722 register char *str;     /* IN: token pointer */
2723 register int len;               /* IN: token length */
2724 register int c;         /* IN: first char after the token */
2725 int *c_extp;            /* IN, OUT: C extensions mask */
2726 int bracelev;           /* IN: brace level */
2727 int parlev;             /* IN: parenthesis level */
2728 bool *is_func_or_var;   /* OUT: function or variable found */
2729 {
2730         /* When structdef is stagseen, scolonseen, or snone with bracelev > 0,
2731            structtype is the type of the preceding struct-like keyword, and
2732            structbracelev is the brace level where it has been seen. */
2733         static enum sym_type structtype;
2734         static int structbracelev;
2735         static enum sym_type toktype;
2736
2737
2738         toktype = C_symtype (str, len, *c_extp);
2739
2740         /*
2741          * Skip __attribute__
2742          */
2743         if (toktype == st_C_attribute)
2744         {
2745                 inattribute = TRUE;
2746                 return FALSE;
2747         }
2748
2749         /*
2750          * Advance the definedef state machine.
2751          */
2752         switch (definedef)
2753         {
2754         case dnone:
2755                 /* We're not on a preprocessor line. */
2756                 if (toktype == st_C_gnumacro)
2757                 {
2758                         fvdef = fdefunkey;
2759                         return FALSE;
2760                 }
2761                 break;
2762         case dsharpseen:
2763                 if (toktype == st_C_define)
2764                 {
2765                         definedef = ddefineseen;
2766                 }
2767                 else
2768                 {
2769                         definedef = dignorerest;
2770                 }
2771                 return FALSE;
2772         case ddefineseen:
2773                 /*
2774                  * Make a tag for any macro, unless it is a constant
2775                  * and constantypedefs is FALSE.
2776                  */
2777                 definedef = dignorerest;
2778                 *is_func_or_var = (c == '(');
2779                 if (!*is_func_or_var && !constantypedefs)
2780                         return FALSE;
2781                 else
2782                         return TRUE;
2783         case dignorerest:
2784                 return FALSE;
2785         default:
2786                 error ("internal error: definedef value.", (char *)NULL);
2787         }
2788
2789         /*
2790          * Now typedefs
2791          */
2792         switch (typdef)
2793         {
2794         case tnone:
2795                 if (toktype == st_C_typedef)
2796                 {
2797                         if (typedefs)
2798                                 typdef = tkeyseen;
2799                         fvextern = FALSE;
2800                         fvdef = fvnone;
2801                         return FALSE;
2802                 }
2803                 break;
2804         case tkeyseen:
2805                 switch (toktype)
2806                 {
2807                 case st_none:
2808                 case st_C_class:
2809                 case st_C_struct:
2810                 case st_C_enum:
2811                         typdef = ttypeseen;
2812
2813                         /* all the rest */
2814                 case st_C_objprot:
2815                 case st_C_objimpl:
2816                 case st_C_objend:
2817                 case st_C_gnumacro:
2818                 case st_C_ignore:
2819                 case st_C_attribute:
2820                 case st_C_javastruct:
2821                 case st_C_operator:
2822                 case st_C_template:
2823                 case st_C_extern:
2824                 case st_C_define:
2825                 case st_C_typedef:
2826                 default:
2827                         break;
2828                 }
2829                 break;
2830         case ttypeseen:
2831                 if (structdef == snone && fvdef == fvnone)
2832                 {
2833                         fvdef = fvnameseen;
2834                         return TRUE;
2835                 }
2836                 break;
2837         case tend:
2838                 switch (toktype)
2839                 {
2840                 case st_C_class:
2841                 case st_C_struct:
2842                 case st_C_enum:
2843                         return FALSE;
2844
2845                         /* all the rest */
2846                 case st_none:
2847                 case st_C_objprot:
2848                 case st_C_objimpl:
2849                 case st_C_objend:
2850                 case st_C_gnumacro:
2851                 case st_C_ignore:
2852                 case st_C_attribute:
2853                 case st_C_javastruct:
2854                 case st_C_operator:
2855                 case st_C_template:
2856                 case st_C_extern:
2857                 case st_C_define:
2858                 case st_C_typedef:
2859                 default:
2860                         break;
2861                 }
2862                 return TRUE;
2863
2864                 /* all the rest */
2865         case tinbody:
2866         case tignore:
2867         default:
2868                 break;
2869         }
2870
2871         switch (toktype)
2872         {
2873         case st_C_javastruct:
2874                 if (structdef == stagseen)
2875                         structdef = scolonseen;
2876                 return FALSE;
2877         case st_C_template:
2878         case st_C_class:
2879                 if ((*c_extp & C_AUTO)  /* automatic detection of C++ language */
2880                     && bracelev == 0
2881                     && definedef == dnone && structdef == snone
2882                     && typdef == tnone && fvdef == fvnone)
2883                         *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
2884                 if (toktype == st_C_template)
2885                         break;
2886                 /* FALLTHRU */
2887         case st_C_struct:
2888         case st_C_enum:
2889                 if (parlev == 0
2890                     && fvdef != vignore
2891                     && (typdef == tkeyseen
2892                         || (typedefs_or_cplusplus && structdef == snone)))
2893                 {
2894                         structdef = skeyseen;
2895                         structtype = toktype;
2896                         structbracelev = bracelev;
2897                         if (fvdef == fvnameseen)
2898                                 fvdef = fvnone;
2899                 }
2900                 return FALSE;
2901
2902                 /* all the rest */
2903         case st_none:
2904         case st_C_objprot:
2905         case st_C_objimpl:
2906         case st_C_objend:
2907         case st_C_gnumacro:
2908         case st_C_ignore:
2909         case st_C_attribute:
2910         case st_C_operator:
2911         case st_C_extern:
2912         case st_C_define:
2913         case st_C_typedef:
2914         default:
2915                 break;
2916         }
2917
2918         if (structdef == skeyseen)
2919         {
2920                 structdef = stagseen;
2921                 return TRUE;
2922         }
2923
2924         if (typdef != tnone)
2925                 definedef = dnone;
2926
2927         /* Detect Objective C constructs. */
2928         switch (objdef)
2929         {
2930         case onone:
2931                 switch (toktype)
2932                 {
2933                 case st_C_objprot:
2934                         objdef = oprotocol;
2935                         return FALSE;
2936                 case st_C_objimpl:
2937                         objdef = oimplementation;
2938                         return FALSE;
2939
2940                         /* all the rest */
2941                 case st_none:
2942                 case st_C_objend:
2943                 case st_C_gnumacro:
2944                 case st_C_ignore:
2945                 case st_C_attribute:
2946                 case st_C_javastruct:
2947                 case st_C_operator:
2948                 case st_C_class:
2949                 case st_C_template:
2950                 case st_C_struct:
2951                 case st_C_extern:
2952                 case st_C_enum:
2953                 case st_C_define:
2954                 case st_C_typedef:
2955                 default:
2956                         break;
2957                 }
2958                 break;
2959         case oimplementation:
2960                 /* Save the class tag for functions or variables defined inside. */
2961                 objtag = savenstr (str, len);
2962                 objdef = oinbody;
2963                 return FALSE;
2964         case oprotocol:
2965                 /* Save the class tag for categories. */
2966                 objtag = savenstr (str, len);
2967                 objdef = otagseen;
2968                 *is_func_or_var = TRUE;
2969                 return TRUE;
2970         case oparenseen:
2971                 objdef = ocatseen;
2972                 *is_func_or_var = TRUE;
2973                 return TRUE;
2974         case oinbody:
2975                 break;
2976         case omethodsign:
2977                 if (parlev == 0)
2978                 {
2979                         fvdef = fvnone;
2980                         objdef = omethodtag;
2981                         linebuffer_setlen (&token_name, len);
2982                         strncpy (token_name.buffer, str, len);
2983                         token_name.buffer[len] = '\0';
2984                         return TRUE;
2985                 }
2986                 return FALSE;
2987         case omethodcolon:
2988                 if (parlev == 0)
2989                         objdef = omethodparm;
2990                 return FALSE;
2991         case omethodparm:
2992                 if (parlev == 0)
2993                 {
2994                         fvdef = fvnone;
2995                         objdef = omethodtag;
2996                         linebuffer_setlen (&token_name, token_name.len + len);
2997                         strncat (token_name.buffer, str, len);
2998                         return TRUE;
2999                 }
3000                 return FALSE;
3001         case oignore:
3002                 if (toktype == st_C_objend)
3003                 {
3004                         /* Memory leakage here: the string pointed by objtag is
3005                            never released, because many tests would be needed to
3006                            avoid breaking on incorrect input code.  The amount of
3007                            memory leaked here is the sum of the lengths of the
3008                            class tags.
3009                            free (objtag); */
3010                         objdef = onone;
3011                 }
3012                 return FALSE;
3013
3014                 /* all the rest */
3015         case otagseen:
3016         case ocatseen:
3017         case omethodtag:
3018         default:
3019                 break;
3020         }
3021
3022         /* A function, variable or enum constant? */
3023         switch (toktype)
3024         {
3025         case st_C_extern:
3026                 fvextern = TRUE;
3027                 switch  (fvdef)
3028                 {
3029                 case finlist:
3030                 case flistseen:
3031                 case fignore:
3032                 case vignore:
3033                         break;
3034                 case fvnone:
3035                 case fdefunkey:
3036                 case fdefunname:
3037                 case foperator:
3038                 case fvnameseen:
3039                 case fstartlist:
3040                 default:
3041                         fvdef = fvnone;
3042                 }
3043                 return FALSE;
3044         case st_C_ignore:
3045                 fvextern = FALSE;
3046                 fvdef = vignore;
3047                 return FALSE;
3048         case st_C_operator:
3049                 fvdef = foperator;
3050                 *is_func_or_var = TRUE;
3051                 return TRUE;
3052         case st_none:
3053                 if (constantypedefs
3054                     && structdef == snone
3055                     && structtype == st_C_enum && bracelev > structbracelev)
3056                         return TRUE;            /* enum constant */
3057                 switch (fvdef)
3058                 {
3059                 case fdefunkey:
3060                         if (bracelev > 0)
3061                                 break;
3062                         fvdef = fdefunname;     /* GNU macro */
3063                         *is_func_or_var = TRUE;
3064                         return TRUE;
3065                 case fvnone:
3066                         switch (typdef)
3067                         {
3068                         case ttypeseen:
3069                                 return FALSE;
3070                         case tnone:
3071                                 if ((strneq (str, "asm", 3) && endtoken (str[3]))
3072                                     || (strneq (str, "__asm__", 7) && endtoken (str[7])))
3073                                 {
3074                                         fvdef = vignore;
3075                                         return FALSE;
3076                                 }
3077                                 break;
3078
3079                                 /* all the rest */
3080                         case tkeyseen:
3081                         case tinbody:
3082                         case tend:
3083                         case tignore:
3084                         default:
3085                                 break;
3086                         }
3087                         /* FALLTHRU */
3088                 case fvnameseen:
3089                         if (len >= 10 && strneq (str+len-10, "::operator", 10))
3090                         {
3091                                 if (*c_extp & C_AUTO) /* automatic detection of C++ */
3092                                         *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
3093                                 fvdef = foperator;
3094                                 *is_func_or_var = TRUE;
3095                                 return TRUE;
3096                         }
3097                         if (bracelev > 0 && !instruct)
3098                                 break;
3099                         fvdef = fvnameseen;     /* function or variable */
3100                         *is_func_or_var = TRUE;
3101                         return TRUE;
3102
3103                         /* all the rest */
3104                 case fdefunname:
3105                 case foperator:
3106                 case fstartlist:
3107                 case finlist:
3108                 case flistseen:
3109                 case fignore:
3110                 case vignore:
3111                 default:
3112                         break;
3113                 }
3114                 break;
3115
3116                 /* all the rest */
3117         case st_C_objprot:
3118         case st_C_objimpl:
3119         case st_C_objend:
3120         case st_C_gnumacro:
3121         case st_C_attribute:
3122         case st_C_javastruct:
3123         case st_C_class:
3124         case st_C_template:
3125         case st_C_struct:
3126         case st_C_enum:
3127         case st_C_define:
3128         case st_C_typedef:
3129         default:
3130                 break;
3131         }
3132
3133         return FALSE;
3134 }
3135
3136 \f
3137 /*
3138  * C_entries often keeps pointers to tokens or lines which are older than
3139  * the line currently read.  By keeping two line buffers, and switching
3140  * them at end of line, it is possible to use those pointers.
3141  */
3142 static struct
3143 {
3144         long linepos;
3145         linebuffer lb;
3146 } lbs[2];
3147
3148 #define current_lb_is_new (newndx == curndx)
3149 #define switch_line_buffers() (curndx = 1 - curndx)
3150
3151 #define curlb (lbs[curndx].lb)
3152 #define newlb (lbs[newndx].lb)
3153 #define curlinepos (lbs[curndx].linepos)
3154 #define newlinepos (lbs[newndx].linepos)
3155
3156 #define plainc ((c_ext & C_EXT) == C_PLAIN)
3157 #define cplpl (c_ext & C_PLPL)
3158 #define cjava ((c_ext & C_JAVA) == C_JAVA)
3159
3160 #define CNL_SAVE_DEFINEDEF()                    \
3161         do {                                    \
3162                 curlinepos = charno;            \
3163                 readline (&curlb, inf);         \
3164                 lp = curlb.buffer;              \
3165                 quotednl = FALSE;               \
3166                 newndx = curndx;                \
3167         } while (0)
3168
3169 #define CNL()                                           \
3170         do {                                            \
3171                 CNL_SAVE_DEFINEDEF();                   \
3172                 if (savetoken.valid)                    \
3173                 {                                       \
3174                         token = savetoken;              \
3175                         savetoken.valid = FALSE;        \
3176                 }                                       \
3177                 definedef = dnone;                      \
3178         } while (0)
3179
3180
3181 static void
3182 make_C_tag (isfun)
3183 bool isfun;
3184 {
3185         /* This function is never called when token.valid is FALSE, but
3186            we must protect against invalid input or internal errors. */
3187         if (token.valid)
3188                 make_tag (token_name.buffer, token_name.len, isfun, token.line,
3189                           token.offset+token.length+1, token.lineno, token.linepos);
3190         else if (DEBUG)
3191         {                                 /* this branch is optimised away if !DEBUG */
3192                 make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
3193                           token_name.len + 17, isfun, token.line,
3194                           token.offset+token.length+1, token.lineno, token.linepos);
3195                 error ("INVALID TOKEN", NULL);
3196         }
3197
3198         token.valid = FALSE;
3199 }
3200
3201
3202 /*
3203  * C_entries ()
3204  *      This routine finds functions, variables, typedefs,
3205  *      #define's, enum constants and struct/union/enum definitions in
3206  *      C syntax and adds them to the list.
3207  */
3208 static void
3209 C_entries (c_ext, inf)
3210 int c_ext;                      /* extension of C */
3211 FILE *inf;                      /* input file */
3212 {
3213         register char c;                /* latest char read; '\0' for end of line */
3214         register char *lp;              /* pointer one beyond the character `c' */
3215         int curndx, newndx;             /* indices for current and new lb */
3216         register int tokoff;            /* offset in line of start of current token */
3217         register int toklen;            /* length of current token */
3218         char *qualifier;                /* string used to qualify names */
3219         int qlen;                       /* length of qualifier */
3220         int bracelev;                   /* current brace level */
3221         int bracketlev;         /* current bracket level */
3222         int parlev;                     /* current parenthesis level */
3223         int attrparlev;         /* __attribute__ parenthesis level */
3224         int templatelev;                /* current template level */
3225         int typdefbracelev;             /* bracelev where a typedef struct body begun */
3226         bool incomm, inquote, inchar, quotednl, midtoken;
3227         bool yacc_rules;                /* in the rules part of a yacc file */
3228         struct tok savetoken = {0};     /* token saved during preprocessor handling */
3229
3230
3231         linebuffer_init (&lbs[0].lb);
3232         linebuffer_init (&lbs[1].lb);
3233         if (cstack.size == 0)
3234         {
3235                 cstack.size = (DEBUG) ? 1 : 4;
3236                 cstack.nl = 0;
3237                 cstack.cname = xnew (cstack.size, char *);
3238                 cstack.bracelev = xnew (cstack.size, int);
3239         }
3240
3241         tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */
3242         curndx = newndx = 0;
3243         lp = curlb.buffer;
3244         *lp = 0;
3245
3246         fvdef = fvnone; fvextern = FALSE; typdef = tnone;
3247         structdef = snone; definedef = dnone; objdef = onone;
3248         yacc_rules = FALSE;
3249         midtoken = inquote = inchar = incomm = quotednl = FALSE;
3250         token.valid = savetoken.valid = FALSE;
3251         bracelev = bracketlev = parlev = attrparlev = templatelev = 0;
3252         if (cjava)
3253         { qualifier = "."; qlen = 1; }
3254         else
3255         { qualifier = "::"; qlen = 2; }
3256
3257
3258         while (!feof (inf))
3259         {
3260                 c = *lp++;
3261                 if (c == '\\')
3262                 {
3263                         /* If we are at the end of the line, the next character is a
3264                            '\0'; do not skip it, because it is what tells us
3265                            to read the next line.  */
3266                         if (*lp == '\0')
3267                         {
3268                                 quotednl = TRUE;
3269                                 continue;
3270                         }
3271                         lp++;
3272                         c = ' ';
3273                 }
3274                 else if (incomm)
3275                 {
3276                         switch (c)
3277                         {
3278                         case '*':
3279                                 if (*lp == '/')
3280                                 {
3281                                         c = *lp++;
3282                                         incomm = FALSE;
3283                                 }
3284                                 break;
3285                         case '\0':
3286                                 /* Newlines inside comments do not end macro definitions in
3287                                    traditional cpp. */
3288                                 CNL_SAVE_DEFINEDEF ();
3289                                 break;
3290                         default:
3291                                 break;
3292                         }
3293                         continue;
3294                 }
3295                 else if (inquote)
3296                 {
3297                         switch (c)
3298                         {
3299                         case '"':
3300                                 inquote = FALSE;
3301                                 break;
3302                         case '\0':
3303                                 /* Newlines inside strings do not end macro definitions
3304                                    in traditional cpp, even though compilers don't
3305                                    usually accept them. */
3306                                 CNL_SAVE_DEFINEDEF ();
3307                                 break;
3308                         default:
3309                                 break;
3310                         }
3311                         continue;
3312                 }
3313                 else if (inchar)
3314                 {
3315                         switch (c)
3316                         {
3317                         case '\0':
3318                                 /* Hmmm, something went wrong. */
3319                                 CNL ();
3320                                 /* FALLTHRU */
3321                         case '\'':
3322                                 inchar = FALSE;
3323                                 break;
3324                         default:
3325                                 break;
3326                         }
3327                         continue;
3328                 }
3329                 else if (bracketlev > 0)
3330                 {
3331                         switch (c)
3332                         {
3333                         case ']':
3334                                 if (--bracketlev > 0)
3335                                         continue;
3336                                 break;
3337                         case '\0':
3338                                 CNL_SAVE_DEFINEDEF ();
3339                                 break;
3340                         default:
3341                                 break;
3342                         }
3343                         continue;
3344                 }
3345                 else switch (c)
3346                 {
3347                 case '"':
3348                         inquote = TRUE;
3349                         if (inattribute)
3350                                 break;
3351                         switch (fvdef)
3352                         {
3353                         case fdefunkey:
3354                         case fstartlist:
3355                         case finlist:
3356                         case fignore:
3357                         case vignore:
3358                                 break;
3359                         case fvnone:
3360                         case fdefunname:
3361                         case foperator:
3362                         case fvnameseen:
3363                         case flistseen:
3364                         default:
3365                                 fvextern = FALSE;
3366                                 fvdef = fvnone;
3367                         }
3368                         continue;
3369                 case '\'':
3370                         inchar = TRUE;
3371                         if (inattribute)
3372                                 break;
3373                         if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
3374                         {
3375                                 fvextern = FALSE;
3376                                 fvdef = fvnone;
3377                         }
3378                         continue;
3379                 case '/':
3380                         if (*lp == '*')
3381                         {
3382                                 incomm = TRUE;
3383                                 lp++;
3384                                 c = ' ';
3385                         }
3386                         else if (/* cplpl && */ *lp == '/')
3387                         {
3388                                 c = '\0';
3389                         }
3390                         break;
3391                 case '%':
3392                         if ((c_ext & YACC) && *lp == '%')
3393                         {
3394                                 /* Entering or exiting rules section in yacc file. */
3395                                 lp++;
3396                                 definedef = dnone; fvdef = fvnone; fvextern = FALSE;
3397                                 typdef = tnone; structdef = snone;
3398                                 midtoken = inquote = inchar = incomm = quotednl = FALSE;
3399                                 bracelev = 0;
3400                                 yacc_rules = !yacc_rules;
3401                                 continue;
3402                         }
3403                         else
3404                                 break;
3405                 case '#':
3406                         if (definedef == dnone)
3407                         {
3408                                 char *cp;
3409                                 bool cpptoken = TRUE;
3410
3411                                 /* Look back on this line.  If all blanks, or nonblanks
3412                                    followed by an end of comment, this is a preprocessor
3413                                    token. */
3414                                 for (cp = newlb.buffer; cp < lp-1; cp++)
3415                                         if (!iswhite (*cp))
3416                                         {
3417                                                 if (*cp == '*' && *(cp+1) == '/')
3418                                                 {
3419                                                         cp++;
3420                                                         cpptoken = TRUE;
3421                                                 }
3422                                                 else
3423                                                         cpptoken = FALSE;
3424                                         }
3425                                 if (cpptoken)
3426                                         definedef = dsharpseen;
3427                         } /* if (definedef == dnone) */
3428                         continue;
3429                 case '[':
3430                         bracketlev++;
3431                         continue;
3432                 default:
3433                         break;
3434                 } /* switch (c) */
3435
3436
3437                 /* Consider token only if some involved conditions are satisfied. */
3438                 if (typdef != tignore
3439                     && definedef != dignorerest
3440                     && fvdef != finlist
3441                     && templatelev == 0
3442                     && (definedef != dnone
3443                         || structdef != scolonseen)
3444                     && !inattribute)
3445                 {
3446                         if (midtoken)
3447                         {
3448                                 if (endtoken (c))
3449                                 {
3450                                         if (c == ':' && *lp == ':' && begtoken (lp[1]))
3451                                                 /* This handles :: in the middle,
3452                                                    but not at the beginning of an identifier.
3453                                                    Also, space-separated :: is not recognised. */
3454                                         {
3455                                                 if (c_ext & C_AUTO) /* automatic detection of C++ */
3456                                                         c_ext = (c_ext | C_PLPL) & ~C_AUTO;
3457                                                 lp += 2;
3458                                                 toklen += 2;
3459                                                 c = lp[-1];
3460                                                 goto still_in_token;
3461                                         }
3462                                         else
3463                                         {
3464                                                 bool funorvar = FALSE;
3465
3466                                                 if (yacc_rules
3467                                                     || consider_token (newlb.buffer + tokoff, toklen, c,
3468                                                                        &c_ext, bracelev, parlev,
3469                                                                        &funorvar))
3470                                                 {
3471                                                         if (fvdef == foperator)
3472                                                         {
3473                                                                 char *oldlp = lp;
3474                                                                 lp = skip_spaces (lp-1);
3475                                                                 if (*lp != '\0')
3476                                                                         lp += 1;
3477                                                                 while (*lp != '\0'
3478                                                                        && !iswhite (*lp) && *lp != '(')
3479                                                                         lp += 1;
3480                                                                 c = *lp++;
3481                                                                 toklen += lp - oldlp;
3482                                                         }
3483                                                         token.named = FALSE;
3484                                                         if (!plainc
3485                                                             && nestlev > 0 && definedef == dnone)
3486                                                                 /* in struct body */
3487                                                         {
3488                                                                 write_classname (&token_name, qualifier);
3489                                                                 linebuffer_setlen (&token_name,
3490                                                                                    token_name.len+qlen+toklen);
3491                                                                 strcat (token_name.buffer, qualifier);
3492                                                                 strncat (token_name.buffer,
3493                                                                          newlb.buffer + tokoff, toklen);
3494                                                                 token.named = TRUE;
3495                                                         }
3496                                                         else if (objdef == ocatseen)
3497                                                                 /* Objective C category */
3498                                                         {
3499                                                                 int len = strlen (objtag) + 2 + toklen;
3500                                                                 linebuffer_setlen (&token_name, len);
3501                                                                 strcpy (token_name.buffer, objtag);
3502                                                                 strcat (token_name.buffer, "(");
3503                                                                 strncat (token_name.buffer,
3504                                                                          newlb.buffer + tokoff, toklen);
3505                                                                 strcat (token_name.buffer, ")");
3506                                                                 token.named = TRUE;
3507                                                         }
3508                                                         else if (objdef == omethodtag
3509                                                                  || objdef == omethodparm)
3510                                                                 /* Objective C method */
3511                                                         {
3512                                                                 token.named = TRUE;
3513                                                         }
3514                                                         else if (fvdef == fdefunname)
3515                                                                 /* GNU DEFUN and similar macros */
3516                                                         {
3517                                                                 bool defun = (newlb.buffer[tokoff] == 'F');
3518                                                                 int off = tokoff;
3519                                                                 int len = toklen;
3520
3521                                                                 /* Rewrite the tag so that emacs lisp DEFUNs
3522                                                                    can be found by their elisp name */
3523                                                                 if (defun)
3524                                                                 {
3525                                                                         off += 1;
3526                                                                         len -= 1;
3527                                                                 }
3528                                                                 linebuffer_setlen (&token_name, len);
3529                                                                 strncpy (token_name.buffer,
3530                                                                          newlb.buffer + off, len);
3531                                                                 token_name.buffer[len] = '\0';
3532                                                                 if (defun)
3533                                                                         while (--len >= 0)
3534                                                                                 if (token_name.buffer[len] == '_')
3535                                                                                         token_name.buffer[len] = '-';
3536                                                                 token.named = defun;
3537                                                         }
3538                                                         else
3539                                                         {
3540                                                                 linebuffer_setlen (&token_name, toklen);
3541                                                                 strncpy (token_name.buffer,
3542                                                                          newlb.buffer + tokoff, toklen);
3543                                                                 token_name.buffer[toklen] = '\0';
3544                                                                 /* Name macros and members. */
3545                                                                 token.named = (structdef == stagseen
3546                                                                                || typdef == ttypeseen
3547                                                                                || typdef == tend
3548                                                                                || (funorvar
3549                                                                                    && definedef == dignorerest)
3550                                                                                || (funorvar
3551                                                                                    && definedef == dnone
3552                                                                                    && structdef == snone
3553                                                                                    && bracelev > 0));
3554                                                         }
3555                                                         token.lineno = lineno;
3556                                                         token.offset = tokoff;
3557                                                         token.length = toklen;
3558                                                         token.line = newlb.buffer;
3559                                                         token.linepos = newlinepos;
3560                                                         token.valid = TRUE;
3561
3562                                                         if (definedef == dnone
3563                                                             && (fvdef == fvnameseen
3564                                                                 || fvdef == foperator
3565                                                                 || structdef == stagseen
3566                                                                 || typdef == tend
3567                                                                 || typdef == ttypeseen
3568                                                                 || objdef != onone))
3569                                                         {
3570                                                                 if (current_lb_is_new)
3571                                                                         switch_line_buffers ();
3572                                                         }
3573                                                         else if (definedef != dnone
3574                                                                  || fvdef == fdefunname
3575                                                                  || instruct)
3576                                                                 make_C_tag (funorvar);
3577                                                 }
3578                                                 else /* not yacc and consider_token failed */
3579                                                 {
3580                                                         if (inattribute && fvdef == fignore)
3581                                                         {
3582                                                                 /* We have just met __attribute__ after a
3583                                                                    function parameter list: do not tag the
3584                                                                    function again. */
3585                                                                 fvdef = fvnone;
3586                                                         }
3587                                                 }
3588                                                 midtoken = FALSE;
3589                                         }
3590                                 } /* if (endtoken (c)) */
3591                                 else if (intoken (c))
3592                                 still_in_token:
3593                                 {
3594                                         toklen++;
3595                                         continue;
3596                                 }
3597                         } /* if (midtoken) */
3598                         else if (begtoken (c))
3599                         {
3600                                 switch (definedef)
3601                                 {
3602                                 case dnone:
3603                                         switch (fvdef)
3604                                         {
3605                                         case fstartlist:
3606                                                 /* This prevents tagging fb in
3607                                                    void (__attribute__((noreturn)) *fb) (void);
3608                                                    Fixing this is not easy and not very important. */
3609                                                 fvdef = finlist;
3610                                                 continue;
3611                                         case flistseen:
3612                                                 if (plainc || declarations)
3613                                                 {
3614                                                         make_C_tag (TRUE); /* a function */
3615                                                         fvdef = fignore;
3616                                                 }
3617                                                 break;
3618
3619                                                 /* all the rest */
3620                                         case fvnone:
3621                                         case fdefunkey:
3622                                         case fdefunname:
3623                                         case foperator:
3624                                         case fvnameseen:
3625                                         case finlist:
3626                                         case fignore:
3627                                         case vignore:
3628                                         default:
3629                                                 break;
3630                                         }
3631                                         if (structdef == stagseen && !cjava)
3632                                         {
3633                                                 popclass_above (bracelev);
3634                                                 structdef = snone;
3635                                         }
3636                                         break;
3637                                 case dsharpseen:
3638                                         savetoken = token;
3639                                         break;
3640
3641                                         /* all the rest */
3642                                 case ddefineseen:
3643                                 case dignorerest:
3644                                 default:
3645                                         break;
3646                                 }
3647                                 if (!yacc_rules || lp == newlb.buffer + 1)
3648                                 {
3649                                         tokoff = lp - 1 - newlb.buffer;
3650                                         toklen = 1;
3651                                         midtoken = TRUE;
3652                                 }
3653                                 continue;
3654                         } /* if (begtoken) */
3655                 } /* if must look at token */
3656
3657
3658                 /* Detect end of line, colon, comma, semicolon and various braces
3659                    after having handled a token.*/
3660                 switch (c)
3661                 {
3662                 case ':':
3663                         if (inattribute)
3664                                 break;
3665                         if (yacc_rules && token.offset == 0 && token.valid)
3666                         {
3667                                 make_C_tag (FALSE); /* a yacc function */
3668                                 break;
3669                         }
3670                         if (definedef != dnone)
3671                                 break;
3672                         switch (objdef)
3673                         {
3674                         case  otagseen:
3675                                 objdef = oignore;
3676                                 make_C_tag (TRUE); /* an Objective C class */
3677                                 break;
3678                         case omethodtag:
3679                         case omethodparm:
3680                                 objdef = omethodcolon;
3681                                 linebuffer_setlen (&token_name, token_name.len + 1);
3682                                 strcat (token_name.buffer, ":");
3683                                 break;
3684
3685                                 /* all the rest */
3686                         case onone:
3687                         case oprotocol:
3688                         case oimplementation:
3689                         case oparenseen:
3690                         case ocatseen:
3691                         case oinbody:
3692                         case omethodsign:
3693                         case omethodcolon:
3694                         case oignore:
3695                         default:
3696                                 break;
3697                         }
3698                         if (structdef == stagseen)
3699                         {
3700                                 structdef = scolonseen;
3701                                 break;
3702                         }
3703                         /* Should be useless, but may be work as a safety net. */
3704                         if (cplpl && fvdef == flistseen)
3705                         {
3706                                 make_C_tag (TRUE); /* a function */
3707                                 fvdef = fignore;
3708                                 break;
3709                         }
3710                         break;
3711                 case ';':
3712                         if (definedef != dnone || inattribute)
3713                                 break;
3714                         switch (typdef)
3715                         {
3716                         case tend:
3717                         case ttypeseen:
3718                                 make_C_tag (FALSE); /* a typedef */
3719                                 typdef = tnone;
3720                                 fvdef = fvnone;
3721                                 break;
3722                         case tnone:
3723                         case tinbody:
3724                         case tignore:
3725                                 switch (fvdef)
3726                                 {
3727                                 case fignore:
3728                                         if (typdef == tignore || cplpl)
3729                                                 fvdef = fvnone;
3730                                         break;
3731                                 case fvnameseen:
3732                                         if ((globals && bracelev == 0 && (!fvextern || declarations))
3733                                             || (members && instruct))
3734                                                 make_C_tag (FALSE); /* a variable */
3735                                         fvextern = FALSE;
3736                                         fvdef = fvnone;
3737                                         token.valid = FALSE;
3738                                         break;
3739                                 case flistseen:
3740                                         if ((declarations
3741                                              && (cplpl || !instruct)
3742                                              && (typdef == tnone || (typdef != tignore && instruct)))
3743                                             || (members
3744                                                 && plainc && instruct))
3745                                                 make_C_tag (TRUE);  /* a function */
3746                                         /* FALLTHRU */
3747                                 case fvnone:
3748                                 case fdefunkey:
3749                                 case fdefunname:
3750                                 case foperator:
3751                                 case fstartlist:
3752                                 case finlist:
3753                                 case vignore:
3754                                 default:
3755                                         fvextern = FALSE;
3756                                         fvdef = fvnone;
3757                                         if (declarations
3758                                             && cplpl && structdef == stagseen)
3759                                                 make_C_tag (FALSE);     /* forward declaration */
3760                                         else
3761                                                 token.valid = FALSE;
3762                                 } /* switch (fvdef) */
3763                                 /* FALLTHRU */
3764                         case tkeyseen:
3765                         default:
3766                                 if (!instruct)
3767                                         typdef = tnone;
3768                         }
3769                         if (structdef == stagseen)
3770                                 structdef = snone;
3771                         break;
3772                 case ',':
3773                         if (definedef != dnone || inattribute)
3774                                 break;
3775                         switch (objdef)
3776                         {
3777                         case omethodtag:
3778                         case omethodparm:
3779                                 make_C_tag (TRUE); /* an Objective C method */
3780                                 objdef = oinbody;
3781                                 break;
3782
3783                                 /* all the rest */
3784                         case onone:
3785                         case oprotocol:
3786                         case oimplementation:
3787                         case otagseen:
3788                         case oparenseen:
3789                         case ocatseen:
3790                         case oinbody:
3791                         case omethodsign:
3792                         case omethodcolon:
3793                         case oignore:
3794                         default:
3795                                 break;
3796                         }
3797                         switch (fvdef)
3798                         {
3799                         case fdefunkey:
3800                         case foperator:
3801                         case fstartlist:
3802                         case finlist:
3803                         case fignore:
3804                         case vignore:
3805                                 break;
3806                         case fdefunname:
3807                                 fvdef = fignore;
3808                                 break;
3809                         case fvnameseen:
3810                                 if (parlev == 0
3811                                     && ((globals
3812                                          && bracelev == 0
3813                                          && templatelev == 0
3814                                          && (!fvextern || declarations))
3815                                         || (members && instruct)))
3816                                         make_C_tag (FALSE); /* a variable */
3817                                 break;
3818                         case flistseen:
3819                                 if ((declarations && typdef == tnone && !instruct)
3820                                     || (members && typdef != tignore && instruct))
3821                                 {
3822                                         make_C_tag (TRUE); /* a function */
3823                                         fvdef = fvnameseen;
3824                                 }
3825                                 else if (!declarations)
3826                                         fvdef = fvnone;
3827                                 token.valid = FALSE;
3828                                 break;
3829                         case fvnone:
3830                         default:
3831                                 fvdef = fvnone;
3832                         }
3833                         if (structdef == stagseen)
3834                                 structdef = snone;
3835                         break;
3836                 case ']':
3837                         if (definedef != dnone || inattribute)
3838                                 break;
3839                         if (structdef == stagseen)
3840                                 structdef = snone;
3841                         switch (typdef)
3842                         {
3843                         case ttypeseen:
3844                         case tend:
3845                                 typdef = tignore;
3846                                 make_C_tag (FALSE);     /* a typedef */
3847                                 break;
3848                         case tnone:
3849                         case tinbody:
3850                                 switch (fvdef)
3851                                 {
3852                                 case foperator:
3853                                 case finlist:
3854                                 case fignore:
3855                                 case vignore:
3856                                         break;
3857                                 case fvnameseen:
3858                                         if ((members && bracelev == 1)
3859                                             || (globals && bracelev == 0
3860                                                 && (!fvextern || declarations)))
3861                                                 make_C_tag (FALSE); /* a variable */
3862                                         /* FALLTHRU */
3863                                 case fvnone:
3864                                 case fdefunkey:
3865                                 case fdefunname:
3866                                 case fstartlist:
3867                                 case flistseen:
3868                                 default:
3869                                         fvdef = fvnone;
3870                                 }
3871                                 break;
3872
3873                                 /* all the rest */
3874                         case tkeyseen:
3875                         case tignore:
3876                         default:
3877                                 break;
3878                         }
3879                         break;
3880                 case '(':
3881                         if (inattribute)
3882                         {
3883                                 attrparlev++;
3884                                 break;
3885                         }
3886                         if (definedef != dnone)
3887                                 break;
3888                         if (objdef == otagseen && parlev == 0)
3889                                 objdef = oparenseen;
3890                         switch (fvdef)
3891                         {
3892                         case fvnameseen:
3893                                 if (typdef == ttypeseen
3894                                     && *lp != '*'
3895                                     && !instruct)
3896                                 {
3897                                         /* This handles constructs like:
3898                                            typedef void OperatorFun (int fun); */
3899                                         make_C_tag (FALSE);
3900                                         typdef = tignore;
3901                                         fvdef = fignore;
3902                                         break;
3903                                 }
3904                                 /* FALLTHRU */
3905                         case foperator:
3906                                 fvdef = fstartlist;
3907                                 break;
3908                         case flistseen:
3909                                 fvdef = finlist;
3910                                 break;
3911
3912                                 /* all the rest */
3913                         case fvnone:
3914                         case fdefunkey:
3915                         case fdefunname:
3916                         case fstartlist:
3917                         case finlist:
3918                         case fignore:
3919                         case vignore:
3920                         default:
3921                                 break;
3922                         }
3923                         parlev++;
3924                         break;
3925                 case ')':
3926                         if (inattribute)
3927                         {
3928                                 if (--attrparlev == 0)
3929                                         inattribute = FALSE;
3930                                 break;
3931                         }
3932                         if (definedef != dnone)
3933                                 break;
3934                         if (objdef == ocatseen && parlev == 1)
3935                         {
3936                                 make_C_tag (TRUE); /* an Objective C category */
3937                                 objdef = oignore;
3938                         }
3939                         if (--parlev == 0)
3940                         {
3941                                 switch (fvdef)
3942                                 {
3943                                 case fstartlist:
3944                                 case finlist:
3945                                         fvdef = flistseen;
3946                                         break;
3947
3948                                         /* all the rest */
3949                                 case fvnone:
3950                                 case fdefunkey:
3951                                 case fdefunname:
3952                                 case foperator:
3953                                 case fvnameseen:
3954                                 case flistseen:
3955                                 case fignore:
3956                                 case vignore:
3957                                 default:
3958                                         break;
3959                                 }
3960                                 if (!instruct
3961                                     && (typdef == tend
3962                                         || typdef == ttypeseen))
3963                                 {
3964                                         typdef = tignore;
3965                                         make_C_tag (FALSE); /* a typedef */
3966                                 }
3967                         }
3968                         else if (parlev < 0)    /* can happen due to ill-conceived #if's. */
3969                                 parlev = 0;
3970                         break;
3971                 case '{':
3972                         if (definedef != dnone)
3973                                 break;
3974                         if (typdef == ttypeseen)
3975                         {
3976                                 /* Whenever typdef is set to tinbody (currently only
3977                                    here), typdefbracelev should be set to bracelev. */
3978                                 typdef = tinbody;
3979                                 typdefbracelev = bracelev;
3980                         }
3981                         switch (fvdef)
3982                         {
3983                         case flistseen:
3984                                 make_C_tag (TRUE);    /* a function */
3985                                 /* FALLTHRU */
3986                         case fignore:
3987                                 fvdef = fvnone;
3988                                 break;
3989                         case fvnone:
3990                                 switch (objdef)
3991                                 {
3992                                 case otagseen:
3993                                         make_C_tag (TRUE); /* an Objective C class */
3994                                         objdef = oignore;
3995                                         break;
3996                                 case omethodtag:
3997                                 case omethodparm:
3998                                         make_C_tag (TRUE); /* an Objective C method */
3999                                         objdef = oinbody;
4000                                         break;
4001                                 case onone:
4002                                 case oprotocol:
4003                                 case oimplementation:
4004                                 case oparenseen:
4005                                 case ocatseen:
4006                                 case oinbody:
4007                                 case omethodsign:
4008                                 case omethodcolon:
4009                                 case oignore:
4010                                 default:
4011                                         /* Neutralize `extern "C" {' grot. */
4012                                         if (bracelev == 0 && structdef == snone && nestlev == 0
4013                                             && typdef == tnone)
4014                                                 bracelev = -1;
4015                                 }
4016                                 break;
4017
4018                                 /* all the rest */
4019                         case fdefunkey:
4020                         case fdefunname:
4021                         case foperator:
4022                         case fvnameseen:
4023                         case fstartlist:
4024                         case finlist:
4025                         case vignore:
4026                         default:
4027                                 break;
4028                         }
4029                         switch (structdef)
4030                         {
4031                         case skeyseen:     /* unnamed struct */
4032                                 pushclass_above (bracelev, NULL, 0);
4033                                 structdef = snone;
4034                                 break;
4035                         case stagseen:     /* named struct or enum */
4036                         case scolonseen:           /* a class */
4037                                 pushclass_above (bracelev,token.line+token.offset, token.length);
4038                                 structdef = snone;
4039                                 make_C_tag (FALSE);  /* a struct or enum */
4040                                 break;
4041
4042                                 /* all the rest */
4043                         case snone:
4044                         default:
4045                                 break;
4046                         }
4047                         bracelev += 1;
4048                         break;
4049                 case '*':
4050                         if (definedef != dnone)
4051                                 break;
4052                         if (fvdef == fstartlist)
4053                         {
4054                                 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
4055                                 token.valid = FALSE;
4056                         }
4057                         break;
4058                 case '}':
4059                         if (definedef != dnone)
4060                                 break;
4061                         bracelev -= 1;
4062                         if (!ignoreindent && lp == newlb.buffer + 1)
4063                         {
4064                                 if (bracelev != 0)
4065                                         token.valid = FALSE; /* unexpected value, token unreliable */
4066                                 bracelev = 0;   /* reset brace level if first column */
4067                                 parlev = 0;     /* also reset paren level, just in case... */
4068                         }
4069                         else if (bracelev < 0)
4070                         {
4071                                 token.valid = FALSE; /* something gone amiss, token unreliable */
4072                                 bracelev = 0;
4073                         }
4074                         if (bracelev == 0 && fvdef == vignore)
4075                                 fvdef = fvnone;         /* end of function */
4076                         popclass_above (bracelev);
4077                         structdef = snone;
4078                         /* Only if typdef == tinbody is typdefbracelev significant. */
4079                         if (typdef == tinbody && bracelev <= typdefbracelev)
4080                         {
4081                                 assert (bracelev == typdefbracelev);
4082                                 typdef = tend;
4083                         }
4084                         break;
4085                 case '=':
4086                         if (definedef != dnone)
4087                                 break;
4088                         switch (fvdef)
4089                         {
4090                         case foperator:
4091                         case finlist:
4092                         case fignore:
4093                         case vignore:
4094                                 break;
4095                         case fvnameseen:
4096                                 if ((members && bracelev == 1)
4097                                     || (globals && bracelev == 0 && (!fvextern || declarations)))
4098                                         make_C_tag (FALSE); /* a variable */
4099                                 /* FALLTHRU */
4100                         case fvnone:
4101                         case fdefunkey:
4102                         case fdefunname:
4103                         case fstartlist:
4104                         case flistseen:
4105                         default:
4106                                 fvdef = vignore;
4107                         }
4108                         break;
4109                 case '<':
4110                         if (cplpl
4111                             && (structdef == stagseen || fvdef == fvnameseen))
4112                         {
4113                                 templatelev++;
4114                                 break;
4115                         }
4116                         goto resetfvdef;
4117                 case '>':
4118                         if (templatelev > 0)
4119                         {
4120                                 templatelev--;
4121                                 break;
4122                         }
4123                         goto resetfvdef;
4124                 case '+':
4125                 case '-':
4126                         if (objdef == oinbody && bracelev == 0)
4127                         {
4128                                 objdef = omethodsign;
4129                                 break;
4130                         }
4131                         /* FALLTHRU */
4132                 resetfvdef:
4133                 case '#': case '~': case '&': case '%': case '/':
4134                 case '|': case '^': case '!': case '.': case '?':
4135                         if (definedef != dnone)
4136                                 break;
4137                         /* These surely cannot follow a function tag in C. */
4138                         switch (fvdef)
4139                         {
4140                         case foperator:
4141                         case finlist:
4142                         case fignore:
4143                         case vignore:
4144                                 break;
4145                         case fvnone:
4146                         case fdefunkey:
4147                         case fdefunname:
4148                         case fvnameseen:
4149                         case fstartlist:
4150                         case flistseen:
4151                         default:
4152                                 fvdef = fvnone;
4153                         }
4154                         break;
4155                 case '\0':
4156                         if (objdef == otagseen)
4157                         {
4158                                 make_C_tag (TRUE); /* an Objective C class */
4159                                 objdef = oignore;
4160                         }
4161                         /* If a macro spans multiple lines don't reset its state. */
4162                         if (quotednl)
4163                                 CNL_SAVE_DEFINEDEF ();
4164                         else
4165                                 CNL ();
4166                         break;
4167                 default:
4168                         break;
4169                 } /* switch (c) */
4170
4171         } /* while not eof */
4172
4173         free (lbs[0].lb.buffer);
4174         free (lbs[1].lb.buffer);
4175 }
4176
4177 /*
4178  * Process either a C++ file or a C file depending on the setting
4179  * of a global flag.
4180  */
4181 static void
4182 default_C_entries (inf)
4183 FILE *inf;
4184 {
4185         C_entries (cplusplus ? C_PLPL : C_AUTO, inf);
4186 }
4187
4188 /* Always do plain C. */
4189 static void
4190 plain_C_entries (inf)
4191 FILE *inf;
4192 {
4193         C_entries (0, inf);
4194 }
4195
4196 /* Always do C++. */
4197 static void
4198 Cplusplus_entries (inf)
4199 FILE *inf;
4200 {
4201         C_entries (C_PLPL, inf);
4202 }
4203
4204 /* Always do Java. */
4205 static void
4206 Cjava_entries (inf)
4207 FILE *inf;
4208 {
4209         C_entries (C_JAVA, inf);
4210 }
4211
4212 /* Always do C*. */
4213 static void
4214 Cstar_entries (inf)
4215 FILE *inf;
4216 {
4217         C_entries (C_STAR, inf);
4218 }
4219
4220 /* Always do Yacc. */
4221 static void
4222 Yacc_entries (inf)
4223 FILE *inf;
4224 {
4225         C_entries (YACC, inf);
4226 }
4227
4228 \f
4229 /* Useful macros. */
4230 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer)    \
4231         for (;                  /* loop initialization */               \
4232              !feof (file_pointer)       /* loop test */                 \
4233                      &&                 /* instructions at start of loop */ \
4234                      (readline (&line_buffer, file_pointer),            \
4235                       char_pointer = line_buffer.buffer,                \
4236                       TRUE);                                            \
4237                 )
4238
4239 #define LOOKING_AT(cp, kw)  /* kw is the keyword, a literal string */   \
4240         ((assert("" kw), TRUE)   /* syntax error if not a literal string */ \
4241          && strneq ((cp), kw, sizeof(kw)-1)             /* cp points at kw */ \
4242          && notinname ((cp)[sizeof(kw)-1])              /* end of kw */ \
4243          && ((cp) = skip_spaces((cp)+sizeof(kw)-1)))    /* skip spaces */
4244
4245 /* Similar to LOOKING_AT but does not use notinname, does not skip */
4246 #define LOOKING_AT_NOCASE(cp, kw) /* the keyword is a literal string */ \
4247         ((assert("" kw), TRUE)     /* syntax error if not a literal string */ \
4248          && strncaseeq ((cp), kw, sizeof(kw)-1) /* cp points at kw */   \
4249          && ((cp) += sizeof(kw)-1))                     /* skip spaces */
4250
4251 /*
4252  * Read a file, but do no processing.  This is used to do regexp
4253  * matching on files that have no language defined.
4254  */
4255 static void
4256 just_read_file (inf)
4257 FILE *inf;
4258 {
4259         register char *dummy;
4260
4261         LOOP_ON_INPUT_LINES (inf, lb, dummy)
4262                 continue;
4263 }
4264
4265 \f
4266 /* Fortran parsing */
4267
4268 static void F_takeprec __P((void));
4269 static void F_getit __P((FILE *));
4270
4271 static void
4272 F_takeprec ()
4273 {
4274         dbp = skip_spaces (dbp);
4275         if (*dbp != '*')
4276                 return;
4277         dbp++;
4278         dbp = skip_spaces (dbp);
4279         if (strneq (dbp, "(*)", 3))
4280         {
4281                 dbp += 3;
4282                 return;
4283         }
4284         if (!ISDIGIT (*dbp))
4285         {
4286                 --dbp;                  /* force failure */
4287                 return;
4288         }
4289         do
4290                 dbp++;
4291         while (ISDIGIT (*dbp));
4292 }
4293
4294 static void
4295 F_getit (inf)
4296 FILE *inf;
4297 {
4298         register char *cp;
4299
4300         dbp = skip_spaces (dbp);
4301         if (*dbp == '\0')
4302         {
4303                 readline (&lb, inf);
4304                 dbp = lb.buffer;
4305                 if (dbp[5] != '&')
4306                         return;
4307                 dbp += 6;
4308                 dbp = skip_spaces (dbp);
4309         }
4310         if (!ISALPHA (*dbp) && *dbp != '_' && *dbp != '$')
4311                 return;
4312         for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
4313                 continue;
4314         make_tag (dbp, cp-dbp, TRUE,
4315                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4316 }
4317
4318
4319 static void
4320 Fortran_functions (inf)
4321 FILE *inf;
4322 {
4323         LOOP_ON_INPUT_LINES (inf, lb, dbp)
4324         {
4325                 if (*dbp == '%')
4326                         dbp++;                  /* Ratfor escape to fortran */
4327                 dbp = skip_spaces (dbp);
4328                 if (*dbp == '\0')
4329                         continue;
4330                 switch (lowcase (*dbp))
4331                 {
4332                 case 'i':
4333                         if (nocase_tail ("integer"))
4334                                 F_takeprec ();
4335                         break;
4336                 case 'r':
4337                         if (nocase_tail ("real"))
4338                                 F_takeprec ();
4339                         break;
4340                 case 'l':
4341                         if (nocase_tail ("logical"))
4342                                 F_takeprec ();
4343                         break;
4344                 case 'c':
4345                         if (nocase_tail ("complex") || nocase_tail ("character"))
4346                                 F_takeprec ();
4347                         break;
4348                 case 'd':
4349                         if (nocase_tail ("double"))
4350                         {
4351                                 dbp = skip_spaces (dbp);
4352                                 if (*dbp == '\0')
4353                                         continue;
4354                                 if (nocase_tail ("precision"))
4355                                         break;
4356                                 continue;
4357                         }
4358                         break;
4359                 default:
4360                         break;
4361                 }
4362                 dbp = skip_spaces (dbp);
4363                 if (*dbp == '\0')
4364                         continue;
4365                 switch (lowcase (*dbp))
4366                 {
4367                 case 'f':
4368                         if (nocase_tail ("function"))
4369                                 F_getit (inf);
4370                         continue;
4371                 case 's':
4372                         if (nocase_tail ("subroutine"))
4373                                 F_getit (inf);
4374                         continue;
4375                 case 'e':
4376                         if (nocase_tail ("entry"))
4377                                 F_getit (inf);
4378                         continue;
4379                 case 'b':
4380                         if (nocase_tail ("blockdata") || nocase_tail ("block data"))
4381                         {
4382                                 dbp = skip_spaces (dbp);
4383                                 if (*dbp == '\0')       /* assume un-named */
4384                                         make_tag ("blockdata", 9, TRUE,
4385                                                   lb.buffer, dbp - lb.buffer, lineno, linecharno);
4386                                 else
4387                                         F_getit (inf);  /* look for name */
4388                         }
4389                         continue;
4390                 default:
4391                         break;
4392                 }
4393         }
4394 }
4395
4396 \f
4397 /*
4398  * Ada parsing
4399  * Original code by
4400  * Philippe Waroquiers (1998)
4401  */
4402
4403 static void Ada_getit __P((FILE *, char *));
4404
4405 /* Once we are positioned after an "interesting" keyword, let's get
4406    the real tag value necessary. */
4407 static void
4408 Ada_getit (inf, name_qualifier)
4409 FILE *inf;
4410 char *name_qualifier;
4411 {
4412         register char *cp;
4413         char *name;
4414         char c;
4415
4416         while (!feof (inf))
4417         {
4418                 dbp = skip_spaces (dbp);
4419                 if (*dbp == '\0'
4420                     || (dbp[0] == '-' && dbp[1] == '-'))
4421                 {
4422                         readline (&lb, inf);
4423                         dbp = lb.buffer;
4424                 }
4425                 switch (lowcase(*dbp))
4426                 {
4427                 case 'b':
4428                         if (nocase_tail ("body"))
4429                         {
4430                                 /* Skipping body of   procedure body   or   package body or ....
4431                                    resetting qualifier to body instead of spec. */
4432                                 name_qualifier = "/b";
4433                                 continue;
4434                         }
4435                         break;
4436                 case 't':
4437                         /* Skipping type of   task type   or   protected type ... */
4438                         if (nocase_tail ("type"))
4439                                 continue;
4440                         break;
4441                 default:
4442                         break;
4443                 }
4444                 if (*dbp == '"')
4445                 {
4446                         dbp += 1;
4447                         for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
4448                                 continue;
4449                 }
4450                 else
4451                 {
4452                         dbp = skip_spaces (dbp);
4453                         for (cp = dbp;
4454                              (*cp != '\0'
4455                               && (ISALPHA (*cp) || ISDIGIT (*cp) || *cp == '_' || *cp == '.'));
4456                              cp++)
4457                                 continue;
4458                         if (cp == dbp)
4459                                 return;
4460                 }
4461                 c = *cp;
4462                 *cp = '\0';
4463                 name = concat (dbp, name_qualifier, "");
4464                 *cp = c;
4465                 make_tag (name, strlen (name), TRUE,
4466                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4467                 free (name);
4468                 if (c == '"')
4469                         dbp = cp + 1;
4470                 return;
4471         }
4472 }
4473
4474 static void
4475 Ada_funcs (inf)
4476 FILE *inf;
4477 {
4478         bool inquote = FALSE;
4479         bool skip_till_semicolumn = FALSE;
4480
4481         LOOP_ON_INPUT_LINES (inf, lb, dbp)
4482         {
4483                 while (*dbp != '\0')
4484                 {
4485                         /* Skip a string i.e. "abcd". */
4486                         if (inquote || (*dbp == '"'))
4487                         {
4488                                 dbp = etags_strchr ((inquote) ? dbp : dbp+1, '"');
4489                                 if (dbp != NULL)
4490                                 {
4491                                         inquote = FALSE;
4492                                         dbp += 1;
4493                                         continue;       /* advance char */
4494                                 }
4495                                 else
4496                                 {
4497                                         inquote = TRUE;
4498                                         break;  /* advance line */
4499                                 }
4500                         }
4501
4502                         /* Skip comments. */
4503                         if (dbp[0] == '-' && dbp[1] == '-')
4504                                 break;          /* advance line */
4505
4506                         /* Skip character enclosed in single quote i.e. 'a'
4507                            and skip single quote starting an attribute i.e. 'Image. */
4508                         if (*dbp == '\'')
4509                         {
4510                                 dbp++ ;
4511                                 if (*dbp != '\0')
4512                                         dbp++;
4513                                 continue;
4514                         }
4515
4516                         if (skip_till_semicolumn)
4517                         {
4518                                 if (*dbp == ';')
4519                                         skip_till_semicolumn = FALSE;
4520                                 dbp++;
4521                                 continue;         /* advance char */
4522                         }
4523
4524                         /* Search for beginning of a token.  */
4525                         if (!begtoken (*dbp))
4526                         {
4527                                 dbp++;
4528                                 continue;               /* advance char */
4529                         }
4530
4531                         /* We are at the beginning of a token. */
4532                         switch (lowcase(*dbp))
4533                         {
4534                         case 'f':
4535                                 if (!packages_only && nocase_tail ("function"))
4536                                         Ada_getit (inf, "/f");
4537                                 else
4538                                         break;          /* from switch */
4539                                 continue;               /* advance char */
4540                         case 'p':
4541                                 if (!packages_only && nocase_tail ("procedure"))
4542                                         Ada_getit (inf, "/p");
4543                                 else if (nocase_tail ("package"))
4544                                         Ada_getit (inf, "/s");
4545                                 else if (nocase_tail ("protected")) /* protected type */
4546                                         Ada_getit (inf, "/t");
4547                                 else
4548                                         break;          /* from switch */
4549                                 continue;               /* advance char */
4550
4551                         case 'u':
4552                                 if (typedefs && !packages_only && nocase_tail ("use"))
4553                                 {
4554                                         /* when tagging types, avoid tagging  use type Pack.Typename;
4555                                            for this, we will skip everything till a ; */
4556                                         skip_till_semicolumn = TRUE;
4557                                         continue;     /* advance char */
4558                                 }
4559
4560                         case 't':
4561                                 if (!packages_only && nocase_tail ("task"))
4562                                         Ada_getit (inf, "/k");
4563                                 else if (typedefs && !packages_only && nocase_tail ("type"))
4564                                 {
4565                                         Ada_getit (inf, "/t");
4566                                         while (*dbp != '\0')
4567                                                 dbp += 1;
4568                                 }
4569                                 else
4570                                         break;          /* from switch */
4571                                 continue;               /* advance char */
4572                         default:
4573                                 break;
4574                         }
4575
4576                         /* Look for the end of the token. */
4577                         while (!endtoken (*dbp))
4578                                 dbp++;
4579
4580                 } /* advance char */
4581         } /* advance line */
4582 }
4583
4584 \f
4585 /*
4586  * Unix and microcontroller assembly tag handling
4587  * Labels:  /^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]/
4588  * Idea by Bob Weiner, Motorola Inc. (1994)
4589  */
4590 static void
4591 Asm_labels (inf)
4592 FILE *inf;
4593 {
4594         register char *cp;
4595
4596         LOOP_ON_INPUT_LINES (inf, lb, cp)
4597         {
4598                 /* If first char is alphabetic or one of [_.$], test for colon
4599                    following identifier. */
4600                 if (ISALPHA (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4601                 {
4602                         /* Read past label. */
4603                         cp++;
4604                         while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4605                                 cp++;
4606                         if (*cp == ':' || iswhite (*cp))
4607                                 /* Found end of label, so copy it and add it to the table. */
4608                                 make_tag (lb.buffer, cp - lb.buffer, TRUE,
4609                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4610                 }
4611         }
4612 }
4613
4614 \f
4615 /*
4616  * Perl support
4617  * Perl sub names: /^sub[ \t\n]+[^ \t\n{]+/
4618  * Perl variable names: /^(my|local).../
4619  * Original code by Bart Robinson <lomew@cs.utah.edu> (1995)
4620  * Additions by Michael Ernst <mernst@alum.mit.edu> (1997)
4621  * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
4622  */
4623 static void
4624 Perl_functions (inf)
4625 FILE *inf;
4626 {
4627         char *package = savestr ("main"); /* current package name */
4628         register char *cp;
4629
4630         LOOP_ON_INPUT_LINES (inf, lb, cp)
4631         {
4632                 cp = skip_spaces (cp);
4633
4634                 if (LOOKING_AT (cp, "package"))
4635                 {
4636                         free (package);
4637                         get_tag (cp, &package);
4638                 }
4639                 else if (LOOKING_AT (cp, "sub"))
4640                 {
4641                         char *pos;
4642                         char *sp = cp;
4643
4644                         while (!notinname (*cp))
4645                                 cp++;
4646                         if (cp == sp)
4647                                 continue;               /* nothing found */
4648                         if ((pos = etags_strchr (sp, ':')) != NULL
4649                             && pos < cp && pos[1] == ':')
4650                                 /* The name is already qualified. */
4651                                 make_tag (sp, cp - sp, TRUE,
4652                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4653                         else
4654                                 /* Qualify it. */
4655                         {
4656                                 char savechar, *name;
4657
4658                                 savechar = *cp;
4659                                 *cp = '\0';
4660                                 name = concat (package, "::", sp);
4661                                 *cp = savechar;
4662                                 make_tag (name, strlen(name), TRUE,
4663                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4664                                 free (name);
4665                         }
4666                 }
4667                 else if (globals)       /* only if we are tagging global vars */
4668                 {
4669                         /* Skip a qualifier, if any. */
4670                         bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
4671                         /* After "my" or "local", but before any following paren or space. */
4672                         char *varstart = cp;
4673
4674                         if (qual                /* should this be removed?  If yes, how? */
4675                             && (*cp == '$' || *cp == '@' || *cp == '%'))
4676                         {
4677                                 varstart += 1;
4678                                 do
4679                                         cp++;
4680                                 while (ISALNUM (*cp) || *cp == '_');
4681                         }
4682                         else if (qual)
4683                         {
4684                                 /* Should be examining a variable list at this point;
4685                                    could insist on seeing an open parenthesis. */
4686                                 while (*cp != '\0' && *cp != ';' && *cp != '=' &&  *cp != ')')
4687                                         cp++;
4688                         }
4689                         else
4690                                 continue;
4691
4692                         make_tag (varstart, cp - varstart, FALSE,
4693                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4694                 }
4695         }
4696         free (package);
4697 }
4698
4699
4700 /*
4701  * Python support
4702  * Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
4703  * Idea by Eric S. Raymond <esr@thyrsus.com> (1997)
4704  * More ideas by seb bacon <seb@jamkit.com> (2002)
4705  */
4706 static void
4707 Python_functions (inf)
4708 FILE *inf;
4709 {
4710         register char *cp;
4711
4712         LOOP_ON_INPUT_LINES (inf, lb, cp)
4713         {
4714                 cp = skip_spaces (cp);
4715                 if (LOOKING_AT (cp, "def") || LOOKING_AT (cp, "class"))
4716                 {
4717                         char *name = cp;
4718                         while (!notinname (*cp) && *cp != ':')
4719                                 cp++;
4720                         make_tag (name, cp - name, TRUE,
4721                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4722                 }
4723         }
4724 }
4725
4726 \f
4727 /*
4728  * PHP support
4729  * Look for:
4730  *  - /^[ \t]*function[ \t\n]+[^ \t\n(]+/
4731  *  - /^[ \t]*class[ \t\n]+[^ \t\n]+/
4732  *  - /^[ \t]*define\(\"[^\"]+/
4733  * Only with --members:
4734  *  - /^[ \t]*var[ \t\n]+\$[^ \t\n=;]/
4735  * Idea by Diez B. Roggisch (2001)
4736  */
4737 static void
4738 PHP_functions (inf)
4739 FILE *inf;
4740 {
4741         register char *cp, *name;
4742         bool search_identifier = FALSE;
4743
4744         LOOP_ON_INPUT_LINES (inf, lb, cp)
4745         {
4746                 cp = skip_spaces (cp);
4747                 name = cp;
4748                 if (search_identifier
4749                     && *cp != '\0')
4750                 {
4751                         while (!notinname (*cp))
4752                                 cp++;
4753                         make_tag (name, cp - name, TRUE,
4754                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4755                         search_identifier = FALSE;
4756                 }
4757                 else if (LOOKING_AT (cp, "function"))
4758                 {
4759                         if(*cp == '&')
4760                                 cp = skip_spaces (cp+1);
4761                         if(*cp != '\0')
4762                         {
4763                                 name = cp;
4764                                 while (!notinname (*cp))
4765                                         cp++;
4766                                 make_tag (name, cp - name, TRUE,
4767                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4768                         }
4769                         else
4770                                 search_identifier = TRUE;
4771                 }
4772                 else if (LOOKING_AT (cp, "class"))
4773                 {
4774                         if (*cp != '\0')
4775                         {
4776                                 name = cp;
4777                                 while (*cp != '\0' && !iswhite (*cp))
4778                                         cp++;
4779                                 make_tag (name, cp - name, FALSE,
4780                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4781                         }
4782                         else
4783                                 search_identifier = TRUE;
4784                 }
4785                 else if (strneq (cp, "define", 6)
4786                          && (cp = skip_spaces (cp+6))
4787                          && *cp++ == '('
4788                          && (*cp == '"' || *cp == '\''))
4789                 {
4790                         char quote = *cp++;
4791                         name = cp;
4792                         while (*cp != quote && *cp != '\0')
4793                                 cp++;
4794                         make_tag (name, cp - name, FALSE,
4795                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4796                 }
4797                 else if (members
4798                          && LOOKING_AT (cp, "var")
4799                          && *cp == '$')
4800                 {
4801                         name = cp;
4802                         while (!notinname(*cp))
4803                                 cp++;
4804                         make_tag (name, cp - name, FALSE,
4805                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4806                 }
4807         }
4808 }
4809
4810 \f
4811 /*
4812  * Cobol tag functions
4813  * We could look for anything that could be a paragraph name.
4814  * i.e. anything that starts in column 8 is one word and ends in a full stop.
4815  * Idea by Corny de Souza (1993)
4816  */
4817 static void
4818 Cobol_paragraphs (inf)
4819 FILE *inf;
4820 {
4821         register char *bp, *ep;
4822
4823         LOOP_ON_INPUT_LINES (inf, lb, bp)
4824         {
4825                 if (lb.len < 9)
4826                         continue;
4827                 bp += 8;
4828
4829                 /* If eoln, compiler option or comment ignore whole line. */
4830                 if (bp[-1] != ' ' || !ISALNUM (bp[0]))
4831                         continue;
4832
4833                 for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
4834                         continue;
4835                 if (*ep++ == '.')
4836                         make_tag (bp, ep - bp, TRUE,
4837                                   lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4838         }
4839 }
4840
4841 \f
4842 /*
4843  * Makefile support
4844  * Ideas by Assar Westerlund <assar@sics.se> (2001)
4845  */
4846 static void
4847 Makefile_targets (inf)
4848 FILE *inf;
4849 {
4850         register char *bp;
4851
4852         LOOP_ON_INPUT_LINES (inf, lb, bp)
4853         {
4854                 if (*bp == '\t' || *bp == '#')
4855                         continue;
4856                 while (*bp != '\0' && *bp != '=' && *bp != ':')
4857                         bp++;
4858                 if (*bp == ':' || (globals && *bp == '='))
4859                 {
4860                         /* We should detect if there is more than one tag, but we do not.
4861                            We just skip initial and final spaces. */
4862                         char * namestart = skip_spaces (lb.buffer);
4863                         while (--bp > namestart)
4864                                 if (!notinname (*bp))
4865                                         break;
4866                         make_tag (namestart, bp - namestart + 1, TRUE,
4867                                   lb.buffer, bp - lb.buffer + 2, lineno, linecharno);
4868                 }
4869         }
4870 }
4871
4872 \f
4873 /*
4874  * Pascal parsing
4875  * Original code by Mosur K. Mohan (1989)
4876  *
4877  *  Locates tags for procedures & functions.  Doesn't do any type- or
4878  *  var-definitions.  It does look for the keyword "extern" or
4879  *  "forward" immediately following the procedure statement; if found,
4880  *  the tag is skipped.
4881  */
4882 static void
4883 Pascal_functions (inf)
4884 FILE *inf;
4885 {
4886         linebuffer tline;               /* mostly copied from C_entries */
4887         long save_lcno;
4888         int save_lineno, namelen, taglen;
4889         char c, *name;
4890
4891         bool                            /* each of these flags is TRUE if: */
4892                 incomment,                      /* point is inside a comment */
4893                 inquote,                        /* point is inside '..' string */
4894                 get_tagname,            /* point is after PROCEDURE/FUNCTION
4895                                            keyword, so next item = potential tag */
4896                 found_tag,                      /* point is after a potential tag */
4897                 inparms,                        /* point is within parameter-list */
4898                 verify_tag;                     /* point has passed the parm-list, so the
4899                                                    next token will determine whether this
4900                                                    is a FORWARD/EXTERN to be ignored, or
4901                                                    whether it is a real tag */
4902
4903         save_lcno = save_lineno = namelen = taglen = 0; /* keep compiler quiet */
4904         name = NULL;                    /* keep compiler quiet */
4905         dbp = lb.buffer;
4906         *dbp = '\0';
4907         linebuffer_init (&tline);
4908
4909         incomment = inquote = FALSE;
4910         found_tag = FALSE;              /* have a proc name; check if extern */
4911         get_tagname = FALSE;            /* found "procedure" keyword         */
4912         inparms = FALSE;                /* found '(' after "proc"            */
4913         verify_tag = FALSE;             /* check if "extern" is ahead        */
4914
4915
4916         while (!feof (inf))             /* long main loop to get next char */
4917         {
4918                 c = *dbp++;
4919                 if (c == '\0')          /* if end of line */
4920                 {
4921                         readline (&lb, inf);
4922                         dbp = lb.buffer;
4923                         if (*dbp == '\0')
4924                                 continue;
4925                         if (!((found_tag && verify_tag)
4926                               || get_tagname))
4927                                 c = *dbp++;             /* only if don't need *dbp pointing
4928                                                            to the beginning of the name of
4929                                                            the procedure or function */
4930                 }
4931                 if (incomment)
4932                 {
4933                         if (c == '}')           /* within { } comments */
4934                                 incomment = FALSE;
4935                         else if (c == '*' && *dbp == ')') /* within (* *) comments */
4936                         {
4937                                 dbp++;
4938                                 incomment = FALSE;
4939                         }
4940                         continue;
4941                 }
4942                 else if (inquote)
4943                 {
4944                         if (c == '\'')
4945                                 inquote = FALSE;
4946                         continue;
4947                 }
4948                 else
4949                         switch (c)
4950                         {
4951                         case '\'':
4952                                 inquote = TRUE; /* found first quote */
4953                                 continue;
4954                         case '{':               /* found open { comment */
4955                                 incomment = TRUE;
4956                                 continue;
4957                         case '(':
4958                                 if (*dbp == '*')        /* found open (* comment */
4959                                 {
4960                                         incomment = TRUE;
4961                                         dbp++;
4962                                 }
4963                                 else if (found_tag)     /* found '(' after tag, i.e., parm-list */
4964                                         inparms = TRUE;
4965                                 continue;
4966                         case ')':               /* end of parms list */
4967                                 if (inparms)
4968                                         inparms = FALSE;
4969                                 continue;
4970                         case ';':
4971                                 if (found_tag && !inparms) /* end of proc or fn stmt */
4972                                 {
4973                                         verify_tag = TRUE;
4974                                         break;
4975                                 }
4976                                 continue;
4977                         default:
4978                                 break;
4979                         }
4980                 if (found_tag && verify_tag && (*dbp != ' '))
4981                 {
4982                         /* Check if this is an "extern" declaration. */
4983                         if (*dbp == '\0')
4984                                 continue;
4985                         if (lowcase (*dbp == 'e'))
4986                         {
4987                                 if (nocase_tail ("extern")) /* superfluous, really! */
4988                                 {
4989                                         found_tag = FALSE;
4990                                         verify_tag = FALSE;
4991                                 }
4992                         }
4993                         else if (lowcase (*dbp) == 'f')
4994                         {
4995                                 if (nocase_tail ("forward")) /* check for forward reference */
4996                                 {
4997                                         found_tag = FALSE;
4998                                         verify_tag = FALSE;
4999                                 }
5000                         }
5001                         if (found_tag && verify_tag) /* not external proc, so make tag */
5002                         {
5003                                 found_tag = FALSE;
5004                                 verify_tag = FALSE;
5005                                 make_tag (name, namelen, TRUE,
5006                                           tline.buffer, taglen, save_lineno, save_lcno);
5007                                 continue;
5008                         }
5009                 }
5010                 if (get_tagname)                /* grab name of proc or fn */
5011                 {
5012                         char *cp;
5013
5014                         if (*dbp == '\0')
5015                                 continue;
5016
5017                         /* Find block name. */
5018                         for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
5019                                 continue;
5020
5021                         /* Save all values for later tagging. */
5022                         linebuffer_setlen (&tline, lb.len);
5023                         strncpy(tline.buffer, lb.buffer, lb.len-1);
5024                         save_lineno = lineno;
5025                         save_lcno = linecharno;
5026                         name = tline.buffer + (dbp - lb.buffer);
5027                         namelen = cp - dbp;
5028                         taglen = cp - lb.buffer + 1;
5029
5030                         dbp = cp;               /* set dbp to e-o-token */
5031                         get_tagname = FALSE;
5032                         found_tag = TRUE;
5033                         continue;
5034
5035                         /* And proceed to check for "extern". */
5036                 }
5037                 else if (!incomment && !inquote && !found_tag)
5038                 {
5039                         /* Check for proc/fn keywords. */
5040                         switch (lowcase (c))
5041                         {
5042                         case 'p':
5043                                 if (nocase_tail ("rocedure")) /* c = 'p', dbp has advanced */
5044                                         get_tagname = TRUE;
5045                                 continue;
5046                         case 'f':
5047                                 if (nocase_tail ("unction"))
5048                                         get_tagname = TRUE;
5049                                 continue;
5050                         default:
5051                                 break;
5052                         }
5053                 }
5054         } /* while not eof */
5055
5056         free (tline.buffer);
5057 }
5058
5059 \f
5060 /*
5061  * Lisp tag functions
5062  *  look for (def or (DEF, quote or QUOTE
5063  */
5064
5065 static void L_getit __P((void));
5066
5067 static void
5068 L_getit ()
5069 {
5070         if (*dbp == '\'')               /* Skip prefix quote */
5071                 dbp++;
5072         else if (*dbp == '(')
5073         {
5074                 dbp++;
5075                 /* Try to skip "(quote " */
5076                 if (!LOOKING_AT (dbp, "quote") && !LOOKING_AT (dbp, "QUOTE"))
5077                         /* Ok, then skip "(" before name in (defstruct (foo)) */
5078                         dbp = skip_spaces (dbp);
5079         }
5080         get_tag (dbp, NULL);
5081 }
5082
5083 static void
5084 Lisp_functions (inf)
5085 FILE *inf;
5086 {
5087         LOOP_ON_INPUT_LINES (inf, lb, dbp)
5088         {
5089                 if (dbp[0] != '(')
5090                         continue;
5091
5092                 if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
5093                 {
5094                         dbp = skip_non_spaces (dbp);
5095                         dbp = skip_spaces (dbp);
5096                         L_getit ();
5097                 }
5098                 else
5099                 {
5100                         /* Check for (foo::defmumble name-defined ... */
5101                         do
5102                                 dbp++;
5103                         while (!notinname (*dbp) && *dbp != ':');
5104                         if (*dbp == ':')
5105                         {
5106                                 do
5107                                         dbp++;
5108                                 while (*dbp == ':');
5109
5110                                 if (strneq (dbp, "def", 3) || strneq (dbp, "DEF", 3))
5111                                 {
5112                                         dbp = skip_non_spaces (dbp);
5113                                         dbp = skip_spaces (dbp);
5114                                         L_getit ();
5115                                 }
5116                         }
5117                 }
5118         }
5119 }
5120
5121 \f
5122 /*
5123  * Lua script language parsing
5124  * Original code by David A. Capello <dacap@users.sourceforge.net> (2004)
5125  *
5126  *  "function" and "local function" are tags if they start at column 1.
5127  */
5128 static void
5129 Lua_functions (inf)
5130 FILE *inf;
5131 {
5132         register char *bp;
5133
5134         LOOP_ON_INPUT_LINES (inf, lb, bp)
5135         {
5136                 if (bp[0] != 'f' && bp[0] != 'l')
5137                         continue;
5138
5139                 (void)LOOKING_AT (bp, "local"); /* skip possible "local" */
5140
5141                 if (LOOKING_AT (bp, "function"))
5142                         get_tag (bp, NULL);
5143         }
5144 }
5145
5146 \f
5147 /*
5148  * Postscript tags
5149  * Just look for lines where the first character is '/'
5150  * Also look at "defineps" for PSWrap
5151  * Ideas by:
5152  *   Richard Mlynarik <mly@adoc.xerox.com> (1997)
5153  *   Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
5154  */
5155 static void
5156 PS_functions (inf)
5157 FILE *inf;
5158 {
5159         register char *bp, *ep;
5160
5161         LOOP_ON_INPUT_LINES (inf, lb, bp)
5162         {
5163                 if (bp[0] == '/')
5164                 {
5165                         for (ep = bp+1;
5166                              *ep != '\0' && *ep != ' ' && *ep != '{';
5167                              ep++)
5168                                 continue;
5169                         make_tag (bp, ep - bp, TRUE,
5170                                   lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
5171                 }
5172                 else if (LOOKING_AT (bp, "defineps"))
5173                         get_tag (bp, NULL);
5174         }
5175 }
5176
5177 \f
5178 /*
5179  * Forth tags
5180  * Ignore anything after \ followed by space or in ( )
5181  * Look for words defined by :
5182  * Look for constant, code, create, defer, value, and variable
5183  * OBP extensions:  Look for buffer:, field,
5184  * Ideas by Eduardo Horvath <eeh@netbsd.org> (2004)
5185  */
5186 static void
5187 Forth_words (inf)
5188 FILE *inf;
5189 {
5190         register char *bp;
5191
5192         LOOP_ON_INPUT_LINES (inf, lb, bp)
5193                 while ((bp = skip_spaces (bp))[0] != '\0')
5194                         if (bp[0] == '\\' && iswhite(bp[1]))
5195                                 break;                  /* read next line */
5196                         else if (bp[0] == '(' && iswhite(bp[1]))
5197                                 do                      /* skip to ) or eol */
5198                                         bp++;
5199                                 while (*bp != ')' && *bp != '\0');
5200                         else if ((bp[0] == ':' && iswhite(bp[1]) && bp++)
5201                                  || LOOKING_AT_NOCASE (bp, "constant")
5202                                  || LOOKING_AT_NOCASE (bp, "code")
5203                                  || LOOKING_AT_NOCASE (bp, "create")
5204                                  || LOOKING_AT_NOCASE (bp, "defer")
5205                                  || LOOKING_AT_NOCASE (bp, "value")
5206                                  || LOOKING_AT_NOCASE (bp, "variable")
5207                                  || LOOKING_AT_NOCASE (bp, "buffer:")
5208                                  || LOOKING_AT_NOCASE (bp, "field"))
5209                                 get_tag (skip_spaces (bp), NULL); /* Yay!  A definition! */
5210                         else
5211                                 bp = skip_non_spaces (bp);
5212 }
5213
5214 \f
5215 /*
5216  * Scheme tag functions
5217  * look for (def... xyzzy
5218  *          (def... (xyzzy
5219  *          (def ... ((...(xyzzy ....
5220  *          (set! xyzzy
5221  * Original code by Ken Haase (1985?)
5222  */
5223 static void
5224 Scheme_functions (inf)
5225 FILE *inf;
5226 {
5227         register char *bp;
5228
5229         LOOP_ON_INPUT_LINES (inf, lb, bp)
5230         {
5231                 if (strneq (bp, "(def", 4) || strneq (bp, "(DEF", 4))
5232                 {
5233                         bp = skip_non_spaces (bp+4);
5234                         /* Skip over open parens and white space */
5235                         while (notinname (*bp))
5236                                 bp++;
5237                         get_tag (bp, NULL);
5238                 }
5239                 if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))
5240                         get_tag (bp, NULL);
5241         }
5242 }
5243
5244 \f
5245 /* Find tags in TeX and LaTeX input files.  */
5246
5247 /* TEX_toktab is a table of TeX control sequences that define tags.
5248  * Each entry records one such control sequence.
5249  *
5250  * Original code from who knows whom.
5251  * Ideas by:
5252  *   Stefan Monnier (2002)
5253  */
5254
5255 static linebuffer *TEX_toktab = NULL; /* Table with tag tokens */
5256
5257 /* Default set of control sequences to put into TEX_toktab.
5258    The value of environment var TEXTAGS is prepended to this.  */
5259 static char *TEX_defenv = "\
5260 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
5261 :part:appendix:entry:index:def\
5262 :newcommand:renewcommand:newenvironment:renewenvironment";
5263
5264 static void TEX_mode __P((FILE *));
5265 static void TEX_decode_env __P((char *, char *));
5266
5267 static char TEX_esc = '\\';
5268 static char TEX_opgrp = '{';
5269 static char TEX_clgrp = '}';
5270
5271 /*
5272  * TeX/LaTeX scanning loop.
5273  */
5274 static void
5275 TeX_commands (inf)
5276 FILE *inf;
5277 {
5278         char *cp;
5279         linebuffer *key;
5280
5281         /* Select either \ or ! as escape character.  */
5282         TEX_mode (inf);
5283
5284         /* Initialize token table once from environment. */
5285         if (TEX_toktab == NULL)
5286                 TEX_decode_env ("TEXTAGS", TEX_defenv);
5287
5288         LOOP_ON_INPUT_LINES (inf, lb, cp)
5289         {
5290                 /* Look at each TEX keyword in line. */
5291                 for (;;)
5292                 {
5293                         /* Look for a TEX escape. */
5294                         while (*cp++ != TEX_esc)
5295                                 if (cp[-1] == '\0' || cp[-1] == '%')
5296                                         goto tex_next_line;
5297
5298                         for (key = TEX_toktab; key->buffer != NULL; key++)
5299                                 if (strneq (cp, key->buffer, key->len))
5300                                 {
5301                                         register char *p;
5302                                         int namelen, linelen;
5303                                         bool opgrp = FALSE;
5304
5305                                         cp = skip_spaces (cp + key->len);
5306                                         if (*cp == TEX_opgrp)
5307                                         {
5308                                                 opgrp = TRUE;
5309                                                 cp++;
5310                                         }
5311                                         for (p = cp;
5312                                              (!iswhite (*p) && *p != '#' &&
5313                                               *p != TEX_opgrp && *p != TEX_clgrp);
5314                                              p++)
5315                                                 continue;
5316                                         namelen = p - cp;
5317                                         linelen = lb.len;
5318                                         if (!opgrp || *p == TEX_clgrp)
5319                                         {
5320                                                 while (*p != '\0' && *p != TEX_opgrp && *p != TEX_clgrp)
5321                                                         p++;
5322                                                 linelen = p - lb.buffer + 1;
5323                                         }
5324                                         make_tag (cp, namelen, TRUE,
5325                                                   lb.buffer, linelen, lineno, linecharno);
5326                                         goto tex_next_line; /* We only tag a line once */
5327                                 }
5328                 }
5329         tex_next_line:
5330                 ;
5331         }
5332 }
5333
5334 #define TEX_LESC '\\'
5335 #define TEX_SESC '!'
5336
5337 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
5338    chars accordingly. */
5339 static void
5340 TEX_mode (inf)
5341 FILE *inf;
5342 {
5343         int c;
5344
5345         while ((c = getc (inf)) != EOF)
5346         {
5347                 /* Skip to next line if we hit the TeX comment char. */
5348                 if (c == '%')
5349                         while (c != '\n' && c != EOF)
5350                                 c = getc (inf);
5351                 else if (c == TEX_LESC || c == TEX_SESC )
5352                         break;
5353         }
5354
5355         if (c == TEX_LESC)
5356         {
5357                 TEX_esc = TEX_LESC;
5358                 TEX_opgrp = '{';
5359                 TEX_clgrp = '}';
5360         }
5361         else
5362         {
5363                 TEX_esc = TEX_SESC;
5364                 TEX_opgrp = '<';
5365                 TEX_clgrp = '>';
5366         }
5367         /* If the input file is compressed, inf is a pipe, and rewind may fail.
5368            No attempt is made to correct the situation. */
5369         rewind (inf);
5370 }
5371
5372 /* Read environment and prepend it to the default string.
5373    Build token table. */
5374 static void
5375 TEX_decode_env (evarname, defenv)
5376 char *evarname;
5377 char *defenv;
5378 {
5379         register char *env, *p;
5380         int i, len;
5381
5382         /* Append default string to environment. */
5383         env = getenv (evarname);
5384         if (!env)
5385                 env = defenv;
5386         else
5387         {
5388                 char *oldenv = env;
5389                 env = concat (oldenv, defenv, "");
5390         }
5391
5392         /* Allocate a token table */
5393         for (len = 1, p = env; p;)
5394                 if ((p = etags_strchr (p, ':')) && *++p != '\0')
5395                         len++;
5396         TEX_toktab = xnew (len, linebuffer);
5397
5398         /* Unpack environment string into token table. Be careful about */
5399         /* zero-length strings (leading ':', "::" and trailing ':') */
5400         for (i = 0; *env != '\0';)
5401         {
5402                 p = etags_strchr (env, ':');
5403                 if (!p)                 /* End of environment string. */
5404                         p = env + strlen (env);
5405                 if (p - env > 0)
5406                 {                       /* Only non-zero strings. */
5407                         TEX_toktab[i].buffer = savenstr (env, p - env);
5408                         TEX_toktab[i].len = p - env;
5409                         i++;
5410                 }
5411                 if (*p)
5412                         env = p + 1;
5413                 else
5414                 {
5415                         TEX_toktab[i].buffer = NULL; /* Mark end of table. */
5416                         TEX_toktab[i].len = 0;
5417                         break;
5418                 }
5419         }
5420 }
5421
5422 \f
5423 /* Texinfo support.  Dave Love, Mar. 2000.  */
5424 static void
5425 Texinfo_nodes (inf)
5426 FILE * inf;
5427 {
5428         char *cp, *start;
5429         LOOP_ON_INPUT_LINES (inf, lb, cp)
5430                 if (LOOKING_AT (cp, "@node"))
5431                 {
5432                         start = cp;
5433                         while (*cp != '\0' && *cp != ',')
5434                                 cp++;
5435                         make_tag (start, cp - start, TRUE,
5436                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5437                 }
5438 }
5439
5440 \f
5441 /*
5442  * HTML support.
5443  * Contents of <title>, <h1>, <h2>, <h3> are tags.
5444  * Contents of <a name=xxx> are tags with name xxx.
5445  *
5446  * Francesco Potortì, 2002.
5447  */
5448 static void
5449 HTML_labels (inf)
5450 FILE * inf;
5451 {
5452         bool getnext = FALSE;           /* next text outside of HTML tags is a tag */
5453         bool skiptag = FALSE;           /* skip to the end of the current HTML tag */
5454         bool intag = FALSE;             /* inside an html tag, looking for ID= */
5455         bool inanchor = FALSE;  /* when INTAG, is an anchor, look for NAME= */
5456         char *end;
5457
5458
5459         linebuffer_setlen (&token_name, 0); /* no name in buffer */
5460
5461         LOOP_ON_INPUT_LINES (inf, lb, dbp)
5462                 for (;;)                        /* loop on the same line */
5463                 {
5464                         if (skiptag)            /* skip HTML tag */
5465                         {
5466                                 while (*dbp != '\0' && *dbp != '>')
5467                                         dbp++;
5468                                 if (*dbp == '>')
5469                                 {
5470                                         dbp += 1;
5471                                         skiptag = FALSE;
5472                                         continue;       /* look on the same line */
5473                                 }
5474                                 break;          /* go to next line */
5475                         }
5476
5477                         else if (intag) /* look for "name=" or "id=" */
5478                         {
5479                                 while (*dbp != '\0' && *dbp != '>'
5480                                        && lowcase (*dbp) != 'n' && lowcase (*dbp) != 'i')
5481                                         dbp++;
5482                                 if (*dbp == '\0')
5483                                         break;          /* go to next line */
5484                                 if (*dbp == '>')
5485                                 {
5486                                         dbp += 1;
5487                                         intag = FALSE;
5488                                         continue;       /* look on the same line */
5489                                 }
5490                                 if ((inanchor && LOOKING_AT_NOCASE (dbp, "name="))
5491                                     || LOOKING_AT_NOCASE (dbp, "id="))
5492                                 {
5493                                         bool quoted = (dbp[0] == '"');
5494
5495                                         if (quoted)
5496                                                 for (end = ++dbp; *end != '\0' && *end != '"'; end++)
5497                                                         continue;
5498                                         else
5499                                                 for (end = dbp; *end != '\0' && intoken (*end); end++)
5500                                                         continue;
5501                                         linebuffer_setlen (&token_name, end - dbp);
5502                                         strncpy (token_name.buffer, dbp, end - dbp);
5503                                         token_name.buffer[end - dbp] = '\0';
5504
5505                                         dbp = end;
5506                                         intag = FALSE;  /* we found what we looked for */
5507                                         skiptag = TRUE; /* skip to the end of the tag */
5508                                         getnext = TRUE; /* then grab the text */
5509                                         continue;       /* look on the same line */
5510                                 }
5511                                 dbp += 1;
5512                         }
5513
5514                         else if (getnext)       /* grab next tokens and tag them */
5515                         {
5516                                 dbp = skip_spaces (dbp);
5517                                 if (*dbp == '\0')
5518                                         break;          /* go to next line */
5519                                 if (*dbp == '<')
5520                                 {
5521                                         intag = TRUE;
5522                                         inanchor = (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]));
5523                                         continue;       /* look on the same line */
5524                                 }
5525
5526                                 for (end = dbp + 1; *end != '\0' && *end != '<'; end++)
5527                                         continue;
5528                                 make_tag (token_name.buffer, token_name.len, TRUE,
5529                                           dbp, end - dbp, lineno, linecharno);
5530                                 linebuffer_setlen (&token_name, 0);     /* no name in buffer */
5531                                 getnext = FALSE;
5532                                 break;          /* go to next line */
5533                         }
5534
5535                         else                    /* look for an interesting HTML tag */
5536                         {
5537                                 while (*dbp != '\0' && *dbp != '<')
5538                                         dbp++;
5539                                 if (*dbp == '\0')
5540                                         break;          /* go to next line */
5541                                 intag = TRUE;
5542                                 if (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]))
5543                                 {
5544                                         inanchor = TRUE;
5545                                         continue;       /* look on the same line */
5546                                 }
5547                                 else if (LOOKING_AT_NOCASE (dbp, "<title>")
5548                                          || LOOKING_AT_NOCASE (dbp, "<h1>")
5549                                          || LOOKING_AT_NOCASE (dbp, "<h2>")
5550                                          || LOOKING_AT_NOCASE (dbp, "<h3>"))
5551                                 {
5552                                         intag = FALSE;
5553                                         getnext = TRUE;
5554                                         continue;       /* look on the same line */
5555                                 }
5556                                 dbp += 1;
5557                         }
5558                 }
5559 }
5560
5561 \f
5562 /*
5563  * Prolog support
5564  *
5565  * Assumes that the predicate or rule starts at column 0.
5566  * Only the first clause of a predicate or rule is added.
5567  * Original code by Sunichirou Sugou (1989)
5568  * Rewritten by Anders Lindgren (1996)
5569  */
5570 static int prolog_pr __P((char *, char *));
5571 static void prolog_skip_comment __P((linebuffer *, FILE *));
5572 static int prolog_atom __P((char *, int));
5573
5574 static void
5575 Prolog_functions (inf)
5576 FILE *inf;
5577 {
5578         char *cp, *last;
5579         int len;
5580         int allocated;
5581
5582         allocated = 0;
5583         len = 0;
5584         last = NULL;
5585
5586         LOOP_ON_INPUT_LINES (inf, lb, cp)
5587         {
5588                 if (cp[0] == '\0')      /* Empty line */
5589                         continue;
5590                 else if (iswhite (cp[0])) /* Not a predicate */
5591                         continue;
5592                 else if (cp[0] == '/' && cp[1] == '*')  /* comment. */
5593                         prolog_skip_comment (&lb, inf);
5594                 else if ((len = prolog_pr (cp, last)) > 0)
5595                 {
5596                         /* Predicate or rule.  Store the function name so that we
5597                            only generate a tag for the first clause.  */
5598                         if (last == NULL)
5599                                 last = xnew(len + 1, char);
5600                         else if (len + 1 > allocated)
5601                                 xrnew (last, len + 1, char);
5602                         allocated = len + 1;
5603                         strncpy (last, cp, len);
5604                         last[len] = '\0';
5605                 }
5606         }
5607         free (last);
5608 }
5609
5610
5611 static void
5612 prolog_skip_comment (plb, inf)
5613 linebuffer *plb;
5614 FILE *inf;
5615 {
5616         char *cp;
5617
5618         do
5619         {
5620                 for (cp = plb->buffer; *cp != '\0'; cp++)
5621                         if (cp[0] == '*' && cp[1] == '/')
5622                                 return;
5623                 readline (plb, inf);
5624         }
5625         while (!feof(inf));
5626 }
5627
5628 /*
5629  * A predicate or rule definition is added if it matches:
5630  *     <beginning of line><Prolog Atom><whitespace>(
5631  * or  <beginning of line><Prolog Atom><whitespace>:-
5632  *
5633  * It is added to the tags database if it doesn't match the
5634  * name of the previous clause header.
5635  *
5636  * Return the size of the name of the predicate or rule, or 0 if no
5637  * header was found.
5638  */
5639 static int
5640 prolog_pr (s, last)
5641 char *s;
5642 char *last;             /* Name of last clause. */
5643 {
5644         int pos;
5645         int len;
5646
5647         pos = prolog_atom (s, 0);
5648         if (pos < 1)
5649                 return 0;
5650
5651         len = pos;
5652         pos = skip_spaces (s + pos) - s;
5653
5654         if ((s[pos] == '.'
5655              || (s[pos] == '(' && (pos += 1))
5656              || (s[pos] == ':' && s[pos + 1] == '-' && (pos += 2)))
5657             && (last == NULL            /* save only the first clause */
5658                 || len != (int)strlen (last)
5659                 || !strneq (s, last, len)))
5660         {
5661                 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5662                 return len;
5663         }
5664         else
5665                 return 0;
5666 }
5667
5668 /*
5669  * Consume a Prolog atom.
5670  * Return the number of bytes consumed, or -1 if there was an error.
5671  *
5672  * A prolog atom, in this context, could be one of:
5673  * - An alphanumeric sequence, starting with a lower case letter.
5674  * - A quoted arbitrary string. Single quotes can escape themselves.
5675  *   Backslash quotes everything.
5676  */
5677 static int
5678 prolog_atom (s, pos)
5679 char *s;
5680 int pos;
5681 {
5682         int origpos;
5683
5684         origpos = pos;
5685
5686         if (ISLOWER(s[pos]) || (s[pos] == '_'))
5687         {
5688                 /* The atom is unquoted. */
5689                 pos++;
5690                 while (ISALNUM(s[pos]) || (s[pos] == '_'))
5691                 {
5692                         pos++;
5693                 }
5694                 return pos - origpos;
5695         }
5696         else if (s[pos] == '\'')
5697         {
5698                 pos++;
5699
5700                 for (;;)
5701                 {
5702                         if (s[pos] == '\'')
5703                         {
5704                                 pos++;
5705                                 if (s[pos] != '\'')
5706                                         break;
5707                                 pos++;          /* A double quote */
5708                         }
5709                         else if (s[pos] == '\0')
5710                                 /* Multiline quoted atoms are ignored. */
5711                                 return -1;
5712                         else if (s[pos] == '\\')
5713                         {
5714                                 if (s[pos+1] == '\0')
5715                                         return -1;
5716                                 pos += 2;
5717                         }
5718                         else
5719                                 pos++;
5720                 }
5721                 return pos - origpos;
5722         }
5723         else
5724                 return -1;
5725 }
5726
5727 \f
5728 /*
5729  * Support for Erlang
5730  *
5731  * Generates tags for functions, defines, and records.
5732  * Assumes that Erlang functions start at column 0.
5733  * Original code by Anders Lindgren (1996)
5734  */
5735 static int erlang_func __P((char *, char *));
5736 static void erlang_attribute __P((char *));
5737 static int erlang_atom __P((char *));
5738
5739 static void
5740 Erlang_functions (inf)
5741 FILE *inf;
5742 {
5743         char *cp, *last;
5744         int len;
5745         int allocated;
5746
5747         allocated = 0;
5748         len = 0;
5749         last = NULL;
5750
5751         LOOP_ON_INPUT_LINES (inf, lb, cp)
5752         {
5753                 if (cp[0] == '\0')      /* Empty line */
5754                         continue;
5755                 else if (iswhite (cp[0])) /* Not function nor attribute */
5756                         continue;
5757                 else if (cp[0] == '%')  /* comment */
5758                         continue;
5759                 else if (cp[0] == '"')  /* Sometimes, strings start in column one */
5760                         continue;
5761                 else if (cp[0] == '-')  /* attribute, e.g. "-define" */
5762                 {
5763                         erlang_attribute (cp);
5764                         if (last != NULL)
5765                         {
5766                                 free (last);
5767                                 last = NULL;
5768                         }
5769                 }
5770                 else if ((len = erlang_func (cp, last)) > 0)
5771                 {
5772                         /*
5773                          * Function.  Store the function name so that we only
5774                          * generates a tag for the first clause.
5775                          */
5776                         if (last == NULL)
5777                                 last = xnew (len + 1, char);
5778                         else if (len + 1 > allocated)
5779                                 xrnew (last, len + 1, char);
5780                         allocated = len + 1;
5781                         strncpy (last, cp, len);
5782                         last[len] = '\0';
5783                 }
5784         }
5785         free (last);
5786 }
5787
5788
5789 /*
5790  * A function definition is added if it matches:
5791  *     <beginning of line><Erlang Atom><whitespace>(
5792  *
5793  * It is added to the tags database if it doesn't match the
5794  * name of the previous clause header.
5795  *
5796  * Return the size of the name of the function, or 0 if no function
5797  * was found.
5798  */
5799 static int
5800 erlang_func (s, last)
5801 char *s;
5802 char *last;             /* Name of last clause. */
5803 {
5804         int pos;
5805         int len;
5806
5807         pos = erlang_atom (s);
5808         if (pos < 1)
5809                 return 0;
5810
5811         len = pos;
5812         pos = skip_spaces (s + pos) - s;
5813
5814         /* Save only the first clause. */
5815         if (s[pos++] == '('
5816             && (last == NULL
5817                 || len != (int)strlen (last)
5818                 || !strneq (s, last, len)))
5819         {
5820                 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5821                 return len;
5822         }
5823
5824         return 0;
5825 }
5826
5827
5828 /*
5829  * Handle attributes.  Currently, tags are generated for defines
5830  * and records.
5831  *
5832  * They are on the form:
5833  * -define(foo, bar).
5834  * -define(Foo(M, N), M+N).
5835  * -record(graph, {vtab = notable, cyclic = true}).
5836  */
5837 static void
5838 erlang_attribute (s)
5839 char *s;
5840 {
5841         char *cp = s;
5842
5843         if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
5844             && *cp++ == '(')
5845         {
5846                 int len = erlang_atom (skip_spaces (cp));
5847                 if (len > 0)
5848                         make_tag (cp, len, TRUE, s, cp + len - s, lineno, linecharno);
5849         }
5850         return;
5851 }
5852
5853
5854 /*
5855  * Consume an Erlang atom (or variable).
5856  * Return the number of bytes consumed, or -1 if there was an error.
5857  */
5858 static int
5859 erlang_atom (s)
5860 char *s;
5861 {
5862         int pos = 0;
5863
5864         if (ISALPHA (s[pos]) || s[pos] == '_')
5865         {
5866                 /* The atom is unquoted. */
5867                 do
5868                         pos++;
5869                 while (ISALNUM (s[pos]) || s[pos] == '_');
5870         }
5871         else if (s[pos] == '\'')
5872         {
5873                 for (pos++; s[pos] != '\''; pos++)
5874                         if (s[pos] == '\0'      /* multiline quoted atoms are ignored */
5875                             || (s[pos] == '\\' && s[++pos] == '\0'))
5876                                 return 0;
5877                 pos++;
5878         }
5879
5880         return pos;
5881 }
5882
5883 \f
5884 static char *scan_separators __P((char *));
5885 static void add_regex __P((char *, language *));
5886 static char *substitute __P((char *, char *, struct re_registers *));
5887
5888 /*
5889  * Take a string like "/blah/" and turn it into "blah", verifying
5890  * that the first and last characters are the same, and handling
5891  * quoted separator characters.  Actually, stops on the occurrence of
5892  * an unquoted separator.  Also process \t, \n, etc. and turn into
5893  * appropriate characters. Works in place.  Null terminates name string.
5894  * Returns pointer to terminating separator, or NULL for
5895  * unterminated regexps.
5896  */
5897 static char *
5898 scan_separators (name)
5899 char *name;
5900 {
5901         char sep = name[0];
5902         char *copyto = name;
5903         bool quoted = FALSE;
5904
5905         for (++name; *name != '\0'; ++name)
5906         {
5907                 if (quoted)
5908                 {
5909                         switch (*name)
5910                         {
5911                         case 'a': *copyto++ = '\007'; break; /* BEL (bell)               */
5912                         case 'b': *copyto++ = '\b'; break;       /* BS (back space)      */
5913                         case 'd': *copyto++ = 0177; break;       /* DEL (delete)         */
5914                         case 'e': *copyto++ = 033; break;        /* ESC (delete)         */
5915                         case 'f': *copyto++ = '\f'; break;       /* FF (form feed)       */
5916                         case 'n': *copyto++ = '\n'; break;       /* NL (new line)        */
5917                         case 'r': *copyto++ = '\r'; break;       /* CR (carriage return) */
5918                         case 't': *copyto++ = '\t'; break;       /* TAB (horizontal tab) */
5919                         case 'v': *copyto++ = '\v'; break;       /* VT (vertical tab)    */
5920                         default:
5921                                 if (*name == sep)
5922                                         *copyto++ = sep;
5923                                 else
5924                                 {
5925                                         /* Something else is quoted, so preserve the quote. */
5926                                         *copyto++ = '\\';
5927                                         *copyto++ = *name;
5928                                 }
5929                                 break;
5930                         }
5931                         quoted = FALSE;
5932                 }
5933                 else if (*name == '\\')
5934                         quoted = TRUE;
5935                 else if (*name == sep)
5936                         break;
5937                 else
5938                         *copyto++ = *name;
5939         }
5940         if (*name != sep)
5941                 name = NULL;            /* signal unterminated regexp */
5942
5943         /* Terminate copied string. */
5944         *copyto = '\0';
5945         return name;
5946 }
5947
5948 /* Look at the argument of --regex or --no-regex and do the right
5949    thing.  Same for each line of a regexp file. */
5950 static void
5951 analyse_regex (regex_arg)
5952 char *regex_arg;
5953 {
5954         if (regex_arg == NULL)
5955         {
5956                 free_regexps ();                /* --no-regex: remove existing regexps */
5957                 return;
5958         }
5959
5960         /* A real --regexp option or a line in a regexp file. */
5961         switch (regex_arg[0])
5962         {
5963                 /* Comments in regexp file or null arg to --regex. */
5964         case '\0':
5965         case ' ':
5966         case '\t':
5967                 break;
5968
5969                 /* Read a regex file.  This is recursive and may result in a
5970                    loop, which will stop when the file descriptors are exhausted. */
5971         case '@':
5972         {
5973                 FILE *regexfp;
5974                 linebuffer regexbuf;
5975                 char *regexfile = regex_arg + 1;
5976
5977                 /* regexfile is a file containing regexps, one per line. */
5978                 regexfp = fopen (regexfile, "r");
5979                 if (regexfp == NULL)
5980                 {
5981                         pfatal (regexfile);
5982                         return;
5983                 }
5984                 linebuffer_init (&regexbuf);
5985                 while (readline_internal (&regexbuf, regexfp) > 0)
5986                         analyse_regex (regexbuf.buffer);
5987                 free (regexbuf.buffer);
5988                 fclose (regexfp);
5989         }
5990         break;
5991
5992         /* Regexp to be used for a specific language only. */
5993         case '{':
5994         {
5995                 language *lang;
5996                 char *lang_name = regex_arg + 1;
5997                 char *cp;
5998
5999                 for (cp = lang_name; *cp != '}'; cp++)
6000                         if (*cp == '\0')
6001                         {
6002                                 error ("unterminated language name in regex: %s", regex_arg);
6003                                 return;
6004                         }
6005                 *cp++ = '\0';
6006                 lang = get_language_from_langname (lang_name);
6007                 if (lang == NULL)
6008                         return;
6009                 add_regex (cp, lang);
6010         }
6011         break;
6012
6013         /* Regexp to be used for any language. */
6014         default:
6015                 add_regex (regex_arg, NULL);
6016                 break;
6017         }
6018 }
6019
6020 /* Separate the regexp pattern, compile it,
6021    and care for optional name and modifiers. */
6022 static void
6023 add_regex (regexp_pattern, lang)
6024 char *regexp_pattern;
6025 language *lang;
6026 {
6027         static struct re_pattern_buffer zeropattern;
6028         char sep, *pat, *name, *modifiers;
6029         const char *err;
6030         struct re_pattern_buffer *patbuf;
6031         regexp *rp;
6032         bool
6033                 force_explicit_name = TRUE, /* do not use implicit tag names */
6034                 ignore_case = FALSE,    /* case is significant */
6035                 multi_line = FALSE,             /* matches are done one line at a time */
6036                 single_line = FALSE;    /* dot does not match newline */
6037
6038
6039         if (strlen(regexp_pattern) < 3)
6040         {
6041                 error ("null regexp", (char *)NULL);
6042                 return;
6043         }
6044         sep = regexp_pattern[0];
6045         name = scan_separators (regexp_pattern);
6046         if (name == NULL)
6047         {
6048                 error ("%s: unterminated regexp", regexp_pattern);
6049                 return;
6050         }
6051         if (name[1] == sep)
6052         {
6053                 error ("null name for regexp \"%s\"", regexp_pattern);
6054                 return;
6055         }
6056         modifiers = scan_separators (name);
6057         if (modifiers == NULL)  /* no terminating separator --> no name */
6058         {
6059                 modifiers = name;
6060                 name = "";
6061         }
6062         else
6063                 modifiers += 1;         /* skip separator */
6064
6065         /* Parse regex modifiers. */
6066         for (; modifiers[0] != '\0'; modifiers++)
6067                 switch (modifiers[0])
6068                 {
6069                 case 'N':
6070                         if (modifiers == name)
6071                                 error ("forcing explicit tag name but no name, ignoring", NULL);
6072                         force_explicit_name = TRUE;
6073                         break;
6074                 case 'i':
6075                         ignore_case = TRUE;
6076                         break;
6077                 case 's':
6078                         single_line = TRUE;
6079                         /* FALLTHRU */
6080                 case 'm':
6081                         multi_line = TRUE;
6082                         need_filebuf = TRUE;
6083                         break;
6084                 default:
6085                 {
6086                         char wrongmod [2];
6087                         wrongmod[0] = modifiers[0];
6088                         wrongmod[1] = '\0';
6089                         error ("invalid regexp modifier `%s', ignoring", wrongmod);
6090                 }
6091                 break;
6092                 }
6093
6094         patbuf = xnew (1, struct re_pattern_buffer);
6095         *patbuf = zeropattern;
6096         if (ignore_case)
6097         {
6098                 static char lc_trans[CHARS];
6099                 int i;
6100                 for (i = 0; i < CHARS; i++)
6101                         lc_trans[i] = lowcase (i);
6102                 patbuf->translate = lc_trans;   /* translation table to fold case  */
6103         }
6104
6105         if (multi_line)
6106                 pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
6107         else
6108                 pat = regexp_pattern;
6109
6110         if (single_line)
6111                 re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
6112         else
6113                 re_set_syntax (RE_SYNTAX_EMACS);
6114
6115         err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
6116         if (multi_line)
6117                 free (pat);
6118         if (err != NULL)
6119         {
6120                 error ("%s while compiling pattern", err);
6121                 return;
6122         }
6123
6124         rp = p_head;
6125         p_head = xnew (1, regexp);
6126         p_head->pattern = savestr (regexp_pattern);
6127         p_head->p_next = rp;
6128         p_head->lang = lang;
6129         p_head->pat = patbuf;
6130         p_head->name = savestr (name);
6131         p_head->error_signaled = FALSE;
6132         p_head->force_explicit_name = force_explicit_name;
6133         p_head->ignore_case = ignore_case;
6134         p_head->multi_line = multi_line;
6135 }
6136
6137 /*
6138  * Do the substitutions indicated by the regular expression and
6139  * arguments.
6140  */
6141 static char *
6142 substitute (in, out, regs)
6143 char *in, *out;
6144 struct re_registers *regs;
6145 {
6146         char *result, *t;
6147         int size, dig, diglen;
6148
6149         result = NULL;
6150         size = strlen (out);
6151
6152         /* Pass 1: figure out how much to allocate by finding all \N strings. */
6153         if (out[size - 1] == '\\')
6154                 fatal ("pattern error in \"%s\"", out);
6155         for (t = etags_strchr (out, '\\');
6156              t != NULL;
6157              t = etags_strchr (t + 2, '\\'))
6158                 if (ISDIGIT (t[1]))
6159                 {
6160                         dig = t[1] - '0';
6161                         diglen = regs->end[dig] - regs->start[dig];
6162                         size += diglen - 2;
6163                 }
6164                 else
6165                         size -= 1;
6166
6167         /* Allocate space and do the substitutions. */
6168         assert (size >= 0);
6169         result = xnew (size + 1, char);
6170
6171         for (t = result; *out != '\0'; out++)
6172                 if (*out == '\\' && ISDIGIT (*++out))
6173                 {
6174                         dig = *out - '0';
6175                         diglen = regs->end[dig] - regs->start[dig];
6176                         strncpy (t, in + regs->start[dig], diglen);
6177                         t += diglen;
6178                 }
6179                 else
6180                         *t++ = *out;
6181         *t = '\0';
6182
6183         assert (t <= result + size);
6184         assert (t - result == (int)strlen (result));
6185
6186         return result;
6187 }
6188
6189 /* Deallocate all regexps. */
6190 static void
6191 free_regexps ()
6192 {
6193         regexp *rp;
6194         while (p_head != NULL)
6195         {
6196                 rp = p_head->p_next;
6197                 free (p_head->pattern);
6198                 free (p_head->name);
6199                 free (p_head);
6200                 p_head = rp;
6201         }
6202         return;
6203 }
6204
6205 /*
6206  * Reads the whole file as a single string from `filebuf' and looks for
6207  * multi-line regular expressions, creating tags on matches.
6208  * readline already dealt with normal regexps.
6209  *
6210  * Idea by Ben Wing <ben@666.com> (2002).
6211  */
6212 static void
6213 regex_tag_multiline ()
6214 {
6215         char *buffer = filebuf.buffer;
6216         regexp *rp;
6217         char *name;
6218
6219         for (rp = p_head; rp != NULL; rp = rp->p_next)
6220         {
6221                 int match = 0;
6222
6223                 if (!rp->multi_line)
6224                         continue;               /* skip normal regexps */
6225
6226                 /* Generic initialisations before parsing file from memory. */
6227                 lineno = 1;             /* reset global line number */
6228                 charno = 0;             /* reset global char number */
6229                 linecharno = 0;         /* reset global char number of line start */
6230
6231                 /* Only use generic regexps or those for the current language. */
6232                 if (rp->lang != NULL && rp->lang != curfdp->lang)
6233                         continue;
6234
6235                 while (match >= 0 && match < filebuf.len)
6236                 {
6237                         match = re_search (rp->pat, buffer, filebuf.len, charno,
6238                                            filebuf.len - match, &rp->regs);
6239                         switch (match)
6240                         {
6241                         case -2:
6242                                 /* Some error. */
6243                                 if (!rp->error_signaled)
6244                                 {
6245                                         error ("regexp stack overflow while matching \"%s\"",
6246                                                rp->pattern);
6247                                         rp->error_signaled = TRUE;
6248                                 }
6249                                 break;
6250                         case -1:
6251                                 /* No match. */
6252                                 break;
6253                         default:
6254                                 if (match == rp->regs.end[0])
6255                                 {
6256                                         if (!rp->error_signaled)
6257                                         {
6258                                                 error ("regexp matches the empty string: \"%s\"",
6259                                                        rp->pattern);
6260                                                 rp->error_signaled = TRUE;
6261                                         }
6262                                         match = -3;     /* exit from while loop */
6263                                         break;
6264                                 }
6265
6266                                 /* Match occurred.  Construct a tag. */
6267                                 while (charno < rp->regs.end[0])
6268                                         if (buffer[charno++] == '\n')
6269                                                 lineno++, linecharno = charno;
6270                                 name = rp->name;
6271                                 if (name[0] == '\0')
6272                                         name = NULL;
6273                                 else /* make a named tag */
6274                                         name = substitute (buffer, rp->name, &rp->regs);
6275                                 if (rp->force_explicit_name)
6276                                         /* Force explicit tag name, if a name is there. */
6277                                         pfnote (name, TRUE, buffer + linecharno,
6278                                                 charno - linecharno + 1, lineno, linecharno);
6279                                 else
6280                                         make_tag (name, strlen (name), TRUE, buffer + linecharno,
6281                                                   charno - linecharno + 1, lineno, linecharno);
6282                                 break;
6283                         }
6284                 }
6285         }
6286 }
6287
6288 \f
6289 static bool
6290 nocase_tail (cp)
6291 char *cp;
6292 {
6293         register int len = 0;
6294
6295         while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
6296                 cp++, len++;
6297         if (*cp == '\0' && !intoken (dbp[len]))
6298         {
6299                 dbp += len;
6300                 return TRUE;
6301         }
6302         return FALSE;
6303 }
6304
6305 static void
6306 get_tag (bp, namepp)
6307 register char *bp;
6308 char **namepp;
6309 {
6310         register char *cp = bp;
6311
6312         if (*bp != '\0')
6313         {
6314                 /* Go till you get to white space or a syntactic break */
6315                 for (cp = bp + 1; !notinname (*cp); cp++)
6316                         continue;
6317                 make_tag (bp, cp - bp, TRUE,
6318                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
6319         }
6320
6321         if (namepp != NULL)
6322                 *namepp = savenstr (bp, cp - bp);
6323 }
6324
6325 /*
6326  * Read a line of text from `stream' into `lbp', excluding the
6327  * newline or CR-NL, if any.  Return the number of characters read from
6328  * `stream', which is the length of the line including the newline.
6329  *
6330  * On DOS or Windows we do not count the CR character, if any before the
6331  * NL, in the returned length; this mirrors the behavior of Emacs on those
6332  * platforms (for text files, it translates CR-NL to NL as it reads in the
6333  * file).
6334  *
6335  * If multi-line regular expressions are requested, each line read is
6336  * appended to `filebuf'.
6337  */
6338 static long
6339 readline_internal (lbp, stream)
6340 linebuffer *lbp;
6341 register FILE *stream;
6342 {
6343         char *buffer = lbp->buffer;
6344         register char *p = lbp->buffer;
6345         register char *pend;
6346         int chars_deleted;
6347
6348         pend = p + lbp->size;           /* Separate to avoid 386/IX compiler bug.  */
6349
6350         for (;;)
6351         {
6352                 register int c = getc (stream);
6353                 if (p == pend)
6354                 {
6355                         /* We're at the end of linebuffer: expand it. */
6356                         lbp->size *= 2;
6357                         xrnew (buffer, lbp->size, char);
6358                         p += buffer - lbp->buffer;
6359                         pend = buffer + lbp->size;
6360                         lbp->buffer = buffer;
6361                 }
6362                 if (c == EOF)
6363                 {
6364                         *p = '\0';
6365                         chars_deleted = 0;
6366                         break;
6367                 }
6368                 if (c == '\n')
6369                 {
6370                         if (p > buffer && p[-1] == '\r')
6371                         {
6372                                 p -= 1;
6373                                 chars_deleted = 2;
6374                         }
6375                         else
6376                         {
6377                                 chars_deleted = 1;
6378                         }
6379                         *p = '\0';
6380                         break;
6381                 }
6382                 *p++ = c;
6383         }
6384         lbp->len = p - buffer;
6385
6386         if (need_filebuf                /* we need filebuf for multi-line regexps */
6387             && chars_deleted > 0)       /* not at EOF */
6388         {
6389                 while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
6390                 {
6391                         /* Expand filebuf. */
6392                         filebuf.size *= 2;
6393                         xrnew (filebuf.buffer, filebuf.size, char);
6394                 }
6395                 strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
6396                 filebuf.len += lbp->len;
6397                 filebuf.buffer[filebuf.len++] = '\n';
6398                 filebuf.buffer[filebuf.len] = '\0';
6399         }
6400
6401         return lbp->len + chars_deleted;
6402 }
6403
6404 /*
6405  * Like readline_internal, above, but in addition try to match the
6406  * input line against relevant regular expressions and manage #line
6407  * directives.
6408  */
6409 static void
6410 readline (lbp, stream)
6411 linebuffer *lbp;
6412 FILE *stream;
6413 {
6414         long result;
6415
6416         linecharno = charno;            /* update global char number of line start */
6417         result = readline_internal (lbp, stream); /* read line */
6418         lineno += 1;                    /* increment global line number */
6419         charno += result;               /* increment global char number */
6420
6421         /* Honour #line directives. */
6422         if (!no_line_directive)
6423         {
6424                 static bool discard_until_line_directive;
6425
6426                 /* Check whether this is a #line directive. */
6427                 if (result > 12 && strneq (lbp->buffer, "#line ", 6))
6428                 {
6429                         unsigned int lno;
6430                         int start = 0;
6431
6432                         if (sscanf (lbp->buffer, "#line %u \"%n", &lno, &start) >= 1
6433                             && start > 0)       /* double quote character found */
6434                         {
6435                                 char *endp = lbp->buffer + start;
6436
6437                                 while ((endp = etags_strchr (endp, '"')) != NULL
6438                                        && endp[-1] == '\\')
6439                                         endp++;
6440                                 if (endp != NULL)
6441                                         /* Ok, this is a real #line directive.  Let's deal with it. */
6442                                 {
6443                                         char *taggedabsname;    /* absolute name of original file */
6444                                         char *taggedfname;      /* name of original file as given */
6445                                         char *name;             /* temp var */
6446
6447                                         discard_until_line_directive = FALSE; /* found it */
6448                                         name = lbp->buffer + start;
6449                                         *endp = '\0';
6450                                         canonicalize_filename (name);
6451                                         taggedabsname = absolute_filename (name, tagfiledir);
6452                                         if (filename_is_absolute (name)
6453                                             || filename_is_absolute (curfdp->infname))
6454                                                 taggedfname = savestr (taggedabsname);
6455                                         else
6456                                                 taggedfname = relative_filename (taggedabsname,tagfiledir);
6457
6458                                         if (streq (curfdp->taggedfname, taggedfname))
6459                                                 /* The #line directive is only a line number change.  We
6460                                                    deal with this afterwards. */
6461                                                 free (taggedfname);
6462                                         else
6463                                                 /* The tags following this #line directive should be
6464                                                    attributed to taggedfname.  In order to do this, set
6465                                                    curfdp accordingly. */
6466                                         {
6467                                                 fdesc *fdp; /* file description pointer */
6468
6469                                                 /* Go look for a file description already set up for the
6470                                                    file indicated in the #line directive.  If there is
6471                                                    one, use it from now until the next #line
6472                                                    directive. */
6473                                                 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6474                                                         if (streq (fdp->infname, curfdp->infname)
6475                                                             && streq (fdp->taggedfname, taggedfname))
6476                                                                 /* If we remove the second test above (after the &&)
6477                                                                    then all entries pertaining to the same file are
6478                                                                    coalesced in the tags file.  If we use it, then
6479                                                                    entries pertaining to the same file but generated
6480                                                                    from different files (via #line directives) will
6481                                                                    go into separate sections in the tags file.  These
6482                                                                    alternatives look equivalent.  The first one
6483                                                                    destroys some apparently useless information. */
6484                                                         {
6485                                                                 curfdp = fdp;
6486                                                                 free (taggedfname);
6487                                                                 break;
6488                                                         }
6489                                                 /* Else, if we already tagged the real file, skip all
6490                                                    input lines until the next #line directive. */
6491                                                 if (fdp == NULL) /* not found */
6492                                                         for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6493                                                                 if (streq (fdp->infabsname, taggedabsname))
6494                                                                 {
6495                                                                         discard_until_line_directive = TRUE;
6496                                                                         free (taggedfname);
6497                                                                         break;
6498                                                                 }
6499                                                 /* Else create a new file description and use that from
6500                                                    now on, until the next #line directive. */
6501                                                 if (fdp == NULL) /* not found */
6502                                                 {
6503                                                         fdp = fdhead;
6504                                                         fdhead = xnew (1, fdesc);
6505                                                         *fdhead = *curfdp; /* copy curr. file description */
6506                                                         fdhead->next = fdp;
6507                                                         fdhead->infname = savestr (curfdp->infname);
6508                                                         fdhead->infabsname = savestr (curfdp->infabsname);
6509                                                         fdhead->infabsdir = savestr (curfdp->infabsdir);
6510                                                         fdhead->taggedfname = taggedfname;
6511                                                         fdhead->usecharno = FALSE;
6512                                                         fdhead->prop = NULL;
6513                                                         fdhead->written = FALSE;
6514                                                         curfdp = fdhead;
6515                                                 }
6516                                         }
6517                                         free (taggedabsname);
6518                                         lineno = lno - 1;
6519                                         readline (lbp, stream);
6520                                         return;
6521                                 } /* if a real #line directive */
6522                         } /* if #line is followed by a a number */
6523                 } /* if line begins with "#line " */
6524
6525                 /* If we are here, no #line directive was found. */
6526                 if (discard_until_line_directive)
6527                 {
6528                         if (result > 0)
6529                         {
6530                                 /* Do a tail recursion on ourselves, thus discarding the contents
6531                                    of the line buffer. */
6532                                 readline (lbp, stream);
6533                                 return;
6534                         }
6535                         /* End of file. */
6536                         discard_until_line_directive = FALSE;
6537                         return;
6538                 }
6539         } /* if #line directives should be considered */
6540
6541         {
6542                 int match;
6543                 regexp *rp;
6544                 char *name = NULL;
6545
6546                 /* Match against relevant regexps. */
6547                 if (lbp->len > 0)
6548                         for (rp = p_head; rp != NULL; rp = rp->p_next)
6549                         {
6550                                 /* Only use generic regexps or those for the current language.
6551                                    Also do not use multiline regexps, which is the job of
6552                                    regex_tag_multiline. */
6553                                 if ((rp->lang != NULL && rp->lang != fdhead->lang)
6554                                     || rp->multi_line)
6555                                         continue;
6556
6557                                 match = re_match (rp->pat, lbp->buffer, lbp->len, 0, &rp->regs);
6558                                 switch (match)
6559                                 {
6560                                 case -2:
6561                                         /* Some error. */
6562                                         if (!rp->error_signaled)
6563                                         {
6564                                                 error ("regexp stack overflow while matching \"%s\"",
6565                                                        rp->pattern);
6566                                                 rp->error_signaled = TRUE;
6567                                         }
6568                                         break;
6569                                 case -1:
6570                                         /* No match. */
6571                                         break;
6572                                 case 0:
6573                                         /* Empty string matched. */
6574                                         if (!rp->error_signaled)
6575                                         {
6576                                                 error ("regexp matches the empty string: \"%s\"", rp->pattern);
6577                                                 rp->error_signaled = TRUE;
6578                                         }
6579                                         break;
6580                                 default:
6581                                         /* Match occurred.  Construct a tag. */
6582                                         if (rp->name[0] != '\0')
6583                                                 /* make a named tag */
6584                                                 name = substitute (lbp->buffer, rp->name, &rp->regs);
6585                                         if (rp->force_explicit_name)
6586                                                 /* Force explicit tag name, if a name is there. */
6587                                                 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
6588                                         else if (name) {
6589                                                 make_tag (name, strlen (name), TRUE,
6590                                                           lbp->buffer, match, lineno, linecharno);
6591                                                 free(name);
6592                                                 name = NULL;
6593                                         } else 
6594                                                 make_tag (rp->name, strlen (rp->name), TRUE,
6595                                                           lbp->buffer, match, lineno, linecharno);
6596                                         break;
6597                                 }
6598                         }
6599         }
6600 }
6601
6602 \f
6603 /*
6604  * Return a pointer to a space of size strlen(cp)+1 allocated
6605  * with xnew where the string CP has been copied.
6606  */
6607 static char *
6608 savestr (cp)
6609 char *cp;
6610 {
6611         return savenstr (cp, strlen (cp));
6612 }
6613
6614 /*
6615  * Return a pointer to a space of size LEN+1 allocated with xnew where
6616  * the string CP has been copied for at most the first LEN characters.
6617  */
6618 static char *
6619 savenstr (cp, len)
6620 char *cp;
6621 int len;
6622 {
6623         register char *dp;
6624
6625         dp = xnew (len + 1, char);
6626         strncpy (dp, cp, len);
6627         dp[len] = '\0';
6628         return dp;
6629 }
6630
6631 /*
6632  * Return the ptr in sp at which the character c last
6633  * appears; NULL if not found
6634  *
6635  * Identical to POSIX strrchr, included for portability.
6636  */
6637 static char *
6638 etags_strrchr (sp, c)
6639 register const char *sp;
6640 register int c;
6641 {
6642         register const char *r;
6643
6644         r = NULL;
6645         do
6646         {
6647                 if (*sp == c)
6648                         r = sp;
6649         } while (*sp++);
6650         return (char *)r;
6651 }
6652
6653 /*
6654  * Return the ptr in sp at which the character c first
6655  * appears; NULL if not found
6656  *
6657  * Identical to POSIX strchr, included for portability.
6658  */
6659 static char *
6660 etags_strchr (sp, c)
6661 register const char *sp;
6662 register int c;
6663 {
6664         do
6665         {
6666                 if (*sp == c)
6667                         return (char *)sp;
6668         } while (*sp++);
6669         return NULL;
6670 }
6671
6672 /*
6673  * Compare two strings, ignoring case for alphabetic characters.
6674  *
6675  * Same as BSD's strcasecmp, included for portability.
6676  */
6677 static int
6678 etags_strcasecmp (s1, s2)
6679 register const char *s1;
6680 register const char *s2;
6681 {
6682         while (*s1 != '\0'
6683                && (ISALPHA (*s1) && ISALPHA (*s2)
6684                    ? lowcase (*s1) == lowcase (*s2)
6685                    : *s1 == *s2))
6686                 s1++, s2++;
6687
6688         return (ISALPHA (*s1) && ISALPHA (*s2)
6689                 ? lowcase (*s1) - lowcase (*s2)
6690                 : *s1 - *s2);
6691 }
6692
6693 /*
6694  * Compare two strings, ignoring case for alphabetic characters.
6695  * Stop after a given number of characters
6696  *
6697  * Same as BSD's strncasecmp, included for portability.
6698  */
6699 static int
6700 etags_strncasecmp (s1, s2, n)
6701 register const char *s1;
6702 register const char *s2;
6703 register int n;
6704 {
6705         while (*s1 != '\0' && n-- > 0
6706                && (ISALPHA (*s1) && ISALPHA (*s2)
6707                    ? lowcase (*s1) == lowcase (*s2)
6708                    : *s1 == *s2))
6709                 s1++, s2++;
6710
6711         if (n < 0)
6712                 return 0;
6713         else
6714                 return (ISALPHA (*s1) && ISALPHA (*s2)
6715                         ? lowcase (*s1) - lowcase (*s2)
6716                         : *s1 - *s2);
6717 }
6718
6719 /* Skip spaces (end of string is not space), return new pointer. */
6720 static char *
6721 skip_spaces (cp)
6722 char *cp;
6723 {
6724         while (iswhite (*cp))
6725                 cp++;
6726         return cp;
6727 }
6728
6729 /* Skip non spaces, except end of string, return new pointer. */
6730 static char *
6731 skip_non_spaces (cp)
6732 char *cp;
6733 {
6734         while (*cp != '\0' && !iswhite (*cp))
6735                 cp++;
6736         return cp;
6737 }
6738
6739 /* Print error message and exit.  */
6740 void
6741 fatal (s1, s2)
6742 char *s1, *s2;
6743 {
6744         error (s1, s2);
6745         exit (EXIT_FAILURE);
6746 }
6747
6748 static void
6749 pfatal (s1)
6750 char *s1;
6751 {
6752         perror (s1);
6753         exit (EXIT_FAILURE);
6754 }
6755
6756 static void
6757 suggest_asking_for_help ()
6758 {
6759         fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
6760                  progname, NO_LONG_OPTIONS ? "-h" : "--help");
6761         exit (EXIT_FAILURE);
6762 }
6763
6764 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
6765 static void
6766 error (s1, s2)
6767 const char *s1, *s2;
6768 {
6769         fprintf (stderr, "%s: ", progname);
6770         fprintf (stderr, s1, s2);
6771         fprintf (stderr, "\n");
6772 }
6773
6774 /* Return a newly-allocated string whose contents
6775    concatenate those of s1, s2, s3.  */
6776 static char *
6777 concat (s1, s2, s3)
6778 char *s1, *s2, *s3;
6779 {
6780         int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
6781         char *result = xnew (len1 + len2 + len3 + 1, char);
6782
6783         strncpy(result, s1, len1+1);
6784         strncpy(result + len1, s2, len2+1);
6785         strncpy(result + len1 + len2, s3, len3+1);
6786         result[len1 + len2 + len3] = '\0';
6787
6788         return result;
6789 }
6790
6791 \f
6792 /* Does the same work as the system V getcwd, but does not need to
6793    guess the buffer size in advance. */
6794 static char *
6795 etags_getcwd ()
6796 {
6797 #ifdef HAVE_GETCWD
6798         int bufsize = 200;
6799         char *path = xnew (bufsize, char);
6800
6801         while (getcwd (path, bufsize) == NULL)
6802         {
6803                 if (errno != ERANGE)
6804                         pfatal ("getcwd");
6805                 bufsize *= 2;
6806                 free (path);
6807                 path = xnew (bufsize, char);
6808         }
6809
6810         canonicalize_filename (path);
6811         return path;
6812
6813 #else /* not HAVE_GETCWD */
6814         linebuffer path;
6815         FILE *pipe;
6816
6817         linebuffer_init (&path);
6818         pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
6819         if (pipe == NULL || readline_internal (&path, pipe) == 0)
6820                 pfatal ("pwd");
6821         pclose (pipe);
6822
6823         return path.buffer;
6824 #endif /* not HAVE_GETCWD */
6825 }
6826
6827 /* Return a newly allocated string containing the file name of FILE
6828    relative to the absolute directory DIR (which should end with a slash). */
6829 static char *
6830 relative_filename (file, dir)
6831 char *file, *dir;
6832 {
6833         char *fp, *dp, *afn, *res;
6834         int i;
6835         ssize_t res_left;
6836
6837         /* Find the common root of file and dir (with a trailing slash). */
6838         afn = absolute_filename (file, cwd);
6839         fp = afn;
6840         dp = dir;
6841         while (*fp++ == *dp++)
6842                 continue;
6843         fp--, dp--;                     /* back to the first differing char */
6844         do                              /* look at the equal chars until '/' */
6845                 fp--, dp--;
6846         while (*fp != '/');
6847         fp ++; /* Advance past the '/' */
6848
6849         /* Build a sequence of "../" strings for the resulting relative file name. */
6850         i = 0;
6851         while ((dp = etags_strchr (dp + 1, '/')) != NULL)
6852                 i += 1;
6853         res_left = 3 * i + strlen(fp);
6854         res = xnew( res_left + 1, char);
6855         res[0] = '\0';
6856         for ( ; i-- > 0 ; res_left -= 4 )
6857                 strncat(res, "../", res_left );
6858
6859         /* Add the file name relative to the common root of file and dir. */
6860         strncat(res, fp, res_left);
6861         free(afn);
6862
6863         return res;
6864 }
6865
6866 /* Return a newly allocated string containing the absolute file name
6867    of FILE given DIR (which should end with a slash). */
6868 static char *
6869 absolute_filename (file, dir)
6870 char *file, *dir;
6871 {
6872         char *slashp, *cp, *res;
6873
6874         if (filename_is_absolute (file))
6875                 res = savestr (file);
6876         else
6877                 res = concat (dir, file, "");
6878
6879         /* Delete the "/dirname/.." and "/." substrings. */
6880         slashp = etags_strchr (res, '/');
6881         while (slashp != NULL && slashp[0] != '\0')
6882         {
6883                 if (slashp[1] == '.')
6884                 {
6885                         if (slashp[2] == '.'
6886                             && (slashp[3] == '/' || slashp[3] == '\0'))
6887                         {
6888                                 cp = slashp;
6889                                 do
6890                                         cp--;
6891                                 while (cp >= res && !filename_is_absolute (cp));
6892                                 if (cp < res)
6893                                         cp = slashp;    /* the absolute name begins with "/.." */
6894                                 strcpy (cp, slashp + 3);
6895                                 slashp = cp;
6896                                 continue;
6897                         }
6898                         else if (slashp[2] == '/' || slashp[2] == '\0')
6899                         {
6900                                 strcpy (slashp, slashp + 2);
6901                                 continue;
6902                         }
6903                 }
6904
6905                 slashp = etags_strchr (slashp + 1, '/');
6906         }
6907
6908         if (res[0] == '\0')             /* just a safety net: should never happen */
6909         {
6910                 free (res);
6911                 return savestr ("/");
6912         }
6913         else
6914                 return res;
6915 }
6916
6917 /* Return a newly allocated string containing the absolute
6918    file name of dir where FILE resides given DIR (which should
6919    end with a slash). */
6920 static char *
6921 absolute_dirname (file, dir)
6922 char *file, *dir;
6923 {
6924         char *slashp, *res;
6925         char save;
6926
6927         slashp = etags_strrchr (file, '/');
6928         if (slashp == NULL)
6929                 return savestr (dir);
6930         save = slashp[1];
6931         slashp[1] = '\0';
6932         res = absolute_filename (file, dir);
6933         slashp[1] = save;
6934
6935         return res;
6936 }
6937
6938 /* Whether the argument string is an absolute file name.  The argument
6939    string must have been canonicalized with canonicalize_filename. */
6940 static bool
6941 filename_is_absolute (fn)
6942 char *fn;
6943 {
6944         return (fn[0] == '/');
6945 }
6946
6947 /* Upcase DOS drive letter and collapse separators into single slashes.
6948    Works in place. */
6949 static void
6950 canonicalize_filename (fn)
6951 register char *fn;
6952 {
6953         register char* cp;
6954         char sep = '/';
6955
6956         /* Collapse multiple separators into a single slash. */
6957         for (cp = fn; *cp != '\0'; cp++, fn++)
6958                 if (*cp == sep)
6959                 {
6960                         *fn = '/';
6961                         while (cp[1] == sep)
6962                                 cp++;
6963                 }
6964                 else
6965                         *fn = *cp;
6966         *fn = '\0';
6967 }
6968
6969 \f
6970 /* Initialize a linebuffer for use. */
6971 static void
6972 linebuffer_init (lbp)
6973 linebuffer *lbp;
6974 {
6975         lbp->size = (DEBUG) ? 3 : 200;
6976         lbp->buffer = xnew (lbp->size, char);
6977         lbp->buffer[0] = '\0';
6978         lbp->len = 0;
6979 }
6980
6981 /* Set the minimum size of a string contained in a linebuffer. */
6982 static void
6983 linebuffer_setlen (lbp, toksize)
6984 linebuffer *lbp;
6985 int toksize;
6986 {
6987         while (lbp->size <= toksize)
6988         {
6989                 lbp->size *= 2;
6990                 xrnew (lbp->buffer, lbp->size, char);
6991         }
6992         lbp->len = toksize;
6993 }
6994
6995 /* Like malloc but get fatal error if memory is exhausted. */
6996 static PTR
6997 xmalloc (size)
6998 unsigned int size;
6999 {
7000         PTR result = (PTR) malloc (size);
7001         if (result == NULL)
7002                 fatal ("virtual memory exhausted", (char *)NULL);
7003         return result;
7004 }
7005
7006 static PTR
7007 xrealloc (ptr, size)
7008 char *ptr;
7009 unsigned int size;
7010 {
7011         PTR result = (PTR) realloc (ptr, size);
7012         if (result == NULL)
7013                 fatal ("virtual memory exhausted", (char *)NULL);
7014         return result;
7015 }
7016
7017 /*
7018  * Local Variables:
7019  * indent-tabs-mode: t
7020  * tab-width: 8
7021  * fill-column: 79
7022  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
7023  * End:
7024  */
7025
7026 /* etags.c ends here */