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