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