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