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