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