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