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