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