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