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