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