(pfnote, new_pfnote, C_entries, prolog_pred, erlang_func): Add
[bpt/emacs.git] / lib-src / etags.c
CommitLineData
c6d46f5f 1/* Tags file maker to go with GNU Emacs
4ee9629e 2 Copyright (C) 1984, 87, 88, 89, 93, 94, 95, 98, 99
f470f9bd 3 Free Software Foundation, Inc. and Ken Arnold
3b7ad313 4
ea6cd314 5This file is not considered part of GNU Emacs.
c6d46f5f 6
ea6cd314 7This program is free software; you can redistribute it and/or modify
c6d46f5f 8it under the terms of the GNU General Public License as published by
ea6cd314
RS
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
c6d46f5f 11
ea6cd314 12This program is distributed in the hope that it will be useful,
c6d46f5f
JB
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
3b7ad313
EN
18along with this program; if not, write to the Free Software Foundation,
19Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
c6d46f5f
JB
20
21/*
22 * Authors:
23 * Ctags originally by Ken Arnold.
6dd5561c 24 * Fortran added by Jim Kleckner.
c6d46f5f
JB
25 * Ed Pelegri-Llopart added C typedefs.
26 * Gnu Emacs TAGS format and modifications by RMS?
27 * Sam Kendall added C++.
b9755a12 28 * Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
b9755a12 29 * Regexp tags by Tom Tromey.
31d4b314 30 *
ba65dba8 31 * Francesco Potorti` (pot@gnu.org) is the current maintainer.
c6d46f5f
JB
32 */
33
944bdd72 34char pot_etags_version[] = "@(#) pot revision number is 13.38";
75bdbc6a
FP
35
36#define TRUE 1
37#define FALSE 0
d8913c1c 38
75bdbc6a
FP
39#ifndef DEBUG
40# define DEBUG FALSE
41#endif
46c145db 42
944bdd72
FP
43#if defined (__STDC__) && __STDC__
44# define P_(proto) proto
45#else
46# define P_(proto) ()
47#endif
48
4ee9629e
PE
49#ifdef HAVE_CONFIG_H
50# include <config.h>
51 /* On some systems, Emacs defines static as nothing for the sake
52 of unexec. We don't want that here since we don't use unexec. */
53# undef static
93b7ac65
FP
54# define ETAGS_REGEXPS /* use the regexp features */
55# define LONG_OPTIONS /* accept long options */
56#endif /* HAVE_CONFIG_H */
4ee9629e 57
944bdd72
FP
58#ifndef _GNU_SOURCE
59# define _GNU_SOURCE 1 /* enables some compiler checks on GNU */
60#endif
61
c6880c90 62#ifdef MSDOS
944bdd72 63# define MSDOS TRUE
8dc7496c
FP
64# include <fcntl.h>
65# include <sys/param.h>
93b7ac65
FP
66# include <io.h>
67# ifndef HAVE_CONFIG_H
68# define DOS_NT
69# include <sys/config.h>
70# endif
944bdd72
FP
71#else
72# define MSDOS FALSE
c6880c90
RS
73#endif /* MSDOS */
74
c05b6df5 75#ifdef WINDOWSNT
8dc7496c
FP
76# include <stdlib.h>
77# include <fcntl.h>
78# include <string.h>
944bdd72 79# include <direct.h>
a65c6351 80# include <io.h>
8dc7496c 81# define MAXPATHLEN _MAX_PATH
93b7ac65
FP
82# ifdef HAVE_CONFIG_H
83# undef HAVE_NTGUI
84# else
85# define DOS_NT
86# endif /* not HAVE_CONFIG_H */
87# ifndef HAVE_GETCWD
88# define HAVE_GETCWD
89# endif /* undef HAVE_GETCWD */
944bdd72
FP
90#else /* !WINDOWSNT */
91# ifdef STDC_HEADERS
92# include <stdlib.h>
93# include <string.h>
94# else
95 extern char *getenv ();
96# endif
97#endif /* !WINDOWSNT */
cec68fcb 98
93b7ac65
FP
99#ifdef HAVE_UNISTD_H
100# include <unistd.h>
101#else
944bdd72 102# if defined (HAVE_GETCWD) && !WINDOWSNT
93b7ac65
FP
103 extern char *getcwd ();
104# endif
105#endif /* HAVE_UNISTD_H */
106
918f9ad1
JB
107#include <stdio.h>
108#include <ctype.h>
dcc89e63
FP
109#include <errno.h>
110#ifndef errno
93b7ac65 111 extern int errno;
dcc89e63 112#endif
918f9ad1
JB
113#include <sys/types.h>
114#include <sys/stat.h>
115
2b878b4c
FP
116#if !defined (S_ISREG) && defined (S_IFREG)
117# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
118#endif
119
30903246
FP
120#ifdef LONG_OPTIONS
121# include <getopt.h>
122#else
123# define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
124 extern char *optarg;
125 extern int optind, opterr;
126#endif /* LONG_OPTIONS */
b9755a12
FP
127
128#ifdef ETAGS_REGEXPS
8dc7496c 129# include <regex.h>
b9755a12 130#endif /* ETAGS_REGEXPS */
918f9ad1 131
32daa216 132/* Define CTAGS to make the program "ctags" compatible with the usual one.
85e77a3f 133 Leave it undefined to make the program "etags", which makes emacs-style
32daa216
FP
134 tag tables and tags typedefs, #defines and struct/union/enum by default. */
135#ifdef CTAGS
136# undef CTAGS
137# define CTAGS TRUE
138#else
139# define CTAGS FALSE
c6d46f5f
JB
140#endif
141
142/* Exit codes for success and failure. */
143#ifdef VMS
8dc7496c
FP
144# define GOOD 1
145# define BAD 0
c6d46f5f 146#else
8dc7496c
FP
147# define GOOD 0
148# define BAD 1
c6d46f5f
JB
149#endif
150
55597f90
FP
151/* C extensions. */
152#define C_PLPL 0x00001 /* C++ */
153#define C_STAR 0x00003 /* C* */
cec68fcb 154#define C_JAVA 0x00005 /* JAVA */
55597f90 155#define YACC 0x10000 /* yacc file */
c6d46f5f 156
370e3d9d
RS
157#define streq(s,t) ((DEBUG && (s) == NULL && (t) == NULL \
158 && (abort (), 1)) || !strcmp (s, t))
159#define strneq(s,t,n) ((DEBUG && (s) == NULL && (t) == NULL \
160 && (abort (), 1)) || !strncmp (s, t, n))
c6d46f5f 161
3f1c8fcd 162#define lowcase(c) tolower ((char)c)
79263656 163
30903246 164#define CHARS 256 /* 2^sizeof(char) */
93b7ac65 165#define CHAR(x) ((unsigned int)x & (CHARS - 1))
30903246
FP
166#define iswhite(c) (_wht[CHAR(c)]) /* c is white */
167#define notinname(c) (_nin[CHAR(c)]) /* c is not in a name */
168#define begtoken(c) (_btk[CHAR(c)]) /* c can start token */
169#define intoken(c) (_itk[CHAR(c)]) /* c can be in token */
170#define endtoken(c) (_etk[CHAR(c)]) /* c ends tokens */
c6d46f5f 171
b2db879b 172
55597f90 173/*
93b7ac65 174 * xnew, xrnew -- allocate, reallocate storage
55597f90
FP
175 *
176 * SYNOPSIS: Type *xnew (int n, Type);
93b7ac65 177 * Type *xrnew (OldPointer, int n, Type);
55597f90 178 */
2f608d34
FP
179#ifdef chkmalloc
180# include "chkmalloc.h"
93b7ac65
FP
181# define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
182 (n) * sizeof (Type)))
183# define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
184 (op), (n) * sizeof (Type)))
2f608d34 185#else
93b7ac65
FP
186# define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
187# define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
2f608d34 188#endif
c6d46f5f 189
30903246 190typedef int bool;
aab1fdae 191
93b7ac65 192typedef void Lang_function ();
c6d46f5f 193
93b7ac65
FP
194typedef struct
195{
196 char *suffix;
197 char *command; /* Takes one arg and decompresses to stdout */
198} compressor;
c6d46f5f 199
93b7ac65
FP
200typedef struct
201{
202 char *name;
203 Lang_function *function;
204 char **suffixes;
205 char **interpreters;
206} language;
207
944bdd72
FP
208typedef struct node_st
209{ /* sorting structure */
210 char *name; /* function or type name */
211 char *file; /* file name */
212 bool is_func; /* use pattern or line no */
213 bool been_warned; /* set if noticed dup */
214 int lno; /* line number tag is on */
215 long cno; /* character number line starts on */
216 char *pat; /* search pattern */
217 struct node_st *left, *right; /* left and right sons */
218} node;
219
220/*
221 * A `linebuffer' is a structure which holds a line of text.
222 * `readline_internal' reads a line from a stream into a linebuffer
223 * and works regardless of the length of the line.
224 * SIZE is the size of BUFFER, LEN is the length of the string in
225 * BUFFER after readline reads it.
226 */
227typedef struct
228{
229 long size;
230 int len;
231 char *buffer;
232} linebuffer;
b9755a12 233
30903246 234/* Many compilers barf on this:
93b7ac65 235 Lang_function Ada_funcs;
30903246 236 so let's write it this way */
944bdd72
FP
237static void Ada_funcs P_((FILE *inf));
238static void Asm_labels P_((FILE *inf));
239static void C_entries P_((int c_ext, FILE *inf));
240static void default_C_entries P_((FILE *inf));
241static void plain_C_entries P_((FILE *inf));
242static void Cjava_entries P_((FILE *inf));
243static void Cobol_paragraphs P_((FILE *inf));
244static void Cplusplus_entries P_((FILE *inf));
245static void Cstar_entries P_((FILE *inf));
246static void Erlang_functions P_((FILE *inf));
247static void Fortran_functions P_((FILE *inf));
248static void Yacc_entries P_((FILE *inf));
249static void Lisp_functions P_((FILE *inf));
250static void Pascal_functions P_((FILE *inf));
251static void Perl_functions P_((FILE *inf));
252static void Postscript_functions P_((FILE *inf));
253static void Prolog_functions P_((FILE *inf));
254static void Python_functions P_((FILE *inf));
255static void Scheme_functions P_((FILE *inf));
256static void TeX_functions P_((FILE *inf));
257static void just_read_file P_((FILE *inf));
258
259static compressor *get_compressor_from_suffix P_((char *file, char **extptr));
260static language *get_language_from_name P_((char *name));
261static language *get_language_from_interpreter P_((char *interpreter));
262static language *get_language_from_suffix P_((char *file));
263static int total_size_of_entries P_((register node *np));
264static long readline P_((linebuffer *lbp, FILE *stream));
265static long readline_internal P_((linebuffer *lbp, register FILE *stream));
266static void get_tag P_((register char *bp));
93b7ac65 267
b9755a12 268#ifdef ETAGS_REGEXPS
944bdd72
FP
269static void analyse_regex P_((char *regex_arg, bool ignore_case));
270static void add_regex P_((char *regexp_pattern, bool ignore_case, language *lan));
271static void free_patterns P_((void));
30903246 272#endif /* ETAGS_REGEXPS */
944bdd72
FP
273static void error P_((const char *s1, const char *s2));
274static void suggest_asking_for_help P_((void));
275static void fatal P_((char *s1, char *s2));
276static void pfatal P_((char *s1));
277static void add_node P_((node *np, node **cur_node_p));
278
279static void init P_((void));
280static void initbuffer P_((linebuffer *lbp));
281static void find_entries P_((char *file, FILE *inf));
282static void free_tree P_((register node *np));
283static void pfnote P_((char *name, bool is_func, char *linestart,
284 int linelen, int lno, long int cno));
285static void new_pfnote P_((char *name, int namelen, bool is_func,
286 char *linestart, int linelen, int lno, long int cno));
287static void process_file P_((char *file));
288static void put_entries P_((register node *np));
289static void takeprec P_((void));
290
291static char *concat P_((char *s1, char *s2, char *s3));
292static char *skip_spaces P_((char *cp));
293static char *skip_non_spaces P_((char *cp));
294static char *savenstr P_((char *cp, int len));
295static char *savestr P_((char *cp));
296static char *etags_strchr P_((const char *sp, int c));
297static char *etags_strrchr P_((const char *sp, int c));
298static char *etags_getcwd P_((void));
299static char *relative_filename P_((char *file, char *dir));
300static char *absolute_filename P_((char *file, char *dir));
301static char *absolute_dirname P_((char *file, char *dir));
302static bool filename_is_absolute P_((char *fn));
303static void canonicalize_filename P_((register char *fn));
304static void grow_linebuffer P_((linebuffer *lbp, int toksize));
305static long *xmalloc P_((unsigned int size));
306static long *xrealloc P_((char *ptr, unsigned int size));
93b7ac65 307
c6d46f5f 308\f
55597f90 309char searchar = '/'; /* use /.../ searches */
c6d46f5f 310
55597f90
FP
311char *tagfile; /* output file */
312char *progname; /* name this program was invoked with */
313char *cwd; /* current working directory */
314char *tagfiledir; /* directory of tagfile */
55597f90 315FILE *tagf; /* ioptr for tags file */
93b7ac65
FP
316
317char *curfile; /* current input file name */
318language *curlang; /* current language */
319
320int lineno; /* line number of current line */
321long charno; /* current character number */
322long linecharno; /* charno of start of current line */
323char *dbp; /* pointer to start of current tag */
324
93b7ac65 325node *head; /* the head of the binary tree of tags */
c6d46f5f 326
93b7ac65
FP
327linebuffer lb; /* the current line */
328linebuffer token_name; /* used by C_entries as a temporary area */
55597f90
FP
329struct
330{
331 long linepos;
93b7ac65 332 linebuffer lb; /* used by C_entries instead of lb */
55597f90 333} lbs[2];
c6d46f5f 334
55597f90 335/* boolean "functions" (see init) */
30903246 336bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
55597f90 337char
d8913c1c 338 /* white chars */
93b7ac65 339 *white = " \f\t\n\r",
30903246 340 /* not in a name */
93b7ac65 341 *nonam = " \f\t\n\r(=,[;",
d8913c1c 342 /* token ending chars */
93b7ac65 343 *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
d8913c1c
FP
344 /* token starting chars */
345 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
346 /* valid in-token chars */
30903246 347 *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
c6d46f5f 348
30903246
FP
349bool append_to_tagfile; /* -a: append to tags */
350/* The following four default to TRUE for etags, but to FALSE for ctags. */
93b7ac65 351bool typedefs; /* -t: create tags for C and Ada typedefs */
30903246 352bool typedefs_and_cplusplus; /* -T: create tags for C typedefs, level */
c6d46f5f 353 /* 0 struct/enum/union decls, and C++ */
32daa216 354 /* member functions. */
30903246
FP
355bool constantypedefs; /* -d: create tags for C #define, enum */
356 /* constants and variables. */
c6d46f5f 357 /* -D: opposite of -d. Default under ctags. */
93b7ac65
FP
358bool declarations; /* --declarations: tag them and extern in C&Co*/
359bool globals; /* create tags for global variables */
30903246
FP
360bool members; /* create tags for C member variables */
361bool update; /* -u: update tags */
362bool vgrind_style; /* -v: create vgrind style index output */
363bool no_warnings; /* -w: suppress warnings */
364bool cxref_style; /* -x: create cxref style output */
365bool cplusplus; /* .[hc] means C++, not C */
366bool noindentypedefs; /* -I: ignore indentation in C */
93b7ac65 367bool packages_only; /* --packages-only: in Ada, only tag packages*/
30903246
FP
368
369#ifdef LONG_OPTIONS
7537186d
FP
370struct option longopts[] =
371{
93b7ac65
FP
372 { "packages-only", no_argument, &packages_only, TRUE },
373 { "append", no_argument, NULL, 'a' },
374 { "backward-search", no_argument, NULL, 'B' },
375 { "c++", no_argument, NULL, 'C' },
376 { "cxref", no_argument, NULL, 'x' },
377 { "defines", no_argument, NULL, 'd' },
378 { "declarations", no_argument, &declarations, TRUE },
379 { "no-defines", no_argument, NULL, 'D' },
380 { "globals", no_argument, &globals, TRUE },
381 { "no-globals", no_argument, &globals, FALSE },
382 { "help", no_argument, NULL, 'h' },
383 { "help", no_argument, NULL, 'H' },
384 { "ignore-indentation", no_argument, NULL, 'I' },
385 { "include", required_argument, NULL, 'i' },
386 { "language", required_argument, NULL, 'l' },
387 { "members", no_argument, &members, TRUE },
388 { "no-members", no_argument, &members, FALSE },
389 { "no-warn", no_argument, NULL, 'w' },
390 { "output", required_argument, NULL, 'o' },
391#ifdef ETAGS_REGEXPS
392 { "regex", required_argument, NULL, 'r' },
393 { "no-regex", no_argument, NULL, 'R' },
394 { "ignore-case-regex", required_argument, NULL, 'c' },
395#endif /* ETAGS_REGEXPS */
396 { "typedefs", no_argument, NULL, 't' },
397 { "typedefs-and-c++", no_argument, NULL, 'T' },
398 { "update", no_argument, NULL, 'u' },
399 { "version", no_argument, NULL, 'V' },
400 { "vgrind", no_argument, NULL, 'v' },
401 { NULL }
4746118a 402};
30903246 403#endif /* LONG_OPTIONS */
4746118a 404
b9755a12 405#ifdef ETAGS_REGEXPS
c5007f46 406/* Structure defining a regular expression. Elements are
b9755a12 407 the compiled pattern, and the name string. */
93b7ac65 408typedef struct pattern
b9755a12 409{
93b7ac65
FP
410 struct pattern *p_next;
411 language *language;
412 char *regex;
b9755a12
FP
413 struct re_pattern_buffer *pattern;
414 struct re_registers regs;
415 char *name_pattern;
30903246 416 bool error_signaled;
93b7ac65 417} pattern;
b9755a12 418
93b7ac65
FP
419/* List of all regexps. */
420pattern *p_head = NULL;
b9755a12 421
93b7ac65
FP
422/* How many characters in the character set. (From regex.c.) */
423#define CHAR_SET_SIZE 256
424/* Translation table for case-insensitive matching. */
425char lc_trans[CHAR_SET_SIZE];
b9755a12
FP
426#endif /* ETAGS_REGEXPS */
427
93b7ac65
FP
428compressor compressors[] =
429{
430 { "z", "gzip -d -c"},
431 { "Z", "gzip -d -c"},
432 { "gz", "gzip -d -c"},
433 { "GZ", "gzip -d -c"},
434 { "bz2", "bzip2 -d -c" },
435 { NULL }
436};
437
1f638249
FP
438/*
439 * Language stuff.
440 */
b9755a12 441
1f638249 442/* Non-NULL if language fixed. */
93b7ac65
FP
443language *forced_lang = NULL;
444
445/* Ada code */
446char *Ada_suffixes [] =
447 { "ads", "adb", "ada", NULL };
1f638249
FP
448
449/* Assembly code */
450char *Asm_suffixes [] = { "a", /* Unix assembler */
451 "asm", /* Microcontroller assembly */
452 "def", /* BSO/Tasking definition includes */
453 "inc", /* Microcontroller include files */
454 "ins", /* Microcontroller include files */
455 "s", "sa", /* Unix assembler */
829a5736 456 "S", /* cpp-processed Unix assembler */
1f638249
FP
457 "src", /* BSO/Tasking C compiler output */
458 NULL
459 };
460
461/* Note that .c and .h can be considered C++, if the --c++ flag was
462 given. That is why default_C_entries is called here. */
463char *default_C_suffixes [] =
464 { "c", "h", NULL };
465
1f638249 466char *Cplusplus_suffixes [] =
cec68fcb
FP
467 { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
468 "M", /* Objective C++ */
469 "pdb", /* Postscript with C syntax */
470 NULL };
471
472char *Cjava_suffixes [] =
473 { "java", NULL };
1f638249 474
30903246
FP
475char *Cobol_suffixes [] =
476 { "COB", "cob", NULL };
477
1f638249
FP
478char *Cstar_suffixes [] =
479 { "cs", "hs", NULL };
480
8dc7496c
FP
481char *Erlang_suffixes [] =
482 { "erl", "hrl", NULL };
483
1f638249
FP
484char *Fortran_suffixes [] =
485 { "F", "f", "f90", "for", NULL };
486
1f638249
FP
487char *Lisp_suffixes [] =
488 { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
489
1f638249
FP
490char *Pascal_suffixes [] =
491 { "p", "pas", NULL };
492
1f638249
FP
493char *Perl_suffixes [] =
494 { "pl", "pm", NULL };
495char *Perl_interpreters [] =
d8913c1c 496 { "perl", "@PERL@", NULL };
1f638249 497
1f638249 498char *plain_C_suffixes [] =
d8913c1c
FP
499 { "pc", /* Pro*C file */
500 "m", /* Objective C file */
501 "lm", /* Objective lex file */
502 NULL };
1f638249 503
cec68fcb 504char *Postscript_suffixes [] =
93b7ac65 505 { "ps", "psw", NULL }; /* .psw is for PSWrap */
cec68fcb 506
1f638249
FP
507char *Prolog_suffixes [] =
508 { "prolog", NULL };
509
93b7ac65
FP
510char *Python_suffixes [] =
511 { "py", NULL };
512
d8913c1c 513/* Can't do the `SCM' or `scm' prefix with a version number. */
1f638249 514char *Scheme_suffixes [] =
93b7ac65 515 { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "ss", "t", NULL };
1f638249 516
1f638249 517char *TeX_suffixes [] =
d8913c1c 518 { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
1f638249 519
1f638249 520char *Yacc_suffixes [] =
829a5736 521 { "y", "ym", "yy", "yxx", "y++", NULL }; /* .ym is Objective yacc file */
1f638249 522
93b7ac65
FP
523/*
524 * Table of languages.
525 *
526 * It is ok for a given function to be listed under more than one
527 * name. I just didn't.
528 */
b9755a12 529
93b7ac65 530language lang_names [] =
b9755a12 531{
93b7ac65 532 { "ada", Ada_funcs, Ada_suffixes, NULL },
cec68fcb
FP
533 { "asm", Asm_labels, Asm_suffixes, NULL },
534 { "c", default_C_entries, default_C_suffixes, NULL },
535 { "c++", Cplusplus_entries, Cplusplus_suffixes, NULL },
536 { "c*", Cstar_entries, Cstar_suffixes, NULL },
30903246 537 { "cobol", Cobol_paragraphs, Cobol_suffixes, NULL },
cec68fcb
FP
538 { "erlang", Erlang_functions, Erlang_suffixes, NULL },
539 { "fortran", Fortran_functions, Fortran_suffixes, NULL },
b7e22e94 540 { "java", Cjava_entries, Cjava_suffixes, NULL },
cec68fcb
FP
541 { "lisp", Lisp_functions, Lisp_suffixes, NULL },
542 { "pascal", Pascal_functions, Pascal_suffixes, NULL },
543 { "perl", Perl_functions, Perl_suffixes, Perl_interpreters },
544 { "postscript", Postscript_functions, Postscript_suffixes, NULL },
545 { "proc", plain_C_entries, plain_C_suffixes, NULL },
546 { "prolog", Prolog_functions, Prolog_suffixes, NULL },
93b7ac65 547 { "python", Python_functions, Python_suffixes, NULL },
cec68fcb
FP
548 { "scheme", Scheme_functions, Scheme_suffixes, NULL },
549 { "tex", TeX_functions, TeX_suffixes, NULL },
550 { "yacc", Yacc_entries, Yacc_suffixes, NULL },
d8913c1c
FP
551 { "auto", NULL }, /* default guessing scheme */
552 { "none", just_read_file }, /* regexp matching only */
553 { NULL, NULL } /* end of list */
b9755a12 554};
c6d46f5f 555\f
944bdd72 556static void
b9755a12
FP
557print_language_names ()
558{
93b7ac65 559 language *lang;
1f638249 560 char **ext;
b9755a12
FP
561
562 puts ("\nThese are the currently supported languages, along with the\n\
79263656 563default file name suffixes:");
1f638249 564 for (lang = lang_names; lang->name != NULL; lang++)
b9755a12 565 {
1f638249
FP
566 printf ("\t%s\t", lang->name);
567 if (lang->suffixes != NULL)
568 for (ext = lang->suffixes; *ext != NULL; ext++)
569 printf (" .%s", *ext);
b9755a12
FP
570 puts ("");
571 }
79263656
FP
572 puts ("Where `auto' means use default language for files based on file\n\
573name suffix, and `none' means only do regexp processing on files.\n\
574If no language is specified and no matching suffix is found,\n\
1f638249
FP
575the first line of the file is read for a sharp-bang (#!) sequence\n\
576followed by the name of an interpreter. If no such sequence is found,\n\
93b7ac65
FP
577Fortran is tried first; if no tags are found, C is tried next.\n\
578Compressed files are supported using gzip and bzip2.");
b9755a12
FP
579}
580
944bdd72
FP
581#ifndef EMACS_NAME
582# define EMACS_NAME "GNU Emacs"
583#endif
c5007f46 584#ifndef VERSION
944bdd72 585# define VERSION "21"
c5007f46 586#endif
944bdd72 587static void
4746118a
JB
588print_version ()
589{
944bdd72 590 printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
4ee9629e 591 puts ("Copyright (C) 1999 Free Software Foundation, Inc. and Ken Arnold");
b6b48846 592 puts ("This program is distributed under the same terms as Emacs");
4746118a 593
1a0d8c80 594 exit (GOOD);
4746118a
JB
595}
596
944bdd72 597static void
4746118a
JB
598print_help ()
599{
30903246
FP
600 printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
601\n\
602These are the options accepted by %s.\n", progname, progname);
603#ifdef LONG_OPTIONS
604 puts ("You may use unambiguous abbreviations for the long option names.");
605#else
606 puts ("Long option names do not work with this executable, as it is not\n\
607linked with GNU getopt.");
608#endif /* LONG_OPTIONS */
93b7ac65 609 puts ("A - as file name means read names from stdin (one per line).");
8dc7496c 610 if (!CTAGS)
93b7ac65
FP
611 printf (" Absolute names are stored in the output file as they are.\n\
612Relative ones are stored relative to the output file's directory.");
8dc7496c 613 puts ("\n");
4746118a 614
52cc7c59
JB
615 puts ("-a, --append\n\
616 Append tag entries to existing tags file.");
1a0d8c80 617
93b7ac65
FP
618 puts ("--packages-only\n\
619 For Ada files, only generate tags for packages .");
620
32daa216
FP
621 if (CTAGS)
622 puts ("-B, --backward-search\n\
1a0d8c80 623 Write the search commands for the tag entries using '?', the\n\
3ad2882c 624 backward-search command instead of '/', the forward-search command.");
1a0d8c80 625
52cc7c59 626 puts ("-C, --c++\n\
79263656 627 Treat files whose name suffix defaults to C language as C++ files.");
4746118a 628
93b7ac65
FP
629 puts ("--declarations\n\
630 In C and derived languages, create tags for function declarations,");
631 if (CTAGS)
632 puts ("\tand create tags for extern variables if --globals is used.");
633 else
634 puts
635 ("\tand create tags for extern variables unless --no-globals is used.");
636
32daa216
FP
637 if (CTAGS)
638 puts ("-d, --defines\n\
3ca80e28 639 Create tag entries for C #define constants and enum constants, too.");
32daa216
FP
640 else
641 puts ("-D, --no-defines\n\
3ca80e28
FP
642 Don't create tag entries for C #define constants and enum constants.\n\
643 This makes the tags file smaller.");
4746118a 644
32daa216 645 if (!CTAGS)
b9755a12
FP
646 {
647 puts ("-i FILE, --include=FILE\n\
1a0d8c80
FP
648 Include a note in tag file indicating that, when searching for\n\
649 a tag, one should also consult the tags file FILE after\n\
650 checking the current file.");
b9755a12
FP
651 puts ("-l LANG, --language=LANG\n\
652 Force the following files to be considered as written in the\n\
653 named language up to the next --language=LANG option.");
7537186d
FP
654 }
655
30903246
FP
656 if (CTAGS)
657 puts ("--globals\n\
93b7ac65 658 Create tag entries for global variables in some languages.");
30903246
FP
659 else
660 puts ("--no-globals\n\
93b7ac65
FP
661 Do not create tag entries for global variables in some\n\
662 languages. This makes the tags file smaller.");
30903246
FP
663 puts ("--members\n\
664 Create tag entries for member variables in C and derived languages.");
665
b9755a12 666#ifdef ETAGS_REGEXPS
cec68fcb 667 puts ("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
93b7ac65
FP
668 Make a tag for each line matching pattern REGEXP in the following\n\
669 files. {LANGUAGE}/REGEXP/ uses REGEXP for LANGUAGE files only.\n\
670 regexfile is a file containing one REGEXP per line.\n\
671 REGEXP is anchored (as if preceded by ^).\n\
672 The form /REGEXP/NAME/ creates a named tag.\n\
673 For example Tcl named tags can be created with:\n\
b9755a12 674 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
93b7ac65
FP
675 puts ("-c /REGEXP/, --ignore-case-regex=/REGEXP/ or --ignore-case-regex=@regexfile\n\
676 Like -r, --regex but ignore case when matching expressions.");
7537186d 677 puts ("-R, --no-regex\n\
b9755a12
FP
678 Don't create tags from regexps for the following files.");
679#endif /* ETAGS_REGEXPS */
1a0d8c80
FP
680 puts ("-o FILE, --output=FILE\n\
681 Write the tags to FILE.");
201f9f2b 682 puts ("-I, --ignore-indentation\n\
4746118a
JB
683 Don't rely on indentation quite as much as normal. Currently,\n\
684 this means not to assume that a closing brace in the first\n\
685 column is the final brace of a function or structure\n\
32daa216 686 definition in C and C++.");
4746118a 687
32daa216
FP
688 if (CTAGS)
689 {
690 puts ("-t, --typedefs\n\
93b7ac65 691 Generate tag entries for C and Ada typedefs.");
32daa216
FP
692 puts ("-T, --typedefs-and-c++\n\
693 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
694 and C++ member functions.");
32daa216 695 puts ("-u, --update\n\
4746118a
JB
696 Update the tag entries for the given files, leaving tag\n\
697 entries for other files in place. Currently, this is\n\
698 implemented by deleting the existing entries for the given\n\
699 files and then rewriting the new entries at the end of the\n\
700 tags file. It is often faster to simply rebuild the entire\n\
52cc7c59 701 tag file than to use this.");
32daa216 702 puts ("-v, --vgrind\n\
4746118a
JB
703 Generates an index of items intended for human consumption,\n\
704 similar to the output of vgrind. The index is sorted, and\n\
52cc7c59 705 gives the page number of each item.");
b9755a12
FP
706 puts ("-w, --no-warn\n\
707 Suppress warning messages about entries defined in multiple\n\
708 files.");
32daa216 709 puts ("-x, --cxref\n\
4746118a
JB
710 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
711 The output uses line numbers instead of page numbers, but\n\
712 beyond that the differences are cosmetic; try both to see\n\
52cc7c59 713 which you like.");
32daa216 714 }
4746118a
JB
715
716 puts ("-V, --version\n\
717 Print the version of the program.\n\
7537186d 718-h, --help\n\
4746118a
JB
719 Print this help message.");
720
b9755a12
FP
721 print_language_names ();
722
b6b48846 723 puts ("");
a5c7ef8b 724 puts ("Report bugs to bug-gnu-emacs@gnu.org");
b6b48846 725
1a0d8c80 726 exit (GOOD);
4746118a
JB
727}
728
729\f
b9755a12
FP
730enum argument_type
731{
732 at_language,
733 at_regexp,
93b7ac65
FP
734 at_filename,
735 at_icregexp
b9755a12
FP
736};
737
2f608d34 738/* This structure helps us allow mixing of --lang and file names. */
b9755a12
FP
739typedef struct
740{
741 enum argument_type arg_type;
742 char *what;
93b7ac65 743 language *lang; /* language of the regexp */
1f638249 744} argument;
b9755a12
FP
745
746#ifdef VMS /* VMS specific functions */
747
748#define EOS '\0'
749
750/* This is a BUG! ANY arbitrary limit is a BUG!
751 Won't someone please fix this? */
752#define MAX_FILE_SPEC_LEN 255
753typedef struct {
754 short curlen;
755 char body[MAX_FILE_SPEC_LEN + 1];
756} vspec;
757
758/*
759 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
2f608d34 760 returning in each successive call the next file name matching the input
b9755a12
FP
761 spec. The function expects that each in_spec passed
762 to it will be processed to completion; in particular, up to and
763 including the call following that in which the last matching name
764 is returned, the function ignores the value of in_spec, and will
c5007f46 765 only start processing a new spec with the following call.
b9755a12
FP
766 If an error occurs, on return out_spec contains the value
767 of in_spec when the error occurred.
768
2f608d34 769 With each successive file name returned in out_spec, the
b9755a12
FP
770 function's return value is one. When there are no more matching
771 names the function returns zero. If on the first call no file
c5007f46 772 matches in_spec, or there is any other error, -1 is returned.
b9755a12
FP
773*/
774
775#include <rmsdef.h>
776#include <descrip.h>
777#define OUTSIZE MAX_FILE_SPEC_LEN
944bdd72 778static short
b9755a12
FP
779fn_exp (out, in)
780 vspec *out;
781 char *in;
782{
783 static long context = 0;
784 static struct dsc$descriptor_s o;
785 static struct dsc$descriptor_s i;
30903246 786 static bool pass1 = TRUE;
b9755a12
FP
787 long status;
788 short retval;
789
790 if (pass1)
791 {
792 pass1 = FALSE;
793 o.dsc$a_pointer = (char *) out;
794 o.dsc$w_length = (short)OUTSIZE;
795 i.dsc$a_pointer = in;
796 i.dsc$w_length = (short)strlen(in);
797 i.dsc$b_dtype = DSC$K_DTYPE_T;
798 i.dsc$b_class = DSC$K_CLASS_S;
799 o.dsc$b_dtype = DSC$K_DTYPE_VT;
800 o.dsc$b_class = DSC$K_CLASS_VS;
801 }
802 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
803 {
804 out->body[out->curlen] = EOS;
805 return 1;
806 }
807 else if (status == RMS$_NMF)
808 retval = 0;
809 else
810 {
811 strcpy(out->body, in);
812 retval = -1;
813 }
814 lib$find_file_end(&context);
815 pass1 = TRUE;
816 return retval;
c5007f46 817}
b9755a12
FP
818
819/*
c5007f46 820 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
b9755a12
FP
821 name of each file specified by the provided arg expanding wildcards.
822*/
944bdd72 823static char *
b9755a12
FP
824gfnames (arg, p_error)
825 char *arg;
30903246 826 bool *p_error;
b9755a12
FP
827{
828 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
829
830 switch (fn_exp (&filename, arg))
831 {
832 case 1:
833 *p_error = FALSE;
834 return filename.body;
835 case 0:
836 *p_error = FALSE;
837 return NULL;
838 default:
839 *p_error = TRUE;
840 return filename.body;
841 }
842}
843
844#ifndef OLD /* Newer versions of VMS do provide `system'. */
845system (cmd)
846 char *cmd;
847{
2f608d34 848 error ("%s", "system() function not implemented under VMS");
b9755a12
FP
849}
850#endif
851
852#define VERSION_DELIM ';'
853char *massage_name (s)
854 char *s;
855{
c5007f46 856 char *start = s;
b9755a12
FP
857
858 for ( ; *s; s++)
859 if (*s == VERSION_DELIM)
860 {
861 *s = EOS;
862 break;
863 }
864 else
c5007f46 865 *s = lowcase (*s);
b9755a12
FP
866 return start;
867}
868#endif /* VMS */
869
870\f
d0dff6e5 871int
c6d46f5f
JB
872main (argc, argv)
873 int argc;
874 char *argv[];
875{
c6d46f5f 876 int i;
2f608d34
FP
877 unsigned int nincluded_files;
878 char **included_files;
c6d46f5f 879 char *this_file;
1f638249 880 argument *argbuffer;
2f608d34 881 int current_arg, file_count;
93b7ac65 882 linebuffer filename_lb;
c6d46f5f 883#ifdef VMS
30903246 884 bool got_err;
c6d46f5f 885#endif
c5007f46 886
c05b6df5 887#ifdef DOS_NT
42680d3c 888 _fmode = O_BINARY; /* all of files are treated as binary files */
c05b6df5 889#endif /* DOS_NT */
c6880c90 890
c6d46f5f 891 progname = argv[0];
2f608d34
FP
892 nincluded_files = 0;
893 included_files = xnew (argc, char *);
894 current_arg = 0;
895 file_count = 0;
c6d46f5f 896
b9755a12
FP
897 /* Allocate enough no matter what happens. Overkill, but each one
898 is small. */
1f638249 899 argbuffer = xnew (argc, argument);
b9755a12
FP
900
901#ifdef ETAGS_REGEXPS
902 /* Set syntax for regular expression routines. */
93b7ac65
FP
903 re_set_syntax (RE_SYNTAX_EMACS | RE_INTERVALS);
904 /* Translation table for case-insensitive search. */
905 for (i = 0; i < CHAR_SET_SIZE; i++)
906 lc_trans[i] = lowcase (i);
b9755a12
FP
907#endif /* ETAGS_REGEXPS */
908
c6d46f5f
JB
909 /*
910 * If etags, always find typedefs and structure tags. Why not?
30903246 911 * Also default is to find macro constants, enum constants and
93b7ac65 912 * global variables.
c6d46f5f 913 */
32daa216 914 if (!CTAGS)
30903246
FP
915 {
916 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
917 globals = TRUE;
918 members = FALSE;
919 }
c6d46f5f 920
dcc89e63 921 while (1)
c6d46f5f 922 {
30903246
FP
923 int opt;
924 char *optstring;
925
926#ifdef ETAGS_REGEXPS
93b7ac65 927 optstring = "-aCdDf:Il:o:r:c:RStTi:BuvxwVhH";
30903246
FP
928#else
929 optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
930#endif /* ETAGS_REGEXPS */
931
932#ifndef LONG_OPTIONS
933 optstring = optstring + 1;
934#endif /* LONG_OPTIONS */
4746118a 935
30903246 936 opt = getopt_long (argc, argv, optstring, longopts, 0);
4746118a
JB
937 if (opt == EOF)
938 break;
939
940 switch (opt)
c6d46f5f 941 {
b02c5fea
FP
942 case 0:
943 /* If getopt returns 0, then it has already processed a
4746118a
JB
944 long-named option. We should do nothing. */
945 break;
946
b9755a12 947 case 1:
2f608d34 948 /* This means that a file name has been seen. Record it. */
b9755a12
FP
949 argbuffer[current_arg].arg_type = at_filename;
950 argbuffer[current_arg].what = optarg;
951 ++current_arg;
952 ++file_count;
953 break;
954
4746118a 955 /* Common options. */
30903246
FP
956 case 'a': append_to_tagfile = TRUE; break;
957 case 'C': cplusplus = TRUE; break;
958 case 'd': constantypedefs = TRUE; break;
959 case 'D': constantypedefs = FALSE; break;
32daa216 960 case 'f': /* for compatibility with old makefiles */
4746118a 961 case 'o':
6dd5561c 962 if (tagfile)
c6d46f5f 963 {
c8b04710 964 error ("-o option may only be given once.", (char *)NULL);
d8913c1c 965 suggest_asking_for_help ();
c6d46f5f 966 }
6dd5561c 967 tagfile = optarg;
4746118a 968 break;
201f9f2b
FP
969 case 'I':
970 case 'S': /* for backward compatibility */
971 noindentypedefs = TRUE;
972 break;
b9755a12 973 case 'l':
93b7ac65
FP
974 {
975 language *lang = get_language_from_name (optarg);
976 if (lang != NULL)
977 {
978 argbuffer[current_arg].lang = lang;
979 argbuffer[current_arg].arg_type = at_language;
980 ++current_arg;
981 }
982 }
b9755a12
FP
983 break;
984#ifdef ETAGS_REGEXPS
985 case 'r':
986 argbuffer[current_arg].arg_type = at_regexp;
987 argbuffer[current_arg].what = optarg;
988 ++current_arg;
989 break;
990 case 'R':
991 argbuffer[current_arg].arg_type = at_regexp;
992 argbuffer[current_arg].what = NULL;
993 ++current_arg;
994 break;
93b7ac65
FP
995 case 'c':
996 argbuffer[current_arg].arg_type = at_icregexp;
997 argbuffer[current_arg].what = optarg;
998 ++current_arg;
999 break;
b9755a12 1000#endif /* ETAGS_REGEXPS */
4746118a
JB
1001 case 'V':
1002 print_version ();
1003 break;
7537186d 1004 case 'h':
4746118a
JB
1005 case 'H':
1006 print_help ();
1007 break;
0c1fd2e3 1008 case 't':
55597f90 1009 typedefs = TRUE;
0c1fd2e3
FP
1010 break;
1011 case 'T':
55597f90 1012 typedefs = typedefs_and_cplusplus = TRUE;
0c1fd2e3 1013 break;
b02c5fea 1014#if (!CTAGS)
4746118a
JB
1015 /* Etags options */
1016 case 'i':
4746118a
JB
1017 included_files[nincluded_files++] = optarg;
1018 break;
b02c5fea 1019#else /* CTAGS */
4746118a 1020 /* Ctags options. */
30903246
FP
1021 case 'B': searchar = '?'; break;
1022 case 'u': update = TRUE; break;
1023 case 'v': vgrind_style = TRUE; /*FALLTHRU*/
1024 case 'x': cxref_style = TRUE; break;
1025 case 'w': no_warnings = TRUE; break;
b02c5fea 1026#endif /* CTAGS */
4746118a 1027 default:
d8913c1c 1028 suggest_asking_for_help ();
c6d46f5f 1029 }
c6d46f5f
JB
1030 }
1031
b9755a12
FP
1032 for (; optind < argc; ++optind)
1033 {
1034 argbuffer[current_arg].arg_type = at_filename;
1035 argbuffer[current_arg].what = argv[optind];
1036 ++current_arg;
1037 ++file_count;
1038 }
1039
1040 if (nincluded_files == 0 && file_count == 0)
c6d46f5f 1041 {
c8b04710 1042 error ("no input files specified.", (char *)NULL);
d8913c1c 1043 suggest_asking_for_help ();
c6d46f5f
JB
1044 }
1045
6dd5561c 1046 if (tagfile == NULL)
8dc7496c 1047 tagfile = CTAGS ? "tags" : "TAGS";
b02c5fea 1048 cwd = etags_getcwd (); /* the current working directory */
f55aa55a 1049 if (cwd[strlen (cwd) - 1] != '/')
cec68fcb
FP
1050 {
1051 char *oldcwd = cwd;
1052 cwd = concat (oldcwd, "/", "");
1053 free (oldcwd);
1054 }
6dd5561c 1055 if (streq (tagfile, "-"))
8dc7496c 1056 tagfiledir = cwd;
46c145db 1057 else
8dc7496c 1058 tagfiledir = absolute_dirname (tagfile, cwd);
c6d46f5f 1059
b9755a12 1060 init (); /* set up boolean "functions" */
c6d46f5f
JB
1061
1062 initbuffer (&lb);
75bdbc6a 1063 initbuffer (&token_name);
13fde0cd
RS
1064 initbuffer (&lbs[0].lb);
1065 initbuffer (&lbs[1].lb);
c6d46f5f 1066 initbuffer (&filename_lb);
b9755a12 1067
32daa216 1068 if (!CTAGS)
c6d46f5f 1069 {
6dd5561c 1070 if (streq (tagfile, "-"))
ce7f6d62
RS
1071 {
1072 tagf = stdout;
1073#ifdef DOS_NT
1074 /* Switch redirected `stdout' to binary mode (setting `_fmode'
cf347d3c 1075 doesn't take effect until after `stdout' is already open). */
ce7f6d62
RS
1076 if (!isatty (fileno (stdout)))
1077 setmode (fileno (stdout), O_BINARY);
1078#endif /* DOS_NT */
1079 }
c6d46f5f 1080 else
6dd5561c
FP
1081 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1082 if (tagf == NULL)
cdc1f6a7 1083 pfatal (tagfile);
c6d46f5f
JB
1084 }
1085
b9755a12
FP
1086 /*
1087 * Loop through files finding functions.
1088 */
1089 for (i = 0; i < current_arg; ++i)
c6d46f5f 1090 {
b9755a12 1091 switch (argbuffer[i].arg_type)
c6d46f5f 1092 {
b9755a12 1093 case at_language:
93b7ac65 1094 forced_lang = argbuffer[i].lang;
b9755a12
FP
1095 break;
1096#ifdef ETAGS_REGEXPS
1097 case at_regexp:
93b7ac65
FP
1098 analyse_regex (argbuffer[i].what, FALSE);
1099 break;
1100 case at_icregexp:
1101 analyse_regex (argbuffer[i].what, TRUE);
b9755a12 1102 break;
c6d46f5f 1103#endif
b9755a12
FP
1104 case at_filename:
1105#ifdef VMS
1106 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
1107 {
1108 if (got_err)
1109 {
30903246 1110 error ("can't find file %s\n", this_file);
b9755a12
FP
1111 argc--, argv++;
1112 }
1113 else
1114 {
1115 this_file = massage_name (this_file);
1116 }
c6d46f5f 1117#else
b9755a12 1118 this_file = argbuffer[i].what;
c6d46f5f 1119#endif
b9755a12 1120 /* Input file named "-" means read file names from stdin
93b7ac65 1121 (one per line) and use them. */
b9755a12 1122 if (streq (this_file, "-"))
9cb0aa73
FP
1123 while (readline_internal (&filename_lb, stdin) > 0)
1124 process_file (filename_lb.buffer);
b9755a12
FP
1125 else
1126 process_file (this_file);
1127#ifdef VMS
c6d46f5f 1128 }
b9755a12
FP
1129#endif
1130 break;
c6d46f5f 1131 }
46c145db 1132 }
9cb0aa73 1133
93b7ac65
FP
1134#ifdef ETAGS_REGEXPS
1135 free_patterns ();
1136#endif /* ETAGS_REGEXPS */
1137
32daa216 1138 if (!CTAGS)
c6d46f5f 1139 {
1e134a5f 1140 while (nincluded_files-- > 0)
6dd5561c 1141 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1e134a5f 1142
55597f90 1143 fclose (tagf);
1a0d8c80 1144 exit (GOOD);
c6d46f5f
JB
1145 }
1146
55597f90
FP
1147 /* If CTAGS, we are here. process_file did not write the tags yet,
1148 because we want them ordered. Let's do it now. */
c6d46f5f
JB
1149 if (cxref_style)
1150 {
1151 put_entries (head);
93b7ac65
FP
1152 free_tree (head);
1153 head = NULL;
c6d46f5f
JB
1154 exit (GOOD);
1155 }
55597f90 1156
4746118a 1157 if (update)
c6d46f5f 1158 {
55597f90 1159 char cmd[BUFSIZ];
b9755a12 1160 for (i = 0; i < current_arg; ++i)
c6d46f5f 1161 {
55597f90 1162 if (argbuffer[i].arg_type != at_filename)
b9755a12 1163 continue;
c6d46f5f
JB
1164 sprintf (cmd,
1165 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
b9755a12 1166 tagfile, argbuffer[i].what, tagfile);
55597f90 1167 if (system (cmd) != GOOD)
086eac13 1168 fatal ("failed to execute shell command", (char *)NULL);
c6d46f5f 1169 }
55597f90 1170 append_to_tagfile = TRUE;
c6d46f5f 1171 }
55597f90 1172
6dd5561c
FP
1173 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1174 if (tagf == NULL)
55597f90 1175 pfatal (tagfile);
c6d46f5f 1176 put_entries (head);
93b7ac65
FP
1177 free_tree (head);
1178 head = NULL;
55597f90
FP
1179 fclose (tagf);
1180
c6d46f5f
JB
1181 if (update)
1182 {
55597f90 1183 char cmd[BUFSIZ];
6dd5561c 1184 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
55597f90 1185 exit (system (cmd));
c6d46f5f 1186 }
b6b48846 1187 return GOOD;
c6d46f5f
JB
1188}
1189
1190
93b7ac65
FP
1191
1192/*
1193 * Return a compressor given the file name. If EXTPTR is non-zero,
1194 * return a pointer into FILE where the compressor-specific
1195 * extension begins. If no compressor is found, NULL is returned
1196 * and EXTPTR is not significant.
1197 * Idea by Vladimir Alexiev <vladimir@cs.ualberta.ca>
1198 */
944bdd72 1199static compressor *
93b7ac65
FP
1200get_compressor_from_suffix (file, extptr)
1201 char *file;
1202 char **extptr;
1203{
1204 compressor *compr;
1205 char *slash, *suffix;
1206
1207 /* This relies on FN to be after canonicalize_filename,
1208 so we don't need to consider backslashes on DOS_NT. */
1209 slash = etags_strrchr (file, '/');
1210 suffix = etags_strrchr (file, '.');
1211 if (suffix == NULL || suffix < slash)
1212 return NULL;
1213 if (extptr != NULL)
1214 *extptr = suffix;
1215 suffix += 1;
1216 /* Let those poor souls who live with DOS 8+3 file name limits get
1217 some solace by treating foo.cgz as if it were foo.c.gz, etc.
1218 Only the first do loop is run if not MSDOS */
1219 do
1220 {
1221 for (compr = compressors; compr->suffix != NULL; compr++)
1222 if (streq (compr->suffix, suffix))
1223 return compr;
944bdd72
FP
1224 if (!MSDOS)
1225 break; /* do it only once: not really a loop */
93b7ac65
FP
1226 if (extptr != NULL)
1227 *extptr = ++suffix;
1228 } while (*suffix != '\0');
1229 return NULL;
1230}
1231
1232
1233
b9755a12 1234/*
93b7ac65 1235 * Return a language given the name.
b9755a12 1236 */
944bdd72 1237static language *
1f638249
FP
1238get_language_from_name (name)
1239 char *name;
b9755a12 1240{
93b7ac65 1241 language *lang;
b9755a12 1242
93b7ac65
FP
1243 if (name == NULL)
1244 error ("empty language name", (char *)NULL);
1245 else
1246 {
1247 for (lang = lang_names; lang->name != NULL; lang++)
d8913c1c 1248 if (streq (name, lang->name))
93b7ac65
FP
1249 return lang;
1250 error ("unknown language \"%s\"", name);
1251 }
d8913c1c 1252
93b7ac65 1253 return NULL;
1f638249
FP
1254}
1255
1256
1257/*
93b7ac65 1258 * Return a language given the interpreter name.
1f638249 1259 */
944bdd72 1260static language *
1f638249
FP
1261get_language_from_interpreter (interpreter)
1262 char *interpreter;
1263{
93b7ac65 1264 language *lang;
1f638249
FP
1265 char **iname;
1266
1267 if (interpreter == NULL)
1268 return NULL;
1269 for (lang = lang_names; lang->name != NULL; lang++)
1270 if (lang->interpreters != NULL)
1271 for (iname = lang->interpreters; *iname != NULL; iname++)
1272 if (streq (*iname, interpreter))
93b7ac65 1273 return lang;
1f638249
FP
1274
1275 return NULL;
1276}
1277
1278
1279
1280/*
93b7ac65 1281 * Return a language given the file name.
1f638249 1282 */
944bdd72 1283static language *
93b7ac65
FP
1284get_language_from_suffix (file)
1285 char *file;
1f638249 1286{
93b7ac65
FP
1287 language *lang;
1288 char **ext, *suffix;
1f638249 1289
93b7ac65 1290 suffix = etags_strrchr (file, '.');
1f638249
FP
1291 if (suffix == NULL)
1292 return NULL;
93b7ac65 1293 suffix += 1;
1f638249
FP
1294 for (lang = lang_names; lang->name != NULL; lang++)
1295 if (lang->suffixes != NULL)
1296 for (ext = lang->suffixes; *ext != NULL; ext++)
1297 if (streq (*ext, suffix))
93b7ac65 1298 return lang;
1f638249 1299 return NULL;
b9755a12
FP
1300}
1301
1302
93b7ac65 1303
c6d46f5f
JB
1304/*
1305 * This routine is called on each file argument.
1306 */
944bdd72 1307static void
c6d46f5f
JB
1308process_file (file)
1309 char *file;
1310{
1311 struct stat stat_buf;
55597f90 1312 FILE *inf;
93b7ac65
FP
1313 compressor *compr;
1314 char *compressed_name, *uncompressed_name;
1315 char *ext, *real_name;
ce7f6d62 1316
c6d46f5f 1317
93b7ac65 1318 canonicalize_filename (file);
6dd5561c 1319 if (streq (file, tagfile) && !streq (tagfile, "-"))
c6d46f5f 1320 {
30903246 1321 error ("skipping inclusion of %s in self.", file);
c6d46f5f
JB
1322 return;
1323 }
93b7ac65
FP
1324 if ((compr = get_compressor_from_suffix (file, &ext)) == NULL)
1325 {
1326 compressed_name = NULL;
1327 real_name = uncompressed_name = savestr (file);
1328 }
1329 else
1330 {
1331 real_name = compressed_name = savestr (file);
1332 uncompressed_name = savenstr (file, ext - file);
1333 }
1334
1335 /* If the canonicalised uncompressed name has already be dealt with,
1336 skip it silently, else add it to the list. */
1337 {
1338 typedef struct processed_file
1339 {
1340 char *filename;
1341 struct processed_file *next;
1342 } processed_file;
1343 static processed_file *pf_head = NULL;
1344 register processed_file *fnp;
1345
1346 for (fnp = pf_head; fnp != NULL; fnp = fnp->next)
1347 if (streq (uncompressed_name, fnp->filename))
1348 goto exit;
1349 fnp = pf_head;
1350 pf_head = xnew (1, struct processed_file);
1351 pf_head->filename = savestr (uncompressed_name);
1352 pf_head->next = fnp;
1353 }
1354
1355 if (stat (real_name, &stat_buf) != 0)
1356 {
1357 /* Reset real_name and try with a different name. */
1358 real_name = NULL;
1359 if (compressed_name != NULL) /* try with the given suffix */
1360 {
1361 if (stat (uncompressed_name, &stat_buf) == 0)
1362 real_name = uncompressed_name;
1363 }
1364 else /* try all possible suffixes */
1365 {
1366 for (compr = compressors; compr->suffix != NULL; compr++)
1367 {
1368 compressed_name = concat (file, ".", compr->suffix);
1369 if (stat (compressed_name, &stat_buf) != 0)
1370 {
944bdd72 1371 if (MSDOS)
93b7ac65 1372 {
944bdd72
FP
1373 char *suf = compressed_name + strlen (file);
1374 size_t suflen = strlen (compr->suffix) + 1;
1375 for ( ; suf[1]; suf++, suflen--)
93b7ac65 1376 {
944bdd72
FP
1377 memmove (suf, suf + 1, suflen);
1378 if (stat (compressed_name, &stat_buf) == 0)
1379 {
1380 real_name = compressed_name;
1381 break;
1382 }
93b7ac65 1383 }
944bdd72
FP
1384 if (real_name != NULL)
1385 break;
1386 } /* MSDOS */
93b7ac65
FP
1387 free (compressed_name);
1388 compressed_name = NULL;
1389 }
1390 else
1391 {
1392 real_name = compressed_name;
1393 break;
1394 }
1395 }
1396 }
1397 if (real_name == NULL)
1398 {
1399 perror (file);
1400 goto exit;
1401 }
1402 } /* try with a different name */
1403
1404 if (!S_ISREG (stat_buf.st_mode))
1405 {
1406 error ("skipping %s: it is not a regular file.", real_name);
1407 goto exit;
1408 }
1409 if (real_name == compressed_name)
1410 {
1411 char *cmd = concat (compr->command, " ", real_name);
1412 inf = popen (cmd, "r");
1413 free (cmd);
1414 }
1415 else
1416 inf = fopen (real_name, "r");
55597f90 1417 if (inf == NULL)
42680d3c 1418 {
93b7ac65
FP
1419 perror (real_name);
1420 goto exit;
42680d3c 1421 }
55597f90 1422
93b7ac65
FP
1423 find_entries (uncompressed_name, inf);
1424
1425 if (real_name == compressed_name)
1426 pclose (inf);
1427 else
1428 fclose (inf);
55597f90 1429
32daa216 1430 if (!CTAGS)
c6d46f5f 1431 {
46c145db
FP
1432 char *filename;
1433
93b7ac65 1434 if (filename_is_absolute (uncompressed_name))
46c145db 1435 {
2f608d34 1436 /* file is an absolute file name. Canonicalise it. */
93b7ac65 1437 filename = absolute_filename (uncompressed_name, cwd);
46c145db
FP
1438 }
1439 else
1440 {
2f608d34 1441 /* file is a file name relative to cwd. Make it relative
46c145db 1442 to the directory of the tags file. */
93b7ac65 1443 filename = relative_filename (uncompressed_name, tagfiledir);
46c145db 1444 }
6dd5561c 1445 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
a8d9bd4b 1446 free (filename);
c6d46f5f
JB
1447 put_entries (head);
1448 free_tree (head);
1449 head = NULL;
1450 }
93b7ac65
FP
1451
1452 exit:
1453 if (compressed_name) free(compressed_name);
1454 if (uncompressed_name) free(uncompressed_name);
1455 return;
c6d46f5f
JB
1456}
1457
1458/*
eb8c3be9 1459 * This routine sets up the boolean pseudo-functions which work
93b7ac65 1460 * by setting boolean flags dependent upon the corresponding character.
c6d46f5f
JB
1461 * Every char which is NOT in that string is not a white char. Therefore,
1462 * all of the array "_wht" is set to FALSE, and then the elements
1463 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1464 * of a char is TRUE if it is the string "white", else FALSE.
1465 */
944bdd72 1466static void
c6d46f5f
JB
1467init ()
1468{
13fde0cd
RS
1469 register char *sp;
1470 register int i;
c6d46f5f 1471
30903246 1472 for (i = 0; i < CHARS; i++)
93b7ac65
FP
1473 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1474 for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1475 for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1476 for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1477 for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1478 for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1479 iswhite('\0') = iswhite('\n');
1480 notinname('\0') = notinname('\n');
1481 begtoken('\0') = begtoken('\n');
1482 intoken('\0') = intoken('\n');
1483 endtoken('\0') = endtoken('\n');
c6d46f5f
JB
1484}
1485
1486/*
1487 * This routine opens the specified file and calls the function
1488 * which finds the function and type definitions.
1489 */
93b7ac65
FP
1490node *last_node = NULL;
1491
944bdd72 1492static void
55597f90 1493find_entries (file, inf)
c6d46f5f 1494 char *file;
55597f90 1495 FILE *inf;
c6d46f5f 1496{
b9755a12 1497 char *cp;
93b7ac65
FP
1498 language *lang;
1499 node *old_last_node;
1500
1501 /* Memory leakage here: the string pointed by curfile is
1502 never released, because curfile is copied into np->file
1503 for each node, to be used in CTAGS mode. The amount of
1504 memory leaked here is the sum of the lengths of the
1505 file names. */
c6d46f5f 1506 curfile = savestr (file);
c6d46f5f 1507
b9755a12 1508 /* If user specified a language, use it. */
93b7ac65
FP
1509 lang = forced_lang;
1510 if (lang != NULL && lang->function != NULL)
13fde0cd 1511 {
93b7ac65
FP
1512 curlang = lang;
1513 lang->function (inf);
55597f90 1514 return;
13fde0cd 1515 }
b9755a12 1516
93b7ac65
FP
1517 /* Try to guess the language given the file name. */
1518 lang = get_language_from_suffix (file);
1519 if (lang != NULL && lang->function != NULL)
1f638249 1520 {
93b7ac65
FP
1521 curlang = lang;
1522 lang->function (inf);
1523 return;
1f638249
FP
1524 }
1525
1526 /* Look for sharp-bang as the first two characters. */
93b7ac65 1527 if (readline_internal (&lb, inf) > 0
e0903a92 1528 && lb.len >= 2
1f638249
FP
1529 && lb.buffer[0] == '#'
1530 && lb.buffer[1] == '!')
c6d46f5f 1531 {
1f638249
FP
1532 char *lp;
1533
1534 /* Set lp to point at the first char after the last slash in the
1535 line or, if no slashes, at the first nonblank. Then set cp to
1536 the first successive blank and terminate the string. */
1537 lp = etags_strrchr (lb.buffer+2, '/');
1538 if (lp != NULL)
1539 lp += 1;
1540 else
93b7ac65
FP
1541 lp = skip_spaces (lb.buffer + 2);
1542 cp = skip_non_spaces (lp);
1f638249
FP
1543 *cp = '\0';
1544
1545 if (strlen (lp) > 0)
b9755a12 1546 {
93b7ac65
FP
1547 lang = get_language_from_interpreter (lp);
1548 if (lang != NULL && lang->function != NULL)
b9755a12 1549 {
93b7ac65
FP
1550 curlang = lang;
1551 lang->function (inf);
55597f90 1552 return;
b9755a12
FP
1553 }
1554 }
c6d46f5f 1555 }
93b7ac65
FP
1556 /* We rewind here, even if inf may be a pipe. We fail if the
1557 length of the first line is longer than the pipe block size,
1558 which is unlikely. */
1f638249 1559 rewind (inf);
c6d46f5f 1560
b9755a12
FP
1561 /* Try Fortran. */
1562 old_last_node = last_node;
93b7ac65 1563 curlang = get_language_from_name ("fortran");
b9755a12 1564 Fortran_functions (inf);
c6d46f5f 1565
b9755a12
FP
1566 /* No Fortran entries found. Try C. */
1567 if (old_last_node == last_node)
b2db879b 1568 {
93b7ac65
FP
1569 /* We do not tag if rewind fails.
1570 Only the file name will be recorded in the tags file. */
b2db879b 1571 rewind (inf);
93b7ac65 1572 curlang = get_language_from_name (cplusplus ? "c++" : "c");
b2db879b
FP
1573 default_C_entries (inf);
1574 }
1f638249 1575 return;
c6d46f5f
JB
1576}
1577\f
1578/* Record a tag. */
0dacfc4b 1579static void
108c932a 1580pfnote (name, is_func, linestart, linelen, lno, cno)
d8913c1c 1581 char *name; /* tag name, or NULL if unnamed */
30903246 1582 bool is_func; /* tag is a function */
55597f90
FP
1583 char *linestart; /* start of the line where tag is */
1584 int linelen; /* length of the line where tag is */
1585 int lno; /* line number */
1586 long cno; /* character number */
1587{
93b7ac65 1588 register node *np;
d8913c1c
FP
1589
1590 if (CTAGS && name == NULL)
1591 return;
1592
93b7ac65 1593 np = xnew (1, node);
c6d46f5f 1594
c6d46f5f 1595 /* If ctags mode, change name "main" to M<thisfilename>. */
32daa216 1596 if (CTAGS && !cxref_style && streq (name, "main"))
c6d46f5f 1597 {
108c932a 1598 register char *fp = etags_strrchr (curfile, '/');
93b7ac65 1599 np->name = concat ("M", fp == NULL ? curfile : fp + 1, "");
55597f90 1600 fp = etags_strrchr (np->name, '.');
93b7ac65
FP
1601 if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
1602 fp[0] = '\0';
55597f90
FP
1603 }
1604 else
108c932a 1605 np->name = name;
4b533b5b 1606 np->been_warned = FALSE;
c6d46f5f
JB
1607 np->file = curfile;
1608 np->is_func = is_func;
c6d46f5f 1609 np->lno = lno;
aab1fdae
FP
1610 /* Our char numbers are 0-base, because of C language tradition?
1611 ctags compatibility? old versions compatibility? I don't know.
15294654 1612 Anyway, since emacs's are 1-base we expect etags.el to take care
aab1fdae
FP
1613 of the difference. If we wanted to have 1-based numbers, we would
1614 uncomment the +1 below. */
1615 np->cno = cno /* + 1 */ ;
55597f90 1616 np->left = np->right = NULL;
d8913c1c
FP
1617 if (CTAGS && !cxref_style)
1618 {
1619 if (strlen (linestart) < 50)
1620 np->pat = concat (linestart, "$", "");
1621 else
1622 np->pat = savenstr (linestart, 50);
1623 }
1624 else
1625 np->pat = savenstr (linestart, linelen);
c6d46f5f
JB
1626
1627 add_node (np, &head);
1628}
1629
93b7ac65
FP
1630/* Date: Wed, 22 Jan 1997 02:56:31 -0500 [last amended 18 Sep 1997]
1631 * From: Sam Kendall <kendall@mv.mv.com>
30903246
FP
1632 * Subject: Proposal for firming up the TAGS format specification
1633 * To: F.Potorti@cnuce.cnr.it
1634 *
1635 * pfnote should emit the optimized form [unnamed tag] only if:
93b7ac65 1636 * 1. name does not contain any of the characters " \t\r\n(),;";
30903246
FP
1637 * 2. linestart contains name as either a rightmost, or rightmost but
1638 * one character, substring;
1639 * 3. the character, if any, immediately before name in linestart must
93b7ac65 1640 * be one of the characters " \t(),;";
30903246 1641 * 4. the character, if any, immediately after name in linestart must
93b7ac65
FP
1642 * also be one of the characters " \t(),;".
1643 *
1644 * The real implementation uses the notinname() macro, which recognises
1645 * characters slightly different form " \t\r\n(),;". See the variable
1646 * `nonam'.
30903246
FP
1647 */
1648#define traditional_tag_style TRUE
0dacfc4b 1649static void
30903246
FP
1650new_pfnote (name, namelen, is_func, linestart, linelen, lno, cno)
1651 char *name; /* tag name, or NULL if unnamed */
1652 int namelen; /* tag length */
1653 bool is_func; /* tag is a function */
1654 char *linestart; /* start of the line where tag is */
1655 int linelen; /* length of the line where tag is */
1656 int lno; /* line number */
1657 long cno; /* character number */
1658{
1659 register char *cp;
1660 bool named;
1661
1662 named = TRUE;
1663 if (!CTAGS)
1664 {
1665 for (cp = name; !notinname (*cp); cp++)
1666 continue;
1667 if (*cp == '\0') /* rule #1 */
1668 {
1669 cp = linestart + linelen - namelen;
1670 if (notinname (linestart[linelen-1]))
1671 cp -= 1; /* rule #4 */
1672 if (cp >= linestart /* rule #2 */
1673 && (cp == linestart
1674 || notinname (cp[-1])) /* rule #3 */
1675 && strneq (name, cp, namelen)) /* rule #2 */
1676 named = FALSE; /* use unnamed tag */
1677 }
1678 }
93b7ac65 1679
30903246
FP
1680 if (named)
1681 name = savenstr (name, namelen);
1682 else
1683 name = NULL;
1684 pfnote (name, is_func, linestart, linelen, lno, cno);
1685}
1686
c6d46f5f
JB
1687/*
1688 * free_tree ()
1689 * recurse on left children, iterate on right children.
1690 */
944bdd72 1691static void
93b7ac65
FP
1692free_tree (np)
1693 register node *np;
c6d46f5f 1694{
93b7ac65 1695 while (np)
c6d46f5f 1696 {
93b7ac65
FP
1697 register node *node_right = np->right;
1698 free_tree (np->left);
1699 if (np->name != NULL)
1700 free (np->name);
1701 free (np->pat);
1702 free (np);
1703 np = node_right;
c6d46f5f
JB
1704 }
1705}
1706
1707/*
1708 * add_node ()
1709 * Adds a node to the tree of nodes. In etags mode, we don't keep
1710 * it sorted; we just keep a linear list. In ctags mode, maintain
1711 * an ordered tree, with no attempt at balancing.
1712 *
1713 * add_node is the only function allowed to add nodes, so it can
1714 * maintain state.
1715 */
944bdd72 1716static void
93b7ac65
FP
1717add_node (np, cur_node_p)
1718 node *np, **cur_node_p;
c6d46f5f
JB
1719{
1720 register int dif;
93b7ac65 1721 register node *cur_node = *cur_node_p;
c6d46f5f
JB
1722
1723 if (cur_node == NULL)
1724 {
93b7ac65
FP
1725 *cur_node_p = np;
1726 last_node = np;
c6d46f5f
JB
1727 return;
1728 }
1729
32daa216 1730 if (!CTAGS)
c6d46f5f
JB
1731 {
1732 /* Etags Mode */
1a0d8c80 1733 if (last_node == NULL)
086eac13 1734 fatal ("internal error in add_node", (char *)NULL);
93b7ac65
FP
1735 last_node->right = np;
1736 last_node = np;
c6d46f5f
JB
1737 }
1738 else
1739 {
1740 /* Ctags Mode */
93b7ac65 1741 dif = strcmp (np->name, cur_node->name);
c6d46f5f
JB
1742
1743 /*
1744 * If this tag name matches an existing one, then
1745 * do not add the node, but maybe print a warning.
1746 */
1747 if (!dif)
1748 {
93b7ac65 1749 if (streq (np->file, cur_node->file))
c6d46f5f
JB
1750 {
1751 if (!no_warnings)
1752 {
1753 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
93b7ac65 1754 np->file, lineno, np->name);
c6d46f5f
JB
1755 fprintf (stderr, "Second entry ignored\n");
1756 }
c6d46f5f 1757 }
c5007f46 1758 else if (!cur_node->been_warned && !no_warnings)
c6d46f5f 1759 {
c5007f46
FP
1760 fprintf
1761 (stderr,
1762 "Duplicate entry in files %s and %s: %s (Warning only)\n",
93b7ac65 1763 np->file, cur_node->file, np->name);
c5007f46 1764 cur_node->been_warned = TRUE;
c6d46f5f 1765 }
c6d46f5f
JB
1766 return;
1767 }
1768
c6d46f5f 1769 /* Actually add the node */
93b7ac65 1770 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
c6d46f5f
JB
1771 }
1772}
1773\f
944bdd72 1774static void
93b7ac65
FP
1775put_entries (np)
1776 register node *np;
c6d46f5f 1777{
13fde0cd 1778 register char *sp;
c6d46f5f 1779
93b7ac65 1780 if (np == NULL)
c6d46f5f
JB
1781 return;
1782
1783 /* Output subentries that precede this one */
93b7ac65 1784 put_entries (np->left);
c6d46f5f
JB
1785
1786 /* Output this entry */
1787
32daa216 1788 if (!CTAGS)
c6d46f5f 1789 {
93b7ac65 1790 if (np->name != NULL)
fb220ea4 1791 fprintf (tagf, "%s\177%s\001%d,%ld\n",
93b7ac65 1792 np->pat, np->name, np->lno, np->cno);
c6d46f5f 1793 else
fb220ea4 1794 fprintf (tagf, "%s\177%d,%ld\n",
93b7ac65 1795 np->pat, np->lno, np->cno);
c6d46f5f 1796 }
d8913c1c 1797 else
c6d46f5f 1798 {
93b7ac65 1799 if (np->name == NULL)
086eac13 1800 error ("internal error: NULL name in ctags mode.", (char *)NULL);
c6d46f5f 1801
d8913c1c
FP
1802 if (cxref_style)
1803 {
1804 if (vgrind_style)
1805 fprintf (stdout, "%s %s %d\n",
93b7ac65 1806 np->name, np->file, (np->lno + 63) / 64);
d8913c1c
FP
1807 else
1808 fprintf (stdout, "%-16s %3d %-16s %s\n",
93b7ac65 1809 np->name, np->lno, np->file, np->pat);
c6d46f5f
JB
1810 }
1811 else
d8913c1c 1812 {
93b7ac65 1813 fprintf (tagf, "%s\t%s\t", np->name, np->file);
d8913c1c 1814
93b7ac65 1815 if (np->is_func)
d8913c1c
FP
1816 { /* a function */
1817 putc (searchar, tagf);
1818 putc ('^', tagf);
1819
93b7ac65 1820 for (sp = np->pat; *sp; sp++)
d8913c1c
FP
1821 {
1822 if (*sp == '\\' || *sp == searchar)
1823 putc ('\\', tagf);
1824 putc (*sp, tagf);
1825 }
1826 putc (searchar, tagf);
1827 }
1828 else
1829 { /* a typedef; text pattern inadequate */
93b7ac65 1830 fprintf (tagf, "%d", np->lno);
d8913c1c
FP
1831 }
1832 putc ('\n', tagf);
c6d46f5f 1833 }
c6d46f5f 1834 }
c6d46f5f
JB
1835
1836 /* Output subentries that follow this one */
93b7ac65 1837 put_entries (np->right);
c6d46f5f
JB
1838}
1839
1840/* Length of a number's decimal representation. */
944bdd72 1841static int
c6d46f5f
JB
1842number_len (num)
1843 long num;
1844{
93b7ac65
FP
1845 int len = 1;
1846 while ((num /= 10) > 0)
1847 len += 1;
c6d46f5f
JB
1848 return len;
1849}
1850
1851/*
1852 * Return total number of characters that put_entries will output for
32daa216
FP
1853 * the nodes in the subtree of the specified node. Works only if
1854 * we are not ctags, but called only in that case. This count
1855 * is irrelevant with the new tags.el, but is still supplied for
1856 * backward compatibility.
c6d46f5f 1857 */
944bdd72 1858static int
93b7ac65
FP
1859total_size_of_entries (np)
1860 register node *np;
c6d46f5f 1861{
13fde0cd 1862 register int total;
c6d46f5f 1863
93b7ac65 1864 if (np == NULL)
c6d46f5f
JB
1865 return 0;
1866
93b7ac65 1867 for (total = 0; np != NULL; np = np->right)
c6d46f5f
JB
1868 {
1869 /* Count left subentries. */
93b7ac65 1870 total += total_size_of_entries (np->left);
c6d46f5f
JB
1871
1872 /* Count this entry */
93b7ac65
FP
1873 total += strlen (np->pat) + 1;
1874 total += number_len ((long) np->lno) + 1 + number_len (np->cno) + 1;
1875 if (np->name != NULL)
1876 total += 1 + strlen (np->name); /* \001name */
c6d46f5f
JB
1877 }
1878
1879 return total;
1880}
1881\f
1882/*
1883 * The C symbol tables.
1884 */
55597f90
FP
1885enum sym_type
1886{
30903246
FP
1887 st_none,
1888 st_C_objprot, st_C_objimpl, st_C_objend,
1889 st_C_gnumacro,
1890 st_C_ignore,
1891 st_C_javastruct,
93b7ac65
FP
1892 st_C_operator,
1893 st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
55597f90 1894};
c6d46f5f 1895
42680d3c 1896/* Feed stuff between (but not including) %[ and %] lines to:
901b219d 1897 gperf -c -k 1,3 -o -p -r -t
42680d3c
FP
1898%[
1899struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1900%%
93b7ac65
FP
1901if, 0, st_C_ignore
1902for, 0, st_C_ignore
1903while, 0, st_C_ignore
1904switch, 0, st_C_ignore
1905return, 0, st_C_ignore
d8913c1c
FP
1906@interface, 0, st_C_objprot
1907@protocol, 0, st_C_objprot
1908@implementation,0, st_C_objimpl
1909@end, 0, st_C_objend
30903246
FP
1910import, C_JAVA, st_C_ignore
1911package, C_JAVA, st_C_ignore
1912friend, C_PLPL, st_C_ignore
b7e22e94
FP
1913extends, C_JAVA, st_C_javastruct
1914implements, C_JAVA, st_C_javastruct
93b7ac65 1915interface, C_JAVA, st_C_struct
42680d3c 1916class, C_PLPL, st_C_struct
901b219d 1917namespace, C_PLPL, st_C_struct
42680d3c
FP
1918domain, C_STAR, st_C_struct
1919union, 0, st_C_struct
1920struct, 0, st_C_struct
93b7ac65 1921extern, 0, st_C_extern
42680d3c
FP
1922enum, 0, st_C_enum
1923typedef, 0, st_C_typedef
1924define, 0, st_C_define
93b7ac65 1925operator, C_PLPL, st_C_operator
901b219d 1926bool, C_PLPL, st_C_typespec
42680d3c
FP
1927long, 0, st_C_typespec
1928short, 0, st_C_typespec
1929int, 0, st_C_typespec
1930char, 0, st_C_typespec
1931float, 0, st_C_typespec
1932double, 0, st_C_typespec
1933signed, 0, st_C_typespec
1934unsigned, 0, st_C_typespec
1935auto, 0, st_C_typespec
1936void, 0, st_C_typespec
42680d3c
FP
1937static, 0, st_C_typespec
1938const, 0, st_C_typespec
1939volatile, 0, st_C_typespec
901b219d
FP
1940explicit, C_PLPL, st_C_typespec
1941mutable, C_PLPL, st_C_typespec
1942typename, C_PLPL, st_C_typespec
d8913c1c
FP
1943# DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
1944DEFUN, 0, st_C_gnumacro
1945SYSCALL, 0, st_C_gnumacro
1946ENTRY, 0, st_C_gnumacro
1947PSEUDO, 0, st_C_gnumacro
1948# These are defined inside C functions, so currently they are not met.
1949# EXFUN used in glibc, DEFVAR_* in emacs.
1950#EXFUN, 0, st_C_gnumacro
1951#DEFVAR_, 0, st_C_gnumacro
42680d3c
FP
1952%]
1953and replace lines between %< and %> with its output. */
1954/*%<*/
93b7ac65 1955/* C code produced by gperf version 2.7.1 (19981006 egcs) */
901b219d 1956/* Command-line: gperf -c -k 1,3 -o -p -r -t */
42680d3c
FP
1957struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1958
93b7ac65
FP
1959#define TOTAL_KEYWORDS 46
1960#define MIN_WORD_LENGTH 2
d8913c1c 1961#define MAX_WORD_LENGTH 15
93b7ac65
FP
1962#define MIN_HASH_VALUE 13
1963#define MAX_HASH_VALUE 123
1964/* maximum key range = 111, duplicates = 0 */
42680d3c 1965
93b7ac65
FP
1966#ifdef __GNUC__
1967__inline
1968#endif
1969static unsigned int
42680d3c 1970hash (str, len)
93b7ac65
FP
1971 register const char *str;
1972 register unsigned int len;
42680d3c 1973{
93b7ac65 1974 static unsigned char asso_values[] =
42680d3c 1975 {
93b7ac65
FP
1976 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1977 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1978 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1979 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1980 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1981 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1982 124, 124, 124, 124, 3, 124, 124, 124, 43, 6,
1983 11, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1984 11, 124, 124, 58, 7, 124, 124, 124, 124, 124,
1985 124, 124, 124, 124, 124, 124, 124, 57, 7, 42,
1986 4, 14, 52, 0, 124, 53, 124, 124, 29, 11,
1987 6, 35, 32, 124, 29, 34, 59, 58, 51, 24,
1988 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1989 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1990 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1991 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1992 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1993 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1994 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1995 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1996 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1997 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1998 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
1999 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2000 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
2001 124, 124, 124, 124, 124, 124
2002 };
2003 register int hval = len;
2004
2005 switch (hval)
2006 {
2007 default:
2008 case 3:
2009 hval += asso_values[(unsigned char)str[2]];
2010 case 2:
2011 case 1:
2012 hval += asso_values[(unsigned char)str[0]];
2013 break;
2014 }
2015 return hval;
42680d3c 2016}
c6d46f5f 2017
93b7ac65
FP
2018#ifdef __GNUC__
2019__inline
2020#endif
944bdd72 2021static struct C_stab_entry *
901b219d 2022in_word_set (str, len)
93b7ac65 2023 register const char *str;
901b219d 2024 register unsigned int len;
42680d3c 2025{
93b7ac65 2026 static struct C_stab_entry wordlist[] =
42680d3c 2027 {
93b7ac65
FP
2028 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2029 {""}, {""}, {""}, {""},
2030 {"@end", 0, st_C_objend},
2031 {""}, {""}, {""}, {""},
2032 {"ENTRY", 0, st_C_gnumacro},
2033 {"@interface", 0, st_C_objprot},
2034 {""},
2035 {"domain", C_STAR, st_C_struct},
2036 {""},
2037 {"PSEUDO", 0, st_C_gnumacro},
2038 {""}, {""},
2039 {"namespace", C_PLPL, st_C_struct},
2040 {""}, {""},
2041 {"@implementation",0, st_C_objimpl},
2042 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2043 {"long", 0, st_C_typespec},
2044 {"signed", 0, st_C_typespec},
2045 {"@protocol", 0, st_C_objprot},
2046 {""}, {""}, {""}, {""},
2047 {"bool", C_PLPL, st_C_typespec},
2048 {""}, {""}, {""}, {""}, {""}, {""},
2049 {"const", 0, st_C_typespec},
2050 {"explicit", C_PLPL, st_C_typespec},
2051 {"if", 0, st_C_ignore},
2052 {""},
2053 {"operator", C_PLPL, st_C_operator},
2054 {""},
2055 {"DEFUN", 0, st_C_gnumacro},
2056 {""}, {""},
2057 {"define", 0, st_C_define},
2058 {""}, {""}, {""}, {""}, {""},
2059 {"double", 0, st_C_typespec},
2060 {"struct", 0, st_C_struct},
2061 {""}, {""}, {""}, {""},
2062 {"short", 0, st_C_typespec},
2063 {""},
2064 {"enum", 0, st_C_enum},
2065 {"mutable", C_PLPL, st_C_typespec},
2066 {""},
2067 {"extern", 0, st_C_extern},
2068 {"extends", C_JAVA, st_C_javastruct},
2069 {"package", C_JAVA, st_C_ignore},
2070 {"while", 0, st_C_ignore},
2071 {""},
2072 {"for", 0, st_C_ignore},
2073 {""}, {""}, {""},
2074 {"volatile", 0, st_C_typespec},
2075 {""}, {""},
2076 {"import", C_JAVA, st_C_ignore},
2077 {"float", 0, st_C_typespec},
2078 {"switch", 0, st_C_ignore},
2079 {"return", 0, st_C_ignore},
2080 {"implements", C_JAVA, st_C_javastruct},
2081 {""},
2082 {"static", 0, st_C_typespec},
2083 {"typedef", 0, st_C_typedef},
2084 {"typename", C_PLPL, st_C_typespec},
2085 {"unsigned", 0, st_C_typespec},
2086 {""}, {""},
2087 {"char", 0, st_C_typespec},
2088 {"class", C_PLPL, st_C_struct},
2089 {""}, {""}, {""},
2090 {"void", 0, st_C_typespec},
2091 {""}, {""},
2092 {"friend", C_PLPL, st_C_ignore},
2093 {""}, {""}, {""},
2094 {"int", 0, st_C_typespec},
2095 {"union", 0, st_C_struct},
2096 {""}, {""}, {""},
2097 {"auto", 0, st_C_typespec},
2098 {"interface", C_JAVA, st_C_struct},
2099 {""},
2100 {"SYSCALL", 0, st_C_gnumacro}
42680d3c
FP
2101 };
2102
2103 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
2104 {
2105 register int key = hash (str, len);
2106
93b7ac65 2107 if (key <= MAX_HASH_VALUE && key >= 0)
42680d3c 2108 {
93b7ac65 2109 register const char *s = wordlist[key].name;
42680d3c 2110
93b7ac65 2111 if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
42680d3c
FP
2112 return &wordlist[key];
2113 }
2114 }
2115 return 0;
c6d46f5f 2116}
42680d3c 2117/*%>*/
c6d46f5f 2118
944bdd72 2119static enum sym_type
3f1c8fcd 2120C_symtype (str, len, c_ext)
42680d3c
FP
2121 char *str;
2122 int len;
c6d46f5f
JB
2123 int c_ext;
2124{
3f1c8fcd 2125 register struct C_stab_entry *se = in_word_set (str, len);
c6d46f5f 2126
42680d3c
FP
2127 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2128 return st_none;
2129 return se->type;
c6d46f5f
JB
2130}
2131\f
13fde0cd 2132 /*
30903246
FP
2133 * C functions and variables are recognized using a simple
2134 * finite automaton. fvdef is its state variable.
13fde0cd 2135 */
d8913c1c 2136enum
13fde0cd 2137{
30903246 2138 fvnone, /* nothing seen */
93b7ac65 2139 foperator, /* func: operator keyword seen (cplpl) */
30903246
FP
2140 fvnameseen, /* function or variable name seen */
2141 fstartlist, /* func: just after open parenthesis */
2142 finlist, /* func: in parameter list */
2143 flistseen, /* func: after parameter list */
2144 fignore, /* func: before open brace */
2145 vignore /* var-like: ignore until ';' */
2146} fvdef;
13fde0cd 2147
93b7ac65 2148bool fvextern; /* func or var: extern keyword seen; */
13fde0cd 2149
46c145db
FP
2150 /*
2151 * typedefs are recognized using a simple finite automaton.
15294654 2152 * typdef is its state variable.
13fde0cd 2153 */
d8913c1c 2154enum
13fde0cd 2155{
31d4b314 2156 tnone, /* nothing seen */
93b7ac65
FP
2157 tkeyseen, /* typedef keyword seen */
2158 ttypeseen, /* defined type seen */
31d4b314 2159 tinbody, /* inside typedef body */
46c145db
FP
2160 tend, /* just before typedef tag */
2161 tignore /* junk after typedef tag */
d8913c1c 2162} typdef;
13fde0cd
RS
2163
2164
c5007f46 2165 /*
46c145db
FP
2166 * struct-like structures (enum, struct and union) are recognized
2167 * using another simple finite automaton. `structdef' is its state
2168 * variable.
13fde0cd 2169 */
d8913c1c 2170enum
13fde0cd
RS
2171{
2172 snone, /* nothing seen yet */
2173 skeyseen, /* struct-like keyword seen */
2174 stagseen, /* struct-like tag seen */
2175 scolonseen, /* colon seen after struct-like tag */
46e4cb76 2176 sinbody /* in struct body: recognize member func defs*/
d8913c1c 2177} structdef;
46c145db 2178
13fde0cd
RS
2179/*
2180 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
c5007f46 2181 * struct tag, and structtype is the type of the preceding struct-like
42680d3c 2182 * keyword.
13fde0cd 2183 */
55597f90 2184char *structtag = "<uninited>";
42680d3c 2185enum sym_type structtype;
13fde0cd 2186
d8913c1c
FP
2187/*
2188 * When objdef is different from onone, objtag is the name of the class.
2189 */
2190char *objtag = "<uninited>";
2191
13fde0cd
RS
2192/*
2193 * Yet another little state machine to deal with preprocessor lines.
2194 */
d8913c1c 2195enum
13fde0cd
RS
2196{
2197 dnone, /* nothing seen */
2198 dsharpseen, /* '#' seen as first char on line */
2199 ddefineseen, /* '#' and 'define' seen */
46e4cb76 2200 dignorerest /* ignore rest of line */
d8913c1c
FP
2201} definedef;
2202
2203/*
2204 * State machine for Objective C protocols and implementations.
b7e22e94 2205 * Tom R.Hageman <tom@basil.icce.rug.nl>
d8913c1c
FP
2206 */
2207enum
2208{
2209 onone, /* nothing seen */
2210 oprotocol, /* @interface or @protocol seen */
2211 oimplementation, /* @implementations seen */
2212 otagseen, /* class name seen */
2213 oparenseen, /* parenthesis before category seen */
2214 ocatseen, /* category name seen */
2215 oinbody, /* in @implementation body */
2216 omethodsign, /* in @implementation body, after +/- */
2217 omethodtag, /* after method name */
2218 omethodcolon, /* after method colon */
2219 omethodparm, /* after method parameter */
ba1fe3a8 2220 oignore /* wait for @end */
d8913c1c 2221} objdef;
13fde0cd 2222
30903246
FP
2223
2224/*
2225 * Use this structure to keep info about the token read, and how it
2226 * should be tagged. Used by the make_C_tag function to build a tag.
2227 */
2228typedef struct
2229{
2230 bool valid;
2231 char *str;
2232 bool named;
2233 int linelen;
2234 int lineno;
2235 long linepos;
2236 char *buffer;
93b7ac65 2237} token;
30903246 2238
93b7ac65 2239token tok; /* latest token read */
30903246 2240
13fde0cd
RS
2241/*
2242 * Set this to TRUE, and the next token considered is called a function.
cdc1f6a7 2243 * Used only for GNU emacs's function-defining macros.
13fde0cd 2244 */
30903246 2245bool next_token_is_func;
13fde0cd
RS
2246
2247/*
2248 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
2249 */
30903246 2250bool yacc_rules;
13fde0cd 2251
d8913c1c
FP
2252/*
2253 * methodlen is the length of the method name stored in token_name.
2254 */
2255int methodlen;
2256
6dd5561c
FP
2257/*
2258 * consider_token ()
2259 * checks to see if the current token is at the start of a
30903246
FP
2260 * function or variable, or corresponds to a typedef, or
2261 * is a struct/union/enum tag, or #define, or an enum constant.
6dd5561c 2262 *
3ca80e28
FP
2263 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2264 * with args. C_EXT is which language we are looking at.
6dd5561c 2265 *
6dd5561c 2266 * Globals
30903246 2267 * fvdef IN OUT
6dd5561c
FP
2268 * structdef IN OUT
2269 * definedef IN OUT
2270 * typdef IN OUT
d8913c1c 2271 * objdef IN OUT
6dd5561c
FP
2272 * next_token_is_func IN OUT
2273 */
2274
944bdd72 2275static bool
30903246 2276consider_token (str, len, c, c_ext, cblev, parlev, is_func_or_var)
55597f90
FP
2277 register char *str; /* IN: token pointer */
2278 register int len; /* IN: token length */
6dd5561c 2279 register char c; /* IN: first char after the token */
6dd5561c
FP
2280 int c_ext; /* IN: C extensions mask */
2281 int cblev; /* IN: curly brace level */
d8913c1c 2282 int parlev; /* IN: parenthesis level */
30903246 2283 bool *is_func_or_var; /* OUT: function or variable found */
6dd5561c 2284{
55597f90 2285 enum sym_type toktype = C_symtype (str, len, c_ext);
6dd5561c
FP
2286
2287 /*
2288 * Advance the definedef state machine.
2289 */
2290 switch (definedef)
2291 {
2292 case dnone:
2293 /* We're not on a preprocessor line. */
2294 break;
2295 case dsharpseen:
2296 if (toktype == st_C_define)
2297 {
2298 definedef = ddefineseen;
2299 }
2300 else
2301 {
2302 definedef = dignorerest;
2303 }
b9755a12 2304 return FALSE;
6dd5561c
FP
2305 case ddefineseen:
2306 /*
ee70dba5
FP
2307 * Make a tag for any macro, unless it is a constant
2308 * and constantypedefs is FALSE.
6dd5561c
FP
2309 */
2310 definedef = dignorerest;
30903246
FP
2311 *is_func_or_var = (c == '(');
2312 if (!*is_func_or_var && !constantypedefs)
b9755a12 2313 return FALSE;
6dd5561c 2314 else
b9755a12 2315 return TRUE;
6dd5561c 2316 case dignorerest:
b9755a12 2317 return FALSE;
6dd5561c 2318 default:
086eac13 2319 error ("internal error: definedef value.", (char *)NULL);
6dd5561c
FP
2320 }
2321
2322 /*
2323 * Now typedefs
2324 */
2325 switch (typdef)
2326 {
2327 case tnone:
2328 if (toktype == st_C_typedef)
2329 {
2330 if (typedefs)
93b7ac65
FP
2331 typdef = tkeyseen;
2332 fvextern = FALSE;
30903246 2333 fvdef = fvnone;
b9755a12 2334 return FALSE;
6dd5561c
FP
2335 }
2336 break;
93b7ac65 2337 case tkeyseen:
6dd5561c
FP
2338 switch (toktype)
2339 {
2340 case st_none:
2341 case st_C_typespec:
6dd5561c
FP
2342 case st_C_struct:
2343 case st_C_enum:
93b7ac65 2344 typdef = ttypeseen;
6dd5561c
FP
2345 break;
2346 }
2347 /* Do not return here, so the structdef stuff has a chance. */
2348 break;
2349 case tend:
2350 switch (toktype)
2351 {
2352 case st_C_typespec:
2353 case st_C_struct:
2354 case st_C_enum:
b9755a12 2355 return FALSE;
6dd5561c 2356 }
b9755a12 2357 return TRUE;
6dd5561c
FP
2358 }
2359
2360 /*
2361 * This structdef business is currently only invoked when cblev==0.
2362 * It should be recursively invoked whatever the curly brace level,
2363 * and a stack of states kept, to allow for definitions of structs
2364 * within structs.
2365 *
2366 * This structdef business is NOT invoked when we are ctags and the
2367 * file is plain C. This is because a struct tag may have the same
2368 * name as another tag, and this loses with ctags.
6dd5561c
FP
2369 */
2370 switch (toktype)
2371 {
b7e22e94 2372 case st_C_javastruct:
cec68fcb
FP
2373 if (structdef == stagseen)
2374 structdef = scolonseen;
2375 return FALSE;
6dd5561c
FP
2376 case st_C_struct:
2377 case st_C_enum:
93b7ac65 2378 if (typdef == tkeyseen
6dd5561c
FP
2379 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
2380 {
2381 structdef = skeyseen;
2382 structtype = toktype;
2383 }
b9755a12 2384 return FALSE;
6dd5561c 2385 }
3ca80e28 2386
6dd5561c
FP
2387 if (structdef == skeyseen)
2388 {
30903246
FP
2389 /* Save the tag for struct/union/class, for functions and variables
2390 that may be defined inside. */
6dd5561c 2391 if (structtype == st_C_struct)
55597f90 2392 structtag = savenstr (str, len);
6dd5561c 2393 else
55597f90 2394 structtag = "<enum>";
6dd5561c 2395 structdef = stagseen;
b9755a12 2396 return TRUE;
6dd5561c
FP
2397 }
2398
6dd5561c 2399 if (typdef != tnone)
93b7ac65 2400 definedef = dnone;
6dd5561c 2401
3ca80e28
FP
2402 /* Detect GNU macros.
2403
93b7ac65
FP
2404 Writers of emacs code are recommended to put the
2405 first two args of a DEFUN on the same line.
2406
3ca80e28
FP
2407 The DEFUN macro, used in emacs C source code, has a first arg
2408 that is a string (the lisp function name), and a second arg that
2409 is a C function name. Since etags skips strings, the second arg
2410 is tagged. This is unfortunate, as it would be better to tag the
2411 first arg. The simplest way to deal with this problem would be
2412 to name the tag with a name built from the function name, by
2413 removing the initial 'F' character and substituting '-' for '_'.
2414 Anyway, this assumes that the conventions of naming lisp
2415 functions will never change. Currently, this method is not
93b7ac65 2416 implemented. */
d8913c1c
FP
2417 if (definedef == dnone && toktype == st_C_gnumacro)
2418 {
2419 next_token_is_func = TRUE;
2420 return FALSE;
2421 }
6dd5561c
FP
2422 if (next_token_is_func)
2423 {
2424 next_token_is_func = FALSE;
30903246
FP
2425 fvdef = fignore;
2426 *is_func_or_var = TRUE;
b9755a12 2427 return TRUE;
6dd5561c
FP
2428 }
2429
3ca80e28 2430 /* Detect Objective C constructs. */
d8913c1c
FP
2431 switch (objdef)
2432 {
2433 case onone:
2434 switch (toktype)
2435 {
2436 case st_C_objprot:
2437 objdef = oprotocol;
2438 return FALSE;
2439 case st_C_objimpl:
2440 objdef = oimplementation;
2441 return FALSE;
2442 }
2443 break;
2444 case oimplementation:
30903246 2445 /* Save the class tag for functions or variables defined inside. */
d8913c1c
FP
2446 objtag = savenstr (str, len);
2447 objdef = oinbody;
2448 return FALSE;
2449 case oprotocol:
2450 /* Save the class tag for categories. */
2451 objtag = savenstr (str, len);
2452 objdef = otagseen;
30903246 2453 *is_func_or_var = TRUE;
d8913c1c
FP
2454 return TRUE;
2455 case oparenseen:
2456 objdef = ocatseen;
30903246 2457 *is_func_or_var = TRUE;
d8913c1c
FP
2458 return TRUE;
2459 case oinbody:
2460 break;
2461 case omethodsign:
2462 if (parlev == 0)
2463 {
2464 objdef = omethodtag;
2465 methodlen = len;
30903246 2466 grow_linebuffer (&token_name, methodlen + 1);
d8913c1c
FP
2467 strncpy (token_name.buffer, str, len);
2468 token_name.buffer[methodlen] = '\0';
30903246 2469 token_name.len = methodlen;
d8913c1c
FP
2470 return TRUE;
2471 }
2472 return FALSE;
2473 case omethodcolon:
2474 if (parlev == 0)
2475 objdef = omethodparm;
2476 return FALSE;
2477 case omethodparm:
2478 if (parlev == 0)
2479 {
2480 objdef = omethodtag;
9884ba1f 2481 methodlen += len;
30903246 2482 grow_linebuffer (&token_name, methodlen + 1);
d8913c1c 2483 strncat (token_name.buffer, str, len);
30903246 2484 token_name.len = methodlen;
d8913c1c
FP
2485 return TRUE;
2486 }
2487 return FALSE;
2488 case oignore:
2489 if (toktype == st_C_objend)
2490 {
2491 /* Memory leakage here: the string pointed by objtag is
2492 never released, because many tests would be needed to
2493 avoid breaking on incorrect input code. The amount of
15294654 2494 memory leaked here is the sum of the lengths of the
d8913c1c
FP
2495 class tags.
2496 free (objtag); */
2497 objdef = onone;
2498 }
2499 return FALSE;
2500 }
2501
30903246 2502 /* A function, variable or enum constant? */
6dd5561c
FP
2503 switch (toktype)
2504 {
93b7ac65
FP
2505 case st_C_extern:
2506 fvextern = TRUE;
2507 /* FALLTHRU */
6dd5561c 2508 case st_C_typespec:
93b7ac65
FP
2509 if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
2510 fvdef = fvnone; /* should be useless */
30903246
FP
2511 return FALSE;
2512 case st_C_ignore:
93b7ac65 2513 fvextern = FALSE;
30903246 2514 fvdef = vignore;
b9755a12 2515 return FALSE;
93b7ac65
FP
2516 case st_C_operator:
2517 fvdef = foperator;
2518 *is_func_or_var = TRUE;
2519 return TRUE;
3ca80e28 2520 case st_none:
93b7ac65
FP
2521 if ((c_ext & C_PLPL) && strneq (str+len-10, "::operator", 10))
2522 {
2523 fvdef = foperator;
2524 *is_func_or_var = TRUE;
2525 return TRUE;
2526 }
3ca80e28
FP
2527 if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
2528 return TRUE;
30903246 2529 if (fvdef == fvnone)
6dd5561c 2530 {
30903246
FP
2531 fvdef = fvnameseen; /* function or variable */
2532 *is_func_or_var = TRUE;
b9755a12 2533 return TRUE;
6dd5561c 2534 }
93b7ac65 2535 break;
6dd5561c
FP
2536 }
2537
b9755a12 2538 return FALSE;
6dd5561c
FP
2539}
2540
c6d46f5f
JB
2541/*
2542 * C_entries ()
30903246
FP
2543 * This routine finds functions, variables, typedefs,
2544 * #define's, enum constants and struct/union/enum definitions in
93b7ac65 2545 * C syntax and adds them to the list.
c6d46f5f 2546 */
55597f90
FP
2547#define current_lb_is_new (newndx == curndx)
2548#define switch_line_buffers() (curndx = 1 - curndx)
c6d46f5f 2549
13fde0cd
RS
2550#define curlb (lbs[curndx].lb)
2551#define othlb (lbs[1-curndx].lb)
2552#define newlb (lbs[newndx].lb)
2553#define curlinepos (lbs[curndx].linepos)
2554#define othlinepos (lbs[1-curndx].linepos)
2555#define newlinepos (lbs[newndx].linepos)
2556
93b7ac65 2557#define CNL_SAVE_DEFINEDEF() \
13fde0cd 2558do { \
55597f90 2559 curlinepos = charno; \
c6d46f5f 2560 lineno++; \
cf347d3c 2561 linecharno = charno; \
13fde0cd
RS
2562 charno += readline (&curlb, inf); \
2563 lp = curlb.buffer; \
2564 quotednl = FALSE; \
2565 newndx = curndx; \
b9755a12 2566} while (0)
c6d46f5f 2567
93b7ac65 2568#define CNL() \
13fde0cd 2569do { \
93b7ac65 2570 CNL_SAVE_DEFINEDEF(); \
75bdbc6a 2571 if (savetok.valid) \
55597f90
FP
2572 { \
2573 tok = savetok; \
75bdbc6a 2574 savetok.valid = FALSE; \
55597f90 2575 } \
c6d46f5f 2576 definedef = dnone; \
b9755a12 2577} while (0)
13fde0cd 2578
086eac13 2579
944bdd72 2580static void
30903246
FP
2581make_C_tag (isfun)
2582 bool isfun;
086eac13 2583{
086eac13
FP
2584 /* This function should never be called when tok.valid is FALSE, but
2585 we must protect against invalid input or internal errors. */
30903246 2586 if (tok.valid)
086eac13 2587 {
30903246
FP
2588 if (traditional_tag_style)
2589 {
2590 /* This was the original code. Now we call new_pfnote instead,
2591 which uses the new method for naming tags (see new_pfnote). */
2592 char *name = NULL;
2593
2594 if (CTAGS || tok.named)
2595 name = savestr (token_name.buffer);
2596 pfnote (name, isfun,
2597 tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2598 }
2599 else
2600 new_pfnote (token_name.buffer, token_name.len, isfun,
2601 tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2602 tok.valid = FALSE;
086eac13
FP
2603 }
2604 else if (DEBUG)
2605 abort ();
2606}
2607
c6d46f5f 2608
0dacfc4b 2609static void
6dd5561c 2610C_entries (c_ext, inf)
b9755a12
FP
2611 int c_ext; /* extension of C */
2612 FILE *inf; /* input file */
c6d46f5f 2613{
13fde0cd 2614 register char c; /* latest char read; '\0' for end of line */
c6d46f5f 2615 register char *lp; /* pointer one beyond the character `c' */
13fde0cd 2616 int curndx, newndx; /* indices for current and new lb */
55597f90
FP
2617 register int tokoff; /* offset in line of start of current token */
2618 register int toklen; /* length of current token */
30903246
FP
2619 char *qualifier; /* string used to qualify names */
2620 int qlen; /* length of qualifier */
591fa824 2621 int cblev; /* current curly brace level */
b12756c8 2622 int parlev; /* current parenthesis level */
30903246 2623 bool incomm, inquote, inchar, quotednl, midtoken;
93b7ac65
FP
2624 bool purec, cplpl, cjava;
2625 token savetok; /* token saved during preprocessor handling */
c6d46f5f 2626
75bdbc6a 2627
93b7ac65 2628 tokoff = toklen = 0; /* keep compiler quiet */
13fde0cd 2629 curndx = newndx = 0;
c6d46f5f
JB
2630 lineno = 0;
2631 charno = 0;
13fde0cd 2632 lp = curlb.buffer;
c6d46f5f
JB
2633 *lp = 0;
2634
93b7ac65
FP
2635 fvdef = fvnone; fvextern = FALSE; typdef = tnone;
2636 structdef = snone; definedef = dnone; objdef = onone;
75bdbc6a 2637 next_token_is_func = yacc_rules = FALSE;
13fde0cd 2638 midtoken = inquote = inchar = incomm = quotednl = FALSE;
75bdbc6a 2639 tok.valid = savetok.valid = FALSE;
591fa824 2640 cblev = 0;
b12756c8 2641 parlev = 0;
93b7ac65 2642 purec = !(c_ext & ~YACC); /* no extensions (apart from possibly yacc) */
30903246
FP
2643 cplpl = (c_ext & C_PLPL) == C_PLPL;
2644 cjava = (c_ext & C_JAVA) == C_JAVA;
2645 if (cjava)
2646 { qualifier = "."; qlen = 1; }
2647 else
2648 { qualifier = "::"; qlen = 2; }
c6d46f5f 2649
c6d46f5f
JB
2650 while (!feof (inf))
2651 {
2652 c = *lp++;
c6d46f5f
JB
2653 if (c == '\\')
2654 {
4746118a
JB
2655 /* If we're at the end of the line, the next character is a
2656 '\0'; don't skip it, because it's the thing that tells us
2657 to read the next line. */
13fde0cd 2658 if (*lp == '\0')
99e0a2e0 2659 {
13fde0cd 2660 quotednl = TRUE;
99e0a2e0
RS
2661 continue;
2662 }
1e134a5f 2663 lp++;
c6d46f5f
JB
2664 c = ' ';
2665 }
2666 else if (incomm)
2667 {
13fde0cd 2668 switch (c)
c6d46f5f 2669 {
13fde0cd
RS
2670 case '*':
2671 if (*lp == '/')
2672 {
2673 c = *lp++;
2674 incomm = FALSE;
2675 }
2676 break;
2677 case '\0':
2678 /* Newlines inside comments do not end macro definitions in
2679 traditional cpp. */
93b7ac65 2680 CNL_SAVE_DEFINEDEF ();
13fde0cd 2681 break;
c6d46f5f 2682 }
13fde0cd 2683 continue;
c6d46f5f
JB
2684 }
2685 else if (inquote)
2686 {
13fde0cd
RS
2687 switch (c)
2688 {
2689 case '"':
2690 inquote = FALSE;
2691 break;
2692 case '\0':
42680d3c 2693 /* Newlines inside strings do not end macro definitions
13fde0cd
RS
2694 in traditional cpp, even though compilers don't
2695 usually accept them. */
93b7ac65 2696 CNL_SAVE_DEFINEDEF ();
13fde0cd
RS
2697 break;
2698 }
2699 continue;
c6d46f5f
JB
2700 }
2701 else if (inchar)
2702 {
42680d3c
FP
2703 switch (c)
2704 {
2705 case '\0':
2706 /* Hmmm, something went wrong. */
93b7ac65 2707 CNL ();
42680d3c
FP
2708 /* FALLTHRU */
2709 case '\'':
46c145db 2710 inchar = FALSE;
42680d3c
FP
2711 break;
2712 }
c6d46f5f
JB
2713 continue;
2714 }
c5007f46 2715 else
c6d46f5f
JB
2716 switch (c)
2717 {
2718 case '"':
2719 inquote = TRUE;
30903246 2720 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
93b7ac65
FP
2721 {
2722 fvextern = FALSE;
2723 fvdef = fvnone;
2724 }
c6d46f5f
JB
2725 continue;
2726 case '\'':
2727 inchar = TRUE;
30903246 2728 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
93b7ac65
FP
2729 {
2730 fvextern = FALSE;
2731 fvdef = fvnone;
2732 }
c6d46f5f
JB
2733 continue;
2734 case '/':
2735 if (*lp == '*')
2736 {
2737 lp++;
2738 incomm = TRUE;
13fde0cd 2739 continue;
c6d46f5f 2740 }
d8913c1c 2741 else if (/* cplpl && */ *lp == '/')
c6d46f5f 2742 {
d8913c1c 2743 c = '\0';
daa37602 2744 break;
c6d46f5f 2745 }
b12756c8
FP
2746 else
2747 break;
13fde0cd
RS
2748 case '%':
2749 if ((c_ext & YACC) && *lp == '%')
2750 {
2751 /* entering or exiting rules section in yacc file */
2752 lp++;
93b7ac65 2753 definedef = dnone; fvdef = fvnone; fvextern = FALSE;
46c145db 2754 typdef = tnone; structdef = snone;
13fde0cd
RS
2755 next_token_is_func = FALSE;
2756 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 2757 cblev = 0;
13fde0cd
RS
2758 yacc_rules = !yacc_rules;
2759 continue;
591fa824 2760 }
b12756c8
FP
2761 else
2762 break;
c6d46f5f 2763 case '#':
ee70dba5
FP
2764 if (definedef == dnone)
2765 {
2766 char *cp;
30903246 2767 bool cpptoken = TRUE;
ee70dba5
FP
2768
2769 /* Look back on this line. If all blanks, or nonblanks
2770 followed by an end of comment, this is a preprocessor
2771 token. */
2772 for (cp = newlb.buffer; cp < lp-1; cp++)
2773 if (!iswhite (*cp))
2774 {
2775 if (*cp == '*' && *(cp+1) == '/')
2776 {
2777 cp++;
2778 cpptoken = TRUE;
2779 }
2780 else
2781 cpptoken = FALSE;
2782 }
2783 if (cpptoken)
2784 definedef = dsharpseen;
2785 } /* if (definedef == dnone) */
2786
c6d46f5f 2787 continue;
13fde0cd 2788 } /* switch (c) */
c6d46f5f 2789
c6d46f5f 2790
591fa824 2791 /* Consider token only if some complicated conditions are satisfied. */
ee70dba5
FP
2792 if ((definedef != dnone
2793 || (cblev == 0 && structdef != scolonseen)
3ca80e28 2794 || (cblev == 1 && cplpl && structdef == sinbody)
93b7ac65 2795 || (structdef == sinbody && purec))
46c145db 2796 && typdef != tignore
13fde0cd 2797 && definedef != dignorerest
30903246 2798 && fvdef != finlist)
c6d46f5f
JB
2799 {
2800 if (midtoken)
2801 {
2802 if (endtoken (c))
2803 {
93b7ac65
FP
2804 bool funorvar = FALSE;
2805
2806 if (c == ':' && cplpl && *lp == ':' && begtoken (lp[1]))
c6d46f5f
JB
2807 {
2808 /*
ee70dba5 2809 * This handles :: in the middle, but not at the
93b7ac65
FP
2810 * beginning of an identifier. Also, space-separated
2811 * :: is not recognised.
c6d46f5f
JB
2812 */
2813 lp += 2;
93b7ac65
FP
2814 toklen += 2;
2815 c = lp[-1];
c8b04710 2816 goto intok;
c6d46f5f
JB
2817 }
2818 else
2819 {
13fde0cd 2820 if (yacc_rules
d8913c1c 2821 || consider_token (newlb.buffer + tokoff, toklen, c,
30903246 2822 c_ext, cblev, parlev, &funorvar))
c6d46f5f 2823 {
93b7ac65
FP
2824 if (fvdef == foperator)
2825 {
2826 char *oldlp = lp;
2827 lp = skip_spaces (lp-1);
2828 if (*lp != '\0')
2829 lp += 1;
2830 while (*lp != '\0'
2831 && !isspace (*lp) && *lp != '(')
2832 lp += 1;
2833 c = *lp++;
2834 toklen += lp - oldlp;
2835 }
30903246 2836 tok.named = FALSE;
93b7ac65
FP
2837 if (!purec
2838 && funorvar
fe0b3356 2839 && definedef == dnone
93b7ac65 2840 && structdef == sinbody)
30903246 2841 /* function or var defined in C++ class body */
fe0b3356 2842 {
30903246
FP
2843 int len = strlen (structtag) + qlen + toklen;
2844 grow_linebuffer (&token_name, len + 1);
75bdbc6a 2845 strcpy (token_name.buffer, structtag);
30903246 2846 strcat (token_name.buffer, qualifier);
75bdbc6a 2847 strncat (token_name.buffer,
30903246
FP
2848 newlb.buffer + tokoff, toklen);
2849 token_name.len = len;
ee70dba5 2850 tok.named = TRUE;
c6d46f5f 2851 }
d8913c1c
FP
2852 else if (objdef == ocatseen)
2853 /* Objective C category */
2854 {
30903246
FP
2855 int len = strlen (objtag) + 2 + toklen;
2856 grow_linebuffer (&token_name, len + 1);
d8913c1c
FP
2857 strcpy (token_name.buffer, objtag);
2858 strcat (token_name.buffer, "(");
2859 strncat (token_name.buffer,
30903246 2860 newlb.buffer + tokoff, toklen);
d8913c1c 2861 strcat (token_name.buffer, ")");
30903246 2862 token_name.len = len;
d8913c1c
FP
2863 tok.named = TRUE;
2864 }
2865 else if (objdef == omethodtag
2866 || objdef == omethodparm)
2867 /* Objective C method */
2868 {
2869 tok.named = TRUE;
2870 }
c6d46f5f
JB
2871 else
2872 {
30903246 2873 grow_linebuffer (&token_name, toklen + 1);
75bdbc6a 2874 strncpy (token_name.buffer,
30903246 2875 newlb.buffer + tokoff, toklen);
75bdbc6a 2876 token_name.buffer[toklen] = '\0';
30903246 2877 token_name.len = toklen;
93b7ac65 2878 /* Name macros and members. */
30903246 2879 tok.named = (structdef == stagseen
93b7ac65 2880 || typdef == ttypeseen
30903246
FP
2881 || typdef == tend
2882 || (funorvar
93b7ac65
FP
2883 && definedef == dignorerest)
2884 || (funorvar
2885 && definedef == dnone
2886 && structdef == sinbody));
c6d46f5f 2887 }
55597f90
FP
2888 tok.lineno = lineno;
2889 tok.linelen = tokoff + toklen + 1;
2bd88040
FP
2890 tok.buffer = newlb.buffer;
2891 tok.linepos = newlinepos;
75bdbc6a 2892 tok.valid = TRUE;
fe0b3356 2893
b12756c8 2894 if (definedef == dnone
30903246 2895 && (fvdef == fvnameseen
93b7ac65 2896 || fvdef == foperator
b12756c8 2897 || structdef == stagseen
d8913c1c
FP
2898 || typdef == tend
2899 || objdef != onone))
13fde0cd 2900 {
55597f90
FP
2901 if (current_lb_is_new)
2902 switch_line_buffers ();
13fde0cd
RS
2903 }
2904 else
30903246 2905 make_C_tag (funorvar);
c6d46f5f
JB
2906 }
2907 midtoken = FALSE;
2908 }
13fde0cd 2909 } /* if (endtoken (c)) */
c6d46f5f 2910 else if (intoken (c))
c8b04710 2911 intok:
13fde0cd
RS
2912 {
2913 toklen++;
2914 continue;
2915 }
2916 } /* if (midtoken) */
c6d46f5f
JB
2917 else if (begtoken (c))
2918 {
b12756c8 2919 switch (definedef)
13fde0cd 2920 {
b12756c8 2921 case dnone:
30903246 2922 switch (fvdef)
b12756c8
FP
2923 {
2924 case fstartlist:
30903246 2925 fvdef = finlist;
b12756c8
FP
2926 continue;
2927 case flistseen:
30903246
FP
2928 make_C_tag (TRUE); /* a function */
2929 fvdef = fignore;
b12756c8 2930 break;
30903246
FP
2931 case fvnameseen:
2932 fvdef = fvnone;
b12756c8
FP
2933 break;
2934 }
cec68fcb 2935 if (structdef == stagseen && !cjava)
b12756c8 2936 structdef = snone;
13fde0cd 2937 break;
b12756c8 2938 case dsharpseen:
4b533b5b 2939 savetok = tok;
13fde0cd 2940 }
13fde0cd
RS
2941 if (!yacc_rules || lp == newlb.buffer + 1)
2942 {
2943 tokoff = lp - 1 - newlb.buffer;
2944 toklen = 1;
2945 midtoken = TRUE;
2946 }
2947 continue;
4b533b5b 2948 } /* if (begtoken) */
13fde0cd
RS
2949 } /* if must look at token */
2950
2951
2952 /* Detect end of line, colon, comma, semicolon and various braces
b12756c8 2953 after having handled a token.*/
13fde0cd 2954 switch (c)
1e134a5f 2955 {
13fde0cd 2956 case ':':
b12756c8
FP
2957 if (definedef != dnone)
2958 break;
d8913c1c
FP
2959 switch (objdef)
2960 {
2961 case otagseen:
2962 objdef = oignore;
30903246 2963 make_C_tag (TRUE); /* an Objective C class */
d8913c1c
FP
2964 break;
2965 case omethodtag:
2966 case omethodparm:
2967 objdef = omethodcolon;
2968 methodlen += 1;
30903246 2969 grow_linebuffer (&token_name, methodlen + 1);
d8913c1c 2970 strcat (token_name.buffer, ":");
30903246 2971 token_name.len = methodlen;
d8913c1c
FP
2972 break;
2973 }
13fde0cd
RS
2974 if (structdef == stagseen)
2975 structdef = scolonseen;
b12756c8 2976 else
30903246 2977 switch (fvdef)
b12756c8 2978 {
30903246 2979 case fvnameseen:
b12756c8
FP
2980 if (yacc_rules)
2981 {
30903246
FP
2982 make_C_tag (FALSE); /* a yacc function */
2983 fvdef = fignore;
b12756c8
FP
2984 }
2985 break;
2986 case fstartlist:
93b7ac65 2987 fvextern = FALSE;
30903246 2988 fvdef = fvnone;
b12756c8
FP
2989 break;
2990 }
13fde0cd
RS
2991 break;
2992 case ';':
b12756c8
FP
2993 if (definedef != dnone)
2994 break;
46c145db
FP
2995 if (cblev == 0)
2996 switch (typdef)
2997 {
2998 case tend:
30903246 2999 make_C_tag (FALSE); /* a typedef */
46c145db
FP
3000 /* FALLTHRU */
3001 default:
3002 typdef = tnone;
3003 }
30903246 3004 switch (fvdef)
1f638249 3005 {
30903246
FP
3006 case fignore:
3007 break;
3008 case fvnameseen:
93b7ac65
FP
3009 if ((members && cblev == 1)
3010 || (globals && cblev == 0 && (!fvextern || declarations)))
30903246 3011 make_C_tag (FALSE); /* a variable */
93b7ac65
FP
3012 fvextern = FALSE;
3013 fvdef = fvnone;
3014 tok.valid = FALSE;
3015 break;
3016 case flistseen:
3017 if (declarations && (cblev == 0 || cblev == 1))
3018 make_C_tag (TRUE); /* a function declaration */
30903246
FP
3019 /* FALLTHRU */
3020 default:
93b7ac65 3021 fvextern = FALSE;
30903246 3022 fvdef = fvnone;
1f638249
FP
3023 /* The following instruction invalidates the token.
3024 Probably the token should be invalidated in all
3025 other cases where some state machine is reset. */
3026 tok.valid = FALSE;
3027 }
46c145db
FP
3028 if (structdef == stagseen)
3029 structdef = snone;
3030 break;
13fde0cd 3031 case ',':
46c145db
FP
3032 if (definedef != dnone)
3033 break;
d8913c1c
FP
3034 switch (objdef)
3035 {
3036 case omethodtag:
3037 case omethodparm:
30903246 3038 make_C_tag (TRUE); /* an Objective C method */
d8913c1c
FP
3039 objdef = oinbody;
3040 break;
3041 }
30903246
FP
3042 switch (fvdef)
3043 {
93b7ac65 3044 case foperator:
30903246
FP
3045 case finlist:
3046 case fignore:
3047 case vignore:
3048 break;
3049 case fvnameseen:
93b7ac65
FP
3050 if ((members && cblev == 1)
3051 || (globals && cblev == 0 && (!fvextern || declarations)))
30903246
FP
3052 make_C_tag (FALSE); /* a variable */
3053 break;
3054 default:
3055 fvdef = fvnone;
3056 }
46c145db
FP
3057 if (structdef == stagseen)
3058 structdef = snone;
3059 break;
13fde0cd 3060 case '[':
b12756c8
FP
3061 if (definedef != dnone)
3062 break;
46c145db
FP
3063 if (cblev == 0 && typdef == tend)
3064 {
3065 typdef = tignore;
30903246 3066 make_C_tag (FALSE); /* a typedef */
46c145db
FP
3067 break;
3068 }
30903246
FP
3069 switch (fvdef)
3070 {
93b7ac65 3071 case foperator:
30903246
FP
3072 case finlist:
3073 case fignore:
3074 case vignore:
3075 break;
3076 case fvnameseen:
93b7ac65
FP
3077 if ((members && cblev == 1)
3078 || (globals && cblev == 0 && (!fvextern || declarations)))
30903246
FP
3079 make_C_tag (FALSE); /* a variable */
3080 /* FALLTHRU */
3081 default:
3082 fvdef = fvnone;
3083 }
13fde0cd
RS
3084 if (structdef == stagseen)
3085 structdef = snone;
3086 break;
3087 case '(':
b12756c8
FP
3088 if (definedef != dnone)
3089 break;
d8913c1c
FP
3090 if (objdef == otagseen && parlev == 0)
3091 objdef = oparenseen;
30903246 3092 switch (fvdef)
57e83cfe 3093 {
30903246 3094 case fvnameseen:
93b7ac65
FP
3095 if (typdef == ttypeseen
3096 && tok.valid
3097 && *lp != '*'
3098 && structdef != sinbody)
3099 {
3100 /* This handles constructs like:
3101 typedef void OperatorFun (int fun); */
3102 make_C_tag (FALSE);
3103 typdef = tignore;
3104 }
3105 /* FALLTHRU */
3106 case foperator:
3107 fvdef = fstartlist;
13fde0cd 3108 break;
13fde0cd 3109 case flistseen:
30903246 3110 fvdef = finlist;
13fde0cd 3111 break;
57e83cfe 3112 }
b12756c8 3113 parlev++;
13fde0cd
RS
3114 break;
3115 case ')':
b12756c8
FP
3116 if (definedef != dnone)
3117 break;
d8913c1c
FP
3118 if (objdef == ocatseen && parlev == 1)
3119 {
30903246 3120 make_C_tag (TRUE); /* an Objective C category */
d8913c1c
FP
3121 objdef = oignore;
3122 }
b12756c8
FP
3123 if (--parlev == 0)
3124 {
30903246 3125 switch (fvdef)
b12756c8
FP
3126 {
3127 case fstartlist:
3128 case finlist:
30903246 3129 fvdef = flistseen;
b12756c8
FP
3130 break;
3131 }
93b7ac65 3132 if (cblev == 0 && (typdef == tend))
46c145db
FP
3133 {
3134 typdef = tignore;
30903246 3135 make_C_tag (FALSE); /* a typedef */
46c145db 3136 }
b12756c8
FP
3137 }
3138 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3139 parlev = 0;
13fde0cd
RS
3140 break;
3141 case '{':
b12756c8
FP
3142 if (definedef != dnone)
3143 break;
93b7ac65 3144 if (typdef == ttypeseen)
13fde0cd
RS
3145 typdef = tinbody;
3146 switch (structdef)
3147 {
3148 case skeyseen: /* unnamed struct */
13fde0cd 3149 structdef = sinbody;
3ca80e28 3150 structtag = "_anonymous_";
13fde0cd
RS
3151 break;
3152 case stagseen:
3153 case scolonseen: /* named struct */
3154 structdef = sinbody;
30903246 3155 make_C_tag (FALSE); /* a struct */
13fde0cd
RS
3156 break;
3157 }
30903246 3158 switch (fvdef)
31d4b314
FP
3159 {
3160 case flistseen:
30903246 3161 make_C_tag (TRUE); /* a function */
31d4b314
FP
3162 /* FALLTHRU */
3163 case fignore:
30903246 3164 fvdef = fvnone;
46c145db 3165 break;
30903246 3166 case fvnone:
d8913c1c
FP
3167 switch (objdef)
3168 {
3169 case otagseen:
30903246 3170 make_C_tag (TRUE); /* an Objective C class */
d8913c1c
FP
3171 objdef = oignore;
3172 break;
3173 case omethodtag:
3174 case omethodparm:
30903246 3175 make_C_tag (TRUE); /* an Objective C method */
d8913c1c
FP
3176 objdef = oinbody;
3177 break;
3178 default:
3ca80e28 3179 /* Neutralize `extern "C" {' grot. */
d8913c1c
FP
3180 if (cblev == 0 && structdef == snone && typdef == tnone)
3181 cblev = -1;
3182 }
31d4b314 3183 }
591fa824 3184 cblev++;
31d4b314 3185 break;
13fde0cd 3186 case '*':
b12756c8
FP
3187 if (definedef != dnone)
3188 break;
30903246
FP
3189 if (fvdef == fstartlist)
3190 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
13fde0cd
RS
3191 break;
3192 case '}':
b12756c8
FP
3193 if (definedef != dnone)
3194 break;
13fde0cd 3195 if (!noindentypedefs && lp == newlb.buffer + 1)
b12756c8
FP
3196 {
3197 cblev = 0; /* reset curly brace level if first column */
3198 parlev = 0; /* also reset paren level, just in case... */
3199 }
591fa824
RS
3200 else if (cblev > 0)
3201 cblev--;
3202 if (cblev == 0)
13fde0cd
RS
3203 {
3204 if (typdef == tinbody)
3205 typdef = tend;
c5007f46
FP
3206 /* Memory leakage here: the string pointed by structtag is
3207 never released, because I fear to miss something and
3208 break things while freeing the area. The amount of
15294654 3209 memory leaked here is the sum of the lengths of the
c5007f46
FP
3210 struct tags.
3211 if (structdef == sinbody)
3212 free (structtag); */
9cb0aa73 3213
13fde0cd 3214 structdef = snone;
55597f90 3215 structtag = "<error>";
13fde0cd
RS
3216 }
3217 break;
30903246
FP
3218 case '=':
3219 if (definedef != dnone)
3220 break;
3221 switch (fvdef)
3222 {
93b7ac65 3223 case foperator:
30903246
FP
3224 case finlist:
3225 case fignore:
3226 case vignore:
3227 break;
3228 case fvnameseen:
93b7ac65
FP
3229 if ((members && cblev == 1)
3230 || (globals && cblev == 0 && (!fvextern || declarations)))
30903246
FP
3231 make_C_tag (FALSE); /* a variable */
3232 /* FALLTHRU */
3233 default:
3234 fvdef = vignore;
3235 }
3236 break;
d8913c1c
FP
3237 case '+':
3238 case '-':
3239 if (objdef == oinbody && cblev == 0)
3240 {
3241 objdef = omethodsign;
3242 break;
3243 }
3244 /* FALLTHRU */
30903246
FP
3245 case '#': case '~': case '&': case '%': case '/': case '|':
3246 case '^': case '!': case '<': case '>': case '.': case '?': case ']':
b12756c8
FP
3247 if (definedef != dnone)
3248 break;
93b7ac65
FP
3249 /* These surely cannot follow a function tag in C. */
3250 switch (fvdef)
3251 {
3252 case foperator:
3253 case finlist:
3254 case fignore:
3255 case vignore:
3256 break;
3257 default:
3258 fvdef = fvnone;
3259 }
b12756c8 3260 break;
13fde0cd 3261 case '\0':
d8913c1c
FP
3262 if (objdef == otagseen)
3263 {
30903246 3264 make_C_tag (TRUE); /* an Objective C class */
d8913c1c
FP
3265 objdef = oignore;
3266 }
13fde0cd
RS
3267 /* If a macro spans multiple lines don't reset its state. */
3268 if (quotednl)
93b7ac65 3269 CNL_SAVE_DEFINEDEF ();
13fde0cd 3270 else
93b7ac65 3271 CNL ();
13fde0cd
RS
3272 break;
3273 } /* switch (c) */
3274
3275 } /* while not eof */
c6d46f5f 3276}
b9755a12
FP
3277
3278/*
3279 * Process either a C++ file or a C file depending on the setting
3280 * of a global flag.
3281 */
944bdd72 3282static void
b9755a12
FP
3283default_C_entries (inf)
3284 FILE *inf;
3285{
3286 C_entries (cplusplus ? C_PLPL : 0, inf);
3287}
3288
79263656 3289/* Always do plain ANSI C. */
944bdd72 3290static void
79263656
FP
3291plain_C_entries (inf)
3292 FILE *inf;
3293{
3294 C_entries (0, inf);
3295}
3296
b9755a12 3297/* Always do C++. */
944bdd72 3298static void
b9755a12
FP
3299Cplusplus_entries (inf)
3300 FILE *inf;
3301{
3302 C_entries (C_PLPL, inf);
3303}
3304
cec68fcb 3305/* Always do Java. */
944bdd72 3306static void
30903246
FP
3307Cjava_entries (inf)
3308 FILE *inf;
cec68fcb
FP
3309{
3310 C_entries (C_JAVA, inf);
3311}
3312
b9755a12 3313/* Always do C*. */
944bdd72 3314static void
b9755a12
FP
3315Cstar_entries (inf)
3316 FILE *inf;
3317{
3318 C_entries (C_STAR, inf);
3319}
3320
3321/* Always do Yacc. */
944bdd72 3322static void
b9755a12
FP
3323Yacc_entries (inf)
3324 FILE *inf;
3325{
3326 C_entries (YACC, inf);
3327}
6dd5561c 3328\f
93b7ac65
FP
3329/* A useful macro. */
3330#define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3331 for (lineno = charno = 0; /* loop initialization */ \
3332 !feof (file_pointer) /* loop test */ \
3333 && (lineno++, /* instructions at start of loop */ \
3334 linecharno = charno, \
3335 charno += readline (&line_buffer, file_pointer), \
3336 char_pointer = lb.buffer, \
3337 TRUE); \
3338 )
c6d46f5f 3339
93b7ac65
FP
3340
3341/*
3342 * Read a file, but do no processing. This is used to do regexp
3343 * matching on files that have no language defined.
3344 */
944bdd72 3345static void
93b7ac65
FP
3346just_read_file (inf)
3347 FILE *inf;
3348{
3349 register char *dummy;
3350
3351 LOOP_ON_INPUT_LINES (inf, lb, dummy)
3352 continue;
3353}
3354\f
3355/* Fortran parsing */
c6d46f5f 3356
944bdd72 3357static bool
6dd5561c
FP
3358tail (cp)
3359 char *cp;
c6d46f5f 3360{
6dd5561c 3361 register int len = 0;
c6d46f5f 3362
93b7ac65 3363 while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
6dd5561c 3364 cp++, len++;
93b7ac65 3365 if (*cp == '\0' && !intoken (dbp[len]))
c6d46f5f 3366 {
6dd5561c 3367 dbp += len;
b9755a12 3368 return TRUE;
c6d46f5f 3369 }
b9755a12 3370 return FALSE;
6dd5561c 3371}
13fde0cd 3372
944bdd72 3373static void
6dd5561c
FP
3374takeprec ()
3375{
93b7ac65 3376 dbp = skip_spaces (dbp);
6dd5561c
FP
3377 if (*dbp != '*')
3378 return;
3379 dbp++;
93b7ac65 3380 dbp = skip_spaces (dbp);
79263656
FP
3381 if (strneq (dbp, "(*)", 3))
3382 {
3383 dbp += 3;
3384 return;
3385 }
6dd5561c 3386 if (!isdigit (*dbp))
c6d46f5f 3387 {
6dd5561c
FP
3388 --dbp; /* force failure */
3389 return;
c6d46f5f 3390 }
6dd5561c
FP
3391 do
3392 dbp++;
3393 while (isdigit (*dbp));
3394}
13fde0cd 3395
944bdd72 3396static void
6dd5561c
FP
3397getit (inf)
3398 FILE *inf;
3399{
3400 register char *cp;
13fde0cd 3401
93b7ac65 3402 dbp = skip_spaces (dbp);
6dd5561c 3403 if (*dbp == '\0')
c6d46f5f 3404 {
6dd5561c
FP
3405 lineno++;
3406 linecharno = charno;
3407 charno += readline (&lb, inf);
3408 dbp = lb.buffer;
3409 if (dbp[5] != '&')
3410 return;
3411 dbp += 6;
93b7ac65 3412 dbp = skip_spaces (dbp);
c6d46f5f 3413 }
93b7ac65 3414 if (!isalpha (*dbp) && *dbp != '_' && *dbp != '$')
6dd5561c 3415 return;
93b7ac65 3416 for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
6dd5561c 3417 continue;
15d5b889 3418 pfnote (savenstr (dbp, cp-dbp), TRUE,
d8913c1c 3419 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f 3420}
c6d46f5f 3421
93b7ac65 3422
944bdd72 3423static void
6dd5561c
FP
3424Fortran_functions (inf)
3425 FILE *inf;
c6d46f5f 3426{
93b7ac65 3427 LOOP_ON_INPUT_LINES (inf, lb, dbp)
c6d46f5f 3428 {
c6d46f5f
JB
3429 if (*dbp == '%')
3430 dbp++; /* Ratfor escape to fortran */
93b7ac65 3431 dbp = skip_spaces (dbp);
108c932a 3432 if (*dbp == '\0')
c6d46f5f 3433 continue;
79263656 3434 switch (lowcase (*dbp))
c6d46f5f
JB
3435 {
3436 case 'i':
3437 if (tail ("integer"))
3438 takeprec ();
3439 break;
3440 case 'r':
3441 if (tail ("real"))
3442 takeprec ();
3443 break;
3444 case 'l':
3445 if (tail ("logical"))
3446 takeprec ();
3447 break;
3448 case 'c':
3449 if (tail ("complex") || tail ("character"))
3450 takeprec ();
3451 break;
3452 case 'd':
3453 if (tail ("double"))
3454 {
93b7ac65 3455 dbp = skip_spaces (dbp);
108c932a 3456 if (*dbp == '\0')
c6d46f5f
JB
3457 continue;
3458 if (tail ("precision"))
3459 break;
3460 continue;
3461 }
3462 break;
3463 }
93b7ac65 3464 dbp = skip_spaces (dbp);
108c932a 3465 if (*dbp == '\0')
c6d46f5f 3466 continue;
79263656 3467 switch (lowcase (*dbp))
c6d46f5f
JB
3468 {
3469 case 'f':
3470 if (tail ("function"))
6dd5561c 3471 getit (inf);
c6d46f5f
JB
3472 continue;
3473 case 's':
3474 if (tail ("subroutine"))
6dd5561c 3475 getit (inf);
c6d46f5f 3476 continue;
8a6c8bcf
RS
3477 case 'e':
3478 if (tail ("entry"))
6dd5561c 3479 getit (inf);
8a6c8bcf 3480 continue;
15d5b889
RS
3481 case 'b':
3482 if (tail ("blockdata") || tail ("block data"))
3483 {
93b7ac65 3484 dbp = skip_spaces (dbp);
15d5b889 3485 if (*dbp == '\0') /* assume un-named */
93b7ac65
FP
3486 pfnote (savestr ("blockdata"), TRUE,
3487 lb.buffer, dbp - lb.buffer, lineno, linecharno);
15d5b889
RS
3488 else
3489 getit (inf); /* look for name */
3490 }
3491 continue;
c6d46f5f
JB
3492 }
3493 }
c6d46f5f 3494}
6dd5561c 3495\f
93b7ac65
FP
3496/*
3497 * Philippe Waroquiers <philippe.waroquiers@eurocontrol.be>, 1998-04-24
3498 * Ada parsing
3499 */
3500/* Once we are positioned after an "interesting" keyword, let's get
3501 the real tag value necessary. */
944bdd72 3502static void
93b7ac65
FP
3503adagetit (inf, name_qualifier)
3504 FILE *inf;
3505 char *name_qualifier;
3506{
3507 register char *cp;
3508 char *name;
3509 char c;
3510
3511 while (!feof (inf))
3512 {
3513 dbp = skip_spaces (dbp);
3514 if (*dbp == '\0'
3515 || (dbp[0] == '-' && dbp[1] == '-'))
3516 {
3517 lineno++;
3518 linecharno = charno;
3519 charno += readline (&lb, inf);
3520 dbp = lb.buffer;
3521 }
3522 switch (*dbp)
3523 {
3524 case 'b':
3525 case 'B':
3526 if (tail ("body"))
3527 {
3528 /* Skipping body of procedure body or package body or ....
3529 resetting qualifier to body instead of spec. */
3530 name_qualifier = "/b";
3531 continue;
3532 }
3533 break;
3534 case 't':
3535 case 'T':
3536 /* Skipping type of task type or protected type ... */
3537 if (tail ("type"))
3538 continue;
3539 break;
3540 }
3541 if (*dbp == '"')
3542 {
3543 dbp += 1;
3544 for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
3545 continue;
3546 }
3547 else
3548 {
3549 dbp = skip_spaces (dbp);
3550 for (cp = dbp;
3551 (*cp != '\0'
3552 && (isalpha (*cp) || isdigit (*cp) || *cp == '_' || *cp == '.'));
3553 cp++)
3554 continue;
3555 if (cp == dbp)
3556 return;
3557 }
3558 c = *cp;
3559 *cp = '\0';
3560 name = concat (dbp, name_qualifier, "");
3561 *cp = c;
3562 pfnote (name, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3563 if (c == '"')
3564 dbp = cp + 1;
3565 return;
3566 }
3567}
3568
944bdd72 3569static void
93b7ac65
FP
3570Ada_funcs (inf)
3571 FILE *inf;
3572{
3573 bool inquote = FALSE;
3574
3575 LOOP_ON_INPUT_LINES (inf, lb, dbp)
3576 {
3577 while (*dbp != '\0')
3578 {
3579 /* Skip a string i.e. "abcd". */
3580 if (inquote || (*dbp == '"'))
3581 {
3582 dbp = etags_strchr ((inquote) ? dbp : dbp+1, '"');
3583 if (dbp != NULL)
3584 {
3585 inquote = FALSE;
3586 dbp += 1;
3587 continue; /* advance char */
3588 }
3589 else
3590 {
3591 inquote = TRUE;
3592 break; /* advance line */
3593 }
3594 }
3595
3596 /* Skip comments. */
3597 if (dbp[0] == '-' && dbp[1] == '-')
3598 break; /* advance line */
3599
3600 /* Skip character enclosed in single quote i.e. 'a'
3601 and skip single quote starting an attribute i.e. 'Image. */
3602 if (*dbp == '\'')
3603 {
3604 dbp++ ;
3605 if (*dbp != '\0')
3606 dbp++;
3607 continue;
3608 }
3609
3610 /* Search for beginning of a token. */
3611 if (!begtoken (*dbp))
3612 {
3613 dbp++;
3614 continue; /* advance char */
3615 }
3616
3617 /* We are at the beginning of a token. */
3618 switch (*dbp)
3619 {
3620 case 'f':
3621 case 'F':
3622 if (!packages_only && tail ("function"))
3623 adagetit (inf, "/f");
3624 else
3625 break; /* from switch */
3626 continue; /* advance char */
3627 case 'p':
3628 case 'P':
3629 if (!packages_only && tail ("procedure"))
3630 adagetit (inf, "/p");
3631 else if (tail ("package"))
3632 adagetit (inf, "/s");
3633 else if (tail ("protected")) /* protected type */
3634 adagetit (inf, "/t");
3635 else
3636 break; /* from switch */
3637 continue; /* advance char */
3638 case 't':
3639 case 'T':
3640 if (!packages_only && tail ("task"))
3641 adagetit (inf, "/k");
3642 else if (typedefs && !packages_only && tail ("type"))
3643 {
3644 adagetit (inf, "/t");
3645 while (*dbp != '\0')
3646 dbp += 1;
3647 }
3648 else
3649 break; /* from switch */
3650 continue; /* advance char */
3651 }
3652
3653 /* Look for the end of the token. */
3654 while (!endtoken (*dbp))
3655 dbp++;
3656
3657 } /* advance char */
3658 } /* advance line */
3659}
3660\f
6dd5561c
FP
3661/*
3662 * Bob Weiner, Motorola Inc., 4/3/94
3663 * Unix and microcontroller assembly tag handling
3664 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3665 */
944bdd72 3666static void
6dd5561c
FP
3667Asm_labels (inf)
3668 FILE *inf;
c6d46f5f
JB
3669{
3670 register char *cp;
c6d46f5f 3671
93b7ac65 3672 LOOP_ON_INPUT_LINES (inf, lb, cp)
c6d46f5f 3673 {
6dd5561c
FP
3674 /* If first char is alphabetic or one of [_.$], test for colon
3675 following identifier. */
3676 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3677 {
3678 /* Read past label. */
3679 cp++;
3680 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3681 cp++;
3682 if (*cp == ':' || isspace (*cp))
3683 {
3684 /* Found end of label, so copy it and add it to the table. */
15d5b889 3685 pfnote (savenstr(lb.buffer, cp-lb.buffer), TRUE,
55597f90 3686 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
6dd5561c
FP
3687 }
3688 }
c6d46f5f
JB
3689 }
3690}
3691\f
1f638249
FP
3692/*
3693 * Perl support by Bart Robinson <lomew@cs.utah.edu>
93b7ac65 3694 * enhanced by Michael Ernst <mernst@alum.mit.edu>
1f638249 3695 * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
93b7ac65 3696 * Perl variable names: /^(my|local).../
1f638249 3697 */
944bdd72 3698static void
1f638249
FP
3699Perl_functions (inf)
3700 FILE *inf;
3701{
3702 register char *cp;
3703
93b7ac65 3704 LOOP_ON_INPUT_LINES (inf, lb, cp)
1f638249 3705 {
93b7ac65
FP
3706 if (*cp++ == 's'
3707 && *cp++ == 'u'
3708 && *cp++ == 'b' && isspace (*cp++))
3709 {
3710 cp = skip_spaces (cp);
3711 if (*cp != '\0')
3712 {
3713 char *sp = cp;
3714 while (*cp != '\0'
3715 && !isspace (*cp) && *cp != '{' && *cp != '(')
3716 cp++;
3717 pfnote (savenstr (sp, cp-sp), TRUE,
3718 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3719 }
3720 }
3721 else if (globals /* only if tagging global vars is enabled */
3722 && ((cp = lb.buffer,
3723 *cp++ == 'm'
3724 && *cp++ == 'y')
3725 || (cp = lb.buffer,
3726 *cp++ == 'l'
3727 && *cp++ == 'o'
3728 && *cp++ == 'c'
3729 && *cp++ == 'a'
3730 && *cp++ == 'l'))
3731 && (*cp == '(' || isspace (*cp)))
3732 {
3733 /* After "my" or "local", but before any following paren or space. */
3734 char *varname = NULL;
1f638249 3735
93b7ac65
FP
3736 cp = skip_spaces (cp);
3737 if (*cp == '$' || *cp == '@' || *cp == '%')
3738 {
3739 char* varstart = ++cp;
3740 while (isalnum (*cp) || *cp == '_')
3741 cp++;
3742 varname = savenstr (varstart, cp-varstart);
3743 }
3744 else
3745 {
3746 /* Should be examining a variable list at this point;
3747 could insist on seeing an open parenthesis. */
3748 while (*cp != '\0' && *cp != ';' && *cp != '=' && *cp != ')')
3749 cp++;
3750 }
3751
3752 /* Perhaps I should back cp up one character, so the TAGS table
3753 doesn't mention (and so depend upon) the following char. */
3754 pfnote ((CTAGS) ? savenstr (lb.buffer, cp-lb.buffer) : varname,
3755 FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3756 }
3757 }
3758}
3759\f
3760/*
3761 * Python support by Eric S. Raymond <esr@thyrsus.com>
3762 * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3763 */
944bdd72 3764static void
93b7ac65
FP
3765Python_functions (inf)
3766 FILE *inf;
3767{
3768 register char *cp;
3769
3770 LOOP_ON_INPUT_LINES (inf, lb, cp)
3771 {
3772 if (*cp++ == 'd'
3773 && *cp++ == 'e'
3774 && *cp++ == 'f' && isspace (*cp++))
1f638249 3775 {
93b7ac65
FP
3776 cp = skip_spaces (cp);
3777 while (*cp != '\0' && !isspace (*cp) && *cp != '(' && *cp != ':')
1f638249 3778 cp++;
93b7ac65
FP
3779 pfnote (NULL, TRUE,
3780 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3781 }
3782
3783 cp = lb.buffer;
3784 if (*cp++ == 'c'
3785 && *cp++ == 'l'
3786 && *cp++ == 'a'
3787 && *cp++ == 's'
3788 && *cp++ == 's' && isspace (*cp++))
3789 {
3790 cp = skip_spaces (cp);
3791 while (*cp != '\0' && !isspace (*cp) && *cp != '(' && *cp != ':')
1f638249 3792 cp++;
93b7ac65 3793 pfnote (NULL, TRUE,
1f638249
FP
3794 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3795 }
3796 }
3797}
3798\f
30903246
FP
3799/* Idea by Corny de Souza
3800 * Cobol tag functions
3801 * We could look for anything that could be a paragraph name.
3802 * i.e. anything that starts in column 8 is one word and ends in a full stop.
3803 */
944bdd72 3804static void
30903246
FP
3805Cobol_paragraphs (inf)
3806 FILE *inf;
3807{
93b7ac65 3808 register char *bp, *ep;
30903246 3809
93b7ac65 3810 LOOP_ON_INPUT_LINES (inf, lb, bp)
30903246 3811 {
30903246
FP
3812 if (lb.len < 9)
3813 continue;
93b7ac65 3814 bp += 8;
30903246
FP
3815
3816 /* If eoln, compiler option or comment ignore whole line. */
93b7ac65 3817 if (bp[-1] != ' ' || !isalnum (bp[0]))
30903246
FP
3818 continue;
3819
93b7ac65 3820 for (ep = bp; isalnum (*ep) || *ep == '-'; ep++)
30903246 3821 continue;
93b7ac65
FP
3822 if (*ep++ == '.')
3823 pfnote (savenstr (bp, ep-bp), TRUE,
3824 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
30903246
FP
3825 }
3826}
3827\f
c6d46f5f
JB
3828/* Added by Mosur Mohan, 4/22/88 */
3829/* Pascal parsing */
3830
aab1fdae
FP
3831/*
3832 * Locates tags for procedures & functions. Doesn't do any type- or
3833 * var-definitions. It does look for the keyword "extern" or
3834 * "forward" immediately following the procedure statement; if found,
3835 * the tag is skipped.
c6d46f5f 3836 */
944bdd72 3837static void
6dd5561c
FP
3838Pascal_functions (inf)
3839 FILE *inf;
c6d46f5f 3840{
93b7ac65 3841 linebuffer tline; /* mostly copied from C_entries */
c6d46f5f 3842 long save_lcno;
108c932a 3843 int save_lineno, save_len;
d8913c1c 3844 char c, *cp, *namebuf;
c6d46f5f 3845
30903246 3846 bool /* each of these flags is TRUE iff: */
b9755a12 3847 incomment, /* point is inside a comment */
c6d46f5f 3848 inquote, /* point is inside '..' string */
108c932a
FP
3849 get_tagname, /* point is after PROCEDURE/FUNCTION
3850 keyword, so next item = potential tag */
c6d46f5f
JB
3851 found_tag, /* point is after a potential tag */
3852 inparms, /* point is within parameter-list */
108c932a
FP
3853 verify_tag; /* point has passed the parm-list, so the
3854 next token will determine whether this
3855 is a FORWARD/EXTERN to be ignored, or
3856 whether it is a real tag */
c6d46f5f 3857
93b7ac65
FP
3858 save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3859 namebuf = NULL; /* keep compiler quiet */
c6d46f5f
JB
3860 lineno = 0;
3861 charno = 0;
3862 dbp = lb.buffer;
108c932a 3863 *dbp = '\0';
c6d46f5f
JB
3864 initbuffer (&tline);
3865
b9755a12 3866 incomment = inquote = FALSE;
c6d46f5f
JB
3867 found_tag = FALSE; /* have a proc name; check if extern */
3868 get_tagname = FALSE; /* have found "procedure" keyword */
3869 inparms = FALSE; /* found '(' after "proc" */
3870 verify_tag = FALSE; /* check if "extern" is ahead */
3871
93b7ac65
FP
3872
3873 while (!feof (inf)) /* long main loop to get next char */
c6d46f5f
JB
3874 {
3875 c = *dbp++;
55597f90 3876 if (c == '\0') /* if end of line */
c6d46f5f 3877 {
cf347d3c
FP
3878 lineno++;
3879 linecharno = charno;
3880 charno += readline (&lb, inf);
3881 dbp = lb.buffer;
55597f90 3882 if (*dbp == '\0')
c6d46f5f 3883 continue;
93b7ac65
FP
3884 if (!((found_tag && verify_tag)
3885 || get_tagname))
108c932a
FP
3886 c = *dbp++; /* only if don't need *dbp pointing
3887 to the beginning of the name of
3888 the procedure or function */
c6d46f5f 3889 }
b9755a12 3890 if (incomment)
c6d46f5f 3891 {
108c932a 3892 if (c == '}') /* within { } comments */
b9755a12 3893 incomment = FALSE;
108c932a 3894 else if (c == '*' && *dbp == ')') /* within (* *) comments */
c6d46f5f 3895 {
b9755a12
FP
3896 dbp++;
3897 incomment = FALSE;
c6d46f5f
JB
3898 }
3899 continue;
3900 }
3901 else if (inquote)
3902 {
3903 if (c == '\'')
3904 inquote = FALSE;
3905 continue;
3906 }
55597f90 3907 else
c6d46f5f
JB
3908 switch (c)
3909 {
3910 case '\'':
3911 inquote = TRUE; /* found first quote */
3912 continue;
108c932a 3913 case '{': /* found open { comment */
b9755a12 3914 incomment = TRUE;
c6d46f5f
JB
3915 continue;
3916 case '(':
108c932a 3917 if (*dbp == '*') /* found open (* comment */
c6d46f5f 3918 {
b9755a12 3919 incomment = TRUE;
c6d46f5f
JB
3920 dbp++;
3921 }
3922 else if (found_tag) /* found '(' after tag, i.e., parm-list */
3923 inparms = TRUE;
3924 continue;
3925 case ')': /* end of parms list */
3926 if (inparms)
3927 inparms = FALSE;
3928 continue;
3929 case ';':
108c932a 3930 if (found_tag && !inparms) /* end of proc or fn stmt */
c6d46f5f
JB
3931 {
3932 verify_tag = TRUE;
3933 break;
3934 }
3935 continue;
3936 }
108c932a 3937 if (found_tag && verify_tag && (*dbp != ' '))
c6d46f5f
JB
3938 {
3939 /* check if this is an "extern" declaration */
108c932a 3940 if (*dbp == '\0')
c6d46f5f 3941 continue;
108c932a 3942 if (lowcase (*dbp == 'e'))
c6d46f5f
JB
3943 {
3944 if (tail ("extern")) /* superfluous, really! */
3945 {
3946 found_tag = FALSE;
3947 verify_tag = FALSE;
3948 }
3949 }
108c932a 3950 else if (lowcase (*dbp) == 'f')
c6d46f5f
JB
3951 {
3952 if (tail ("forward")) /* check for forward reference */
3953 {
3954 found_tag = FALSE;
3955 verify_tag = FALSE;
3956 }
3957 }
108c932a 3958 if (found_tag && verify_tag) /* not external proc, so make tag */
c6d46f5f
JB
3959 {
3960 found_tag = FALSE;
3961 verify_tag = FALSE;
d8913c1c 3962 pfnote (namebuf, TRUE,
108c932a 3963 tline.buffer, save_len, save_lineno, save_lcno);
c6d46f5f
JB
3964 continue;
3965 }
3966 }
3967 if (get_tagname) /* grab name of proc or fn */
3968 {
108c932a 3969 if (*dbp == '\0')
c6d46f5f
JB
3970 continue;
3971
3972 /* save all values for later tagging */
e0903a92 3973 grow_linebuffer (&tline, lb.len + 1);
c6d46f5f
JB
3974 strcpy (tline.buffer, lb.buffer);
3975 save_lineno = lineno;
3976 save_lcno = linecharno;
3977
3978 /* grab block name */
30903246 3979 for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
c6d46f5f 3980 continue;
15d5b889 3981 namebuf = savenstr (dbp, cp-dbp);
d8913c1c 3982 dbp = cp; /* set dbp to e-o-token */
108c932a 3983 save_len = dbp - lb.buffer + 1;
c6d46f5f
JB
3984 get_tagname = FALSE;
3985 found_tag = TRUE;
3986 continue;
3987
3988 /* and proceed to check for "extern" */
3989 }
55597f90 3990 else if (!incomment && !inquote && !found_tag)
c6d46f5f
JB
3991 {
3992 /* check for proc/fn keywords */
79263656 3993 switch (lowcase (c))
c6d46f5f
JB
3994 {
3995 case 'p':
3996 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
3997 get_tagname = TRUE;
3998 continue;
3999 case 'f':
4000 if (tail ("unction"))
4001 get_tagname = TRUE;
4002 continue;
4003 }
4004 }
6dd5561c 4005 } /* while not eof */
c5007f46 4006
108c932a 4007 free (tline.buffer);
c6d46f5f
JB
4008}
4009\f
4010/*
4011 * lisp tag functions
55597f90 4012 * look for (def or (DEF, quote or QUOTE
c6d46f5f 4013 */
944bdd72 4014static int
55597f90
FP
4015L_isdef (strp)
4016 register char *strp;
c6d46f5f 4017{
55597f90
FP
4018 return ((strp[1] == 'd' || strp[1] == 'D')
4019 && (strp[2] == 'e' || strp[2] == 'E')
4020 && (strp[3] == 'f' || strp[3] == 'F'));
31d4b314
FP
4021}
4022
944bdd72 4023static int
55597f90
FP
4024L_isquote (strp)
4025 register char *strp;
4026{
93b7ac65
FP
4027 return ((*++strp == 'q' || *strp == 'Q')
4028 && (*++strp == 'u' || *strp == 'U')
4029 && (*++strp == 'o' || *strp == 'O')
4030 && (*++strp == 't' || *strp == 'T')
4031 && (*++strp == 'e' || *strp == 'E')
4032 && isspace (*++strp));
c6d46f5f
JB
4033}
4034
944bdd72 4035static void
c6d46f5f
JB
4036L_getit ()
4037{
4038 register char *cp;
c6d46f5f 4039
31d4b314
FP
4040 if (*dbp == '\'') /* Skip prefix quote */
4041 dbp++;
93b7ac65 4042 else if (*dbp == '(')
31d4b314 4043 {
93b7ac65
FP
4044 if (L_isquote (dbp))
4045 dbp += 7; /* Skip "(quote " */
4046 else
4047 dbp += 1; /* Skip "(" before name in (defstruct (foo)) */
4048 dbp = skip_spaces (dbp);
31d4b314 4049 }
93b7ac65 4050
55597f90 4051 for (cp = dbp /*+1*/;
93b7ac65 4052 *cp != '\0' && *cp != '(' && !isspace(*cp) && *cp != ')';
55597f90 4053 cp++)
c6d46f5f 4054 continue;
31d4b314
FP
4055 if (cp == dbp)
4056 return;
c5007f46 4057
a6351b48 4058 pfnote (savenstr (dbp, cp-dbp), TRUE,
d8913c1c 4059 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f 4060}
6dd5561c 4061
944bdd72 4062static void
6dd5561c
FP
4063Lisp_functions (inf)
4064 FILE *inf;
4065{
93b7ac65 4066 LOOP_ON_INPUT_LINES (inf, lb, dbp)
6dd5561c 4067 {
6dd5561c
FP
4068 if (dbp[0] == '(')
4069 {
4070 if (L_isdef (dbp))
4071 {
93b7ac65
FP
4072 dbp = skip_non_spaces (dbp);
4073 dbp = skip_spaces (dbp);
6dd5561c
FP
4074 L_getit ();
4075 }
4076 else
4077 {
4078 /* Check for (foo::defmumble name-defined ... */
4079 do
4080 dbp++;
93b7ac65 4081 while (*dbp != '\0' && !isspace (*dbp)
6dd5561c
FP
4082 && *dbp != ':' && *dbp != '(' && *dbp != ')');
4083 if (*dbp == ':')
4084 {
4085 do
4086 dbp++;
4087 while (*dbp == ':');
4088
4089 if (L_isdef (dbp - 1))
4090 {
93b7ac65
FP
4091 dbp = skip_non_spaces (dbp);
4092 dbp = skip_spaces (dbp);
6dd5561c
FP
4093 L_getit ();
4094 }
4095 }
4096 }
4097 }
4098 }
4099}
c6d46f5f 4100\f
cec68fcb
FP
4101/*
4102 * Postscript tag functions
4103 * Just look for lines where the first character is '/'
b7e22e94 4104 * Richard Mlynarik <mly@adoc.xerox.com>
93b7ac65
FP
4105 * Also look at "defineps" for PSWrap
4106 * suggested by Masatake YAMATO <masata-y@is.aist-nara.ac.jp>
cec68fcb 4107 */
944bdd72 4108static void
cec68fcb
FP
4109Postscript_functions (inf)
4110 FILE *inf;
4111{
93b7ac65 4112 register char *bp, *ep;
30903246 4113
93b7ac65 4114 LOOP_ON_INPUT_LINES (inf, lb, bp)
cec68fcb 4115 {
93b7ac65 4116 if (bp[0] == '/')
cec68fcb 4117 {
93b7ac65
FP
4118 for (ep = bp+1;
4119 *ep != '\0' && *ep != ' ' && *ep != '{';
4120 ep++)
cec68fcb 4121 continue;
93b7ac65
FP
4122 pfnote (savenstr (bp, ep-bp), TRUE,
4123 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4124 }
4125 else if (strneq (bp, "defineps", 8))
4126 {
4127 bp = skip_non_spaces (bp);
4128 bp = skip_spaces (bp);
4129 get_tag (bp);
cec68fcb
FP
4130 }
4131 }
4132}
4133
4134\f
c6d46f5f
JB
4135/*
4136 * Scheme tag functions
4137 * look for (def... xyzzy
4138 * look for (def... (xyzzy
4139 * look for (def ... ((...(xyzzy ....
4140 * look for (set! xyzzy
4141 */
4142
944bdd72 4143static void
6dd5561c
FP
4144Scheme_functions (inf)
4145 FILE *inf;
c6d46f5f 4146{
93b7ac65 4147 register char *bp;
c6d46f5f 4148
93b7ac65 4149 LOOP_ON_INPUT_LINES (inf, lb, bp)
c6d46f5f 4150 {
93b7ac65
FP
4151 if (bp[0] == '('
4152 && (bp[1] == 'D' || bp[1] == 'd')
4153 && (bp[2] == 'E' || bp[2] == 'e')
4154 && (bp[3] == 'F' || bp[3] == 'f'))
c6d46f5f 4155 {
93b7ac65 4156 bp = skip_non_spaces (bp);
c6d46f5f 4157 /* Skip over open parens and white space */
93b7ac65
FP
4158 while (isspace (*bp) || *bp == '(')
4159 bp++;
4160 get_tag (bp);
c6d46f5f 4161 }
93b7ac65
FP
4162 if (bp[0] == '('
4163 && (bp[1] == 'S' || bp[1] == 's')
4164 && (bp[2] == 'E' || bp[2] == 'e')
4165 && (bp[3] == 'T' || bp[3] == 't')
4166 && (bp[4] == '!' || bp[4] == '!')
4167 && (isspace (bp[5])))
c6d46f5f 4168 {
93b7ac65
FP
4169 bp = skip_non_spaces (bp);
4170 bp = skip_spaces (bp);
4171 get_tag (bp);
c6d46f5f
JB
4172 }
4173 }
4174}
c6d46f5f
JB
4175\f
4176/* Find tags in TeX and LaTeX input files. */
4177
4178/* TEX_toktab is a table of TeX control sequences that define tags.
4179 Each TEX_tabent records one such control sequence.
4180 CONVERT THIS TO USE THE Stab TYPE!! */
c6d46f5f
JB
4181struct TEX_tabent
4182{
4183 char *name;
4184 int len;
4185};
4186
4187struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
4188
4189/* Default set of control sequences to put into TEX_toktab.
4190 The value of environment var TEXTAGS is prepended to this. */
4191
6dd5561c 4192char *TEX_defenv = "\
c5007f46
FP
4193:chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4194:part:appendix:entry:index";
c6d46f5f 4195
944bdd72
FP
4196static void TEX_mode P_((FILE *inf));
4197static struct TEX_tabent *TEX_decode_env P_((char *evarname, char *defenv));
4198static int TEX_Token P_((char *cp));
c6d46f5f 4199
6dd5561c
FP
4200char TEX_esc = '\\';
4201char TEX_opgrp = '{';
4202char TEX_clgrp = '}';
c6d46f5f
JB
4203
4204/*
4205 * TeX/LaTeX scanning loop.
4206 */
944bdd72 4207static void
6dd5561c
FP
4208TeX_functions (inf)
4209 FILE *inf;
c6d46f5f 4210{
93b7ac65 4211 char *cp, *lasthit;
30903246 4212 register int i;
c6d46f5f 4213
c6d46f5f 4214 /* Select either \ or ! as escape character. */
6dd5561c 4215 TEX_mode (inf);
c6d46f5f
JB
4216
4217 /* Initialize token table once from environment. */
4218 if (!TEX_toktab)
4219 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
4220
93b7ac65
FP
4221 LOOP_ON_INPUT_LINES (inf, lb, cp)
4222 {
4223 lasthit = cp;
4224 /* Look at each esc in line. */
4225 while ((cp = etags_strchr (cp, TEX_esc)) != NULL)
8a6c8bcf 4226 {
93b7ac65 4227 if (*++cp == '\0')
8a6c8bcf 4228 break;
93b7ac65
FP
4229 linecharno += cp - lasthit;
4230 lasthit = cp;
8a6c8bcf 4231 i = TEX_Token (lasthit);
30903246 4232 if (i >= 0)
c6d46f5f 4233 {
30903246
FP
4234 /* We seem to include the TeX command in the tag name.
4235 register char *p;
4236 for (p = lasthit + TEX_toktab[i].len;
4237 *p != '\0' && *p != TEX_clgrp;
4238 p++)
4239 continue; */
4240 pfnote (/*savenstr (lasthit, p-lasthit)*/ (char *)NULL, TRUE,
e0903a92 4241 lb.buffer, lb.len, lineno, linecharno);
30903246 4242 break; /* We only tag a line once */
c6d46f5f
JB
4243 }
4244 }
4245 }
4246}
4247
4248#define TEX_LESC '\\'
4249#define TEX_SESC '!'
4250#define TEX_cmt '%'
4251
aab1fdae
FP
4252/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4253 chars accordingly. */
944bdd72 4254static void
6dd5561c
FP
4255TEX_mode (inf)
4256 FILE *inf;
c6d46f5f
JB
4257{
4258 int c;
4259
6dd5561c 4260 while ((c = getc (inf)) != EOF)
c6d46f5f
JB
4261 {
4262 /* Skip to next line if we hit the TeX comment char. */
4263 if (c == TEX_cmt)
4264 while (c != '\n')
6dd5561c 4265 c = getc (inf);
c6d46f5f
JB
4266 else if (c == TEX_LESC || c == TEX_SESC )
4267 break;
4268 }
4269
4270 if (c == TEX_LESC)
4271 {
4272 TEX_esc = TEX_LESC;
4273 TEX_opgrp = '{';
4274 TEX_clgrp = '}';
4275 }
4276 else
4277 {
4278 TEX_esc = TEX_SESC;
4279 TEX_opgrp = '<';
4280 TEX_clgrp = '>';
4281 }
93b7ac65
FP
4282 /* If the input file is compressed, inf is a pipe, and rewind may fail.
4283 No attempt is made to correct the situation. */
6dd5561c 4284 rewind (inf);
c6d46f5f
JB
4285}
4286
aab1fdae
FP
4287/* Read environment and prepend it to the default string.
4288 Build token table. */
944bdd72 4289static struct TEX_tabent *
c6d46f5f
JB
4290TEX_decode_env (evarname, defenv)
4291 char *evarname;
4292 char *defenv;
4293{
4294 register char *env, *p;
c6d46f5f
JB
4295
4296 struct TEX_tabent *tab;
4297 int size, i;
4298
4299 /* Append default string to environment. */
4300 env = getenv (evarname);
4301 if (!env)
4302 env = defenv;
4303 else
cec68fcb
FP
4304 {
4305 char *oldenv = env;
4306 env = concat (oldenv, defenv, "");
cec68fcb 4307 }
c6d46f5f
JB
4308
4309 /* Allocate a token table */
4310 for (size = 1, p = env; p;)
93b7ac65 4311 if ((p = etags_strchr (p, ':')) && *++p != '\0')
c6d46f5f 4312 size++;
8a6c8bcf
RS
4313 /* Add 1 to leave room for null terminator. */
4314 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
4315
4316 /* Unpack environment string into token table. Be careful about */
4317 /* zero-length strings (leading ':', "::" and trailing ':') */
4318 for (i = 0; *env;)
4319 {
b02c5fea 4320 p = etags_strchr (env, ':');
c6d46f5f
JB
4321 if (!p) /* End of environment string. */
4322 p = env + strlen (env);
4323 if (p - env > 0)
4324 { /* Only non-zero strings. */
4325 tab[i].name = savenstr (env, p - env);
4326 tab[i].len = strlen (tab[i].name);
4327 i++;
4328 }
4329 if (*p)
4330 env = p + 1;
4331 else
4332 {
4333 tab[i].name = NULL; /* Mark end of table. */
4334 tab[i].len = 0;
4335 break;
4336 }
4337 }
4338 return tab;
4339}
4340
c6d46f5f 4341/* If the text at CP matches one of the tag-defining TeX command names,
b02c5fea 4342 return the pointer to the first occurrence of that command in TEX_toktab.
aab1fdae 4343 Otherwise return -1.
93b7ac65 4344 Keep the capital `T' in `token' for dumb truncating compilers
c6d46f5f 4345 (this distinguishes it from `TEX_toktab' */
944bdd72 4346static int
c6d46f5f
JB
4347TEX_Token (cp)
4348 char *cp;
4349{
4350 int i;
4351
4352 for (i = 0; TEX_toktab[i].len > 0; i++)
1a0d8c80 4353 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
c6d46f5f
JB
4354 return i;
4355 return -1;
4356}
4357\f
8dc7496c
FP
4358/*
4359 * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4360 *
4361 * Assumes that the predicate starts at column 0.
93b7ac65 4362 * Only the first clause of a predicate is added.
8dc7496c 4363 */
944bdd72
FP
4364static int prolog_pred P_((char *s, char *last));
4365static void prolog_skip_comment P_((linebuffer *plb, FILE *inf));
4366static int prolog_atom P_((char *s, int pos));
30903246 4367
944bdd72 4368static void
8dc7496c
FP
4369Prolog_functions (inf)
4370 FILE *inf;
4371{
93b7ac65 4372 char *cp, *last;
8dc7496c
FP
4373 int len;
4374 int allocated;
4375
4376 allocated = 0;
4377 len = 0;
4378 last = NULL;
4379
93b7ac65 4380 LOOP_ON_INPUT_LINES (inf, lb, cp)
8dc7496c 4381 {
93b7ac65 4382 if (cp[0] == '\0') /* Empty line */
8dc7496c 4383 continue;
93b7ac65 4384 else if (isspace (cp[0])) /* Not a predicate */
8dc7496c 4385 continue;
93b7ac65 4386 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
3f1c8fcd 4387 prolog_skip_comment (&lb, inf);
93b7ac65 4388 else if ((len = prolog_pred (cp, last)) > 0)
8dc7496c
FP
4389 {
4390 /* Predicate. Store the function name so that we only
086eac13 4391 generate a tag for the first clause. */
8dc7496c
FP
4392 if (last == NULL)
4393 last = xnew(len + 1, char);
4394 else if (len + 1 > allocated)
93b7ac65 4395 last = xrnew (last, len + 1, char);
8dc7496c 4396 allocated = len + 1;
93b7ac65 4397 strncpy (last, cp, len);
8dc7496c
FP
4398 last[len] = '\0';
4399 }
4400 }
4401}
4402
c6d46f5f 4403
944bdd72 4404static void
8dc7496c 4405prolog_skip_comment (plb, inf)
93b7ac65 4406 linebuffer *plb;
8dc7496c
FP
4407 FILE *inf;
4408{
4409 char *cp;
4410
4411 do
4412 {
4413 for (cp = plb->buffer; *cp != '\0'; cp++)
4414 if (cp[0] == '*' && cp[1] == '/')
4415 return;
4416 lineno++;
4417 linecharno += readline (plb, inf);
4418 }
4419 while (!feof(inf));
4420}
4421
4422/*
4423 * A predicate definition is added if it matches:
4424 * <beginning of line><Prolog Atom><whitespace>(
4425 *
4426 * It is added to the tags database if it doesn't match the
4427 * name of the previous clause header.
4428 *
4429 * Return the size of the name of the predicate, or 0 if no header
4430 * was found.
4431 */
0dacfc4b 4432static int
8dc7496c 4433prolog_pred (s, last)
c6d46f5f 4434 char *s;
8dc7496c 4435 char *last; /* Name of last clause. */
c6d46f5f 4436{
8dc7496c
FP
4437 int pos;
4438 int len;
4439
30903246 4440 pos = prolog_atom (s, 0);
8dc7496c
FP
4441 if (pos < 1)
4442 return 0;
4443
4444 len = pos;
93b7ac65 4445 pos = skip_spaces (s + pos) - s;
8dc7496c
FP
4446
4447 if ((s[pos] == '(') || (s[pos] == '.'))
c6d46f5f 4448 {
8dc7496c
FP
4449 if (s[pos] == '(')
4450 pos++;
4451
4452 /* Save only the first clause. */
30903246 4453 if (last == NULL
93b7ac65 4454 || len != (int)strlen (last)
30903246 4455 || !strneq (s, last, len))
c6d46f5f 4456 {
93b7ac65 4457 pfnote (savenstr (s, len), TRUE, s, pos, lineno, linecharno);
8dc7496c 4458 return len;
c6d46f5f 4459 }
8dc7496c
FP
4460 }
4461 return 0;
4462}
4463
4464/*
4465 * Consume a Prolog atom.
4466 * Return the number of bytes consumed, or -1 if there was an error.
4467 *
4468 * A prolog atom, in this context, could be one of:
4469 * - An alphanumeric sequence, starting with a lower case letter.
4470 * - A quoted arbitrary string. Single quotes can escape themselves.
4471 * Backslash quotes everything.
4472 */
944bdd72 4473static int
8dc7496c
FP
4474prolog_atom (s, pos)
4475 char *s;
4476 int pos;
4477{
4478 int origpos;
4479
4480 origpos = pos;
4481
4482 if (islower(s[pos]) || (s[pos] == '_'))
4483 {
4484 /* The atom is unquoted. */
4485 pos++;
4486 while (isalnum(s[pos]) || (s[pos] == '_'))
c6d46f5f 4487 {
8dc7496c 4488 pos++;
c6d46f5f 4489 }
8dc7496c
FP
4490 return pos - origpos;
4491 }
4492 else if (s[pos] == '\'')
4493 {
4494 pos++;
4495
93b7ac65 4496 while (1)
c6d46f5f 4497 {
8dc7496c
FP
4498 if (s[pos] == '\'')
4499 {
4500 pos++;
4501 if (s[pos] != '\'')
4502 break;
4503 pos++; /* A double quote */
4504 }
4505 else if (s[pos] == '\0')
4506 /* Multiline quoted atoms are ignored. */
4507 return -1;
4508 else if (s[pos] == '\\')
4509 {
4510 if (s[pos+1] == '\0')
4511 return -1;
4512 pos += 2;
4513 }
4514 else
4515 pos++;
c6d46f5f 4516 }
8dc7496c 4517 return pos - origpos;
c6d46f5f 4518 }
8dc7496c
FP
4519 else
4520 return -1;
c6d46f5f 4521}
8dc7496c 4522\f
93b7ac65 4523/*
8dc7496c
FP
4524 * Support for Erlang -- Anders Lindgren, Feb 1996.
4525 *
4526 * Generates tags for functions, defines, and records.
4527 *
4528 * Assumes that Erlang functions start at column 0.
4529 */
944bdd72
FP
4530static int erlang_func P_((char *s, char *last));
4531static void erlang_attribute P_((char *s));
4532static int erlang_atom P_((char *s, int pos));
30903246 4533
944bdd72 4534static void
8dc7496c 4535Erlang_functions (inf)
6dd5561c 4536 FILE *inf;
c6d46f5f 4537{
93b7ac65 4538 char *cp, *last;
8dc7496c
FP
4539 int len;
4540 int allocated;
4541
4542 allocated = 0;
4543 len = 0;
4544 last = NULL;
4545
93b7ac65 4546 LOOP_ON_INPUT_LINES (inf, lb, cp)
c6d46f5f 4547 {
93b7ac65 4548 if (cp[0] == '\0') /* Empty line */
c6d46f5f 4549 continue;
93b7ac65 4550 else if (isspace (cp[0])) /* Not function nor attribute */
c6d46f5f 4551 continue;
93b7ac65 4552 else if (cp[0] == '%') /* comment */
8dc7496c 4553 continue;
93b7ac65 4554 else if (cp[0] == '"') /* Sometimes, strings start in column one */
8dc7496c 4555 continue;
93b7ac65 4556 else if (cp[0] == '-') /* attribute, e.g. "-define" */
8dc7496c 4557 {
93b7ac65 4558 erlang_attribute (cp);
8dc7496c
FP
4559 last = NULL;
4560 }
93b7ac65 4561 else if ((len = erlang_func (cp, last)) > 0)
8dc7496c 4562 {
93b7ac65 4563 /*
8dc7496c
FP
4564 * Function. Store the function name so that we only
4565 * generates a tag for the first clause.
4566 */
4567 if (last == NULL)
30903246 4568 last = xnew (len + 1, char);
8dc7496c 4569 else if (len + 1 > allocated)
93b7ac65 4570 last = xrnew (last, len + 1, char);
8dc7496c 4571 allocated = len + 1;
93b7ac65 4572 strncpy (last, cp, len);
8dc7496c
FP
4573 last[len] = '\0';
4574 }
4575 }
4576}
4577
4578
4579/*
4580 * A function definition is added if it matches:
4581 * <beginning of line><Erlang Atom><whitespace>(
4582 *
4583 * It is added to the tags database if it doesn't match the
4584 * name of the previous clause header.
4585 *
4586 * Return the size of the name of the function, or 0 if no function
4587 * was found.
4588 */
0dacfc4b 4589static int
8dc7496c
FP
4590erlang_func (s, last)
4591 char *s;
4592 char *last; /* Name of last clause. */
4593{
8dc7496c
FP
4594 int pos;
4595 int len;
4596
30903246 4597 pos = erlang_atom (s, 0);
8dc7496c
FP
4598 if (pos < 1)
4599 return 0;
4600
4601 len = pos;
93b7ac65 4602 pos = skip_spaces (s + pos) - s;
8dc7496c 4603
30903246
FP
4604 /* Save only the first clause. */
4605 if (s[pos++] == '('
4606 && (last == NULL
93b7ac65 4607 || len != (int)strlen (last)
30903246 4608 || !strneq (s, last, len)))
8dc7496c 4609 {
93b7ac65 4610 pfnote (savenstr (s, len), TRUE, s, pos, lineno, linecharno);
8dc7496c
FP
4611 return len;
4612 }
30903246 4613
8dc7496c 4614 return 0;
c6d46f5f
JB
4615}
4616
8dc7496c
FP
4617
4618/*
93b7ac65 4619 * Handle attributes. Currently, tags are generated for defines
8dc7496c
FP
4620 * and records.
4621 *
4622 * They are on the form:
4623 * -define(foo, bar).
4624 * -define(Foo(M, N), M+N).
4625 * -record(graph, {vtab = notable, cyclic = true}).
4626 */
944bdd72 4627static void
8dc7496c
FP
4628erlang_attribute (s)
4629 char *s;
c6d46f5f 4630{
8dc7496c
FP
4631 int pos;
4632 int len;
4633
30903246 4634 if (strneq (s, "-define", 7) || strneq (s, "-record", 7))
c6d46f5f 4635 {
93b7ac65
FP
4636 pos = skip_spaces (s + 7) - s;
4637 if (s[pos++] == '(')
8dc7496c 4638 {
93b7ac65
FP
4639 pos = skip_spaces (s + pos) - s;
4640 len = erlang_atom (s, pos);
4641 if (len != 0)
4642 pfnote (savenstr (& s[pos], len), TRUE,
4643 s, pos + len, lineno, linecharno);
8dc7496c 4644 }
b9755a12 4645 }
8dc7496c
FP
4646 return;
4647}
4648
4649
4650/*
4651 * Consume an Erlang atom (or variable).
4652 * Return the number of bytes consumed, or -1 if there was an error.
4653 */
944bdd72 4654static int
8dc7496c
FP
4655erlang_atom (s, pos)
4656 char *s;
4657 int pos;
4658{
4659 int origpos;
4660
4661 origpos = pos;
4662
4663 if (isalpha (s[pos]) || s[pos] == '_')
4664 {
4665 /* The atom is unquoted. */
4666 pos++;
4667 while (isalnum (s[pos]) || s[pos] == '_')
4668 pos++;
4669 return pos - origpos;
4670 }
4671 else if (s[pos] == '\'')
4672 {
4673 pos++;
4674
93b7ac65 4675 while (1)
8dc7496c
FP
4676 {
4677 if (s[pos] == '\'')
4678 {
4679 pos++;
4680 break;
4681 }
4682 else if (s[pos] == '\0')
4683 /* Multiline quoted atoms are ignored. */
4684 return -1;
4685 else if (s[pos] == '\\')
4686 {
4687 if (s[pos+1] == '\0')
4688 return -1;
4689 pos += 2;
4690 }
4691 else
4692 pos++;
4693 }
4694 return pos - origpos;
4695 }
4696 else
4697 return -1;
4698}
b9755a12
FP
4699\f
4700#ifdef ETAGS_REGEXPS
93b7ac65 4701
b9755a12
FP
4702/* Take a string like "/blah/" and turn it into "blah", making sure
4703 that the first and last characters are the same, and handling
15294654 4704 quoted separator characters. Actually, stops on the occurrence of
b9755a12
FP
4705 an unquoted separator. Also turns "\t" into a Tab character.
4706 Returns pointer to terminating separator. Works in place. Null
4707 terminates name string. */
944bdd72 4708static char *
b9755a12
FP
4709scan_separators (name)
4710 char *name;
4711{
4712 char sep = name[0];
4713 char *copyto = name;
30903246 4714 bool quoted = FALSE;
b9755a12
FP
4715
4716 for (++name; *name != '\0'; ++name)
4717 {
4718 if (quoted)
4719 {
4720 if (*name == 't')
4721 *copyto++ = '\t';
4722 else if (*name == sep)
4723 *copyto++ = sep;
4724 else
4725 {
4726 /* Something else is quoted, so preserve the quote. */
4727 *copyto++ = '\\';
4728 *copyto++ = *name;
4729 }
4730 quoted = FALSE;
4731 }
4732 else if (*name == '\\')
4733 quoted = TRUE;
4734 else if (*name == sep)
4735 break;
4736 else
4737 *copyto++ = *name;
4738 }
c6d46f5f 4739
b9755a12
FP
4740 /* Terminate copied string. */
4741 *copyto = '\0';
4742 return name;
4743}
c6d46f5f 4744
cec68fcb 4745/* Look at the argument of --regex or --no-regex and do the right
93b7ac65 4746 thing. Same for each line of a regexp file. */
944bdd72 4747static void
93b7ac65 4748analyse_regex (regex_arg, ignore_case)
cec68fcb 4749 char *regex_arg;
93b7ac65 4750 bool ignore_case;
c6d46f5f 4751{
cec68fcb 4752 if (regex_arg == NULL)
93b7ac65
FP
4753 free_patterns (); /* --no-regex: remove existing regexps */
4754
4755 /* A real --regexp option or a line in a regexp file. */
4756 switch (regex_arg[0])
b9755a12 4757 {
93b7ac65
FP
4758 /* Comments in regexp file or null arg to --regex. */
4759 case '\0':
4760 case ' ':
4761 case '\t':
4762 break;
cec68fcb 4763
93b7ac65
FP
4764 /* Read a regex file. This is recursive and may result in a
4765 loop, which will stop when the file descriptors are exhausted. */
4766 case '@':
4767 {
4768 FILE *regexfp;
4769 linebuffer regexbuf;
4770 char *regexfile = regex_arg + 1;
4771
4772 /* regexfile is a file containing regexps, one per line. */
4773 regexfp = fopen (regexfile, "r");
4774 if (regexfp == NULL)
4775 {
4776 pfatal (regexfile);
4777 return;
4778 }
4779 initbuffer (&regexbuf);
4780 while (readline_internal (&regexbuf, regexfp) > 0)
4781 analyse_regex (regexbuf.buffer, ignore_case);
4782 free (regexbuf.buffer);
4783 fclose (regexfp);
4784 }
4785 break;
4786
4787 /* Regexp to be used for a specific language only. */
4788 case '{':
4789 {
4790 language *lang;
4791 char *lang_name = regex_arg + 1;
4792 char *cp;
4793
4794 for (cp = lang_name; *cp != '}'; cp++)
4795 if (*cp == '\0')
4796 {
4797 error ("unterminated language name in regex: %s", regex_arg);
4798 return;
4799 }
4800 *cp = '\0';
4801 lang = get_language_from_name (lang_name);
4802 if (lang == NULL)
cec68fcb 4803 return;
93b7ac65
FP
4804 add_regex (cp + 1, ignore_case, lang);
4805 }
4806 break;
4807
4808 /* Regexp to be used for any language. */
4809 default:
4810 add_regex (regex_arg, ignore_case, NULL);
4811 break;
cec68fcb
FP
4812 }
4813}
4814
4815/* Turn a name, which is an ed-style (but Emacs syntax) regular
4816 expression, into a real regular expression by compiling it. */
944bdd72 4817static void
93b7ac65 4818add_regex (regexp_pattern, ignore_case, lang)
cec68fcb 4819 char *regexp_pattern;
93b7ac65
FP
4820 bool ignore_case;
4821 language *lang;
cec68fcb
FP
4822{
4823 char *name;
4824 const char *err;
4825 struct re_pattern_buffer *patbuf;
93b7ac65 4826 pattern *pp;
cec68fcb
FP
4827
4828
b9755a12
FP
4829 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
4830 {
4831 error ("%s: unterminated regexp", regexp_pattern);
4832 return;
4833 }
4834 name = scan_separators (regexp_pattern);
4835 if (regexp_pattern[0] == '\0')
4836 {
086eac13 4837 error ("null regexp", (char *)NULL);
b9755a12
FP
4838 return;
4839 }
4840 (void) scan_separators (name);
4841
4842 patbuf = xnew (1, struct re_pattern_buffer);
93b7ac65
FP
4843 /* Translation table to fold case if appropriate. */
4844 patbuf->translate = (ignore_case) ? lc_trans : NULL;
2f608d34
FP
4845 patbuf->fastmap = NULL;
4846 patbuf->buffer = NULL;
4847 patbuf->allocated = 0;
b9755a12
FP
4848
4849 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
4850 if (err != NULL)
4851 {
4852 error ("%s while compiling pattern", err);
4853 return;
4854 }
4855
93b7ac65
FP
4856 pp = p_head;
4857 p_head = xnew (1, pattern);
4858 p_head->regex = savestr (regexp_pattern);
4859 p_head->p_next = pp;
4860 p_head->language = lang;
4861 p_head->pattern = patbuf;
4862 p_head->name_pattern = savestr (name);
4863 p_head->error_signaled = FALSE;
b9755a12
FP
4864}
4865
4866/*
c5007f46 4867 * Do the substitutions indicated by the regular expression and
b9755a12
FP
4868 * arguments.
4869 */
944bdd72 4870static char *
b9755a12
FP
4871substitute (in, out, regs)
4872 char *in, *out;
4873 struct re_registers *regs;
4874{
2f608d34 4875 char *result, *t;
e0903a92 4876 int size, dig, diglen;
2f608d34
FP
4877
4878 result = NULL;
4879 size = strlen (out);
b9755a12 4880
e0903a92
FP
4881 /* Pass 1: figure out how much to allocate by finding all \N strings. */
4882 if (out[size - 1] == '\\')
4883 fatal ("pattern error in \"%s\"", out);
4884 for (t = etags_strchr (out, '\\');
4885 t != NULL;
4886 t = etags_strchr (t + 2, '\\'))
4887 if (isdigit (t[1]))
2f608d34 4888 {
e0903a92
FP
4889 dig = t[1] - '0';
4890 diglen = regs->end[dig] - regs->start[dig];
4891 size += diglen - 2;
2f608d34 4892 }
e0903a92
FP
4893 else
4894 size -= 1;
b9755a12
FP
4895
4896 /* Allocate space and do the substitutions. */
4897 result = xnew (size + 1, char);
e0903a92
FP
4898
4899 for (t = result; *out != '\0'; out++)
4900 if (*out == '\\' && isdigit (*++out))
4901 {
4902 /* Using "dig2" satisfies my debugger. Bleah. */
4903 dig = *out - '0';
4904 diglen = regs->end[dig] - regs->start[dig];
4905 strncpy (t, in + regs->start[dig], diglen);
4906 t += diglen;
4907 }
4908 else
4909 *t++ = *out;
4910 *t = '\0';
4911
93b7ac65 4912 if (DEBUG && (t > result + size || t - result != (int)strlen (result)))
2f608d34 4913 abort ();
b9755a12
FP
4914
4915 return result;
c6d46f5f 4916}
93b7ac65
FP
4917
4918/* Deallocate all patterns. */
944bdd72 4919static void
93b7ac65
FP
4920free_patterns ()
4921{
4922 pattern *pp;
4923 while (p_head != NULL)
4924 {
4925 pp = p_head->p_next;
4926 free (p_head->regex);
4927 free (p_head->name_pattern);
4928 free (p_head);
4929 p_head = pp;
4930 }
4931 return;
4932}
c6d46f5f 4933\f
944bdd72 4934static void
93b7ac65
FP
4935get_tag (bp)
4936 register char *bp;
4937{
4938 register char *cp;
4939
4940 if (*bp == '\0')
4941 return;
4942 /* Go till you get to white space or a syntactic break */
4943 for (cp = bp + 1;
4944 *cp != '\0' && *cp != '(' && *cp != ')' && !isspace (*cp);
4945 cp++)
4946 continue;
4947 pfnote (savenstr (bp, cp-bp), TRUE,
4948 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4949}
4950
b9755a12 4951#endif /* ETAGS_REGEXPS */
c6d46f5f 4952/* Initialize a linebuffer for use */
944bdd72 4953static void
93b7ac65
FP
4954initbuffer (lbp)
4955 linebuffer *lbp;
c6d46f5f 4956{
93b7ac65
FP
4957 lbp->size = 200;
4958 lbp->buffer = xnew (200, char);
c6d46f5f
JB
4959}
4960
4961/*
93b7ac65
FP
4962 * Read a line of text from `stream' into `lbp', excluding the
4963 * newline or CR-NL, if any. Return the number of characters read from
4964 * `stream', which is the length of the line including the newline.
4965 *
4966 * On DOS or Windows we do not count the CR character, if any, before the
4967 * NL, in the returned length; this mirrors the behavior of emacs on those
4968 * platforms (for text files, it translates CR-NL to NL as it reads in the
4969 * file).
c6d46f5f 4970 */
944bdd72 4971static long
93b7ac65
FP
4972readline_internal (lbp, stream)
4973 linebuffer *lbp;
c6d46f5f
JB
4974 register FILE *stream;
4975{
93b7ac65
FP
4976 char *buffer = lbp->buffer;
4977 register char *p = lbp->buffer;
c6d46f5f 4978 register char *pend;
aab1fdae 4979 int chars_deleted;
c6d46f5f 4980
93b7ac65 4981 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
c6d46f5f
JB
4982
4983 while (1)
4984 {
4985 register int c = getc (stream);
4986 if (p == pend)
4987 {
93b7ac65
FP
4988 /* We're at the end of linebuffer: expand it. */
4989 lbp->size *= 2;
4990 buffer = xrnew (buffer, lbp->size, char);
4991 p += buffer - lbp->buffer;
4992 pend = buffer + lbp->size;
4993 lbp->buffer = buffer;
c6d46f5f 4994 }
aab1fdae 4995 if (c == EOF)
c6d46f5f 4996 {
8dc7496c 4997 *p = '\0';
aab1fdae
FP
4998 chars_deleted = 0;
4999 break;
5000 }
5001 if (c == '\n')
5002 {
a8d9bd4b 5003 if (p > buffer && p[-1] == '\r')
aab1fdae 5004 {
e0903a92 5005 p -= 1;
70611080 5006#ifdef DOS_NT
b6b48846
FP
5007 /* Assume CRLF->LF translation will be performed by Emacs
5008 when loading this file, so CRs won't appear in the buffer.
5009 It would be cleaner to compensate within Emacs;
5010 however, Emacs does not know how many CRs were deleted
5011 before any given point in the file. */
70611080
RS
5012 chars_deleted = 1;
5013#else
aab1fdae 5014 chars_deleted = 2;
70611080 5015#endif
aab1fdae
FP
5016 }
5017 else
5018 {
aab1fdae
FP
5019 chars_deleted = 1;
5020 }
e0903a92 5021 *p = '\0';
c6d46f5f
JB
5022 break;
5023 }
5024 *p++ = c;
5025 }
93b7ac65 5026 lbp->len = p - buffer;
c6d46f5f 5027
93b7ac65 5028 return lbp->len + chars_deleted;
c6d46f5f 5029}
b9755a12
FP
5030
5031/*
e0903a92 5032 * Like readline_internal, above, but in addition try to match the
93b7ac65 5033 * input line against relevant regular expressions.
b9755a12 5034 */
944bdd72 5035static long
93b7ac65
FP
5036readline (lbp, stream)
5037 linebuffer *lbp;
b9755a12
FP
5038 FILE *stream;
5039{
5040 /* Read new line. */
93b7ac65 5041 long result = readline_internal (lbp, stream);
b9755a12 5042#ifdef ETAGS_REGEXPS
93b7ac65
FP
5043 int match;
5044 pattern *pp;
d8913c1c 5045
93b7ac65
FP
5046 /* Match against relevant patterns. */
5047 if (lbp->len > 0)
5048 for (pp = p_head; pp != NULL; pp = pp->p_next)
e0903a92 5049 {
93b7ac65
FP
5050 /* Only use generic regexps or those for the current language. */
5051 if (pp->language != NULL && pp->language != curlang)
5052 continue;
5053
5054 match = re_match (pp->pattern, lbp->buffer, lbp->len, 0, &pp->regs);
e0903a92
FP
5055 switch (match)
5056 {
5057 case -2:
5058 /* Some error. */
93b7ac65 5059 if (!pp->error_signaled)
e0903a92 5060 {
93b7ac65
FP
5061 error ("error while matching \"%s\"", pp->regex);
5062 pp->error_signaled = TRUE;
e0903a92
FP
5063 }
5064 break;
5065 case -1:
5066 /* No match. */
5067 break;
5068 default:
5069 /* Match occurred. Construct a tag. */
93b7ac65 5070 if (pp->name_pattern[0] != '\0')
e0903a92
FP
5071 {
5072 /* Make a named tag. */
93b7ac65
FP
5073 char *name = substitute (lbp->buffer,
5074 pp->name_pattern, &pp->regs);
e0903a92 5075 if (name != NULL)
93b7ac65 5076 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
e0903a92
FP
5077 }
5078 else
5079 {
5080 /* Make an unnamed tag. */
5081 pfnote ((char *)NULL, TRUE,
93b7ac65 5082 lbp->buffer, match, lineno, linecharno);
e0903a92
FP
5083 }
5084 break;
5085 }
5086 }
b9755a12 5087#endif /* ETAGS_REGEXPS */
b9755a12 5088
93b7ac65 5089 return result;
b9755a12 5090}
c6d46f5f 5091\f
55597f90
FP
5092/*
5093 * Return a pointer to a space of size strlen(cp)+1 allocated
5094 * with xnew where the string CP has been copied.
5095 */
944bdd72 5096static char *
c6d46f5f
JB
5097savestr (cp)
5098 char *cp;
5099{
5100 return savenstr (cp, strlen (cp));
5101}
5102
55597f90
FP
5103/*
5104 * Return a pointer to a space of size LEN+1 allocated with xnew where
5105 * the string CP has been copied for at most the first LEN characters.
5106 */
944bdd72 5107static char *
c6d46f5f
JB
5108savenstr (cp, len)
5109 char *cp;
5110 int len;
5111{
5112 register char *dp;
5113
5114 dp = xnew (len + 1, char);
1a0d8c80 5115 strncpy (dp, cp, len);
c6d46f5f
JB
5116 dp[len] = '\0';
5117 return dp;
5118}
5119
c6d46f5f
JB
5120/*
5121 * Return the ptr in sp at which the character c last
5122 * appears; NULL if not found
5123 *
944bdd72 5124 * Identical to POSIX strrchr, included for portability.
c6d46f5f 5125 */
944bdd72 5126static char *
b02c5fea 5127etags_strrchr (sp, c)
944bdd72
FP
5128 register const char *sp;
5129 register int c;
c6d46f5f 5130{
944bdd72 5131 register const char *r;
c6d46f5f
JB
5132
5133 r = NULL;
5134 do
5135 {
5136 if (*sp == c)
5137 r = sp;
5138 } while (*sp++);
944bdd72 5139 return (char *)r;
c6d46f5f
JB
5140}
5141
9d7ad1b3 5142
c6d46f5f
JB
5143/*
5144 * Return the ptr in sp at which the character c first
5145 * appears; NULL if not found
5146 *
944bdd72 5147 * Identical to POSIX strchr, included for portability.
c6d46f5f 5148 */
944bdd72 5149static char *
b02c5fea 5150etags_strchr (sp, c)
944bdd72
FP
5151 register const char *sp;
5152 register int c;
c6d46f5f
JB
5153{
5154 do
5155 {
5156 if (*sp == c)
944bdd72 5157 return (char *)sp;
b9755a12
FP
5158 } while (*sp++);
5159 return NULL;
c6d46f5f
JB
5160}
5161
93b7ac65 5162/* Skip spaces, return new pointer. */
944bdd72 5163static char *
93b7ac65
FP
5164skip_spaces (cp)
5165 char *cp;
5166{
5167 while (isspace (*cp)) /* isspace('\0')==FALSE */
5168 cp++;
5169 return cp;
5170}
5171
5172/* Skip non spaces, return new pointer. */
944bdd72 5173static char *
93b7ac65
FP
5174skip_non_spaces (cp)
5175 char *cp;
5176{
5177 while (!iswhite (*cp)) /* iswhite('\0')==TRUE */
5178 cp++;
5179 return cp;
5180}
5181
c6d46f5f 5182/* Print error message and exit. */
944bdd72 5183static void
c6d46f5f
JB
5184fatal (s1, s2)
5185 char *s1, *s2;
5186{
5187 error (s1, s2);
1a0d8c80 5188 exit (BAD);
c6d46f5f
JB
5189}
5190
944bdd72 5191static void
cdc1f6a7
FP
5192pfatal (s1)
5193 char *s1;
5194{
5195 perror (s1);
5196 exit (BAD);
5197}
5198
944bdd72 5199static void
d8913c1c
FP
5200suggest_asking_for_help ()
5201{
93b7ac65
FP
5202 fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
5203 progname,
5204#ifdef LONG_OPTIONS
5205 "--help"
5206#else
5207 "-h"
5208#endif
5209 );
d8913c1c
FP
5210 exit (BAD);
5211}
5212
c6d46f5f 5213/* Print error message. `s1' is printf control string, `s2' is arg for it. */
944bdd72 5214static void
c6d46f5f 5215error (s1, s2)
944bdd72 5216 const char *s1, *s2;
c6d46f5f
JB
5217{
5218 fprintf (stderr, "%s: ", progname);
5219 fprintf (stderr, s1, s2);
5220 fprintf (stderr, "\n");
5221}
5222
46c145db
FP
5223/* Return a newly-allocated string whose contents
5224 concatenate those of s1, s2, s3. */
944bdd72 5225static char *
c6d46f5f
JB
5226concat (s1, s2, s3)
5227 char *s1, *s2, *s3;
5228{
5229 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
5230 char *result = xnew (len1 + len2 + len3 + 1, char);
5231
1a0d8c80
FP
5232 strcpy (result, s1);
5233 strcpy (result + len1, s2);
5234 strcpy (result + len1 + len2, s3);
46c145db 5235 result[len1 + len2 + len3] = '\0';
c6d46f5f
JB
5236
5237 return result;
5238}
b02c5fea 5239\f
cdc1f6a7 5240/* Does the same work as the system V getcwd, but does not need to
c5007f46 5241 guess the buffer size in advance. */
944bdd72 5242static char *
88f125fc 5243etags_getcwd ()
915e30c8 5244{
93b7ac65 5245#ifdef HAVE_GETCWD
cdc1f6a7
FP
5246 int bufsize = 200;
5247 char *path = xnew (bufsize, char);
c6d46f5f 5248
cdc1f6a7 5249 while (getcwd (path, bufsize) == NULL)
b02c5fea 5250 {
dcc89e63 5251 if (errno != ERANGE)
0f394065 5252 pfatal ("getcwd");
5e9c8296 5253 bufsize *= 2;
cec68fcb 5254 free (path);
cdc1f6a7 5255 path = xnew (bufsize, char);
5e9c8296 5256 }
b02c5fea 5257
93b7ac65 5258 canonicalize_filename (path);
cdc1f6a7 5259 return path;
ae178a12 5260
6469b6d2
RS
5261#else /* not HAVE_GETCWD */
5262#ifdef MSDOS
5263 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
5264
5265 getwd (path);
5266
5267 for (p = path; *p != '\0'; p++)
5268 if (*p == '\\')
5269 *p = '/';
5270 else
5271 *p = lowcase (*p);
5272
5273 return strdup (path);
5274#else /* not MSDOS */
93b7ac65 5275 linebuffer path;
cdc1f6a7 5276 FILE *pipe;
b02c5fea 5277
cdc1f6a7 5278 initbuffer (&path);
915e30c8 5279 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
cdc1f6a7 5280 if (pipe == NULL || readline_internal (&path, pipe) == 0)
915e30c8 5281 pfatal ("pwd");
cdc1f6a7 5282 pclose (pipe);
b02c5fea 5283
cdc1f6a7 5284 return path.buffer;
90e0918a 5285#endif /* not MSDOS */
6469b6d2 5286#endif /* not HAVE_GETCWD */
b02c5fea
FP
5287}
5288
93b7ac65
FP
5289/* Return a newly allocated string containing the file name of FILE
5290 relative to the absolute directory DIR (which should end with a slash). */
944bdd72 5291static char *
46c145db
FP
5292relative_filename (file, dir)
5293 char *file, *dir;
5294{
93b7ac65 5295 char *fp, *dp, *afn, *res;
2f608d34 5296 int i;
46c145db 5297
3ca80e28 5298 /* Find the common root of file and dir (with a trailing slash). */
93b7ac65
FP
5299 afn = absolute_filename (file, cwd);
5300 fp = afn;
46c145db
FP
5301 dp = dir;
5302 while (*fp++ == *dp++)
5303 continue;
3f1c8fcd 5304 fp--, dp--; /* back to the first differing char */
93b7ac65
FP
5305#ifdef DOS_NT
5306 if (fp == afn && afn[0] != '/') /* cannot build a relative name */
5307 return afn;
5308#endif
5309 do /* look at the equal chars until '/' */
3ca80e28 5310 fp--, dp--;
93b7ac65 5311 while (*fp != '/');
46c145db 5312
2f608d34
FP
5313 /* Build a sequence of "../" strings for the resulting relative file name. */
5314 i = 0;
5315 while ((dp = etags_strchr (dp + 1, '/')) != NULL)
5316 i += 1;
5317 res = xnew (3*i + strlen (fp + 1) + 1, char);
5318 res[0] = '\0';
5319 while (i-- > 0)
5320 strcat (res, "../");
5321
5322 /* Add the file name relative to the common root of file and dir. */
5323 strcat (res, fp + 1);
93b7ac65 5324 free (afn);
46c145db 5325
108c932a 5326 return res;
46c145db
FP
5327}
5328
93b7ac65
FP
5329/* Return a newly allocated string containing the absolute file name
5330 of FILE given DIR (which should end with a slash). */
944bdd72 5331static char *
93b7ac65
FP
5332absolute_filename (file, dir)
5333 char *file, *dir;
46c145db
FP
5334{
5335 char *slashp, *cp, *res;
5336
93b7ac65 5337 if (filename_is_absolute (file))
2f608d34 5338 res = savestr (file);
ce7f6d62 5339#ifdef DOS_NT
2f608d34 5340 /* We don't support non-absolute file names with a drive
ce7f6d62
RS
5341 letter, like `d:NAME' (it's too much hassle). */
5342 else if (file[1] == ':')
2f608d34 5343 fatal ("%s: relative file names with drive letters not supported", file);
ce7f6d62 5344#endif
46c145db 5345 else
93b7ac65 5346 res = concat (dir, file, "");
46c145db
FP
5347
5348 /* Delete the "/dirname/.." and "/." substrings. */
b02c5fea 5349 slashp = etags_strchr (res, '/');
46c145db
FP
5350 while (slashp != NULL && slashp[0] != '\0')
5351 {
5352 if (slashp[1] == '.')
5353 {
5354 if (slashp[2] == '.'
5355 && (slashp[3] == '/' || slashp[3] == '\0'))
5356 {
5357 cp = slashp;
5358 do
5359 cp--;
93b7ac65 5360 while (cp >= res && !filename_is_absolute (cp));
2f608d34
FP
5361 if (cp < res)
5362 cp = slashp; /* the absolute name begins with "/.." */
ce7f6d62
RS
5363#ifdef DOS_NT
5364 /* Under MSDOS and NT we get `d:/NAME' as absolute
2f608d34 5365 file name, so the luser could say `d:/../NAME'.
ce7f6d62 5366 We silently treat this as `d:/NAME'. */
2f608d34
FP
5367 else if (cp[0] != '/')
5368 cp = slashp;
ce7f6d62 5369#endif
2f608d34 5370 strcpy (cp, slashp + 3);
46c145db 5371 slashp = cp;
e9b2b94c 5372 continue;
46c145db
FP
5373 }
5374 else if (slashp[2] == '/' || slashp[2] == '\0')
5375 {
5376 strcpy (slashp, slashp + 2);
e9b2b94c 5377 continue;
46c145db
FP
5378 }
5379 }
e9b2b94c
FP
5380
5381 slashp = etags_strchr (slashp + 1, '/');
46c145db 5382 }
7ebca6a6 5383
2f608d34
FP
5384 if (res[0] == '\0')
5385 return savestr ("/");
5386 else
5387 return res;
46c145db
FP
5388}
5389
b02c5fea 5390/* Return a newly allocated string containing the absolute
93b7ac65 5391 file name of dir where FILE resides given DIR (which should
b02c5fea 5392 end with a slash). */
944bdd72 5393static char *
93b7ac65
FP
5394absolute_dirname (file, dir)
5395 char *file, *dir;
46c145db
FP
5396{
5397 char *slashp, *res;
5398 char save;
5399
93b7ac65 5400 canonicalize_filename (file);
b02c5fea 5401 slashp = etags_strrchr (file, '/');
46c145db 5402 if (slashp == NULL)
93b7ac65 5403 return savestr (dir);
46c145db
FP
5404 save = slashp[1];
5405 slashp[1] = '\0';
93b7ac65 5406 res = absolute_filename (file, dir);
46c145db
FP
5407 slashp[1] = save;
5408
5409 return res;
5410}
5411
93b7ac65
FP
5412/* Whether the argument string is an absolute file name. The argument
5413 string must have been canonicalized with canonicalize_filename. */
944bdd72 5414static bool
93b7ac65
FP
5415filename_is_absolute (fn)
5416 char *fn;
5417{
5418 return (fn[0] == '/'
5419#ifdef DOS_NT
5420 || (isalpha(fn[0]) && fn[1] == ':' && fn[2] == '/')
5421#endif
5422 );
5423}
5424
5425/* Translate backslashes into slashes. Works in place. */
944bdd72 5426static void
93b7ac65
FP
5427canonicalize_filename (fn)
5428 register char *fn;
5429{
5430#ifdef DOS_NT
c8b04710
FP
5431 /* Canonicalize drive letter case. */
5432 if (islower (fn[0]))
5433 fn[0] = toupper (fn[0]);
93b7ac65
FP
5434 /* Convert backslashes to slashes. */
5435 for (; *fn != '\0'; fn++)
5436 if (*fn == '\\')
5437 *fn = '/';
93b7ac65
FP
5438#else
5439 /* No action. */
5440 fn = NULL; /* shut up the compiler */
5441#endif
5442}
5443
3f1c8fcd 5444/* Increase the size of a linebuffer. */
944bdd72 5445static void
93b7ac65
FP
5446grow_linebuffer (lbp, toksize)
5447 linebuffer *lbp;
3f1c8fcd
FP
5448 int toksize;
5449{
93b7ac65
FP
5450 while (lbp->size < toksize)
5451 lbp->size *= 2;
5452 lbp->buffer = xrnew (lbp->buffer, lbp->size, char);
3f1c8fcd
FP
5453}
5454
c6d46f5f 5455/* Like malloc but get fatal error if memory is exhausted. */
944bdd72 5456static long *
c6d46f5f 5457xmalloc (size)
42680d3c 5458 unsigned int size;
c6d46f5f 5459{
03cdafdf 5460 long *result = (long *) malloc (size);
1a0d8c80 5461 if (result == NULL)
086eac13 5462 fatal ("virtual memory exhausted", (char *)NULL);
c6d46f5f
JB
5463 return result;
5464}
5465
944bdd72 5466static long *
c6d46f5f
JB
5467xrealloc (ptr, size)
5468 char *ptr;
42680d3c 5469 unsigned int size;
c6d46f5f 5470{
108c932a 5471 long *result = (long *) realloc (ptr, size);
1a0d8c80 5472 if (result == NULL)
086eac13 5473 fatal ("virtual memory exhausted", (char *)NULL);
c6d46f5f
JB
5474 return result;
5475}