(easy-menu-filter-return):
[emacs.git] / lib-src / etags.c
blob5e5e9e9421f12f8385f3706822c930b79d230249
1 /* Tags file maker to go with GNU Emacs -*- coding: latin-1 -*-
2 Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002
3 Free Software Foundation, Inc. and Ken Arnold
5 This file is not considered part of GNU Emacs.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 * Authors:
23 * Ctags originally by Ken Arnold.
24 * Fortran added by Jim Kleckner.
25 * Ed Pelegri-Llopart added C typedefs.
26 * Gnu Emacs TAGS format and modifications by RMS?
27 * 1989 Sam Kendall added C++.
28 * 1992 Joseph B. Wells improved C and C++ parsing.
29 * 1993 Francesco Potortì reorganised C and C++.
30 * 1994 Line-by-line regexp tags by Tom Tromey.
31 * 2001 Nested classes by Francesco Potortì (concept by Mykola Dzyuba).
32 * 2002 #line directives by Francesco Potortì.
34 * Francesco Potortì <pot@gnu.org> has maintained and improved it since 1993.
38 char pot_etags_version[] = "@(#) pot revision number is 16.54";
40 #define TRUE 1
41 #define FALSE 0
43 #ifdef DEBUG
44 # undef DEBUG
45 # define DEBUG TRUE
46 #else
47 # define DEBUG FALSE
48 # define NDEBUG /* disable assert */
49 #endif
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 /* On some systems, Emacs defines static as nothing for the sake
54 of unexec. We don't want that here since we don't use unexec. */
55 # undef static
56 # define ETAGS_REGEXPS /* use the regexp features */
57 # define LONG_OPTIONS /* accept long options */
58 # ifndef PTR /* for Xemacs */
59 # define PTR void *
60 # endif
61 # ifndef __P /* for Xemacs */
62 # define __P(args) args
63 # endif
64 #else
65 # if defined(__STDC__) && (__STDC__ || defined(__SUNPRO_C))
66 # define __P(args) args /* use prototypes */
67 # define PTR void * /* for generic pointers */
68 # else
69 # define __P(args) () /* no prototypes */
70 # define const /* remove const for old compilers' sake */
71 # define PTR long * /* don't use void* */
72 # endif
73 #endif /* !HAVE_CONFIG_H */
75 #ifndef _GNU_SOURCE
76 # define _GNU_SOURCE 1 /* enables some compiler checks on GNU */
77 #endif
79 /* WIN32_NATIVE is for Xemacs.
80 MSDOS, WINDOWSNT, DOS_NT are for Emacs. */
81 #ifdef WIN32_NATIVE
82 # undef MSDOS
83 # undef WINDOWSNT
84 # define WINDOWSNT
85 #endif /* WIN32_NATIVE */
87 #ifdef MSDOS
88 # undef MSDOS
89 # define MSDOS TRUE
90 # include <fcntl.h>
91 # include <sys/param.h>
92 # include <io.h>
93 # ifndef HAVE_CONFIG_H
94 # define DOS_NT
95 # include <sys/config.h>
96 # endif
97 #else
98 # define MSDOS FALSE
99 #endif /* MSDOS */
101 #ifdef WINDOWSNT
102 # include <stdlib.h>
103 # include <fcntl.h>
104 # include <string.h>
105 # include <direct.h>
106 # include <io.h>
107 # define MAXPATHLEN _MAX_PATH
108 # undef HAVE_NTGUI
109 # undef DOS_NT
110 # define DOS_NT
111 # ifndef HAVE_GETCWD
112 # define HAVE_GETCWD
113 # endif /* undef HAVE_GETCWD */
114 #else /* !WINDOWSNT */
115 # ifdef STDC_HEADERS
116 # include <stdlib.h>
117 # include <string.h>
118 # else
119 extern char *getenv ();
120 # endif
121 #endif /* !WINDOWSNT */
123 #ifdef HAVE_UNISTD_H
124 # include <unistd.h>
125 #else
126 # if defined (HAVE_GETCWD) && !defined (WINDOWSNT)
127 extern char *getcwd (char *buf, size_t size);
128 # endif
129 #endif /* HAVE_UNISTD_H */
131 #include <stdio.h>
132 #include <ctype.h>
133 #include <errno.h>
134 #ifndef errno
135 extern int errno;
136 #endif
137 #include <sys/types.h>
138 #include <sys/stat.h>
140 #include <assert.h>
141 #ifdef NDEBUG
142 # undef assert /* some systems have a buggy assert.h */
143 # define assert(x) ((void) 0)
144 #endif
146 #if !defined (S_ISREG) && defined (S_IFREG)
147 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
148 #endif
150 #ifdef LONG_OPTIONS
151 # include <getopt.h>
152 #else
153 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
154 extern char *optarg;
155 extern int optind, opterr;
156 #endif /* LONG_OPTIONS */
158 #ifdef ETAGS_REGEXPS
159 # ifndef HAVE_CONFIG_H /* this is a standalone compilation */
160 # ifdef __CYGWIN__ /* compiling on Cygwin */
161 !!! NOTICE !!!
162 the regex.h distributed with Cygwin is not compatible with etags, alas!
163 If you want regular expression support, you should delete this notice and
164 arrange to use the GNU regex.h and regex.c.
165 # endif
166 # endif
167 # include <regex.h>
168 #endif /* ETAGS_REGEXPS */
170 /* Define CTAGS to make the program "ctags" compatible with the usual one.
171 Leave it undefined to make the program "etags", which makes emacs-style
172 tag tables and tags typedefs, #defines and struct/union/enum by default. */
173 #ifdef CTAGS
174 # undef CTAGS
175 # define CTAGS TRUE
176 #else
177 # define CTAGS FALSE
178 #endif
180 /* Exit codes for success and failure. */
181 #ifdef VMS
182 # define GOOD 1
183 # define BAD 0
184 #else
185 # define GOOD 0
186 # define BAD 1
187 #endif
189 #define streq(s,t) (assert((s)!=NULL || (t)!=NULL), !strcmp (s, t))
190 #define strcaseeq(s,t) (assert((s)!=NULL && (t)!=NULL), !etags_strcasecmp (s, t))
191 #define strneq(s,t,n) (assert((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
192 #define strncaseeq(s,t,n) (assert((s)!=NULL && (t)!=NULL), !etags_strncasecmp (s, t, n))
194 #define CHARS 256 /* 2^sizeof(char) */
195 #define CHAR(x) ((unsigned int)(x) & (CHARS - 1))
196 #define iswhite(c) (_wht[CHAR(c)]) /* c is white (see white) */
197 #define notinname(c) (_nin[CHAR(c)]) /* c is not in a name (see nonam) */
198 #define begtoken(c) (_btk[CHAR(c)]) /* c can start token (see begtk) */
199 #define intoken(c) (_itk[CHAR(c)]) /* c can be in token (see midtk) */
200 #define endtoken(c) (_etk[CHAR(c)]) /* c ends tokens (see endtk) */
202 #define ISALNUM(c) isalnum (CHAR(c))
203 #define ISALPHA(c) isalpha (CHAR(c))
204 #define ISDIGIT(c) isdigit (CHAR(c))
205 #define ISLOWER(c) islower (CHAR(c))
207 #define lowcase(c) tolower (CHAR(c))
208 #define upcase(c) toupper (CHAR(c))
212 * xnew, xrnew -- allocate, reallocate storage
214 * SYNOPSIS: Type *xnew (int n, Type);
215 * void xrnew (OldPointer, int n, Type);
217 #if DEBUG
218 # include "chkmalloc.h"
219 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
220 (n) * sizeof (Type)))
221 # define xrnew(op,n,Type) ((op) = (Type *) trace_realloc (__FILE__, __LINE__, \
222 (char *) (op), (n) * sizeof (Type)))
223 #else
224 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
225 # define xrnew(op,n,Type) ((op) = (Type *) xrealloc ( \
226 (char *) (op), (n) * sizeof (Type)))
227 #endif
229 #define bool int
231 typedef void Lang_function __P((FILE *));
233 typedef struct
235 char *suffix; /* file name suffix for this compressor */
236 char *command; /* takes one arg and decompresses to stdout */
237 } compressor;
239 typedef struct
241 char *name; /* language name */
242 bool metasource; /* source used to generate other sources */
243 Lang_function *function; /* parse function */
244 char **filenames; /* names of this language's files */
245 char **suffixes; /* name suffixes of this language's files */
246 char **interpreters; /* interpreters for this language */
247 } language;
249 typedef struct fdesc
251 struct fdesc *next; /* for the linked list */
252 char *infname; /* uncompressed input file name */
253 char *infabsname; /* absolute uncompressed input file name */
254 char *infabsdir; /* absolute dir of input file */
255 char *taggedfname; /* file name to write in tagfile */
256 language *lang; /* language of file */
257 char *prop; /* file properties to write in tagfile */
258 bool usecharno; /* etags tags shall contain char number */
259 bool written; /* entry written in the tags file */
260 } fdesc;
262 typedef struct node_st
263 { /* sorting structure */
264 struct node_st *left, *right; /* left and right sons */
265 fdesc *fdp; /* description of file to whom tag belongs */
266 char *name; /* tag name */
267 char *regex; /* search regexp */
268 bool valid; /* write this tag on the tag file */
269 bool is_func; /* function tag: use regexp in CTAGS mode */
270 bool been_warned; /* warning already given for duplicated tag */
271 int lno; /* line number tag is on */
272 long cno; /* character number line starts on */
273 } node;
276 * A `linebuffer' is a structure which holds a line of text.
277 * `readline_internal' reads a line from a stream into a linebuffer
278 * and works regardless of the length of the line.
279 * SIZE is the size of BUFFER, LEN is the length of the string in
280 * BUFFER after readline reads it.
282 typedef struct
284 long size;
285 int len;
286 char *buffer;
287 } linebuffer;
289 /* Used to support mixing of --lang and file names. */
290 typedef struct
292 enum {
293 at_language, /* a language specification */
294 at_regexp, /* a regular expression */
295 at_filename, /* a file name */
296 at_stdin /* read from stdin here */
297 } arg_type; /* argument type */
298 language *lang; /* language associated with the argument */
299 char *what; /* the argument itself */
300 } argument;
302 #ifdef ETAGS_REGEXPS
303 /* Structure defining a regular expression. */
304 typedef struct regexp
306 struct regexp *p_next; /* pointer to next in list */
307 language *lang; /* if set, use only for this language */
308 char *pattern; /* the regexp pattern */
309 char *name; /* tag name */
310 struct re_pattern_buffer *pat; /* the compiled pattern */
311 struct re_registers regs; /* re registers */
312 bool error_signaled; /* already signaled for this regexp */
313 bool force_explicit_name; /* do not allow implict tag name */
314 bool ignore_case; /* ignore case when matching */
315 bool multi_line; /* do a multi-line match on the whole file */
316 } regexp;
317 #endif /* ETAGS_REGEXPS */
320 /* Many compilers barf on this:
321 Lang_function Ada_funcs;
322 so let's write it this way */
323 static void Ada_funcs __P((FILE *));
324 static void Asm_labels __P((FILE *));
325 static void C_entries __P((int c_ext, FILE *));
326 static void default_C_entries __P((FILE *));
327 static void plain_C_entries __P((FILE *));
328 static void Cjava_entries __P((FILE *));
329 static void Cobol_paragraphs __P((FILE *));
330 static void Cplusplus_entries __P((FILE *));
331 static void Cstar_entries __P((FILE *));
332 static void Erlang_functions __P((FILE *));
333 static void Fortran_functions __P((FILE *));
334 static void HTML_labels __P((FILE *));
335 static void Lisp_functions __P((FILE *));
336 static void Makefile_targets __P((FILE *));
337 static void Pascal_functions __P((FILE *));
338 static void Perl_functions __P((FILE *));
339 static void PHP_functions __P((FILE *));
340 static void Postscript_functions __P((FILE *));
341 static void Prolog_functions __P((FILE *));
342 static void Python_functions __P((FILE *));
343 static void Scheme_functions __P((FILE *));
344 static void TeX_commands __P((FILE *));
345 static void Texinfo_nodes __P((FILE *));
346 static void Yacc_entries __P((FILE *));
347 static void just_read_file __P((FILE *));
349 static void print_language_names __P((void));
350 static void print_version __P((void));
351 static void print_help __P((void));
352 int main __P((int, char **));
354 static compressor *get_compressor_from_suffix __P((char *, char **));
355 static language *get_language_from_langname __P((const char *));
356 static language *get_language_from_interpreter __P((char *));
357 static language *get_language_from_filename __P((char *, bool));
358 static void readline __P((linebuffer *, FILE *));
359 static long readline_internal __P((linebuffer *, FILE *));
360 static bool nocase_tail __P((char *));
361 static void get_tag __P((char *, char **));
363 #ifdef ETAGS_REGEXPS
364 static void analyse_regex __P((char *));
365 static void free_regexps __P((void));
366 static void regex_tag_multiline __P((void));
367 #endif /* ETAGS_REGEXPS */
368 static void error __P((const char *, const char *));
369 static void suggest_asking_for_help __P((void));
370 void fatal __P((char *, char *));
371 static void pfatal __P((char *));
372 static void add_node __P((node *, node **));
374 static void init __P((void));
375 static void process_file_name __P((char *, language *));
376 static void process_file __P((FILE *, char *, language *));
377 static void find_entries __P((FILE *));
378 static void free_tree __P((node *));
379 static void free_fdesc __P((fdesc *));
380 static void pfnote __P((char *, bool, char *, int, int, long));
381 static void make_tag __P((char *, int, bool, char *, int, int, long));
382 static void invalidate_nodes __P((fdesc *, node **));
383 static void put_entries __P((node *));
385 static char *concat __P((char *, char *, char *));
386 static char *skip_spaces __P((char *));
387 static char *skip_non_spaces __P((char *));
388 static char *savenstr __P((char *, int));
389 static char *savestr __P((char *));
390 static char *etags_strchr __P((const char *, int));
391 static char *etags_strrchr __P((const char *, int));
392 static int etags_strcasecmp __P((const char *, const char *));
393 static int etags_strncasecmp __P((const char *, const char *, int));
394 static char *etags_getcwd __P((void));
395 static char *relative_filename __P((char *, char *));
396 static char *absolute_filename __P((char *, char *));
397 static char *absolute_dirname __P((char *, char *));
398 static bool filename_is_absolute __P((char *f));
399 static void canonicalize_filename __P((char *));
400 static void linebuffer_init __P((linebuffer *));
401 static void linebuffer_setlen __P((linebuffer *, int));
402 static PTR xmalloc __P((unsigned int));
403 static PTR xrealloc __P((char *, unsigned int));
406 static char searchar = '/'; /* use /.../ searches */
408 static char *tagfile; /* output file */
409 static char *progname; /* name this program was invoked with */
410 static char *cwd; /* current working directory */
411 static char *tagfiledir; /* directory of tagfile */
412 static FILE *tagf; /* ioptr for tags file */
414 static fdesc *fdhead; /* head of file description list */
415 static fdesc *curfdp; /* current file description */
416 static int lineno; /* line number of current line */
417 static long charno; /* current character number */
418 static long linecharno; /* charno of start of current line */
419 static char *dbp; /* pointer to start of current tag */
421 static const int invalidcharno = -1;
423 static node *nodehead; /* the head of the binary tree of tags */
424 static node *last_node; /* the last node created */
426 static linebuffer lb; /* the current line */
427 static linebuffer filebuf; /* a buffer containing the whole file */
428 static linebuffer token_name; /* a buffer containing a tag name */
430 /* boolean "functions" (see init) */
431 static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
432 static char
433 /* white chars */
434 *white = " \f\t\n\r\v",
435 /* not in a name */
436 *nonam = " \f\t\n\r()=,;", /* look at make_tag before modifying! */
437 /* token ending chars */
438 *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
439 /* token starting chars */
440 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
441 /* valid in-token chars */
442 *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
444 static bool append_to_tagfile; /* -a: append to tags */
445 /* The next four default to TRUE for etags, but to FALSE for ctags. */
446 static bool typedefs; /* -t: create tags for C and Ada typedefs */
447 static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */
448 /* 0 struct/enum/union decls, and C++ */
449 /* member functions. */
450 static bool constantypedefs; /* -d: create tags for C #define, enum */
451 /* constants and variables. */
452 /* -D: opposite of -d. Default under ctags. */
453 static bool globals; /* create tags for global variables */
454 static bool declarations; /* --declarations: tag them and extern in C&Co*/
455 static bool members; /* create tags for C member variables */
456 static bool no_line_directive; /* ignore #line directives (undocumented) */
457 static bool update; /* -u: update tags */
458 static bool vgrind_style; /* -v: create vgrind style index output */
459 static bool no_warnings; /* -w: suppress warnings */
460 static bool cxref_style; /* -x: create cxref style output */
461 static bool cplusplus; /* .[hc] means C++, not C */
462 static bool ignoreindent; /* -I: ignore indentation in C */
463 static bool packages_only; /* --packages-only: in Ada, only tag packages*/
465 #define STDIN 0x1001 /* returned by getopt_long on --parse-stdin */
466 static bool parsing_stdin; /* --parse-stdin used */
468 #ifdef ETAGS_REGEXPS
469 static regexp *p_head; /* list of all regexps */
470 static bool need_filebuf; /* some regexes are multi-line */
471 #else
472 # define need_filebuf FALSE
473 #endif /* ETAGS_REGEXPS */
475 #ifdef LONG_OPTIONS
476 static struct option longopts[] =
478 { "packages-only", no_argument, &packages_only, TRUE },
479 { "c++", no_argument, NULL, 'C' },
480 { "declarations", no_argument, &declarations, TRUE },
481 { "no-line-directive", no_argument, &no_line_directive, TRUE },
482 { "help", no_argument, NULL, 'h' },
483 { "help", no_argument, NULL, 'H' },
484 { "ignore-indentation", no_argument, NULL, 'I' },
485 { "language", required_argument, NULL, 'l' },
486 { "members", no_argument, &members, TRUE },
487 { "no-members", no_argument, &members, FALSE },
488 { "output", required_argument, NULL, 'o' },
489 #ifdef ETAGS_REGEXPS
490 { "regex", required_argument, NULL, 'r' },
491 { "no-regex", no_argument, NULL, 'R' },
492 { "ignore-case-regex", required_argument, NULL, 'c' },
493 #endif /* ETAGS_REGEXPS */
494 { "parse-stdin", required_argument, NULL, STDIN },
495 { "version", no_argument, NULL, 'V' },
497 #if CTAGS /* Etags options */
498 { "backward-search", no_argument, NULL, 'B' },
499 { "cxref", no_argument, NULL, 'x' },
500 { "defines", no_argument, NULL, 'd' },
501 { "globals", no_argument, &globals, TRUE },
502 { "typedefs", no_argument, NULL, 't' },
503 { "typedefs-and-c++", no_argument, NULL, 'T' },
504 { "update", no_argument, NULL, 'u' },
505 { "vgrind", no_argument, NULL, 'v' },
506 { "no-warn", no_argument, NULL, 'w' },
508 #else /* Ctags options */
509 { "append", no_argument, NULL, 'a' },
510 { "no-defines", no_argument, NULL, 'D' },
511 { "no-globals", no_argument, &globals, FALSE },
512 { "include", required_argument, NULL, 'i' },
513 #endif
514 { NULL }
516 #endif /* LONG_OPTIONS */
518 static compressor compressors[] =
520 { "z", "gzip -d -c"},
521 { "Z", "gzip -d -c"},
522 { "gz", "gzip -d -c"},
523 { "GZ", "gzip -d -c"},
524 { "bz2", "bzip2 -d -c" },
525 { NULL }
529 * Language stuff.
532 /* Ada code */
533 static char *Ada_suffixes [] =
534 { "ads", "adb", "ada", NULL };
536 /* Assembly code */
537 static char *Asm_suffixes [] =
538 { "a", /* Unix assembler */
539 "asm", /* Microcontroller assembly */
540 "def", /* BSO/Tasking definition includes */
541 "inc", /* Microcontroller include files */
542 "ins", /* Microcontroller include files */
543 "s", "sa", /* Unix assembler */
544 "S", /* cpp-processed Unix assembler */
545 "src", /* BSO/Tasking C compiler output */
546 NULL
549 /* Note that .c and .h can be considered C++, if the --c++ flag was
550 given, or if the `class' keyowrd is met inside the file.
551 That is why default_C_entries is called for these. */
552 static char *default_C_suffixes [] =
553 { "c", "h", NULL };
555 static char *Cplusplus_suffixes [] =
556 { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
557 "M", /* Objective C++ */
558 "pdb", /* Postscript with C syntax */
559 NULL };
561 static char *Cjava_suffixes [] =
562 { "java", NULL };
564 static char *Cobol_suffixes [] =
565 { "COB", "cob", NULL };
567 static char *Cstar_suffixes [] =
568 { "cs", "hs", NULL };
570 static char *Erlang_suffixes [] =
571 { "erl", "hrl", NULL };
573 static char *Fortran_suffixes [] =
574 { "F", "f", "f90", "for", NULL };
576 static char *HTML_suffixes [] =
577 { "htm", "html", "shtml", NULL };
579 static char *Lisp_suffixes [] =
580 { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
582 static char *Makefile_filenames [] =
583 { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
585 static char *Pascal_suffixes [] =
586 { "p", "pas", NULL };
588 static char *Perl_suffixes [] =
589 { "pl", "pm", NULL };
591 static char *Perl_interpreters [] =
592 { "perl", "@PERL@", NULL };
594 static char *PHP_suffixes [] =
595 { "php", "php3", "php4", NULL };
597 static char *plain_C_suffixes [] =
598 { "lm", /* Objective lex file */
599 "m", /* Objective C file */
600 "pc", /* Pro*C file */
601 NULL };
603 static char *Postscript_suffixes [] =
604 { "ps", "psw", NULL }; /* .psw is for PSWrap */
606 static char *Prolog_suffixes [] =
607 { "prolog", NULL };
609 static char *Python_suffixes [] =
610 { "py", NULL };
612 /* Can't do the `SCM' or `scm' prefix with a version number. */
613 static char *Scheme_suffixes [] =
614 { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
616 static char *TeX_suffixes [] =
617 { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
619 static char *Texinfo_suffixes [] =
620 { "texi", "texinfo", "txi", NULL };
622 static char *Yacc_suffixes [] =
623 { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
626 * Table of languages.
628 * It is ok for a given function to be listed under more than one
629 * name. I just didn't.
632 static language lang_names [] =
634 { "ada", FALSE, Ada_funcs, NULL, Ada_suffixes, NULL },
635 { "asm", FALSE, Asm_labels, NULL, Asm_suffixes, NULL },
636 { "c", FALSE, default_C_entries, NULL, default_C_suffixes, NULL },
637 { "c++", FALSE, Cplusplus_entries, NULL, Cplusplus_suffixes, NULL },
638 { "c*", FALSE, Cstar_entries, NULL, Cstar_suffixes, NULL },
639 { "cobol", FALSE, Cobol_paragraphs, NULL, Cobol_suffixes, NULL },
640 { "erlang", FALSE, Erlang_functions, NULL, Erlang_suffixes, NULL },
641 { "fortran", FALSE, Fortran_functions, NULL, Fortran_suffixes, NULL },
642 { "html", FALSE, HTML_labels, NULL, HTML_suffixes, NULL },
643 { "java", FALSE, Cjava_entries, NULL, Cjava_suffixes, NULL },
644 { "lisp", FALSE, Lisp_functions, NULL, Lisp_suffixes, NULL },
645 { "makefile", FALSE, Makefile_targets, Makefile_filenames, NULL, NULL },
646 { "pascal", FALSE, Pascal_functions, NULL, Pascal_suffixes, NULL },
647 { "perl", FALSE, Perl_functions,NULL, Perl_suffixes, Perl_interpreters },
648 { "php", FALSE, PHP_functions, NULL, PHP_suffixes, NULL },
649 { "postscript",FALSE, Postscript_functions,NULL, Postscript_suffixes, NULL },
650 { "proc", FALSE, plain_C_entries, NULL, plain_C_suffixes, NULL },
651 { "prolog", FALSE, Prolog_functions, NULL, Prolog_suffixes, NULL },
652 { "python", FALSE, Python_functions, NULL, Python_suffixes, NULL },
653 { "scheme", FALSE, Scheme_functions, NULL, Scheme_suffixes, NULL },
654 { "tex", FALSE, TeX_commands, NULL, TeX_suffixes, NULL },
655 { "texinfo", FALSE, Texinfo_nodes, NULL, Texinfo_suffixes, NULL },
656 { "yacc", TRUE, Yacc_entries, NULL, Yacc_suffixes, NULL },
657 { "auto", FALSE, NULL }, /* default guessing scheme */
658 { "none", FALSE, just_read_file }, /* regexp matching only */
659 { NULL, FALSE, NULL } /* end of list */
663 static void
664 print_language_names ()
666 language *lang;
667 char **name, **ext;
669 puts ("\nThese are the currently supported languages, along with the\n\
670 default file names and dot suffixes:");
671 for (lang = lang_names; lang->name != NULL; lang++)
673 printf (" %-*s", 10, lang->name);
674 if (lang->filenames != NULL)
675 for (name = lang->filenames; *name != NULL; name++)
676 printf (" %s", *name);
677 if (lang->suffixes != NULL)
678 for (ext = lang->suffixes; *ext != NULL; ext++)
679 printf (" .%s", *ext);
680 puts ("");
682 puts ("Where `auto' means use default language for files based on file\n\
683 name suffix, and `none' means only do regexp processing on files.\n\
684 If no language is specified and no matching suffix is found,\n\
685 the first line of the file is read for a sharp-bang (#!) sequence\n\
686 followed by the name of an interpreter. If no such sequence is found,\n\
687 Fortran is tried first; if no tags are found, C is tried next.\n\
688 When parsing any C file, a \"class\" keyword switches to C++.\n\
689 Compressed files are supported using gzip and bzip2.");
692 #ifndef EMACS_NAME
693 # define EMACS_NAME "standalone"
694 #endif
695 #ifndef VERSION
696 # define VERSION "version"
697 #endif
698 static void
699 print_version ()
701 printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
702 puts ("Copyright (C) 2002 Free Software Foundation, Inc. and Ken Arnold");
703 puts ("This program is distributed under the same terms as Emacs");
705 exit (GOOD);
708 static void
709 print_help ()
711 printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
713 These are the options accepted by %s.\n", progname, progname);
714 #ifdef LONG_OPTIONS
715 puts ("You may use unambiguous abbreviations for the long option names.");
716 #else
717 puts ("Long option names do not work with this executable, as it is not\n\
718 linked with GNU getopt.");
719 #endif /* LONG_OPTIONS */
720 puts (" A - as file name means read names from stdin (one per line).\n\
721 Absolute names are stored in the output file as they are.\n\
722 Relative ones are stored relative to the output file's directory.\n");
724 if (!CTAGS)
725 puts ("-a, --append\n\
726 Append tag entries to existing tags file.");
728 puts ("--packages-only\n\
729 For Ada files, only generate tags for packages.");
731 if (CTAGS)
732 puts ("-B, --backward-search\n\
733 Write the search commands for the tag entries using '?', the\n\
734 backward-search command instead of '/', the forward-search command.");
736 /* This option is mostly obsolete, because etags can now automatically
737 detect C++. Retained for backward compatibility and for debugging and
738 experimentation. In principle, we could want to tag as C++ even
739 before any "class" keyword.
740 puts ("-C, --c++\n\
741 Treat files whose name suffix defaults to C language as C++ files.");
744 puts ("--declarations\n\
745 In C and derived languages, create tags for function declarations,");
746 if (CTAGS)
747 puts ("\tand create tags for extern variables if --globals is used.");
748 else
749 puts
750 ("\tand create tags for extern variables unless --no-globals is used.");
752 if (CTAGS)
753 puts ("-d, --defines\n\
754 Create tag entries for C #define constants and enum constants, too.");
755 else
756 puts ("-D, --no-defines\n\
757 Don't create tag entries for C #define constants and enum constants.\n\
758 This makes the tags file smaller.");
760 if (!CTAGS)
761 puts ("-i FILE, --include=FILE\n\
762 Include a note in tag file indicating that, when searching for\n\
763 a tag, one should also consult the tags file FILE after\n\
764 checking the current file.");
766 puts ("-l LANG, --language=LANG\n\
767 Force the following files to be considered as written in the\n\
768 named language up to the next --language=LANG option.");
770 if (CTAGS)
771 puts ("--globals\n\
772 Create tag entries for global variables in some languages.");
773 else
774 puts ("--no-globals\n\
775 Do not create tag entries for global variables in some\n\
776 languages. This makes the tags file smaller.");
777 puts ("--members\n\
778 Create tag entries for member variables in some languages.");
780 #ifdef ETAGS_REGEXPS
781 puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
782 Make a tag for each line matching a regular expression pattern\n\
783 in the following files. {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
784 files only. REGEXFILE is a file containing one REGEXP per line.\n\
785 REGEXP takes the form /TAGREGEXP/TAGNAME/MODS, where TAGNAME/ is\n\
786 optional. The TAGREGEXP pattern is anchored (as if preceded by ^).");
787 puts (" If TAGNAME/ is present, the tags created are named.\n\
788 For example Tcl named tags can be created with:\n\
789 --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\".\n\
790 MODS are optional one-letter modifiers: `i' means to ignore case,\n\
791 `m' means to allow multi-line matches, `s' implies `m' and\n\
792 causes dot to match any character, including newline.");
793 puts ("-R, --no-regex\n\
794 Don't create tags from regexps for the following files.");
795 #endif /* ETAGS_REGEXPS */
796 puts ("-I, --ignore-indentation\n\
797 In C and C++ do not assume that a closing brace in the first\n\
798 column is the final brace of a function or structure definition.");
799 puts ("-o FILE, --output=FILE\n\
800 Write the tags to FILE.");
801 puts ("--parse-stdin=NAME\n\
802 Read from standard input and record tags as belonging to file NAME.");
804 if (CTAGS)
806 puts ("-t, --typedefs\n\
807 Generate tag entries for C and Ada typedefs.");
808 puts ("-T, --typedefs-and-c++\n\
809 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
810 and C++ member functions.");
813 if (CTAGS)
814 puts ("-u, --update\n\
815 Update the tag entries for the given files, leaving tag\n\
816 entries for other files in place. Currently, this is\n\
817 implemented by deleting the existing entries for the given\n\
818 files and then rewriting the new entries at the end of the\n\
819 tags file. It is often faster to simply rebuild the entire\n\
820 tag file than to use this.");
822 if (CTAGS)
824 puts ("-v, --vgrind\n\
825 Generates an index of items intended for human consumption,\n\
826 similar to the output of vgrind. The index is sorted, and\n\
827 gives the page number of each item.");
828 puts ("-w, --no-warn\n\
829 Suppress warning messages about entries defined in multiple\n\
830 files.");
831 puts ("-x, --cxref\n\
832 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
833 The output uses line numbers instead of page numbers, but\n\
834 beyond that the differences are cosmetic; try both to see\n\
835 which you like.");
838 puts ("-V, --version\n\
839 Print the version of the program.\n\
840 -h, --help\n\
841 Print this help message.");
843 print_language_names ();
845 puts ("");
846 puts ("Report bugs to bug-gnu-emacs@gnu.org");
848 exit (GOOD);
852 #ifdef VMS /* VMS specific functions */
854 #define EOS '\0'
856 /* This is a BUG! ANY arbitrary limit is a BUG!
857 Won't someone please fix this? */
858 #define MAX_FILE_SPEC_LEN 255
859 typedef struct {
860 short curlen;
861 char body[MAX_FILE_SPEC_LEN + 1];
862 } vspec;
865 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
866 returning in each successive call the next file name matching the input
867 spec. The function expects that each in_spec passed
868 to it will be processed to completion; in particular, up to and
869 including the call following that in which the last matching name
870 is returned, the function ignores the value of in_spec, and will
871 only start processing a new spec with the following call.
872 If an error occurs, on return out_spec contains the value
873 of in_spec when the error occurred.
875 With each successive file name returned in out_spec, the
876 function's return value is one. When there are no more matching
877 names the function returns zero. If on the first call no file
878 matches in_spec, or there is any other error, -1 is returned.
881 #include <rmsdef.h>
882 #include <descrip.h>
883 #define OUTSIZE MAX_FILE_SPEC_LEN
884 static short
885 fn_exp (out, in)
886 vspec *out;
887 char *in;
889 static long context = 0;
890 static struct dsc$descriptor_s o;
891 static struct dsc$descriptor_s i;
892 static bool pass1 = TRUE;
893 long status;
894 short retval;
896 if (pass1)
898 pass1 = FALSE;
899 o.dsc$a_pointer = (char *) out;
900 o.dsc$w_length = (short)OUTSIZE;
901 i.dsc$a_pointer = in;
902 i.dsc$w_length = (short)strlen(in);
903 i.dsc$b_dtype = DSC$K_DTYPE_T;
904 i.dsc$b_class = DSC$K_CLASS_S;
905 o.dsc$b_dtype = DSC$K_DTYPE_VT;
906 o.dsc$b_class = DSC$K_CLASS_VS;
908 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
910 out->body[out->curlen] = EOS;
911 return 1;
913 else if (status == RMS$_NMF)
914 retval = 0;
915 else
917 strcpy(out->body, in);
918 retval = -1;
920 lib$find_file_end(&context);
921 pass1 = TRUE;
922 return retval;
926 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
927 name of each file specified by the provided arg expanding wildcards.
929 static char *
930 gfnames (arg, p_error)
931 char *arg;
932 bool *p_error;
934 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
936 switch (fn_exp (&filename, arg))
938 case 1:
939 *p_error = FALSE;
940 return filename.body;
941 case 0:
942 *p_error = FALSE;
943 return NULL;
944 default:
945 *p_error = TRUE;
946 return filename.body;
950 #ifndef OLD /* Newer versions of VMS do provide `system'. */
951 system (cmd)
952 char *cmd;
954 error ("%s", "system() function not implemented under VMS");
956 #endif
958 #define VERSION_DELIM ';'
959 char *massage_name (s)
960 char *s;
962 char *start = s;
964 for ( ; *s; s++)
965 if (*s == VERSION_DELIM)
967 *s = EOS;
968 break;
970 else
971 *s = lowcase (*s);
972 return start;
974 #endif /* VMS */
978 main (argc, argv)
979 int argc;
980 char *argv[];
982 int i;
983 unsigned int nincluded_files;
984 char **included_files;
985 argument *argbuffer;
986 int current_arg, file_count;
987 linebuffer filename_lb;
988 #ifdef VMS
989 bool got_err;
990 #endif
991 char *optstring;
992 int opt;
995 #ifdef DOS_NT
996 _fmode = O_BINARY; /* all of files are treated as binary files */
997 #endif /* DOS_NT */
999 progname = argv[0];
1000 nincluded_files = 0;
1001 included_files = xnew (argc, char *);
1002 current_arg = 0;
1003 file_count = 0;
1005 /* Allocate enough no matter what happens. Overkill, but each one
1006 is small. */
1007 argbuffer = xnew (argc, argument);
1010 * If etags, always find typedefs and structure tags. Why not?
1011 * Also default to find macro constants, enum constants and
1012 * global variables.
1014 if (!CTAGS)
1016 typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;
1017 globals = TRUE;
1020 optstring = "-";
1021 #ifdef ETAGS_REGEXPS
1022 optstring = "-r:Rc:";
1023 #endif /* ETAGS_REGEXPS */
1024 #ifndef LONG_OPTIONS
1025 optstring = optstring + 1;
1026 #endif /* LONG_OPTIONS */
1027 optstring = concat (optstring,
1028 "Cf:Il:o:SVhH",
1029 (CTAGS) ? "BxdtTuvw" : "aDi:");
1031 while ((opt = getopt_long (argc, argv, optstring, longopts, 0)) != EOF)
1032 switch (opt)
1034 case 0:
1035 /* If getopt returns 0, then it has already processed a
1036 long-named option. We should do nothing. */
1037 break;
1039 case 1:
1040 /* This means that a file name has been seen. Record it. */
1041 argbuffer[current_arg].arg_type = at_filename;
1042 argbuffer[current_arg].what = optarg;
1043 ++current_arg;
1044 ++file_count;
1045 break;
1047 case STDIN:
1048 /* Parse standard input. Idea by Vivek <vivek@etla.org>. */
1049 argbuffer[current_arg].arg_type = at_stdin;
1050 argbuffer[current_arg].what = optarg;
1051 ++current_arg;
1052 ++file_count;
1053 if (parsing_stdin)
1054 fatal ("cannot parse standard input more than once", (char *)NULL);
1055 parsing_stdin = TRUE;
1056 break;
1058 /* Common options. */
1059 case 'C': cplusplus = TRUE; break;
1060 case 'f': /* for compatibility with old makefiles */
1061 case 'o':
1062 if (tagfile)
1064 error ("-o option may only be given once.", (char *)NULL);
1065 suggest_asking_for_help ();
1067 tagfile = optarg;
1068 break;
1069 case 'I':
1070 case 'S': /* for backward compatibility */
1071 ignoreindent = TRUE;
1072 break;
1073 case 'l':
1075 language *lang = get_language_from_langname (optarg);
1076 if (lang != NULL)
1078 argbuffer[current_arg].lang = lang;
1079 argbuffer[current_arg].arg_type = at_language;
1080 ++current_arg;
1083 break;
1084 case 'c':
1085 /* Backward compatibility: support obsolete --ignore-case-regexp. */
1086 optarg = concat (optarg, "i", ""); /* memory leak here */
1087 /* FALLTHRU */
1088 case 'r':
1089 argbuffer[current_arg].arg_type = at_regexp;
1090 argbuffer[current_arg].what = optarg;
1091 ++current_arg;
1092 break;
1093 case 'R':
1094 argbuffer[current_arg].arg_type = at_regexp;
1095 argbuffer[current_arg].what = NULL;
1096 ++current_arg;
1097 break;
1098 case 'V':
1099 print_version ();
1100 break;
1101 case 'h':
1102 case 'H':
1103 print_help ();
1104 break;
1106 /* Etags options */
1107 case 'a': append_to_tagfile = TRUE; break;
1108 case 'D': constantypedefs = FALSE; break;
1109 case 'i': included_files[nincluded_files++] = optarg; break;
1111 /* Ctags options. */
1112 case 'B': searchar = '?'; break;
1113 case 'd': constantypedefs = TRUE; break;
1114 case 't': typedefs = TRUE; break;
1115 case 'T': typedefs = typedefs_or_cplusplus = TRUE; break;
1116 case 'u': update = TRUE; break;
1117 case 'v': vgrind_style = TRUE; /*FALLTHRU*/
1118 case 'x': cxref_style = TRUE; break;
1119 case 'w': no_warnings = TRUE; break;
1120 default:
1121 suggest_asking_for_help ();
1124 for (; optind < argc; ++optind)
1126 argbuffer[current_arg].arg_type = at_filename;
1127 argbuffer[current_arg].what = argv[optind];
1128 ++current_arg;
1129 ++file_count;
1132 if (nincluded_files == 0 && file_count == 0)
1134 error ("no input files specified.", (char *)NULL);
1135 suggest_asking_for_help ();
1138 if (tagfile == NULL)
1139 tagfile = CTAGS ? "tags" : "TAGS";
1140 cwd = etags_getcwd (); /* the current working directory */
1141 if (cwd[strlen (cwd) - 1] != '/')
1143 char *oldcwd = cwd;
1144 cwd = concat (oldcwd, "/", "");
1145 free (oldcwd);
1147 if (streq (tagfile, "-"))
1148 tagfiledir = cwd;
1149 else
1150 tagfiledir = absolute_dirname (tagfile, cwd);
1152 init (); /* set up boolean "functions" */
1154 linebuffer_init (&lb);
1155 linebuffer_init (&filename_lb);
1156 linebuffer_init (&filebuf);
1157 linebuffer_init (&token_name);
1159 if (!CTAGS)
1161 if (streq (tagfile, "-"))
1163 tagf = stdout;
1164 #ifdef DOS_NT
1165 /* Switch redirected `stdout' to binary mode (setting `_fmode'
1166 doesn't take effect until after `stdout' is already open). */
1167 if (!isatty (fileno (stdout)))
1168 setmode (fileno (stdout), O_BINARY);
1169 #endif /* DOS_NT */
1171 else
1172 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1173 if (tagf == NULL)
1174 pfatal (tagfile);
1178 * Loop through files finding functions.
1180 for (i = 0; i < current_arg; ++i)
1182 static language *lang; /* non-NULL if language is forced */
1183 char *this_file;
1185 switch (argbuffer[i].arg_type)
1187 case at_language:
1188 lang = argbuffer[i].lang;
1189 break;
1190 #ifdef ETAGS_REGEXPS
1191 case at_regexp:
1192 analyse_regex (argbuffer[i].what);
1193 break;
1194 #endif
1195 case at_filename:
1196 #ifdef VMS
1197 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
1199 if (got_err)
1201 error ("can't find file %s\n", this_file);
1202 argc--, argv++;
1204 else
1206 this_file = massage_name (this_file);
1208 #else
1209 this_file = argbuffer[i].what;
1210 #endif
1211 /* Input file named "-" means read file names from stdin
1212 (one per line) and use them. */
1213 if (streq (this_file, "-"))
1215 if (parsing_stdin)
1216 fatal ("cannot parse standard input AND read file names from it",
1217 (char *)NULL);
1218 while (readline_internal (&filename_lb, stdin) > 0)
1219 process_file_name (filename_lb.buffer, lang);
1221 else
1222 process_file_name (this_file, lang);
1223 #ifdef VMS
1225 #endif
1226 break;
1227 case at_stdin:
1228 this_file = argbuffer[i].what;
1229 process_file (stdin, this_file, lang);
1230 break;
1234 #ifdef ETAGS_REGEXPS
1235 free_regexps ();
1236 #endif /* ETAGS_REGEXPS */
1237 free (lb.buffer);
1238 free (filebuf.buffer);
1239 free (token_name.buffer);
1241 if (!CTAGS || cxref_style)
1243 put_entries (nodehead); /* write the remainig tags (ETAGS) */
1244 free_tree (nodehead);
1245 nodehead = NULL;
1246 if (!CTAGS)
1248 fdesc *fdp;
1250 /* Output file entries that have no tags. */
1251 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1252 if (!fdp->written)
1253 fprintf (tagf, "\f\n%s,0\n", fdp->taggedfname);
1255 while (nincluded_files-- > 0)
1256 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1259 if (fclose (tagf) == EOF)
1260 pfatal (tagfile);
1261 exit (GOOD);
1264 if (update)
1266 char cmd[BUFSIZ];
1267 for (i = 0; i < current_arg; ++i)
1269 switch (argbuffer[i].arg_type)
1271 case at_filename:
1272 case at_stdin:
1273 break;
1274 default:
1275 continue; /* the for loop */
1277 sprintf (cmd,
1278 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1279 tagfile, argbuffer[i].what, tagfile);
1280 if (system (cmd) != GOOD)
1281 fatal ("failed to execute shell command", (char *)NULL);
1283 append_to_tagfile = TRUE;
1286 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1287 if (tagf == NULL)
1288 pfatal (tagfile);
1289 put_entries (nodehead); /* write all the tags (CTAGS) */
1290 free_tree (nodehead);
1291 nodehead = NULL;
1292 if (fclose (tagf) == EOF)
1293 pfatal (tagfile);
1295 if (update)
1297 char cmd[2*BUFSIZ+10];
1298 sprintf (cmd, "sort -o %.*s %.*s", BUFSIZ, tagfile, BUFSIZ, tagfile);
1299 exit (system (cmd));
1301 return GOOD;
1306 * Return a compressor given the file name. If EXTPTR is non-zero,
1307 * return a pointer into FILE where the compressor-specific
1308 * extension begins. If no compressor is found, NULL is returned
1309 * and EXTPTR is not significant.
1310 * Idea by Vladimir Alexiev <vladimir@cs.ualberta.ca> (1998)
1312 static compressor *
1313 get_compressor_from_suffix (file, extptr)
1314 char *file;
1315 char **extptr;
1317 compressor *compr;
1318 char *slash, *suffix;
1320 /* This relies on FN to be after canonicalize_filename,
1321 so we don't need to consider backslashes on DOS_NT. */
1322 slash = etags_strrchr (file, '/');
1323 suffix = etags_strrchr (file, '.');
1324 if (suffix == NULL || suffix < slash)
1325 return NULL;
1326 if (extptr != NULL)
1327 *extptr = suffix;
1328 suffix += 1;
1329 /* Let those poor souls who live with DOS 8+3 file name limits get
1330 some solace by treating foo.cgz as if it were foo.c.gz, etc.
1331 Only the first do loop is run if not MSDOS */
1334 for (compr = compressors; compr->suffix != NULL; compr++)
1335 if (streq (compr->suffix, suffix))
1336 return compr;
1337 if (!MSDOS)
1338 break; /* do it only once: not really a loop */
1339 if (extptr != NULL)
1340 *extptr = ++suffix;
1341 } while (*suffix != '\0');
1342 return NULL;
1348 * Return a language given the name.
1350 static language *
1351 get_language_from_langname (name)
1352 const char *name;
1354 language *lang;
1356 if (name == NULL)
1357 error ("empty language name", (char *)NULL);
1358 else
1360 for (lang = lang_names; lang->name != NULL; lang++)
1361 if (streq (name, lang->name))
1362 return lang;
1363 error ("unknown language \"%s\"", name);
1366 return NULL;
1371 * Return a language given the interpreter name.
1373 static language *
1374 get_language_from_interpreter (interpreter)
1375 char *interpreter;
1377 language *lang;
1378 char **iname;
1380 if (interpreter == NULL)
1381 return NULL;
1382 for (lang = lang_names; lang->name != NULL; lang++)
1383 if (lang->interpreters != NULL)
1384 for (iname = lang->interpreters; *iname != NULL; iname++)
1385 if (streq (*iname, interpreter))
1386 return lang;
1388 return NULL;
1394 * Return a language given the file name.
1396 static language *
1397 get_language_from_filename (file, case_sensitive)
1398 char *file;
1399 bool case_sensitive;
1401 language *lang;
1402 char **name, **ext, *suffix;
1404 /* Try whole file name first. */
1405 for (lang = lang_names; lang->name != NULL; lang++)
1406 if (lang->filenames != NULL)
1407 for (name = lang->filenames; *name != NULL; name++)
1408 if ((case_sensitive)
1409 ? streq (*name, file)
1410 : strcaseeq (*name, file))
1411 return lang;
1413 /* If not found, try suffix after last dot. */
1414 suffix = etags_strrchr (file, '.');
1415 if (suffix == NULL)
1416 return NULL;
1417 suffix += 1;
1418 for (lang = lang_names; lang->name != NULL; lang++)
1419 if (lang->suffixes != NULL)
1420 for (ext = lang->suffixes; *ext != NULL; ext++)
1421 if ((case_sensitive)
1422 ? streq (*ext, suffix)
1423 : strcaseeq (*ext, suffix))
1424 return lang;
1425 return NULL;
1430 * This routine is called on each file argument.
1432 static void
1433 process_file_name (file, lang)
1434 char *file;
1435 language *lang;
1437 struct stat stat_buf;
1438 FILE *inf;
1439 fdesc *fdp;
1440 compressor *compr;
1441 char *compressed_name, *uncompressed_name;
1442 char *ext, *real_name;
1443 int retval;
1445 canonicalize_filename (file);
1446 if (streq (file, tagfile) && !streq (tagfile, "-"))
1448 error ("skipping inclusion of %s in self.", file);
1449 return;
1451 if ((compr = get_compressor_from_suffix (file, &ext)) == NULL)
1453 compressed_name = NULL;
1454 real_name = uncompressed_name = savestr (file);
1456 else
1458 real_name = compressed_name = savestr (file);
1459 uncompressed_name = savenstr (file, ext - file);
1462 /* If the canonicalized uncompressed name
1463 has already been dealt with, skip it silently. */
1464 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
1466 assert (fdp->infname != NULL);
1467 if (streq (uncompressed_name, fdp->infname))
1468 goto cleanup;
1471 if (stat (real_name, &stat_buf) != 0)
1473 /* Reset real_name and try with a different name. */
1474 real_name = NULL;
1475 if (compressed_name != NULL) /* try with the given suffix */
1477 if (stat (uncompressed_name, &stat_buf) == 0)
1478 real_name = uncompressed_name;
1480 else /* try all possible suffixes */
1482 for (compr = compressors; compr->suffix != NULL; compr++)
1484 compressed_name = concat (file, ".", compr->suffix);
1485 if (stat (compressed_name, &stat_buf) != 0)
1487 if (MSDOS)
1489 char *suf = compressed_name + strlen (file);
1490 size_t suflen = strlen (compr->suffix) + 1;
1491 for ( ; suf[1]; suf++, suflen--)
1493 memmove (suf, suf + 1, suflen);
1494 if (stat (compressed_name, &stat_buf) == 0)
1496 real_name = compressed_name;
1497 break;
1500 if (real_name != NULL)
1501 break;
1502 } /* MSDOS */
1503 free (compressed_name);
1504 compressed_name = NULL;
1506 else
1508 real_name = compressed_name;
1509 break;
1513 if (real_name == NULL)
1515 perror (file);
1516 goto cleanup;
1518 } /* try with a different name */
1520 if (!S_ISREG (stat_buf.st_mode))
1522 error ("skipping %s: it is not a regular file.", real_name);
1523 goto cleanup;
1525 if (real_name == compressed_name)
1527 char *cmd = concat (compr->command, " ", real_name);
1528 inf = (FILE *) popen (cmd, "r");
1529 free (cmd);
1531 else
1532 inf = fopen (real_name, "r");
1533 if (inf == NULL)
1535 perror (real_name);
1536 goto cleanup;
1539 process_file (inf, uncompressed_name, lang);
1541 if (real_name == compressed_name)
1542 retval = pclose (inf);
1543 else
1544 retval = fclose (inf);
1545 if (retval < 0)
1546 pfatal (file);
1548 cleanup:
1549 if (compressed_name) free (compressed_name);
1550 if (uncompressed_name) free (uncompressed_name);
1551 last_node = NULL;
1552 curfdp = NULL;
1553 return;
1556 static void
1557 process_file (fh, fn, lang)
1558 FILE *fh;
1559 char *fn;
1560 language *lang;
1562 static const fdesc emptyfdesc;
1563 fdesc *fdp;
1565 /* Create a new input file description entry. */
1566 fdp = xnew (1, fdesc);
1567 *fdp = emptyfdesc;
1568 fdp->next = fdhead;
1569 fdp->infname = savestr (fn);
1570 fdp->lang = lang;
1571 fdp->infabsname = absolute_filename (fn, cwd);
1572 fdp->infabsdir = absolute_dirname (fn, cwd);
1573 if (filename_is_absolute (fn))
1575 /* An absolute file name. Canonicalize it. */
1576 fdp->taggedfname = absolute_filename (fn, NULL);
1578 else
1580 /* A file name relative to cwd. Make it relative
1581 to the directory of the tags file. */
1582 fdp->taggedfname = relative_filename (fn, tagfiledir);
1584 fdp->usecharno = TRUE; /* use char position when making tags */
1585 fdp->prop = NULL;
1586 fdp->written = FALSE; /* not written on tags file yet */
1588 fdhead = fdp;
1589 curfdp = fdhead; /* the current file description */
1591 find_entries (fh);
1593 /* If not Ctags, and if this is not metasource and if it contained no #line
1594 directives, we can write the tags and free all nodes pointing to
1595 curfdp. */
1596 if (!CTAGS
1597 && curfdp->usecharno /* no #line directives in this file */
1598 && !curfdp->lang->metasource)
1600 node *np, *prev;
1602 /* Look for the head of the sublist relative to this file. See add_node
1603 for the structure of the node tree. */
1604 prev = NULL;
1605 for (np = nodehead; np != NULL; prev = np, np = np->left)
1606 if (np->fdp == curfdp)
1607 break;
1609 /* If we generated tags for this file, write and delete them. */
1610 if (np != NULL)
1612 /* This is the head of the last sublist, if any. The following
1613 instructions depend on this being true. */
1614 assert (np->left == NULL);
1616 assert (fdhead == curfdp);
1617 assert (last_node->fdp == curfdp);
1618 put_entries (np); /* write tags for file curfdp->taggedfname */
1619 free_tree (np); /* remove the written nodes */
1620 if (prev == NULL)
1621 nodehead = NULL; /* no nodes left */
1622 else
1623 prev->left = NULL; /* delete the pointer to the sublist */
1629 * This routine sets up the boolean pseudo-functions which work
1630 * by setting boolean flags dependent upon the corresponding character.
1631 * Every char which is NOT in that string is not a white char. Therefore,
1632 * all of the array "_wht" is set to FALSE, and then the elements
1633 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1634 * of a char is TRUE if it is the string "white", else FALSE.
1636 static void
1637 init ()
1639 register char *sp;
1640 register int i;
1642 for (i = 0; i < CHARS; i++)
1643 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1644 for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1645 for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1646 notinname('\0') = notinname('\n');
1647 for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1648 begtoken('\0') = begtoken('\n');
1649 for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1650 intoken('\0') = intoken('\n');
1651 for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1652 endtoken('\0') = endtoken('\n');
1656 * This routine opens the specified file and calls the function
1657 * which finds the function and type definitions.
1659 static void
1660 find_entries (inf)
1661 FILE *inf;
1663 char *cp;
1664 language *lang = curfdp->lang;
1665 Lang_function *parser = NULL;
1667 /* If user specified a language, use it. */
1668 if (lang != NULL && lang->function != NULL)
1670 parser = lang->function;
1673 /* Else try to guess the language given the file name. */
1674 if (parser == NULL)
1676 lang = get_language_from_filename (curfdp->infname, TRUE);
1677 if (lang != NULL && lang->function != NULL)
1679 curfdp->lang = lang;
1680 parser = lang->function;
1684 /* Else look for sharp-bang as the first two characters. */
1685 if (parser == NULL
1686 && readline_internal (&lb, inf) > 0
1687 && lb.len >= 2
1688 && lb.buffer[0] == '#'
1689 && lb.buffer[1] == '!')
1691 char *lp;
1693 /* Set lp to point at the first char after the last slash in the
1694 line or, if no slashes, at the first nonblank. Then set cp to
1695 the first successive blank and terminate the string. */
1696 lp = etags_strrchr (lb.buffer+2, '/');
1697 if (lp != NULL)
1698 lp += 1;
1699 else
1700 lp = skip_spaces (lb.buffer + 2);
1701 cp = skip_non_spaces (lp);
1702 *cp = '\0';
1704 if (strlen (lp) > 0)
1706 lang = get_language_from_interpreter (lp);
1707 if (lang != NULL && lang->function != NULL)
1709 curfdp->lang = lang;
1710 parser = lang->function;
1715 /* We rewind here, even if inf may be a pipe. We fail if the
1716 length of the first line is longer than the pipe block size,
1717 which is unlikely. */
1718 rewind (inf);
1720 /* Else try to guess the language given the case insensitive file name. */
1721 if (parser == NULL)
1723 lang = get_language_from_filename (curfdp->infname, FALSE);
1724 if (lang != NULL && lang->function != NULL)
1726 curfdp->lang = lang;
1727 parser = lang->function;
1731 /* Else try Fortran or C. */
1732 if (parser == NULL)
1734 node *old_last_node = last_node;
1736 curfdp->lang = get_language_from_langname ("fortran");
1737 find_entries (inf);
1739 if (old_last_node == last_node)
1740 /* No Fortran entries found. Try C. */
1742 /* We do not tag if rewind fails.
1743 Only the file name will be recorded in the tags file. */
1744 rewind (inf);
1745 curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
1746 find_entries (inf);
1748 return;
1751 if (!no_line_directive
1752 && curfdp->lang != NULL && curfdp->lang->metasource)
1753 /* It may be that this is a bingo.y file, and we already parsed a bingo.c
1754 file, or anyway we parsed a file that is automatically generated from
1755 this one. If this is the case, the bingo.c file contained #line
1756 directives that generated tags pointing to this file. Let's delete
1757 them all before parsing this file, which is the real source. */
1759 fdesc **fdpp = &fdhead;
1760 while (*fdpp != NULL)
1761 if (*fdpp != curfdp
1762 && streq ((*fdpp)->taggedfname, curfdp->taggedfname))
1763 /* We found one of those! We must delete both the file description
1764 and all tags referring to it. */
1766 fdesc *badfdp = *fdpp;
1768 /* Delete the tags referring to badfdp->taggedfname
1769 that were obtained from badfdp->infname. */
1770 invalidate_nodes (badfdp, &nodehead);
1772 *fdpp = badfdp->next; /* remove the bad description from the list */
1773 free_fdesc (badfdp);
1775 else
1776 fdpp = &(*fdpp)->next; /* advance the list pointer */
1779 assert (parser != NULL);
1781 /* Generic initialisations before reading from file. */
1782 linebuffer_setlen (&filebuf, 0); /* reset the file buffer */
1784 /* Generic initialisations before parsing file with readline. */
1785 lineno = 0; /* reset global line number */
1786 charno = 0; /* reset global char number */
1787 linecharno = 0; /* reset global char number of line start */
1789 parser (inf);
1791 #ifdef ETAGS_REGEXPS
1792 regex_tag_multiline ();
1793 #endif /* ETAGS_REGEXPS */
1798 * Check whether an implicitly named tag should be created,
1799 * then call `pfnote'.
1800 * NAME is a string that is internally copied by this function.
1802 * TAGS format specification
1803 * Idea by Sam Kendall <kendall@mv.mv.com> (1997)
1804 * The following is explained in some more detail in etc/ETAGS.EBNF.
1806 * make_tag creates tags with "implicit tag names" (unnamed tags)
1807 * if the following are all true, assuming NONAM=" \f\t\n\r()=,;":
1808 * 1. NAME does not contain any of the characters in NONAM;
1809 * 2. LINESTART contains name as either a rightmost, or rightmost but
1810 * one character, substring;
1811 * 3. the character, if any, immediately before NAME in LINESTART must
1812 * be a character in NONAM;
1813 * 4. the character, if any, immediately after NAME in LINESTART must
1814 * also be a character in NONAM.
1816 * The implementation uses the notinname() macro, which recognises the
1817 * characters stored in the string `nonam'.
1818 * etags.el needs to use the same characters that are in NONAM.
1820 static void
1821 make_tag (name, namelen, is_func, linestart, linelen, lno, cno)
1822 char *name; /* tag name, or NULL if unnamed */
1823 int namelen; /* tag length */
1824 bool is_func; /* tag is a function */
1825 char *linestart; /* start of the line where tag is */
1826 int linelen; /* length of the line where tag is */
1827 int lno; /* line number */
1828 long cno; /* character number */
1830 bool named = (name != NULL && namelen > 0);
1832 if (!CTAGS && named) /* maybe set named to false */
1833 /* Let's try to make an implicit tag name, that is, create an unnamed tag
1834 such that etags.el can guess a name from it. */
1836 int i;
1837 register char *cp = name;
1839 for (i = 0; i < namelen; i++)
1840 if (notinname (*cp++))
1841 break;
1842 if (i == namelen) /* rule #1 */
1844 cp = linestart + linelen - namelen;
1845 if (notinname (linestart[linelen-1]))
1846 cp -= 1; /* rule #4 */
1847 if (cp >= linestart /* rule #2 */
1848 && (cp == linestart
1849 || notinname (cp[-1])) /* rule #3 */
1850 && strneq (name, cp, namelen)) /* rule #2 */
1851 named = FALSE; /* use implicit tag name */
1855 if (named)
1856 name = savenstr (name, namelen);
1857 else
1858 name = NULL;
1859 pfnote (name, is_func, linestart, linelen, lno, cno);
1862 /* Record a tag. */
1863 static void
1864 pfnote (name, is_func, linestart, linelen, lno, cno)
1865 char *name; /* tag name, or NULL if unnamed */
1866 bool is_func; /* tag is a function */
1867 char *linestart; /* start of the line where tag is */
1868 int linelen; /* length of the line where tag is */
1869 int lno; /* line number */
1870 long cno; /* character number */
1872 register node *np;
1874 if (CTAGS && name == NULL)
1875 return;
1877 np = xnew (1, node);
1879 /* If ctags mode, change name "main" to M<thisfilename>. */
1880 if (CTAGS && !cxref_style && streq (name, "main"))
1882 register char *fp = etags_strrchr (curfdp->taggedfname, '/');
1883 np->name = concat ("M", fp == NULL ? curfdp->taggedfname : fp + 1, "");
1884 fp = etags_strrchr (np->name, '.');
1885 if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
1886 fp[0] = '\0';
1888 else
1889 np->name = name;
1890 np->valid = TRUE;
1891 np->been_warned = FALSE;
1892 np->fdp = curfdp;
1893 np->is_func = is_func;
1894 np->lno = lno;
1895 if (np->fdp->usecharno)
1896 /* Our char numbers are 0-base, because of C language tradition?
1897 ctags compatibility? old versions compatibility? I don't know.
1898 Anyway, since emacs's are 1-base we expect etags.el to take care
1899 of the difference. If we wanted to have 1-based numbers, we would
1900 uncomment the +1 below. */
1901 np->cno = cno /* + 1 */ ;
1902 else
1903 np->cno = invalidcharno;
1904 np->left = np->right = NULL;
1905 if (CTAGS && !cxref_style)
1907 if (strlen (linestart) < 50)
1908 np->regex = concat (linestart, "$", "");
1909 else
1910 np->regex = savenstr (linestart, 50);
1912 else
1913 np->regex = savenstr (linestart, linelen);
1915 add_node (np, &nodehead);
1919 * free_tree ()
1920 * recurse on left children, iterate on right children.
1922 static void
1923 free_tree (np)
1924 register node *np;
1926 while (np)
1928 register node *node_right = np->right;
1929 free_tree (np->left);
1930 if (np->name != NULL)
1931 free (np->name);
1932 free (np->regex);
1933 free (np);
1934 np = node_right;
1939 * free_fdesc ()
1940 * delete a file description
1942 static void
1943 free_fdesc (fdp)
1944 register fdesc *fdp;
1946 if (fdp->infname != NULL) free (fdp->infname);
1947 if (fdp->infabsname != NULL) free (fdp->infabsname);
1948 if (fdp->infabsdir != NULL) free (fdp->infabsdir);
1949 if (fdp->taggedfname != NULL) free (fdp->taggedfname);
1950 if (fdp->prop != NULL) free (fdp->prop);
1951 free (fdp);
1955 * add_node ()
1956 * Adds a node to the tree of nodes. In etags mode, sort by file
1957 * name. In ctags mode, sort by tag name. Make no attempt at
1958 * balancing.
1960 * add_node is the only function allowed to add nodes, so it can
1961 * maintain state.
1963 static void
1964 add_node (np, cur_node_p)
1965 node *np, **cur_node_p;
1967 register int dif;
1968 register node *cur_node = *cur_node_p;
1970 if (cur_node == NULL)
1972 *cur_node_p = np;
1973 last_node = np;
1974 return;
1977 if (!CTAGS)
1978 /* Etags Mode */
1980 /* For each file name, tags are in a linked sublist on the right
1981 pointer. The first tags of different files are a linked list
1982 on the left pointer. last_node points to the end of the last
1983 used sublist. */
1984 if (last_node != NULL && last_node->fdp == np->fdp)
1986 /* Let's use the same sublist as the last added node. */
1987 assert (last_node->right == NULL);
1988 last_node->right = np;
1989 last_node = np;
1991 else if (cur_node->fdp == np->fdp)
1993 /* Scanning the list we found the head of a sublist which is
1994 good for us. Let's scan this sublist. */
1995 add_node (np, &cur_node->right);
1997 else
1998 /* The head of this sublist is not good for us. Let's try the
1999 next one. */
2000 add_node (np, &cur_node->left);
2001 } /* if ETAGS mode */
2003 else
2005 /* Ctags Mode */
2006 dif = strcmp (np->name, cur_node->name);
2009 * If this tag name matches an existing one, then
2010 * do not add the node, but maybe print a warning.
2012 if (!dif)
2014 if (np->fdp == cur_node->fdp)
2016 if (!no_warnings)
2018 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
2019 np->fdp->infname, lineno, np->name);
2020 fprintf (stderr, "Second entry ignored\n");
2023 else if (!cur_node->been_warned && !no_warnings)
2025 fprintf
2026 (stderr,
2027 "Duplicate entry in files %s and %s: %s (Warning only)\n",
2028 np->fdp->infname, cur_node->fdp->infname, np->name);
2029 cur_node->been_warned = TRUE;
2031 return;
2034 /* Actually add the node */
2035 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
2036 } /* if CTAGS mode */
2040 * invalidate_nodes ()
2041 * Scan the node tree and invalidate all nodes pointing to the
2042 * given file description (CTAGS case) or free them (ETAGS case).
2044 static void
2045 invalidate_nodes (badfdp, npp)
2046 fdesc *badfdp;
2047 node **npp;
2049 node *np = *npp;
2051 if (np == NULL)
2052 return;
2054 if (CTAGS)
2056 if (np->left != NULL)
2057 invalidate_nodes (badfdp, &np->left);
2058 if (np->fdp == badfdp)
2059 np->valid = FALSE;
2060 if (np->right != NULL)
2061 invalidate_nodes (badfdp, &np->right);
2063 else
2065 assert (np->fdp != NULL);
2066 if (np->fdp == badfdp)
2068 *npp = np->left; /* detach the sublist from the list */
2069 np->left = NULL; /* isolate it */
2070 free_tree (np); /* free it */
2071 invalidate_nodes (badfdp, npp);
2073 else
2074 invalidate_nodes (badfdp, &np->left);
2079 static int total_size_of_entries __P((node *));
2080 static int number_len __P((long));
2082 /* Length of a non-negative number's decimal representation. */
2083 static int
2084 number_len (num)
2085 long num;
2087 int len = 1;
2088 while ((num /= 10) > 0)
2089 len += 1;
2090 return len;
2094 * Return total number of characters that put_entries will output for
2095 * the nodes in the linked list at the right of the specified node.
2096 * This count is irrelevant with etags.el since emacs 19.34 at least,
2097 * but is still supplied for backward compatibility.
2099 static int
2100 total_size_of_entries (np)
2101 register node *np;
2103 register int total = 0;
2105 for (; np != NULL; np = np->right)
2106 if (np->valid)
2108 total += strlen (np->regex) + 1; /* pat\177 */
2109 if (np->name != NULL)
2110 total += strlen (np->name) + 1; /* name\001 */
2111 total += number_len ((long) np->lno) + 1; /* lno, */
2112 if (np->cno != invalidcharno) /* cno */
2113 total += number_len (np->cno);
2114 total += 1; /* newline */
2117 return total;
2120 static void
2121 put_entries (np)
2122 register node *np;
2124 register char *sp;
2125 static fdesc *fdp = NULL;
2127 if (np == NULL)
2128 return;
2130 /* Output subentries that precede this one */
2131 if (CTAGS)
2132 put_entries (np->left);
2134 /* Output this entry */
2135 if (np->valid)
2137 if (!CTAGS)
2139 /* Etags mode */
2140 if (fdp != np->fdp)
2142 fdp = np->fdp;
2143 fprintf (tagf, "\f\n%s,%d\n",
2144 fdp->taggedfname, total_size_of_entries (np));
2145 fdp->written = TRUE;
2147 fputs (np->regex, tagf);
2148 fputc ('\177', tagf);
2149 if (np->name != NULL)
2151 fputs (np->name, tagf);
2152 fputc ('\001', tagf);
2154 fprintf (tagf, "%d,", np->lno);
2155 if (np->cno != invalidcharno)
2156 fprintf (tagf, "%ld", np->cno);
2157 fputs ("\n", tagf);
2159 else
2161 /* Ctags mode */
2162 if (np->name == NULL)
2163 error ("internal error: NULL name in ctags mode.", (char *)NULL);
2165 if (cxref_style)
2167 if (vgrind_style)
2168 fprintf (stdout, "%s %s %d\n",
2169 np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
2170 else
2171 fprintf (stdout, "%-16s %3d %-16s %s\n",
2172 np->name, np->lno, np->fdp->taggedfname, np->regex);
2174 else
2176 fprintf (tagf, "%s\t%s\t", np->name, np->fdp->taggedfname);
2178 if (np->is_func)
2179 { /* function or #define macro with args */
2180 putc (searchar, tagf);
2181 putc ('^', tagf);
2183 for (sp = np->regex; *sp; sp++)
2185 if (*sp == '\\' || *sp == searchar)
2186 putc ('\\', tagf);
2187 putc (*sp, tagf);
2189 putc (searchar, tagf);
2191 else
2192 { /* anything else; text pattern inadequate */
2193 fprintf (tagf, "%d", np->lno);
2195 putc ('\n', tagf);
2198 } /* if this node contains a valid tag */
2200 /* Output subentries that follow this one */
2201 put_entries (np->right);
2202 if (!CTAGS)
2203 put_entries (np->left);
2207 /* C extensions. */
2208 #define C_EXT 0x00fff /* C extensions */
2209 #define C_PLAIN 0x00000 /* C */
2210 #define C_PLPL 0x00001 /* C++ */
2211 #define C_STAR 0x00003 /* C* */
2212 #define C_JAVA 0x00005 /* JAVA */
2213 #define C_AUTO 0x01000 /* C, but switch to C++ if `class' is met */
2214 #define YACC 0x10000 /* yacc file */
2217 * The C symbol tables.
2219 enum sym_type
2221 st_none,
2222 st_C_objprot, st_C_objimpl, st_C_objend,
2223 st_C_gnumacro,
2224 st_C_ignore,
2225 st_C_javastruct,
2226 st_C_operator,
2227 st_C_class, st_C_template,
2228 st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
2231 static unsigned int hash __P((const char *, unsigned int));
2232 static struct C_stab_entry * in_word_set __P((const char *, unsigned int));
2233 static enum sym_type C_symtype __P((char *, int, int));
2235 /* Feed stuff between (but not including) %[ and %] lines to:
2236 gperf -c -k 1,3 -o -p -r -t
2238 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
2240 if, 0, st_C_ignore
2241 for, 0, st_C_ignore
2242 while, 0, st_C_ignore
2243 switch, 0, st_C_ignore
2244 return, 0, st_C_ignore
2245 @interface, 0, st_C_objprot
2246 @protocol, 0, st_C_objprot
2247 @implementation,0, st_C_objimpl
2248 @end, 0, st_C_objend
2249 import, C_JAVA, st_C_ignore
2250 package, C_JAVA, st_C_ignore
2251 friend, C_PLPL, st_C_ignore
2252 extends, C_JAVA, st_C_javastruct
2253 implements, C_JAVA, st_C_javastruct
2254 interface, C_JAVA, st_C_struct
2255 class, 0, st_C_class
2256 namespace, C_PLPL, st_C_struct
2257 domain, C_STAR, st_C_struct
2258 union, 0, st_C_struct
2259 struct, 0, st_C_struct
2260 extern, 0, st_C_extern
2261 enum, 0, st_C_enum
2262 typedef, 0, st_C_typedef
2263 define, 0, st_C_define
2264 operator, C_PLPL, st_C_operator
2265 template, 0, st_C_template
2266 bool, C_PLPL, st_C_typespec
2267 long, 0, st_C_typespec
2268 short, 0, st_C_typespec
2269 int, 0, st_C_typespec
2270 char, 0, st_C_typespec
2271 float, 0, st_C_typespec
2272 double, 0, st_C_typespec
2273 signed, 0, st_C_typespec
2274 unsigned, 0, st_C_typespec
2275 auto, 0, st_C_typespec
2276 void, 0, st_C_typespec
2277 static, 0, st_C_typespec
2278 const, 0, st_C_typespec
2279 volatile, 0, st_C_typespec
2280 explicit, C_PLPL, st_C_typespec
2281 mutable, C_PLPL, st_C_typespec
2282 typename, C_PLPL, st_C_typespec
2283 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
2284 DEFUN, 0, st_C_gnumacro
2285 SYSCALL, 0, st_C_gnumacro
2286 ENTRY, 0, st_C_gnumacro
2287 PSEUDO, 0, st_C_gnumacro
2288 # These are defined inside C functions, so currently they are not met.
2289 # EXFUN used in glibc, DEFVAR_* in emacs.
2290 #EXFUN, 0, st_C_gnumacro
2291 #DEFVAR_, 0, st_C_gnumacro
2293 and replace lines between %< and %> with its output,
2294 then make in_word_set and C_stab_entry static. */
2295 /*%<*/
2296 /* C code produced by gperf version 2.7.1 (19981006 egcs) */
2297 /* Command-line: gperf -c -k 1,3 -o -p -r -t */
2298 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
2300 #define TOTAL_KEYWORDS 47
2301 #define MIN_WORD_LENGTH 2
2302 #define MAX_WORD_LENGTH 15
2303 #define MIN_HASH_VALUE 18
2304 #define MAX_HASH_VALUE 138
2305 /* maximum key range = 121, duplicates = 0 */
2307 #ifdef __GNUC__
2308 __inline
2309 #endif
2310 static unsigned int
2311 hash (str, len)
2312 register const char *str;
2313 register unsigned int len;
2315 static unsigned char asso_values[] =
2317 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2318 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2319 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2320 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2321 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2322 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2323 139, 139, 139, 139, 63, 139, 139, 139, 33, 44,
2324 62, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2325 42, 139, 139, 12, 32, 139, 139, 139, 139, 139,
2326 139, 139, 139, 139, 139, 139, 139, 34, 59, 37,
2327 24, 58, 33, 3, 139, 16, 139, 139, 42, 60,
2328 18, 11, 39, 139, 23, 57, 4, 63, 6, 20,
2329 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2330 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2331 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2332 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2333 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2334 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2335 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2336 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2337 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2338 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2339 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2340 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2341 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2342 139, 139, 139, 139, 139, 139
2344 register int hval = len;
2346 switch (hval)
2348 default:
2349 case 3:
2350 hval += asso_values[(unsigned char)str[2]];
2351 case 2:
2352 case 1:
2353 hval += asso_values[(unsigned char)str[0]];
2354 break;
2356 return hval;
2359 #ifdef __GNUC__
2360 __inline
2361 #endif
2362 static struct C_stab_entry *
2363 in_word_set (str, len)
2364 register const char *str;
2365 register unsigned int len;
2367 static struct C_stab_entry wordlist[] =
2369 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2370 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2371 {"if", 0, st_C_ignore},
2372 {""}, {""}, {""}, {""},
2373 {"int", 0, st_C_typespec},
2374 {""}, {""},
2375 {"void", 0, st_C_typespec},
2376 {""}, {""},
2377 {"interface", C_JAVA, st_C_struct},
2378 {""},
2379 {"SYSCALL", 0, st_C_gnumacro},
2380 {""},
2381 {"return", 0, st_C_ignore},
2382 {""}, {""}, {""}, {""}, {""}, {""}, {""},
2383 {"while", 0, st_C_ignore},
2384 {"auto", 0, st_C_typespec},
2385 {""}, {""}, {""}, {""}, {""}, {""},
2386 {"float", 0, st_C_typespec},
2387 {"typedef", 0, st_C_typedef},
2388 {"typename", C_PLPL, st_C_typespec},
2389 {""}, {""}, {""},
2390 {"friend", C_PLPL, st_C_ignore},
2391 {"volatile", 0, st_C_typespec},
2392 {""}, {""},
2393 {"for", 0, st_C_ignore},
2394 {"const", 0, st_C_typespec},
2395 {"import", C_JAVA, st_C_ignore},
2396 {""},
2397 {"define", 0, st_C_define},
2398 {"long", 0, st_C_typespec},
2399 {"implements", C_JAVA, st_C_javastruct},
2400 {"signed", 0, st_C_typespec},
2401 {""},
2402 {"extern", 0, st_C_extern},
2403 {"extends", C_JAVA, st_C_javastruct},
2404 {""},
2405 {"mutable", C_PLPL, st_C_typespec},
2406 {"template", 0, st_C_template},
2407 {"short", 0, st_C_typespec},
2408 {"bool", C_PLPL, st_C_typespec},
2409 {"char", 0, st_C_typespec},
2410 {"class", 0, st_C_class},
2411 {"operator", C_PLPL, st_C_operator},
2412 {""},
2413 {"switch", 0, st_C_ignore},
2414 {""},
2415 {"ENTRY", 0, st_C_gnumacro},
2416 {""},
2417 {"package", C_JAVA, st_C_ignore},
2418 {"union", 0, st_C_struct},
2419 {"@end", 0, st_C_objend},
2420 {"struct", 0, st_C_struct},
2421 {"namespace", C_PLPL, st_C_struct},
2422 {""}, {""},
2423 {"domain", C_STAR, st_C_struct},
2424 {"@interface", 0, st_C_objprot},
2425 {"PSEUDO", 0, st_C_gnumacro},
2426 {"double", 0, st_C_typespec},
2427 {""},
2428 {"@protocol", 0, st_C_objprot},
2429 {""},
2430 {"static", 0, st_C_typespec},
2431 {""}, {""},
2432 {"DEFUN", 0, st_C_gnumacro},
2433 {""}, {""}, {""}, {""},
2434 {"explicit", C_PLPL, st_C_typespec},
2435 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2436 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2437 {""},
2438 {"enum", 0, st_C_enum},
2439 {""}, {""},
2440 {"unsigned", 0, st_C_typespec},
2441 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2442 {"@implementation",0, st_C_objimpl}
2445 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
2447 register int key = hash (str, len);
2449 if (key <= MAX_HASH_VALUE && key >= 0)
2451 register const char *s = wordlist[key].name;
2453 if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
2454 return &wordlist[key];
2457 return 0;
2459 /*%>*/
2461 static enum sym_type
2462 C_symtype (str, len, c_ext)
2463 char *str;
2464 int len;
2465 int c_ext;
2467 register struct C_stab_entry *se = in_word_set (str, len);
2469 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2470 return st_none;
2471 return se->type;
2476 * C functions and variables are recognized using a simple
2477 * finite automaton. fvdef is its state variable.
2479 static enum
2481 fvnone, /* nothing seen */
2482 fdefunkey, /* Emacs DEFUN keyword seen */
2483 fdefunname, /* Emacs DEFUN name seen */
2484 foperator, /* func: operator keyword seen (cplpl) */
2485 fvnameseen, /* function or variable name seen */
2486 fstartlist, /* func: just after open parenthesis */
2487 finlist, /* func: in parameter list */
2488 flistseen, /* func: after parameter list */
2489 fignore, /* func: before open brace */
2490 vignore /* var-like: ignore until ';' */
2491 } fvdef;
2493 static bool fvextern; /* func or var: extern keyword seen; */
2496 * typedefs are recognized using a simple finite automaton.
2497 * typdef is its state variable.
2499 static enum
2501 tnone, /* nothing seen */
2502 tkeyseen, /* typedef keyword seen */
2503 ttypeseen, /* defined type seen */
2504 tinbody, /* inside typedef body */
2505 tend, /* just before typedef tag */
2506 tignore /* junk after typedef tag */
2507 } typdef;
2510 * struct-like structures (enum, struct and union) are recognized
2511 * using another simple finite automaton. `structdef' is its state
2512 * variable.
2514 static enum
2516 snone, /* nothing seen yet,
2517 or in struct body if cblev > 0 */
2518 skeyseen, /* struct-like keyword seen */
2519 stagseen, /* struct-like tag seen */
2520 sintemplate, /* inside template (ignore) */
2521 scolonseen /* colon seen after struct-like tag */
2522 } structdef;
2525 * When objdef is different from onone, objtag is the name of the class.
2527 static char *objtag = "<uninited>";
2530 * Yet another little state machine to deal with preprocessor lines.
2532 static enum
2534 dnone, /* nothing seen */
2535 dsharpseen, /* '#' seen as first char on line */
2536 ddefineseen, /* '#' and 'define' seen */
2537 dignorerest /* ignore rest of line */
2538 } definedef;
2541 * State machine for Objective C protocols and implementations.
2542 * Idea by Tom R.Hageman <tom@basil.icce.rug.nl> (1995)
2544 static enum
2546 onone, /* nothing seen */
2547 oprotocol, /* @interface or @protocol seen */
2548 oimplementation, /* @implementations seen */
2549 otagseen, /* class name seen */
2550 oparenseen, /* parenthesis before category seen */
2551 ocatseen, /* category name seen */
2552 oinbody, /* in @implementation body */
2553 omethodsign, /* in @implementation body, after +/- */
2554 omethodtag, /* after method name */
2555 omethodcolon, /* after method colon */
2556 omethodparm, /* after method parameter */
2557 oignore /* wait for @end */
2558 } objdef;
2562 * Use this structure to keep info about the token read, and how it
2563 * should be tagged. Used by the make_C_tag function to build a tag.
2565 static struct tok
2567 char *line; /* string containing the token */
2568 int offset; /* where the token starts in LINE */
2569 int length; /* token length */
2571 The previous members can be used to pass strings around for generic
2572 purposes. The following ones specifically refer to creating tags. In this
2573 case the token contained here is the pattern that will be used to create a
2574 tag.
2576 bool valid; /* do not create a tag; the token should be
2577 invalidated whenever a state machine is
2578 reset prematurely */
2579 bool named; /* create a named tag */
2580 int lineno; /* source line number of tag */
2581 long linepos; /* source char number of tag */
2582 } token; /* latest token read */
2585 * Variables and functions for dealing with nested structures.
2586 * Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001)
2588 static void pushclass_above __P((int, char *, int));
2589 static void popclass_above __P((int));
2590 static void write_classname __P((linebuffer *, char *qualifier));
2592 static struct {
2593 char **cname; /* nested class names */
2594 int *cblev; /* nested class curly brace level */
2595 int nl; /* class nesting level (elements used) */
2596 int size; /* length of the array */
2597 } cstack; /* stack for nested declaration tags */
2598 /* Current struct nesting depth (namespace, class, struct, union, enum). */
2599 #define nestlev (cstack.nl)
2600 /* After struct keyword or in struct body, not inside a nested function. */
2601 #define instruct (structdef == snone && nestlev > 0 \
2602 && cblev == cstack.cblev[nestlev-1] + 1)
2604 static void
2605 pushclass_above (cblev, str, len)
2606 int cblev;
2607 char *str;
2608 int len;
2610 int nl;
2612 popclass_above (cblev);
2613 nl = cstack.nl;
2614 if (nl >= cstack.size)
2616 int size = cstack.size *= 2;
2617 xrnew (cstack.cname, size, char *);
2618 xrnew (cstack.cblev, size, int);
2620 assert (nl == 0 || cstack.cblev[nl-1] < cblev);
2621 cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
2622 cstack.cblev[nl] = cblev;
2623 cstack.nl = nl + 1;
2626 static void
2627 popclass_above (cblev)
2628 int cblev;
2630 int nl;
2632 for (nl = cstack.nl - 1;
2633 nl >= 0 && cstack.cblev[nl] >= cblev;
2634 nl--)
2636 if (cstack.cname[nl] != NULL)
2637 free (cstack.cname[nl]);
2638 cstack.nl = nl;
2642 static void
2643 write_classname (cn, qualifier)
2644 linebuffer *cn;
2645 char *qualifier;
2647 int i, len;
2648 int qlen = strlen (qualifier);
2650 if (cstack.nl == 0 || cstack.cname[0] == NULL)
2652 len = 0;
2653 cn->len = 0;
2654 cn->buffer[0] = '\0';
2656 else
2658 len = strlen (cstack.cname[0]);
2659 linebuffer_setlen (cn, len);
2660 strcpy (cn->buffer, cstack.cname[0]);
2662 for (i = 1; i < cstack.nl; i++)
2664 char *s;
2665 int slen;
2667 s = cstack.cname[i];
2668 if (s == NULL)
2669 continue;
2670 slen = strlen (s);
2671 len += slen + qlen;
2672 linebuffer_setlen (cn, len);
2673 strncat (cn->buffer, qualifier, qlen);
2674 strncat (cn->buffer, s, slen);
2679 static bool consider_token __P((char *, int, int, int *, int, int, bool *));
2680 static void make_C_tag __P((bool));
2683 * consider_token ()
2684 * checks to see if the current token is at the start of a
2685 * function or variable, or corresponds to a typedef, or
2686 * is a struct/union/enum tag, or #define, or an enum constant.
2688 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2689 * with args. C_EXTP points to which language we are looking at.
2691 * Globals
2692 * fvdef IN OUT
2693 * structdef IN OUT
2694 * definedef IN OUT
2695 * typdef IN OUT
2696 * objdef IN OUT
2699 static bool
2700 consider_token (str, len, c, c_extp, cblev, parlev, is_func_or_var)
2701 register char *str; /* IN: token pointer */
2702 register int len; /* IN: token length */
2703 register int c; /* IN: first char after the token */
2704 int *c_extp; /* IN, OUT: C extensions mask */
2705 int cblev; /* IN: curly brace level */
2706 int parlev; /* IN: parenthesis level */
2707 bool *is_func_or_var; /* OUT: function or variable found */
2709 /* When structdef is stagseen, scolonseen, or snone with cblev > 0,
2710 structtype is the type of the preceding struct-like keyword, and
2711 structcblev is the curly brace level where it has been seen. */
2712 static enum sym_type structtype;
2713 static int structcblev;
2714 static enum sym_type toktype;
2717 toktype = C_symtype (str, len, *c_extp);
2720 * Advance the definedef state machine.
2722 switch (definedef)
2724 case dnone:
2725 /* We're not on a preprocessor line. */
2726 if (toktype == st_C_gnumacro)
2728 fvdef = fdefunkey;
2729 return FALSE;
2731 break;
2732 case dsharpseen:
2733 if (toktype == st_C_define)
2735 definedef = ddefineseen;
2737 else
2739 definedef = dignorerest;
2741 return FALSE;
2742 case ddefineseen:
2744 * Make a tag for any macro, unless it is a constant
2745 * and constantypedefs is FALSE.
2747 definedef = dignorerest;
2748 *is_func_or_var = (c == '(');
2749 if (!*is_func_or_var && !constantypedefs)
2750 return FALSE;
2751 else
2752 return TRUE;
2753 case dignorerest:
2754 return FALSE;
2755 default:
2756 error ("internal error: definedef value.", (char *)NULL);
2760 * Now typedefs
2762 switch (typdef)
2764 case tnone:
2765 if (toktype == st_C_typedef)
2767 if (typedefs)
2768 typdef = tkeyseen;
2769 fvextern = FALSE;
2770 fvdef = fvnone;
2771 return FALSE;
2773 break;
2774 case tkeyseen:
2775 switch (toktype)
2777 case st_none:
2778 case st_C_typespec:
2779 case st_C_class:
2780 case st_C_struct:
2781 case st_C_enum:
2782 typdef = ttypeseen;
2783 break;
2785 break;
2786 case ttypeseen:
2787 if (structdef == snone && fvdef == fvnone)
2789 fvdef = fvnameseen;
2790 return TRUE;
2792 break;
2793 case tend:
2794 switch (toktype)
2796 case st_C_typespec:
2797 case st_C_class:
2798 case st_C_struct:
2799 case st_C_enum:
2800 return FALSE;
2802 return TRUE;
2806 * This structdef business is NOT invoked when we are ctags and the
2807 * file is plain C. This is because a struct tag may have the same
2808 * name as another tag, and this loses with ctags.
2810 switch (toktype)
2812 case st_C_javastruct:
2813 if (structdef == stagseen)
2814 structdef = scolonseen;
2815 return FALSE;
2816 case st_C_template:
2817 case st_C_class:
2818 if ((*c_extp & C_AUTO) /* automatic detection of C++ language */
2819 && cblev == 0
2820 && definedef == dnone && structdef == snone
2821 && typdef == tnone && fvdef == fvnone)
2822 *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
2823 if (toktype == st_C_template)
2824 break;
2825 /* FALLTHRU */
2826 case st_C_struct:
2827 case st_C_enum:
2828 if (parlev == 0
2829 && fvdef != vignore
2830 && (typdef == tkeyseen
2831 || (typedefs_or_cplusplus && structdef == snone)))
2833 structdef = skeyseen;
2834 structtype = toktype;
2835 structcblev = cblev;
2837 return FALSE;
2840 if (structdef == skeyseen)
2842 structdef = stagseen;
2843 return TRUE;
2846 if (typdef != tnone)
2847 definedef = dnone;
2849 /* Detect Objective C constructs. */
2850 switch (objdef)
2852 case onone:
2853 switch (toktype)
2855 case st_C_objprot:
2856 objdef = oprotocol;
2857 return FALSE;
2858 case st_C_objimpl:
2859 objdef = oimplementation;
2860 return FALSE;
2862 break;
2863 case oimplementation:
2864 /* Save the class tag for functions or variables defined inside. */
2865 objtag = savenstr (str, len);
2866 objdef = oinbody;
2867 return FALSE;
2868 case oprotocol:
2869 /* Save the class tag for categories. */
2870 objtag = savenstr (str, len);
2871 objdef = otagseen;
2872 *is_func_or_var = TRUE;
2873 return TRUE;
2874 case oparenseen:
2875 objdef = ocatseen;
2876 *is_func_or_var = TRUE;
2877 return TRUE;
2878 case oinbody:
2879 break;
2880 case omethodsign:
2881 if (parlev == 0)
2883 objdef = omethodtag;
2884 linebuffer_setlen (&token_name, len);
2885 strncpy (token_name.buffer, str, len);
2886 token_name.buffer[len] = '\0';
2887 return TRUE;
2889 return FALSE;
2890 case omethodcolon:
2891 if (parlev == 0)
2892 objdef = omethodparm;
2893 return FALSE;
2894 case omethodparm:
2895 if (parlev == 0)
2897 objdef = omethodtag;
2898 linebuffer_setlen (&token_name, token_name.len + len);
2899 strncat (token_name.buffer, str, len);
2900 return TRUE;
2902 return FALSE;
2903 case oignore:
2904 if (toktype == st_C_objend)
2906 /* Memory leakage here: the string pointed by objtag is
2907 never released, because many tests would be needed to
2908 avoid breaking on incorrect input code. The amount of
2909 memory leaked here is the sum of the lengths of the
2910 class tags.
2911 free (objtag); */
2912 objdef = onone;
2914 return FALSE;
2917 /* A function, variable or enum constant? */
2918 switch (toktype)
2920 case st_C_extern:
2921 fvextern = TRUE;
2922 /* FALLTHRU */
2923 case st_C_typespec:
2924 switch (fvdef)
2926 case finlist:
2927 case flistseen:
2928 case fignore:
2929 case vignore:
2930 break;
2931 default:
2932 fvdef = fvnone;
2934 return FALSE;
2935 case st_C_ignore:
2936 fvextern = FALSE;
2937 fvdef = vignore;
2938 return FALSE;
2939 case st_C_operator:
2940 fvdef = foperator;
2941 *is_func_or_var = TRUE;
2942 return TRUE;
2943 case st_none:
2944 if (constantypedefs
2945 && structdef == snone
2946 && structtype == st_C_enum && cblev > structcblev)
2947 return TRUE; /* enum constant */
2948 switch (fvdef)
2950 case fdefunkey:
2951 if (cblev > 0)
2952 break;
2953 fvdef = fdefunname; /* GNU macro */
2954 *is_func_or_var = TRUE;
2955 return TRUE;
2956 case fvnone:
2957 if ((strneq (str, "asm", 3) && endtoken (str[3]))
2958 || (strneq (str, "__asm__", 7) && endtoken (str[7])))
2960 fvdef = vignore;
2961 return FALSE;
2963 if (strneq (str+len-10, "::operator", 10))
2965 if (*c_extp & C_AUTO) /* automatic detection of C++ */
2966 *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
2967 fvdef = foperator;
2968 *is_func_or_var = TRUE;
2969 return TRUE;
2971 if (cblev > 0 && !instruct)
2972 break;
2973 fvdef = fvnameseen; /* function or variable */
2974 *is_func_or_var = TRUE;
2975 return TRUE;
2977 break;
2980 return FALSE;
2985 * C_entries often keeps pointers to tokens or lines which are older than
2986 * the line currently read. By keeping two line buffers, and switching
2987 * them at end of line, it is possible to use those pointers.
2989 static struct
2991 long linepos;
2992 linebuffer lb;
2993 } lbs[2];
2995 #define current_lb_is_new (newndx == curndx)
2996 #define switch_line_buffers() (curndx = 1 - curndx)
2998 #define curlb (lbs[curndx].lb)
2999 #define newlb (lbs[newndx].lb)
3000 #define curlinepos (lbs[curndx].linepos)
3001 #define newlinepos (lbs[newndx].linepos)
3003 #define plainc ((c_ext & C_EXT) == C_PLAIN)
3004 #define cplpl (c_ext & C_PLPL)
3005 #define cjava ((c_ext & C_JAVA) == C_JAVA)
3007 #define CNL_SAVE_DEFINEDEF() \
3008 do { \
3009 curlinepos = charno; \
3010 readline (&curlb, inf); \
3011 lp = curlb.buffer; \
3012 quotednl = FALSE; \
3013 newndx = curndx; \
3014 } while (0)
3016 #define CNL() \
3017 do { \
3018 CNL_SAVE_DEFINEDEF(); \
3019 if (savetoken.valid) \
3021 token = savetoken; \
3022 savetoken.valid = FALSE; \
3024 definedef = dnone; \
3025 } while (0)
3028 static void
3029 make_C_tag (isfun)
3030 bool isfun;
3032 /* This function should never be called when token.valid is FALSE, but
3033 we must protect against invalid input or internal errors. */
3034 if (!DEBUG && !token.valid)
3035 return;
3037 if (token.valid)
3038 make_tag (token_name.buffer, token_name.len, isfun, token.line,
3039 token.offset+token.length+1, token.lineno, token.linepos);
3040 else /* this case is optimised away if !DEBUG */
3041 make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
3042 token_name.len + 17, isfun, token.line,
3043 token.offset+token.length+1, token.lineno, token.linepos);
3045 token.valid = FALSE;
3050 * C_entries ()
3051 * This routine finds functions, variables, typedefs,
3052 * #define's, enum constants and struct/union/enum definitions in
3053 * C syntax and adds them to the list.
3055 static void
3056 C_entries (c_ext, inf)
3057 int c_ext; /* extension of C */
3058 FILE *inf; /* input file */
3060 register char c; /* latest char read; '\0' for end of line */
3061 register char *lp; /* pointer one beyond the character `c' */
3062 int curndx, newndx; /* indices for current and new lb */
3063 register int tokoff; /* offset in line of start of current token */
3064 register int toklen; /* length of current token */
3065 char *qualifier; /* string used to qualify names */
3066 int qlen; /* length of qualifier */
3067 int cblev; /* current curly brace level */
3068 int parlev; /* current parenthesis level */
3069 int typdefcblev; /* cblev where a typedef struct body begun */
3070 bool incomm, inquote, inchar, quotednl, midtoken;
3071 bool yacc_rules; /* in the rules part of a yacc file */
3072 struct tok savetoken; /* token saved during preprocessor handling */
3075 linebuffer_init (&lbs[0].lb);
3076 linebuffer_init (&lbs[1].lb);
3077 if (cstack.size == 0)
3079 cstack.size = (DEBUG) ? 1 : 4;
3080 cstack.nl = 0;
3081 cstack.cname = xnew (cstack.size, char *);
3082 cstack.cblev = xnew (cstack.size, int);
3085 tokoff = toklen = typdefcblev = 0; /* keep compiler quiet */
3086 curndx = newndx = 0;
3087 lp = curlb.buffer;
3088 *lp = 0;
3090 fvdef = fvnone; fvextern = FALSE; typdef = tnone;
3091 structdef = snone; definedef = dnone; objdef = onone;
3092 yacc_rules = FALSE;
3093 midtoken = inquote = inchar = incomm = quotednl = FALSE;
3094 token.valid = savetoken.valid = FALSE;
3095 cblev = 0;
3096 parlev = 0;
3097 if (cjava)
3098 { qualifier = "."; qlen = 1; }
3099 else
3100 { qualifier = "::"; qlen = 2; }
3103 while (!feof (inf))
3105 c = *lp++;
3106 if (c == '\\')
3108 /* If we're at the end of the line, the next character is a
3109 '\0'; don't skip it, because it's the thing that tells us
3110 to read the next line. */
3111 if (*lp == '\0')
3113 quotednl = TRUE;
3114 continue;
3116 lp++;
3117 c = ' ';
3119 else if (incomm)
3121 switch (c)
3123 case '*':
3124 if (*lp == '/')
3126 c = *lp++;
3127 incomm = FALSE;
3129 break;
3130 case '\0':
3131 /* Newlines inside comments do not end macro definitions in
3132 traditional cpp. */
3133 CNL_SAVE_DEFINEDEF ();
3134 break;
3136 continue;
3138 else if (inquote)
3140 switch (c)
3142 case '"':
3143 inquote = FALSE;
3144 break;
3145 case '\0':
3146 /* Newlines inside strings do not end macro definitions
3147 in traditional cpp, even though compilers don't
3148 usually accept them. */
3149 CNL_SAVE_DEFINEDEF ();
3150 break;
3152 continue;
3154 else if (inchar)
3156 switch (c)
3158 case '\0':
3159 /* Hmmm, something went wrong. */
3160 CNL ();
3161 /* FALLTHRU */
3162 case '\'':
3163 inchar = FALSE;
3164 break;
3166 continue;
3168 else
3169 switch (c)
3171 case '"':
3172 inquote = TRUE;
3173 switch (fvdef)
3175 case fdefunkey:
3176 case fstartlist:
3177 case finlist:
3178 case fignore:
3179 case vignore:
3180 break;
3181 default:
3182 fvextern = FALSE;
3183 fvdef = fvnone;
3185 continue;
3186 case '\'':
3187 inchar = TRUE;
3188 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
3190 fvextern = FALSE;
3191 fvdef = fvnone;
3193 continue;
3194 case '/':
3195 if (*lp == '*')
3197 lp++;
3198 incomm = TRUE;
3199 continue;
3201 else if (/* cplpl && */ *lp == '/')
3203 c = '\0';
3204 break;
3206 else
3207 break;
3208 case '%':
3209 if ((c_ext & YACC) && *lp == '%')
3211 /* Entering or exiting rules section in yacc file. */
3212 lp++;
3213 definedef = dnone; fvdef = fvnone; fvextern = FALSE;
3214 typdef = tnone; structdef = snone;
3215 midtoken = inquote = inchar = incomm = quotednl = FALSE;
3216 cblev = 0;
3217 yacc_rules = !yacc_rules;
3218 continue;
3220 else
3221 break;
3222 case '#':
3223 if (definedef == dnone)
3225 char *cp;
3226 bool cpptoken = TRUE;
3228 /* Look back on this line. If all blanks, or nonblanks
3229 followed by an end of comment, this is a preprocessor
3230 token. */
3231 for (cp = newlb.buffer; cp < lp-1; cp++)
3232 if (!iswhite (*cp))
3234 if (*cp == '*' && *(cp+1) == '/')
3236 cp++;
3237 cpptoken = TRUE;
3239 else
3240 cpptoken = FALSE;
3242 if (cpptoken)
3243 definedef = dsharpseen;
3244 } /* if (definedef == dnone) */
3246 continue;
3247 } /* switch (c) */
3250 /* Consider token only if some involved conditions are satisfied. */
3251 if (typdef != tignore
3252 && definedef != dignorerest
3253 && fvdef != finlist
3254 && structdef != sintemplate
3255 && (definedef != dnone
3256 || structdef != scolonseen))
3258 if (midtoken)
3260 if (endtoken (c))
3262 if (c == ':' && *lp == ':' && begtoken (lp[1]))
3263 /* This handles :: in the middle,
3264 but not at the beginning of an identifier.
3265 Also, space-separated :: is not recognised. */
3267 if (c_ext & C_AUTO) /* automatic detection of C++ */
3268 c_ext = (c_ext | C_PLPL) & ~C_AUTO;
3269 lp += 2;
3270 toklen += 2;
3271 c = lp[-1];
3272 goto still_in_token;
3274 else
3276 bool funorvar = FALSE;
3278 if (yacc_rules
3279 || consider_token (newlb.buffer + tokoff, toklen, c,
3280 &c_ext, cblev, parlev, &funorvar))
3282 if (fvdef == foperator)
3284 char *oldlp = lp;
3285 lp = skip_spaces (lp-1);
3286 if (*lp != '\0')
3287 lp += 1;
3288 while (*lp != '\0'
3289 && !iswhite (*lp) && *lp != '(')
3290 lp += 1;
3291 c = *lp++;
3292 toklen += lp - oldlp;
3294 token.named = FALSE;
3295 if (!plainc
3296 && nestlev > 0 && definedef == dnone)
3297 /* in struct body */
3299 write_classname (&token_name, qualifier);
3300 linebuffer_setlen (&token_name,
3301 token_name.len+qlen+toklen);
3302 strcat (token_name.buffer, qualifier);
3303 strncat (token_name.buffer,
3304 newlb.buffer + tokoff, toklen);
3305 token.named = TRUE;
3307 else if (objdef == ocatseen)
3308 /* Objective C category */
3310 int len = strlen (objtag) + 2 + toklen;
3311 linebuffer_setlen (&token_name, len);
3312 strcpy (token_name.buffer, objtag);
3313 strcat (token_name.buffer, "(");
3314 strncat (token_name.buffer,
3315 newlb.buffer + tokoff, toklen);
3316 strcat (token_name.buffer, ")");
3317 token.named = TRUE;
3319 else if (objdef == omethodtag
3320 || objdef == omethodparm)
3321 /* Objective C method */
3323 token.named = TRUE;
3325 else if (fvdef == fdefunname)
3326 /* GNU DEFUN and similar macros */
3328 bool defun = (newlb.buffer[tokoff] == 'F');
3329 int off = tokoff;
3330 int len = toklen;
3332 /* Rewrite the tag so that emacs lisp DEFUNs
3333 can be found by their elisp name */
3334 if (defun)
3336 off += 1;
3337 len -= 1;
3339 len = toklen;
3340 linebuffer_setlen (&token_name, len);
3341 strncpy (token_name.buffer,
3342 newlb.buffer + off, len);
3343 token_name.buffer[len] = '\0';
3344 if (defun)
3345 while (--len >= 0)
3346 if (token_name.buffer[len] == '_')
3347 token_name.buffer[len] = '-';
3348 token.named = defun;
3350 else
3352 linebuffer_setlen (&token_name, toklen);
3353 strncpy (token_name.buffer,
3354 newlb.buffer + tokoff, toklen);
3355 token_name.buffer[toklen] = '\0';
3356 /* Name macros and members. */
3357 token.named = (structdef == stagseen
3358 || typdef == ttypeseen
3359 || typdef == tend
3360 || (funorvar
3361 && definedef == dignorerest)
3362 || (funorvar
3363 && definedef == dnone
3364 && structdef == snone
3365 && cblev > 0));
3367 token.lineno = lineno;
3368 token.offset = tokoff;
3369 token.length = toklen;
3370 token.line = newlb.buffer;
3371 token.linepos = newlinepos;
3372 token.valid = TRUE;
3374 if (definedef == dnone
3375 && (fvdef == fvnameseen
3376 || fvdef == foperator
3377 || structdef == stagseen
3378 || typdef == tend
3379 || typdef == ttypeseen
3380 || objdef != onone))
3382 if (current_lb_is_new)
3383 switch_line_buffers ();
3385 else if (definedef != dnone
3386 || fvdef == fdefunname
3387 || instruct)
3388 make_C_tag (funorvar);
3390 midtoken = FALSE;
3392 } /* if (endtoken (c)) */
3393 else if (intoken (c))
3394 still_in_token:
3396 toklen++;
3397 continue;
3399 } /* if (midtoken) */
3400 else if (begtoken (c))
3402 switch (definedef)
3404 case dnone:
3405 switch (fvdef)
3407 case fstartlist:
3408 fvdef = finlist;
3409 continue;
3410 case flistseen:
3411 if (plainc || declarations)
3413 make_C_tag (TRUE); /* a function */
3414 fvdef = fignore;
3416 break;
3417 case fvnameseen:
3418 fvdef = fvnone;
3419 break;
3421 if (structdef == stagseen && !cjava)
3423 popclass_above (cblev);
3424 structdef = snone;
3426 break;
3427 case dsharpseen:
3428 savetoken = token;
3429 break;
3431 if (!yacc_rules || lp == newlb.buffer + 1)
3433 tokoff = lp - 1 - newlb.buffer;
3434 toklen = 1;
3435 midtoken = TRUE;
3437 continue;
3438 } /* if (begtoken) */
3439 } /* if must look at token */
3442 /* Detect end of line, colon, comma, semicolon and various braces
3443 after having handled a token.*/
3444 switch (c)
3446 case ':':
3447 if (yacc_rules && token.offset == 0 && token.valid)
3449 make_C_tag (FALSE); /* a yacc function */
3450 break;
3452 if (definedef != dnone)
3453 break;
3454 switch (objdef)
3456 case otagseen:
3457 objdef = oignore;
3458 make_C_tag (TRUE); /* an Objective C class */
3459 break;
3460 case omethodtag:
3461 case omethodparm:
3462 objdef = omethodcolon;
3463 linebuffer_setlen (&token_name, token_name.len + 1);
3464 strcat (token_name.buffer, ":");
3465 break;
3467 if (structdef == stagseen)
3469 structdef = scolonseen;
3470 break;
3472 /* Should be useless, but may be work as a safety net. */
3473 if (cplpl && fvdef == flistseen)
3475 make_C_tag (TRUE); /* a function */
3476 fvdef = fignore;
3477 break;
3479 break;
3480 case ';':
3481 if (definedef != dnone)
3482 break;
3483 switch (typdef)
3485 case tend:
3486 case ttypeseen:
3487 make_C_tag (FALSE); /* a typedef */
3488 typdef = tnone;
3489 fvdef = fvnone;
3490 break;
3491 case tnone:
3492 case tinbody:
3493 case tignore:
3494 switch (fvdef)
3496 case fignore:
3497 if (typdef == tignore || cplpl)
3498 fvdef = fvnone;
3499 break;
3500 case fvnameseen:
3501 if ((globals && cblev == 0 && (!fvextern || declarations))
3502 || (members && instruct))
3503 make_C_tag (FALSE); /* a variable */
3504 fvextern = FALSE;
3505 fvdef = fvnone;
3506 token.valid = FALSE;
3507 break;
3508 case flistseen:
3509 if (declarations
3510 && (typdef == tnone || (typdef != tignore && instruct)))
3511 make_C_tag (TRUE); /* a function declaration */
3512 /* FALLTHRU */
3513 default:
3514 fvextern = FALSE;
3515 fvdef = fvnone;
3516 if (declarations
3517 && cplpl && structdef == stagseen)
3518 make_C_tag (FALSE); /* forward declaration */
3519 else
3520 token.valid = FALSE;
3521 } /* switch (fvdef) */
3522 /* FALLTHRU */
3523 default:
3524 if (!instruct)
3525 typdef = tnone;
3527 if (structdef == stagseen)
3528 structdef = snone;
3529 break;
3530 case ',':
3531 if (definedef != dnone)
3532 break;
3533 switch (objdef)
3535 case omethodtag:
3536 case omethodparm:
3537 make_C_tag (TRUE); /* an Objective C method */
3538 objdef = oinbody;
3539 break;
3541 switch (fvdef)
3543 case fdefunkey:
3544 case foperator:
3545 case fstartlist:
3546 case finlist:
3547 case fignore:
3548 case vignore:
3549 break;
3550 case fdefunname:
3551 fvdef = fignore;
3552 break;
3553 case fvnameseen: /* a variable */
3554 if ((globals && cblev == 0 && (!fvextern || declarations))
3555 || (members && instruct))
3556 make_C_tag (FALSE);
3557 break;
3558 case flistseen: /* a function */
3559 if ((declarations && typdef == tnone && !instruct)
3560 || (members && typdef != tignore && instruct))
3562 make_C_tag (TRUE); /* a function declaration */
3563 fvdef = fvnameseen;
3565 else if (!declarations)
3566 fvdef = fvnone;
3567 token.valid = FALSE;
3568 break;
3569 default:
3570 fvdef = fvnone;
3572 if (structdef == stagseen)
3573 structdef = snone;
3574 break;
3575 case '[':
3576 if (definedef != dnone)
3577 break;
3578 if (structdef == stagseen)
3579 structdef = snone;
3580 switch (typdef)
3582 case ttypeseen:
3583 case tend:
3584 typdef = tignore;
3585 make_C_tag (FALSE); /* a typedef */
3586 break;
3587 case tnone:
3588 case tinbody:
3589 switch (fvdef)
3591 case foperator:
3592 case finlist:
3593 case fignore:
3594 case vignore:
3595 break;
3596 case fvnameseen:
3597 if ((members && cblev == 1)
3598 || (globals && cblev == 0
3599 && (!fvextern || declarations)))
3600 make_C_tag (FALSE); /* a variable */
3601 /* FALLTHRU */
3602 default:
3603 fvdef = fvnone;
3605 break;
3607 break;
3608 case '(':
3609 if (definedef != dnone)
3610 break;
3611 if (objdef == otagseen && parlev == 0)
3612 objdef = oparenseen;
3613 switch (fvdef)
3615 case fvnameseen:
3616 if (typdef == ttypeseen
3617 && *lp != '*'
3618 && !instruct)
3620 /* This handles constructs like:
3621 typedef void OperatorFun (int fun); */
3622 make_C_tag (FALSE);
3623 typdef = tignore;
3624 fvdef = fignore;
3625 break;
3627 /* FALLTHRU */
3628 case foperator:
3629 fvdef = fstartlist;
3630 break;
3631 case flistseen:
3632 fvdef = finlist;
3633 break;
3635 parlev++;
3636 break;
3637 case ')':
3638 if (definedef != dnone)
3639 break;
3640 if (objdef == ocatseen && parlev == 1)
3642 make_C_tag (TRUE); /* an Objective C category */
3643 objdef = oignore;
3645 if (--parlev == 0)
3647 switch (fvdef)
3649 case fstartlist:
3650 case finlist:
3651 fvdef = flistseen;
3652 break;
3654 if (!instruct
3655 && (typdef == tend
3656 || typdef == ttypeseen))
3658 typdef = tignore;
3659 make_C_tag (FALSE); /* a typedef */
3662 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3663 parlev = 0;
3664 break;
3665 case '{':
3666 if (definedef != dnone)
3667 break;
3668 if (typdef == ttypeseen)
3670 /* Whenever typdef is set to tinbody (currently only
3671 here), typdefcblev should be set to cblev. */
3672 typdef = tinbody;
3673 typdefcblev = cblev;
3675 switch (fvdef)
3677 case flistseen:
3678 make_C_tag (TRUE); /* a function */
3679 /* FALLTHRU */
3680 case fignore:
3681 fvdef = fvnone;
3682 break;
3683 case fvnone:
3684 switch (objdef)
3686 case otagseen:
3687 make_C_tag (TRUE); /* an Objective C class */
3688 objdef = oignore;
3689 break;
3690 case omethodtag:
3691 case omethodparm:
3692 make_C_tag (TRUE); /* an Objective C method */
3693 objdef = oinbody;
3694 break;
3695 default:
3696 /* Neutralize `extern "C" {' grot. */
3697 if (cblev == 0 && structdef == snone && nestlev == 0
3698 && typdef == tnone)
3699 cblev = -1;
3701 break;
3703 switch (structdef)
3705 case skeyseen: /* unnamed struct */
3706 pushclass_above (cblev, NULL, 0);
3707 structdef = snone;
3708 break;
3709 case stagseen: /* named struct or enum */
3710 case scolonseen: /* a class */
3711 pushclass_above (cblev, token.line+token.offset, token.length);
3712 structdef = snone;
3713 make_C_tag (FALSE); /* a struct or enum */
3714 break;
3716 cblev++;
3717 break;
3718 case '*':
3719 if (definedef != dnone)
3720 break;
3721 if (fvdef == fstartlist)
3723 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
3724 token.valid = FALSE;
3726 break;
3727 case '}':
3728 if (definedef != dnone)
3729 break;
3730 if (!ignoreindent && lp == newlb.buffer + 1)
3732 if (cblev != 0)
3733 token.valid = FALSE;
3734 cblev = 0; /* reset curly brace level if first column */
3735 parlev = 0; /* also reset paren level, just in case... */
3737 else if (cblev > 0)
3738 cblev--;
3739 else
3740 token.valid = FALSE; /* something gone amiss, token unreliable */
3741 popclass_above (cblev);
3742 structdef = snone;
3743 /* Only if typdef == tinbody is typdefcblev significant. */
3744 if (typdef == tinbody && cblev <= typdefcblev)
3746 assert (cblev == typdefcblev);
3747 typdef = tend;
3749 break;
3750 case '=':
3751 if (definedef != dnone)
3752 break;
3753 switch (fvdef)
3755 case foperator:
3756 case finlist:
3757 case fignore:
3758 case vignore:
3759 break;
3760 case fvnameseen:
3761 if ((members && cblev == 1)
3762 || (globals && cblev == 0 && (!fvextern || declarations)))
3763 make_C_tag (FALSE); /* a variable */
3764 /* FALLTHRU */
3765 default:
3766 fvdef = vignore;
3768 break;
3769 case '<':
3770 if (cplpl && structdef == stagseen)
3772 structdef = sintemplate;
3773 break;
3775 goto resetfvdef;
3776 case '>':
3777 if (structdef == sintemplate)
3779 structdef = stagseen;
3780 break;
3782 goto resetfvdef;
3783 case '+':
3784 case '-':
3785 if (objdef == oinbody && cblev == 0)
3787 objdef = omethodsign;
3788 break;
3790 /* FALLTHRU */
3791 resetfvdef:
3792 case '#': case '~': case '&': case '%': case '/': case '|':
3793 case '^': case '!': case '.': case '?': case ']':
3794 if (definedef != dnone)
3795 break;
3796 /* These surely cannot follow a function tag in C. */
3797 switch (fvdef)
3799 case foperator:
3800 case finlist:
3801 case fignore:
3802 case vignore:
3803 break;
3804 default:
3805 fvdef = fvnone;
3807 break;
3808 case '\0':
3809 if (objdef == otagseen)
3811 make_C_tag (TRUE); /* an Objective C class */
3812 objdef = oignore;
3814 /* If a macro spans multiple lines don't reset its state. */
3815 if (quotednl)
3816 CNL_SAVE_DEFINEDEF ();
3817 else
3818 CNL ();
3819 break;
3820 } /* switch (c) */
3822 } /* while not eof */
3824 free (lbs[0].lb.buffer);
3825 free (lbs[1].lb.buffer);
3829 * Process either a C++ file or a C file depending on the setting
3830 * of a global flag.
3832 static void
3833 default_C_entries (inf)
3834 FILE *inf;
3836 C_entries (cplusplus ? C_PLPL : C_AUTO, inf);
3839 /* Always do plain C. */
3840 static void
3841 plain_C_entries (inf)
3842 FILE *inf;
3844 C_entries (0, inf);
3847 /* Always do C++. */
3848 static void
3849 Cplusplus_entries (inf)
3850 FILE *inf;
3852 C_entries (C_PLPL, inf);
3855 /* Always do Java. */
3856 static void
3857 Cjava_entries (inf)
3858 FILE *inf;
3860 C_entries (C_JAVA, inf);
3863 /* Always do C*. */
3864 static void
3865 Cstar_entries (inf)
3866 FILE *inf;
3868 C_entries (C_STAR, inf);
3871 /* Always do Yacc. */
3872 static void
3873 Yacc_entries (inf)
3874 FILE *inf;
3876 C_entries (YACC, inf);
3880 /* Useful macros. */
3881 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3882 for (; /* loop initialization */ \
3883 !feof (file_pointer) /* loop test */ \
3884 && /* instructions at start of loop */ \
3885 (readline (&line_buffer, file_pointer), \
3886 char_pointer = line_buffer.buffer, \
3887 TRUE); \
3889 #define LOOKING_AT(cp, keyword) /* keyword is a constant string */ \
3890 (strneq ((cp), keyword, sizeof(keyword)-1) /* cp points at keyword */ \
3891 && notinname ((cp)[sizeof(keyword)-1]) /* end of keyword */ \
3892 && ((cp) = skip_spaces((cp)+sizeof(keyword)-1))) /* skip spaces */
3895 * Read a file, but do no processing. This is used to do regexp
3896 * matching on files that have no language defined.
3898 static void
3899 just_read_file (inf)
3900 FILE *inf;
3902 register char *dummy;
3904 LOOP_ON_INPUT_LINES (inf, lb, dummy)
3905 continue;
3909 /* Fortran parsing */
3911 static void F_takeprec __P((void));
3912 static void F_getit __P((FILE *));
3914 static void
3915 F_takeprec ()
3917 dbp = skip_spaces (dbp);
3918 if (*dbp != '*')
3919 return;
3920 dbp++;
3921 dbp = skip_spaces (dbp);
3922 if (strneq (dbp, "(*)", 3))
3924 dbp += 3;
3925 return;
3927 if (!ISDIGIT (*dbp))
3929 --dbp; /* force failure */
3930 return;
3933 dbp++;
3934 while (ISDIGIT (*dbp));
3937 static void
3938 F_getit (inf)
3939 FILE *inf;
3941 register char *cp;
3943 dbp = skip_spaces (dbp);
3944 if (*dbp == '\0')
3946 readline (&lb, inf);
3947 dbp = lb.buffer;
3948 if (dbp[5] != '&')
3949 return;
3950 dbp += 6;
3951 dbp = skip_spaces (dbp);
3953 if (!ISALPHA (*dbp) && *dbp != '_' && *dbp != '$')
3954 return;
3955 for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
3956 continue;
3957 make_tag (dbp, cp-dbp, TRUE,
3958 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3962 static void
3963 Fortran_functions (inf)
3964 FILE *inf;
3966 LOOP_ON_INPUT_LINES (inf, lb, dbp)
3968 if (*dbp == '%')
3969 dbp++; /* Ratfor escape to fortran */
3970 dbp = skip_spaces (dbp);
3971 if (*dbp == '\0')
3972 continue;
3973 switch (lowcase (*dbp))
3975 case 'i':
3976 if (nocase_tail ("integer"))
3977 F_takeprec ();
3978 break;
3979 case 'r':
3980 if (nocase_tail ("real"))
3981 F_takeprec ();
3982 break;
3983 case 'l':
3984 if (nocase_tail ("logical"))
3985 F_takeprec ();
3986 break;
3987 case 'c':
3988 if (nocase_tail ("complex") || nocase_tail ("character"))
3989 F_takeprec ();
3990 break;
3991 case 'd':
3992 if (nocase_tail ("double"))
3994 dbp = skip_spaces (dbp);
3995 if (*dbp == '\0')
3996 continue;
3997 if (nocase_tail ("precision"))
3998 break;
3999 continue;
4001 break;
4003 dbp = skip_spaces (dbp);
4004 if (*dbp == '\0')
4005 continue;
4006 switch (lowcase (*dbp))
4008 case 'f':
4009 if (nocase_tail ("function"))
4010 F_getit (inf);
4011 continue;
4012 case 's':
4013 if (nocase_tail ("subroutine"))
4014 F_getit (inf);
4015 continue;
4016 case 'e':
4017 if (nocase_tail ("entry"))
4018 F_getit (inf);
4019 continue;
4020 case 'b':
4021 if (nocase_tail ("blockdata") || nocase_tail ("block data"))
4023 dbp = skip_spaces (dbp);
4024 if (*dbp == '\0') /* assume un-named */
4025 make_tag ("blockdata", 9, TRUE,
4026 lb.buffer, dbp - lb.buffer, lineno, linecharno);
4027 else
4028 F_getit (inf); /* look for name */
4030 continue;
4037 * Ada parsing
4038 * Original code by
4039 * Philippe Waroquiers <philippe.waroquiers@eurocontrol.int> (1998)
4042 static void Ada_getit __P((FILE *, char *));
4044 /* Once we are positioned after an "interesting" keyword, let's get
4045 the real tag value necessary. */
4046 static void
4047 Ada_getit (inf, name_qualifier)
4048 FILE *inf;
4049 char *name_qualifier;
4051 register char *cp;
4052 char *name;
4053 char c;
4055 while (!feof (inf))
4057 dbp = skip_spaces (dbp);
4058 if (*dbp == '\0'
4059 || (dbp[0] == '-' && dbp[1] == '-'))
4061 readline (&lb, inf);
4062 dbp = lb.buffer;
4064 switch (lowcase(*dbp))
4066 case 'b':
4067 if (nocase_tail ("body"))
4069 /* Skipping body of procedure body or package body or ....
4070 resetting qualifier to body instead of spec. */
4071 name_qualifier = "/b";
4072 continue;
4074 break;
4075 case 't':
4076 /* Skipping type of task type or protected type ... */
4077 if (nocase_tail ("type"))
4078 continue;
4079 break;
4081 if (*dbp == '"')
4083 dbp += 1;
4084 for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
4085 continue;
4087 else
4089 dbp = skip_spaces (dbp);
4090 for (cp = dbp;
4091 (*cp != '\0'
4092 && (ISALPHA (*cp) || ISDIGIT (*cp) || *cp == '_' || *cp == '.'));
4093 cp++)
4094 continue;
4095 if (cp == dbp)
4096 return;
4098 c = *cp;
4099 *cp = '\0';
4100 name = concat (dbp, name_qualifier, "");
4101 *cp = c;
4102 make_tag (name, strlen (name), TRUE,
4103 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4104 free (name);
4105 if (c == '"')
4106 dbp = cp + 1;
4107 return;
4111 static void
4112 Ada_funcs (inf)
4113 FILE *inf;
4115 bool inquote = FALSE;
4116 bool skip_till_semicolumn = FALSE;
4118 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4120 while (*dbp != '\0')
4122 /* Skip a string i.e. "abcd". */
4123 if (inquote || (*dbp == '"'))
4125 dbp = etags_strchr ((inquote) ? dbp : dbp+1, '"');
4126 if (dbp != NULL)
4128 inquote = FALSE;
4129 dbp += 1;
4130 continue; /* advance char */
4132 else
4134 inquote = TRUE;
4135 break; /* advance line */
4139 /* Skip comments. */
4140 if (dbp[0] == '-' && dbp[1] == '-')
4141 break; /* advance line */
4143 /* Skip character enclosed in single quote i.e. 'a'
4144 and skip single quote starting an attribute i.e. 'Image. */
4145 if (*dbp == '\'')
4147 dbp++ ;
4148 if (*dbp != '\0')
4149 dbp++;
4150 continue;
4153 if (skip_till_semicolumn)
4155 if (*dbp == ';')
4156 skip_till_semicolumn = FALSE;
4157 dbp++;
4158 continue; /* advance char */
4161 /* Search for beginning of a token. */
4162 if (!begtoken (*dbp))
4164 dbp++;
4165 continue; /* advance char */
4168 /* We are at the beginning of a token. */
4169 switch (lowcase(*dbp))
4171 case 'f':
4172 if (!packages_only && nocase_tail ("function"))
4173 Ada_getit (inf, "/f");
4174 else
4175 break; /* from switch */
4176 continue; /* advance char */
4177 case 'p':
4178 if (!packages_only && nocase_tail ("procedure"))
4179 Ada_getit (inf, "/p");
4180 else if (nocase_tail ("package"))
4181 Ada_getit (inf, "/s");
4182 else if (nocase_tail ("protected")) /* protected type */
4183 Ada_getit (inf, "/t");
4184 else
4185 break; /* from switch */
4186 continue; /* advance char */
4188 case 'u':
4189 if (typedefs && !packages_only && nocase_tail ("use"))
4191 /* when tagging types, avoid tagging use type Pack.Typename;
4192 for this, we will skip everything till a ; */
4193 skip_till_semicolumn = TRUE;
4194 continue; /* advance char */
4197 case 't':
4198 if (!packages_only && nocase_tail ("task"))
4199 Ada_getit (inf, "/k");
4200 else if (typedefs && !packages_only && nocase_tail ("type"))
4202 Ada_getit (inf, "/t");
4203 while (*dbp != '\0')
4204 dbp += 1;
4206 else
4207 break; /* from switch */
4208 continue; /* advance char */
4211 /* Look for the end of the token. */
4212 while (!endtoken (*dbp))
4213 dbp++;
4215 } /* advance char */
4216 } /* advance line */
4221 * Unix and microcontroller assembly tag handling
4222 * Labels: /^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]/
4223 * Idea by Bob Weiner, Motorola Inc. (1994)
4225 static void
4226 Asm_labels (inf)
4227 FILE *inf;
4229 register char *cp;
4231 LOOP_ON_INPUT_LINES (inf, lb, cp)
4233 /* If first char is alphabetic or one of [_.$], test for colon
4234 following identifier. */
4235 if (ISALPHA (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4237 /* Read past label. */
4238 cp++;
4239 while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4240 cp++;
4241 if (*cp == ':' || iswhite (*cp))
4242 /* Found end of label, so copy it and add it to the table. */
4243 make_tag (lb.buffer, cp - lb.buffer, TRUE,
4244 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4251 * Perl support
4252 * Perl sub names: /^sub[ \t\n]+[^ \t\n{]+/
4253 * Perl variable names: /^(my|local).../
4254 * Original code by Bart Robinson <lomew@cs.utah.edu> (1995)
4255 * Additions by Michael Ernst <mernst@alum.mit.edu> (1997)
4256 * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
4258 static void
4259 Perl_functions (inf)
4260 FILE *inf;
4262 char *package = savestr ("main"); /* current package name */
4263 register char *cp;
4265 LOOP_ON_INPUT_LINES (inf, lb, cp)
4267 skip_spaces(cp);
4269 if (LOOKING_AT (cp, "package"))
4271 free (package);
4272 get_tag (cp, &package);
4274 else if (LOOKING_AT (cp, "sub"))
4276 char *pos;
4277 char *sp = cp;
4279 while (!notinname (*cp))
4280 cp++;
4281 if (cp == sp)
4282 continue; /* nothing found */
4283 if ((pos = etags_strchr (sp, ':')) != NULL
4284 && pos < cp && pos[1] == ':')
4285 /* The name is already qualified. */
4286 make_tag (sp, cp - sp, TRUE,
4287 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4288 else
4289 /* Qualify it. */
4291 char savechar, *name;
4293 savechar = *cp;
4294 *cp = '\0';
4295 name = concat (package, "::", sp);
4296 *cp = savechar;
4297 make_tag (name, strlen(name), TRUE,
4298 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4299 free (name);
4302 else if (globals) /* only if we are tagging global vars */
4304 /* Skip a qualifier, if any. */
4305 bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
4306 /* After "my" or "local", but before any following paren or space. */
4307 char *varstart = cp;
4309 if (qual /* should this be removed? If yes, how? */
4310 && (*cp == '$' || *cp == '@' || *cp == '%'))
4312 varstart += 1;
4314 cp++;
4315 while (ISALNUM (*cp) || *cp == '_');
4317 else if (qual)
4319 /* Should be examining a variable list at this point;
4320 could insist on seeing an open parenthesis. */
4321 while (*cp != '\0' && *cp != ';' && *cp != '=' && *cp != ')')
4322 cp++;
4324 else
4325 continue;
4327 make_tag (varstart, cp - varstart, FALSE,
4328 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4335 * Python support
4336 * Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
4337 * Idea by Eric S. Raymond <esr@thyrsus.com> (1997)
4338 * More ideas by seb bacon <seb@jamkit.com> (2002)
4340 static void
4341 Python_functions (inf)
4342 FILE *inf;
4344 register char *cp;
4346 LOOP_ON_INPUT_LINES (inf, lb, cp)
4348 cp = skip_spaces (cp);
4349 if (LOOKING_AT (cp, "def") || LOOKING_AT (cp, "class"))
4351 char *name = cp;
4352 while (!notinname (*cp) && *cp != ':')
4353 cp++;
4354 make_tag (name, cp - name, TRUE,
4355 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4362 * PHP support
4363 * Look for:
4364 * - /^[ \t]*function[ \t\n]+[^ \t\n(]+/
4365 * - /^[ \t]*class[ \t\n]+[^ \t\n]+/
4366 * - /^[ \t]*define\(\"[^\"]+/
4367 * Only with --members:
4368 * - /^[ \t]*var[ \t\n]+\$[^ \t\n=;]/
4369 * Idea by Diez B. Roggisch (2001)
4371 static void
4372 PHP_functions (inf)
4373 FILE *inf;
4375 register char *cp, *name;
4376 bool search_identifier = FALSE;
4378 LOOP_ON_INPUT_LINES (inf, lb, cp)
4380 cp = skip_spaces (cp);
4381 name = cp;
4382 if (search_identifier
4383 && *cp != '\0')
4385 while (!notinname (*cp))
4386 cp++;
4387 make_tag (name, cp - name, TRUE,
4388 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4389 search_identifier = FALSE;
4391 else if (LOOKING_AT (cp, "function"))
4393 if(*cp == '&')
4394 cp = skip_spaces (cp+1);
4395 if(*cp != '\0')
4397 name = cp;
4398 while (!notinname (*cp))
4399 cp++;
4400 make_tag (name, cp - name, TRUE,
4401 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4403 else
4404 search_identifier = TRUE;
4406 else if (LOOKING_AT (cp, "class"))
4408 if (*cp != '\0')
4410 name = cp;
4411 while (*cp != '\0' && !iswhite (*cp))
4412 cp++;
4413 make_tag (name, cp - name, FALSE,
4414 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4416 else
4417 search_identifier = TRUE;
4419 else if (strneq (cp, "define", 6)
4420 && (cp = skip_spaces (cp+6))
4421 && *cp++ == '('
4422 && (*cp == '"' || *cp == '\''))
4424 char quote = *cp++;
4425 name = cp;
4426 while (*cp != quote && *cp != '\0')
4427 cp++;
4428 make_tag (name, cp - name, FALSE,
4429 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4431 else if (members
4432 && LOOKING_AT (cp, "var")
4433 && *cp == '$')
4435 name = cp;
4436 while (!notinname(*cp))
4437 cp++;
4438 make_tag (name, cp - name, FALSE,
4439 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4446 * Cobol tag functions
4447 * We could look for anything that could be a paragraph name.
4448 * i.e. anything that starts in column 8 is one word and ends in a full stop.
4449 * Idea by Corny de Souza (1993)
4451 static void
4452 Cobol_paragraphs (inf)
4453 FILE *inf;
4455 register char *bp, *ep;
4457 LOOP_ON_INPUT_LINES (inf, lb, bp)
4459 if (lb.len < 9)
4460 continue;
4461 bp += 8;
4463 /* If eoln, compiler option or comment ignore whole line. */
4464 if (bp[-1] != ' ' || !ISALNUM (bp[0]))
4465 continue;
4467 for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
4468 continue;
4469 if (*ep++ == '.')
4470 make_tag (bp, ep - bp, TRUE,
4471 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4477 * Makefile support
4478 * Ideas by Assar Westerlund <assar@sics.se> (2001)
4480 static void
4481 Makefile_targets (inf)
4482 FILE *inf;
4484 register char *bp;
4486 LOOP_ON_INPUT_LINES (inf, lb, bp)
4488 if (*bp == '\t' || *bp == '#')
4489 continue;
4490 while (*bp != '\0' && *bp != '=' && *bp != ':')
4491 bp++;
4492 if (*bp == ':' || (globals && *bp == '='))
4493 make_tag (lb.buffer, bp - lb.buffer, TRUE,
4494 lb.buffer, bp - lb.buffer + 1, lineno, linecharno);
4500 * Pascal parsing
4501 * Original code by Mosur K. Mohan (1989)
4503 * Locates tags for procedures & functions. Doesn't do any type- or
4504 * var-definitions. It does look for the keyword "extern" or
4505 * "forward" immediately following the procedure statement; if found,
4506 * the tag is skipped.
4508 static void
4509 Pascal_functions (inf)
4510 FILE *inf;
4512 linebuffer tline; /* mostly copied from C_entries */
4513 long save_lcno;
4514 int save_lineno, namelen, taglen;
4515 char c, *name;
4517 bool /* each of these flags is TRUE iff: */
4518 incomment, /* point is inside a comment */
4519 inquote, /* point is inside '..' string */
4520 get_tagname, /* point is after PROCEDURE/FUNCTION
4521 keyword, so next item = potential tag */
4522 found_tag, /* point is after a potential tag */
4523 inparms, /* point is within parameter-list */
4524 verify_tag; /* point has passed the parm-list, so the
4525 next token will determine whether this
4526 is a FORWARD/EXTERN to be ignored, or
4527 whether it is a real tag */
4529 save_lcno = save_lineno = namelen = taglen = 0; /* keep compiler quiet */
4530 name = NULL; /* keep compiler quiet */
4531 dbp = lb.buffer;
4532 *dbp = '\0';
4533 linebuffer_init (&tline);
4535 incomment = inquote = FALSE;
4536 found_tag = FALSE; /* have a proc name; check if extern */
4537 get_tagname = FALSE; /* found "procedure" keyword */
4538 inparms = FALSE; /* found '(' after "proc" */
4539 verify_tag = FALSE; /* check if "extern" is ahead */
4542 while (!feof (inf)) /* long main loop to get next char */
4544 c = *dbp++;
4545 if (c == '\0') /* if end of line */
4547 readline (&lb, inf);
4548 dbp = lb.buffer;
4549 if (*dbp == '\0')
4550 continue;
4551 if (!((found_tag && verify_tag)
4552 || get_tagname))
4553 c = *dbp++; /* only if don't need *dbp pointing
4554 to the beginning of the name of
4555 the procedure or function */
4557 if (incomment)
4559 if (c == '}') /* within { } comments */
4560 incomment = FALSE;
4561 else if (c == '*' && *dbp == ')') /* within (* *) comments */
4563 dbp++;
4564 incomment = FALSE;
4566 continue;
4568 else if (inquote)
4570 if (c == '\'')
4571 inquote = FALSE;
4572 continue;
4574 else
4575 switch (c)
4577 case '\'':
4578 inquote = TRUE; /* found first quote */
4579 continue;
4580 case '{': /* found open { comment */
4581 incomment = TRUE;
4582 continue;
4583 case '(':
4584 if (*dbp == '*') /* found open (* comment */
4586 incomment = TRUE;
4587 dbp++;
4589 else if (found_tag) /* found '(' after tag, i.e., parm-list */
4590 inparms = TRUE;
4591 continue;
4592 case ')': /* end of parms list */
4593 if (inparms)
4594 inparms = FALSE;
4595 continue;
4596 case ';':
4597 if (found_tag && !inparms) /* end of proc or fn stmt */
4599 verify_tag = TRUE;
4600 break;
4602 continue;
4604 if (found_tag && verify_tag && (*dbp != ' '))
4606 /* Check if this is an "extern" declaration. */
4607 if (*dbp == '\0')
4608 continue;
4609 if (lowcase (*dbp == 'e'))
4611 if (nocase_tail ("extern")) /* superfluous, really! */
4613 found_tag = FALSE;
4614 verify_tag = FALSE;
4617 else if (lowcase (*dbp) == 'f')
4619 if (nocase_tail ("forward")) /* check for forward reference */
4621 found_tag = FALSE;
4622 verify_tag = FALSE;
4625 if (found_tag && verify_tag) /* not external proc, so make tag */
4627 found_tag = FALSE;
4628 verify_tag = FALSE;
4629 make_tag (name, namelen, TRUE,
4630 tline.buffer, taglen, save_lineno, save_lcno);
4631 continue;
4634 if (get_tagname) /* grab name of proc or fn */
4636 char *cp;
4638 if (*dbp == '\0')
4639 continue;
4641 /* Find block name. */
4642 for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
4643 continue;
4645 /* Save all values for later tagging. */
4646 linebuffer_setlen (&tline, lb.len);
4647 strcpy (tline.buffer, lb.buffer);
4648 save_lineno = lineno;
4649 save_lcno = linecharno;
4650 name = tline.buffer + (dbp - lb.buffer);
4651 namelen = cp - dbp;
4652 taglen = cp - lb.buffer + 1;
4654 dbp = cp; /* set dbp to e-o-token */
4655 get_tagname = FALSE;
4656 found_tag = TRUE;
4657 continue;
4659 /* And proceed to check for "extern". */
4661 else if (!incomment && !inquote && !found_tag)
4663 /* Check for proc/fn keywords. */
4664 switch (lowcase (c))
4666 case 'p':
4667 if (nocase_tail ("rocedure")) /* c = 'p', dbp has advanced */
4668 get_tagname = TRUE;
4669 continue;
4670 case 'f':
4671 if (nocase_tail ("unction"))
4672 get_tagname = TRUE;
4673 continue;
4676 } /* while not eof */
4678 free (tline.buffer);
4683 * Lisp tag functions
4684 * look for (def or (DEF, quote or QUOTE
4687 static void L_getit __P((void));
4689 static void
4690 L_getit ()
4692 if (*dbp == '\'') /* Skip prefix quote */
4693 dbp++;
4694 else if (*dbp == '(')
4696 dbp++;
4697 /* Try to skip "(quote " */
4698 if (!LOOKING_AT (dbp, "quote") && !LOOKING_AT (dbp, "QUOTE"))
4699 /* Ok, then skip "(" before name in (defstruct (foo)) */
4700 dbp = skip_spaces (dbp);
4702 get_tag (dbp, NULL);
4705 static void
4706 Lisp_functions (inf)
4707 FILE *inf;
4709 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4711 if (dbp[0] != '(')
4712 continue;
4714 if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
4716 dbp = skip_non_spaces (dbp);
4717 dbp = skip_spaces (dbp);
4718 L_getit ();
4720 else
4722 /* Check for (foo::defmumble name-defined ... */
4724 dbp++;
4725 while (!notinname (*dbp) && *dbp != ':');
4726 if (*dbp == ':')
4729 dbp++;
4730 while (*dbp == ':');
4732 if (strneq (dbp, "def", 3) || strneq (dbp, "DEF", 3))
4734 dbp = skip_non_spaces (dbp);
4735 dbp = skip_spaces (dbp);
4736 L_getit ();
4745 * Postscript tag functions
4746 * Just look for lines where the first character is '/'
4747 * Also look at "defineps" for PSWrap
4748 * Ideas by:
4749 * Richard Mlynarik <mly@adoc.xerox.com> (1997)
4750 * Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
4752 static void
4753 Postscript_functions (inf)
4754 FILE *inf;
4756 register char *bp, *ep;
4758 LOOP_ON_INPUT_LINES (inf, lb, bp)
4760 if (bp[0] == '/')
4762 for (ep = bp+1;
4763 *ep != '\0' && *ep != ' ' && *ep != '{';
4764 ep++)
4765 continue;
4766 make_tag (bp, ep - bp, TRUE,
4767 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4769 else if (LOOKING_AT (bp, "defineps"))
4770 get_tag (bp, NULL);
4776 * Scheme tag functions
4777 * look for (def... xyzzy
4778 * (def... (xyzzy
4779 * (def ... ((...(xyzzy ....
4780 * (set! xyzzy
4781 * Original code by Ken Haase (1985?)
4784 static void
4785 Scheme_functions (inf)
4786 FILE *inf;
4788 register char *bp;
4790 LOOP_ON_INPUT_LINES (inf, lb, bp)
4792 if (strneq (bp, "(def", 4) || strneq (bp, "(DEF", 4))
4794 bp = skip_non_spaces (bp+4);
4795 /* Skip over open parens and white space */
4796 while (notinname (*bp))
4797 bp++;
4798 get_tag (bp, NULL);
4800 if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))
4801 get_tag (bp, NULL);
4806 /* Find tags in TeX and LaTeX input files. */
4808 /* TEX_toktab is a table of TeX control sequences that define tags.
4809 * Each entry records one such control sequence.
4811 * Original code from who knows whom.
4812 * Ideas by:
4813 * Stefan Monnier (2002)
4816 static linebuffer *TEX_toktab = NULL; /* Table with tag tokens */
4818 /* Default set of control sequences to put into TEX_toktab.
4819 The value of environment var TEXTAGS is prepended to this. */
4820 static char *TEX_defenv = "\
4821 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4822 :part:appendix:entry:index:def\
4823 :newcommand:renewcommand:newenvironment:renewenvironment";
4825 static void TEX_mode __P((FILE *));
4826 static void TEX_decode_env __P((char *, char *));
4828 static char TEX_esc = '\\';
4829 static char TEX_opgrp = '{';
4830 static char TEX_clgrp = '}';
4833 * TeX/LaTeX scanning loop.
4835 static void
4836 TeX_commands (inf)
4837 FILE *inf;
4839 char *cp;
4840 linebuffer *key;
4842 /* Select either \ or ! as escape character. */
4843 TEX_mode (inf);
4845 /* Initialize token table once from environment. */
4846 if (TEX_toktab == NULL)
4847 TEX_decode_env ("TEXTAGS", TEX_defenv);
4849 LOOP_ON_INPUT_LINES (inf, lb, cp)
4851 /* Look at each TEX keyword in line. */
4852 for (;;)
4854 /* Look for a TEX escape. */
4855 while (*cp++ != TEX_esc)
4856 if (cp[-1] == '\0' || cp[-1] == '%')
4857 goto tex_next_line;
4859 for (key = TEX_toktab; key->buffer != NULL; key++)
4860 if (strneq (cp, key->buffer, key->len))
4862 register char *p;
4863 int namelen, linelen;
4864 bool opgrp = FALSE;
4866 cp = skip_spaces (cp + key->len);
4867 if (*cp == TEX_opgrp)
4869 opgrp = TRUE;
4870 cp++;
4872 for (p = cp;
4873 (!iswhite (*p) && *p != '#' &&
4874 *p != TEX_opgrp && *p != TEX_clgrp);
4875 p++)
4876 continue;
4877 namelen = p - cp;
4878 linelen = lb.len;
4879 if (!opgrp || *p == TEX_clgrp)
4881 while (*p != '\0' && *p != TEX_opgrp && *p != TEX_clgrp)
4882 *p++;
4883 linelen = p - lb.buffer + 1;
4885 make_tag (cp, namelen, TRUE,
4886 lb.buffer, linelen, lineno, linecharno);
4887 goto tex_next_line; /* We only tag a line once */
4890 tex_next_line:
4895 #define TEX_LESC '\\'
4896 #define TEX_SESC '!'
4898 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4899 chars accordingly. */
4900 static void
4901 TEX_mode (inf)
4902 FILE *inf;
4904 int c;
4906 while ((c = getc (inf)) != EOF)
4908 /* Skip to next line if we hit the TeX comment char. */
4909 if (c == '%')
4910 while (c != '\n')
4911 c = getc (inf);
4912 else if (c == TEX_LESC || c == TEX_SESC )
4913 break;
4916 if (c == TEX_LESC)
4918 TEX_esc = TEX_LESC;
4919 TEX_opgrp = '{';
4920 TEX_clgrp = '}';
4922 else
4924 TEX_esc = TEX_SESC;
4925 TEX_opgrp = '<';
4926 TEX_clgrp = '>';
4928 /* If the input file is compressed, inf is a pipe, and rewind may fail.
4929 No attempt is made to correct the situation. */
4930 rewind (inf);
4933 /* Read environment and prepend it to the default string.
4934 Build token table. */
4935 static void
4936 TEX_decode_env (evarname, defenv)
4937 char *evarname;
4938 char *defenv;
4940 register char *env, *p;
4941 int i, len;
4943 /* Append default string to environment. */
4944 env = getenv (evarname);
4945 if (!env)
4946 env = defenv;
4947 else
4949 char *oldenv = env;
4950 env = concat (oldenv, defenv, "");
4953 /* Allocate a token table */
4954 for (len = 1, p = env; p;)
4955 if ((p = etags_strchr (p, ':')) && *++p != '\0')
4956 len++;
4957 TEX_toktab = xnew (len, linebuffer);
4959 /* Unpack environment string into token table. Be careful about */
4960 /* zero-length strings (leading ':', "::" and trailing ':') */
4961 for (i = 0; *env != '\0';)
4963 p = etags_strchr (env, ':');
4964 if (!p) /* End of environment string. */
4965 p = env + strlen (env);
4966 if (p - env > 0)
4967 { /* Only non-zero strings. */
4968 TEX_toktab[i].buffer = savenstr (env, p - env);
4969 TEX_toktab[i].len = p - env;
4970 i++;
4972 if (*p)
4973 env = p + 1;
4974 else
4976 TEX_toktab[i].buffer = NULL; /* Mark end of table. */
4977 TEX_toktab[i].len = 0;
4978 break;
4984 /* Texinfo support. Dave Love, Mar. 2000. */
4985 static void
4986 Texinfo_nodes (inf)
4987 FILE * inf;
4989 char *cp, *start;
4990 LOOP_ON_INPUT_LINES (inf, lb, cp)
4991 if (LOOKING_AT (cp, "@node"))
4993 start = cp;
4994 while (*cp != '\0' && *cp != ',')
4995 cp++;
4996 make_tag (start, cp - start, TRUE,
4997 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5002 /* Similar to LOOKING_AT but does not use notinname, does not skip */
5003 #define LOOKING_AT_NOCASE(cp, kw) /* kw is a constant string */ \
5004 (strncaseeq ((cp), kw, sizeof(kw)-1) /* cp points at kw */ \
5005 && ((cp) += sizeof(kw)-1)) /* skip spaces */
5008 * HTML support.
5009 * Contents of <title>, <h1>, <h2>, <h3> are tags.
5010 * Contents of <a name=xxx> are tags with name xxx.
5012 * Francesco Potortì, 2002.
5014 static void
5015 HTML_labels (inf)
5016 FILE * inf;
5018 bool getnext = FALSE; /* next text outside of HTML tags is a tag */
5019 bool skiptag = FALSE; /* skip to the end of the current HTML tag */
5020 bool intag = FALSE; /* inside an html tag, looking for ID= */
5021 bool inanchor = FALSE; /* when INTAG, is an anchor, look for NAME= */
5022 char *end;
5025 linebuffer_setlen (&token_name, 0); /* no name in buffer */
5027 LOOP_ON_INPUT_LINES (inf, lb, dbp)
5028 for (;;) /* loop on the same line */
5030 if (skiptag) /* skip HTML tag */
5032 while (*dbp != '\0' && *dbp != '>')
5033 dbp++;
5034 if (*dbp == '>')
5036 dbp += 1;
5037 skiptag = FALSE;
5038 continue; /* look on the same line */
5040 break; /* go to next line */
5043 else if (intag) /* look for "name=" or "id=" */
5045 while (*dbp != '\0' && *dbp != '>'
5046 && lowcase (*dbp) != 'n' && lowcase (*dbp) != 'i')
5047 dbp++;
5048 if (*dbp == '\0')
5049 break; /* go to next line */
5050 if (*dbp == '>')
5052 dbp += 1;
5053 intag = FALSE;
5054 continue; /* look on the same line */
5056 if ((inanchor && LOOKING_AT_NOCASE (dbp, "name="))
5057 || LOOKING_AT_NOCASE (dbp, "id="))
5059 bool quoted = (dbp[0] == '"');
5061 if (quoted)
5062 for (end = ++dbp; *end != '\0' && *end != '"'; end++)
5063 continue;
5064 else
5065 for (end = dbp; *end != '\0' && intoken (*end); end++)
5066 continue;
5067 linebuffer_setlen (&token_name, end - dbp);
5068 strncpy (token_name.buffer, dbp, end - dbp);
5069 token_name.buffer[end - dbp] = '\0';
5071 dbp = end;
5072 intag = FALSE; /* we found what we looked for */
5073 skiptag = TRUE; /* skip to the end of the tag */
5074 getnext = TRUE; /* then grab the text */
5075 continue; /* look on the same line */
5077 dbp += 1;
5080 else if (getnext) /* grab next tokens and tag them */
5082 dbp = skip_spaces (dbp);
5083 if (*dbp == '\0')
5084 break; /* go to next line */
5085 if (*dbp == '<')
5087 intag = TRUE;
5088 inanchor = (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]));
5089 continue; /* look on the same line */
5092 for (end = dbp + 1; *end != '\0' && *end != '<'; end++)
5093 continue;
5094 make_tag (token_name.buffer, token_name.len, TRUE,
5095 dbp, end - dbp, lineno, linecharno);
5096 linebuffer_setlen (&token_name, 0); /* no name in buffer */
5097 getnext = FALSE;
5098 break; /* go to next line */
5101 else /* look for an interesting HTML tag */
5103 while (*dbp != '\0' && *dbp != '<')
5104 dbp++;
5105 if (*dbp == '\0')
5106 break; /* go to next line */
5107 intag = TRUE;
5108 if (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]))
5110 inanchor = TRUE;
5111 continue; /* look on the same line */
5113 else if (LOOKING_AT_NOCASE (dbp, "<title>")
5114 || LOOKING_AT_NOCASE (dbp, "<h1>")
5115 || LOOKING_AT_NOCASE (dbp, "<h2>")
5116 || LOOKING_AT_NOCASE (dbp, "<h3>"))
5118 intag = FALSE;
5119 getnext = TRUE;
5120 continue; /* look on the same line */
5122 dbp += 1;
5129 * Prolog support
5131 * Assumes that the predicate or rule starts at column 0.
5132 * Only the first clause of a predicate or rule is added.
5133 * Original code by Sunichirou Sugou (1989)
5134 * Rewritten by Anders Lindgren (1996)
5136 static int prolog_pr __P((char *, char *));
5137 static void prolog_skip_comment __P((linebuffer *, FILE *));
5138 static int prolog_atom __P((char *, int));
5140 static void
5141 Prolog_functions (inf)
5142 FILE *inf;
5144 char *cp, *last;
5145 int len;
5146 int allocated;
5148 allocated = 0;
5149 len = 0;
5150 last = NULL;
5152 LOOP_ON_INPUT_LINES (inf, lb, cp)
5154 if (cp[0] == '\0') /* Empty line */
5155 continue;
5156 else if (iswhite (cp[0])) /* Not a predicate */
5157 continue;
5158 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
5159 prolog_skip_comment (&lb, inf);
5160 else if ((len = prolog_pr (cp, last)) > 0)
5162 /* Predicate or rule. Store the function name so that we
5163 only generate a tag for the first clause. */
5164 if (last == NULL)
5165 last = xnew(len + 1, char);
5166 else if (len + 1 > allocated)
5167 xrnew (last, len + 1, char);
5168 allocated = len + 1;
5169 strncpy (last, cp, len);
5170 last[len] = '\0';
5176 static void
5177 prolog_skip_comment (plb, inf)
5178 linebuffer *plb;
5179 FILE *inf;
5181 char *cp;
5185 for (cp = plb->buffer; *cp != '\0'; cp++)
5186 if (cp[0] == '*' && cp[1] == '/')
5187 return;
5188 readline (plb, inf);
5190 while (!feof(inf));
5194 * A predicate or rule definition is added if it matches:
5195 * <beginning of line><Prolog Atom><whitespace>(
5196 * or <beginning of line><Prolog Atom><whitespace>:-
5198 * It is added to the tags database if it doesn't match the
5199 * name of the previous clause header.
5201 * Return the size of the name of the predicate or rule, or 0 if no
5202 * header was found.
5204 static int
5205 prolog_pr (s, last)
5206 char *s;
5207 char *last; /* Name of last clause. */
5209 int pos;
5210 int len;
5212 pos = prolog_atom (s, 0);
5213 if (pos < 1)
5214 return 0;
5216 len = pos;
5217 pos = skip_spaces (s + pos) - s;
5219 if ((s[pos] == '.'
5220 || (s[pos] == '(' && (pos += 1))
5221 || (s[pos] == ':' && s[pos + 1] == '-' && (pos += 2)))
5222 && (last == NULL /* save only the first clause */
5223 || len != strlen (last)
5224 || !strneq (s, last, len)))
5226 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5227 return len;
5229 else
5230 return 0;
5234 * Consume a Prolog atom.
5235 * Return the number of bytes consumed, or -1 if there was an error.
5237 * A prolog atom, in this context, could be one of:
5238 * - An alphanumeric sequence, starting with a lower case letter.
5239 * - A quoted arbitrary string. Single quotes can escape themselves.
5240 * Backslash quotes everything.
5242 static int
5243 prolog_atom (s, pos)
5244 char *s;
5245 int pos;
5247 int origpos;
5249 origpos = pos;
5251 if (ISLOWER(s[pos]) || (s[pos] == '_'))
5253 /* The atom is unquoted. */
5254 pos++;
5255 while (ISALNUM(s[pos]) || (s[pos] == '_'))
5257 pos++;
5259 return pos - origpos;
5261 else if (s[pos] == '\'')
5263 pos++;
5265 for (;;)
5267 if (s[pos] == '\'')
5269 pos++;
5270 if (s[pos] != '\'')
5271 break;
5272 pos++; /* A double quote */
5274 else if (s[pos] == '\0')
5275 /* Multiline quoted atoms are ignored. */
5276 return -1;
5277 else if (s[pos] == '\\')
5279 if (s[pos+1] == '\0')
5280 return -1;
5281 pos += 2;
5283 else
5284 pos++;
5286 return pos - origpos;
5288 else
5289 return -1;
5294 * Support for Erlang
5296 * Generates tags for functions, defines, and records.
5297 * Assumes that Erlang functions start at column 0.
5298 * Original code by Anders Lindgren (1996)
5300 static int erlang_func __P((char *, char *));
5301 static void erlang_attribute __P((char *));
5302 static int erlang_atom __P((char *));
5304 static void
5305 Erlang_functions (inf)
5306 FILE *inf;
5308 char *cp, *last;
5309 int len;
5310 int allocated;
5312 allocated = 0;
5313 len = 0;
5314 last = NULL;
5316 LOOP_ON_INPUT_LINES (inf, lb, cp)
5318 if (cp[0] == '\0') /* Empty line */
5319 continue;
5320 else if (iswhite (cp[0])) /* Not function nor attribute */
5321 continue;
5322 else if (cp[0] == '%') /* comment */
5323 continue;
5324 else if (cp[0] == '"') /* Sometimes, strings start in column one */
5325 continue;
5326 else if (cp[0] == '-') /* attribute, e.g. "-define" */
5328 erlang_attribute (cp);
5329 last = NULL;
5331 else if ((len = erlang_func (cp, last)) > 0)
5334 * Function. Store the function name so that we only
5335 * generates a tag for the first clause.
5337 if (last == NULL)
5338 last = xnew (len + 1, char);
5339 else if (len + 1 > allocated)
5340 xrnew (last, len + 1, char);
5341 allocated = len + 1;
5342 strncpy (last, cp, len);
5343 last[len] = '\0';
5350 * A function definition is added if it matches:
5351 * <beginning of line><Erlang Atom><whitespace>(
5353 * It is added to the tags database if it doesn't match the
5354 * name of the previous clause header.
5356 * Return the size of the name of the function, or 0 if no function
5357 * was found.
5359 static int
5360 erlang_func (s, last)
5361 char *s;
5362 char *last; /* Name of last clause. */
5364 int pos;
5365 int len;
5367 pos = erlang_atom (s);
5368 if (pos < 1)
5369 return 0;
5371 len = pos;
5372 pos = skip_spaces (s + pos) - s;
5374 /* Save only the first clause. */
5375 if (s[pos++] == '('
5376 && (last == NULL
5377 || len != (int)strlen (last)
5378 || !strneq (s, last, len)))
5380 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5381 return len;
5384 return 0;
5389 * Handle attributes. Currently, tags are generated for defines
5390 * and records.
5392 * They are on the form:
5393 * -define(foo, bar).
5394 * -define(Foo(M, N), M+N).
5395 * -record(graph, {vtab = notable, cyclic = true}).
5397 static void
5398 erlang_attribute (s)
5399 char *s;
5401 char *cp = s;
5403 if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
5404 && *cp++ == '(')
5406 int len = erlang_atom (skip_spaces (cp));
5407 if (len > 0)
5408 make_tag (cp, len, TRUE, s, cp + len - s, lineno, linecharno);
5410 return;
5415 * Consume an Erlang atom (or variable).
5416 * Return the number of bytes consumed, or -1 if there was an error.
5418 static int
5419 erlang_atom (s)
5420 char *s;
5422 int pos = 0;
5424 if (ISALPHA (s[pos]) || s[pos] == '_')
5426 /* The atom is unquoted. */
5428 pos++;
5429 while (ISALNUM (s[pos]) || s[pos] == '_');
5431 else if (s[pos] == '\'')
5433 for (pos++; s[pos] != '\''; pos++)
5434 if (s[pos] == '\0' /* multiline quoted atoms are ignored */
5435 || (s[pos] == '\\' && s[++pos] == '\0'))
5436 return 0;
5437 pos++;
5440 return pos;
5444 #ifdef ETAGS_REGEXPS
5446 static char *scan_separators __P((char *));
5447 static void add_regex __P((char *, language *));
5448 static char *substitute __P((char *, char *, struct re_registers *));
5451 * Take a string like "/blah/" and turn it into "blah", verifying
5452 * that the first and last characters are the same, and handling
5453 * quoted separator characters. Actually, stops on the occurrence of
5454 * an unquoted separator. Also process \t, \n, etc. and turn into
5455 * appropriate characters. Works in place. Null terminates name string.
5456 * Returns pointer to terminating separator, or NULL for
5457 * unterminated regexps.
5459 static char *
5460 scan_separators (name)
5461 char *name;
5463 char sep = name[0];
5464 char *copyto = name;
5465 bool quoted = FALSE;
5467 for (++name; *name != '\0'; ++name)
5469 if (quoted)
5471 switch (*name)
5473 case 'a': *copyto++ = '\007'; break; /* BEL (bell) */
5474 case 'b': *copyto++ = '\b'; break; /* BS (back space) */
5475 case 'd': *copyto++ = 0177; break; /* DEL (delete) */
5476 case 'e': *copyto++ = 033; break; /* ESC (delete) */
5477 case 'f': *copyto++ = '\f'; break; /* FF (form feed) */
5478 case 'n': *copyto++ = '\n'; break; /* NL (new line) */
5479 case 'r': *copyto++ = '\r'; break; /* CR (carriage return) */
5480 case 't': *copyto++ = '\t'; break; /* TAB (horizontal tab) */
5481 case 'v': *copyto++ = '\v'; break; /* VT (vertical tab) */
5482 default:
5483 if (*name == sep)
5484 *copyto++ = sep;
5485 else
5487 /* Something else is quoted, so preserve the quote. */
5488 *copyto++ = '\\';
5489 *copyto++ = *name;
5491 break;
5493 quoted = FALSE;
5495 else if (*name == '\\')
5496 quoted = TRUE;
5497 else if (*name == sep)
5498 break;
5499 else
5500 *copyto++ = *name;
5502 if (*name != sep)
5503 name = NULL; /* signal unterminated regexp */
5505 /* Terminate copied string. */
5506 *copyto = '\0';
5507 return name;
5510 /* Look at the argument of --regex or --no-regex and do the right
5511 thing. Same for each line of a regexp file. */
5512 static void
5513 analyse_regex (regex_arg)
5514 char *regex_arg;
5516 if (regex_arg == NULL)
5518 free_regexps (); /* --no-regex: remove existing regexps */
5519 return;
5522 /* A real --regexp option or a line in a regexp file. */
5523 switch (regex_arg[0])
5525 /* Comments in regexp file or null arg to --regex. */
5526 case '\0':
5527 case ' ':
5528 case '\t':
5529 break;
5531 /* Read a regex file. This is recursive and may result in a
5532 loop, which will stop when the file descriptors are exhausted. */
5533 case '@':
5535 FILE *regexfp;
5536 linebuffer regexbuf;
5537 char *regexfile = regex_arg + 1;
5539 /* regexfile is a file containing regexps, one per line. */
5540 regexfp = fopen (regexfile, "r");
5541 if (regexfp == NULL)
5543 pfatal (regexfile);
5544 return;
5546 linebuffer_init (&regexbuf);
5547 while (readline_internal (&regexbuf, regexfp) > 0)
5548 analyse_regex (regexbuf.buffer);
5549 free (regexbuf.buffer);
5550 fclose (regexfp);
5552 break;
5554 /* Regexp to be used for a specific language only. */
5555 case '{':
5557 language *lang;
5558 char *lang_name = regex_arg + 1;
5559 char *cp;
5561 for (cp = lang_name; *cp != '}'; cp++)
5562 if (*cp == '\0')
5564 error ("unterminated language name in regex: %s", regex_arg);
5565 return;
5567 *cp++ = '\0';
5568 lang = get_language_from_langname (lang_name);
5569 if (lang == NULL)
5570 return;
5571 add_regex (cp, lang);
5573 break;
5575 /* Regexp to be used for any language. */
5576 default:
5577 add_regex (regex_arg, NULL);
5578 break;
5582 /* Separate the regexp pattern, compile it,
5583 and care for optional name and modifiers. */
5584 static void
5585 add_regex (regexp_pattern, lang)
5586 char *regexp_pattern;
5587 language *lang;
5589 static struct re_pattern_buffer zeropattern;
5590 char sep, *pat, *name, *modifiers;
5591 const char *err;
5592 struct re_pattern_buffer *patbuf;
5593 regexp *rp;
5594 bool
5595 force_explicit_name = TRUE, /* do not use implicit tag names */
5596 ignore_case = FALSE, /* case is significant */
5597 multi_line = FALSE, /* matches are done one line at a time */
5598 single_line = FALSE; /* dot does not match newline */
5601 if (strlen(regexp_pattern) < 3)
5603 error ("null regexp", (char *)NULL);
5604 return;
5606 sep = regexp_pattern[0];
5607 name = scan_separators (regexp_pattern);
5608 if (name == NULL)
5610 error ("%s: unterminated regexp", regexp_pattern);
5611 return;
5613 if (name[1] == sep)
5615 error ("null name for regexp \"%s\"", regexp_pattern);
5616 return;
5618 modifiers = scan_separators (name);
5619 if (modifiers == NULL) /* no terminating separator --> no name */
5621 modifiers = name;
5622 name = "";
5624 else
5625 modifiers += 1; /* skip separator */
5627 /* Parse regex modifiers. */
5628 for (; modifiers[0] != '\0'; modifiers++)
5629 switch (modifiers[0])
5631 case 'N':
5632 if (modifiers == name)
5633 error ("forcing explicit tag name but no name, ignoring", NULL);
5634 force_explicit_name = TRUE;
5635 break;
5636 case 'i':
5637 ignore_case = TRUE;
5638 break;
5639 case 's':
5640 single_line = TRUE;
5641 /* FALLTHRU */
5642 case 'm':
5643 multi_line = TRUE;
5644 need_filebuf = TRUE;
5645 break;
5646 default:
5648 char wrongmod [2];
5649 wrongmod[0] = modifiers[0];
5650 wrongmod[1] = '\0';
5651 error ("invalid regexp modifier `%s', ignoring", wrongmod);
5653 break;
5656 patbuf = xnew (1, struct re_pattern_buffer);
5657 *patbuf = zeropattern;
5658 if (ignore_case)
5660 static char lc_trans[CHARS];
5661 int i;
5662 for (i = 0; i < CHARS; i++)
5663 lc_trans[i] = lowcase (i);
5664 patbuf->translate = lc_trans; /* translation table to fold case */
5667 if (multi_line)
5668 pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
5669 else
5670 pat = regexp_pattern;
5672 if (single_line)
5673 re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
5674 else
5675 re_set_syntax (RE_SYNTAX_EMACS);
5677 err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
5678 if (multi_line)
5679 free (pat);
5680 if (err != NULL)
5682 error ("%s while compiling pattern", err);
5683 return;
5686 rp = p_head;
5687 p_head = xnew (1, regexp);
5688 p_head->pattern = savestr (regexp_pattern);
5689 p_head->p_next = rp;
5690 p_head->lang = lang;
5691 p_head->pat = patbuf;
5692 p_head->name = savestr (name);
5693 p_head->error_signaled = FALSE;
5694 p_head->force_explicit_name = force_explicit_name;
5695 p_head->ignore_case = ignore_case;
5696 p_head->multi_line = multi_line;
5700 * Do the substitutions indicated by the regular expression and
5701 * arguments.
5703 static char *
5704 substitute (in, out, regs)
5705 char *in, *out;
5706 struct re_registers *regs;
5708 char *result, *t;
5709 int size, dig, diglen;
5711 result = NULL;
5712 size = strlen (out);
5714 /* Pass 1: figure out how much to allocate by finding all \N strings. */
5715 if (out[size - 1] == '\\')
5716 fatal ("pattern error in \"%s\"", out);
5717 for (t = etags_strchr (out, '\\');
5718 t != NULL;
5719 t = etags_strchr (t + 2, '\\'))
5720 if (ISDIGIT (t[1]))
5722 dig = t[1] - '0';
5723 diglen = regs->end[dig] - regs->start[dig];
5724 size += diglen - 2;
5726 else
5727 size -= 1;
5729 /* Allocate space and do the substitutions. */
5730 result = xnew (size + 1, char);
5732 for (t = result; *out != '\0'; out++)
5733 if (*out == '\\' && ISDIGIT (*++out))
5735 dig = *out - '0';
5736 diglen = regs->end[dig] - regs->start[dig];
5737 strncpy (t, in + regs->start[dig], diglen);
5738 t += diglen;
5740 else
5741 *t++ = *out;
5742 *t = '\0';
5744 assert (t <= result + size && t - result == (int)strlen (result));
5746 return result;
5749 /* Deallocate all regexps. */
5750 static void
5751 free_regexps ()
5753 regexp *rp;
5754 while (p_head != NULL)
5756 rp = p_head->p_next;
5757 free (p_head->pattern);
5758 free (p_head->name);
5759 free (p_head);
5760 p_head = rp;
5762 return;
5766 * Reads the whole file as a single string from `filebuf' and looks for
5767 * multi-line regular expressions, creating tags on matches.
5768 * readline already dealt with normal regexps.
5770 * Idea by Ben Wing <ben@666.com> (2002).
5772 static void
5773 regex_tag_multiline ()
5775 char *buffer = filebuf.buffer;
5776 regexp *rp;
5777 char *name;
5779 for (rp = p_head; rp != NULL; rp = rp->p_next)
5781 int match = 0;
5783 if (!rp->multi_line)
5784 continue; /* skip normal regexps */
5786 /* Generic initialisations before parsing file from memory. */
5787 lineno = 1; /* reset global line number */
5788 charno = 0; /* reset global char number */
5789 linecharno = 0; /* reset global char number of line start */
5791 /* Only use generic regexps or those for the current language. */
5792 if (rp->lang != NULL && rp->lang != curfdp->lang)
5793 continue;
5795 while (match >= 0 && match < filebuf.len)
5797 match = re_search (rp->pat, buffer, filebuf.len, charno,
5798 filebuf.len - match, &rp->regs);
5799 switch (match)
5801 case -2:
5802 /* Some error. */
5803 if (!rp->error_signaled)
5805 error ("regexp stack overflow while matching \"%s\"",
5806 rp->pattern);
5807 rp->error_signaled = TRUE;
5809 break;
5810 case -1:
5811 /* No match. */
5812 break;
5813 default:
5814 if (match == rp->regs.end[0])
5816 if (!rp->error_signaled)
5818 error ("regexp matches the empty string: \"%s\"",
5819 rp->pattern);
5820 rp->error_signaled = TRUE;
5822 match = -3; /* exit from while loop */
5823 break;
5826 /* Match occurred. Construct a tag. */
5827 while (charno < rp->regs.end[0])
5828 if (buffer[charno++] == '\n')
5829 lineno++, linecharno = charno;
5830 name = rp->name;
5831 if (name[0] != '\0')
5832 /* Make a named tag. */
5833 name = substitute (buffer, rp->name, &rp->regs);
5834 if (rp->force_explicit_name)
5835 /* Force explicit tag name, if a name is there. */
5836 pfnote (name, TRUE, buffer + linecharno,
5837 charno - linecharno + 1, lineno, linecharno);
5838 else
5839 make_tag (name, strlen (name), TRUE, buffer + linecharno,
5840 charno - linecharno + 1, lineno, linecharno);
5841 break;
5847 #endif /* ETAGS_REGEXPS */
5850 static bool
5851 nocase_tail (cp)
5852 char *cp;
5854 register int len = 0;
5856 while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
5857 cp++, len++;
5858 if (*cp == '\0' && !intoken (dbp[len]))
5860 dbp += len;
5861 return TRUE;
5863 return FALSE;
5866 static void
5867 get_tag (bp, namepp)
5868 register char *bp;
5869 char **namepp;
5871 register char *cp = bp;
5873 if (*bp != '\0')
5875 /* Go till you get to white space or a syntactic break */
5876 for (cp = bp + 1; !notinname (*cp); cp++)
5877 continue;
5878 make_tag (bp, cp - bp, TRUE,
5879 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5882 if (namepp != NULL)
5883 *namepp = savenstr (bp, cp - bp);
5887 * Read a line of text from `stream' into `lbp', excluding the
5888 * newline or CR-NL, if any. Return the number of characters read from
5889 * `stream', which is the length of the line including the newline.
5891 * On DOS or Windows we do not count the CR character, if any before the
5892 * NL, in the returned length; this mirrors the behavior of Emacs on those
5893 * platforms (for text files, it translates CR-NL to NL as it reads in the
5894 * file).
5896 * If multi-line regular expressions are requested, each line read is
5897 * appended to `filebuf'.
5899 static long
5900 readline_internal (lbp, stream)
5901 linebuffer *lbp;
5902 register FILE *stream;
5904 char *buffer = lbp->buffer;
5905 register char *p = lbp->buffer;
5906 register char *pend;
5907 int chars_deleted;
5909 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
5911 for (;;)
5913 register int c = getc (stream);
5914 if (p == pend)
5916 /* We're at the end of linebuffer: expand it. */
5917 lbp->size *= 2;
5918 xrnew (buffer, lbp->size, char);
5919 p += buffer - lbp->buffer;
5920 pend = buffer + lbp->size;
5921 lbp->buffer = buffer;
5923 if (c == EOF)
5925 *p = '\0';
5926 chars_deleted = 0;
5927 break;
5929 if (c == '\n')
5931 if (p > buffer && p[-1] == '\r')
5933 p -= 1;
5934 #ifdef DOS_NT
5935 /* Assume CRLF->LF translation will be performed by Emacs
5936 when loading this file, so CRs won't appear in the buffer.
5937 It would be cleaner to compensate within Emacs;
5938 however, Emacs does not know how many CRs were deleted
5939 before any given point in the file. */
5940 chars_deleted = 1;
5941 #else
5942 chars_deleted = 2;
5943 #endif
5945 else
5947 chars_deleted = 1;
5949 *p = '\0';
5950 break;
5952 *p++ = c;
5954 lbp->len = p - buffer;
5956 if (need_filebuf /* we need filebuf for multi-line regexps */
5957 && chars_deleted > 0) /* not at EOF */
5959 while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
5961 /* Expand filebuf. */
5962 filebuf.size *= 2;
5963 xrnew (filebuf.buffer, filebuf.size, char);
5965 strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
5966 filebuf.len += lbp->len;
5967 filebuf.buffer[filebuf.len++] = '\n';
5968 filebuf.buffer[filebuf.len] = '\0';
5971 return lbp->len + chars_deleted;
5975 * Like readline_internal, above, but in addition try to match the
5976 * input line against relevant regular expressions and manage #line
5977 * directives.
5979 static void
5980 readline (lbp, stream)
5981 linebuffer *lbp;
5982 FILE *stream;
5984 long result;
5986 linecharno = charno; /* update global char number of line start */
5987 result = readline_internal (lbp, stream); /* read line */
5988 lineno += 1; /* increment global line number */
5989 charno += result; /* increment global char number */
5991 /* Honour #line directives. */
5992 if (!no_line_directive)
5994 static bool discard_until_line_directive;
5996 /* Check whether this is a #line directive. */
5997 if (result > 12 && strneq (lbp->buffer, "#line ", 6))
5999 int start, lno;
6001 if (DEBUG) start = 0; /* shut up the compiler */
6002 if (sscanf (lbp->buffer, "#line %d \"%n", &lno, &start) == 1)
6004 char *endp = lbp->buffer + start;
6006 assert (start > 0);
6007 while ((endp = etags_strchr (endp, '"')) != NULL
6008 && endp[-1] == '\\')
6009 endp++;
6010 if (endp != NULL)
6011 /* Ok, this is a real #line directive. Let's deal with it. */
6013 char *taggedabsname; /* absolute name of original file */
6014 char *taggedfname; /* name of original file as given */
6015 char *name; /* temp var */
6017 discard_until_line_directive = FALSE; /* found it */
6018 name = lbp->buffer + start;
6019 *endp = '\0';
6020 canonicalize_filename (name); /* for DOS */
6021 taggedabsname = absolute_filename (name, curfdp->infabsdir);
6022 if (filename_is_absolute (name)
6023 || filename_is_absolute (curfdp->infname))
6024 taggedfname = savestr (taggedabsname);
6025 else
6026 taggedfname = relative_filename (taggedabsname,tagfiledir);
6028 if (streq (curfdp->taggedfname, taggedfname))
6029 /* The #line directive is only a line number change. We
6030 deal with this afterwards. */
6031 free (taggedfname);
6032 else
6033 /* The tags following this #line directive should be
6034 attributed to taggedfname. In order to do this, set
6035 curfdp accordingly. */
6037 fdesc *fdp; /* file description pointer */
6039 /* Go look for a file description already set up for the
6040 file indicated in the #line directive. If there is
6041 one, use it from now until the next #line
6042 directive. */
6043 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6044 if (streq (fdp->infname, curfdp->infname)
6045 && streq (fdp->taggedfname, taggedfname))
6046 /* If we remove the second test above (after the &&)
6047 then all entries pertaining to the same file are
6048 coalesced in the tags file. If we use it, then
6049 entries pertaining to the same file but generated
6050 from different files (via #line directives) will
6051 go into separate sections in the tags file. These
6052 alternatives look equivalent. The first one
6053 destroys some apparently useless information. */
6055 curfdp = fdp;
6056 free (taggedfname);
6057 break;
6059 /* Else, if we already tagged the real file, skip all
6060 input lines until the next #line directive. */
6061 if (fdp == NULL) /* not found */
6062 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6063 if (streq (fdp->infabsname, taggedabsname))
6065 discard_until_line_directive = TRUE;
6066 free (taggedfname);
6067 break;
6069 /* Else create a new file description and use that from
6070 now on, until the next #line directive. */
6071 if (fdp == NULL) /* not found */
6073 fdp = fdhead;
6074 fdhead = xnew (1, fdesc);
6075 *fdhead = *curfdp; /* copy curr. file description */
6076 fdhead->next = fdp;
6077 fdhead->infname = savestr (curfdp->infname);
6078 fdhead->infabsname = savestr (curfdp->infabsname);
6079 fdhead->infabsdir = savestr (curfdp->infabsdir);
6080 fdhead->taggedfname = taggedfname;
6081 fdhead->usecharno = FALSE;
6082 fdhead->prop = NULL;
6083 fdhead->written = FALSE;
6084 curfdp = fdhead;
6087 free (taggedabsname);
6088 lineno = lno - 1;
6089 readline (lbp, stream);
6090 return;
6091 } /* if a real #line directive */
6092 } /* if #line is followed by a a number */
6093 } /* if line begins with "#line " */
6095 /* If we are here, no #line directive was found. */
6096 if (discard_until_line_directive)
6098 if (result > 0)
6100 /* Do a tail recursion on ourselves, thus discarding the contents
6101 of the line buffer. */
6102 readline (lbp, stream);
6103 return;
6105 /* End of file. */
6106 discard_until_line_directive = FALSE;
6107 return;
6109 } /* if #line directives should be considered */
6111 #ifdef ETAGS_REGEXPS
6113 int match;
6114 regexp *rp;
6115 char *name;
6117 /* Match against relevant regexps. */
6118 if (lbp->len > 0)
6119 for (rp = p_head; rp != NULL; rp = rp->p_next)
6121 /* Only use generic regexps or those for the current language.
6122 Also do not use multiline regexps, which is the job of
6123 regex_tag_multiline. */
6124 if ((rp->lang != NULL && rp->lang != fdhead->lang)
6125 || rp->multi_line)
6126 continue;
6128 match = re_match (rp->pat, lbp->buffer, lbp->len, 0, &rp->regs);
6129 switch (match)
6131 case -2:
6132 /* Some error. */
6133 if (!rp->error_signaled)
6135 error ("regexp stack overflow while matching \"%s\"",
6136 rp->pattern);
6137 rp->error_signaled = TRUE;
6139 break;
6140 case -1:
6141 /* No match. */
6142 break;
6143 case 0:
6144 /* Empty string matched. */
6145 if (!rp->error_signaled)
6147 error ("regexp matches the empty string: \"%s\"", rp->pattern);
6148 rp->error_signaled = TRUE;
6150 break;
6151 default:
6152 /* Match occurred. Construct a tag. */
6153 name = rp->name;
6154 if (name[0] != '\0')
6155 /* Make a named tag. */
6156 name = substitute (lbp->buffer, rp->name, &rp->regs);
6157 if (rp->force_explicit_name)
6158 /* Force explicit tag name, if a name is there. */
6159 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
6160 else
6161 make_tag (name, strlen (name), TRUE,
6162 lbp->buffer, match, lineno, linecharno);
6163 break;
6167 #endif /* ETAGS_REGEXPS */
6172 * Return a pointer to a space of size strlen(cp)+1 allocated
6173 * with xnew where the string CP has been copied.
6175 static char *
6176 savestr (cp)
6177 char *cp;
6179 return savenstr (cp, strlen (cp));
6183 * Return a pointer to a space of size LEN+1 allocated with xnew where
6184 * the string CP has been copied for at most the first LEN characters.
6186 static char *
6187 savenstr (cp, len)
6188 char *cp;
6189 int len;
6191 register char *dp;
6193 dp = xnew (len + 1, char);
6194 strncpy (dp, cp, len);
6195 dp[len] = '\0';
6196 return dp;
6200 * Return the ptr in sp at which the character c last
6201 * appears; NULL if not found
6203 * Identical to POSIX strrchr, included for portability.
6205 static char *
6206 etags_strrchr (sp, c)
6207 register const char *sp;
6208 register int c;
6210 register const char *r;
6212 r = NULL;
6215 if (*sp == c)
6216 r = sp;
6217 } while (*sp++);
6218 return (char *)r;
6222 * Return the ptr in sp at which the character c first
6223 * appears; NULL if not found
6225 * Identical to POSIX strchr, included for portability.
6227 static char *
6228 etags_strchr (sp, c)
6229 register const char *sp;
6230 register int c;
6234 if (*sp == c)
6235 return (char *)sp;
6236 } while (*sp++);
6237 return NULL;
6241 * Compare two strings, ignoring case for alphabetic characters.
6243 * Same as BSD's strcasecmp, included for portability.
6245 static int
6246 etags_strcasecmp (s1, s2)
6247 register const char *s1;
6248 register const char *s2;
6250 while (*s1 != '\0'
6251 && (ISALPHA (*s1) && ISALPHA (*s2)
6252 ? lowcase (*s1) == lowcase (*s2)
6253 : *s1 == *s2))
6254 s1++, s2++;
6256 return (ISALPHA (*s1) && ISALPHA (*s2)
6257 ? lowcase (*s1) - lowcase (*s2)
6258 : *s1 - *s2);
6262 * Compare two strings, ignoring case for alphabetic characters.
6263 * Stop after a given number of characters
6265 * Same as BSD's strncasecmp, included for portability.
6267 static int
6268 etags_strncasecmp (s1, s2, n)
6269 register const char *s1;
6270 register const char *s2;
6271 register int n;
6273 while (*s1 != '\0' && n-- > 0
6274 && (ISALPHA (*s1) && ISALPHA (*s2)
6275 ? lowcase (*s1) == lowcase (*s2)
6276 : *s1 == *s2))
6277 s1++, s2++;
6279 if (n < 0)
6280 return 0;
6281 else
6282 return (ISALPHA (*s1) && ISALPHA (*s2)
6283 ? lowcase (*s1) - lowcase (*s2)
6284 : *s1 - *s2);
6287 /* Skip spaces, return new pointer. */
6288 static char *
6289 skip_spaces (cp)
6290 char *cp;
6292 while (iswhite (*cp))
6293 cp++;
6294 return cp;
6297 /* Skip non spaces, return new pointer. */
6298 static char *
6299 skip_non_spaces (cp)
6300 char *cp;
6302 while (*cp != '\0' && !iswhite (*cp))
6303 cp++;
6304 return cp;
6307 /* Print error message and exit. */
6308 void
6309 fatal (s1, s2)
6310 char *s1, *s2;
6312 error (s1, s2);
6313 exit (BAD);
6316 static void
6317 pfatal (s1)
6318 char *s1;
6320 perror (s1);
6321 exit (BAD);
6324 static void
6325 suggest_asking_for_help ()
6327 fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
6328 progname,
6329 #ifdef LONG_OPTIONS
6330 "--help"
6331 #else
6332 "-h"
6333 #endif
6335 exit (BAD);
6338 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
6339 static void
6340 error (s1, s2)
6341 const char *s1, *s2;
6343 fprintf (stderr, "%s: ", progname);
6344 fprintf (stderr, s1, s2);
6345 fprintf (stderr, "\n");
6348 /* Return a newly-allocated string whose contents
6349 concatenate those of s1, s2, s3. */
6350 static char *
6351 concat (s1, s2, s3)
6352 char *s1, *s2, *s3;
6354 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
6355 char *result = xnew (len1 + len2 + len3 + 1, char);
6357 strcpy (result, s1);
6358 strcpy (result + len1, s2);
6359 strcpy (result + len1 + len2, s3);
6360 result[len1 + len2 + len3] = '\0';
6362 return result;
6366 /* Does the same work as the system V getcwd, but does not need to
6367 guess the buffer size in advance. */
6368 static char *
6369 etags_getcwd ()
6371 #ifdef HAVE_GETCWD
6372 int bufsize = 200;
6373 char *path = xnew (bufsize, char);
6375 while (getcwd (path, bufsize) == NULL)
6377 if (errno != ERANGE)
6378 pfatal ("getcwd");
6379 bufsize *= 2;
6380 free (path);
6381 path = xnew (bufsize, char);
6384 canonicalize_filename (path);
6385 return path;
6387 #else /* not HAVE_GETCWD */
6388 #if MSDOS
6390 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
6392 getwd (path);
6394 for (p = path; *p != '\0'; p++)
6395 if (*p == '\\')
6396 *p = '/';
6397 else
6398 *p = lowcase (*p);
6400 return strdup (path);
6401 #else /* not MSDOS */
6402 linebuffer path;
6403 FILE *pipe;
6405 linebuffer_init (&path);
6406 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
6407 if (pipe == NULL || readline_internal (&path, pipe) == 0)
6408 pfatal ("pwd");
6409 pclose (pipe);
6411 return path.buffer;
6412 #endif /* not MSDOS */
6413 #endif /* not HAVE_GETCWD */
6416 /* Return a newly allocated string containing the file name of FILE
6417 relative to the absolute directory DIR (which should end with a slash). */
6418 static char *
6419 relative_filename (file, dir)
6420 char *file, *dir;
6422 char *fp, *dp, *afn, *res;
6423 int i;
6425 /* Find the common root of file and dir (with a trailing slash). */
6426 afn = absolute_filename (file, cwd);
6427 fp = afn;
6428 dp = dir;
6429 while (*fp++ == *dp++)
6430 continue;
6431 fp--, dp--; /* back to the first differing char */
6432 #ifdef DOS_NT
6433 if (fp == afn && afn[0] != '/') /* cannot build a relative name */
6434 return afn;
6435 #endif
6436 do /* look at the equal chars until '/' */
6437 fp--, dp--;
6438 while (*fp != '/');
6440 /* Build a sequence of "../" strings for the resulting relative file name. */
6441 i = 0;
6442 while ((dp = etags_strchr (dp + 1, '/')) != NULL)
6443 i += 1;
6444 res = xnew (3*i + strlen (fp + 1) + 1, char);
6445 res[0] = '\0';
6446 while (i-- > 0)
6447 strcat (res, "../");
6449 /* Add the file name relative to the common root of file and dir. */
6450 strcat (res, fp + 1);
6451 free (afn);
6453 return res;
6456 /* Return a newly allocated string containing the absolute file name
6457 of FILE given DIR (which should end with a slash). */
6458 static char *
6459 absolute_filename (file, dir)
6460 char *file, *dir;
6462 char *slashp, *cp, *res;
6464 if (filename_is_absolute (file))
6465 res = savestr (file);
6466 #ifdef DOS_NT
6467 /* We don't support non-absolute file names with a drive
6468 letter, like `d:NAME' (it's too much hassle). */
6469 else if (file[1] == ':')
6470 fatal ("%s: relative file names with drive letters not supported", file);
6471 #endif
6472 else
6473 res = concat (dir, file, "");
6475 /* Delete the "/dirname/.." and "/." substrings. */
6476 slashp = etags_strchr (res, '/');
6477 while (slashp != NULL && slashp[0] != '\0')
6479 if (slashp[1] == '.')
6481 if (slashp[2] == '.'
6482 && (slashp[3] == '/' || slashp[3] == '\0'))
6484 cp = slashp;
6486 cp--;
6487 while (cp >= res && !filename_is_absolute (cp));
6488 if (cp < res)
6489 cp = slashp; /* the absolute name begins with "/.." */
6490 #ifdef DOS_NT
6491 /* Under MSDOS and NT we get `d:/NAME' as absolute
6492 file name, so the luser could say `d:/../NAME'.
6493 We silently treat this as `d:/NAME'. */
6494 else if (cp[0] != '/')
6495 cp = slashp;
6496 #endif
6497 strcpy (cp, slashp + 3);
6498 slashp = cp;
6499 continue;
6501 else if (slashp[2] == '/' || slashp[2] == '\0')
6503 strcpy (slashp, slashp + 2);
6504 continue;
6508 slashp = etags_strchr (slashp + 1, '/');
6511 if (res[0] == '\0')
6512 return savestr ("/");
6513 else
6514 return res;
6517 /* Return a newly allocated string containing the absolute
6518 file name of dir where FILE resides given DIR (which should
6519 end with a slash). */
6520 static char *
6521 absolute_dirname (file, dir)
6522 char *file, *dir;
6524 char *slashp, *res;
6525 char save;
6527 canonicalize_filename (file);
6528 slashp = etags_strrchr (file, '/');
6529 if (slashp == NULL)
6530 return savestr (dir);
6531 save = slashp[1];
6532 slashp[1] = '\0';
6533 res = absolute_filename (file, dir);
6534 slashp[1] = save;
6536 return res;
6539 /* Whether the argument string is an absolute file name. The argument
6540 string must have been canonicalized with canonicalize_filename. */
6541 static bool
6542 filename_is_absolute (fn)
6543 char *fn;
6545 return (fn[0] == '/'
6546 #ifdef DOS_NT
6547 || (ISALPHA(fn[0]) && fn[1] == ':' && fn[2] == '/')
6548 #endif
6552 /* Translate backslashes into slashes. Works in place. */
6553 static void
6554 canonicalize_filename (fn)
6555 register char *fn;
6557 #ifdef DOS_NT
6558 /* Canonicalize drive letter case. */
6559 if (fn[0] != '\0' && fn[1] == ':' && ISLOWER (fn[0]))
6560 fn[0] = upcase (fn[0]);
6561 /* Convert backslashes to slashes. */
6562 for (; *fn != '\0'; fn++)
6563 if (*fn == '\\')
6564 *fn = '/';
6565 #else
6566 /* No action. */
6567 fn = NULL; /* shut up the compiler */
6568 #endif
6572 /* Initialize a linebuffer for use */
6573 static void
6574 linebuffer_init (lbp)
6575 linebuffer *lbp;
6577 lbp->size = (DEBUG) ? 3 : 200;
6578 lbp->buffer = xnew (lbp->size, char);
6579 lbp->buffer[0] = '\0';
6580 lbp->len = 0;
6583 /* Set the minimum size of a string contained in a linebuffer. */
6584 static void
6585 linebuffer_setlen (lbp, toksize)
6586 linebuffer *lbp;
6587 int toksize;
6589 while (lbp->size <= toksize)
6591 lbp->size *= 2;
6592 xrnew (lbp->buffer, lbp->size, char);
6594 lbp->len = toksize;
6597 /* Like malloc but get fatal error if memory is exhausted. */
6598 static PTR
6599 xmalloc (size)
6600 unsigned int size;
6602 PTR result = (PTR) malloc (size);
6603 if (result == NULL)
6604 fatal ("virtual memory exhausted", (char *)NULL);
6605 return result;
6608 static PTR
6609 xrealloc (ptr, size)
6610 char *ptr;
6611 unsigned int size;
6613 PTR result = (PTR) realloc (ptr, size);
6614 if (result == NULL)
6615 fatal ("virtual memory exhausted", (char *)NULL);
6616 return result;
6620 * Local Variables:
6621 * c-indentation-style: gnu
6622 * indent-tabs-mode: t
6623 * tab-width: 8
6624 * fill-column: 79
6625 * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
6626 * End: