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