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