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