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