9b5756ee82fae555795005bcefad47fe9690fe15
[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         return NULL;
1617 }
1618
1619 \f
1620 /*
1621  * This routine is called on each file argument.
1622  */
1623 static void
1624 process_file_name (file, lang)
1625 char *file;
1626 language *lang;
1627 {
1628         struct stat stat_buf;
1629         FILE *inf = NULL;
1630         fdesc *fdp = NULL;
1631         compressor *compr = NULL;
1632         char *compressed_name = NULL, 
1633              *uncompressed_name = NULL;
1634         char *ext = NULL, 
1635              *real_name = NULL;
1636         int retval;
1637
1638         canonicalize_filename (file);
1639         if (streq (file, tagfile) && !streq (tagfile, "-"))
1640         {
1641                 error ("skipping inclusion of %s in self.", file);
1642                 return;
1643         }
1644         if ( get_compressor_from_suffix (file, &ext) == NULL)
1645         {
1646                 real_name = uncompressed_name = savestr (file);
1647         }
1648         else
1649         {
1650                 real_name = compressed_name = savestr (file);
1651                 uncompressed_name = savenstr (file, ext - file);
1652         }
1653
1654         /* If the canonicalized uncompressed name
1655            has already been dealt with, skip it silently. */
1656         for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1657         {
1658                 assert (fdp->infname != NULL);
1659                 if (streq (uncompressed_name, fdp->infname))
1660                         goto cleanup;
1661         }
1662
1663         compr = compressors;
1664         do {
1665                 /* First try to open ... */
1666                 if (real_name == compressed_name)
1667                 {
1668                         char *cmd = concat (compr->command, " ", real_name);
1669                         inf = (FILE *) popen (cmd, "r");
1670                         free (cmd);
1671                 }
1672                 else
1673                         inf = fopen (real_name, "r");
1674                 if ( inf != NULL ) {
1675                         /* Open was successfull, check it is a regular file */
1676                         if (stat (real_name, &stat_buf) == 0 && 
1677                             !S_ISREG (stat_buf.st_mode))
1678                         {
1679                                 error ("skipping %s: it is not a regular file.", 
1680                                        real_name);
1681                                 fclose(inf);
1682                                 inf = NULL;
1683                         }
1684                 } 
1685                 /* Not else from previous if because inner check may reset inf
1686                    to NULL, at which case we will want to try the next?
1687                    compressed filename... */
1688                 if ( inf == NULL ) {
1689                         /* Reset real_name and try with a different name. */
1690                         free(compressed_name);
1691                         real_name = NULL;
1692                         if (compressed_name != NULL) 
1693                                 /* try with the given suffix */
1694                         {
1695                                 compressed_name = NULL;
1696                                 real_name = uncompressed_name;
1697                         }
1698                         else if ( compr && compr->suffix != NULL ) 
1699                                 /* try all possible suffixes */
1700                         {
1701                                 compressed_name = concat (file, ".", compr->suffix);
1702                                 real_name = compressed_name;
1703                                 compr++;
1704                         }
1705                 }
1706         } while( inf == NULL && real_name != NULL);
1707         if (inf == NULL)
1708         {
1709                 perror (real_name);
1710                 goto cleanup;
1711         }
1712
1713         process_file (inf, uncompressed_name, lang);
1714
1715         if (real_name == compressed_name)
1716                 retval = pclose (inf);
1717         else
1718                 retval = fclose (inf);
1719         if (retval < 0)
1720                 pfatal (file);
1721
1722 cleanup:
1723         free (compressed_name);
1724         free (uncompressed_name);
1725         last_node = NULL;
1726         curfdp = NULL;
1727         return;
1728 }
1729
1730 static void
1731 process_file (fh, fn, lang)
1732 FILE *fh;
1733 char *fn;
1734 language *lang;
1735 {
1736         static const fdesc emptyfdesc;
1737         fdesc *fdp;
1738
1739         /* Create a new input file description entry. */
1740         fdp = xnew (1, fdesc);
1741         *fdp = emptyfdesc;
1742         fdp->next = fdhead;
1743         fdp->infname = savestr (fn);
1744         fdp->lang = lang;
1745         fdp->infabsname = absolute_filename (fn, cwd);
1746         fdp->infabsdir = absolute_dirname (fn, cwd);
1747         if (filename_is_absolute (fn))
1748         {
1749                 /* An absolute file name.  Canonicalize it. */
1750                 fdp->taggedfname = absolute_filename (fn, NULL);
1751         }
1752         else
1753         {
1754                 /* A file name relative to cwd.  Make it relative
1755                    to the directory of the tags file. */
1756                 fdp->taggedfname = relative_filename (fn, tagfiledir);
1757         }
1758         fdp->usecharno = TRUE;  /* use char position when making tags */
1759         fdp->prop = NULL;
1760         fdp->written = FALSE;           /* not written on tags file yet */
1761
1762         fdhead = fdp;
1763         curfdp = fdhead;                /* the current file description */
1764
1765         find_entries (fh);
1766
1767         /* If not Ctags, and if this is not metasource and if it contained no #line
1768            directives, we can write the tags and free all nodes pointing to
1769            curfdp. */
1770         if (!CTAGS
1771             && curfdp->usecharno        /* no #line directives in this file */
1772             && !curfdp->lang->metasource)
1773         {
1774                 node *np, *prev;
1775
1776                 /* Look for the head of the sublist relative to this file.  See add_node
1777                    for the structure of the node tree. */
1778                 prev = NULL;
1779                 for (np = nodehead; np != NULL; prev = np, np = np->left)
1780                         if (np->fdp == curfdp)
1781                                 break;
1782
1783                 /* If we generated tags for this file, write and delete them. */
1784                 if (np != NULL)
1785                 {
1786                         /* This is the head of the last sublist, if any.  The following
1787                            instructions depend on this being true. */
1788                         assert (np->left == NULL);
1789
1790                         assert (fdhead == curfdp);
1791                         assert (last_node->fdp == curfdp);
1792                         put_entries (np);       /* write tags for file curfdp->taggedfname */
1793                         free_tree (np); /* remove the written nodes */
1794                         if (prev == NULL)
1795                                 nodehead = NULL;        /* no nodes left */
1796                         else
1797                                 prev->left = NULL;      /* delete the pointer to the sublist */
1798                 }
1799         }
1800 }
1801
1802 /*
1803  * This routine sets up the boolean pseudo-functions which work
1804  * by setting boolean flags dependent upon the corresponding character.
1805  * Every char which is NOT in that string is not a white char.  Therefore,
1806  * all of the array "_wht" is set to FALSE, and then the elements
1807  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
1808  * of a char is TRUE if it is the string "white", else FALSE.
1809  */
1810 static void
1811 init ()
1812 {
1813         register char *sp;
1814         register int i;
1815
1816         for (i = 0; i < CHARS; i++)
1817                 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1818         for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1819         for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1820         notinname('\0') = notinname('\n');
1821         for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1822         begtoken('\0') = begtoken('\n');
1823         for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1824         intoken('\0') = intoken('\n');
1825         for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1826         endtoken('\0') = endtoken('\n');
1827 }
1828
1829 /*
1830  * This routine opens the specified file and calls the function
1831  * which finds the function and type definitions.
1832  */
1833 static void
1834 find_entries (inf)
1835 FILE *inf;
1836 {
1837         char *cp;
1838         language *lang = curfdp->lang;
1839         Lang_function *parser = NULL;
1840
1841         /* If user specified a language, use it. */
1842         if (lang != NULL && lang->function != NULL)
1843         {
1844                 parser = lang->function;
1845         }
1846
1847         /* Else try to guess the language given the file name. */
1848         if (parser == NULL)
1849         {
1850                 lang = get_language_from_filename (curfdp->infname, TRUE);
1851                 if (lang != NULL && lang->function != NULL)
1852                 {
1853                         curfdp->lang = lang;
1854                         parser = lang->function;
1855                 }
1856         }
1857
1858         /* Else look for sharp-bang as the first two characters. */
1859         if (parser == NULL
1860             && readline_internal (&lb, inf) > 0
1861             && lb.len >= 2
1862             && lb.buffer[0] == '#'
1863             && lb.buffer[1] == '!')
1864         {
1865                 char *lp;
1866
1867                 /* Set lp to point at the first char after the last slash in the
1868                    line or, if no slashes, at the first nonblank.  Then set cp to
1869                    the first successive blank and terminate the string. */
1870                 lp = etags_strrchr (lb.buffer+2, '/');
1871                 if (lp != NULL)
1872                         lp += 1;
1873                 else
1874                         lp = skip_spaces (lb.buffer + 2);
1875                 cp = skip_non_spaces (lp);
1876                 *cp = '\0';
1877
1878                 if (strlen (lp) > 0)
1879                 {
1880                         lang = get_language_from_interpreter (lp);
1881                         if (lang != NULL && lang->function != NULL)
1882                         {
1883                                 curfdp->lang = lang;
1884                                 parser = lang->function;
1885                         }
1886                 }
1887         }
1888
1889         /* We rewind here, even if inf may be a pipe.  We fail if the
1890            length of the first line is longer than the pipe block size,
1891            which is unlikely. */
1892         rewind (inf);
1893
1894         /* Else try to guess the language given the case insensitive file name. */
1895         if (parser == NULL)
1896         {
1897                 lang = get_language_from_filename (curfdp->infname, FALSE);
1898                 if (lang != NULL && lang->function != NULL)
1899                 {
1900                         curfdp->lang = lang;
1901                         parser = lang->function;
1902                 }
1903         }
1904
1905         /* Else try Fortran or C. */
1906         if (parser == NULL)
1907         {
1908                 node *old_last_node = last_node;
1909
1910                 curfdp->lang = get_language_from_langname ("fortran");
1911                 find_entries (inf);
1912
1913                 if (old_last_node == last_node)
1914                         /* No Fortran entries found.  Try C. */
1915                 {
1916                         /* We do not tag if rewind fails.
1917                            Only the file name will be recorded in the tags file. */
1918                         rewind (inf);
1919                         curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
1920                         find_entries (inf);
1921                 }
1922                 return;
1923         }
1924
1925         if (!no_line_directive
1926             && curfdp->lang != NULL && curfdp->lang->metasource)
1927                 /* It may be that this is a bingo.y file, and we already parsed a bingo.c
1928                    file, or anyway we parsed a file that is automatically generated from
1929                    this one.  If this is the case, the bingo.c file contained #line
1930                    directives that generated tags pointing to this file.  Let's delete
1931                    them all before parsing this file, which is the real source. */
1932         {
1933                 fdesc **fdpp = &fdhead;
1934                 while (*fdpp != NULL)
1935                         if (*fdpp != curfdp
1936                             && streq ((*fdpp)->taggedfname, curfdp->taggedfname))
1937                                 /* We found one of those!  We must delete both the file description
1938                                    and all tags referring to it. */
1939                         {
1940                                 fdesc *badfdp = *fdpp;
1941
1942                                 /* Delete the tags referring to badfdp->taggedfname
1943                                    that were obtained from badfdp->infname. */
1944                                 invalidate_nodes (badfdp, &nodehead);
1945
1946                                 *fdpp = badfdp->next; /* remove the bad description from the list */
1947                                 free_fdesc (badfdp);
1948                         }
1949                         else
1950                                 fdpp = &(*fdpp)->next; /* advance the list pointer */
1951         }
1952
1953         assert (parser != NULL);
1954
1955         /* Generic initialisations before reading from file. */
1956         linebuffer_setlen (&filebuf, 0); /* reset the file buffer */
1957
1958         /* Generic initialisations before parsing file with readline. */
1959         lineno = 0;                    /* reset global line number */
1960         charno = 0;                    /* reset global char number */
1961         linecharno = 0;        /* reset global char number of line start */
1962
1963         parser (inf);
1964
1965         regex_tag_multiline ();
1966 }
1967
1968 \f
1969 /*
1970  * Check whether an implicitly named tag should be created,
1971  * then call `pfnote'.
1972  * NAME is a string that is internally copied by this function.
1973  *
1974  * TAGS format specification
1975  * Idea by Sam Kendall <kendall@mv.mv.com> (1997)
1976  * The following is explained in some more detail in etc/ETAGS.EBNF.
1977  *
1978  * make_tag creates tags with "implicit tag names" (unnamed tags)
1979  * if the following are all true, assuming NONAM=" \f\t\n\r()=,;":
1980  *  1. NAME does not contain any of the characters in NONAM;
1981  *  2. LINESTART contains name as either a rightmost, or rightmost but
1982  *     one character, substring;
1983  *  3. the character, if any, immediately before NAME in LINESTART must
1984  *     be a character in NONAM;
1985  *  4. the character, if any, immediately after NAME in LINESTART must
1986  *     also be a character in NONAM.
1987  *
1988  * The implementation uses the notinname() macro, which recognises the
1989  * characters stored in the string `nonam'.
1990  * etags.el needs to use the same characters that are in NONAM.
1991  */
1992 static void
1993 make_tag (name, namelen, is_func, linestart, linelen, lno, cno)
1994 char *name;             /* tag name, or NULL if unnamed */
1995 int namelen;            /* tag length */
1996 bool is_func;           /* tag is a function */
1997 char *linestart;                /* start of the line where tag is */
1998 int linelen;            /* length of the line where tag is */
1999 int lno;                        /* line number */
2000 long cno;                       /* character number */
2001 {
2002         bool named = (name != NULL && namelen > 0);
2003
2004         if (!CTAGS && named)            /* maybe set named to false */
2005                 /* Let's try to make an implicit tag name, that is, create an unnamed tag
2006                    such that etags.el can guess a name from it. */
2007         {
2008                 int i;
2009                 register char *cp = name;
2010
2011                 for (i = 0; i < namelen; i++)
2012                         if (notinname (*cp++))
2013                                 break;
2014                 if (i == namelen)                               /* rule #1 */
2015                 {
2016                         cp = linestart + linelen - namelen;
2017                         if (notinname (linestart[linelen-1]))
2018                                 cp -= 1;                                /* rule #4 */
2019                         if (cp >= linestart                     /* rule #2 */
2020                             && (cp == linestart
2021                                 || notinname (cp[-1]))  /* rule #3 */
2022                             && strneq (name, cp, namelen))      /* rule #2 */
2023                                 named = FALSE;  /* use implicit tag name */
2024                 }
2025         }
2026
2027         if (named)
2028                 name = savenstr (name, namelen);
2029         else
2030                 name = NULL;
2031         pfnote (name, is_func, linestart, linelen, lno, cno);
2032 }
2033
2034 /* Record a tag. */
2035 static void
2036 pfnote (name, is_func, linestart, linelen, lno, cno)
2037 char *name;             /* tag name, or NULL if unnamed */
2038 bool is_func;           /* tag is a function */
2039 char *linestart;                /* start of the line where tag is */
2040 int linelen;            /* length of the line where tag is */
2041 int lno;                        /* line number */
2042 long cno;                       /* character number */
2043 {
2044         register node *np;
2045
2046         assert (name == NULL || name[0] != '\0');
2047         if (CTAGS && name == NULL)
2048                 return;
2049
2050         np = xnew (1, node);
2051
2052         /* If ctags mode, change name "main" to M<thisfilename>. */
2053         if (CTAGS && !cxref_style && streq (name, "main"))
2054         {
2055                 register char *fp = etags_strrchr (curfdp->taggedfname, '/');
2056                 np->name = concat ("M", fp == NULL ? curfdp->taggedfname : fp + 1, "");
2057                 fp = etags_strrchr (np->name, '.');
2058                 if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
2059                         fp[0] = '\0';
2060         }
2061         else
2062                 np->name = name;
2063         np->valid = TRUE;
2064         np->been_warned = FALSE;
2065         np->fdp = curfdp;
2066         np->is_func = is_func;
2067         np->lno = lno;
2068         if (np->fdp->usecharno)
2069                 /* Our char numbers are 0-base, because of C language tradition?
2070                    ctags compatibility?  old versions compatibility?   I don't know.
2071                    Anyway, since emacs's are 1-base we expect etags.el to take care
2072                    of the difference.  If we wanted to have 1-based numbers, we would
2073                    uncomment the +1 below. */
2074                 np->cno = cno /* + 1 */ ;
2075         else
2076                 np->cno = invalidcharno;
2077         np->left = np->right = NULL;
2078         if (CTAGS && !cxref_style)
2079         {
2080                 if (strlen (linestart) < 50)
2081                         np->regex = concat (linestart, "$", "");
2082                 else
2083                         np->regex = savenstr (linestart, 50);
2084         }
2085         else
2086                 np->regex = savenstr (linestart, linelen);
2087
2088         add_node (np, &nodehead);
2089 }
2090
2091 /*
2092  * free_tree ()
2093  *      recurse on left children, iterate on right children.
2094  */
2095 static void
2096 free_tree (np)
2097 register node *np;
2098 {
2099         while (np)
2100         {
2101                 register node *node_right = np->right;
2102                 free_tree (np->left);
2103                 free (np->name);
2104                 free (np->regex);
2105                 free (np);
2106                 np = node_right;
2107         }
2108 }
2109
2110 /*
2111  * free_fdesc ()
2112  *      delete a file description
2113  */
2114 static void
2115 free_fdesc (fdp)
2116 register fdesc *fdp;
2117 {
2118         free (fdp->infname);
2119         free (fdp->infabsname);
2120         free (fdp->infabsdir);
2121         free (fdp->taggedfname);
2122         free (fdp->prop);
2123         free (fdp);
2124 }
2125
2126 /*
2127  * add_node ()
2128  *      Adds a node to the tree of nodes.  In etags mode, sort by file
2129  *      name.  In ctags mode, sort by tag name.  Make no attempt at
2130  *      balancing.
2131  *
2132  *      add_node is the only function allowed to add nodes, so it can
2133  *      maintain state.
2134  */
2135 static void
2136 add_node (np, cur_node_p)
2137 node *np, **cur_node_p;
2138 {
2139         register int dif;
2140         register node *cur_node = *cur_node_p;
2141
2142         if (cur_node == NULL)
2143         {
2144                 *cur_node_p = np;
2145                 last_node = np;
2146                 return;
2147         }
2148
2149         if (!CTAGS)
2150                 /* Etags Mode */
2151         {
2152                 /* For each file name, tags are in a linked sublist on the right
2153                    pointer.  The first tags of different files are a linked list
2154                    on the left pointer.  last_node points to the end of the last
2155                    used sublist. */
2156                 if (last_node != NULL && last_node->fdp == np->fdp)
2157                 {
2158                         /* Let's use the same sublist as the last added node. */
2159                         assert (last_node->right == NULL);
2160                         last_node->right = np;
2161                         last_node = np;
2162                 }
2163                 else if (cur_node->fdp == np->fdp)
2164                 {
2165                         /* Scanning the list we found the head of a sublist which is
2166                            good for us.  Let's scan this sublist. */
2167                         add_node (np, &cur_node->right);
2168                 }
2169                 else
2170                         /* The head of this sublist is not good for us.  Let's try the
2171                            next one. */
2172                         add_node (np, &cur_node->left);
2173         } /* if ETAGS mode */
2174
2175         else
2176         {
2177                 /* Ctags Mode */
2178                 dif = strcmp (np->name, cur_node->name);
2179
2180                 /*
2181                  * If this tag name matches an existing one, then
2182                  * do not add the node, but maybe print a warning.
2183                  */
2184                 if (no_duplicates && !dif)
2185                 {
2186                         if (np->fdp == cur_node->fdp)
2187                         {
2188                                 if (!no_warnings)
2189                                 {
2190                                         fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
2191                                                  np->fdp->infname, lineno, np->name);
2192                                         fprintf (stderr, "Second entry ignored\n");
2193                                 }
2194                         }
2195                         else if (!cur_node->been_warned && !no_warnings)
2196                         {
2197                                 fprintf
2198                                         (stderr,
2199                                          "Duplicate entry in files %s and %s: %s (Warning only)\n",
2200                                          np->fdp->infname, cur_node->fdp->infname, np->name);
2201                                 cur_node->been_warned = TRUE;
2202                         }
2203                         return;
2204                 }
2205
2206                 /* Actually add the node */
2207                 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
2208         } /* if CTAGS mode */
2209 }
2210
2211 /*
2212  * invalidate_nodes ()
2213  *      Scan the node tree and invalidate all nodes pointing to the
2214  *      given file description (CTAGS case) or free them (ETAGS case).
2215  */
2216 static void
2217 invalidate_nodes (badfdp, npp)
2218 fdesc *badfdp;
2219 node **npp;
2220 {
2221         node *np = *npp;
2222
2223         if (np == NULL)
2224                 return;
2225
2226         if (CTAGS)
2227         {
2228                 if (np->left != NULL)
2229                         invalidate_nodes (badfdp, &np->left);
2230                 if (np->fdp == badfdp)
2231                         np->valid = FALSE;
2232                 if (np->right != NULL)
2233                         invalidate_nodes (badfdp, &np->right);
2234         }
2235         else
2236         {
2237                 assert (np->fdp != NULL);
2238                 if (np->fdp == badfdp)
2239                 {
2240                         *npp = np->left;        /* detach the sublist from the list */
2241                         np->left = NULL;        /* isolate it */
2242                         free_tree (np); /* free it */
2243                         invalidate_nodes (badfdp, npp);
2244                 }
2245                 else
2246                         invalidate_nodes (badfdp, &np->left);
2247         }
2248 }
2249
2250 \f
2251 static int total_size_of_entries __P((node *));
2252 static int number_len __P((long));
2253
2254 /* Length of a non-negative number's decimal representation. */
2255 static int
2256 number_len (num)
2257 long num;
2258 {
2259         int len = 1;
2260         while ((num /= 10) > 0)
2261                 len += 1;
2262         return len;
2263 }
2264
2265 /*
2266  * Return total number of characters that put_entries will output for
2267  * the nodes in the linked list at the right of the specified node.
2268  * This count is irrelevant with etags.el since emacs 19.34 at least,
2269  * but is still supplied for backward compatibility.
2270  */
2271 static int
2272 total_size_of_entries (np)
2273 register node *np;
2274 {
2275         register int total = 0;
2276
2277         for (; np != NULL; np = np->right)
2278                 if (np->valid)
2279                 {
2280                         total += strlen (np->regex) + 1;                /* pat\177 */
2281                         if (np->name != NULL)
2282                                 total += strlen (np->name) + 1;         /* name\001 */
2283                         total += number_len ((long) np->lno) + 1;       /* lno, */
2284                         if (np->cno != invalidcharno)                   /* cno */
2285                                 total += number_len (np->cno);
2286                         total += 1;                                     /* newline */
2287                 }
2288
2289         return total;
2290 }
2291
2292 static void
2293 put_entries (np)
2294 register node *np;
2295 {
2296         register char *sp;
2297         static fdesc *fdp = NULL;
2298
2299         if (np == NULL)
2300                 return;
2301
2302         /* Output subentries that precede this one */
2303         if (CTAGS)
2304                 put_entries (np->left);
2305
2306         /* Output this entry */
2307         if (np->valid)
2308         {
2309                 if (!CTAGS)
2310                 {
2311                         /* Etags mode */
2312                         if (fdp != np->fdp)
2313                         {
2314                                 fdp = np->fdp;
2315                                 fprintf (tagf, "\f\n%s,%d\n",
2316                                          fdp->taggedfname, total_size_of_entries (np));
2317                                 fdp->written = TRUE;
2318                         }
2319                         fputs (np->regex, tagf);
2320                         fputc ('\177', tagf);
2321                         if (np->name != NULL)
2322                         {
2323                                 fputs (np->name, tagf);
2324                                 fputc ('\001', tagf);
2325                         }
2326                         fprintf (tagf, "%d,", np->lno);
2327                         if (np->cno != invalidcharno)
2328                                 fprintf (tagf, "%ld", np->cno);
2329                         fputs ("\n", tagf);
2330                 }
2331                 else
2332                 {
2333                         /* Ctags mode */
2334                         if (np->name == NULL)
2335                                 error ("internal error: NULL name in ctags mode.", (char *)NULL);
2336
2337                         if (cxref_style)
2338                         {
2339                                 if (vgrind_style)
2340                                         fprintf (stdout, "%s %s %d\n",
2341                                                  np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
2342                                 else
2343                                         fprintf (stdout, "%-16s %3d %-16s %s\n",
2344                                                  np->name, np->lno, np->fdp->taggedfname, np->regex);
2345                         }
2346                         else
2347                         {
2348                                 fprintf (tagf, "%s\t%s\t", np->name, np->fdp->taggedfname);
2349
2350                                 if (np->is_func)
2351                                 {               /* function or #define macro with args */
2352                                         putc (searchar, tagf);
2353                                         putc ('^', tagf);
2354
2355                                         for (sp = np->regex; *sp; sp++)
2356                                         {
2357                                                 if (*sp == '\\' || *sp == searchar)
2358                                                         putc ('\\', tagf);
2359                                                 putc (*sp, tagf);
2360                                         }
2361                                         putc (searchar, tagf);
2362                                 }
2363                                 else
2364                                 {               /* anything else; text pattern inadequate */
2365                                         fprintf (tagf, "%d", np->lno);
2366                                 }
2367                                 putc ('\n', tagf);
2368                         }
2369                 }
2370         } /* if this node contains a valid tag */
2371
2372         /* Output subentries that follow this one */
2373         put_entries (np->right);
2374         if (!CTAGS)
2375                 put_entries (np->left);
2376 }
2377
2378 \f
2379 /* C extensions. */
2380 #define C_EXT   0x00fff         /* C extensions */
2381 #define C_PLAIN 0x00000         /* C */
2382 #define C_PLPL  0x00001         /* C++ */
2383 #define C_STAR  0x00003         /* C* */
2384 #define C_JAVA  0x00005         /* JAVA */
2385 #define C_AUTO  0x01000         /* C, but switch to C++ if `class' is met */
2386 #define YACC    0x10000         /* yacc file */
2387
2388 /*
2389  * The C symbol tables.
2390  */
2391 enum sym_type
2392 {
2393         st_none,
2394         st_C_objprot, st_C_objimpl, st_C_objend,
2395         st_C_gnumacro,
2396         st_C_ignore, st_C_attribute,
2397         st_C_javastruct,
2398         st_C_operator,
2399         st_C_class, st_C_template,
2400         st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef
2401 };
2402
2403 static unsigned int hash __P((const char *, unsigned int));
2404 static struct C_stab_entry * in_word_set __P((const char *, unsigned int));
2405 static enum sym_type C_symtype __P((char *, int, int));
2406
2407 /* Feed stuff between (but not including) %[ and %] lines to:
2408    gperf -m 5
2409    %[
2410    %compare-strncmp
2411    %enum
2412    %struct-type
2413    struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
2414    %%
2415    if,                  0,                      st_C_ignore
2416    for,                 0,                      st_C_ignore
2417    while,               0,                      st_C_ignore
2418    switch,              0,                      st_C_ignore
2419    return,              0,                      st_C_ignore
2420    __attribute__,       0,                      st_C_attribute
2421    GTY,                 0,                      st_C_attribute
2422    @interface,          0,                      st_C_objprot
2423    @protocol,           0,                      st_C_objprot
2424    @implementation,     0,                      st_C_objimpl
2425    @end,                0,                      st_C_objend
2426    import,              (C_JAVA & ~C_PLPL),     st_C_ignore
2427    package,             (C_JAVA & ~C_PLPL),     st_C_ignore
2428    friend,              C_PLPL,                 st_C_ignore
2429    extends,             (C_JAVA & ~C_PLPL),     st_C_javastruct
2430    implements,          (C_JAVA & ~C_PLPL),     st_C_javastruct
2431    interface,           (C_JAVA & ~C_PLPL),     st_C_struct
2432    class,               0,                      st_C_class
2433    namespace,           C_PLPL,                 st_C_struct
2434    domain,              C_STAR,                 st_C_struct
2435    union,               0,                      st_C_struct
2436    struct,              0,                      st_C_struct
2437    extern,              0,                      st_C_extern
2438    enum,                0,                      st_C_enum
2439    typedef,             0,                      st_C_typedef
2440    define,              0,                      st_C_define
2441    undef,               0,                      st_C_define
2442    operator,            C_PLPL,                 st_C_operator
2443    template,            0,                      st_C_template
2444    # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
2445    DEFUN,               0,                      st_C_gnumacro
2446    SYSCALL,             0,                      st_C_gnumacro
2447    ENTRY,               0,                      st_C_gnumacro
2448    PSEUDO,              0,                      st_C_gnumacro
2449    # These are defined inside C functions, so currently they are not met.
2450    # EXFUN used in glibc, DEFVAR_* in emacs.
2451    #EXFUN,              0,                      st_C_gnumacro
2452    #DEFVAR_,            0,                      st_C_gnumacro
2453    %]
2454    and replace lines between %< and %> with its output, then:
2455    - remove the #if characterset check
2456    - make in_word_set static and not inline. */
2457 /*%<*/
2458 /* C code produced by gperf version 3.0.1 */
2459 /* Command-line: gperf -m 5  */
2460 /* Computed positions: -k'2-3' */
2461
2462 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
2463 /* maximum key range = 33, duplicates = 0 */
2464
2465 #ifdef __GNUC__
2466 __inline
2467 #else
2468 #ifdef __cplusplus
2469 inline
2470 #endif
2471 #endif
2472 static unsigned int
2473 hash (str, len)
2474 register const char *str;
2475 register unsigned int len;
2476 {
2477         static unsigned char asso_values[] =
2478                 {
2479                         35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
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,  3,
2486                         26, 35, 35, 35, 35, 35, 35, 35, 27, 35,
2487                         35, 35, 35, 24,  0, 35, 35, 35, 35,  0,
2488                         35, 35, 35, 35, 35,  1, 35, 16, 35,  6,
2489                         23,  0,  0, 35, 22,  0, 35, 35,  5,  0,
2490                         0, 15,  1, 35,  6, 35,  8, 19, 35, 16,
2491                         4,  5, 35, 35, 35, 35, 35, 35, 35, 35,
2492                         35, 35, 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
2505                 };
2506         register int hval = len;
2507
2508         switch (hval)
2509         {
2510         default:
2511                 hval += asso_values[(unsigned char)str[2]];
2512                 /*FALLTHROUGH*/
2513         case 2:
2514                 hval += asso_values[(unsigned char)str[1]];
2515                 break;
2516         }
2517         return hval;
2518 }
2519
2520 static struct C_stab_entry *
2521 in_word_set (str, len)
2522 register const char *str;
2523 register unsigned int len;
2524 {
2525         enum
2526         {
2527                 TOTAL_KEYWORDS = 33,
2528                 MIN_WORD_LENGTH = 2,
2529                 MAX_WORD_LENGTH = 15,
2530                 MIN_HASH_VALUE = 2,
2531                 MAX_HASH_VALUE = 34
2532         };
2533
2534         static struct C_stab_entry wordlist[] =
2535                 {
2536                         {""}, {""},
2537                         {"if",          0,                      st_C_ignore},
2538                         {"GTY",           0,                      st_C_attribute},
2539                         {"@end",                0,                      st_C_objend},
2540                         {"union",               0,                      st_C_struct},
2541                         {"define",              0,                      st_C_define},
2542                         {"import",              (C_JAVA & ~C_PLPL),     st_C_ignore},
2543                         {"template",    0,                      st_C_template},
2544                         {"operator",    C_PLPL,                 st_C_operator},
2545                         {"@interface",  0,                      st_C_objprot},
2546                         {"implements",  (C_JAVA & ~C_PLPL),     st_C_javastruct},
2547                         {"friend",              C_PLPL,                 st_C_ignore},
2548                         {"typedef",     0,                      st_C_typedef},
2549                         {"return",              0,                      st_C_ignore},
2550                         {"@implementation",0,                   st_C_objimpl},
2551                         {"@protocol",   0,                      st_C_objprot},
2552                         {"interface",   (C_JAVA & ~C_PLPL),     st_C_struct},
2553                         {"extern",              0,                      st_C_extern},
2554                         {"extends",     (C_JAVA & ~C_PLPL),     st_C_javastruct},
2555                         {"struct",              0,                      st_C_struct},
2556                         {"domain",              C_STAR,                 st_C_struct},
2557                         {"switch",              0,                      st_C_ignore},
2558                         {"enum",                0,                      st_C_enum},
2559                         {"for",         0,                      st_C_ignore},
2560                         {"namespace",   C_PLPL,                 st_C_struct},
2561                         {"class",               0,                      st_C_class},
2562                         {"while",               0,                      st_C_ignore},
2563                         {"undef",               0,                      st_C_define},
2564                         {"package",     (C_JAVA & ~C_PLPL),     st_C_ignore},
2565                         {"__attribute__",       0,                      st_C_attribute},
2566                         {"SYSCALL",     0,                      st_C_gnumacro},
2567                         {"ENTRY",               0,                      st_C_gnumacro},
2568                         {"PSEUDO",              0,                      st_C_gnumacro},
2569                         {"DEFUN",               0,                      st_C_gnumacro}
2570                 };
2571
2572         if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
2573         {
2574                 register int key = hash (str, len);
2575
2576                 if (key <= MAX_HASH_VALUE && key >= 0)
2577                 {
2578                         register const char *s = wordlist[key].name;
2579
2580                         if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
2581                                 return &wordlist[key];
2582                 }
2583         }
2584         return 0;
2585 }
2586 /*%>*/
2587
2588 static enum sym_type
2589 C_symtype (str, len, c_ext)
2590 char *str;
2591 int len;
2592 int c_ext;
2593 {
2594         register struct C_stab_entry *se = in_word_set (str, len);
2595
2596         if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2597                 return st_none;
2598         return se->type;
2599 }
2600
2601 \f
2602 /*
2603  * Ignoring __attribute__ ((list))
2604  */
2605 static bool inattribute;        /* looking at an __attribute__ construct */
2606
2607 /*
2608  * C functions and variables are recognized using a simple
2609  * finite automaton.  fvdef is its state variable.
2610  */
2611 static enum
2612 {
2613         fvnone,                 /* nothing seen */
2614         fdefunkey,                      /* Emacs DEFUN keyword seen */
2615         fdefunname,                     /* Emacs DEFUN name seen */
2616         foperator,                      /* func: operator keyword seen (cplpl) */
2617         fvnameseen,                     /* function or variable name seen */
2618         fstartlist,                     /* func: just after open parenthesis */
2619         finlist,                        /* func: in parameter list */
2620         flistseen,                      /* func: after parameter list */
2621         fignore,                        /* func: before open brace */
2622         vignore                 /* var-like: ignore until ';' */
2623 } fvdef;
2624
2625 static bool fvextern;           /* func or var: extern keyword seen; */
2626
2627 /*
2628  * typedefs are recognized using a simple finite automaton.
2629  * typdef is its state variable.
2630  */
2631 static enum
2632 {
2633         tnone,                  /* nothing seen */
2634         tkeyseen,                       /* typedef keyword seen */
2635         ttypeseen,                      /* defined type seen */
2636         tinbody,                        /* inside typedef body */
2637         tend,                           /* just before typedef tag */
2638         tignore                 /* junk after typedef tag */
2639 } typdef;
2640
2641 /*
2642  * struct-like structures (enum, struct and union) are recognized
2643  * using another simple finite automaton.  `structdef' is its state
2644  * variable.
2645  */
2646 static enum
2647 {
2648         snone,                  /* nothing seen yet,
2649                                    or in struct body if bracelev > 0 */
2650         skeyseen,                       /* struct-like keyword seen */
2651         stagseen,                       /* struct-like tag seen */
2652         scolonseen                      /* colon seen after struct-like tag */
2653 } structdef;
2654
2655 /*
2656  * When objdef is different from onone, objtag is the name of the class.
2657  */
2658 static char *objtag = "<uninited>";
2659
2660 /*
2661  * Yet another little state machine to deal with preprocessor lines.
2662  */
2663 static enum
2664 {
2665         dnone,                  /* nothing seen */
2666         dsharpseen,                     /* '#' seen as first char on line */
2667         ddefineseen,                    /* '#' and 'define' seen */
2668         dignorerest                     /* ignore rest of line */
2669 } definedef;
2670
2671 /*
2672  * State machine for Objective C protocols and implementations.
2673  * Idea by Tom R.Hageman <tom@basil.icce.rug.nl> (1995)
2674  */
2675 static enum
2676 {
2677         onone,                  /* nothing seen */
2678         oprotocol,                      /* @interface or @protocol seen */
2679         oimplementation,                /* @implementations seen */
2680         otagseen,                       /* class name seen */
2681         oparenseen,                     /* parenthesis before category seen */
2682         ocatseen,                       /* category name seen */
2683         oinbody,                        /* in @implementation body */
2684         omethodsign,                    /* in @implementation body, after +/- */
2685         omethodtag,                     /* after method name */
2686         omethodcolon,                   /* after method colon */
2687         omethodparm,                    /* after method parameter */
2688         oignore                 /* wait for @end */
2689 } objdef;
2690
2691
2692 /*
2693  * Use this structure to keep info about the token read, and how it
2694  * should be tagged.  Used by the make_C_tag function to build a tag.
2695  */
2696 static struct tok
2697 {
2698         char *line;                     /* string containing the token */
2699         int offset;                     /* where the token starts in LINE */
2700         int length;                     /* token length */
2701         /*
2702           The previous members can be used to pass strings around for generic
2703           purposes.  The following ones specifically refer to creating tags.  In this
2704           case the token contained here is the pattern that will be used to create a
2705           tag.
2706         */
2707         bool valid;                     /* do not create a tag; the token should be
2708                                            invalidated whenever a state machine is
2709                                            reset prematurely */
2710         bool named;                     /* create a named tag */
2711         int lineno;                     /* source line number of tag */
2712         long linepos;                   /* source char number of tag */
2713 } token;                        /* latest token read */
2714
2715 /*
2716  * Variables and functions for dealing with nested structures.
2717  * Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001)
2718  */
2719 static void pushclass_above __P((int, char *, int));
2720 static void popclass_above __P((int));
2721 static void write_classname __P((linebuffer *, char *qualifier));
2722
2723 static struct {
2724         char **cname;                   /* nested class names */
2725         int *bracelev;          /* nested class brace level */
2726         int nl;                 /* class nesting level (elements used) */
2727         int size;                       /* length of the array */
2728 } cstack;                       /* stack for nested declaration tags */
2729 /* Current struct nesting depth (namespace, class, struct, union, enum). */
2730 #define nestlev         (cstack.nl)
2731 /* After struct keyword or in struct body, not inside a nested function. */
2732 #define instruct        (structdef == snone && nestlev > 0              \
2733                          && bracelev == cstack.bracelev[nestlev-1] + 1)
2734
2735 static void
2736 pushclass_above (bracelev, str, len)
2737 int bracelev;
2738 char *str;
2739 int len;
2740 {
2741         int nl;
2742
2743         popclass_above (bracelev);
2744         nl = cstack.nl;
2745         if (nl >= cstack.size)
2746         {
2747                 int size = cstack.size *= 2;
2748                 xrnew (cstack.cname, size, char *);
2749                 xrnew (cstack.bracelev, size, int);
2750         }
2751         assert (nl == 0 || cstack.bracelev[nl-1] < bracelev);
2752         cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
2753         cstack.bracelev[nl] = bracelev;
2754         cstack.nl = nl + 1;
2755 }
2756
2757 static void
2758 popclass_above (bracelev)
2759 int bracelev;
2760 {
2761         int nl;
2762
2763         for (nl = cstack.nl - 1;
2764              nl >= 0 && cstack.bracelev[nl] >= bracelev;
2765              nl--)
2766         {
2767                 free (cstack.cname[nl]);
2768                 cstack.nl = nl;
2769         }
2770 }
2771
2772 static void
2773 write_classname (cn, qualifier)
2774 linebuffer *cn;
2775 char *qualifier;
2776 {
2777         int i, len;
2778         int qlen = strlen (qualifier);
2779
2780         if (cstack.nl == 0 || cstack.cname[0] == NULL)
2781         {
2782                 len = 0;
2783                 cn->len = 0;
2784                 cn->buffer[0] = '\0';
2785         }
2786         else
2787         {
2788                 len = strlen (cstack.cname[0]);
2789                 linebuffer_setlen (cn, len+1);
2790                 xstrncpy (cn->buffer, cstack.cname[0],len+1);
2791         }
2792         for (i = 1; i < cstack.nl; i++)
2793         {
2794                 char *s;
2795                 int slen;
2796
2797                 s = cstack.cname[i];
2798                 if (s == NULL)
2799                         continue;
2800                 slen = strlen (s);
2801                 len += slen + qlen;
2802                 linebuffer_setlen (cn, len);
2803                 strncat (cn->buffer, qualifier, qlen);
2804                 strncat (cn->buffer, s, slen);
2805         }
2806 }
2807
2808 \f
2809 static bool consider_token __P((char *, int, int, int *, int, int, bool *));
2810 static void make_C_tag __P((bool));
2811
2812 /*
2813  * consider_token ()
2814  *      checks to see if the current token is at the start of a
2815  *      function or variable, or corresponds to a typedef, or
2816  *      is a struct/union/enum tag, or #define, or an enum constant.
2817  *
2818  *      *IS_FUNC gets TRUE if the token is a function or #define macro
2819  *      with args.  C_EXTP points to which language we are looking at.
2820  *
2821  * Globals
2822  *      fvdef                   IN OUT
2823  *      structdef               IN OUT
2824  *      definedef               IN OUT
2825  *      typdef                  IN OUT
2826  *      objdef                  IN OUT
2827  */
2828
2829 static bool
2830 consider_token (str, len, c, c_extp, bracelev, parlev, is_func_or_var)
2831 register char *str;     /* IN: token pointer */
2832 register int len;               /* IN: token length */
2833 register int c;         /* IN: first char after the token */
2834 int *c_extp;            /* IN, OUT: C extensions mask */
2835 int bracelev;           /* IN: brace level */
2836 int parlev;             /* IN: parenthesis level */
2837 bool *is_func_or_var;   /* OUT: function or variable found */
2838 {
2839         /* When structdef is stagseen, scolonseen, or snone with bracelev > 0,
2840            structtype is the type of the preceding struct-like keyword, and
2841            structbracelev is the brace level where it has been seen. */
2842         static enum sym_type structtype;
2843         static int structbracelev;
2844         static enum sym_type toktype;
2845
2846
2847         toktype = C_symtype (str, len, *c_extp);
2848
2849         /*
2850          * Skip __attribute__
2851          */
2852         if (toktype == st_C_attribute)
2853         {
2854                 inattribute = TRUE;
2855                 return FALSE;
2856         }
2857
2858         /*
2859          * Advance the definedef state machine.
2860          */
2861         switch (definedef)
2862         {
2863         case dnone:
2864                 /* We're not on a preprocessor line. */
2865                 if (toktype == st_C_gnumacro)
2866                 {
2867                         fvdef = fdefunkey;
2868                         return FALSE;
2869                 }
2870                 break;
2871         case dsharpseen:
2872                 if (toktype == st_C_define)
2873                 {
2874                         definedef = ddefineseen;
2875                 }
2876                 else
2877                 {
2878                         definedef = dignorerest;
2879                 }
2880                 return FALSE;
2881         case ddefineseen:
2882                 /*
2883                  * Make a tag for any macro, unless it is a constant
2884                  * and constantypedefs is FALSE.
2885                  */
2886                 definedef = dignorerest;
2887                 *is_func_or_var = (c == '(');
2888                 if (!*is_func_or_var && !constantypedefs)
2889                         return FALSE;
2890                 else
2891                         return TRUE;
2892         case dignorerest:
2893                 return FALSE;
2894         default:
2895                 error ("internal error: definedef value.", (char *)NULL);
2896         }
2897
2898         /*
2899          * Now typedefs
2900          */
2901         switch (typdef)
2902         {
2903         case tnone:
2904                 if (toktype == st_C_typedef)
2905                 {
2906                         if (typedefs)
2907                                 typdef = tkeyseen;
2908                         fvextern = FALSE;
2909                         fvdef = fvnone;
2910                         return FALSE;
2911                 }
2912                 break;
2913         case tkeyseen:
2914                 switch (toktype)
2915                 {
2916                 case st_none:
2917                 case st_C_class:
2918                 case st_C_struct:
2919                 case st_C_enum:
2920                         typdef = ttypeseen;
2921
2922                         /* all the rest */
2923                 case st_C_objprot:
2924                 case st_C_objimpl:
2925                 case st_C_objend:
2926                 case st_C_gnumacro:
2927                 case st_C_ignore:
2928                 case st_C_attribute:
2929                 case st_C_javastruct:
2930                 case st_C_operator:
2931                 case st_C_template:
2932                 case st_C_extern:
2933                 case st_C_define:
2934                 case st_C_typedef:
2935                 default:
2936                         break;
2937                 }
2938                 break;
2939         case ttypeseen:
2940                 if (structdef == snone && fvdef == fvnone)
2941                 {
2942                         fvdef = fvnameseen;
2943                         return TRUE;
2944                 }
2945                 break;
2946         case tend:
2947                 switch (toktype)
2948                 {
2949                 case st_C_class:
2950                 case st_C_struct:
2951                 case st_C_enum:
2952                         return FALSE;
2953
2954                         /* all the rest */
2955                 case st_none:
2956                 case st_C_objprot:
2957                 case st_C_objimpl:
2958                 case st_C_objend:
2959                 case st_C_gnumacro:
2960                 case st_C_ignore:
2961                 case st_C_attribute:
2962                 case st_C_javastruct:
2963                 case st_C_operator:
2964                 case st_C_template:
2965                 case st_C_extern:
2966                 case st_C_define:
2967                 case st_C_typedef:
2968                 default:
2969                         break;
2970                 }
2971                 return TRUE;
2972
2973                 /* all the rest */
2974         case tinbody:
2975         case tignore:
2976         default:
2977                 break;
2978         }
2979
2980         switch (toktype)
2981         {
2982         case st_C_javastruct:
2983                 if (structdef == stagseen)
2984                         structdef = scolonseen;
2985                 return FALSE;
2986         case st_C_template:
2987         case st_C_class:
2988                 if ((*c_extp & C_AUTO)  /* automatic detection of C++ language */
2989                     && bracelev == 0
2990                     && definedef == dnone && structdef == snone
2991                     && typdef == tnone && fvdef == fvnone)
2992                         *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
2993                 if (toktype == st_C_template)
2994                         break;
2995                 /* FALLTHRU */
2996         case st_C_struct:
2997         case st_C_enum:
2998                 if (parlev == 0
2999                     && fvdef != vignore
3000                     && (typdef == tkeyseen
3001                         || (typedefs_or_cplusplus && structdef == snone)))
3002                 {
3003                         structdef = skeyseen;
3004                         structtype = toktype;
3005                         structbracelev = bracelev;
3006                         if (fvdef == fvnameseen)
3007                                 fvdef = fvnone;
3008                 }
3009                 return FALSE;
3010
3011                 /* all the rest */
3012         case st_none:
3013         case st_C_objprot:
3014         case st_C_objimpl:
3015         case st_C_objend:
3016         case st_C_gnumacro:
3017         case st_C_ignore:
3018         case st_C_attribute:
3019         case st_C_operator:
3020         case st_C_extern:
3021         case st_C_define:
3022         case st_C_typedef:
3023         default:
3024                 break;
3025         }
3026
3027         if (structdef == skeyseen)
3028         {
3029                 structdef = stagseen;
3030                 return TRUE;
3031         }
3032
3033         if (typdef != tnone)
3034                 definedef = dnone;
3035
3036         /* Detect Objective C constructs. */
3037         switch (objdef)
3038         {
3039         case onone:
3040                 switch (toktype)
3041                 {
3042                 case st_C_objprot:
3043                         objdef = oprotocol;
3044                         return FALSE;
3045                 case st_C_objimpl:
3046                         objdef = oimplementation;
3047                         return FALSE;
3048
3049                         /* all the rest */
3050                 case st_none:
3051                 case st_C_objend:
3052                 case st_C_gnumacro:
3053                 case st_C_ignore:
3054                 case st_C_attribute:
3055                 case st_C_javastruct:
3056                 case st_C_operator:
3057                 case st_C_class:
3058                 case st_C_template:
3059                 case st_C_struct:
3060                 case st_C_extern:
3061                 case st_C_enum:
3062                 case st_C_define:
3063                 case st_C_typedef:
3064                 default:
3065                         break;
3066                 }
3067                 break;
3068         case oimplementation:
3069                 /* Save the class tag for functions or variables defined inside. */
3070                 objtag = savenstr (str, len);
3071                 objdef = oinbody;
3072                 return FALSE;
3073         case oprotocol:
3074                 /* Save the class tag for categories. */
3075                 objtag = savenstr (str, len);
3076                 objdef = otagseen;
3077                 *is_func_or_var = TRUE;
3078                 return TRUE;
3079         case oparenseen:
3080                 objdef = ocatseen;
3081                 *is_func_or_var = TRUE;
3082                 return TRUE;
3083         case oinbody:
3084                 break;
3085         case omethodsign:
3086                 if (parlev == 0)
3087                 {
3088                         fvdef = fvnone;
3089                         objdef = omethodtag;
3090                         linebuffer_setlen (&token_name, len+1);
3091                         xstrncpy (token_name.buffer, str, len+1);
3092                         token_name.buffer[len] = '\0';
3093                         return TRUE;
3094                 }
3095                 return FALSE;
3096         case omethodcolon:
3097                 if (parlev == 0)
3098                         objdef = omethodparm;
3099                 return FALSE;
3100         case omethodparm:
3101                 if (parlev == 0)
3102                 {
3103                         fvdef = fvnone;
3104                         objdef = omethodtag;
3105                         linebuffer_setlen (&token_name, token_name.len + len);
3106                         strncat (token_name.buffer, str, len);
3107                         return TRUE;
3108                 }
3109                 return FALSE;
3110         case oignore:
3111                 if (toktype == st_C_objend)
3112                 {
3113                         /* Memory leakage here: the string pointed by objtag is
3114                            never released, because many tests would be needed to
3115                            avoid breaking on incorrect input code.  The amount of
3116                            memory leaked here is the sum of the lengths of the
3117                            class tags.
3118                            free (objtag); */
3119                         objdef = onone;
3120                 }
3121                 return FALSE;
3122
3123                 /* all the rest */
3124         case otagseen:
3125         case ocatseen:
3126         case omethodtag:
3127         default:
3128                 break;
3129         }
3130
3131         /* A function, variable or enum constant? */
3132         switch (toktype)
3133         {
3134         case st_C_extern:
3135                 fvextern = TRUE;
3136                 switch  (fvdef)
3137                 {
3138                 case finlist:
3139                 case flistseen:
3140                 case fignore:
3141                 case vignore:
3142                         break;
3143                 case fvnone:
3144                 case fdefunkey:
3145                 case fdefunname:
3146                 case foperator:
3147                 case fvnameseen:
3148                 case fstartlist:
3149                 default:
3150                         fvdef = fvnone;
3151                 }
3152                 return FALSE;
3153         case st_C_ignore:
3154                 fvextern = FALSE;
3155                 fvdef = vignore;
3156                 return FALSE;
3157         case st_C_operator:
3158                 fvdef = foperator;
3159                 *is_func_or_var = TRUE;
3160                 return TRUE;
3161         case st_none:
3162                 if (constantypedefs
3163                     && structdef == snone
3164                     && structtype == st_C_enum && bracelev > structbracelev)
3165                         return TRUE;            /* enum constant */
3166                 switch (fvdef)
3167                 {
3168                 case fdefunkey:
3169                         if (bracelev > 0)
3170                                 break;
3171                         fvdef = fdefunname;     /* GNU macro */
3172                         *is_func_or_var = TRUE;
3173                         return TRUE;
3174                 case fvnone:
3175                         switch (typdef)
3176                         {
3177                         case ttypeseen:
3178                                 return FALSE;
3179                         case tnone:
3180                                 if ((strneq (str, "asm", 3) && endtoken (str[3]))
3181                                     || (strneq (str, "__asm__", 7) && endtoken (str[7])))
3182                                 {
3183                                         fvdef = vignore;
3184                                         return FALSE;
3185                                 }
3186                                 break;
3187
3188                                 /* all the rest */
3189                         case tkeyseen:
3190                         case tinbody:
3191                         case tend:
3192                         case tignore:
3193                         default:
3194                                 break;
3195                         }
3196                         /* FALLTHRU */
3197                 case fvnameseen:
3198                         if (len >= 10 && strneq (str+len-10, "::operator", 10))
3199                         {
3200                                 if (*c_extp & C_AUTO) /* automatic detection of C++ */
3201                                         *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
3202                                 fvdef = foperator;
3203                                 *is_func_or_var = TRUE;
3204                                 return TRUE;
3205                         }
3206                         if (bracelev > 0 && !instruct)
3207                                 break;
3208                         fvdef = fvnameseen;     /* function or variable */
3209                         *is_func_or_var = TRUE;
3210                         return TRUE;
3211
3212                         /* all the rest */
3213                 case fdefunname:
3214                 case foperator:
3215                 case fstartlist:
3216                 case finlist:
3217                 case flistseen:
3218                 case fignore:
3219                 case vignore:
3220                 default:
3221                         break;
3222                 }
3223                 break;
3224
3225                 /* all the rest */
3226         case st_C_objprot:
3227         case st_C_objimpl:
3228         case st_C_objend:
3229         case st_C_gnumacro:
3230         case st_C_attribute:
3231         case st_C_javastruct:
3232         case st_C_class:
3233         case st_C_template:
3234         case st_C_struct:
3235         case st_C_enum:
3236         case st_C_define:
3237         case st_C_typedef:
3238         default:
3239                 break;
3240         }
3241
3242         return FALSE;
3243 }
3244
3245 \f
3246 /*
3247  * C_entries often keeps pointers to tokens or lines which are older than
3248  * the line currently read.  By keeping two line buffers, and switching
3249  * them at end of line, it is possible to use those pointers.
3250  */
3251 static struct
3252 {
3253         long linepos;
3254         linebuffer lb;
3255 } lbs[2];
3256
3257 #define current_lb_is_new (newndx == curndx)
3258 #define switch_line_buffers() (curndx = 1 - curndx)
3259
3260 #define curlb (lbs[curndx].lb)
3261 #define newlb (lbs[newndx].lb)
3262 #define curlinepos (lbs[curndx].linepos)
3263 #define newlinepos (lbs[newndx].linepos)
3264
3265 #define plainc ((c_ext & C_EXT) == C_PLAIN)
3266 #define cplpl (c_ext & C_PLPL)
3267 #define cjava ((c_ext & C_JAVA) == C_JAVA)
3268
3269 #define CNL_SAVE_DEFINEDEF()                    \
3270         do {                                    \
3271                 curlinepos = charno;            \
3272                 readline (&curlb, inf);         \
3273                 lp = curlb.buffer;              \
3274                 quotednl = FALSE;               \
3275                 newndx = curndx;                \
3276         } while (0)
3277
3278 #define CNL()                                           \
3279         do {                                            \
3280                 CNL_SAVE_DEFINEDEF();                   \
3281                 if (savetoken.valid)                    \
3282                 {                                       \
3283                         token = savetoken;              \
3284                         savetoken.valid = FALSE;        \
3285                 }                                       \
3286                 definedef = dnone;                      \
3287         } while (0)
3288
3289
3290 static void
3291 make_C_tag (isfun)
3292 bool isfun;
3293 {
3294         /* This function is never called when token.valid is FALSE, but
3295            we must protect against invalid input or internal errors. */
3296         if (token.valid)
3297                 make_tag (token_name.buffer, token_name.len, isfun, token.line,
3298                           token.offset+token.length+1, token.lineno, token.linepos);
3299         else if (DEBUG)
3300         {                                 /* this branch is optimised away if !DEBUG */
3301                 make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
3302                           token_name.len + 17, isfun, token.line,
3303                           token.offset+token.length+1, token.lineno, token.linepos);
3304                 error ("INVALID TOKEN", NULL);
3305         }
3306
3307         token.valid = FALSE;
3308 }
3309
3310
3311 /*
3312  * C_entries ()
3313  *      This routine finds functions, variables, typedefs,
3314  *      #define's, enum constants and struct/union/enum definitions in
3315  *      C syntax and adds them to the list.
3316  */
3317 static void
3318 C_entries (c_ext, inf)
3319 int c_ext;                      /* extension of C */
3320 FILE *inf;                      /* input file */
3321 {
3322         register char c;                /* latest char read; '\0' for end of line */
3323         register char *lp;              /* pointer one beyond the character `c' */
3324         int curndx, newndx;             /* indices for current and new lb */
3325         register int tokoff;            /* offset in line of start of current token */
3326         register int toklen;            /* length of current token */
3327         char *qualifier;                /* string used to qualify names */
3328         int qlen;                       /* length of qualifier */
3329         int bracelev;                   /* current brace level */
3330         int bracketlev;         /* current bracket level */
3331         int parlev;                     /* current parenthesis level */
3332         int attrparlev;         /* __attribute__ parenthesis level */
3333         int templatelev;                /* current template level */
3334         int typdefbracelev;             /* bracelev where a typedef struct body begun */
3335         bool incomm, inquote, inchar, quotednl, midtoken;
3336         bool yacc_rules;                /* in the rules part of a yacc file */
3337         struct tok savetoken = {0};     /* token saved during preprocessor handling */
3338
3339
3340         linebuffer_init (&lbs[0].lb);
3341         linebuffer_init (&lbs[1].lb);
3342         if (cstack.size == 0)
3343         {
3344                 cstack.size = (DEBUG) ? 1 : 4;
3345                 cstack.nl = 0;
3346                 cstack.cname = xnew (cstack.size, char *);
3347                 cstack.bracelev = xnew (cstack.size, int);
3348         }
3349
3350         tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */
3351         curndx = newndx = 0;
3352         lp = curlb.buffer;
3353         *lp = 0;
3354
3355         fvdef = fvnone; fvextern = FALSE; typdef = tnone;
3356         structdef = snone; definedef = dnone; objdef = onone;
3357         yacc_rules = FALSE;
3358         midtoken = inquote = inchar = incomm = quotednl = FALSE;
3359         token.valid = savetoken.valid = FALSE;
3360         bracelev = bracketlev = parlev = attrparlev = templatelev = 0;
3361         if (cjava)
3362         { qualifier = "."; qlen = 1; }
3363         else
3364         { qualifier = "::"; qlen = 2; }
3365
3366
3367         while (!feof (inf))
3368         {
3369                 c = *lp++;
3370                 if (c == '\\')
3371                 {
3372                         /* If we are at the end of the line, the next character is a
3373                            '\0'; do not skip it, because it is what tells us
3374                            to read the next line.  */
3375                         if (*lp == '\0')
3376                         {
3377                                 quotednl = TRUE;
3378                                 continue;
3379                         }
3380                         lp++;
3381                         c = ' ';
3382                 }
3383                 else if (incomm)
3384                 {
3385                         switch (c)
3386                         {
3387                         case '*':
3388                                 if (*lp == '/')
3389                                 {
3390                                         c = *lp++;
3391                                         incomm = FALSE;
3392                                 }
3393                                 break;
3394                         case '\0':
3395                                 /* Newlines inside comments do not end macro definitions in
3396                                    traditional cpp. */
3397                                 CNL_SAVE_DEFINEDEF ();
3398                                 break;
3399                         default:
3400                                 break;
3401                         }
3402                         continue;
3403                 }
3404                 else if (inquote)
3405                 {
3406                         switch (c)
3407                         {
3408                         case '"':
3409                                 inquote = FALSE;
3410                                 break;
3411                         case '\0':
3412                                 /* Newlines inside strings do not end macro definitions
3413                                    in traditional cpp, even though compilers don't
3414                                    usually accept them. */
3415                                 CNL_SAVE_DEFINEDEF ();
3416                                 break;
3417                         default:
3418                                 break;
3419                         }
3420                         continue;
3421                 }
3422                 else if (inchar)
3423                 {
3424                         switch (c)
3425                         {
3426                         case '\0':
3427                                 /* Hmmm, something went wrong. */
3428                                 CNL ();
3429                                 /* FALLTHRU */
3430                         case '\'':
3431                                 inchar = FALSE;
3432                                 break;
3433                         default:
3434                                 break;
3435                         }
3436                         continue;
3437                 }
3438                 else if (bracketlev > 0)
3439                 {
3440                         switch (c)
3441                         {
3442                         case ']':
3443                                 if (--bracketlev > 0)
3444                                         continue;
3445                                 break;
3446                         case '\0':
3447                                 CNL_SAVE_DEFINEDEF ();
3448                                 break;
3449                         default:
3450                                 break;
3451                         }
3452                         continue;
3453                 }
3454                 else switch (c)
3455                 {
3456                 case '"':
3457                         inquote = TRUE;
3458                         if (inattribute)
3459                                 break;
3460                         switch (fvdef)
3461                         {
3462                         case fdefunkey:
3463                         case fstartlist:
3464                         case finlist:
3465                         case fignore:
3466                         case vignore:
3467                                 break;
3468                         case fvnone:
3469                         case fdefunname:
3470                         case foperator:
3471                         case fvnameseen:
3472                         case flistseen:
3473                         default:
3474                                 fvextern = FALSE;
3475                                 fvdef = fvnone;
3476                         }
3477                         continue;
3478                 case '\'':
3479                         inchar = TRUE;
3480                         if (inattribute)
3481                                 break;
3482                         if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
3483                         {
3484                                 fvextern = FALSE;
3485                                 fvdef = fvnone;
3486                         }
3487                         continue;
3488                 case '/':
3489                         if (*lp == '*')
3490                         {
3491                                 incomm = TRUE;
3492                                 lp++;
3493                                 c = ' ';
3494                         }
3495                         else if (/* cplpl && */ *lp == '/')
3496                         {
3497                                 c = '\0';
3498                         }
3499                         break;
3500                 case '%':
3501                         if ((c_ext & YACC) && *lp == '%')
3502                         {
3503                                 /* Entering or exiting rules section in yacc file. */
3504                                 lp++;
3505                                 definedef = dnone; fvdef = fvnone; fvextern = FALSE;
3506                                 typdef = tnone; structdef = snone;
3507                                 midtoken = inquote = inchar = incomm = quotednl = FALSE;
3508                                 bracelev = 0;
3509                                 yacc_rules = !yacc_rules;
3510                                 continue;
3511                         }
3512                         else
3513                                 break;
3514                 case '#':
3515                         if (definedef == dnone)
3516                         {
3517                                 char *cp;
3518                                 bool cpptoken = TRUE;
3519
3520                                 /* Look back on this line.  If all blanks, or nonblanks
3521                                    followed by an end of comment, this is a preprocessor
3522                                    token. */
3523                                 for (cp = newlb.buffer; cp < lp-1; cp++)
3524                                         if (!iswhite (*cp))
3525                                         {
3526                                                 if (*cp == '*' && *(cp+1) == '/')
3527                                                 {
3528                                                         cp++;
3529                                                         cpptoken = TRUE;
3530                                                 }
3531                                                 else
3532                                                         cpptoken = FALSE;
3533                                         }
3534                                 if (cpptoken)
3535                                         definedef = dsharpseen;
3536                         } /* if (definedef == dnone) */
3537                         continue;
3538                 case '[':
3539                         bracketlev++;
3540                         continue;
3541                 default:
3542                         break;
3543                 } /* switch (c) */
3544
3545
3546                 /* Consider token only if some involved conditions are satisfied. */
3547                 if (typdef != tignore
3548                     && definedef != dignorerest
3549                     && fvdef != finlist
3550                     && templatelev == 0
3551                     && (definedef != dnone
3552                         || structdef != scolonseen)
3553                     && !inattribute)
3554                 {
3555                         if (midtoken)
3556                         {
3557                                 if (endtoken (c))
3558                                 {
3559                                         if (c == ':' && *lp == ':' && begtoken (lp[1]))
3560                                                 /* This handles :: in the middle,
3561                                                    but not at the beginning of an identifier.
3562                                                    Also, space-separated :: is not recognised. */
3563                                         {
3564                                                 if (c_ext & C_AUTO) /* automatic detection of C++ */
3565                                                         c_ext = (c_ext | C_PLPL) & ~C_AUTO;
3566                                                 lp += 2;
3567                                                 toklen += 2;
3568                                                 c = lp[-1];
3569                                                 goto still_in_token;
3570                                         }
3571                                         else
3572                                         {
3573                                                 bool funorvar = FALSE;
3574
3575                                                 if (yacc_rules
3576                                                     || consider_token (newlb.buffer + tokoff, toklen, c,
3577                                                                        &c_ext, bracelev, parlev,
3578                                                                        &funorvar))
3579                                                 {
3580                                                         if (fvdef == foperator)
3581                                                         {
3582                                                                 char *oldlp = lp;
3583                                                                 lp = skip_spaces (lp-1);
3584                                                                 if (*lp != '\0')
3585                                                                         lp += 1;
3586                                                                 while (*lp != '\0'
3587                                                                        && !iswhite (*lp) && *lp != '(')
3588                                                                         lp += 1;
3589                                                                 c = *lp++;
3590                                                                 toklen += lp - oldlp;
3591                                                         }
3592                                                         token.named = FALSE;
3593                                                         if (!plainc
3594                                                             && nestlev > 0 && definedef == dnone)
3595                                                                 /* in struct body */
3596                                                         {
3597                                                                 write_classname (&token_name, qualifier);
3598                                                                 linebuffer_setlen (&token_name,
3599                                                                                    token_name.len+qlen+toklen);
3600                                                                 strcat (token_name.buffer, qualifier);
3601                                                                 strncat (token_name.buffer,
3602                                                                          newlb.buffer + tokoff, toklen);
3603                                                                 token.named = TRUE;
3604                                                         }
3605                                                         else if (objdef == ocatseen)
3606                                                                 /* Objective C category */
3607                                                         {
3608                                                                 int len = strlen (objtag) + 2 + toklen;
3609                                                                 linebuffer_setlen (&token_name, len);
3610                                                                 strcpy (token_name.buffer, objtag);
3611                                                                 strcat (token_name.buffer, "(");
3612                                                                 strncat (token_name.buffer,
3613                                                                          newlb.buffer + tokoff, toklen);
3614                                                                 strcat (token_name.buffer, ")");
3615                                                                 token.named = TRUE;
3616                                                         }
3617                                                         else if (objdef == omethodtag
3618                                                                  || objdef == omethodparm)
3619                                                                 /* Objective C method */
3620                                                         {
3621                                                                 token.named = TRUE;
3622                                                         }
3623                                                         else if (fvdef == fdefunname)
3624                                                                 /* GNU DEFUN and similar macros */
3625                                                         {
3626                                                                 bool defun = (newlb.buffer[tokoff] == 'F');
3627                                                                 int off = tokoff;
3628                                                                 int len = toklen;
3629
3630                                                                 /* Rewrite the tag so that emacs lisp DEFUNs
3631                                                                    can be found by their elisp name */
3632                                                                 if (defun)
3633                                                                 {
3634                                                                         off += 1;
3635                                                                         len -= 1;
3636                                                                 }
3637                                                                 linebuffer_setlen (&token_name, len+1);
3638                                                                 xstrncpy (token_name.buffer,
3639                                                                          newlb.buffer + off, len+1);
3640                                                                 if (defun)
3641                                                                         while (--len >= 0)
3642                                                                                 if (token_name.buffer[len] == '_')
3643                                                                                         token_name.buffer[len] = '-';
3644                                                                 token.named = defun;
3645                                                         }
3646                                                         else
3647                                                         {
3648                                                                 linebuffer_setlen (&token_name, toklen+1);
3649                                                                 xstrncpy (token_name.buffer,
3650                                                                          newlb.buffer + tokoff, toklen+1);
3651                                                                 token_name.buffer[toklen] = '\0';
3652                                                                 /* Name macros and members. */
3653                                                                 token.named = (structdef == stagseen
3654                                                                                || typdef == ttypeseen
3655                                                                                || typdef == tend
3656                                                                                || (funorvar
3657                                                                                    && definedef == dignorerest)
3658                                                                                || (funorvar
3659                                                                                    && definedef == dnone
3660                                                                                    && structdef == snone
3661                                                                                    && bracelev > 0));
3662                                                         }
3663                                                         token.lineno = lineno;
3664                                                         token.offset = tokoff;
3665                                                         token.length = toklen;
3666                                                         token.line = newlb.buffer;
3667                                                         token.linepos = newlinepos;
3668                                                         token.valid = TRUE;
3669
3670                                                         if (definedef == dnone
3671                                                             && (fvdef == fvnameseen
3672                                                                 || fvdef == foperator
3673                                                                 || structdef == stagseen
3674                                                                 || typdef == tend
3675                                                                 || typdef == ttypeseen
3676                                                                 || objdef != onone))
3677                                                         {
3678                                                                 if (current_lb_is_new)
3679                                                                         switch_line_buffers ();
3680                                                         }
3681                                                         else if (definedef != dnone
3682                                                                  || fvdef == fdefunname
3683                                                                  || instruct)
3684                                                                 make_C_tag (funorvar);
3685                                                 }
3686                                                 else /* not yacc and consider_token failed */
3687                                                 {
3688                                                         if (inattribute && fvdef == fignore)
3689                                                         {
3690                                                                 /* We have just met __attribute__ after a
3691                                                                    function parameter list: do not tag the
3692                                                                    function again. */
3693                                                                 fvdef = fvnone;
3694                                                         }
3695                                                 }
3696                                                 midtoken = FALSE;
3697                                         }
3698                                 } /* if (endtoken (c)) */
3699                                 else if (intoken (c))
3700                                 still_in_token:
3701                                 {
3702                                         toklen++;
3703                                         continue;
3704                                 }
3705                         } /* if (midtoken) */
3706                         else if (begtoken (c))
3707                         {
3708                                 switch (definedef)
3709                                 {
3710                                 case dnone:
3711                                         switch (fvdef)
3712                                         {
3713                                         case fstartlist:
3714                                                 /* This prevents tagging fb in
3715                                                    void (__attribute__((noreturn)) *fb) (void);
3716                                                    Fixing this is not easy and not very important. */
3717                                                 fvdef = finlist;
3718                                                 continue;
3719                                         case flistseen:
3720                                                 if (plainc || declarations)
3721                                                 {
3722                                                         make_C_tag (TRUE); /* a function */
3723                                                         fvdef = fignore;
3724                                                 }
3725                                                 break;
3726
3727                                                 /* all the rest */
3728                                         case fvnone:
3729                                         case fdefunkey:
3730                                         case fdefunname:
3731                                         case foperator:
3732                                         case fvnameseen:
3733                                         case finlist:
3734                                         case fignore:
3735                                         case vignore:
3736                                         default:
3737                                                 break;
3738                                         }
3739                                         if (structdef == stagseen && !cjava)
3740                                         {
3741                                                 popclass_above (bracelev);
3742                                                 structdef = snone;
3743                                         }
3744                                         break;
3745                                 case dsharpseen:
3746                                         savetoken = token;
3747                                         break;
3748
3749                                         /* all the rest */
3750                                 case ddefineseen:
3751                                 case dignorerest:
3752                                 default:
3753                                         break;
3754                                 }
3755                                 if (!yacc_rules || lp == newlb.buffer + 1)
3756                                 {
3757                                         tokoff = lp - 1 - newlb.buffer;
3758                                         toklen = 1;
3759                                         midtoken = TRUE;
3760                                 }
3761                                 continue;
3762                         } /* if (begtoken) */
3763                 } /* if must look at token */
3764
3765
3766                 /* Detect end of line, colon, comma, semicolon and various braces
3767                    after having handled a token.*/
3768                 switch (c)
3769                 {
3770                 case ':':
3771                         if (inattribute)
3772                                 break;
3773                         if (yacc_rules && token.offset == 0 && token.valid)
3774                         {
3775                                 make_C_tag (FALSE); /* a yacc function */
3776                                 break;
3777                         }
3778                         if (definedef != dnone)
3779                                 break;
3780                         switch (objdef)
3781                         {
3782                         case  otagseen:
3783                                 objdef = oignore;
3784                                 make_C_tag (TRUE); /* an Objective C class */
3785                                 break;
3786                         case omethodtag:
3787                         case omethodparm:
3788                                 objdef = omethodcolon;
3789                                 linebuffer_setlen (&token_name, token_name.len + 1);
3790                                 strcat (token_name.buffer, ":");
3791                                 break;
3792
3793                                 /* all the rest */
3794                         case onone:
3795                         case oprotocol:
3796                         case oimplementation:
3797                         case oparenseen:
3798                         case ocatseen:
3799                         case oinbody:
3800                         case omethodsign:
3801                         case omethodcolon:
3802                         case oignore:
3803                         default:
3804                                 break;
3805                         }
3806                         if (structdef == stagseen)
3807                         {
3808                                 structdef = scolonseen;
3809                                 break;
3810                         }
3811                         /* Should be useless, but may be work as a safety net. */
3812                         if (cplpl && fvdef == flistseen)
3813                         {
3814                                 make_C_tag (TRUE); /* a function */
3815                                 fvdef = fignore;
3816                                 break;
3817                         }
3818                         break;
3819                 case ';':
3820                         if (definedef != dnone || inattribute)
3821                                 break;
3822                         switch (typdef)
3823                         {
3824                         case tend:
3825                         case ttypeseen:
3826                                 make_C_tag (FALSE); /* a typedef */
3827                                 typdef = tnone;
3828                                 fvdef = fvnone;
3829                                 break;
3830                         case tnone:
3831                         case tinbody:
3832                         case tignore:
3833                                 switch (fvdef)
3834                                 {
3835                                 case fignore:
3836                                         if (typdef == tignore || cplpl)
3837                                                 fvdef = fvnone;
3838                                         break;
3839                                 case fvnameseen:
3840                                         if ((globals && bracelev == 0 && (!fvextern || declarations))
3841                                             || (members && instruct))
3842                                                 make_C_tag (FALSE); /* a variable */
3843                                         fvextern = FALSE;
3844                                         fvdef = fvnone;
3845                                         token.valid = FALSE;
3846                                         break;
3847                                 case flistseen:
3848                                         if ((declarations
3849                                              && (cplpl || !instruct)
3850                                              && (typdef == tnone || (typdef != tignore && instruct)))
3851                                             || (members
3852                                                 && plainc && instruct))
3853                                                 make_C_tag (TRUE);  /* a function */
3854                                         /* FALLTHRU */
3855                                 case fvnone:
3856                                 case fdefunkey:
3857                                 case fdefunname:
3858                                 case foperator:
3859                                 case fstartlist:
3860                                 case finlist:
3861                                 case vignore:
3862                                 default:
3863                                         fvextern = FALSE;
3864                                         fvdef = fvnone;
3865                                         if (declarations
3866                                             && cplpl && structdef == stagseen)
3867                                                 make_C_tag (FALSE);     /* forward declaration */
3868                                         else
3869                                                 token.valid = FALSE;
3870                                 } /* switch (fvdef) */
3871                                 /* FALLTHRU */
3872                         case tkeyseen:
3873                         default:
3874                                 if (!instruct)
3875                                         typdef = tnone;
3876                         }
3877                         if (structdef == stagseen)
3878                                 structdef = snone;
3879                         break;
3880                 case ',':
3881                         if (definedef != dnone || inattribute)
3882                                 break;
3883                         switch (objdef)
3884                         {
3885                         case omethodtag:
3886                         case omethodparm:
3887                                 make_C_tag (TRUE); /* an Objective C method */
3888                                 objdef = oinbody;
3889                                 break;
3890
3891                                 /* all the rest */
3892                         case onone:
3893                         case oprotocol:
3894                         case oimplementation:
3895                         case otagseen:
3896                         case oparenseen:
3897                         case ocatseen:
3898                         case oinbody:
3899                         case omethodsign:
3900                         case omethodcolon:
3901                         case oignore:
3902                         default:
3903                                 break;
3904                         }
3905                         switch (fvdef)
3906                         {
3907                         case fdefunkey:
3908                         case foperator:
3909                         case fstartlist:
3910                         case finlist:
3911                         case fignore:
3912                         case vignore:
3913                                 break;
3914                         case fdefunname:
3915                                 fvdef = fignore;
3916                                 break;
3917                         case fvnameseen:
3918                                 if (parlev == 0
3919                                     && ((globals
3920                                          && bracelev == 0
3921                                          && templatelev == 0
3922                                          && (!fvextern || declarations))
3923                                         || (members && instruct)))
3924                                         make_C_tag (FALSE); /* a variable */
3925                                 break;
3926                         case flistseen:
3927                                 if ((declarations && typdef == tnone && !instruct)
3928                                     || (members && typdef != tignore && instruct))
3929                                 {
3930                                         make_C_tag (TRUE); /* a function */
3931                                         fvdef = fvnameseen;
3932                                 }
3933                                 else if (!declarations)
3934                                         fvdef = fvnone;
3935                                 token.valid = FALSE;
3936                                 break;
3937                         case fvnone:
3938                         default:
3939                                 fvdef = fvnone;
3940                         }
3941                         if (structdef == stagseen)
3942                                 structdef = snone;
3943                         break;
3944                 case ']':
3945                         if (definedef != dnone || inattribute)
3946                                 break;
3947                         if (structdef == stagseen)
3948                                 structdef = snone;
3949                         switch (typdef)
3950                         {
3951                         case ttypeseen:
3952                         case tend:
3953                                 typdef = tignore;
3954                                 make_C_tag (FALSE);     /* a typedef */
3955                                 break;
3956                         case tnone:
3957                         case tinbody:
3958                                 switch (fvdef)
3959                                 {
3960                                 case foperator:
3961                                 case finlist:
3962                                 case fignore:
3963                                 case vignore:
3964                                         break;
3965                                 case fvnameseen:
3966                                         if ((members && bracelev == 1)
3967                                             || (globals && bracelev == 0
3968                                                 && (!fvextern || declarations)))
3969                                                 make_C_tag (FALSE); /* a variable */
3970                                         /* FALLTHRU */
3971                                 case fvnone:
3972                                 case fdefunkey:
3973                                 case fdefunname:
3974                                 case fstartlist:
3975                                 case flistseen:
3976                                 default:
3977                                         fvdef = fvnone;
3978                                 }
3979                                 break;
3980
3981                                 /* all the rest */
3982                         case tkeyseen:
3983                         case tignore:
3984                         default:
3985                                 break;
3986                         }
3987                         break;
3988                 case '(':
3989                         if (inattribute)
3990                         {
3991                                 attrparlev++;
3992                                 break;
3993                         }
3994                         if (definedef != dnone)
3995                                 break;
3996                         if (objdef == otagseen && parlev == 0)
3997                                 objdef = oparenseen;
3998                         switch (fvdef)
3999                         {
4000                         case fvnameseen:
4001                                 if (typdef == ttypeseen
4002                                     && *lp != '*'
4003                                     && !instruct)
4004                                 {
4005                                         /* This handles constructs like:
4006                                            typedef void OperatorFun (int fun); */
4007                                         make_C_tag (FALSE);
4008                                         typdef = tignore;
4009                                         fvdef = fignore;
4010                                         break;
4011                                 }
4012                                 /* FALLTHRU */
4013                         case foperator:
4014                                 fvdef = fstartlist;
4015                                 break;
4016                         case flistseen:
4017                                 fvdef = finlist;
4018                                 break;
4019
4020                                 /* all the rest */
4021                         case fvnone:
4022                         case fdefunkey:
4023                         case fdefunname:
4024                         case fstartlist:
4025                         case finlist:
4026                         case fignore:
4027                         case vignore:
4028                         default:
4029                                 break;
4030                         }
4031                         parlev++;
4032                         break;
4033                 case ')':
4034                         if (inattribute)
4035                         {
4036                                 if (--attrparlev == 0)
4037                                         inattribute = FALSE;
4038                                 break;
4039                         }
4040                         if (definedef != dnone)
4041                                 break;
4042                         if (objdef == ocatseen && parlev == 1)
4043                         {
4044                                 make_C_tag (TRUE); /* an Objective C category */
4045                                 objdef = oignore;
4046                         }
4047                         if (--parlev == 0)
4048                         {
4049                                 switch (fvdef)
4050                                 {
4051                                 case fstartlist:
4052                                 case finlist:
4053                                         fvdef = flistseen;
4054                                         break;
4055
4056                                         /* all the rest */
4057                                 case fvnone:
4058                                 case fdefunkey:
4059                                 case fdefunname:
4060                                 case foperator:
4061                                 case fvnameseen:
4062                                 case flistseen:
4063                                 case fignore:
4064                                 case vignore:
4065                                 default:
4066                                         break;
4067                                 }
4068                                 if (!instruct
4069                                     && (typdef == tend
4070                                         || typdef == ttypeseen))
4071                                 {
4072                                         typdef = tignore;
4073                                         make_C_tag (FALSE); /* a typedef */
4074                                 }
4075                         }
4076                         else if (parlev < 0)    /* can happen due to ill-conceived #if's. */
4077                                 parlev = 0;
4078                         break;
4079                 case '{':
4080                         if (definedef != dnone)
4081                                 break;
4082                         if (typdef == ttypeseen)
4083                         {
4084                                 /* Whenever typdef is set to tinbody (currently only
4085                                    here), typdefbracelev should be set to bracelev. */
4086                                 typdef = tinbody;
4087                                 typdefbracelev = bracelev;
4088                         }
4089                         switch (fvdef)
4090                         {
4091                         case flistseen:
4092                                 make_C_tag (TRUE);    /* a function */
4093                                 /* FALLTHRU */
4094                         case fignore:
4095                                 fvdef = fvnone;
4096                                 break;
4097                         case fvnone:
4098                                 switch (objdef)
4099                                 {
4100                                 case otagseen:
4101                                         make_C_tag (TRUE); /* an Objective C class */
4102                                         objdef = oignore;
4103                                         break;
4104                                 case omethodtag:
4105                                 case omethodparm:
4106                                         make_C_tag (TRUE); /* an Objective C method */
4107                                         objdef = oinbody;
4108                                         break;
4109                                 case onone:
4110                                 case oprotocol:
4111                                 case oimplementation:
4112                                 case oparenseen:
4113                                 case ocatseen:
4114                                 case oinbody:
4115                                 case omethodsign:
4116                                 case omethodcolon:
4117                                 case oignore:
4118                                 default:
4119                                         /* Neutralize `extern "C" {' grot. */
4120                                         if (bracelev == 0 && structdef == snone && nestlev == 0
4121                                             && typdef == tnone)
4122                                                 bracelev = -1;
4123                                 }
4124                                 break;
4125
4126                                 /* all the rest */
4127                         case fdefunkey:
4128                         case fdefunname:
4129                         case foperator:
4130                         case fvnameseen:
4131                         case fstartlist:
4132                         case finlist:
4133                         case vignore:
4134                         default:
4135                                 break;
4136                         }
4137                         switch (structdef)
4138                         {
4139                         case skeyseen:     /* unnamed struct */
4140                                 pushclass_above (bracelev, NULL, 0);
4141                                 structdef = snone;
4142                                 break;
4143                         case stagseen:     /* named struct or enum */
4144                         case scolonseen:           /* a class */
4145                                 pushclass_above (bracelev,token.line+token.offset, token.length);
4146                                 structdef = snone;
4147                                 make_C_tag (FALSE);  /* a struct or enum */
4148                                 break;
4149
4150                                 /* all the rest */
4151                         case snone:
4152                         default:
4153                                 break;
4154                         }
4155                         bracelev += 1;
4156                         break;
4157                 case '*':
4158                         if (definedef != dnone)
4159                                 break;
4160                         if (fvdef == fstartlist)
4161                         {
4162                                 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
4163                                 token.valid = FALSE;
4164                         }
4165                         break;
4166                 case '}':
4167                         if (definedef != dnone)
4168                                 break;
4169                         bracelev -= 1;
4170                         if (!ignoreindent && lp == newlb.buffer + 1)
4171                         {
4172                                 if (bracelev != 0)
4173                                         token.valid = FALSE; /* unexpected value, token unreliable */
4174                                 bracelev = 0;   /* reset brace level if first column */
4175                                 parlev = 0;     /* also reset paren level, just in case... */
4176                         }
4177                         else if (bracelev < 0)
4178                         {
4179                                 token.valid = FALSE; /* something gone amiss, token unreliable */
4180                                 bracelev = 0;
4181                         }
4182                         if (bracelev == 0 && fvdef == vignore)
4183                                 fvdef = fvnone;         /* end of function */
4184                         popclass_above (bracelev);
4185                         structdef = snone;
4186                         /* Only if typdef == tinbody is typdefbracelev significant. */
4187                         if (typdef == tinbody && bracelev <= typdefbracelev)
4188                         {
4189                                 assert (bracelev == typdefbracelev);
4190                                 typdef = tend;
4191                         }
4192                         break;
4193                 case '=':
4194                         if (definedef != dnone)
4195                                 break;
4196                         switch (fvdef)
4197                         {
4198                         case foperator:
4199                         case finlist:
4200                         case fignore:
4201                         case vignore:
4202                                 break;
4203                         case fvnameseen:
4204                                 if ((members && bracelev == 1)
4205                                     || (globals && bracelev == 0 && (!fvextern || declarations)))
4206                                         make_C_tag (FALSE); /* a variable */
4207                                 /* FALLTHRU */
4208                         case fvnone:
4209                         case fdefunkey:
4210                         case fdefunname:
4211                         case fstartlist:
4212                         case flistseen:
4213                         default:
4214                                 fvdef = vignore;
4215                         }
4216                         break;
4217                 case '<':
4218                         if (cplpl
4219                             && (structdef == stagseen || fvdef == fvnameseen))
4220                         {
4221                                 templatelev++;
4222                                 break;
4223                         }
4224                         goto resetfvdef;
4225                 case '>':
4226                         if (templatelev > 0)
4227                         {
4228                                 templatelev--;
4229                                 break;
4230                         }
4231                         goto resetfvdef;
4232                 case '+':
4233                 case '-':
4234                         if (objdef == oinbody && bracelev == 0)
4235                         {
4236                                 objdef = omethodsign;
4237                                 break;
4238                         }
4239                         /* FALLTHRU */
4240                 resetfvdef:
4241                 case '#': case '~': case '&': case '%': case '/':
4242                 case '|': case '^': case '!': case '.': case '?':
4243                         if (definedef != dnone)
4244                                 break;
4245                         /* These surely cannot follow a function tag in C. */
4246                         switch (fvdef)
4247                         {
4248                         case foperator:
4249                         case finlist:
4250                         case fignore:
4251                         case vignore:
4252                                 break;
4253                         case fvnone:
4254                         case fdefunkey:
4255                         case fdefunname:
4256                         case fvnameseen:
4257                         case fstartlist:
4258                         case flistseen:
4259                         default:
4260                                 fvdef = fvnone;
4261                         }
4262                         break;
4263                 case '\0':
4264                         if (objdef == otagseen)
4265                         {
4266                                 make_C_tag (TRUE); /* an Objective C class */
4267                                 objdef = oignore;
4268                         }
4269                         /* If a macro spans multiple lines don't reset its state. */
4270                         if (quotednl)
4271                                 CNL_SAVE_DEFINEDEF ();
4272                         else
4273                                 CNL ();
4274                         break;
4275                 default:
4276                         break;
4277                 } /* switch (c) */
4278
4279         } /* while not eof */
4280
4281         free (lbs[0].lb.buffer);
4282         free (lbs[1].lb.buffer);
4283 }
4284
4285 /*
4286  * Process either a C++ file or a C file depending on the setting
4287  * of a global flag.
4288  */
4289 static void
4290 default_C_entries (inf)
4291 FILE *inf;
4292 {
4293         C_entries (cplusplus ? C_PLPL : C_AUTO, inf);
4294 }
4295
4296 /* Always do plain C. */
4297 static void
4298 plain_C_entries (inf)
4299 FILE *inf;
4300 {
4301         C_entries (0, inf);
4302 }
4303
4304 /* Always do C++. */
4305 static void
4306 Cplusplus_entries (inf)
4307 FILE *inf;
4308 {
4309         C_entries (C_PLPL, inf);
4310 }
4311
4312 /* Always do Java. */
4313 static void
4314 Cjava_entries (inf)
4315 FILE *inf;
4316 {
4317         C_entries (C_JAVA, inf);
4318 }
4319
4320 /* Always do C*. */
4321 static void
4322 Cstar_entries (inf)
4323 FILE *inf;
4324 {
4325         C_entries (C_STAR, inf);
4326 }
4327
4328 /* Always do Yacc. */
4329 static void
4330 Yacc_entries (inf)
4331 FILE *inf;
4332 {
4333         C_entries (YACC, inf);
4334 }
4335
4336 \f
4337 /* Useful macros. */
4338 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer)    \
4339         for (;                  /* loop initialization */               \
4340              !feof (file_pointer)       /* loop test */                 \
4341                      &&                 /* instructions at start of loop */ \
4342                      (readline (&line_buffer, file_pointer),            \
4343                       char_pointer = line_buffer.buffer,                \
4344                       TRUE);                                            \
4345                 )
4346
4347 #define LOOKING_AT(cp, kw)  /* kw is the keyword, a literal string */   \
4348         ((assert("" kw), TRUE)   /* syntax error if not a literal string */ \
4349          && strneq ((cp), kw, sizeof(kw)-1)             /* cp points at kw */ \
4350          && notinname ((cp)[sizeof(kw)-1])              /* end of kw */ \
4351          && ((cp) = skip_spaces((cp)+sizeof(kw)-1)))    /* skip spaces */
4352
4353 /* Similar to LOOKING_AT but does not use notinname, does not skip */
4354 #define LOOKING_AT_NOCASE(cp, kw) /* the keyword is a literal string */ \
4355         ((assert("" kw), TRUE)     /* syntax error if not a literal string */ \
4356          && strncaseeq ((cp), kw, sizeof(kw)-1) /* cp points at kw */   \
4357          && ((cp) += sizeof(kw)-1))                     /* skip spaces */
4358
4359 /*
4360  * Read a file, but do no processing.  This is used to do regexp
4361  * matching on files that have no language defined.
4362  */
4363 static void
4364 just_read_file (inf)
4365 FILE *inf;
4366 {
4367         register char *dummy;
4368
4369         LOOP_ON_INPUT_LINES (inf, lb, dummy)
4370                 continue;
4371 }
4372
4373 \f
4374 /* Fortran parsing */
4375
4376 static void F_takeprec __P((void));
4377 static void F_getit __P((FILE *));
4378
4379 static void
4380 F_takeprec ()
4381 {
4382         dbp = skip_spaces (dbp);
4383         if (*dbp != '*')
4384                 return;
4385         dbp++;
4386         dbp = skip_spaces (dbp);
4387         if (strneq (dbp, "(*)", 3))
4388         {
4389                 dbp += 3;
4390                 return;
4391         }
4392         if (!ISDIGIT (*dbp))
4393         {
4394                 --dbp;                  /* force failure */
4395                 return;
4396         }
4397         do
4398                 dbp++;
4399         while (ISDIGIT (*dbp));
4400 }
4401
4402 static void
4403 F_getit (inf)
4404 FILE *inf;
4405 {
4406         register char *cp;
4407
4408         dbp = skip_spaces (dbp);
4409         if (*dbp == '\0')
4410         {
4411                 readline (&lb, inf);
4412                 dbp = lb.buffer;
4413                 if (dbp[5] != '&')
4414                         return;
4415                 dbp += 6;
4416                 dbp = skip_spaces (dbp);
4417         }
4418         if (!ISALPHA (*dbp) && *dbp != '_' && *dbp != '$')
4419                 return;
4420         for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
4421                 continue;
4422         make_tag (dbp, cp-dbp, TRUE,
4423                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4424 }
4425
4426
4427 static void
4428 Fortran_functions (inf)
4429 FILE *inf;
4430 {
4431         LOOP_ON_INPUT_LINES (inf, lb, dbp)
4432         {
4433                 if (*dbp == '%')
4434                         dbp++;                  /* Ratfor escape to fortran */
4435                 dbp = skip_spaces (dbp);
4436                 if (*dbp == '\0')
4437                         continue;
4438                 switch (lowcase (*dbp))
4439                 {
4440                 case 'i':
4441                         if (nocase_tail ("integer"))
4442                                 F_takeprec ();
4443                         break;
4444                 case 'r':
4445                         if (nocase_tail ("real"))
4446                                 F_takeprec ();
4447                         break;
4448                 case 'l':
4449                         if (nocase_tail ("logical"))
4450                                 F_takeprec ();
4451                         break;
4452                 case 'c':
4453                         if (nocase_tail ("complex") || nocase_tail ("character"))
4454                                 F_takeprec ();
4455                         break;
4456                 case 'd':
4457                         if (nocase_tail ("double"))
4458                         {
4459                                 dbp = skip_spaces (dbp);
4460                                 if (*dbp == '\0')
4461                                         continue;
4462                                 if (nocase_tail ("precision"))
4463                                         break;
4464                                 continue;
4465                         }
4466                         break;
4467                 default:
4468                         break;
4469                 }
4470                 dbp = skip_spaces (dbp);
4471                 if (*dbp == '\0')
4472                         continue;
4473                 switch (lowcase (*dbp))
4474                 {
4475                 case 'f':
4476                         if (nocase_tail ("function"))
4477                                 F_getit (inf);
4478                         continue;
4479                 case 's':
4480                         if (nocase_tail ("subroutine"))
4481                                 F_getit (inf);
4482                         continue;
4483                 case 'e':
4484                         if (nocase_tail ("entry"))
4485                                 F_getit (inf);
4486                         continue;
4487                 case 'b':
4488                         if (nocase_tail ("blockdata") || nocase_tail ("block data"))
4489                         {
4490                                 dbp = skip_spaces (dbp);
4491                                 if (*dbp == '\0')       /* assume un-named */
4492                                         make_tag ("blockdata", 9, TRUE,
4493                                                   lb.buffer, dbp - lb.buffer, lineno, linecharno);
4494                                 else
4495                                         F_getit (inf);  /* look for name */
4496                         }
4497                         continue;
4498                 default:
4499                         break;
4500                 }
4501         }
4502 }
4503
4504 \f
4505 /*
4506  * Ada parsing
4507  * Original code by
4508  * Philippe Waroquiers (1998)
4509  */
4510
4511 static void Ada_getit __P((FILE *, char *));
4512
4513 /* Once we are positioned after an "interesting" keyword, let's get
4514    the real tag value necessary. */
4515 static void
4516 Ada_getit (inf, name_qualifier)
4517 FILE *inf;
4518 char *name_qualifier;
4519 {
4520         register char *cp;
4521         char *name;
4522         char c;
4523
4524         while (!feof (inf))
4525         {
4526                 dbp = skip_spaces (dbp);
4527                 if (*dbp == '\0'
4528                     || (dbp[0] == '-' && dbp[1] == '-'))
4529                 {
4530                         readline (&lb, inf);
4531                         dbp = lb.buffer;
4532                 }
4533                 switch (lowcase(*dbp))
4534                 {
4535                 case 'b':
4536                         if (nocase_tail ("body"))
4537                         {
4538                                 /* Skipping body of   procedure body   or   package body or ....
4539                                    resetting qualifier to body instead of spec. */
4540                                 name_qualifier = "/b";
4541                                 continue;
4542                         }
4543                         break;
4544                 case 't':
4545                         /* Skipping type of   task type   or   protected type ... */
4546                         if (nocase_tail ("type"))
4547                                 continue;
4548                         break;
4549                 default:
4550                         break;
4551                 }
4552                 if (*dbp == '"')
4553                 {
4554                         dbp += 1;
4555                         for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
4556                                 continue;
4557                 }
4558                 else
4559                 {
4560                         dbp = skip_spaces (dbp);
4561                         for (cp = dbp;
4562                              (*cp != '\0'
4563                               && (ISALPHA (*cp) || ISDIGIT (*cp) || *cp == '_' || *cp == '.'));
4564                              cp++)
4565                                 continue;
4566                         if (cp == dbp)
4567                                 return;
4568                 }
4569                 c = *cp;
4570                 *cp = '\0';
4571                 name = concat (dbp, name_qualifier, "");
4572                 *cp = c;
4573                 make_tag (name, strlen (name), TRUE,
4574                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4575                 free (name);
4576                 if (c == '"')
4577                         dbp = cp + 1;
4578                 return;
4579         }
4580 }
4581
4582 static void
4583 Ada_funcs (inf)
4584 FILE *inf;
4585 {
4586         bool inquote = FALSE;
4587         bool skip_till_semicolumn = FALSE;
4588
4589         LOOP_ON_INPUT_LINES (inf, lb, dbp)
4590         {
4591                 while (*dbp != '\0')
4592                 {
4593                         /* Skip a string i.e. "abcd". */
4594                         if (inquote || (*dbp == '"'))
4595                         {
4596                                 dbp = etags_strchr ((inquote) ? dbp : dbp+1, '"');
4597                                 if (dbp != NULL)
4598                                 {
4599                                         inquote = FALSE;
4600                                         dbp += 1;
4601                                         continue;       /* advance char */
4602                                 }
4603                                 else
4604                                 {
4605                                         inquote = TRUE;
4606                                         break;  /* advance line */
4607                                 }
4608                         }
4609
4610                         /* Skip comments. */
4611                         if (dbp[0] == '-' && dbp[1] == '-')
4612                                 break;          /* advance line */
4613
4614                         /* Skip character enclosed in single quote i.e. 'a'
4615                            and skip single quote starting an attribute i.e. 'Image. */
4616                         if (*dbp == '\'')
4617                         {
4618                                 dbp++ ;
4619                                 if (*dbp != '\0')
4620                                         dbp++;
4621                                 continue;
4622                         }
4623
4624                         if (skip_till_semicolumn)
4625                         {
4626                                 if (*dbp == ';')
4627                                         skip_till_semicolumn = FALSE;
4628                                 dbp++;
4629                                 continue;         /* advance char */
4630                         }
4631
4632                         /* Search for beginning of a token.  */
4633                         if (!begtoken (*dbp))
4634                         {
4635                                 dbp++;
4636                                 continue;               /* advance char */
4637                         }
4638
4639                         /* We are at the beginning of a token. */
4640                         switch (lowcase(*dbp))
4641                         {
4642                         case 'f':
4643                                 if (!packages_only && nocase_tail ("function"))
4644                                         Ada_getit (inf, "/f");
4645                                 else
4646                                         break;          /* from switch */
4647                                 continue;               /* advance char */
4648                         case 'p':
4649                                 if (!packages_only && nocase_tail ("procedure"))
4650                                         Ada_getit (inf, "/p");
4651                                 else if (nocase_tail ("package"))
4652                                         Ada_getit (inf, "/s");
4653                                 else if (nocase_tail ("protected")) /* protected type */
4654                                         Ada_getit (inf, "/t");
4655                                 else
4656                                         break;          /* from switch */
4657                                 continue;               /* advance char */
4658
4659                         case 'u':
4660                                 if (typedefs && !packages_only && nocase_tail ("use"))
4661                                 {
4662                                         /* when tagging types, avoid tagging  use type Pack.Typename;
4663                                            for this, we will skip everything till a ; */
4664                                         skip_till_semicolumn = TRUE;
4665                                         continue;     /* advance char */
4666                                 }
4667
4668                         case 't':
4669                                 if (!packages_only && nocase_tail ("task"))
4670                                         Ada_getit (inf, "/k");
4671                                 else if (typedefs && !packages_only && nocase_tail ("type"))
4672                                 {
4673                                         Ada_getit (inf, "/t");
4674                                         while (*dbp != '\0')
4675                                                 dbp += 1;
4676                                 }
4677                                 else
4678                                         break;          /* from switch */
4679                                 continue;               /* advance char */
4680                         default:
4681                                 break;
4682                         }
4683
4684                         /* Look for the end of the token. */
4685                         while (!endtoken (*dbp))
4686                                 dbp++;
4687
4688                 } /* advance char */
4689         } /* advance line */
4690 }
4691
4692 \f
4693 /*
4694  * Unix and microcontroller assembly tag handling
4695  * Labels:  /^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]/
4696  * Idea by Bob Weiner, Motorola Inc. (1994)
4697  */
4698 static void
4699 Asm_labels (inf)
4700 FILE *inf;
4701 {
4702         register char *cp;
4703
4704         LOOP_ON_INPUT_LINES (inf, lb, cp)
4705         {
4706                 /* If first char is alphabetic or one of [_.$], test for colon
4707                    following identifier. */
4708                 if (ISALPHA (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4709                 {
4710                         /* Read past label. */
4711                         cp++;
4712                         while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4713                                 cp++;
4714                         if (*cp == ':' || iswhite (*cp))
4715                                 /* Found end of label, so copy it and add it to the table. */
4716                                 make_tag (lb.buffer, cp - lb.buffer, TRUE,
4717                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4718                 }
4719         }
4720 }
4721
4722 \f
4723 /*
4724  * Perl support
4725  * Perl sub names: /^sub[ \t\n]+[^ \t\n{]+/
4726  * Perl variable names: /^(my|local).../
4727  * Original code by Bart Robinson <lomew@cs.utah.edu> (1995)
4728  * Additions by Michael Ernst <mernst@alum.mit.edu> (1997)
4729  * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
4730  */
4731 static void
4732 Perl_functions (inf)
4733 FILE *inf;
4734 {
4735         char *package = savestr ("main"); /* current package name */
4736         register char *cp;
4737
4738         LOOP_ON_INPUT_LINES (inf, lb, cp)
4739         {
4740                 cp = skip_spaces (cp);
4741
4742                 if (LOOKING_AT (cp, "package"))
4743                 {
4744                         free (package);
4745                         get_tag (cp, &package);
4746                 }
4747                 else if (LOOKING_AT (cp, "sub"))
4748                 {
4749                         char *pos;
4750                         char *sp = cp;
4751
4752                         while (!notinname (*cp))
4753                                 cp++;
4754                         if (cp == sp)
4755                                 continue;               /* nothing found */
4756                         if ((pos = etags_strchr (sp, ':')) != NULL
4757                             && pos < cp && pos[1] == ':')
4758                                 /* The name is already qualified. */
4759                                 make_tag (sp, cp - sp, TRUE,
4760                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4761                         else
4762                                 /* Qualify it. */
4763                         {
4764                                 char savechar, *name;
4765
4766                                 savechar = *cp;
4767                                 *cp = '\0';
4768                                 name = concat (package, "::", sp);
4769                                 *cp = savechar;
4770                                 make_tag (name, strlen(name), TRUE,
4771                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4772                                 free (name);
4773                         }
4774                 }
4775                 else if (globals)       /* only if we are tagging global vars */
4776                 {
4777                         /* Skip a qualifier, if any. */
4778                         bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
4779                         /* After "my" or "local", but before any following paren or space. */
4780                         char *varstart = cp;
4781
4782                         if (qual                /* should this be removed?  If yes, how? */
4783                             && (*cp == '$' || *cp == '@' || *cp == '%'))
4784                         {
4785                                 varstart += 1;
4786                                 do
4787                                         cp++;
4788                                 while (ISALNUM (*cp) || *cp == '_');
4789                         }
4790                         else if (qual)
4791                         {
4792                                 /* Should be examining a variable list at this point;
4793                                    could insist on seeing an open parenthesis. */
4794                                 while (*cp != '\0' && *cp != ';' && *cp != '=' &&  *cp != ')')
4795                                         cp++;
4796                         }
4797                         else
4798                                 continue;
4799
4800                         make_tag (varstart, cp - varstart, FALSE,
4801                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4802                 }
4803         }
4804         free (package);
4805 }
4806
4807
4808 /*
4809  * Python support
4810  * Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
4811  * Idea by Eric S. Raymond <esr@thyrsus.com> (1997)
4812  * More ideas by seb bacon <seb@jamkit.com> (2002)
4813  */
4814 static void
4815 Python_functions (inf)
4816 FILE *inf;
4817 {
4818         register char *cp;
4819
4820         LOOP_ON_INPUT_LINES (inf, lb, cp)
4821         {
4822                 cp = skip_spaces (cp);
4823                 if (LOOKING_AT (cp, "def") || LOOKING_AT (cp, "class"))
4824                 {
4825                         char *name = cp;
4826                         while (!notinname (*cp) && *cp != ':')
4827                                 cp++;
4828                         make_tag (name, cp - name, TRUE,
4829                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4830                 }
4831         }
4832 }
4833
4834 \f
4835 /*
4836  * PHP support
4837  * Look for:
4838  *  - /^[ \t]*function[ \t\n]+[^ \t\n(]+/
4839  *  - /^[ \t]*class[ \t\n]+[^ \t\n]+/
4840  *  - /^[ \t]*define\(\"[^\"]+/
4841  * Only with --members:
4842  *  - /^[ \t]*var[ \t\n]+\$[^ \t\n=;]/
4843  * Idea by Diez B. Roggisch (2001)
4844  */
4845 static void
4846 PHP_functions (inf)
4847 FILE *inf;
4848 {
4849         register char *cp, *name;
4850         bool search_identifier = FALSE;
4851
4852         LOOP_ON_INPUT_LINES (inf, lb, cp)
4853         {
4854                 cp = skip_spaces (cp);
4855                 name = cp;
4856                 if (search_identifier
4857                     && *cp != '\0')
4858                 {
4859                         while (!notinname (*cp))
4860                                 cp++;
4861                         make_tag (name, cp - name, TRUE,
4862                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4863                         search_identifier = FALSE;
4864                 }
4865                 else if (LOOKING_AT (cp, "function"))
4866                 {
4867                         if(*cp == '&')
4868                                 cp = skip_spaces (cp+1);
4869                         if(*cp != '\0')
4870                         {
4871                                 name = cp;
4872                                 while (!notinname (*cp))
4873                                         cp++;
4874                                 make_tag (name, cp - name, TRUE,
4875                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4876                         }
4877                         else
4878                                 search_identifier = TRUE;
4879                 }
4880                 else if (LOOKING_AT (cp, "class"))
4881                 {
4882                         if (*cp != '\0')
4883                         {
4884                                 name = cp;
4885                                 while (*cp != '\0' && !iswhite (*cp))
4886                                         cp++;
4887                                 make_tag (name, cp - name, FALSE,
4888                                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4889                         }
4890                         else
4891                                 search_identifier = TRUE;
4892                 }
4893                 else if (strneq (cp, "define", 6)
4894                          && (cp = skip_spaces (cp+6))
4895                          && *cp++ == '('
4896                          && (*cp == '"' || *cp == '\''))
4897                 {
4898                         char quote = *cp++;
4899                         name = cp;
4900                         while (*cp != quote && *cp != '\0')
4901                                 cp++;
4902                         make_tag (name, cp - name, FALSE,
4903                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4904                 }
4905                 else if (members
4906                          && LOOKING_AT (cp, "var")
4907                          && *cp == '$')
4908                 {
4909                         name = cp;
4910                         while (!notinname(*cp))
4911                                 cp++;
4912                         make_tag (name, cp - name, FALSE,
4913                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4914                 }
4915         }
4916 }
4917
4918 \f
4919 /*
4920  * Cobol tag functions
4921  * We could look for anything that could be a paragraph name.
4922  * i.e. anything that starts in column 8 is one word and ends in a full stop.
4923  * Idea by Corny de Souza (1993)
4924  */
4925 static void
4926 Cobol_paragraphs (inf)
4927 FILE *inf;
4928 {
4929         register char *bp, *ep;
4930
4931         LOOP_ON_INPUT_LINES (inf, lb, bp)
4932         {
4933                 if (lb.len < 9)
4934                         continue;
4935                 bp += 8;
4936
4937                 /* If eoln, compiler option or comment ignore whole line. */
4938                 if (bp[-1] != ' ' || !ISALNUM (bp[0]))
4939                         continue;
4940
4941                 for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
4942                         continue;
4943                 if (*ep++ == '.')
4944                         make_tag (bp, ep - bp, TRUE,
4945                                   lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4946         }
4947 }
4948
4949 \f
4950 /*
4951  * Makefile support
4952  * Ideas by Assar Westerlund <assar@sics.se> (2001)
4953  */
4954 static void
4955 Makefile_targets (inf)
4956 FILE *inf;
4957 {
4958         register char *bp;
4959
4960         LOOP_ON_INPUT_LINES (inf, lb, bp)
4961         {
4962                 if (*bp == '\t' || *bp == '#')
4963                         continue;
4964                 while (*bp != '\0' && *bp != '=' && *bp != ':')
4965                         bp++;
4966                 if (*bp == ':' || (globals && *bp == '='))
4967                 {
4968                         /* We should detect if there is more than one tag, but we do not.
4969                            We just skip initial and final spaces. */
4970                         char * namestart = skip_spaces (lb.buffer);
4971                         while (--bp > namestart)
4972                                 if (!notinname (*bp))
4973                                         break;
4974                         make_tag (namestart, bp - namestart + 1, TRUE,
4975                                   lb.buffer, bp - lb.buffer + 2, lineno, linecharno);
4976                 }
4977         }
4978 }
4979
4980 \f
4981 /*
4982  * Pascal parsing
4983  * Original code by Mosur K. Mohan (1989)
4984  *
4985  *  Locates tags for procedures & functions.  Doesn't do any type- or
4986  *  var-definitions.  It does look for the keyword "extern" or
4987  *  "forward" immediately following the procedure statement; if found,
4988  *  the tag is skipped.
4989  */
4990 static void
4991 Pascal_functions (inf)
4992 FILE *inf;
4993 {
4994         linebuffer tline;               /* mostly copied from C_entries */
4995         long save_lcno;
4996         int save_lineno, namelen, taglen;
4997         char c, *name;
4998
4999         bool                            /* each of these flags is TRUE if: */
5000                 incomment,                      /* point is inside a comment */
5001                 inquote,                        /* point is inside '..' string */
5002                 get_tagname,            /* point is after PROCEDURE/FUNCTION
5003                                            keyword, so next item = potential tag */
5004                 found_tag,                      /* point is after a potential tag */
5005                 inparms,                        /* point is within parameter-list */
5006                 verify_tag;                     /* point has passed the parm-list, so the
5007                                                    next token will determine whether this
5008                                                    is a FORWARD/EXTERN to be ignored, or
5009                                                    whether it is a real tag */
5010
5011         save_lcno = save_lineno = namelen = taglen = 0; /* keep compiler quiet */
5012         name = NULL;                    /* keep compiler quiet */
5013         dbp = lb.buffer;
5014         *dbp = '\0';
5015         linebuffer_init (&tline);
5016
5017         incomment = inquote = FALSE;
5018         found_tag = FALSE;              /* have a proc name; check if extern */
5019         get_tagname = FALSE;            /* found "procedure" keyword         */
5020         inparms = FALSE;                /* found '(' after "proc"            */
5021         verify_tag = FALSE;             /* check if "extern" is ahead        */
5022
5023
5024         while (!feof (inf))             /* long main loop to get next char */
5025         {
5026                 c = *dbp++;
5027                 if (c == '\0')          /* if end of line */
5028                 {
5029                         readline (&lb, inf);
5030                         dbp = lb.buffer;
5031                         if (*dbp == '\0')
5032                                 continue;
5033                         if (!((found_tag && verify_tag)
5034                               || get_tagname))
5035                                 c = *dbp++;             /* only if don't need *dbp pointing
5036                                                            to the beginning of the name of
5037                                                            the procedure or function */
5038                 }
5039                 if (incomment)
5040                 {
5041                         if (c == '}')           /* within { } comments */
5042                                 incomment = FALSE;
5043                         else if (c == '*' && *dbp == ')') /* within (* *) comments */
5044                         {
5045                                 dbp++;
5046                                 incomment = FALSE;
5047                         }
5048                         continue;
5049                 }
5050                 else if (inquote)
5051                 {
5052                         if (c == '\'')
5053                                 inquote = FALSE;
5054                         continue;
5055                 }
5056                 else
5057                         switch (c)
5058                         {
5059                         case '\'':
5060                                 inquote = TRUE; /* found first quote */
5061                                 continue;
5062                         case '{':               /* found open { comment */
5063                                 incomment = TRUE;
5064                                 continue;
5065                         case '(':
5066                                 if (*dbp == '*')        /* found open (* comment */
5067                                 {
5068                                         incomment = TRUE;
5069                                         dbp++;
5070                                 }
5071                                 else if (found_tag)     /* found '(' after tag, i.e., parm-list */
5072                                         inparms = TRUE;
5073                                 continue;
5074                         case ')':               /* end of parms list */
5075                                 if (inparms)
5076                                         inparms = FALSE;
5077                                 continue;
5078                         case ';':
5079                                 if (found_tag && !inparms) /* end of proc or fn stmt */
5080                                 {
5081                                         verify_tag = TRUE;
5082                                         break;
5083                                 }
5084                                 continue;
5085                         default:
5086                                 break;
5087                         }
5088                 if (found_tag && verify_tag && (*dbp != ' '))
5089                 {
5090                         /* Check if this is an "extern" declaration. */
5091                         if (*dbp == '\0')
5092                                 continue;
5093                         if (lowcase (*dbp == 'e'))
5094                         {
5095                                 if (nocase_tail ("extern")) /* superfluous, really! */
5096                                 {
5097                                         found_tag = FALSE;
5098                                         verify_tag = FALSE;
5099                                 }
5100                         }
5101                         else if (lowcase (*dbp) == 'f')
5102                         {
5103                                 if (nocase_tail ("forward")) /* check for forward reference */
5104                                 {
5105                                         found_tag = FALSE;
5106                                         verify_tag = FALSE;
5107                                 }
5108                         }
5109                         if (found_tag && verify_tag) /* not external proc, so make tag */
5110                         {
5111                                 found_tag = FALSE;
5112                                 verify_tag = FALSE;
5113                                 make_tag (name, namelen, TRUE,
5114                                           tline.buffer, taglen, save_lineno, save_lcno);
5115                                 continue;
5116                         }
5117                 }
5118                 if (get_tagname)                /* grab name of proc or fn */
5119                 {
5120                         char *cp;
5121
5122                         if (*dbp == '\0')
5123                                 continue;
5124
5125                         /* Find block name. */
5126                         for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
5127                                 continue;
5128
5129                         /* Save all values for later tagging. */
5130                         linebuffer_setlen (&tline, lb.len+1);
5131                         xstrncpy(tline.buffer, lb.buffer, lb.len+1);
5132                         save_lineno = lineno;
5133                         save_lcno = linecharno;
5134                         name = tline.buffer + (dbp - lb.buffer);
5135                         namelen = cp - dbp;
5136                         taglen = cp - lb.buffer + 1;
5137
5138                         dbp = cp;               /* set dbp to e-o-token */
5139                         get_tagname = FALSE;
5140                         found_tag = TRUE;
5141                         continue;
5142
5143                         /* And proceed to check for "extern". */
5144                 }
5145                 else if (!incomment && !inquote && !found_tag)
5146                 {
5147                         /* Check for proc/fn keywords. */
5148                         switch (lowcase (c))
5149                         {
5150                         case 'p':
5151                                 if (nocase_tail ("rocedure")) /* c = 'p', dbp has advanced */
5152                                         get_tagname = TRUE;
5153                                 continue;
5154                         case 'f':
5155                                 if (nocase_tail ("unction"))
5156                                         get_tagname = TRUE;
5157                                 continue;
5158                         default:
5159                                 break;
5160                         }
5161                 }
5162         } /* while not eof */
5163
5164         free (tline.buffer);
5165 }
5166
5167 \f
5168 /*
5169  * Lisp tag functions
5170  *  look for (def or (DEF, quote or QUOTE
5171  */
5172
5173 static void L_getit __P((void));
5174
5175 static void
5176 L_getit ()
5177 {
5178         if (*dbp == '\'')               /* Skip prefix quote */
5179                 dbp++;
5180         else if (*dbp == '(')
5181         {
5182                 dbp++;
5183                 /* Try to skip "(quote " */
5184                 if (!LOOKING_AT (dbp, "quote") && !LOOKING_AT (dbp, "QUOTE"))
5185                         /* Ok, then skip "(" before name in (defstruct (foo)) */
5186                         dbp = skip_spaces (dbp);
5187         }
5188         get_tag (dbp, NULL);
5189 }
5190
5191 static void
5192 Lisp_functions (inf)
5193 FILE *inf;
5194 {
5195         LOOP_ON_INPUT_LINES (inf, lb, dbp)
5196         {
5197                 if (dbp[0] != '(')
5198                         continue;
5199
5200                 if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
5201                 {
5202                         dbp = skip_non_spaces (dbp);
5203                         dbp = skip_spaces (dbp);
5204                         L_getit ();
5205                 }
5206                 else
5207                 {
5208                         /* Check for (foo::defmumble name-defined ... */
5209                         do
5210                                 dbp++;
5211                         while (!notinname (*dbp) && *dbp != ':');
5212                         if (*dbp == ':')
5213                         {
5214                                 do
5215                                         dbp++;
5216                                 while (*dbp == ':');
5217
5218                                 if (strneq (dbp, "def", 3) || strneq (dbp, "DEF", 3))
5219                                 {
5220                                         dbp = skip_non_spaces (dbp);
5221                                         dbp = skip_spaces (dbp);
5222                                         L_getit ();
5223                                 }
5224                         }
5225                 }
5226         }
5227 }
5228
5229 \f
5230 /*
5231  * Lua script language parsing
5232  * Original code by David A. Capello <dacap@users.sourceforge.net> (2004)
5233  *
5234  *  "function" and "local function" are tags if they start at column 1.
5235  */
5236 static void
5237 Lua_functions (inf)
5238 FILE *inf;
5239 {
5240         register char *bp;
5241
5242         LOOP_ON_INPUT_LINES (inf, lb, bp)
5243         {
5244                 if (bp[0] != 'f' && bp[0] != 'l')
5245                         continue;
5246
5247                 (void)LOOKING_AT (bp, "local"); /* skip possible "local" */
5248
5249                 if (LOOKING_AT (bp, "function"))
5250                         get_tag (bp, NULL);
5251         }
5252 }
5253
5254 \f
5255 /*
5256  * Postscript tags
5257  * Just look for lines where the first character is '/'
5258  * Also look at "defineps" for PSWrap
5259  * Ideas by:
5260  *   Richard Mlynarik <mly@adoc.xerox.com> (1997)
5261  *   Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
5262  */
5263 static void
5264 PS_functions (inf)
5265 FILE *inf;
5266 {
5267         register char *bp, *ep;
5268
5269         LOOP_ON_INPUT_LINES (inf, lb, bp)
5270         {
5271                 if (bp[0] == '/')
5272                 {
5273                         for (ep = bp+1;
5274                              *ep != '\0' && *ep != ' ' && *ep != '{';
5275                              ep++)
5276                                 continue;
5277                         make_tag (bp, ep - bp, TRUE,
5278                                   lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
5279                 }
5280                 else if (LOOKING_AT (bp, "defineps"))
5281                         get_tag (bp, NULL);
5282         }
5283 }
5284
5285 \f
5286 /*
5287  * Forth tags
5288  * Ignore anything after \ followed by space or in ( )
5289  * Look for words defined by :
5290  * Look for constant, code, create, defer, value, and variable
5291  * OBP extensions:  Look for buffer:, field,
5292  * Ideas by Eduardo Horvath <eeh@netbsd.org> (2004)
5293  */
5294 static void
5295 Forth_words (inf)
5296 FILE *inf;
5297 {
5298         register char *bp;
5299
5300         LOOP_ON_INPUT_LINES (inf, lb, bp)
5301                 while ((bp = skip_spaces (bp))[0] != '\0')
5302                         if (bp[0] == '\\' && iswhite(bp[1]))
5303                                 break;                  /* read next line */
5304                         else if (bp[0] == '(' && iswhite(bp[1]))
5305                                 do                      /* skip to ) or eol */
5306                                         bp++;
5307                                 while (*bp != ')' && *bp != '\0');
5308                         else if ((bp[0] == ':' && iswhite(bp[1]) && bp++)
5309                                  || LOOKING_AT_NOCASE (bp, "constant")
5310                                  || LOOKING_AT_NOCASE (bp, "code")
5311                                  || LOOKING_AT_NOCASE (bp, "create")
5312                                  || LOOKING_AT_NOCASE (bp, "defer")
5313                                  || LOOKING_AT_NOCASE (bp, "value")
5314                                  || LOOKING_AT_NOCASE (bp, "variable")
5315                                  || LOOKING_AT_NOCASE (bp, "buffer:")
5316                                  || LOOKING_AT_NOCASE (bp, "field"))
5317                                 get_tag (skip_spaces (bp), NULL); /* Yay!  A definition! */
5318                         else
5319                                 bp = skip_non_spaces (bp);
5320 }
5321
5322 \f
5323 /*
5324  * Scheme tag functions
5325  * look for (def... xyzzy
5326  *          (def... (xyzzy
5327  *          (def ... ((...(xyzzy ....
5328  *          (set! xyzzy
5329  * Original code by Ken Haase (1985?)
5330  */
5331 static void
5332 Scheme_functions (inf)
5333 FILE *inf;
5334 {
5335         register char *bp;
5336
5337         LOOP_ON_INPUT_LINES (inf, lb, bp)
5338         {
5339                 if (strneq (bp, "(def", 4) || strneq (bp, "(DEF", 4))
5340                 {
5341                         bp = skip_non_spaces (bp+4);
5342                         /* Skip over open parens and white space */
5343                         while (notinname (*bp))
5344                                 bp++;
5345                         get_tag (bp, NULL);
5346                 }
5347                 if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))
5348                         get_tag (bp, NULL);
5349         }
5350 }
5351
5352 \f
5353 /* Find tags in TeX and LaTeX input files.  */
5354
5355 /* TEX_toktab is a table of TeX control sequences that define tags.
5356  * Each entry records one such control sequence.
5357  *
5358  * Original code from who knows whom.
5359  * Ideas by:
5360  *   Stefan Monnier (2002)
5361  */
5362
5363 static linebuffer *TEX_toktab = NULL; /* Table with tag tokens */
5364
5365 /* Default set of control sequences to put into TEX_toktab.
5366    The value of environment var TEXTAGS is prepended to this.  */
5367 static char *TEX_defenv = "\
5368 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
5369 :part:appendix:entry:index:def\
5370 :newcommand:renewcommand:newenvironment:renewenvironment";
5371
5372 static void TEX_mode __P((FILE *));
5373 static void TEX_decode_env __P((char *, char *));
5374
5375 static char TEX_esc = '\\';
5376 static char TEX_opgrp = '{';
5377 static char TEX_clgrp = '}';
5378
5379 /*
5380  * TeX/LaTeX scanning loop.
5381  */
5382 static void
5383 TeX_commands (inf)
5384 FILE *inf;
5385 {
5386         char *cp;
5387         linebuffer *key;
5388
5389         /* Select either \ or ! as escape character.  */
5390         TEX_mode (inf);
5391
5392         /* Initialize token table once from environment. */
5393         if (TEX_toktab == NULL)
5394                 TEX_decode_env ("TEXTAGS", TEX_defenv);
5395
5396         LOOP_ON_INPUT_LINES (inf, lb, cp)
5397         {
5398                 /* Look at each TEX keyword in line. */
5399                 for (;;)
5400                 {
5401                         /* Look for a TEX escape. */
5402                         while (*cp++ != TEX_esc)
5403                                 if (cp[-1] == '\0' || cp[-1] == '%')
5404                                         goto tex_next_line;
5405
5406                         for (key = TEX_toktab; key->buffer != NULL; key++)
5407                                 if (strneq (cp, key->buffer, key->len))
5408                                 {
5409                                         register char *p;
5410                                         int namelen, linelen;
5411                                         bool opgrp = FALSE;
5412
5413                                         cp = skip_spaces (cp + key->len);
5414                                         if (*cp == TEX_opgrp)
5415                                         {
5416                                                 opgrp = TRUE;
5417                                                 cp++;
5418                                         }
5419                                         for (p = cp;
5420                                              (!iswhite (*p) && *p != '#' &&
5421                                               *p != TEX_opgrp && *p != TEX_clgrp);
5422                                              p++)
5423                                                 continue;
5424                                         namelen = p - cp;
5425                                         linelen = lb.len;
5426                                         if (!opgrp || *p == TEX_clgrp)
5427                                         {
5428                                                 while (*p != '\0' && *p != TEX_opgrp && *p != TEX_clgrp)
5429                                                         p++;
5430                                                 linelen = p - lb.buffer + 1;
5431                                         }
5432                                         make_tag (cp, namelen, TRUE,
5433                                                   lb.buffer, linelen, lineno, linecharno);
5434                                         goto tex_next_line; /* We only tag a line once */
5435                                 }
5436                 }
5437         tex_next_line:
5438                 ;
5439         }
5440 }
5441
5442 #define TEX_LESC '\\'
5443 #define TEX_SESC '!'
5444
5445 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
5446    chars accordingly. */
5447 static void
5448 TEX_mode (inf)
5449 FILE *inf;
5450 {
5451         int c;
5452
5453         while ((c = getc (inf)) != EOF)
5454         {
5455                 /* Skip to next line if we hit the TeX comment char. */
5456                 if (c == '%')
5457                         while (c != '\n' && c != EOF)
5458                                 c = getc (inf);
5459                 else if (c == TEX_LESC || c == TEX_SESC )
5460                         break;
5461         }
5462
5463         if (c == TEX_LESC)
5464         {
5465                 TEX_esc = TEX_LESC;
5466                 TEX_opgrp = '{';
5467                 TEX_clgrp = '}';
5468         }
5469         else
5470         {
5471                 TEX_esc = TEX_SESC;
5472                 TEX_opgrp = '<';
5473                 TEX_clgrp = '>';
5474         }
5475         /* If the input file is compressed, inf is a pipe, and rewind may fail.
5476            No attempt is made to correct the situation. */
5477         rewind (inf);
5478 }
5479
5480 /* Read environment and prepend it to the default string.
5481    Build token table. */
5482 static void
5483 TEX_decode_env (evarname, defenv)
5484 char *evarname;
5485 char *defenv;
5486 {
5487         register char *env, *p;
5488         int i, len;
5489
5490         /* Append default string to environment. */
5491         env = getenv (evarname);
5492         if (!env)
5493                 env = defenv;
5494         else
5495         {
5496                 char *oldenv = env;
5497                 env = concat (oldenv, defenv, "");
5498         }
5499
5500         /* Allocate a token table */
5501         for (len = 1, p = env; p;)
5502                 if ((p = etags_strchr (p, ':')) && *++p != '\0')
5503                         len++;
5504         TEX_toktab = xnew (len, linebuffer);
5505
5506         /* Unpack environment string into token table. Be careful about */
5507         /* zero-length strings (leading ':', "::" and trailing ':') */
5508         for (i = 0; *env != '\0';)
5509         {
5510                 p = etags_strchr (env, ':');
5511                 if (!p)                 /* End of environment string. */
5512                         p = env + strlen (env);
5513                 if (p - env > 0)
5514                 {                       /* Only non-zero strings. */
5515                         TEX_toktab[i].buffer = savenstr (env, p - env);
5516                         TEX_toktab[i].len = p - env;
5517                         i++;
5518                 }
5519                 if (*p)
5520                         env = p + 1;
5521                 else
5522                 {
5523                         TEX_toktab[i].buffer = NULL; /* Mark end of table. */
5524                         TEX_toktab[i].len = 0;
5525                         break;
5526                 }
5527         }
5528 }
5529
5530 \f
5531 /* Texinfo support.  Dave Love, Mar. 2000.  */
5532 static void
5533 Texinfo_nodes (inf)
5534 FILE * inf;
5535 {
5536         char *cp, *start;
5537         LOOP_ON_INPUT_LINES (inf, lb, cp)
5538                 if (LOOKING_AT (cp, "@node"))
5539                 {
5540                         start = cp;
5541                         while (*cp != '\0' && *cp != ',')
5542                                 cp++;
5543                         make_tag (start, cp - start, TRUE,
5544                                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5545                 }
5546 }
5547
5548 \f
5549 /*
5550  * HTML support.
5551  * Contents of <title>, <h1>, <h2>, <h3> are tags.
5552  * Contents of <a name=xxx> are tags with name xxx.
5553  *
5554  * Francesco Potortì, 2002.
5555  */
5556 static void
5557 HTML_labels (inf)
5558 FILE * inf;
5559 {
5560         bool getnext = FALSE;           /* next text outside of HTML tags is a tag */
5561         bool skiptag = FALSE;           /* skip to the end of the current HTML tag */
5562         bool intag = FALSE;             /* inside an html tag, looking for ID= */
5563         bool inanchor = FALSE;  /* when INTAG, is an anchor, look for NAME= */
5564         char *end;
5565
5566
5567         linebuffer_setlen (&token_name, 0); /* no name in buffer */
5568
5569         LOOP_ON_INPUT_LINES (inf, lb, dbp)
5570                 for (;;)                        /* loop on the same line */
5571                 {
5572                         if (skiptag)            /* skip HTML tag */
5573                         {
5574                                 while (*dbp != '\0' && *dbp != '>')
5575                                         dbp++;
5576                                 if (*dbp == '>')
5577                                 {
5578                                         dbp += 1;
5579                                         skiptag = FALSE;
5580                                         continue;       /* look on the same line */
5581                                 }
5582                                 break;          /* go to next line */
5583                         }
5584
5585                         else if (intag) /* look for "name=" or "id=" */
5586                         {
5587                                 while (*dbp != '\0' && *dbp != '>'
5588                                        && lowcase (*dbp) != 'n' && lowcase (*dbp) != 'i')
5589                                         dbp++;
5590                                 if (*dbp == '\0')
5591                                         break;          /* go to next line */
5592                                 if (*dbp == '>')
5593                                 {
5594                                         dbp += 1;
5595                                         intag = FALSE;
5596                                         continue;       /* look on the same line */
5597                                 }
5598                                 if ((inanchor && LOOKING_AT_NOCASE (dbp, "name="))
5599                                     || LOOKING_AT_NOCASE (dbp, "id="))
5600                                 {
5601                                         bool quoted = (dbp[0] == '"');
5602
5603                                         if (quoted)
5604                                                 for (end = ++dbp; *end != '\0' && *end != '"'; end++)
5605                                                         continue;
5606                                         else
5607                                                 for (end = dbp; *end != '\0' && intoken (*end); end++)
5608                                                         continue;
5609                                         linebuffer_setlen (&token_name, end - dbp+1);
5610                                         xstrncpy (token_name.buffer, dbp, end - dbp+1);
5611                                         token_name.buffer[end - dbp] = '\0';
5612
5613                                         dbp = end;
5614                                         intag = FALSE;  /* we found what we looked for */
5615                                         skiptag = TRUE; /* skip to the end of the tag */
5616                                         getnext = TRUE; /* then grab the text */
5617                                         continue;       /* look on the same line */
5618                                 }
5619                                 dbp += 1;
5620                         }
5621
5622                         else if (getnext)       /* grab next tokens and tag them */
5623                         {
5624                                 dbp = skip_spaces (dbp);
5625                                 if (*dbp == '\0')
5626                                         break;          /* go to next line */
5627                                 if (*dbp == '<')
5628                                 {
5629                                         intag = TRUE;
5630                                         inanchor = (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]));
5631                                         continue;       /* look on the same line */
5632                                 }
5633
5634                                 for (end = dbp + 1; *end != '\0' && *end != '<'; end++)
5635                                         continue;
5636                                 make_tag (token_name.buffer, token_name.len, TRUE,
5637                                           dbp, end - dbp, lineno, linecharno);
5638                                 linebuffer_setlen (&token_name, 0);     /* no name in buffer */
5639                                 getnext = FALSE;
5640                                 break;          /* go to next line */
5641                         }
5642
5643                         else                    /* look for an interesting HTML tag */
5644                         {
5645                                 while (*dbp != '\0' && *dbp != '<')
5646                                         dbp++;
5647                                 if (*dbp == '\0')
5648                                         break;          /* go to next line */
5649                                 intag = TRUE;
5650                                 if (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]))
5651                                 {
5652                                         inanchor = TRUE;
5653                                         continue;       /* look on the same line */
5654                                 }
5655                                 else if (LOOKING_AT_NOCASE (dbp, "<title>")
5656                                          || LOOKING_AT_NOCASE (dbp, "<h1>")
5657                                          || LOOKING_AT_NOCASE (dbp, "<h2>")
5658                                          || LOOKING_AT_NOCASE (dbp, "<h3>"))
5659                                 {
5660                                         intag = FALSE;
5661                                         getnext = TRUE;
5662                                         continue;       /* look on the same line */
5663                                 }
5664                                 dbp += 1;
5665                         }
5666                 }
5667 }
5668
5669 \f
5670 /*
5671  * Prolog support
5672  *
5673  * Assumes that the predicate or rule starts at column 0.
5674  * Only the first clause of a predicate or rule is added.
5675  * Original code by Sunichirou Sugou (1989)
5676  * Rewritten by Anders Lindgren (1996)
5677  */
5678 static int prolog_pr __P((char *, char *));
5679 static void prolog_skip_comment __P((linebuffer *, FILE *));
5680 static int prolog_atom __P((char *, int));
5681
5682 static void
5683 Prolog_functions (inf)
5684 FILE *inf;
5685 {
5686         char *cp, *last;
5687         int len;
5688         int allocated;
5689
5690         allocated = 0;
5691         len = 0;
5692         last = NULL;
5693
5694         LOOP_ON_INPUT_LINES (inf, lb, cp)
5695         {
5696                 if (cp[0] == '\0')      /* Empty line */
5697                         continue;
5698                 else if (iswhite (cp[0])) /* Not a predicate */
5699                         continue;
5700                 else if (cp[0] == '/' && cp[1] == '*')  /* comment. */
5701                         prolog_skip_comment (&lb, inf);
5702                 else if ((len = prolog_pr (cp, last)) > 0)
5703                 {
5704                         /* Predicate or rule.  Store the function name so that we
5705                            only generate a tag for the first clause.  */
5706                         if (last == NULL)
5707                                 last = xnew(len + 1, char);
5708                         else if (len + 1 > allocated)
5709                                 xrnew (last, len + 1, char);
5710                         allocated = len + 1;
5711                         xstrncpy (last, cp, len+1);
5712                 }
5713         }
5714         free (last);
5715 }
5716
5717
5718 static void
5719 prolog_skip_comment (plb, inf)
5720 linebuffer *plb;
5721 FILE *inf;
5722 {
5723         char *cp;
5724
5725         do
5726         {
5727                 for (cp = plb->buffer; *cp != '\0'; cp++)
5728                         if (cp[0] == '*' && cp[1] == '/')
5729                                 return;
5730                 readline (plb, inf);
5731         }
5732         while (!feof(inf));
5733 }
5734
5735 /*
5736  * A predicate or rule definition is added if it matches:
5737  *     <beginning of line><Prolog Atom><whitespace>(
5738  * or  <beginning of line><Prolog Atom><whitespace>:-
5739  *
5740  * It is added to the tags database if it doesn't match the
5741  * name of the previous clause header.
5742  *
5743  * Return the size of the name of the predicate or rule, or 0 if no
5744  * header was found.
5745  */
5746 static int
5747 prolog_pr (s, last)
5748 char *s;
5749 char *last;             /* Name of last clause. */
5750 {
5751         int pos;
5752         int len;
5753
5754         pos = prolog_atom (s, 0);
5755         if (pos < 1)
5756                 return 0;
5757
5758         len = pos;
5759         pos = skip_spaces (s + pos) - s;
5760
5761         if ((s[pos] == '.'
5762              || (s[pos] == '(' && (pos += 1))
5763              || (s[pos] == ':' && s[pos + 1] == '-' && (pos += 2)))
5764             && (last == NULL            /* save only the first clause */
5765                 || len != (int)strlen (last)
5766                 || !strneq (s, last, len)))
5767         {
5768                 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5769                 return len;
5770         }
5771         else
5772                 return 0;
5773 }
5774
5775 /*
5776  * Consume a Prolog atom.
5777  * Return the number of bytes consumed, or -1 if there was an error.
5778  *
5779  * A prolog atom, in this context, could be one of:
5780  * - An alphanumeric sequence, starting with a lower case letter.
5781  * - A quoted arbitrary string. Single quotes can escape themselves.
5782  *   Backslash quotes everything.
5783  */
5784 static int
5785 prolog_atom (s, pos)
5786 char *s;
5787 int pos;
5788 {
5789         int origpos;
5790
5791         origpos = pos;
5792
5793         if (ISLOWER(s[pos]) || (s[pos] == '_'))
5794         {
5795                 /* The atom is unquoted. */
5796                 pos++;
5797                 while (ISALNUM(s[pos]) || (s[pos] == '_'))
5798                 {
5799                         pos++;
5800                 }
5801                 return pos - origpos;
5802         }
5803         else if (s[pos] == '\'')
5804         {
5805                 pos++;
5806
5807                 for (;;)
5808                 {
5809                         if (s[pos] == '\'')
5810                         {
5811                                 pos++;
5812                                 if (s[pos] != '\'')
5813                                         break;
5814                                 pos++;          /* A double quote */
5815                         }
5816                         else if (s[pos] == '\0')
5817                                 /* Multiline quoted atoms are ignored. */
5818                                 return -1;
5819                         else if (s[pos] == '\\')
5820                         {
5821                                 if (s[pos+1] == '\0')
5822                                         return -1;
5823                                 pos += 2;
5824                         }
5825                         else
5826                                 pos++;
5827                 }
5828                 return pos - origpos;
5829         }
5830         else
5831                 return -1;
5832 }
5833
5834 \f
5835 /*
5836  * Support for Erlang
5837  *
5838  * Generates tags for functions, defines, and records.
5839  * Assumes that Erlang functions start at column 0.
5840  * Original code by Anders Lindgren (1996)
5841  */
5842 static int erlang_func __P((char *, char *));
5843 static void erlang_attribute __P((char *));
5844 static int erlang_atom __P((char *));
5845
5846 static void
5847 Erlang_functions (inf)
5848 FILE *inf;
5849 {
5850         char *cp, *last;
5851         int len;
5852         int allocated;
5853
5854         allocated = 0;
5855         len = 0;
5856         last = NULL;
5857
5858         LOOP_ON_INPUT_LINES (inf, lb, cp)
5859         {
5860                 if (cp[0] == '\0')      /* Empty line */
5861                         continue;
5862                 else if (iswhite (cp[0])) /* Not function nor attribute */
5863                         continue;
5864                 else if (cp[0] == '%')  /* comment */
5865                         continue;
5866                 else if (cp[0] == '"')  /* Sometimes, strings start in column one */
5867                         continue;
5868                 else if (cp[0] == '-')  /* attribute, e.g. "-define" */
5869                 {
5870                         erlang_attribute (cp);
5871                         if (last != NULL)
5872                         {
5873                                 free (last);
5874                                 last = NULL;
5875                         }
5876                 }
5877                 else if ((len = erlang_func (cp, last)) > 0)
5878                 {
5879                         /*
5880                          * Function.  Store the function name so that we only
5881                          * generates a tag for the first clause.
5882                          */
5883                         if (last == NULL)
5884                                 last = xnew (len + 1, char);
5885                         else if (len + 1 > allocated)
5886                                 xrnew (last, len + 1, char);
5887                         allocated = len + 1;
5888                         xstrncpy (last, cp, allocated);
5889                 }
5890         }
5891         free (last);
5892 }
5893
5894
5895 /*
5896  * A function definition is added if it matches:
5897  *     <beginning of line><Erlang Atom><whitespace>(
5898  *
5899  * It is added to the tags database if it doesn't match the
5900  * name of the previous clause header.
5901  *
5902  * Return the size of the name of the function, or 0 if no function
5903  * was found.
5904  */
5905 static int
5906 erlang_func (s, last)
5907 char *s;
5908 char *last;             /* Name of last clause. */
5909 {
5910         int pos;
5911         int len;
5912
5913         pos = erlang_atom (s);
5914         if (pos < 1)
5915                 return 0;
5916
5917         len = pos;
5918         pos = skip_spaces (s + pos) - s;
5919
5920         /* Save only the first clause. */
5921         if (s[pos++] == '('
5922             && (last == NULL
5923                 || len != (int)strlen (last)
5924                 || !strneq (s, last, len)))
5925         {
5926                 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5927                 return len;
5928         }
5929
5930         return 0;
5931 }
5932
5933
5934 /*
5935  * Handle attributes.  Currently, tags are generated for defines
5936  * and records.
5937  *
5938  * They are on the form:
5939  * -define(foo, bar).
5940  * -define(Foo(M, N), M+N).
5941  * -record(graph, {vtab = notable, cyclic = true}).
5942  */
5943 static void
5944 erlang_attribute (s)
5945 char *s;
5946 {
5947         char *cp = s;
5948
5949         if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
5950             && *cp++ == '(')
5951         {
5952                 int len = erlang_atom (skip_spaces (cp));
5953                 if (len > 0)
5954                         make_tag (cp, len, TRUE, s, cp + len - s, lineno, linecharno);
5955         }
5956         return;
5957 }
5958
5959
5960 /*
5961  * Consume an Erlang atom (or variable).
5962  * Return the number of bytes consumed, or -1 if there was an error.
5963  */
5964 static int
5965 erlang_atom (s)
5966 char *s;
5967 {
5968         int pos = 0;
5969
5970         if (ISALPHA (s[pos]) || s[pos] == '_')
5971         {
5972                 /* The atom is unquoted. */
5973                 do
5974                         pos++;
5975                 while (ISALNUM (s[pos]) || s[pos] == '_');
5976         }
5977         else if (s[pos] == '\'')
5978         {
5979                 for (pos++; s[pos] != '\''; pos++)
5980                         if (s[pos] == '\0'      /* multiline quoted atoms are ignored */
5981                             || (s[pos] == '\\' && s[++pos] == '\0'))
5982                                 return 0;
5983                 pos++;
5984         }
5985
5986         return pos;
5987 }
5988
5989 \f
5990 static char *scan_separators __P((char *));
5991 static void add_regex __P((char *, language *));
5992 static char *substitute __P((char *, char *, struct re_registers *));
5993
5994 /*
5995  * Take a string like "/blah/" and turn it into "blah", verifying
5996  * that the first and last characters are the same, and handling
5997  * quoted separator characters.  Actually, stops on the occurrence of
5998  * an unquoted separator.  Also process \t, \n, etc. and turn into
5999  * appropriate characters. Works in place.  Null terminates name string.
6000  * Returns pointer to terminating separator, or NULL for
6001  * unterminated regexps.
6002  */
6003 static char *
6004 scan_separators (name)
6005 char *name;
6006 {
6007         char sep = name[0];
6008         char *copyto = name;
6009         bool quoted = FALSE;
6010
6011         for (++name; *name != '\0'; ++name)
6012         {
6013                 if (quoted)
6014                 {
6015                         switch (*name)
6016                         {
6017                         case 'a': *copyto++ = '\007'; break; /* BEL (bell)               */
6018                         case 'b': *copyto++ = '\b'; break;       /* BS (back space)      */
6019                         case 'd': *copyto++ = 0177; break;       /* DEL (delete)         */
6020                         case 'e': *copyto++ = 033; break;        /* ESC (delete)         */
6021                         case 'f': *copyto++ = '\f'; break;       /* FF (form feed)       */
6022                         case 'n': *copyto++ = '\n'; break;       /* NL (new line)        */
6023                         case 'r': *copyto++ = '\r'; break;       /* CR (carriage return) */
6024                         case 't': *copyto++ = '\t'; break;       /* TAB (horizontal tab) */
6025                         case 'v': *copyto++ = '\v'; break;       /* VT (vertical tab)    */
6026                         default:
6027                                 if (*name == sep)
6028                                         *copyto++ = sep;
6029                                 else
6030                                 {
6031                                         /* Something else is quoted, so preserve the quote. */
6032                                         *copyto++ = '\\';
6033                                         *copyto++ = *name;
6034                                 }
6035                                 break;
6036                         }
6037                         quoted = FALSE;
6038                 }
6039                 else if (*name == '\\')
6040                         quoted = TRUE;
6041                 else if (*name == sep)
6042                         break;
6043                 else
6044                         *copyto++ = *name;
6045         }
6046         if (*name != sep)
6047                 name = NULL;            /* signal unterminated regexp */
6048
6049         /* Terminate copied string. */
6050         *copyto = '\0';
6051         return name;
6052 }
6053
6054 /* Look at the argument of --regex or --no-regex and do the right
6055    thing.  Same for each line of a regexp file. */
6056 static void
6057 analyse_regex (regex_arg)
6058 char *regex_arg;
6059 {
6060         if (regex_arg == NULL)
6061         {
6062                 free_regexps ();                /* --no-regex: remove existing regexps */
6063                 return;
6064         }
6065
6066         /* A real --regexp option or a line in a regexp file. */
6067         switch (regex_arg[0])
6068         {
6069                 /* Comments in regexp file or null arg to --regex. */
6070         case '\0':
6071         case ' ':
6072         case '\t':
6073                 break;
6074
6075                 /* Read a regex file.  This is recursive and may result in a
6076                    loop, which will stop when the file descriptors are exhausted. */
6077         case '@':
6078         {
6079                 FILE *regexfp;
6080                 linebuffer regexbuf;
6081                 char *regexfile = regex_arg + 1;
6082
6083                 /* regexfile is a file containing regexps, one per line. */
6084                 regexfp = fopen (regexfile, "r");
6085                 if (regexfp == NULL)
6086                 {
6087                         pfatal (regexfile);
6088                         return;
6089                 }
6090                 linebuffer_init (&regexbuf);
6091                 while (readline_internal (&regexbuf, regexfp) > 0)
6092                         analyse_regex (regexbuf.buffer);
6093                 free (regexbuf.buffer);
6094                 fclose (regexfp);
6095         }
6096         break;
6097
6098         /* Regexp to be used for a specific language only. */
6099         case '{':
6100         {
6101                 language *lang;
6102                 char *lang_name = regex_arg + 1;
6103                 char *cp;
6104
6105                 for (cp = lang_name; *cp != '}'; cp++)
6106                         if (*cp == '\0')
6107                         {
6108                                 error ("unterminated language name in regex: %s", regex_arg);
6109                                 return;
6110                         }
6111                 *cp++ = '\0';
6112                 lang = get_language_from_langname (lang_name);
6113                 if (lang == NULL)
6114                         return;
6115                 add_regex (cp, lang);
6116         }
6117         break;
6118
6119         /* Regexp to be used for any language. */
6120         default:
6121                 add_regex (regex_arg, NULL);
6122                 break;
6123         }
6124 }
6125
6126 /* Separate the regexp pattern, compile it,
6127    and care for optional name and modifiers. */
6128 static void
6129 add_regex (regexp_pattern, lang)
6130 char *regexp_pattern;
6131 language *lang;
6132 {
6133         static struct re_pattern_buffer zeropattern;
6134         char sep, *pat, *name, *modifiers;
6135         const char *err;
6136         struct re_pattern_buffer *patbuf;
6137         regexp *rp;
6138         bool
6139                 force_explicit_name = TRUE, /* do not use implicit tag names */
6140                 ignore_case = FALSE,    /* case is significant */
6141                 multi_line = FALSE,             /* matches are done one line at a time */
6142                 single_line = FALSE;    /* dot does not match newline */
6143
6144
6145         if (strlen(regexp_pattern) < 3)
6146         {
6147                 error ("null regexp", (char *)NULL);
6148                 return;
6149         }
6150         sep = regexp_pattern[0];
6151         name = scan_separators (regexp_pattern);
6152         if (name == NULL)
6153         {
6154                 error ("%s: unterminated regexp", regexp_pattern);
6155                 return;
6156         }
6157         if (name[1] == sep)
6158         {
6159                 error ("null name for regexp \"%s\"", regexp_pattern);
6160                 return;
6161         }
6162         modifiers = scan_separators (name);
6163         if (modifiers == NULL)  /* no terminating separator --> no name */
6164         {
6165                 modifiers = name;
6166                 name = "";
6167         }
6168         else
6169                 modifiers += 1;         /* skip separator */
6170
6171         /* Parse regex modifiers. */
6172         for (; modifiers[0] != '\0'; modifiers++)
6173                 switch (modifiers[0])
6174                 {
6175                 case 'N':
6176                         if (modifiers == name)
6177                                 error ("forcing explicit tag name but no name, ignoring", NULL);
6178                         force_explicit_name = TRUE;
6179                         break;
6180                 case 'i':
6181                         ignore_case = TRUE;
6182                         break;
6183                 case 's':
6184                         single_line = TRUE;
6185                         /* FALLTHRU */
6186                 case 'm':
6187                         multi_line = TRUE;
6188                         need_filebuf = TRUE;
6189                         break;
6190                 default:
6191                 {
6192                         char wrongmod [2];
6193                         wrongmod[0] = modifiers[0];
6194                         wrongmod[1] = '\0';
6195                         error ("invalid regexp modifier `%s', ignoring", wrongmod);
6196                 }
6197                 break;
6198                 }
6199
6200         patbuf = xnew (1, struct re_pattern_buffer);
6201         *patbuf = zeropattern;
6202         if (ignore_case)
6203         {
6204                 static char lc_trans[CHARS];
6205                 int i;
6206                 for (i = 0; i < CHARS; i++)
6207                         lc_trans[i] = lowcase (i);
6208                 patbuf->translate = lc_trans;   /* translation table to fold case  */
6209         }
6210
6211         if (multi_line)
6212                 pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
6213         else
6214                 pat = regexp_pattern;
6215
6216         if (single_line)
6217                 re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
6218         else
6219                 re_set_syntax (RE_SYNTAX_EMACS);
6220
6221         err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
6222         if (multi_line)
6223                 free (pat);
6224         if (err != NULL)
6225         {
6226                 error ("%s while compiling pattern", err);
6227                 return;
6228         }
6229
6230         rp = p_head;
6231         p_head = xnew (1, regexp);
6232         p_head->pattern = savestr (regexp_pattern);
6233         p_head->p_next = rp;
6234         p_head->lang = lang;
6235         p_head->pat = patbuf;
6236         p_head->name = savestr (name);
6237         p_head->error_signaled = FALSE;
6238         p_head->force_explicit_name = force_explicit_name;
6239         p_head->ignore_case = ignore_case;
6240         p_head->multi_line = multi_line;
6241 }
6242
6243 /*
6244  * Do the substitutions indicated by the regular expression and
6245  * arguments.
6246  */
6247 static char *
6248 substitute (in, out, regs)
6249 char *in, *out;
6250 struct re_registers *regs;
6251 {
6252         char *result, *t;
6253         int size, dig, diglen;
6254
6255         result = NULL;
6256         size = strlen (out);
6257
6258         /* Pass 1: figure out how much to allocate by finding all \N strings. */
6259         if (out[size - 1] == '\\')
6260                 fatal ("pattern error in \"%s\"", out);
6261         for (t = etags_strchr (out, '\\');
6262              t != NULL;
6263              t = etags_strchr (t + 2, '\\'))
6264                 if (ISDIGIT (t[1]))
6265                 {
6266                         dig = t[1] - '0';
6267                         diglen = regs->end[dig] - regs->start[dig];
6268                         size += diglen - 2;
6269                 }
6270                 else
6271                         size -= 1;
6272
6273         /* Allocate space and do the substitutions. */
6274         assert (size >= 0);
6275         size_t avail = size + 1;
6276         result = xnew (avail, char);
6277
6278         for (t = result; *out != '\0'; out++)
6279                 if (*out == '\\' && ISDIGIT (*++out))
6280                 {
6281                         dig = *out - '0';
6282                         diglen = regs->end[dig] - regs->start[dig];
6283                         xstrncpy (t, in + regs->start[dig], avail);
6284                         t += diglen;
6285                         avail -= diglen;
6286                 }
6287                 else {
6288                         *t++ = *out;
6289                         avail --;
6290                 }
6291         *t = '\0';
6292
6293         assert (t <= result + size);
6294         assert (t - result == (int)strlen (result));
6295
6296         return result;
6297 }
6298
6299 /* Deallocate all regexps. */
6300 static void
6301 free_regexps ()
6302 {
6303         regexp *rp;
6304         while (p_head != NULL)
6305         {
6306                 rp = p_head->p_next;
6307                 free (p_head->pattern);
6308                 free (p_head->name);
6309                 free (p_head);
6310                 p_head = rp;
6311         }
6312         return;
6313 }
6314
6315 /*
6316  * Reads the whole file as a single string from `filebuf' and looks for
6317  * multi-line regular expressions, creating tags on matches.
6318  * readline already dealt with normal regexps.
6319  *
6320  * Idea by Ben Wing <ben@666.com> (2002).
6321  */
6322 static void
6323 regex_tag_multiline ()
6324 {
6325         char *buffer = filebuf.buffer;
6326         regexp *rp;
6327         char *name = NULL;
6328
6329         for (rp = p_head; rp != NULL; rp = rp->p_next)
6330         {
6331                 int match = 0;
6332
6333                 if (!rp->multi_line)
6334                         continue;               /* skip normal regexps */
6335
6336                 /* Generic initialisations before parsing file from memory. */
6337                 lineno = 1;             /* reset global line number */
6338                 charno = 0;             /* reset global char number */
6339                 linecharno = 0;         /* reset global char number of line start */
6340
6341                 /* Only use generic regexps or those for the current language. */
6342                 if (rp->lang != NULL && rp->lang != curfdp->lang)
6343                         continue;
6344
6345                 while (match >= 0 && match < filebuf.len)
6346                 {
6347                         match = re_search (rp->pat, buffer, filebuf.len, charno,
6348                                            filebuf.len - match, &rp->regs);
6349                         switch (match)
6350                         {
6351                         case -2:
6352                                 /* Some error. */
6353                                 if (!rp->error_signaled)
6354                                 {
6355                                         error ("regexp stack overflow while matching \"%s\"",
6356                                                rp->pattern);
6357                                         rp->error_signaled = TRUE;
6358                                 }
6359                                 break;
6360                         case -1:
6361                                 /* No match. */
6362                                 break;
6363                         default:
6364                                 if (match == rp->regs.end[0])
6365                                 {
6366                                         if (!rp->error_signaled)
6367                                         {
6368                                                 error ("regexp matches the empty string: \"%s\"",
6369                                                        rp->pattern);
6370                                                 rp->error_signaled = TRUE;
6371                                         }
6372                                         match = -3;     /* exit from while loop */
6373                                         break;
6374                                 }
6375
6376                                 /* Match occurred.  Construct a tag. */
6377                                 while (charno < rp->regs.end[0])
6378                                         if (buffer[charno++] == '\n')
6379                                                 lineno++, linecharno = charno;
6380                                 if (! rp->name || rp->name[0] == '\0')
6381                                         name = NULL;
6382                                 else /* make a named tag */
6383                                         name = substitute (buffer, rp->name, &rp->regs);
6384                                 if (rp->force_explicit_name)
6385                                         /* Force explicit tag name, if a name
6386                                            is there. */
6387                                         pfnote (name, TRUE, buffer + linecharno,
6388                                                 charno - linecharno + 1, lineno,
6389                                                 linecharno);
6390                                 else if(name == NULL)
6391                                         abort();
6392                                 else
6393                                         make_tag (name, strlen (name), TRUE,
6394                                                   buffer + linecharno,
6395                                                   charno - linecharno + 1,
6396                                                   lineno, linecharno);
6397                                 free(name);
6398                                 name = NULL;
6399                                 break;
6400                         }
6401                 }
6402         }
6403 }
6404
6405 \f
6406 static bool
6407 nocase_tail (cp)
6408 char *cp;
6409 {
6410         register int len = 0;
6411
6412         while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
6413                 cp++, len++;
6414         if (*cp == '\0' && !intoken (dbp[len]))
6415         {
6416                 dbp += len;
6417                 return TRUE;
6418         }
6419         return FALSE;
6420 }
6421
6422 static void
6423 get_tag (bp, namepp)
6424 register char *bp;
6425 char **namepp;
6426 {
6427         register char *cp = bp;
6428
6429         if (*bp != '\0')
6430         {
6431                 /* Go till you get to white space or a syntactic break */
6432                 for (cp = bp + 1; !notinname (*cp); cp++)
6433                         continue;
6434                 make_tag (bp, cp - bp, TRUE,
6435                           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
6436         }
6437
6438         if (namepp != NULL)
6439                 *namepp = savenstr (bp, cp - bp);
6440 }
6441
6442 /*
6443  * Read a line of text from `stream' into `lbp', excluding the
6444  * newline or CR-NL, if any.  Return the number of characters read from
6445  * `stream', which is the length of the line including the newline.
6446  *
6447  * On DOS or Windows we do not count the CR character, if any before the
6448  * NL, in the returned length; this mirrors the behavior of Emacs on those
6449  * platforms (for text files, it translates CR-NL to NL as it reads in the
6450  * file).
6451  *
6452  * If multi-line regular expressions are requested, each line read is
6453  * appended to `filebuf'.
6454  */
6455 static long
6456 readline_internal (lbp, stream)
6457 linebuffer *lbp;
6458 register FILE *stream;
6459 {
6460         char *buffer = lbp->buffer;
6461         register char *p = lbp->buffer;
6462         register char *pend;
6463         int chars_deleted;
6464
6465         pend = p + lbp->size;           /* Separate to avoid 386/IX compiler bug.  */
6466
6467         for (;;)
6468         {
6469                 register int c = getc (stream);
6470                 if (p == pend)
6471                 {
6472                         /* We're at the end of linebuffer: expand it. */
6473                         lbp->size *= 2;
6474                         xrnew (buffer, lbp->size, char);
6475                         p += buffer - lbp->buffer;
6476                         pend = buffer + lbp->size;
6477                         lbp->buffer = buffer;
6478                 }
6479                 if (c == EOF)
6480                 {
6481                         *p = '\0';
6482                         chars_deleted = 0;
6483                         break;
6484                 }
6485                 if (c == '\n')
6486                 {
6487                         if (p > buffer && p[-1] == '\r')
6488                         {
6489                                 p -= 1;
6490                                 chars_deleted = 2;
6491                         }
6492                         else
6493                         {
6494                                 chars_deleted = 1;
6495                         }
6496                         *p = '\0';
6497                         break;
6498                 }
6499                 *p++ = c;
6500         }
6501         lbp->len = p - buffer;
6502
6503         if (need_filebuf                /* we need filebuf for multi-line regexps */
6504             && chars_deleted > 0)       /* not at EOF */
6505         {
6506                 size_t need = filebuf.len + lbp->len + 1; /* +1 for \n */
6507                 while (filebuf.size <= need ) 
6508                         filebuf.size *= 2;
6509                 /* Expand filebuf. */
6510                 xrnew (filebuf.buffer, filebuf.size, char);
6511                 xstrncpy (filebuf.buffer + filebuf.len, lbp->buffer, filebuf.size - filebuf.len);
6512                 filebuf.len += lbp->len;
6513                 filebuf.buffer[filebuf.len++] = '\n';
6514                 filebuf.buffer[filebuf.len] = '\0';
6515         }
6516
6517         return lbp->len + chars_deleted;
6518 }
6519
6520 /*
6521  * Like readline_internal, above, but in addition try to match the
6522  * input line against relevant regular expressions and manage #line
6523  * directives.
6524  */
6525 static void
6526 readline (lbp, stream)
6527 linebuffer *lbp;
6528 FILE *stream;
6529 {
6530         long result;
6531
6532         linecharno = charno;            /* update global char number of line start */
6533         result = readline_internal (lbp, stream); /* read line */
6534         lineno += 1;                    /* increment global line number */
6535         charno += result;               /* increment global char number */
6536
6537         /* Honour #line directives. */
6538         if (!no_line_directive)
6539         {
6540                 static bool discard_until_line_directive;
6541
6542                 /* Check whether this is a #line directive. */
6543                 if (result > 12 && strneq (lbp->buffer, "#line ", 6))
6544                 {
6545                         unsigned int lno;
6546                         int start = 0;
6547
6548                         if (sscanf (lbp->buffer, "#line %u \"%n", &lno, &start) >= 1
6549                             && start > 0)       /* double quote character found */
6550                         {
6551                                 char *endp = lbp->buffer + start;
6552
6553                                 while ((endp = etags_strchr (endp, '"')) != NULL
6554                                        && endp[-1] == '\\')
6555                                         endp++;
6556                                 if (endp != NULL)
6557                                         /* Ok, this is a real #line directive.  Let's deal with it. */
6558                                 {
6559                                         char *taggedabsname;    /* absolute name of original file */
6560                                         char *taggedfname;      /* name of original file as given */
6561                                         char *name;             /* temp var */
6562
6563                                         discard_until_line_directive = FALSE; /* found it */
6564                                         name = lbp->buffer + start;
6565                                         *endp = '\0';
6566                                         canonicalize_filename (name);
6567                                         taggedabsname = absolute_filename (name, tagfiledir);
6568                                         if (filename_is_absolute (name)
6569                                             || filename_is_absolute (curfdp->infname))
6570                                                 taggedfname = savestr (taggedabsname);
6571                                         else
6572                                                 taggedfname = relative_filename (taggedabsname,tagfiledir);
6573
6574                                         if (streq (curfdp->taggedfname, taggedfname))
6575                                                 /* The #line directive is only a line number change.  We
6576                                                    deal with this afterwards. */
6577                                                 free (taggedfname);
6578                                         else
6579                                                 /* The tags following this #line directive should be
6580                                                    attributed to taggedfname.  In order to do this, set
6581                                                    curfdp accordingly. */
6582                                         {
6583                                                 fdesc *fdp; /* file description pointer */
6584
6585                                                 /* Go look for a file description already set up for the
6586                                                    file indicated in the #line directive.  If there is
6587                                                    one, use it from now until the next #line
6588                                                    directive. */
6589                                                 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6590                                                         if (streq (fdp->infname, curfdp->infname)
6591                                                             && streq (fdp->taggedfname, taggedfname))
6592                                                                 /* If we remove the second test above (after the &&)
6593                                                                    then all entries pertaining to the same file are
6594                                                                    coalesced in the tags file.  If we use it, then
6595                                                                    entries pertaining to the same file but generated
6596                                                                    from different files (via #line directives) will
6597                                                                    go into separate sections in the tags file.  These
6598                                                                    alternatives look equivalent.  The first one
6599                                                                    destroys some apparently useless information. */
6600                                                         {
6601                                                                 curfdp = fdp;
6602                                                                 free (taggedfname);
6603                                                                 break;
6604                                                         }
6605                                                 /* Else, if we already tagged the real file, skip all
6606                                                    input lines until the next #line directive. */
6607                                                 if (fdp == NULL) /* not found */
6608                                                         for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6609                                                                 if (streq (fdp->infabsname, taggedabsname))
6610                                                                 {
6611                                                                         discard_until_line_directive = TRUE;
6612                                                                         free (taggedfname);
6613                                                                         break;
6614                                                                 }
6615                                                 /* Else create a new file description and use that from
6616                                                    now on, until the next #line directive. */
6617                                                 if (fdp == NULL) /* not found */
6618                                                 {
6619                                                         fdp = fdhead;
6620                                                         fdhead = xnew (1, fdesc);
6621                                                         *fdhead = *curfdp; /* copy curr. file description */
6622                                                         fdhead->next = fdp;
6623                                                         fdhead->infname = savestr (curfdp->infname);
6624                                                         fdhead->infabsname = savestr (curfdp->infabsname);
6625                                                         fdhead->infabsdir = savestr (curfdp->infabsdir);
6626                                                         fdhead->taggedfname = taggedfname;
6627                                                         fdhead->usecharno = FALSE;
6628                                                         fdhead->prop = NULL;
6629                                                         fdhead->written = FALSE;
6630                                                         curfdp = fdhead;
6631                                                 }
6632                                         }
6633                                         free (taggedabsname);
6634                                         lineno = lno - 1;
6635                                         readline (lbp, stream);
6636                                         return;
6637                                 } /* if a real #line directive */
6638                         } /* if #line is followed by a a number */
6639                 } /* if line begins with "#line " */
6640
6641                 /* If we are here, no #line directive was found. */
6642                 if (discard_until_line_directive)
6643                 {
6644                         if (result > 0)
6645                         {
6646                                 /* Do a tail recursion on ourselves, thus discarding the contents
6647                                    of the line buffer. */
6648                                 readline (lbp, stream);
6649                                 return;
6650                         }
6651                         /* End of file. */
6652                         discard_until_line_directive = FALSE;
6653                         return;
6654                 }
6655         } /* if #line directives should be considered */
6656
6657         {
6658                 int match;
6659                 regexp *rp;
6660                 char *name = NULL;
6661
6662                 /* Match against relevant regexps. */
6663                 if (lbp->len > 0)
6664                         for (rp = p_head; rp != NULL; rp = rp->p_next)
6665                         {
6666                                 /* Only use generic regexps or those for the current language.
6667                                    Also do not use multiline regexps, which is the job of
6668                                    regex_tag_multiline. */
6669                                 if ((rp->lang != NULL && rp->lang != fdhead->lang)
6670                                     || rp->multi_line)
6671                                         continue;
6672
6673                                 match = re_match (rp->pat, lbp->buffer, lbp->len, 0, &rp->regs);
6674                                 switch (match)
6675                                 {
6676                                 case -2:
6677                                         /* Some error. */
6678                                         if (!rp->error_signaled)
6679                                         {
6680                                                 error ("regexp stack overflow while matching \"%s\"",
6681                                                        rp->pattern);
6682                                                 rp->error_signaled = TRUE;
6683                                         }
6684                                         break;
6685                                 case -1:
6686                                         /* No match. */
6687                                         break;
6688                                 case 0:
6689                                         /* Empty string matched. */
6690                                         if (!rp->error_signaled)
6691                                         {
6692                                                 error ("regexp matches the empty string: \"%s\"", rp->pattern);
6693                                                 rp->error_signaled = TRUE;
6694                                         }
6695                                         break;
6696                                 default:
6697                                         /* Match occurred.  Construct a tag. */
6698                                         if (rp->name[0] != '\0')
6699                                                 /* make a named tag */
6700                                                 name = substitute (lbp->buffer, rp->name, &rp->regs);
6701                                         if (rp->force_explicit_name)
6702                                                 /* Force explicit tag name, if a name is there. */
6703                                                 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
6704                                         else if (name) {
6705                                                 make_tag (name, strlen (name), TRUE,
6706                                                           lbp->buffer, match, lineno, linecharno);
6707                                                 free(name);
6708                                                 name = NULL;
6709                                         } else
6710                                                 make_tag (rp->name, strlen (rp->name), TRUE,
6711                                                           lbp->buffer, match, lineno, linecharno);
6712                                         break;
6713                                 }
6714                         }
6715         }
6716 }
6717
6718 \f
6719 /*
6720  * Return a pointer to a space of size strlen(cp)+1 allocated
6721  * with xnew where the string CP has been copied.
6722  */
6723 static char *
6724 savestr (cp)
6725 char *cp;
6726 {
6727         return savenstr (cp, strlen (cp));
6728 }
6729
6730 /*
6731  * Return a pointer to a space of size LEN+1 allocated with xnew where
6732  * the string CP has been copied for at most the first LEN characters.
6733  */
6734 static char *
6735 savenstr (cp, len)
6736 char *cp;
6737 int len;
6738 {
6739         register char *dp;
6740
6741         dp = xnew (len + 1, char);
6742         xstrncpy (dp, cp, len+1);
6743         dp[len] = '\0';
6744         return dp;
6745 }
6746
6747
6748 /* Skip spaces (end of string is not space), return new pointer. */
6749 static char *
6750 skip_spaces (cp)
6751 char *cp;
6752 {
6753         while (iswhite (*cp))
6754                 cp++;
6755         return cp;
6756 }
6757
6758 /* Skip non spaces, except end of string, return new pointer. */
6759 static char *
6760 skip_non_spaces (cp)
6761 char *cp;
6762 {
6763         while (*cp != '\0' && !iswhite (*cp))
6764                 cp++;
6765         return cp;
6766 }
6767
6768 /* Print error message and exit.  */
6769 void
6770 fatal (s1, s2)
6771 char *s1, *s2;
6772 {
6773         error (s1, s2);
6774         exit (EXIT_FAILURE);
6775 }
6776
6777 static void
6778 pfatal (s1)
6779 char *s1;
6780 {
6781         perror (s1);
6782         exit (EXIT_FAILURE);
6783 }
6784
6785 static void
6786 suggest_asking_for_help ()
6787 {
6788         fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
6789                  progname, NO_LONG_OPTIONS ? "-h" : "--help");
6790         exit (EXIT_FAILURE);
6791 }
6792
6793 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
6794 static void
6795 error (s1, s2)
6796 const char *s1, *s2;
6797 {
6798         fprintf (stderr, "%s: ", progname);
6799         fprintf (stderr, s1, s2);
6800         fprintf (stderr, "\n");
6801 }
6802
6803 /* Return a newly-allocated string whose contents
6804    concatenate those of s1, s2, s3.  */
6805 static char *
6806 concat (s1, s2, s3)
6807 char *s1, *s2, *s3;
6808 {
6809         int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
6810         char *result = xnew (len1 + len2 + len3 + 1, char);
6811
6812         xstrncpy(result, s1, len1+1);
6813         xstrncpy(result + len1, s2, len2+1);
6814         xstrncpy(result + len1 + len2, s3, len3+1);
6815         result[len1 + len2 + len3] = '\0';
6816
6817         return result;
6818 }
6819
6820 \f
6821 /* Does the same work as the system V getcwd, but does not need to
6822    guess the buffer size in advance. */
6823 static char *
6824 etags_getcwd ()
6825 {
6826 #ifdef HAVE_GETCWD
6827         int bufsize = 200;
6828         char *path = xnew (bufsize, char);
6829
6830         while (getcwd (path, bufsize) == NULL)
6831         {
6832                 if (errno != ERANGE)
6833                         pfatal ("getcwd");
6834                 bufsize *= 2;
6835                 free (path);
6836                 path = xnew (bufsize, char);
6837         }
6838
6839         canonicalize_filename (path);
6840         return path;
6841
6842 #else /* not HAVE_GETCWD */
6843         linebuffer path;
6844         FILE *pipe;
6845
6846         linebuffer_init (&path);
6847         pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
6848         if (pipe == NULL || readline_internal (&path, pipe) == 0)
6849                 pfatal ("pwd");
6850         pclose (pipe);
6851
6852         return path.buffer;
6853 #endif /* not HAVE_GETCWD */
6854 }
6855
6856 /* Return a newly allocated string containing the file name of FILE
6857    relative to the absolute directory DIR (which should end with a slash). */
6858 static char *
6859 relative_filename (file, dir)
6860 char *file, *dir;
6861 {
6862         char *fp, *dp, *afn, *res;
6863         int i;
6864         ssize_t res_left;
6865
6866         /* Find the common root of file and dir (with a trailing slash). */
6867         afn = absolute_filename (file, cwd);
6868         fp = afn;
6869         dp = dir;
6870         while (*fp++ == *dp++)
6871                 continue;
6872         fp--, dp--;                     /* back to the first differing char */
6873         do                              /* look at the equal chars until '/' */
6874                 fp--, dp--;
6875         while (*fp != '/');
6876         fp ++; /* Advance past the '/' */
6877
6878         /* Build a sequence of "../" strings for the resulting relative file name. */
6879         i = 0;
6880         while ((dp = etags_strchr (dp + 1, '/')) != NULL)
6881                 i += 1;
6882         res_left = 3 * i + strlen(fp);
6883         res = xnew( res_left + 1, char);
6884         res[0] = '\0';
6885         for ( ; i-- > 0 ; res_left -= 3 )
6886                 strncat(res, "../", res_left );
6887
6888         /* Add the file name relative to the common root of file and dir. */
6889         strncat(res, fp, res_left);
6890         free(afn);
6891
6892         return res;
6893 }
6894
6895 /* Return a newly allocated string containing the absolute file name
6896    of FILE given DIR (which should end with a slash). */
6897 static char *
6898 absolute_filename (file, dir)
6899 char *file, *dir;
6900 {
6901         char *slashp, *cp, *res;
6902
6903         if (filename_is_absolute (file))
6904                 res = savestr (file);
6905         else
6906                 res = concat (dir, file, "");
6907
6908         /* Delete the "/dirname/.." and "/." substrings. */
6909         slashp = etags_strchr (res, '/');
6910         while (slashp != NULL && slashp[0] != '\0')
6911         {
6912                 if (slashp[1] == '.')
6913                 {
6914                         if (slashp[2] == '.'
6915                             && (slashp[3] == '/' || slashp[3] == '\0'))
6916                         {
6917                                 cp = slashp;
6918                                 do
6919                                         cp--;
6920                                 while (cp >= res && !filename_is_absolute (cp));
6921                                 if (cp < res)
6922                                         cp = slashp;    /* the absolute name begins with "/.." */
6923                                 slashp += 3;
6924                                 memmove(cp, slashp,strlen(slashp)+1);
6925                                 slashp = cp;
6926                                 continue;
6927                         }
6928                         else if (slashp[2] == '/' || slashp[2] == '\0')
6929                         {
6930                                 strcpy (slashp, slashp + 2);
6931                                 continue;
6932                         }
6933                 }
6934
6935                 slashp = etags_strchr (slashp + 1, '/');
6936         }
6937
6938         if (res[0] == '\0')             /* just a safety net: should never happen */
6939         {
6940                 free (res);
6941                 return savestr ("/");
6942         }
6943         else
6944                 return res;
6945 }
6946
6947 /* Return a newly allocated string containing the absolute
6948    file name of dir where FILE resides given DIR (which should
6949    end with a slash). */
6950 static char *
6951 absolute_dirname (file, dir)
6952 char *file, *dir;
6953 {
6954         char *slashp, *res;
6955         char save;
6956
6957         slashp = etags_strrchr (file, '/');
6958         if (slashp == NULL)
6959                 return savestr (dir);
6960         save = slashp[1];
6961         slashp[1] = '\0';
6962         res = absolute_filename (file, dir);
6963         slashp[1] = save;
6964
6965         return res;
6966 }
6967
6968 /* Whether the argument string is an absolute file name.  The argument
6969    string must have been canonicalized with canonicalize_filename. */
6970 static bool
6971 filename_is_absolute (fn)
6972 char *fn;
6973 {
6974         return (fn[0] == '/');
6975 }
6976
6977 /* Upcase DOS drive letter and collapse separators into single slashes.
6978    Works in place. */
6979 static void
6980 canonicalize_filename (fn)
6981 register char *fn;
6982 {
6983         register char* cp;
6984         char sep = '/';
6985
6986         /* Collapse multiple separators into a single slash. */
6987         for (cp = fn; *cp != '\0'; cp++, fn++)
6988                 if (*cp == sep)
6989                 {
6990                         *fn = '/';
6991                         while (cp[1] == sep)
6992                                 cp++;
6993                 }
6994                 else
6995                         *fn = *cp;
6996         *fn = '\0';
6997 }
6998
6999 \f
7000 /* Initialize a linebuffer for use. */
7001 static void
7002 linebuffer_init (lbp)
7003 linebuffer *lbp;
7004 {
7005         lbp->size = (DEBUG) ? 3 : 200;
7006         lbp->buffer = xnew (lbp->size, char);
7007         lbp->buffer[0] = '\0';
7008         lbp->len = 0;
7009 }
7010
7011 /* Set the minimum size of a string contained in a linebuffer. */
7012 static void
7013 linebuffer_setlen (lbp, toksize)
7014 linebuffer *lbp;
7015 int toksize;
7016 {
7017         while (lbp->size <= toksize)
7018                 lbp->size *= 2;
7019         xrnew (lbp->buffer, lbp->size, char);
7020         lbp->len = toksize;
7021 }
7022
7023 /* Like malloc but get fatal error if memory is exhausted. */
7024 static PTR
7025 xmalloc (size)
7026 unsigned int size;
7027 {
7028         PTR result = (PTR) malloc (size);
7029         if (result == NULL)
7030                 fatal ("virtual memory exhausted", (char *)NULL);
7031         return result;
7032 }
7033
7034 static PTR
7035 xrealloc (ptr, size)
7036 char *ptr;
7037 unsigned int size;
7038 {
7039         PTR result = (PTR) realloc (ptr, size);
7040         if (result == NULL)
7041                 fatal ("virtual memory exhausted", (char *)NULL);
7042         return result;
7043 }
7044
7045 /*
7046  * Local Variables:
7047  * indent-tabs-mode: t
7048  * tab-width: 8
7049  * fill-column: 79
7050  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
7051  * End:
7052  */
7053
7054 /* etags.c ends here */