(mouse-select-buffer) Handle an aborted selection.
[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
cdc1f6a7 34char pot_etags_version[] = "@(#) pot revision number is 11.14";
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 ();
cdc1f6a7 188#if FALSE /* 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 ();
cdc1f6a7 227void fatal (), pfatal ();
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)
cdc1f6a7 952 pfatal (tagfile);
c6d46f5f
JB
953 }
954
b9755a12
FP
955 /*
956 * Loop through files finding functions.
957 */
958 for (i = 0; i < current_arg; ++i)
c6d46f5f 959 {
b9755a12 960 switch (argbuffer[i].arg_type)
c6d46f5f 961 {
b9755a12
FP
962 case at_language:
963 lang_func = argbuffer[i].function;
964 break;
965#ifdef ETAGS_REGEXPS
966 case at_regexp:
967 add_regex (argbuffer[i].what);
968 break;
c6d46f5f 969#endif
b9755a12
FP
970 case at_filename:
971#ifdef VMS
972 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
973 {
974 if (got_err)
975 {
976 error ("Can't find file %s\n", this_file);
977 argc--, argv++;
978 }
979 else
980 {
981 this_file = massage_name (this_file);
982 }
c6d46f5f 983#else
b9755a12 984 this_file = argbuffer[i].what;
c6d46f5f 985#endif
b9755a12
FP
986 /* Input file named "-" means read file names from stdin
987 and use them. */
988 if (streq (this_file, "-"))
989 {
990 while (!feof (stdin))
991 {
992 /* Use readline_internal so that regexp matching */
993 /* is not done on filenames. */
994 (void) readline_internal (&filename_lb, stdin);
995 if (strlen (filename_lb.buffer) > 0)
996 process_file (filename_lb.buffer);
997 }
998 }
999 else
1000 process_file (this_file);
1001#ifdef VMS
c6d46f5f 1002 }
b9755a12
FP
1003#endif
1004 break;
c6d46f5f 1005 }
46c145db 1006 }
c6d46f5f 1007
32daa216 1008 if (!CTAGS)
c6d46f5f 1009 {
1e134a5f 1010 while (nincluded_files-- > 0)
6dd5561c 1011 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1e134a5f 1012
6dd5561c 1013 (void) fclose (tagf);
1a0d8c80 1014 exit (GOOD);
c6d46f5f
JB
1015 }
1016
1017 if (cxref_style)
1018 {
1019 put_entries (head);
1020 exit (GOOD);
1021 }
4746118a 1022 if (update)
c6d46f5f 1023 {
b9755a12 1024 for (i = 0; i < current_arg; ++i)
c6d46f5f 1025 {
b9755a12
FP
1026 if (argbuffer[i].arg_type == at_language)
1027 continue;
c6d46f5f
JB
1028 sprintf (cmd,
1029 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
b9755a12 1030 tagfile, argbuffer[i].what, tagfile);
c6d46f5f
JB
1031 (void) system (cmd);
1032 }
1033 append_to_tagfile++;
1034 }
6dd5561c
FP
1035 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1036 if (tagf == NULL)
c6d46f5f 1037 {
6dd5561c 1038 perror (tagfile);
c6d46f5f
JB
1039 exit (GOOD);
1040 }
1041 put_entries (head);
6dd5561c 1042 (void) fclose (tagf);
c6d46f5f
JB
1043 if (update)
1044 {
6dd5561c 1045 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
c6d46f5f
JB
1046 (void) system (cmd);
1047 }
1048 exit (GOOD);
1049}
1050
1051
b9755a12
FP
1052/*
1053 * Set the language, given the name.
1054 */
1055logical
1056get_language (language, func)
1057 char *language;
1058 Lang_function **func;
1059{
1060 struct lang_entry *lang;
1061
1062 for (lang = lang_names; lang->extension; ++lang)
1063 {
1064 if (streq (language, lang->extension))
1065 {
1066 *func = lang->function;
1067 return TRUE;
1068 }
1069 }
1070
1071 return FALSE;
1072}
1073
1074
c6d46f5f
JB
1075/*
1076 * This routine is called on each file argument.
1077 */
1078void
1079process_file (file)
1080 char *file;
1081{
1082 struct stat stat_buf;
1083
42680d3c 1084 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
c6d46f5f
JB
1085 {
1086 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
1087 return;
1088 }
6dd5561c 1089 if (streq (file, tagfile) && !streq (tagfile, "-"))
c6d46f5f
JB
1090 {
1091 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
1092 return;
1093 }
42680d3c
FP
1094 if (!find_entries (file))
1095 {
1096 return;
1097 }
32daa216 1098 if (!CTAGS)
c6d46f5f 1099 {
46c145db
FP
1100 char *filename;
1101
1102 if (file[0] == '/')
1103 {
1104 /* file is an absolute filename. Canonicalise it. */
1105 filename = absolute_filename (file, cwd);
1106 }
1107 else
1108 {
1109 /* file is a filename relative to cwd. Make it relative
1110 to the directory of the tags file. */
6dd5561c 1111 filename = relative_filename (file, tagfiledir);
46c145db 1112 }
6dd5561c 1113 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
c6d46f5f
JB
1114 put_entries (head);
1115 free_tree (head);
1116 head = NULL;
1117 }
1118}
1119
1120/*
eb8c3be9 1121 * This routine sets up the boolean pseudo-functions which work
99e0a2e0 1122 * by setting boolean flags dependent upon the corresponding character
c6d46f5f
JB
1123 * Every char which is NOT in that string is not a white char. Therefore,
1124 * all of the array "_wht" is set to FALSE, and then the elements
1125 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1126 * of a char is TRUE if it is the string "white", else FALSE.
1127 */
1128void
1129init ()
1130{
13fde0cd
RS
1131 register char *sp;
1132 register int i;
c6d46f5f
JB
1133
1134 for (i = 0; i < 0177; i++)
13fde0cd 1135 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
c6d46f5f
JB
1136 for (sp = white; *sp; sp++)
1137 _wht[*sp] = TRUE;
1138 for (sp = endtk; *sp; sp++)
1139 _etk[*sp] = TRUE;
1140 for (sp = intk; *sp; sp++)
1141 _itk[*sp] = TRUE;
1142 for (sp = begtk; *sp; sp++)
1143 _btk[*sp] = TRUE;
c6d46f5f
JB
1144 _wht[0] = _wht['\n'];
1145 _etk[0] = _etk['\n'];
1146 _btk[0] = _btk['\n'];
1147 _itk[0] = _itk['\n'];
c6d46f5f
JB
1148}
1149
1150/*
1151 * This routine opens the specified file and calls the function
1152 * which finds the function and type definitions.
1153 */
42680d3c 1154logical
c6d46f5f
JB
1155find_entries (file)
1156 char *file;
1157{
6dd5561c 1158 FILE *inf;
b9755a12
FP
1159 char *cp;
1160 struct lang_entry *lang;
1161 NODE *old_last_node;
1162 extern NODE *last_node;
c6d46f5f
JB
1163
1164 inf = fopen (file, "r");
1165 if (inf == NULL)
1166 {
1167 perror (file);
42680d3c 1168 return FALSE;
c6d46f5f
JB
1169 }
1170 curfile = savestr (file);
b02c5fea 1171 cp = etags_strrchr (file, '.');
c6d46f5f 1172
b9755a12
FP
1173 /* If user specified a language, use it. */
1174 if (lang_func != NULL)
13fde0cd 1175 {
b9755a12
FP
1176 lang_func (inf);
1177 fclose (inf);
1178 return TRUE;
13fde0cd 1179 }
b9755a12
FP
1180
1181 if (cp)
c6d46f5f 1182 {
b9755a12
FP
1183 ++cp;
1184 for (lang = lang_extensions; lang->extension; ++lang)
1185 {
1186 if (streq (cp, lang->extension))
1187 {
1188 lang->function (inf);
1189 fclose (inf);
1190 return TRUE;
1191 }
1192 }
c6d46f5f 1193 }
c6d46f5f 1194
b9755a12
FP
1195 /* Try Fortran. */
1196 old_last_node = last_node;
1197 Fortran_functions (inf);
c6d46f5f 1198
b9755a12
FP
1199 /* No Fortran entries found. Try C. */
1200 if (old_last_node == last_node)
1201 default_C_entries (inf);
1202 fclose (inf);
1203 return TRUE;
c6d46f5f
JB
1204}
1205\f
1206/* Record a tag. */
1207/* Should take a TOKEN* instead!! */
c6d46f5f 1208void
fe0b3356 1209pfnote (name, is_func, named, linestart, linelen, lno, cno)
c6d46f5f
JB
1210 char *name; /* tag name */
1211 logical is_func; /* function or type name? */
fe0b3356 1212 logical named; /* tag different from text of definition? */
c6d46f5f
JB
1213 char *linestart;
1214 int linelen;
1215 int lno;
1216 long cno;
1217{
1218 register char *fp;
1219 register NODE *np;
1220 char tem[51];
1221 char c;
1222
1a0d8c80 1223 np = xnew (1, NODE);
c6d46f5f
JB
1224 if (np == NULL)
1225 {
32daa216 1226 if (CTAGS)
c6d46f5f
JB
1227 {
1228 /* It's okay to output early in etags -- it only disrupts the
1229 * character count of the tag entries, which is no longer used
1230 * by tags.el anyway.
1231 */
1a0d8c80 1232 error ("too many entries to sort", 0);
c6d46f5f
JB
1233 }
1234 put_entries (head);
1235 free_tree (head);
1236 head = NULL;
1237 np = xnew (1, NODE);
1238 }
1239 /* If ctags mode, change name "main" to M<thisfilename>. */
32daa216 1240 if (CTAGS && !cxref_style && streq (name, "main"))
c6d46f5f 1241 {
b02c5fea 1242 fp = etags_strrchr (curfile, '/');
c6d46f5f 1243 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
b02c5fea 1244 fp = etags_strrchr (name, '.');
c6d46f5f
JB
1245 if (fp && fp[1] != '\0' && fp[2] == '\0')
1246 *fp = 0;
fe0b3356 1247 named = TRUE;
c6d46f5f
JB
1248 }
1249 np->name = savestr (name);
1250 np->file = curfile;
1251 np->is_func = is_func;
fe0b3356 1252 np->named = named;
c6d46f5f 1253 np->lno = lno;
aab1fdae
FP
1254 /* Our char numbers are 0-base, because of C language tradition?
1255 ctags compatibility? old versions compatibility? I don't know.
1256 Anyway, since emacs's are 1-base we espect etags.el to take care
1257 of the difference. If we wanted to have 1-based numbers, we would
1258 uncomment the +1 below. */
1259 np->cno = cno /* + 1 */ ;
c6d46f5f 1260 np->left = np->right = 0;
32daa216 1261 if (!CTAGS)
c6d46f5f
JB
1262 {
1263 c = linestart[linelen];
1264 linestart[linelen] = 0;
1265 }
1266 else if (cxref_style == 0)
1267 {
1268 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
1269 linestart = tem;
1270 }
1271 np->pat = savestr (linestart);
32daa216 1272 if (!CTAGS)
c6d46f5f
JB
1273 {
1274 linestart[linelen] = c;
1275 }
1276
1277 add_node (np, &head);
1278}
1279
1280/*
1281 * free_tree ()
1282 * recurse on left children, iterate on right children.
1283 */
1284void
1285free_tree (node)
1286 register NODE *node;
1287{
1288 while (node)
1289 {
1290 register NODE *node_right = node->right;
1291 free_tree (node->left);
1292 free (node->name);
1293 free (node->pat);
1294 free ((char *) node);
1295 node = node_right;
1296 }
1297}
1298
1299/*
1300 * add_node ()
1301 * Adds a node to the tree of nodes. In etags mode, we don't keep
1302 * it sorted; we just keep a linear list. In ctags mode, maintain
1303 * an ordered tree, with no attempt at balancing.
1304 *
1305 * add_node is the only function allowed to add nodes, so it can
1306 * maintain state.
1307 */
6dd5561c 1308NODE *last_node = NULL;
c6d46f5f
JB
1309void
1310add_node (node, cur_node_p)
1311 NODE *node, **cur_node_p;
1312{
1313 register int dif;
1314 register NODE *cur_node = *cur_node_p;
c6d46f5f
JB
1315
1316 if (cur_node == NULL)
1317 {
1318 *cur_node_p = node;
1319 last_node = node;
1320 return;
1321 }
1322
32daa216 1323 if (!CTAGS)
c6d46f5f
JB
1324 {
1325 /* Etags Mode */
1a0d8c80
FP
1326 if (last_node == NULL)
1327 fatal ("internal error in add_node", 0);
c6d46f5f
JB
1328 last_node->right = node;
1329 last_node = node;
1330 }
1331 else
1332 {
1333 /* Ctags Mode */
1334 dif = strcmp (node->name, cur_node->name);
1335
1336 /*
1337 * If this tag name matches an existing one, then
1338 * do not add the node, but maybe print a warning.
1339 */
1340 if (!dif)
1341 {
1342 if (node->file == cur_node->file)
1343 {
1344 if (!no_warnings)
1345 {
1346 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1347 node->file, lineno, node->name);
1348 fprintf (stderr, "Second entry ignored\n");
1349 }
1350 return;
1351 }
1352 if (!cur_node->been_warned && !no_warnings)
1353 {
1354 fprintf (stderr,
1355 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1356 node->file, cur_node->file, node->name);
1357 }
1358 cur_node->been_warned = TRUE;
1359 return;
1360 }
1361
1362 /* Maybe refuse to add duplicate nodes. */
1363 if (!permit_duplicates)
1364 {
1a0d8c80
FP
1365 if (streq (node->name, cur_node->name)
1366 && streq (node->file, cur_node->file))
c6d46f5f
JB
1367 return;
1368 }
1369
1370 /* Actually add the node */
1371 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1372 }
1373}
1374\f
1375void
1376put_entries (node)
13fde0cd 1377 register NODE *node;
c6d46f5f 1378{
13fde0cd 1379 register char *sp;
c6d46f5f
JB
1380
1381 if (node == NULL)
1382 return;
1383
1384 /* Output subentries that precede this one */
1385 put_entries (node->left);
1386
1387 /* Output this entry */
1388
32daa216 1389 if (!CTAGS)
c6d46f5f 1390 {
fe0b3356 1391 if (node->named)
c6d46f5f 1392 {
6dd5561c 1393 fprintf (tagf, "%s\177%s\001%d,%d\n",
cc6d6e58
RM
1394 node->pat, node->name,
1395 node->lno, node->cno);
c6d46f5f
JB
1396 }
1397 else
1398 {
6dd5561c 1399 fprintf (tagf, "%s\177%d,%d\n",
cc6d6e58
RM
1400 node->pat,
1401 node->lno, node->cno);
c6d46f5f
JB
1402 }
1403 }
1404 else if (!cxref_style)
1405 {
6dd5561c 1406 fprintf (tagf, "%s\t%s\t",
c6d46f5f
JB
1407 node->name, node->file);
1408
1409 if (node->is_func)
1410 { /* a function */
6dd5561c
FP
1411 putc (searchar, tagf);
1412 putc ('^', tagf);
c6d46f5f
JB
1413
1414 for (sp = node->pat; *sp; sp++)
1415 {
1416 if (*sp == '\\' || *sp == searchar)
6dd5561c
FP
1417 putc ('\\', tagf);
1418 putc (*sp, tagf);
c6d46f5f 1419 }
6dd5561c 1420 putc (searchar, tagf);
c6d46f5f
JB
1421 }
1422 else
1423 { /* a typedef; text pattern inadequate */
6dd5561c 1424 fprintf (tagf, "%d", node->lno);
c6d46f5f 1425 }
6dd5561c 1426 putc ('\n', tagf);
c6d46f5f
JB
1427 }
1428 else if (vgrind_style)
1429 fprintf (stdout, "%s %s %d\n",
1430 node->name, node->file, (node->lno + 63) / 64);
1431 else
daa37602 1432 fprintf (stdout, "%-16s %3d %-16s %s\n",
c6d46f5f
JB
1433 node->name, node->lno, node->file, node->pat);
1434
1435 /* Output subentries that follow this one */
1436 put_entries (node->right);
1437}
1438
1439/* Length of a number's decimal representation. */
1440int
1441number_len (num)
1442 long num;
1443{
1444 int len = 0;
1445 if (!num)
1446 return 1;
1447 for (; num; num /= 10)
1448 ++len;
1449 return len;
1450}
1451
1452/*
1453 * Return total number of characters that put_entries will output for
32daa216
FP
1454 * the nodes in the subtree of the specified node. Works only if
1455 * we are not ctags, but called only in that case. This count
1456 * is irrelevant with the new tags.el, but is still supplied for
1457 * backward compatibility.
c6d46f5f
JB
1458 */
1459int
1460total_size_of_entries (node)
13fde0cd 1461 register NODE *node;
c6d46f5f 1462{
13fde0cd 1463 register int total;
c6d46f5f
JB
1464
1465 if (node == NULL)
1466 return 0;
1467
1468 total = 0;
1469 for (; node; node = node->right)
1470 {
1471 /* Count left subentries. */
1472 total += total_size_of_entries (node->left);
1473
1474 /* Count this entry */
1475 total += strlen (node->pat) + 1;
1476 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
fe0b3356 1477 if (node->named)
c6d46f5f
JB
1478 total += 1 + strlen (node->name); /* \001name */
1479 }
1480
1481 return total;
1482}
1483\f
1484/*
1485 * The C symbol tables.
1486 */
1487
42680d3c
FP
1488/* Feed stuff between (but not including) %[ and %] lines to:
1489 gperf -c -k1,3 -o -p -r -t
1490%[
1491struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1492%%
1493class, C_PLPL, st_C_struct
1494domain, C_STAR, st_C_struct
1495union, 0, st_C_struct
1496struct, 0, st_C_struct
1497enum, 0, st_C_enum
1498typedef, 0, st_C_typedef
1499define, 0, st_C_define
1500long, 0, st_C_typespec
1501short, 0, st_C_typespec
1502int, 0, st_C_typespec
1503char, 0, st_C_typespec
1504float, 0, st_C_typespec
1505double, 0, st_C_typespec
1506signed, 0, st_C_typespec
1507unsigned, 0, st_C_typespec
1508auto, 0, st_C_typespec
1509void, 0, st_C_typespec
1510extern, 0, st_C_typespec
1511static, 0, st_C_typespec
1512const, 0, st_C_typespec
1513volatile, 0, st_C_typespec
1514%]
1515and replace lines between %< and %> with its output. */
1516/*%<*/
1517/* C code produced by gperf version 1.8.1 (K&R C version) */
1518/* Command-line: gperf -c -k1,3 -o -p -r -t */
1519
1520
1521struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1522
1523#define MIN_WORD_LENGTH 3
1524#define MAX_WORD_LENGTH 8
1525#define MIN_HASH_VALUE 10
1526#define MAX_HASH_VALUE 62
c6d46f5f 1527/*
42680d3c
FP
1528 21 keywords
1529 53 is the maximum key range
1530*/
1531
1532static int
1533hash (str, len)
1534 register char *str;
1535 register int len;
1536{
1537 static unsigned char hash_table[] =
1538 {
1539 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1540 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1541 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1542 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1543 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1544 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
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, 2, 62, 7,
1549 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1550 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1551 62, 62, 62, 62, 62, 62, 62, 62,
1552 };
1553 return len + hash_table[str[2]] + hash_table[str[0]];
1554}
c6d46f5f 1555
42680d3c
FP
1556struct C_stab_entry *
1557in_word_set (str, len)
1558 register char *str;
1559 register int len;
1560{
1561
1562 static struct C_stab_entry wordlist[] =
1563 {
1564 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1565 {"",},
1566 {"volatile", 0, st_C_typespec},
1567 {"",},
1568 {"long", 0, st_C_typespec},
1569 {"char", 0, st_C_typespec},
1570 {"class", C_PLPL, st_C_struct},
1571 {"",}, {"",}, {"",}, {"",},
1572 {"const", 0, st_C_typespec},
1573 {"",}, {"",}, {"",}, {"",},
1574 {"auto", 0, st_C_typespec},
1575 {"",}, {"",},
1576 {"define", 0, st_C_define},
1577 {"",},
1578 {"void", 0, st_C_typespec},
1579 {"",}, {"",}, {"",},
1580 {"extern", 0, st_C_typespec},
1581 {"static", 0, st_C_typespec},
1582 {"",},
1583 {"domain", C_STAR, st_C_struct},
1584 {"",},
1585 {"typedef", 0, st_C_typedef},
1586 {"double", 0, st_C_typespec},
1587 {"enum", 0, st_C_enum},
1588 {"",}, {"",}, {"",}, {"",},
1589 {"int", 0, st_C_typespec},
1590 {"",},
1591 {"float", 0, st_C_typespec},
1592 {"",}, {"",}, {"",},
1593 {"struct", 0, st_C_struct},
1594 {"",}, {"",}, {"",}, {"",},
1595 {"union", 0, st_C_struct},
1596 {"",},
1597 {"short", 0, st_C_typespec},
1598 {"",}, {"",},
1599 {"unsigned", 0, st_C_typespec},
1600 {"signed", 0, st_C_typespec},
1601 };
1602
1603 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1604 {
1605 register int key = hash (str, len);
1606
1607 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1608 {
1609 register char *s = wordlist[key].name;
1610
1a0d8c80 1611 if (*s == *str && strneq (str + 1, s + 1, len - 1))
42680d3c
FP
1612 return &wordlist[key];
1613 }
1614 }
1615 return 0;
c6d46f5f 1616}
42680d3c 1617/*%>*/
c6d46f5f 1618
42680d3c
FP
1619enum sym_type
1620C_symtype(str, len, c_ext)
1621 char *str;
1622 int len;
c6d46f5f
JB
1623 int c_ext;
1624{
42680d3c 1625 register struct C_stab_entry *se = in_word_set(str, len);
c6d46f5f 1626
42680d3c
FP
1627 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1628 return st_none;
1629 return se->type;
c6d46f5f
JB
1630}
1631\f
13fde0cd 1632 /*
13fde0cd
RS
1633 * C functions are recognized using a simple finite automaton.
1634 * funcdef is its state variable.
1635 */
1636typedef enum
1637{
31d4b314
FP
1638 fnone, /* nothing seen */
1639 ftagseen, /* function-like tag seen */
b12756c8 1640 fstartlist, /* just after open parenthesis */
31d4b314
FP
1641 finlist, /* in parameter list */
1642 flistseen, /* after parameter list */
46e4cb76 1643 fignore /* before open brace */
13fde0cd
RS
1644} FUNCST;
1645FUNCST funcdef;
1646
1647
46c145db
FP
1648 /*
1649 * typedefs are recognized using a simple finite automaton.
13fde0cd
RS
1650 * typeddef is its state variable.
1651 */
1652typedef enum
1653{
31d4b314
FP
1654 tnone, /* nothing seen */
1655 ttypedseen, /* typedef keyword seen */
1656 tinbody, /* inside typedef body */
46c145db
FP
1657 tend, /* just before typedef tag */
1658 tignore /* junk after typedef tag */
13fde0cd
RS
1659} TYPEDST;
1660TYPEDST typdef;
1661
1662
46c145db
FP
1663 /*
1664 * struct-like structures (enum, struct and union) are recognized
1665 * using another simple finite automaton. `structdef' is its state
1666 * variable.
13fde0cd
RS
1667 */
1668typedef enum
1669{
1670 snone, /* nothing seen yet */
1671 skeyseen, /* struct-like keyword seen */
1672 stagseen, /* struct-like tag seen */
1673 scolonseen, /* colon seen after struct-like tag */
46e4cb76 1674 sinbody /* in struct body: recognize member func defs*/
13fde0cd
RS
1675} STRUCTST;
1676STRUCTST structdef;
46c145db 1677
13fde0cd
RS
1678/*
1679 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
42680d3c
FP
1680 * struct tag, and structtype is the type of the preceding struct-like
1681 * keyword.
13fde0cd
RS
1682 */
1683char structtag[BUFSIZ];
42680d3c 1684enum sym_type structtype;
13fde0cd
RS
1685
1686/*
1687 * Yet another little state machine to deal with preprocessor lines.
1688 */
1689typedef enum
1690{
1691 dnone, /* nothing seen */
1692 dsharpseen, /* '#' seen as first char on line */
1693 ddefineseen, /* '#' and 'define' seen */
46e4cb76 1694 dignorerest /* ignore rest of line */
13fde0cd
RS
1695} DEFINEST;
1696DEFINEST definedef;
1697
1698/*
1699 * Set this to TRUE, and the next token considered is called a function.
cdc1f6a7 1700 * Used only for GNU emacs's function-defining macros.
13fde0cd
RS
1701 */
1702logical next_token_is_func;
1703
1704/*
1705 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1706 */
1707logical yacc_rules;
1708
6dd5561c
FP
1709/*
1710 * consider_token ()
1711 * checks to see if the current token is at the start of a
1712 * function, or corresponds to a typedef, or is a struct/union/enum
1713 * tag.
1714 *
1715 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1716 * C_EXT is which language we are looking at.
1717 *
1718 * In the future we will need some way to adjust where the end of
1719 * the token is; for instance, implementing the C++ keyword
1720 * `operator' properly will adjust the end of the token to be after
1721 * whatever follows `operator'.
1722 *
1723 * Globals
1724 * funcdef IN OUT
1725 * structdef IN OUT
1726 * definedef IN OUT
1727 * typdef IN OUT
1728 * next_token_is_func IN OUT
1729 */
1730
1731logical
1732consider_token (c, tokp, c_ext, cblev, is_func)
1733 register char c; /* IN: first char after the token */
1734 register TOKEN *tokp; /* IN: token pointer */
1735 int c_ext; /* IN: C extensions mask */
1736 int cblev; /* IN: curly brace level */
715b6f8c 1737 logical *is_func; /* OUT: function found */
6dd5561c
FP
1738{
1739 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1740
1741 /*
1742 * Advance the definedef state machine.
1743 */
1744 switch (definedef)
1745 {
1746 case dnone:
1747 /* We're not on a preprocessor line. */
1748 break;
1749 case dsharpseen:
1750 if (toktype == st_C_define)
1751 {
1752 definedef = ddefineseen;
1753 }
1754 else
1755 {
1756 definedef = dignorerest;
1757 }
b9755a12 1758 return FALSE;
6dd5561c
FP
1759 case ddefineseen:
1760 /*
ee70dba5
FP
1761 * Make a tag for any macro, unless it is a constant
1762 * and constantypedefs is FALSE.
6dd5561c
FP
1763 */
1764 definedef = dignorerest;
1765 *is_func = (c == '(');
1766 if (!*is_func && !constantypedefs)
b9755a12 1767 return FALSE;
6dd5561c 1768 else
b9755a12 1769 return TRUE;
6dd5561c 1770 case dignorerest:
b9755a12 1771 return FALSE;
6dd5561c
FP
1772 default:
1773 error ("internal error: definedef value.", 0);
1774 }
1775
1776 /*
1777 * Now typedefs
1778 */
1779 switch (typdef)
1780 {
1781 case tnone:
1782 if (toktype == st_C_typedef)
1783 {
1784 if (typedefs)
1785 typdef = ttypedseen;
1786 funcdef = fnone;
b9755a12 1787 return FALSE;
6dd5561c
FP
1788 }
1789 break;
1790 case ttypedseen:
1791 switch (toktype)
1792 {
1793 case st_none:
1794 case st_C_typespec:
1795 typdef = tend;
1796 break;
1797 case st_C_struct:
1798 case st_C_enum:
1799 break;
1800 }
1801 /* Do not return here, so the structdef stuff has a chance. */
1802 break;
1803 case tend:
1804 switch (toktype)
1805 {
1806 case st_C_typespec:
1807 case st_C_struct:
1808 case st_C_enum:
b9755a12 1809 return FALSE;
6dd5561c 1810 }
b9755a12 1811 return TRUE;
6dd5561c
FP
1812 }
1813
1814 /*
1815 * This structdef business is currently only invoked when cblev==0.
1816 * It should be recursively invoked whatever the curly brace level,
1817 * and a stack of states kept, to allow for definitions of structs
1818 * within structs.
1819 *
1820 * This structdef business is NOT invoked when we are ctags and the
1821 * file is plain C. This is because a struct tag may have the same
1822 * name as another tag, and this loses with ctags.
1823 *
1824 * This if statement deals with the typdef state machine as
1825 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
b9755a12 1826 * return FALSE. All the other code here is for the structdef
6dd5561c
FP
1827 * state machine.
1828 */
1829 switch (toktype)
1830 {
1831 case st_C_struct:
1832 case st_C_enum:
1833 if (typdef == ttypedseen
1834 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1835 {
1836 structdef = skeyseen;
1837 structtype = toktype;
1838 }
b9755a12 1839 return FALSE;
6dd5561c
FP
1840 }
1841 if (structdef == skeyseen)
1842 {
1843 if (structtype == st_C_struct)
1844 {
1845 strncpy (structtag, tokp->p, tokp->len);
1846 structtag[tokp->len] = '\0'; /* for struct/union/class */
1847 }
1848 else
1849 {
1850 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1851 }
1852 structdef = stagseen;
b9755a12 1853 return TRUE;
6dd5561c
FP
1854 }
1855
1856 /* Avoid entering funcdef stuff if typdef is going on. */
1857 if (typdef != tnone)
1858 {
1859 definedef = dnone;
b9755a12 1860 return FALSE;
6dd5561c
FP
1861 }
1862
715b6f8c 1863 /* Detect GNU macros. */
6dd5561c 1864 if (definedef == dnone)
715b6f8c
FP
1865 if (strneq (tokp->p, "DEFUN", 5) /* Used in emacs */
1866#if FALSE
1867 These are defined inside C functions, so currently they
1868 are not met anyway.
1869 || strneq (tokp->p, "EXFUN", 5) /* Used in glibc */
1870 || strneq (tokp->p, "DEFVAR_", 7) /* Used in emacs */
1871#endif
1872 || strneq (tokp->p, "SYSCALL", 7) /* Used in glibc (mach) */
1873 || strneq (tokp->p, "ENTRY", 5) /* Used in glibc */
1874 || strneq (tokp->p, "PSEUDO", 6)) /* Used in glibc */
1875
1876 {
1877 next_token_is_func = TRUE;
b9755a12 1878 return FALSE;
715b6f8c 1879 }
6dd5561c
FP
1880 if (next_token_is_func)
1881 {
1882 next_token_is_func = FALSE;
715b6f8c
FP
1883 funcdef = fignore;
1884 *is_func = TRUE;
b9755a12 1885 return TRUE;
6dd5561c
FP
1886 }
1887
1888 /* A function? */
1889 switch (toktype)
1890 {
1891 case st_C_typespec:
1892 if (funcdef != finlist && funcdef != fignore)
1893 funcdef = fnone; /* should be useless */
b9755a12 1894 return FALSE;
6dd5561c
FP
1895 default:
1896 if (funcdef == fnone)
1897 {
1898 funcdef = ftagseen;
1899 *is_func = TRUE;
b9755a12 1900 return TRUE;
6dd5561c
FP
1901 }
1902 }
1903
b9755a12 1904 return FALSE;
6dd5561c
FP
1905}
1906
c6d46f5f
JB
1907/*
1908 * C_entries ()
13fde0cd
RS
1909 * This routine finds functions, typedefs, #define's and
1910 * struct/union/enum definitions in C syntax and adds them
c6d46f5f
JB
1911 * to the list.
1912 */
1913
13fde0cd
RS
1914#define curlb (lbs[curndx].lb)
1915#define othlb (lbs[1-curndx].lb)
1916#define newlb (lbs[newndx].lb)
1917#define curlinepos (lbs[curndx].linepos)
1918#define othlinepos (lbs[1-curndx].linepos)
1919#define newlinepos (lbs[newndx].linepos)
1920
b12756c8
FP
1921/* Save and restore token state. This is used when preprocessor defines
1922 are handled, to avoid disturbing active function/typedef/struct states. */
1923#define TOKEN_SAVED_P (savetok.lineno > 0)
1924#define SAVE_TOKEN (savetok = tok, savetok.p = (char *) tokoff, \
1925 savetok.len = toklen, strcpy(savenameb, nameb))
1926#define RESTORE_TOKEN (tok = savetok, tokoff = (int) tok.p, \
1927 toklen = tok.len, strcpy(nameb, savenameb), \
1928 savetok.lineno = 0)
1929
c6d46f5f 1930#define CNL_SAVE_DEFINEDEF \
13fde0cd
RS
1931do { \
1932 SET_FILEPOS (curlinepos, inf, charno); \
c6d46f5f 1933 lineno++; \
13fde0cd
RS
1934 charno += readline (&curlb, inf); \
1935 lp = curlb.buffer; \
1936 quotednl = FALSE; \
1937 newndx = curndx; \
b9755a12 1938} while (0)
c6d46f5f
JB
1939
1940#define CNL \
13fde0cd 1941do { \
c6d46f5f 1942 CNL_SAVE_DEFINEDEF; \
b12756c8
FP
1943 if (TOKEN_SAVED_P) \
1944 RESTORE_TOKEN; \
c6d46f5f 1945 definedef = dnone; \
b9755a12 1946} while (0)
13fde0cd 1947
fe0b3356 1948#define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
13fde0cd 1949 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
fe0b3356 1950#define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
13fde0cd 1951 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
c6d46f5f
JB
1952
1953void
6dd5561c 1954C_entries (c_ext, inf)
b9755a12
FP
1955 int c_ext; /* extension of C */
1956 FILE *inf; /* input file */
c6d46f5f 1957{
13fde0cd 1958 register char c; /* latest char read; '\0' for end of line */
c6d46f5f 1959 register char *lp; /* pointer one beyond the character `c' */
13fde0cd
RS
1960 int curndx, newndx; /* indices for current and new lb */
1961 TOKEN tok; /* latest token read for funcdef & structdef */
fe0b3356 1962 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
13fde0cd
RS
1963 register int tokoff; /* offset in line of start of latest token */
1964 register int toklen; /* length of latest token */
591fa824 1965 int cblev; /* current curly brace level */
b12756c8 1966 int parlev; /* current parenthesis level */
13fde0cd
RS
1967 logical incomm, inquote, inchar, quotednl, midtoken;
1968 logical cplpl;
b12756c8 1969 TOKEN savetok; /* saved token during preprocessor handling */
b12756c8 1970 char savenameb[BUFSIZ]; /* ouch! */
c6d46f5f 1971
b12756c8 1972 savetok.lineno = 0;
13fde0cd 1973 curndx = newndx = 0;
c6d46f5f
JB
1974 lineno = 0;
1975 charno = 0;
13fde0cd 1976 lp = curlb.buffer;
c6d46f5f
JB
1977 *lp = 0;
1978
46c145db 1979 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
13fde0cd
RS
1980 next_token_is_func = yacc_rules = FALSE;
1981 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1982 cblev = 0;
b12756c8 1983 parlev = 0;
13fde0cd 1984 cplpl = c_ext & C_PLPL;
c6d46f5f 1985
c6d46f5f
JB
1986 while (!feof (inf))
1987 {
1988 c = *lp++;
c6d46f5f
JB
1989 if (c == '\\')
1990 {
4746118a
JB
1991 /* If we're at the end of the line, the next character is a
1992 '\0'; don't skip it, because it's the thing that tells us
1993 to read the next line. */
13fde0cd 1994 if (*lp == '\0')
99e0a2e0 1995 {
13fde0cd 1996 quotednl = TRUE;
99e0a2e0
RS
1997 continue;
1998 }
1e134a5f 1999 lp++;
c6d46f5f
JB
2000 c = ' ';
2001 }
2002 else if (incomm)
2003 {
13fde0cd 2004 switch (c)
c6d46f5f 2005 {
13fde0cd
RS
2006 case '*':
2007 if (*lp == '/')
2008 {
2009 c = *lp++;
2010 incomm = FALSE;
2011 }
2012 break;
2013 case '\0':
2014 /* Newlines inside comments do not end macro definitions in
2015 traditional cpp. */
2016 CNL_SAVE_DEFINEDEF;
2017 break;
c6d46f5f 2018 }
13fde0cd 2019 continue;
c6d46f5f
JB
2020 }
2021 else if (inquote)
2022 {
13fde0cd
RS
2023 switch (c)
2024 {
2025 case '"':
2026 inquote = FALSE;
2027 break;
2028 case '\0':
42680d3c 2029 /* Newlines inside strings do not end macro definitions
13fde0cd
RS
2030 in traditional cpp, even though compilers don't
2031 usually accept them. */
2032 CNL_SAVE_DEFINEDEF;
2033 break;
2034 }
2035 continue;
c6d46f5f
JB
2036 }
2037 else if (inchar)
2038 {
42680d3c
FP
2039 switch (c)
2040 {
2041 case '\0':
2042 /* Hmmm, something went wrong. */
2043 CNL;
2044 /* FALLTHRU */
2045 case '\'':
46c145db 2046 inchar = FALSE;
42680d3c
FP
2047 break;
2048 }
c6d46f5f
JB
2049 continue;
2050 }
13fde0cd 2051 else
c6d46f5f
JB
2052 switch (c)
2053 {
2054 case '"':
2055 inquote = TRUE;
b12756c8
FP
2056 if (funcdef != finlist && funcdef != fignore)
2057 funcdef = fnone;
c6d46f5f
JB
2058 continue;
2059 case '\'':
2060 inchar = TRUE;
b12756c8
FP
2061 if (funcdef != finlist && funcdef != fignore)
2062 funcdef = fnone;
c6d46f5f
JB
2063 continue;
2064 case '/':
2065 if (*lp == '*')
2066 {
2067 lp++;
2068 incomm = TRUE;
13fde0cd 2069 continue;
c6d46f5f 2070 }
13fde0cd 2071 else if (cplpl && *lp == '/')
c6d46f5f 2072 {
daa37602
JB
2073 c = 0;
2074 break;
c6d46f5f 2075 }
b12756c8
FP
2076 else
2077 break;
13fde0cd
RS
2078 case '%':
2079 if ((c_ext & YACC) && *lp == '%')
2080 {
2081 /* entering or exiting rules section in yacc file */
2082 lp++;
2083 definedef = dnone; funcdef = fnone;
46c145db 2084 typdef = tnone; structdef = snone;
13fde0cd
RS
2085 next_token_is_func = FALSE;
2086 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 2087 cblev = 0;
13fde0cd
RS
2088 yacc_rules = !yacc_rules;
2089 continue;
591fa824 2090 }
b12756c8
FP
2091 else
2092 break;
c6d46f5f 2093 case '#':
ee70dba5
FP
2094 if (definedef == dnone)
2095 {
2096 char *cp;
2097 logical cpptoken = TRUE;
2098
2099 /* Look back on this line. If all blanks, or nonblanks
2100 followed by an end of comment, this is a preprocessor
2101 token. */
2102 for (cp = newlb.buffer; cp < lp-1; cp++)
2103 if (!iswhite (*cp))
2104 {
2105 if (*cp == '*' && *(cp+1) == '/')
2106 {
2107 cp++;
2108 cpptoken = TRUE;
2109 }
2110 else
2111 cpptoken = FALSE;
2112 }
2113 if (cpptoken)
2114 definedef = dsharpseen;
2115 } /* if (definedef == dnone) */
2116
c6d46f5f 2117 continue;
13fde0cd 2118 } /* switch (c) */
c6d46f5f 2119
c6d46f5f 2120
591fa824 2121 /* Consider token only if some complicated conditions are satisfied. */
ee70dba5
FP
2122 if ((definedef != dnone
2123 || (cblev == 0 && structdef != scolonseen)
591fa824 2124 || (cblev == 1 && cplpl && structdef == sinbody))
46c145db 2125 && typdef != tignore
13fde0cd 2126 && definedef != dignorerest
ee70dba5 2127 && funcdef != finlist)
c6d46f5f
JB
2128 {
2129 if (midtoken)
2130 {
2131 if (endtoken (c))
2132 {
b12756c8 2133 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
c6d46f5f
JB
2134 {
2135 /*
ee70dba5
FP
2136 * This handles :: in the middle, but not at the
2137 * beginning of an identifier.
c6d46f5f
JB
2138 */
2139 lp += 2;
2140 toklen += 3;
2141 }
2142 else
2143 {
fe0b3356 2144 logical is_func = FALSE;
c6d46f5f 2145
13fde0cd
RS
2146 tok.lineno = lineno;
2147 tok.p = newlb.buffer + tokoff;
c6d46f5f 2148 tok.len = toklen;
fe0b3356 2149 tok.named = FALSE;
13fde0cd 2150 if (yacc_rules
42680d3c 2151 || consider_token (c, &tok, c_ext, cblev, &is_func))
c6d46f5f 2152 {
99e0a2e0 2153 if (structdef == sinbody
fe0b3356
FP
2154 && definedef == dnone
2155 && is_func)
2156 /* function defined in C++ class body */
2157 {
fe0b3356 2158 sprintf (nameb, "%s::%.*s",
13fde0cd
RS
2159 ((structtag[0] == '\0')
2160 ? "_anonymous_" : structtag),
c6d46f5f 2161 tok.len, tok.p);
ee70dba5 2162 tok.named = TRUE;
c6d46f5f
JB
2163 }
2164 else
2165 {
fe0b3356 2166 sprintf (nameb, "%.*s", tok.len, tok.p);
c6d46f5f 2167 }
13fde0cd 2168
fe0b3356 2169 if (structdef == stagseen
ee70dba5 2170 || typdef == tend
715b6f8c
FP
2171 || (is_func
2172 && definedef == dignorerest)) /* macro */
fe0b3356
FP
2173 tok.named = TRUE;
2174
b12756c8
FP
2175 if (definedef == dnone
2176 && (funcdef == ftagseen
2177 || structdef == stagseen
2178 || typdef == tend))
13fde0cd
RS
2179 {
2180 if (newndx == curndx)
2181 curndx = 1 - curndx; /* switch line buffers */
2182 }
2183 else
2184 MAKE_TAG_FROM_NEW_LB (is_func);
c6d46f5f
JB
2185 }
2186 midtoken = FALSE;
2187 }
13fde0cd 2188 } /* if (endtoken (c)) */
c6d46f5f 2189 else if (intoken (c))
13fde0cd
RS
2190 {
2191 toklen++;
2192 continue;
2193 }
2194 } /* if (midtoken) */
c6d46f5f
JB
2195 else if (begtoken (c))
2196 {
b12756c8 2197 switch (definedef)
13fde0cd 2198 {
b12756c8
FP
2199 case dnone:
2200 switch (funcdef)
2201 {
2202 case fstartlist:
2203 funcdef = finlist;
2204 continue;
2205 case flistseen:
2206 MAKE_TAG_FROM_OTH_LB (TRUE);
2207 funcdef = fignore;
2208 break;
2209 case ftagseen:
2210 funcdef = fnone;
2211 break;
2212 }
2213 if (structdef == stagseen)
2214 structdef = snone;
13fde0cd 2215 break;
b12756c8 2216 case dsharpseen:
ee70dba5 2217 /* Take a quick peek ahead for a define directive,
b12756c8
FP
2218 so we can avoid saving the token when not absolutely
2219 necessary. [This is a speed hack.] */
715b6f8c
FP
2220 if (c == 'd' && strneq (lp, "efine", 5)
2221 && iswhite (*(lp + 5)))
b12756c8
FP
2222 {
2223 SAVE_TOKEN;
2224 definedef = ddefineseen;
2225 lp += 6;
2226 }
2227 else
2228 definedef = dignorerest;
2229 continue;
13fde0cd 2230 }
13fde0cd
RS
2231 if (!yacc_rules || lp == newlb.buffer + 1)
2232 {
2233 tokoff = lp - 1 - newlb.buffer;
2234 toklen = 1;
2235 midtoken = TRUE;
2236 }
2237 continue;
c6d46f5f 2238 }
13fde0cd
RS
2239 } /* if must look at token */
2240
2241
2242 /* Detect end of line, colon, comma, semicolon and various braces
b12756c8 2243 after having handled a token.*/
13fde0cd 2244 switch (c)
1e134a5f 2245 {
13fde0cd 2246 case ':':
b12756c8
FP
2247 if (definedef != dnone)
2248 break;
13fde0cd
RS
2249 if (structdef == stagseen)
2250 structdef = scolonseen;
b12756c8
FP
2251 else
2252 switch (funcdef)
2253 {
2254 case ftagseen:
2255 if (yacc_rules)
2256 {
2257 MAKE_TAG_FROM_OTH_LB (FALSE);
2258 funcdef = fignore;
2259 }
2260 break;
2261 case fstartlist:
2262 funcdef = fnone;
2263 break;
2264 }
13fde0cd
RS
2265 break;
2266 case ';':
b12756c8
FP
2267 if (definedef != dnone)
2268 break;
46c145db
FP
2269 if (cblev == 0)
2270 switch (typdef)
2271 {
2272 case tend:
2273 MAKE_TAG_FROM_OTH_LB (FALSE);
2274 /* FALLTHRU */
2275 default:
2276 typdef = tnone;
2277 }
31d4b314
FP
2278 if (funcdef != fignore)
2279 funcdef = fnone;
46c145db
FP
2280 if (structdef == stagseen)
2281 structdef = snone;
2282 break;
13fde0cd 2283 case ',':
46c145db
FP
2284 if (definedef != dnone)
2285 break;
2286 if (funcdef != finlist && funcdef != fignore)
2287 funcdef = fnone;
2288 if (structdef == stagseen)
2289 structdef = snone;
2290 break;
13fde0cd 2291 case '[':
b12756c8
FP
2292 if (definedef != dnone)
2293 break;
46c145db
FP
2294 if (cblev == 0 && typdef == tend)
2295 {
2296 typdef = tignore;
2297 MAKE_TAG_FROM_OTH_LB (FALSE);
2298 break;
2299 }
31d4b314 2300 if (funcdef != finlist && funcdef != fignore)
13fde0cd
RS
2301 funcdef = fnone;
2302 if (structdef == stagseen)
2303 structdef = snone;
2304 break;
2305 case '(':
b12756c8
FP
2306 if (definedef != dnone)
2307 break;
13fde0cd 2308 switch (funcdef)
57e83cfe 2309 {
ee70dba5
FP
2310 case fnone:
2311 switch (typdef)
2312 {
2313 case ttypedseen:
2314 case tend:
2315 /* Make sure that the next char is not a '*'.
2316 This handles constructs like:
2317 typedef void OperatorFun (int fun); */
2318 if (*lp != '*')
2319 {
2320 typdef = tignore;
2321 MAKE_TAG_FROM_OTH_LB (FALSE);
2322 }
2323 break;
2324 } /* switch (typdef) */
2325 break;
13fde0cd 2326 case ftagseen:
b12756c8 2327 funcdef = fstartlist;
13fde0cd 2328 break;
13fde0cd 2329 case flistseen:
b12756c8 2330 funcdef = finlist;
13fde0cd 2331 break;
57e83cfe 2332 }
b12756c8 2333 parlev++;
13fde0cd
RS
2334 break;
2335 case ')':
b12756c8
FP
2336 if (definedef != dnone)
2337 break;
2338 if (--parlev == 0)
2339 {
2340 switch (funcdef)
2341 {
2342 case fstartlist:
2343 case finlist:
2344 funcdef = flistseen;
2345 break;
2346 }
46c145db
FP
2347 if (cblev == 0 && typdef == tend)
2348 {
2349 typdef = tignore;
2350 MAKE_TAG_FROM_OTH_LB (FALSE);
2351 }
b12756c8
FP
2352 }
2353 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2354 parlev = 0;
13fde0cd
RS
2355 break;
2356 case '{':
b12756c8
FP
2357 if (definedef != dnone)
2358 break;
13fde0cd
RS
2359 if (typdef == ttypedseen)
2360 typdef = tinbody;
2361 switch (structdef)
2362 {
2363 case skeyseen: /* unnamed struct */
2364 structtag[0] = '\0';
2365 structdef = sinbody;
2366 break;
2367 case stagseen:
2368 case scolonseen: /* named struct */
2369 structdef = sinbody;
2370 MAKE_TAG_FROM_OTH_LB (FALSE);
2371 break;
2372 }
31d4b314
FP
2373 switch (funcdef)
2374 {
2375 case flistseen:
2376 MAKE_TAG_FROM_OTH_LB (TRUE);
2377 /* FALLTHRU */
2378 case fignore:
2379 funcdef = fnone;
46c145db
FP
2380 break;
2381 case fnone:
715b6f8c 2382 /* Neutralize `extern "C" {' grot and look inside structs. */
46c145db 2383 if (cblev == 0 && structdef == snone && typdef == tnone)
715b6f8c 2384 cblev = -1;
31d4b314 2385 }
591fa824 2386 cblev++;
31d4b314 2387 break;
13fde0cd 2388 case '*':
b12756c8
FP
2389 if (definedef != dnone)
2390 break;
2391 if (funcdef == fstartlist)
2392 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
13fde0cd
RS
2393 break;
2394 case '}':
b12756c8
FP
2395 if (definedef != dnone)
2396 break;
13fde0cd 2397 if (!noindentypedefs && lp == newlb.buffer + 1)
b12756c8
FP
2398 {
2399 cblev = 0; /* reset curly brace level if first column */
2400 parlev = 0; /* also reset paren level, just in case... */
2401 }
591fa824
RS
2402 else if (cblev > 0)
2403 cblev--;
2404 if (cblev == 0)
13fde0cd
RS
2405 {
2406 if (typdef == tinbody)
2407 typdef = tend;
2408 structdef = snone;
1a0d8c80 2409 strcpy (structtag, "<error 2>");
13fde0cd
RS
2410 }
2411 break;
b12756c8 2412 case '=':
42680d3c
FP
2413 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2414 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
b12756c8
FP
2415 if (definedef != dnone)
2416 break;
2417 /* These surely cannot follow a function tag. */
2418 if (funcdef != finlist && funcdef != fignore)
2419 funcdef = fnone;
2420 break;
13fde0cd
RS
2421 case '\0':
2422 /* If a macro spans multiple lines don't reset its state. */
2423 if (quotednl)
2424 CNL_SAVE_DEFINEDEF;
2425 else
2426 CNL;
2427 break;
2428 } /* switch (c) */
2429
2430 } /* while not eof */
c6d46f5f 2431}
b9755a12
FP
2432
2433/*
2434 * Process either a C++ file or a C file depending on the setting
2435 * of a global flag.
2436 */
2437void
2438default_C_entries (inf)
2439 FILE *inf;
2440{
2441 C_entries (cplusplus ? C_PLPL : 0, inf);
2442}
2443
2444/* Always do C++. */
2445void
2446Cplusplus_entries (inf)
2447 FILE *inf;
2448{
2449 C_entries (C_PLPL, inf);
2450}
2451
2452/* Always do C*. */
2453void
2454Cstar_entries (inf)
2455 FILE *inf;
2456{
2457 C_entries (C_STAR, inf);
2458}
2459
2460/* Always do Yacc. */
2461void
2462Yacc_entries (inf)
2463 FILE *inf;
2464{
2465 C_entries (YACC, inf);
2466}
6dd5561c
FP
2467\f
2468/* Fortran parsing */
c6d46f5f 2469
6dd5561c
FP
2470char *dbp;
2471int pfcnt;
c6d46f5f
JB
2472
2473logical
6dd5561c
FP
2474tail (cp)
2475 char *cp;
c6d46f5f 2476{
6dd5561c 2477 register int len = 0;
c6d46f5f 2478
6dd5561c
FP
2479 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2480 cp++, len++;
2481 if (*cp == 0)
c6d46f5f 2482 {
6dd5561c 2483 dbp += len;
b9755a12 2484 return TRUE;
c6d46f5f 2485 }
b9755a12 2486 return FALSE;
6dd5561c 2487}
13fde0cd 2488
6dd5561c
FP
2489void
2490takeprec ()
2491{
2492 while (isspace (*dbp))
2493 dbp++;
2494 if (*dbp != '*')
2495 return;
2496 dbp++;
2497 while (isspace (*dbp))
2498 dbp++;
0c1fd2e3
FP
2499 if (tail ("(*)"))
2500 return;
6dd5561c 2501 if (!isdigit (*dbp))
c6d46f5f 2502 {
6dd5561c
FP
2503 --dbp; /* force failure */
2504 return;
c6d46f5f 2505 }
6dd5561c
FP
2506 do
2507 dbp++;
2508 while (isdigit (*dbp));
2509}
13fde0cd 2510
6dd5561c
FP
2511void
2512getit (inf)
2513 FILE *inf;
2514{
2515 register char *cp;
2516 char c;
2517 char nambuf[BUFSIZ];
13fde0cd 2518
6dd5561c
FP
2519 while (isspace (*dbp))
2520 dbp++;
2521 if (*dbp == '\0')
c6d46f5f 2522 {
6dd5561c
FP
2523 lineno++;
2524 linecharno = charno;
2525 charno += readline (&lb, inf);
2526 dbp = lb.buffer;
2527 if (dbp[5] != '&')
2528 return;
2529 dbp += 6;
2530 while (isspace (*dbp))
2531 dbp++;
c6d46f5f 2532 }
6dd5561c
FP
2533 if (!isalpha (*dbp)
2534 && *dbp != '_'
2535 && *dbp != '$')
2536 return;
2537 for (cp = dbp + 1;
2538 (*cp
2539 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2540 cp++)
2541 continue;
2542 c = *cp;
2543 *cp = '\0';
2544 strcpy (nambuf, dbp);
2545 *cp = c;
2546 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2547 cp - lb.buffer + 1, lineno, linecharno);
2548 pfcnt++;
c6d46f5f 2549}
c6d46f5f 2550
b9755a12 2551void
6dd5561c
FP
2552Fortran_functions (inf)
2553 FILE *inf;
c6d46f5f
JB
2554{
2555 lineno = 0;
2556 charno = 0;
2557 pfcnt = 0;
2558
6dd5561c 2559 while (!feof (inf))
c6d46f5f
JB
2560 {
2561 lineno++;
2562 linecharno = charno;
6dd5561c 2563 charno += readline (&lb, inf);
c6d46f5f
JB
2564 dbp = lb.buffer;
2565 if (*dbp == '%')
2566 dbp++; /* Ratfor escape to fortran */
2567 while (isspace (*dbp))
2568 dbp++;
2569 if (*dbp == 0)
2570 continue;
2571 switch (*dbp | ' ')
2572 {
2573 case 'i':
2574 if (tail ("integer"))
2575 takeprec ();
2576 break;
2577 case 'r':
2578 if (tail ("real"))
2579 takeprec ();
2580 break;
2581 case 'l':
2582 if (tail ("logical"))
2583 takeprec ();
2584 break;
2585 case 'c':
2586 if (tail ("complex") || tail ("character"))
2587 takeprec ();
2588 break;
2589 case 'd':
2590 if (tail ("double"))
2591 {
2592 while (isspace (*dbp))
2593 dbp++;
2594 if (*dbp == 0)
2595 continue;
2596 if (tail ("precision"))
2597 break;
2598 continue;
2599 }
2600 break;
2601 }
2602 while (isspace (*dbp))
2603 dbp++;
2604 if (*dbp == 0)
2605 continue;
2606 switch (*dbp | ' ')
2607 {
2608 case 'f':
2609 if (tail ("function"))
6dd5561c 2610 getit (inf);
c6d46f5f
JB
2611 continue;
2612 case 's':
2613 if (tail ("subroutine"))
6dd5561c 2614 getit (inf);
c6d46f5f 2615 continue;
8a6c8bcf
RS
2616 case 'e':
2617 if (tail ("entry"))
6dd5561c 2618 getit (inf);
8a6c8bcf 2619 continue;
c6d46f5f
JB
2620 case 'p':
2621 if (tail ("program"))
2622 {
6dd5561c 2623 getit (inf);
c6d46f5f
JB
2624 continue;
2625 }
2626 if (tail ("procedure"))
6dd5561c 2627 getit (inf);
c6d46f5f
JB
2628 continue;
2629 }
2630 }
c6d46f5f 2631}
6dd5561c
FP
2632\f
2633/*
2634 * Bob Weiner, Motorola Inc., 4/3/94
2635 * Unix and microcontroller assembly tag handling
2636 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2637 */
c6d46f5f 2638void
6dd5561c
FP
2639Asm_labels (inf)
2640 FILE *inf;
c6d46f5f 2641{
6dd5561c 2642 char nambuf[BUFSIZ];
c6d46f5f
JB
2643 register char *cp;
2644 char c;
c6d46f5f
JB
2645
2646 lineno = 0;
2647 charno = 0;
2648 pfcnt = 0;
2649
6dd5561c 2650 while (!feof (inf))
c6d46f5f
JB
2651 {
2652 lineno++;
2653 linecharno = charno;
6dd5561c
FP
2654 charno += readline (&lb, inf);
2655 cp = lb.buffer;
2656
2657 /* If first char is alphabetic or one of [_.$], test for colon
2658 following identifier. */
2659 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2660 {
2661 /* Read past label. */
2662 cp++;
2663 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2664 cp++;
2665 if (*cp == ':' || isspace (*cp))
2666 {
2667 /* Found end of label, so copy it and add it to the table. */
2668 c = *cp;
2669 *cp = '\0';
2670 strcpy (nambuf, lb.buffer);
2671 *cp = c;
2672 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2673 cp - lb.buffer + 1, lineno, linecharno);
2674 pfcnt++;
2675 }
2676 }
c6d46f5f
JB
2677 }
2678}
2679\f
2680/* Added by Mosur Mohan, 4/22/88 */
2681/* Pascal parsing */
2682
2683#define GET_NEW_LINE \
2684{ \
2685 linecharno = charno; lineno++; \
2686 charno += 1 + readline (&lb, inf); \
2687 dbp = lb.buffer; \
2688}
2689
aab1fdae
FP
2690/*
2691 * Locates tags for procedures & functions. Doesn't do any type- or
2692 * var-definitions. It does look for the keyword "extern" or
2693 * "forward" immediately following the procedure statement; if found,
2694 * the tag is skipped.
c6d46f5f 2695 */
c6d46f5f 2696void
6dd5561c
FP
2697Pascal_functions (inf)
2698 FILE *inf;
c6d46f5f
JB
2699{
2700 struct linebuffer tline; /* mostly copied from C_entries */
2701 long save_lcno;
2702 int save_lineno;
2703 char c, *cp;
2704 char nambuf[BUFSIZ];
2705
2706 logical /* each of these flags is TRUE iff: */
b9755a12 2707 incomment, /* point is inside a comment */
c6d46f5f
JB
2708 inquote, /* point is inside '..' string */
2709 get_tagname, /* point is after PROCEDURE/FUNCTION */
2710 /* keyword, so next item = potential tag */
2711 found_tag, /* point is after a potential tag */
2712 inparms, /* point is within parameter-list */
2713 verify_tag; /* point has passed the parm-list, so the */
2714 /* next token will determine whether */
2715 /* this is a FORWARD/EXTERN to be */
2716 /* ignored, or whether it is a real tag */
2717
2718 lineno = 0;
2719 charno = 0;
2720 dbp = lb.buffer;
2721 *dbp = 0;
2722 initbuffer (&tline);
2723
b9755a12 2724 incomment = inquote = FALSE;
c6d46f5f
JB
2725 found_tag = FALSE; /* have a proc name; check if extern */
2726 get_tagname = FALSE; /* have found "procedure" keyword */
2727 inparms = FALSE; /* found '(' after "proc" */
2728 verify_tag = FALSE; /* check if "extern" is ahead */
2729
2730 /* long main loop to get next char */
6dd5561c 2731 while (!feof (inf))
c6d46f5f
JB
2732 {
2733 c = *dbp++;
2734 if (c == 0) /* if end of line */
2735 {
2736 GET_NEW_LINE;
2737 if (*dbp == 0)
2738 continue;
2739 if (!((found_tag && verify_tag) ||
2740 get_tagname))
2741 c = *dbp++; /* only if don't need *dbp pointing */
2742 /* to the beginning of the name of */
2743 /* the procedure or function */
2744 }
b9755a12 2745 if (incomment)
c6d46f5f 2746 {
b9755a12
FP
2747 if (c == '}') /* within { - } comments */
2748 incomment = FALSE;
2749 else if (c == '*' && dbp[1] == ')') /* within (* - *) comments */
c6d46f5f 2750 {
b9755a12
FP
2751 dbp++;
2752 incomment = FALSE;
c6d46f5f
JB
2753 }
2754 continue;
2755 }
2756 else if (inquote)
2757 {
2758 if (c == '\'')
2759 inquote = FALSE;
2760 continue;
2761 }
b9755a12 2762 else
c6d46f5f
JB
2763 switch (c)
2764 {
2765 case '\'':
2766 inquote = TRUE; /* found first quote */
2767 continue;
2768 case '{': /* found open-{-comment */
b9755a12 2769 incomment = TRUE;
c6d46f5f
JB
2770 continue;
2771 case '(':
2772 if (*dbp == '*') /* found open-(*-comment */
2773 {
b9755a12 2774 incomment = TRUE;
c6d46f5f
JB
2775 dbp++;
2776 }
2777 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2778 inparms = TRUE;
2779 continue;
2780 case ')': /* end of parms list */
2781 if (inparms)
2782 inparms = FALSE;
2783 continue;
2784 case ';':
2785 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2786 {
2787 verify_tag = TRUE;
2788 break;
2789 }
2790 continue;
2791 }
2792 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2793 {
2794 /* check if this is an "extern" declaration */
2795 if (*dbp == 0)
2796 continue;
2797 if ((*dbp == 'e') || (*dbp == 'E'))
2798 {
2799 if (tail ("extern")) /* superfluous, really! */
2800 {
2801 found_tag = FALSE;
2802 verify_tag = FALSE;
2803 }
2804 }
2805 else if ((*dbp == 'f') || (*dbp == 'F'))
2806 {
2807 if (tail ("forward")) /* check for forward reference */
2808 {
2809 found_tag = FALSE;
2810 verify_tag = FALSE;
2811 }
2812 }
46c145db 2813 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
c6d46f5f
JB
2814 {
2815 found_tag = FALSE;
2816 verify_tag = FALSE;
2817 pfnote (nambuf, TRUE, FALSE,
2818 tline.buffer, cp - tline.buffer + 1,
2819 save_lineno, save_lcno);
2820 continue;
2821 }
2822 }
2823 if (get_tagname) /* grab name of proc or fn */
2824 {
2825 if (*dbp == 0)
2826 continue;
2827
2828 /* save all values for later tagging */
2829 tline.size = lb.size;
2830 strcpy (tline.buffer, lb.buffer);
2831 save_lineno = lineno;
2832 save_lcno = linecharno;
2833
2834 /* grab block name */
2835 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2836 continue;
2837 c = cp[0];
2838 cp[0] = 0;
2839 strcpy (nambuf, dbp);
2840 cp[0] = c;
2841 dbp = cp; /* restore dbp to e-o-token */
2842 get_tagname = FALSE;
2843 found_tag = TRUE;
2844 continue;
2845
2846 /* and proceed to check for "extern" */
2847 }
b9755a12 2848 if (!incomment && !inquote && !found_tag && !get_tagname)
c6d46f5f
JB
2849 {
2850 /* check for proc/fn keywords */
2851 switch (c | ' ')
2852 {
2853 case 'p':
2854 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2855 get_tagname = TRUE;
2856 continue;
2857 case 'f':
2858 if (tail ("unction"))
2859 get_tagname = TRUE;
2860 continue;
2861 }
2862 }
6dd5561c 2863 } /* while not eof */
c6d46f5f
JB
2864}
2865\f
2866/*
2867 * lisp tag functions
2868 * just look for (def or (DEF
2869 */
2870
c6d46f5f 2871int
b9755a12
FP
2872L_isdef (tokp)
2873 register char *tokp;
c6d46f5f 2874{
b9755a12
FP
2875 return ((tokp[1] == 'd' || tokp[1] == 'D')
2876 && (tokp[2] == 'e' || tokp[2] == 'E')
2877 && (tokp[3] == 'f' || tokp[3] == 'F'));
31d4b314
FP
2878}
2879
2880int
b9755a12
FP
2881L_isquote (tokp)
2882 register char *tokp;
2883{
2884 return ((*(++tokp) == 'q' || *tokp == 'Q')
2885 && (*(++tokp) == 'u' || *tokp == 'U')
2886 && (*(++tokp) == 'o' || *tokp == 'O')
2887 && (*(++tokp) == 't' || *tokp == 'T')
2888 && (*(++tokp) == 'e' || *tokp == 'E')
2889 && isspace(*(++tokp)));
c6d46f5f
JB
2890}
2891
2892void
2893L_getit ()
2894{
2895 register char *cp;
2896 char c;
2897 char nambuf[BUFSIZ];
2898
31d4b314
FP
2899 if (*dbp == '\'') /* Skip prefix quote */
2900 dbp++;
2901 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2902 {
2903 dbp += 7;
2904 while (isspace(*dbp))
2905 dbp++;
2906 }
2907 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
c6d46f5f 2908 continue;
31d4b314
FP
2909 if (cp == dbp)
2910 return;
2911
c6d46f5f
JB
2912 c = cp[0];
2913 cp[0] = 0;
1a0d8c80 2914 strcpy (nambuf, dbp);
c6d46f5f 2915 cp[0] = c;
591fa824
RS
2916 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2917 cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f
JB
2918 pfcnt++;
2919}
6dd5561c
FP
2920
2921void
2922Lisp_functions (inf)
2923 FILE *inf;
2924{
2925 lineno = 0;
2926 charno = 0;
2927 pfcnt = 0;
2928
2929 while (!feof (inf))
2930 {
2931 lineno++;
2932 linecharno = charno;
2933 charno += readline (&lb, inf);
2934 dbp = lb.buffer;
2935 if (dbp[0] == '(')
2936 {
2937 if (L_isdef (dbp))
2938 {
2939 while (!isspace (*dbp))
2940 dbp++;
2941 while (isspace (*dbp))
2942 dbp++;
2943 L_getit ();
2944 }
2945 else
2946 {
2947 /* Check for (foo::defmumble name-defined ... */
2948 do
2949 dbp++;
2950 while (*dbp && !isspace (*dbp)
2951 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2952 if (*dbp == ':')
2953 {
2954 do
2955 dbp++;
2956 while (*dbp == ':');
2957
2958 if (L_isdef (dbp - 1))
2959 {
2960 while (!isspace (*dbp))
2961 dbp++;
2962 while (isspace (*dbp))
2963 dbp++;
2964 L_getit ();
2965 }
2966 }
2967 }
2968 }
2969 }
2970}
c6d46f5f
JB
2971\f
2972/*
2973 * Scheme tag functions
2974 * look for (def... xyzzy
2975 * look for (def... (xyzzy
2976 * look for (def ... ((...(xyzzy ....
2977 * look for (set! xyzzy
2978 */
2979
6dd5561c 2980void get_scheme ();
c6d46f5f
JB
2981
2982void
6dd5561c
FP
2983Scheme_functions (inf)
2984 FILE *inf;
c6d46f5f
JB
2985{
2986 lineno = 0;
2987 charno = 0;
2988 pfcnt = 0;
2989
6dd5561c 2990 while (!feof (inf))
c6d46f5f
JB
2991 {
2992 lineno++;
2993 linecharno = charno;
6dd5561c 2994 charno += readline (&lb, inf);
c6d46f5f
JB
2995 dbp = lb.buffer;
2996 if (dbp[0] == '(' &&
2997 (dbp[1] == 'D' || dbp[1] == 'd') &&
2998 (dbp[2] == 'E' || dbp[2] == 'e') &&
2999 (dbp[3] == 'F' || dbp[3] == 'f'))
3000 {
3001 while (!isspace (*dbp))
3002 dbp++;
3003 /* Skip over open parens and white space */
3004 while (*dbp && (isspace (*dbp) || *dbp == '('))
3005 dbp++;
3006 get_scheme ();
3007 }
3008 if (dbp[0] == '(' &&
3009 (dbp[1] == 'S' || dbp[1] == 's') &&
3010 (dbp[2] == 'E' || dbp[2] == 'e') &&
3011 (dbp[3] == 'T' || dbp[3] == 't') &&
3012 (dbp[4] == '!' || dbp[4] == '!') &&
3013 (isspace (dbp[5])))
3014 {
3015 while (!isspace (*dbp))
3016 dbp++;
3017 /* Skip over white space */
3018 while (isspace (*dbp))
3019 dbp++;
3020 get_scheme ();
3021 }
3022 }
3023}
3024
6dd5561c 3025void
c6d46f5f
JB
3026get_scheme ()
3027{
3028 register char *cp;
3029 char c;
3030 char nambuf[BUFSIZ];
3031
3032 if (*dbp == 0)
3033 return;
3034 /* Go till you get to white space or a syntactic break */
3035 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
3036 continue;
3037 /* Null terminate the string there. */
3038 c = cp[0];
3039 cp[0] = 0;
3040 /* Copy the string */
3041 strcpy (nambuf, dbp);
3042 /* Unterminate the string */
3043 cp[0] = c;
3044 /* Announce the change */
3045 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3046 pfcnt++;
3047}
3048\f
3049/* Find tags in TeX and LaTeX input files. */
3050
3051/* TEX_toktab is a table of TeX control sequences that define tags.
3052 Each TEX_tabent records one such control sequence.
3053 CONVERT THIS TO USE THE Stab TYPE!! */
c6d46f5f
JB
3054struct TEX_tabent
3055{
3056 char *name;
3057 int len;
3058};
3059
3060struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
3061
3062/* Default set of control sequences to put into TEX_toktab.
3063 The value of environment var TEXTAGS is prepended to this. */
3064
6dd5561c
FP
3065char *TEX_defenv = "\
3066:chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
c6d46f5f
JB
3067
3068void TEX_mode ();
3069struct TEX_tabent *TEX_decode_env ();
3070void TEX_getit ();
3071int TEX_Token ();
3072
6dd5561c
FP
3073char TEX_esc = '\\';
3074char TEX_opgrp = '{';
3075char TEX_clgrp = '}';
c6d46f5f
JB
3076
3077/*
3078 * TeX/LaTeX scanning loop.
3079 */
c6d46f5f 3080void
6dd5561c
FP
3081TeX_functions (inf)
3082 FILE *inf;
c6d46f5f
JB
3083{
3084 char *lasthit;
3085
3086 lineno = 0;
3087 charno = 0;
3088 pfcnt = 0;
3089
3090 /* Select either \ or ! as escape character. */
6dd5561c 3091 TEX_mode (inf);
c6d46f5f
JB
3092
3093 /* Initialize token table once from environment. */
3094 if (!TEX_toktab)
3095 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
3096
6dd5561c 3097 while (!feof (inf))
d2729198 3098 { /* Scan each line in file */
c6d46f5f
JB
3099 lineno++;
3100 linecharno = charno;
6dd5561c 3101 charno += readline (&lb, inf);
c6d46f5f
JB
3102 dbp = lb.buffer;
3103 lasthit = dbp;
b02c5fea 3104 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
8a6c8bcf
RS
3105 {
3106 register int i;
c6d46f5f 3107
8a6c8bcf
RS
3108 if (!*(++dbp))
3109 break;
3110 linecharno += dbp - lasthit;
c6d46f5f 3111 lasthit = dbp;
8a6c8bcf
RS
3112 i = TEX_Token (lasthit);
3113 if (0 <= i)
c6d46f5f 3114 {
8a6c8bcf 3115 TEX_getit (lasthit, TEX_toktab[i].len);
d2729198 3116 break; /* We only save a line once */
c6d46f5f
JB
3117 }
3118 }
3119 }
3120}
3121
3122#define TEX_LESC '\\'
3123#define TEX_SESC '!'
3124#define TEX_cmt '%'
3125
aab1fdae
FP
3126/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
3127 chars accordingly. */
c6d46f5f 3128void
6dd5561c
FP
3129TEX_mode (inf)
3130 FILE *inf;
c6d46f5f
JB
3131{
3132 int c;
3133
6dd5561c 3134 while ((c = getc (inf)) != EOF)
c6d46f5f
JB
3135 {
3136 /* Skip to next line if we hit the TeX comment char. */
3137 if (c == TEX_cmt)
3138 while (c != '\n')
6dd5561c 3139 c = getc (inf);
c6d46f5f
JB
3140 else if (c == TEX_LESC || c == TEX_SESC )
3141 break;
3142 }
3143
3144 if (c == TEX_LESC)
3145 {
3146 TEX_esc = TEX_LESC;
3147 TEX_opgrp = '{';
3148 TEX_clgrp = '}';
3149 }
3150 else
3151 {
3152 TEX_esc = TEX_SESC;
3153 TEX_opgrp = '<';
3154 TEX_clgrp = '>';
3155 }
6dd5561c 3156 rewind (inf);
c6d46f5f
JB
3157}
3158
aab1fdae
FP
3159/* Read environment and prepend it to the default string.
3160 Build token table. */
c6d46f5f
JB
3161struct TEX_tabent *
3162TEX_decode_env (evarname, defenv)
3163 char *evarname;
3164 char *defenv;
3165{
3166 register char *env, *p;
c6d46f5f
JB
3167
3168 struct TEX_tabent *tab;
3169 int size, i;
3170
3171 /* Append default string to environment. */
3172 env = getenv (evarname);
3173 if (!env)
3174 env = defenv;
3175 else
3176 env = concat (env, defenv, "");
3177
3178 /* Allocate a token table */
3179 for (size = 1, p = env; p;)
b02c5fea 3180 if ((p = etags_strchr (p, ':')) && *(++p))
c6d46f5f 3181 size++;
8a6c8bcf
RS
3182 /* Add 1 to leave room for null terminator. */
3183 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
3184
3185 /* Unpack environment string into token table. Be careful about */
3186 /* zero-length strings (leading ':', "::" and trailing ':') */
3187 for (i = 0; *env;)
3188 {
b02c5fea 3189 p = etags_strchr (env, ':');
c6d46f5f
JB
3190 if (!p) /* End of environment string. */
3191 p = env + strlen (env);
3192 if (p - env > 0)
3193 { /* Only non-zero strings. */
3194 tab[i].name = savenstr (env, p - env);
3195 tab[i].len = strlen (tab[i].name);
3196 i++;
3197 }
3198 if (*p)
3199 env = p + 1;
3200 else
3201 {
3202 tab[i].name = NULL; /* Mark end of table. */
3203 tab[i].len = 0;
3204 break;
3205 }
3206 }
3207 return tab;
3208}
3209
3210/* Record a tag defined by a TeX command of length LEN and starting at NAME.
3211 The name being defined actually starts at (NAME + LEN + 1).
3212 But we seem to include the TeX command in the tag name. */
c6d46f5f
JB
3213void
3214TEX_getit (name, len)
3215 char *name;
3216 int len;
3217{
3218 char *p = name + len;
3219 char nambuf[BUFSIZ];
3220
3221 if (*name == 0)
3222 return;
3223
3224 /* Let tag name extend to next group close (or end of line) */
3225 while (*p && *p != TEX_clgrp)
3226 p++;
1a0d8c80 3227 strncpy (nambuf, name, p - name);
c6d46f5f
JB
3228 nambuf[p - name] = 0;
3229
3230 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
3231 pfcnt++;
3232}
3233
3234/* If the text at CP matches one of the tag-defining TeX command names,
b02c5fea 3235 return the pointer to the first occurrence of that command in TEX_toktab.
aab1fdae
FP
3236 Otherwise return -1.
3237 Keep the capital `T' in `Token' for dumb truncating compilers
c6d46f5f
JB
3238 (this distinguishes it from `TEX_toktab' */
3239int
3240TEX_Token (cp)
3241 char *cp;
3242{
3243 int i;
3244
3245 for (i = 0; TEX_toktab[i].len > 0; i++)
1a0d8c80 3246 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
c6d46f5f
JB
3247 return i;
3248 return -1;
3249}
3250\f
3251/* Support for Prolog. */
3252
aab1fdae 3253/* Whole head (not only functor, but also arguments)
c6d46f5f 3254 is gotten in compound term. */
c6d46f5f 3255void
b9755a12 3256prolog_getit (s)
c6d46f5f 3257 char *s;
c6d46f5f
JB
3258{
3259 char nambuf[BUFSIZ], *save_s, tmpc;
3260 int insquote, npar;
3261
3262 save_s = s;
3263 insquote = FALSE;
3264 npar = 0;
3265 while (1)
3266 {
3267 if (*s == '\0') /* syntax error. */
3268 return;
3269 else if (insquote && *s == '\'' && *(s + 1) == '\'')
3270 s += 2;
3271 else if (*s == '\'')
3272 {
3273 insquote = !insquote;
3274 s++;
3275 }
3276 else if (!insquote && *s == '(')
3277 {
3278 npar++;
3279 s++;
3280 }
3281 else if (!insquote && *s == ')')
3282 {
3283 npar--;
3284 s++;
3285 if (npar == 0)
3286 break;
3287 else if (npar < 0) /* syntax error. */
3288 return;
3289 }
3290 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
3291 { /* fullstop. */
3292 if (npar != 0) /* syntax error. */
3293 return;
3294 s++;
3295 break;
3296 }
3297 else
3298 s++;
3299 }
3300 tmpc = *s;
3301 *s = '\0';
3302 strcpy (nambuf, save_s);
3303 *s = tmpc;
bff8edcc 3304 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
c6d46f5f
JB
3305}
3306
3307/* It is assumed that prolog predicate starts from column 0. */
c6d46f5f 3308void
6dd5561c
FP
3309Prolog_functions (inf)
3310 FILE *inf;
c6d46f5f
JB
3311{
3312 void skip_comment (), prolog_getit ();
3313
3314 lineno = linecharno = charno = 0;
6dd5561c 3315 while (!feof (inf))
c6d46f5f
JB
3316 {
3317 lineno++;
3318 linecharno += charno;
6dd5561c 3319 charno = readline (&lb, inf) + 1; /* 1 for newline. */
c6d46f5f
JB
3320 dbp = lb.buffer;
3321 if (isspace (dbp[0])) /* not predicate header. */
3322 continue;
3323 else if (dbp[0] == '%') /* comment. */
3324 continue;
3325 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
6dd5561c 3326 skip_comment (&lb, inf, &lineno, &linecharno);
c6d46f5f 3327 else /* found. */
b9755a12 3328 prolog_getit (dbp);
c6d46f5f
JB
3329 }
3330}
3331
3332void
6dd5561c 3333skip_comment (plb, inf, plineno, plinecharno)
c6d46f5f 3334 struct linebuffer *plb;
6dd5561c 3335 FILE *inf;
c6d46f5f
JB
3336 int *plineno; /* result */
3337 long *plinecharno; /* result */
3338{
b9755a12
FP
3339 char *cp;
3340
3341 do
c6d46f5f 3342 {
b9755a12
FP
3343 for (cp = plb->buffer; *cp != '\0'; cp++)
3344 if (cp[0] == '*' && cp[1] == '/')
3345 return;
c6d46f5f 3346 (*plineno)++;
b9755a12
FP
3347 *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
3348 }
3349 while (!feof(inf));
c6d46f5f 3350}
b9755a12
FP
3351\f
3352#ifdef ETAGS_REGEXPS
3353/* Take a string like "/blah/" and turn it into "blah", making sure
3354 that the first and last characters are the same, and handling
3355 quoted separator characters. Actually, stops on the occurence of
3356 an unquoted separator. Also turns "\t" into a Tab character.
3357 Returns pointer to terminating separator. Works in place. Null
3358 terminates name string. */
3359char *
3360scan_separators (name)
3361 char *name;
3362{
3363 char sep = name[0];
3364 char *copyto = name;
3365 logical quoted = FALSE;
3366
3367 for (++name; *name != '\0'; ++name)
3368 {
3369 if (quoted)
3370 {
3371 if (*name == 't')
3372 *copyto++ = '\t';
3373 else if (*name == sep)
3374 *copyto++ = sep;
3375 else
3376 {
3377 /* Something else is quoted, so preserve the quote. */
3378 *copyto++ = '\\';
3379 *copyto++ = *name;
3380 }
3381 quoted = FALSE;
3382 }
3383 else if (*name == '\\')
3384 quoted = TRUE;
3385 else if (*name == sep)
3386 break;
3387 else
3388 *copyto++ = *name;
3389 }
c6d46f5f 3390
b9755a12
FP
3391 /* Terminate copied string. */
3392 *copyto = '\0';
3393 return name;
3394}
c6d46f5f 3395
b9755a12
FP
3396/* Turn a name, which is an ed-style (but Emacs syntax) regular
3397 expression, into a real regular expression by compiling it. */
3398void
3399add_regex (regexp_pattern)
3400 char *regexp_pattern;
c6d46f5f 3401{
b9755a12
FP
3402 char *name;
3403 const char *err;
3404 struct re_pattern_buffer *patbuf;
c6d46f5f 3405
b9755a12
FP
3406 if (regexp_pattern == NULL)
3407 {
3408 /* Remove existing regexps. */
3409 num_patterns = 0;
3410 patterns = NULL;
3411 return;
3412 }
c6d46f5f 3413
b9755a12
FP
3414 if (regexp_pattern[0] == '\0')
3415 {
3416 error ("missing regexp", 0);
3417 return;
3418 }
3419 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
3420 {
3421 error ("%s: unterminated regexp", regexp_pattern);
3422 return;
3423 }
3424 name = scan_separators (regexp_pattern);
3425 if (regexp_pattern[0] == '\0')
3426 {
3427 error ("null regexp", 0);
3428 return;
3429 }
3430 (void) scan_separators (name);
3431
3432 patbuf = xnew (1, struct re_pattern_buffer);
3433 patbuf->translate = NULL;
3434 patbuf->fastmap = NULL;
3435 patbuf->buffer = NULL;
3436 patbuf->allocated = 0;
3437
3438 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
3439 if (err != NULL)
3440 {
3441 error ("%s while compiling pattern", err);
3442 return;
3443 }
3444
3445 num_patterns += 1;
3446 if (num_patterns == 1)
3447 patterns = xnew (1, struct pattern);
c6d46f5f 3448 else
b9755a12
FP
3449 patterns = ((struct pattern *)
3450 xrealloc (patterns,
3451 (num_patterns * sizeof (struct pattern))));
3452 patterns[num_patterns - 1].pattern = patbuf;
3453 patterns[num_patterns - 1].name_pattern = savestr (name);
3454 patterns[num_patterns - 1].error_signaled = FALSE;
3455}
3456
3457/*
3458 * Do the subtitutions indicated by the regular expression and
3459 * arguments.
3460 */
3461char *
3462substitute (in, out, regs)
3463 char *in, *out;
3464 struct re_registers *regs;
3465{
3466 char *result = NULL, *t;
3467 int size = 0;
3468
3469 /* Pass 1: figure out how much size to allocate. */
3470 for (t = out; *t; ++t)
3471 {
3472 if (*t == '\\')
3473 {
3474 ++t;
3475 if (!*t)
3476 {
3477 fprintf (stderr, "%s: pattern subtitution ends prematurely\n",
3478 progname);
3479 return NULL;
3480 }
3481 if (isdigit (*t))
3482 {
3483 int dig = *t - '0';
3484 size += regs->end[dig] - regs->start[dig];
3485 }
3486 }
3487 }
3488
3489 /* Allocate space and do the substitutions. */
3490 result = xnew (size + 1, char);
3491 size = 0;
3492 for (; *out; ++out)
3493 {
3494 if (*out == '\\')
3495 {
3496 ++out;
3497 if (isdigit (*out))
3498 {
3499 /* Using "dig2" satisfies my debugger. Bleah. */
3500 int dig2 = *out - '0';
3501 strncpy (result + size, in + regs->start[dig2],
3502 regs->end[dig2] - regs->start[dig2]);
3503 size += regs->end[dig2] - regs->start[dig2];
3504 }
3505 else
3506 {
3507 switch (*out)
3508 {
3509 case '\t':
3510 result[size++] = '\t';
3511 break;
3512 case '\\':
3513 *out = '\\';
3514 break;
3515 default:
3516 result[size++] = *out;
3517 break;
3518 }
3519 }
3520 }
3521 else
3522 result[size++] = *out;
3523 }
3524 result[size] = '\0';
3525
3526 return result;
c6d46f5f
JB
3527}
3528\f
b9755a12 3529#endif /* ETAGS_REGEXPS */
c6d46f5f 3530/* Initialize a linebuffer for use */
c6d46f5f
JB
3531void
3532initbuffer (linebuffer)
3533 struct linebuffer *linebuffer;
3534{
3535 linebuffer->size = 200;
3536 linebuffer->buffer = xnew (200, char);
3537}
3538
3539/*
3540 * Read a line of text from `stream' into `linebuffer'.
3541 * Return the number of characters read from `stream',
3542 * which is the length of the line including the newline, if any.
3543 */
3544long
b9755a12 3545readline_internal (linebuffer, stream)
c6d46f5f
JB
3546 struct linebuffer *linebuffer;
3547 register FILE *stream;
3548{
3549 char *buffer = linebuffer->buffer;
3550 register char *p = linebuffer->buffer;
3551 register char *pend;
aab1fdae 3552 int chars_deleted;
c6d46f5f 3553
eb8c3be9 3554 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
c6d46f5f
JB
3555
3556 while (1)
3557 {
3558 register int c = getc (stream);
3559 if (p == pend)
3560 {
3561 linebuffer->size *= 2;
3562 buffer = (char *) xrealloc (buffer, linebuffer->size);
3563 p += buffer - linebuffer->buffer;
3564 pend = buffer + linebuffer->size;
3565 linebuffer->buffer = buffer;
3566 }
aab1fdae 3567 if (c == EOF)
c6d46f5f 3568 {
aab1fdae
FP
3569 chars_deleted = 0;
3570 break;
3571 }
3572 if (c == '\n')
3573 {
3574 if (p[-1] == '\r' && p > buffer)
3575 {
3576 *--p = '\0';
3577 chars_deleted = 2;
3578 }
3579 else
3580 {
3581 *p = '\0';
3582 chars_deleted = 1;
3583 }
c6d46f5f
JB
3584 break;
3585 }
3586 *p++ = c;
3587 }
3588
aab1fdae 3589 return p - buffer + chars_deleted;
c6d46f5f 3590}
b9755a12
FP
3591
3592/*
3593 * Like readline_internal, above, but try to match the input
3594 * line against any existing regular expressions.
3595 */
3596long
3597readline (linebuffer, stream)
3598 struct linebuffer *linebuffer;
3599 FILE *stream;
3600{
3601 /* Read new line. */
3602 int i;
3603 long result = readline_internal (linebuffer, stream);
3604
3605#ifdef ETAGS_REGEXPS
3606 /* Match against all listed patterns. */
3607 for (i = 0; i < num_patterns; ++i)
3608 {
3609 int match = re_match (patterns[i].pattern, linebuffer->buffer,
3610 (int)result, 0, &patterns[i].regs);
3611 switch (match)
3612 {
3613 case -2:
3614 /* Some error. */
3615 if (!patterns[i].error_signaled)
3616 {
3617 error ("error while matching pattern %d", i);
3618 patterns[i].error_signaled = TRUE;
3619 }
3620 break;
3621 case -1:
3622 /* No match. */
3623 break;
3624 default:
3625 /* Match occurred. Construct a tag. */
3626 if (patterns[i].name_pattern[0] != '\0')
3627 {
3628 /* Make a named tag. */
3629 char *name = substitute (linebuffer->buffer,
3630 patterns[i].name_pattern,
3631 &patterns[i].regs);
3632 if (name != NULL)
3633 pfnote (name, TRUE, TRUE, linebuffer->buffer,
3634 match, lineno, linecharno);
3635 }
3636 else
3637 {
3638 /* Make an unnamed tag. */
3639 pfnote (NULL, TRUE, FALSE, linebuffer->buffer,
3640 match, lineno, linecharno);
3641 }
3642 break;
3643 }
3644 }
3645#endif /* ETAGS_REGEXPS */
3646
3647 return result;
3648}
3649
3650/*
3651 * Read a file, but do no processing. This is used to do regexp
3652 * matching on files that have no language defined.
3653 */
3654void
3655just_read_file (inf)
3656 FILE *inf;
3657{
3658 while (!feof (inf))
3659 {
3660 ++lineno;
3661 linecharno = charno;
3662 charno += readline (&lb, inf) + 1;
3663 }
3664}
3665
c6d46f5f
JB
3666\f
3667char *
3668savestr (cp)
3669 char *cp;
3670{
3671 return savenstr (cp, strlen (cp));
3672}
3673
3674char *
3675savenstr (cp, len)
3676 char *cp;
3677 int len;
3678{
3679 register char *dp;
3680
3681 dp = xnew (len + 1, char);
1a0d8c80 3682 strncpy (dp, cp, len);
c6d46f5f
JB
3683 dp[len] = '\0';
3684 return dp;
3685}
3686
c6d46f5f
JB
3687/*
3688 * Return the ptr in sp at which the character c last
3689 * appears; NULL if not found
3690 *
b02c5fea 3691 * Identical to System V strrchr, included for portability.
c6d46f5f 3692 */
c6d46f5f 3693char *
b02c5fea 3694etags_strrchr (sp, c)
c6d46f5f
JB
3695 register char *sp, c;
3696{
3697 register char *r;
3698
3699 r = NULL;
3700 do
3701 {
3702 if (*sp == c)
3703 r = sp;
3704 } while (*sp++);
b9755a12 3705 return r;
c6d46f5f
JB
3706}
3707
9d7ad1b3 3708
c6d46f5f
JB
3709/*
3710 * Return the ptr in sp at which the character c first
3711 * appears; NULL if not found
3712 *
b02c5fea 3713 * Identical to System V strchr, included for portability.
c6d46f5f 3714 */
c6d46f5f 3715char *
b02c5fea 3716etags_strchr (sp, c)
c6d46f5f
JB
3717 register char *sp, c;
3718{
3719 do
3720 {
3721 if (*sp == c)
b9755a12
FP
3722 return sp;
3723 } while (*sp++);
3724 return NULL;
c6d46f5f
JB
3725}
3726
c6d46f5f 3727/* Print error message and exit. */
c6d46f5f
JB
3728void
3729fatal (s1, s2)
3730 char *s1, *s2;
3731{
3732 error (s1, s2);
1a0d8c80 3733 exit (BAD);
c6d46f5f
JB
3734}
3735
cdc1f6a7
FP
3736void
3737pfatal (s1)
3738 char *s1;
3739{
3740 perror (s1);
3741 exit (BAD);
3742}
3743
c6d46f5f 3744/* Print error message. `s1' is printf control string, `s2' is arg for it. */
c6d46f5f
JB
3745void
3746error (s1, s2)
3747 char *s1, *s2;
3748{
3749 fprintf (stderr, "%s: ", progname);
3750 fprintf (stderr, s1, s2);
3751 fprintf (stderr, "\n");
3752}
3753
46c145db
FP
3754/* Return a newly-allocated string whose contents
3755 concatenate those of s1, s2, s3. */
c6d46f5f
JB
3756char *
3757concat (s1, s2, s3)
3758 char *s1, *s2, *s3;
3759{
3760 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3761 char *result = xnew (len1 + len2 + len3 + 1, char);
3762
1a0d8c80
FP
3763 strcpy (result, s1);
3764 strcpy (result + len1, s2);
3765 strcpy (result + len1 + len2, s3);
46c145db 3766 result[len1 + len2 + len3] = '\0';
c6d46f5f
JB
3767
3768 return result;
3769}
b02c5fea 3770\f
cdc1f6a7
FP
3771/* Does the same work as the system V getcwd, but does not need to
3772 guess buffer size in advance. */
88f125fc
RS
3773char *
3774etags_getcwd ()
cdc1f6a7 3775#ifdef DOS_NT
88f125fc 3776{
cdc1f6a7
FP
3777 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3778
3779 getwd (path);
3780 p = path;
88f125fc
RS
3781 while (*p)
3782 if (*p == '\\')
3783 *p++ = '/';
3784 else
3785 *p++ = tolower (*p);
cdc1f6a7
FP
3786
3787 return strdup (path);
88f125fc 3788}
cdc1f6a7 3789#elif HAVE_GETCWD /* not DOS_NT */
b02c5fea 3790{
cdc1f6a7
FP
3791 int bufsize = 200;
3792 char *path = xnew (bufsize, char);
c6d46f5f 3793
cdc1f6a7 3794 while (getcwd (path, bufsize) == NULL)
b02c5fea 3795 {
dcc89e63 3796 if (errno != ERANGE)
cdc1f6a7 3797 pfatal ("pwd");
5e9c8296 3798 bufsize *= 2;
cdc1f6a7 3799 path = xnew (bufsize, char);
5e9c8296 3800 }
b02c5fea 3801
cdc1f6a7
FP
3802 return path;
3803}
3804#else /* not DOS_NT and not HAVE_GETCWD */
3805{
3806 struct linebuffer path;
3807 FILE *pipe;
b02c5fea 3808
cdc1f6a7
FP
3809 initbuffer (&path);
3810 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
3811 if (pipe == NULL || readline_internal (&path, pipe) == 0)
3812 pfatal ("pwd");
3813 pclose (pipe);
b02c5fea 3814
cdc1f6a7 3815 return path.buffer;
b02c5fea 3816}
cdc1f6a7 3817#endif /* not DOS_NT and not HAVE_GETCWD */
b02c5fea
FP
3818
3819/* Return a newly allocated string containing the filename
3820 of FILE relative to the absolute directory DIR (which
3821 should end with a slash). */
46c145db
FP
3822char *
3823relative_filename (file, dir)
3824 char *file, *dir;
3825{
3826 char *fp, *dp, *res;
3827
3828 /* Find the common root of file and dir. */
3829 fp = absolute_filename (file, cwd);
3830 dp = dir;
3831 while (*fp++ == *dp++)
3832 continue;
3833 do
3834 {
3835 fp--;
3836 dp--;
3837 }
3838 while (*fp != '/');
3839
3840 /* Build a sequence of "../" strings for the resulting relative filename. */
b02c5fea 3841 for (dp = etags_strchr (dp + 1, '/'), res = "";
46c145db 3842 dp != NULL;
b02c5fea 3843 dp = etags_strchr (dp + 1, '/'))
46c145db
FP
3844 {
3845 res = concat (res, "../", "");
3846 }
3847
3848 /* Add the filename relative to the common root of file and dir. */
3849 res = concat (res, fp + 1, "");
3850
3851 return res; /* temporary stub */
3852}
3853
3854/* Return a newly allocated string containing the
b02c5fea
FP
3855 absolute filename of FILE given CWD (which should
3856 end with a slash). */
46c145db
FP
3857char *
3858absolute_filename (file, cwd)
3859 char *file, *cwd;
3860{
3861 char *slashp, *cp, *res;
3862
3863 if (file[0] == '/')
3864 res = concat (file, "", "");
3865 else
3866 res = concat (cwd, file, "");
3867
3868 /* Delete the "/dirname/.." and "/." substrings. */
b02c5fea 3869 slashp = etags_strchr (res, '/');
46c145db
FP
3870 while (slashp != NULL && slashp[0] != '\0')
3871 {
3872 if (slashp[1] == '.')
3873 {
3874 if (slashp[2] == '.'
3875 && (slashp[3] == '/' || slashp[3] == '\0'))
3876 {
3877 cp = slashp;
3878 do
3879 cp--;
3880 while (cp >= res && *cp != '/');
3881 if (*cp == '/')
3882 {
3883 strcpy (cp, slashp + 3);
3884 }
3885 else /* else (cp == res) */
3886 {
1875d994 3887 if (slashp[3] != '\0')
46c145db
FP
3888 strcpy (cp, slashp + 4);
3889 else
3890 return ".";
3891 }
3892 slashp = cp;
e9b2b94c 3893 continue;
46c145db
FP
3894 }
3895 else if (slashp[2] == '/' || slashp[2] == '\0')
3896 {
3897 strcpy (slashp, slashp + 2);
e9b2b94c 3898 continue;
46c145db
FP
3899 }
3900 }
e9b2b94c
FP
3901
3902 slashp = etags_strchr (slashp + 1, '/');
46c145db
FP
3903 }
3904
3905 return res;
3906}
3907
b02c5fea
FP
3908/* Return a newly allocated string containing the absolute
3909 filename of dir where FILE resides given CWD (which should
3910 end with a slash). */
46c145db
FP
3911char *
3912absolute_dirname (file, cwd)
3913 char *file, *cwd;
3914{
3915 char *slashp, *res;
3916 char save;
3917
b02c5fea 3918 slashp = etags_strrchr (file, '/');
46c145db
FP
3919 if (slashp == NULL)
3920 return cwd;
3921 save = slashp[1];
3922 slashp[1] = '\0';
3923 res = absolute_filename (file, cwd);
3924 slashp[1] = save;
3925
3926 return res;
3927}
3928
c6d46f5f 3929/* Like malloc but get fatal error if memory is exhausted. */
c6d46f5f
JB
3930char *
3931xmalloc (size)
42680d3c 3932 unsigned int size;
c6d46f5f 3933{
1a0d8c80
FP
3934 char *result = (char *) malloc (size);
3935 if (result == NULL)
c6d46f5f
JB
3936 fatal ("virtual memory exhausted", 0);
3937 return result;
3938}
3939
3940char *
3941xrealloc (ptr, size)
3942 char *ptr;
42680d3c 3943 unsigned int size;
c6d46f5f 3944{
1a0d8c80
FP
3945 char *result = (char *) realloc (ptr, size);
3946 if (result == NULL)
c6d46f5f
JB
3947 fatal ("virtual memory exhausted");
3948 return result;
3949}