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