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