(insert-directory): Insert free space only when listing a full directory.
[emacs.git] / lib-src / etags.c
blobc0518af603453041cc627881e3f69655752ab58d
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 $Revision: 16.55 $";
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 assert (name == NULL || name[0] != '\0');
1875 if (CTAGS && name == NULL)
1876 return;
1878 np = xnew (1, node);
1880 /* If ctags mode, change name "main" to M<thisfilename>. */
1881 if (CTAGS && !cxref_style && streq (name, "main"))
1883 register char *fp = etags_strrchr (curfdp->taggedfname, '/');
1884 np->name = concat ("M", fp == NULL ? curfdp->taggedfname : fp + 1, "");
1885 fp = etags_strrchr (np->name, '.');
1886 if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
1887 fp[0] = '\0';
1889 else
1890 np->name = name;
1891 np->valid = TRUE;
1892 np->been_warned = FALSE;
1893 np->fdp = curfdp;
1894 np->is_func = is_func;
1895 np->lno = lno;
1896 if (np->fdp->usecharno)
1897 /* Our char numbers are 0-base, because of C language tradition?
1898 ctags compatibility? old versions compatibility? I don't know.
1899 Anyway, since emacs's are 1-base we expect etags.el to take care
1900 of the difference. If we wanted to have 1-based numbers, we would
1901 uncomment the +1 below. */
1902 np->cno = cno /* + 1 */ ;
1903 else
1904 np->cno = invalidcharno;
1905 np->left = np->right = NULL;
1906 if (CTAGS && !cxref_style)
1908 if (strlen (linestart) < 50)
1909 np->regex = concat (linestart, "$", "");
1910 else
1911 np->regex = savenstr (linestart, 50);
1913 else
1914 np->regex = savenstr (linestart, linelen);
1916 add_node (np, &nodehead);
1920 * free_tree ()
1921 * recurse on left children, iterate on right children.
1923 static void
1924 free_tree (np)
1925 register node *np;
1927 while (np)
1929 register node *node_right = np->right;
1930 free_tree (np->left);
1931 if (np->name != NULL)
1932 free (np->name);
1933 free (np->regex);
1934 free (np);
1935 np = node_right;
1940 * free_fdesc ()
1941 * delete a file description
1943 static void
1944 free_fdesc (fdp)
1945 register fdesc *fdp;
1947 if (fdp->infname != NULL) free (fdp->infname);
1948 if (fdp->infabsname != NULL) free (fdp->infabsname);
1949 if (fdp->infabsdir != NULL) free (fdp->infabsdir);
1950 if (fdp->taggedfname != NULL) free (fdp->taggedfname);
1951 if (fdp->prop != NULL) free (fdp->prop);
1952 free (fdp);
1956 * add_node ()
1957 * Adds a node to the tree of nodes. In etags mode, sort by file
1958 * name. In ctags mode, sort by tag name. Make no attempt at
1959 * balancing.
1961 * add_node is the only function allowed to add nodes, so it can
1962 * maintain state.
1964 static void
1965 add_node (np, cur_node_p)
1966 node *np, **cur_node_p;
1968 register int dif;
1969 register node *cur_node = *cur_node_p;
1971 if (cur_node == NULL)
1973 *cur_node_p = np;
1974 last_node = np;
1975 return;
1978 if (!CTAGS)
1979 /* Etags Mode */
1981 /* For each file name, tags are in a linked sublist on the right
1982 pointer. The first tags of different files are a linked list
1983 on the left pointer. last_node points to the end of the last
1984 used sublist. */
1985 if (last_node != NULL && last_node->fdp == np->fdp)
1987 /* Let's use the same sublist as the last added node. */
1988 assert (last_node->right == NULL);
1989 last_node->right = np;
1990 last_node = np;
1992 else if (cur_node->fdp == np->fdp)
1994 /* Scanning the list we found the head of a sublist which is
1995 good for us. Let's scan this sublist. */
1996 add_node (np, &cur_node->right);
1998 else
1999 /* The head of this sublist is not good for us. Let's try the
2000 next one. */
2001 add_node (np, &cur_node->left);
2002 } /* if ETAGS mode */
2004 else
2006 /* Ctags Mode */
2007 dif = strcmp (np->name, cur_node->name);
2010 * If this tag name matches an existing one, then
2011 * do not add the node, but maybe print a warning.
2013 if (!dif)
2015 if (np->fdp == cur_node->fdp)
2017 if (!no_warnings)
2019 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
2020 np->fdp->infname, lineno, np->name);
2021 fprintf (stderr, "Second entry ignored\n");
2024 else if (!cur_node->been_warned && !no_warnings)
2026 fprintf
2027 (stderr,
2028 "Duplicate entry in files %s and %s: %s (Warning only)\n",
2029 np->fdp->infname, cur_node->fdp->infname, np->name);
2030 cur_node->been_warned = TRUE;
2032 return;
2035 /* Actually add the node */
2036 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
2037 } /* if CTAGS mode */
2041 * invalidate_nodes ()
2042 * Scan the node tree and invalidate all nodes pointing to the
2043 * given file description (CTAGS case) or free them (ETAGS case).
2045 static void
2046 invalidate_nodes (badfdp, npp)
2047 fdesc *badfdp;
2048 node **npp;
2050 node *np = *npp;
2052 if (np == NULL)
2053 return;
2055 if (CTAGS)
2057 if (np->left != NULL)
2058 invalidate_nodes (badfdp, &np->left);
2059 if (np->fdp == badfdp)
2060 np->valid = FALSE;
2061 if (np->right != NULL)
2062 invalidate_nodes (badfdp, &np->right);
2064 else
2066 assert (np->fdp != NULL);
2067 if (np->fdp == badfdp)
2069 *npp = np->left; /* detach the sublist from the list */
2070 np->left = NULL; /* isolate it */
2071 free_tree (np); /* free it */
2072 invalidate_nodes (badfdp, npp);
2074 else
2075 invalidate_nodes (badfdp, &np->left);
2080 static int total_size_of_entries __P((node *));
2081 static int number_len __P((long));
2083 /* Length of a non-negative number's decimal representation. */
2084 static int
2085 number_len (num)
2086 long num;
2088 int len = 1;
2089 while ((num /= 10) > 0)
2090 len += 1;
2091 return len;
2095 * Return total number of characters that put_entries will output for
2096 * the nodes in the linked list at the right of the specified node.
2097 * This count is irrelevant with etags.el since emacs 19.34 at least,
2098 * but is still supplied for backward compatibility.
2100 static int
2101 total_size_of_entries (np)
2102 register node *np;
2104 register int total = 0;
2106 for (; np != NULL; np = np->right)
2107 if (np->valid)
2109 total += strlen (np->regex) + 1; /* pat\177 */
2110 if (np->name != NULL)
2111 total += strlen (np->name) + 1; /* name\001 */
2112 total += number_len ((long) np->lno) + 1; /* lno, */
2113 if (np->cno != invalidcharno) /* cno */
2114 total += number_len (np->cno);
2115 total += 1; /* newline */
2118 return total;
2121 static void
2122 put_entries (np)
2123 register node *np;
2125 register char *sp;
2126 static fdesc *fdp = NULL;
2128 if (np == NULL)
2129 return;
2131 /* Output subentries that precede this one */
2132 if (CTAGS)
2133 put_entries (np->left);
2135 /* Output this entry */
2136 if (np->valid)
2138 if (!CTAGS)
2140 /* Etags mode */
2141 if (fdp != np->fdp)
2143 fdp = np->fdp;
2144 fprintf (tagf, "\f\n%s,%d\n",
2145 fdp->taggedfname, total_size_of_entries (np));
2146 fdp->written = TRUE;
2148 fputs (np->regex, tagf);
2149 fputc ('\177', tagf);
2150 if (np->name != NULL)
2152 fputs (np->name, tagf);
2153 fputc ('\001', tagf);
2155 fprintf (tagf, "%d,", np->lno);
2156 if (np->cno != invalidcharno)
2157 fprintf (tagf, "%ld", np->cno);
2158 fputs ("\n", tagf);
2160 else
2162 /* Ctags mode */
2163 if (np->name == NULL)
2164 error ("internal error: NULL name in ctags mode.", (char *)NULL);
2166 if (cxref_style)
2168 if (vgrind_style)
2169 fprintf (stdout, "%s %s %d\n",
2170 np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
2171 else
2172 fprintf (stdout, "%-16s %3d %-16s %s\n",
2173 np->name, np->lno, np->fdp->taggedfname, np->regex);
2175 else
2177 fprintf (tagf, "%s\t%s\t", np->name, np->fdp->taggedfname);
2179 if (np->is_func)
2180 { /* function or #define macro with args */
2181 putc (searchar, tagf);
2182 putc ('^', tagf);
2184 for (sp = np->regex; *sp; sp++)
2186 if (*sp == '\\' || *sp == searchar)
2187 putc ('\\', tagf);
2188 putc (*sp, tagf);
2190 putc (searchar, tagf);
2192 else
2193 { /* anything else; text pattern inadequate */
2194 fprintf (tagf, "%d", np->lno);
2196 putc ('\n', tagf);
2199 } /* if this node contains a valid tag */
2201 /* Output subentries that follow this one */
2202 put_entries (np->right);
2203 if (!CTAGS)
2204 put_entries (np->left);
2208 /* C extensions. */
2209 #define C_EXT 0x00fff /* C extensions */
2210 #define C_PLAIN 0x00000 /* C */
2211 #define C_PLPL 0x00001 /* C++ */
2212 #define C_STAR 0x00003 /* C* */
2213 #define C_JAVA 0x00005 /* JAVA */
2214 #define C_AUTO 0x01000 /* C, but switch to C++ if `class' is met */
2215 #define YACC 0x10000 /* yacc file */
2218 * The C symbol tables.
2220 enum sym_type
2222 st_none,
2223 st_C_objprot, st_C_objimpl, st_C_objend,
2224 st_C_gnumacro,
2225 st_C_ignore,
2226 st_C_javastruct,
2227 st_C_operator,
2228 st_C_class, st_C_template,
2229 st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
2232 static unsigned int hash __P((const char *, unsigned int));
2233 static struct C_stab_entry * in_word_set __P((const char *, unsigned int));
2234 static enum sym_type C_symtype __P((char *, int, int));
2236 /* Feed stuff between (but not including) %[ and %] lines to:
2237 gperf -c -k 1,3 -o -p -r -t
2239 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
2241 if, 0, st_C_ignore
2242 for, 0, st_C_ignore
2243 while, 0, st_C_ignore
2244 switch, 0, st_C_ignore
2245 return, 0, st_C_ignore
2246 @interface, 0, st_C_objprot
2247 @protocol, 0, st_C_objprot
2248 @implementation,0, st_C_objimpl
2249 @end, 0, st_C_objend
2250 import, C_JAVA, st_C_ignore
2251 package, C_JAVA, st_C_ignore
2252 friend, C_PLPL, st_C_ignore
2253 extends, C_JAVA, st_C_javastruct
2254 implements, C_JAVA, st_C_javastruct
2255 interface, C_JAVA, st_C_struct
2256 class, 0, st_C_class
2257 namespace, C_PLPL, st_C_struct
2258 domain, C_STAR, st_C_struct
2259 union, 0, st_C_struct
2260 struct, 0, st_C_struct
2261 extern, 0, st_C_extern
2262 enum, 0, st_C_enum
2263 typedef, 0, st_C_typedef
2264 define, 0, st_C_define
2265 operator, C_PLPL, st_C_operator
2266 template, 0, st_C_template
2267 bool, C_PLPL, st_C_typespec
2268 long, 0, st_C_typespec
2269 short, 0, st_C_typespec
2270 int, 0, st_C_typespec
2271 char, 0, st_C_typespec
2272 float, 0, st_C_typespec
2273 double, 0, st_C_typespec
2274 signed, 0, st_C_typespec
2275 unsigned, 0, st_C_typespec
2276 auto, 0, st_C_typespec
2277 void, 0, st_C_typespec
2278 static, 0, st_C_typespec
2279 const, 0, st_C_typespec
2280 volatile, 0, st_C_typespec
2281 explicit, C_PLPL, st_C_typespec
2282 mutable, C_PLPL, st_C_typespec
2283 typename, C_PLPL, st_C_typespec
2284 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
2285 DEFUN, 0, st_C_gnumacro
2286 SYSCALL, 0, st_C_gnumacro
2287 ENTRY, 0, st_C_gnumacro
2288 PSEUDO, 0, st_C_gnumacro
2289 # These are defined inside C functions, so currently they are not met.
2290 # EXFUN used in glibc, DEFVAR_* in emacs.
2291 #EXFUN, 0, st_C_gnumacro
2292 #DEFVAR_, 0, st_C_gnumacro
2294 and replace lines between %< and %> with its output,
2295 then make in_word_set and C_stab_entry static. */
2296 /*%<*/
2297 /* C code produced by gperf version 2.7.1 (19981006 egcs) */
2298 /* Command-line: gperf -c -k 1,3 -o -p -r -t */
2299 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
2301 #define TOTAL_KEYWORDS 47
2302 #define MIN_WORD_LENGTH 2
2303 #define MAX_WORD_LENGTH 15
2304 #define MIN_HASH_VALUE 18
2305 #define MAX_HASH_VALUE 138
2306 /* maximum key range = 121, duplicates = 0 */
2308 #ifdef __GNUC__
2309 __inline
2310 #endif
2311 static unsigned int
2312 hash (str, len)
2313 register const char *str;
2314 register unsigned int len;
2316 static unsigned char asso_values[] =
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, 139, 139, 139, 139, 139, 139,
2324 139, 139, 139, 139, 63, 139, 139, 139, 33, 44,
2325 62, 139, 139, 139, 139, 139, 139, 139, 139, 139,
2326 42, 139, 139, 12, 32, 139, 139, 139, 139, 139,
2327 139, 139, 139, 139, 139, 139, 139, 34, 59, 37,
2328 24, 58, 33, 3, 139, 16, 139, 139, 42, 60,
2329 18, 11, 39, 139, 23, 57, 4, 63, 6, 20,
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, 139, 139, 139, 139,
2343 139, 139, 139, 139, 139, 139
2345 register int hval = len;
2347 switch (hval)
2349 default:
2350 case 3:
2351 hval += asso_values[(unsigned char)str[2]];
2352 case 2:
2353 case 1:
2354 hval += asso_values[(unsigned char)str[0]];
2355 break;
2357 return hval;
2360 #ifdef __GNUC__
2361 __inline
2362 #endif
2363 static struct C_stab_entry *
2364 in_word_set (str, len)
2365 register const char *str;
2366 register unsigned int len;
2368 static struct C_stab_entry wordlist[] =
2370 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2371 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2372 {"if", 0, st_C_ignore},
2373 {""}, {""}, {""}, {""},
2374 {"int", 0, st_C_typespec},
2375 {""}, {""},
2376 {"void", 0, st_C_typespec},
2377 {""}, {""},
2378 {"interface", C_JAVA, st_C_struct},
2379 {""},
2380 {"SYSCALL", 0, st_C_gnumacro},
2381 {""},
2382 {"return", 0, st_C_ignore},
2383 {""}, {""}, {""}, {""}, {""}, {""}, {""},
2384 {"while", 0, st_C_ignore},
2385 {"auto", 0, st_C_typespec},
2386 {""}, {""}, {""}, {""}, {""}, {""},
2387 {"float", 0, st_C_typespec},
2388 {"typedef", 0, st_C_typedef},
2389 {"typename", C_PLPL, st_C_typespec},
2390 {""}, {""}, {""},
2391 {"friend", C_PLPL, st_C_ignore},
2392 {"volatile", 0, st_C_typespec},
2393 {""}, {""},
2394 {"for", 0, st_C_ignore},
2395 {"const", 0, st_C_typespec},
2396 {"import", C_JAVA, st_C_ignore},
2397 {""},
2398 {"define", 0, st_C_define},
2399 {"long", 0, st_C_typespec},
2400 {"implements", C_JAVA, st_C_javastruct},
2401 {"signed", 0, st_C_typespec},
2402 {""},
2403 {"extern", 0, st_C_extern},
2404 {"extends", C_JAVA, st_C_javastruct},
2405 {""},
2406 {"mutable", C_PLPL, st_C_typespec},
2407 {"template", 0, st_C_template},
2408 {"short", 0, st_C_typespec},
2409 {"bool", C_PLPL, st_C_typespec},
2410 {"char", 0, st_C_typespec},
2411 {"class", 0, st_C_class},
2412 {"operator", C_PLPL, st_C_operator},
2413 {""},
2414 {"switch", 0, st_C_ignore},
2415 {""},
2416 {"ENTRY", 0, st_C_gnumacro},
2417 {""},
2418 {"package", C_JAVA, st_C_ignore},
2419 {"union", 0, st_C_struct},
2420 {"@end", 0, st_C_objend},
2421 {"struct", 0, st_C_struct},
2422 {"namespace", C_PLPL, st_C_struct},
2423 {""}, {""},
2424 {"domain", C_STAR, st_C_struct},
2425 {"@interface", 0, st_C_objprot},
2426 {"PSEUDO", 0, st_C_gnumacro},
2427 {"double", 0, st_C_typespec},
2428 {""},
2429 {"@protocol", 0, st_C_objprot},
2430 {""},
2431 {"static", 0, st_C_typespec},
2432 {""}, {""},
2433 {"DEFUN", 0, st_C_gnumacro},
2434 {""}, {""}, {""}, {""},
2435 {"explicit", C_PLPL, st_C_typespec},
2436 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2437 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2438 {""},
2439 {"enum", 0, st_C_enum},
2440 {""}, {""},
2441 {"unsigned", 0, st_C_typespec},
2442 {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
2443 {"@implementation",0, st_C_objimpl}
2446 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
2448 register int key = hash (str, len);
2450 if (key <= MAX_HASH_VALUE && key >= 0)
2452 register const char *s = wordlist[key].name;
2454 if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
2455 return &wordlist[key];
2458 return 0;
2460 /*%>*/
2462 static enum sym_type
2463 C_symtype (str, len, c_ext)
2464 char *str;
2465 int len;
2466 int c_ext;
2468 register struct C_stab_entry *se = in_word_set (str, len);
2470 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2471 return st_none;
2472 return se->type;
2477 * C functions and variables are recognized using a simple
2478 * finite automaton. fvdef is its state variable.
2480 static enum
2482 fvnone, /* nothing seen */
2483 fdefunkey, /* Emacs DEFUN keyword seen */
2484 fdefunname, /* Emacs DEFUN name seen */
2485 foperator, /* func: operator keyword seen (cplpl) */
2486 fvnameseen, /* function or variable name seen */
2487 fstartlist, /* func: just after open parenthesis */
2488 finlist, /* func: in parameter list */
2489 flistseen, /* func: after parameter list */
2490 fignore, /* func: before open brace */
2491 vignore /* var-like: ignore until ';' */
2492 } fvdef;
2494 static bool fvextern; /* func or var: extern keyword seen; */
2497 * typedefs are recognized using a simple finite automaton.
2498 * typdef is its state variable.
2500 static enum
2502 tnone, /* nothing seen */
2503 tkeyseen, /* typedef keyword seen */
2504 ttypeseen, /* defined type seen */
2505 tinbody, /* inside typedef body */
2506 tend, /* just before typedef tag */
2507 tignore /* junk after typedef tag */
2508 } typdef;
2511 * struct-like structures (enum, struct and union) are recognized
2512 * using another simple finite automaton. `structdef' is its state
2513 * variable.
2515 static enum
2517 snone, /* nothing seen yet,
2518 or in struct body if cblev > 0 */
2519 skeyseen, /* struct-like keyword seen */
2520 stagseen, /* struct-like tag seen */
2521 sintemplate, /* inside template (ignore) */
2522 scolonseen /* colon seen after struct-like tag */
2523 } structdef;
2526 * When objdef is different from onone, objtag is the name of the class.
2528 static char *objtag = "<uninited>";
2531 * Yet another little state machine to deal with preprocessor lines.
2533 static enum
2535 dnone, /* nothing seen */
2536 dsharpseen, /* '#' seen as first char on line */
2537 ddefineseen, /* '#' and 'define' seen */
2538 dignorerest /* ignore rest of line */
2539 } definedef;
2542 * State machine for Objective C protocols and implementations.
2543 * Idea by Tom R.Hageman <tom@basil.icce.rug.nl> (1995)
2545 static enum
2547 onone, /* nothing seen */
2548 oprotocol, /* @interface or @protocol seen */
2549 oimplementation, /* @implementations seen */
2550 otagseen, /* class name seen */
2551 oparenseen, /* parenthesis before category seen */
2552 ocatseen, /* category name seen */
2553 oinbody, /* in @implementation body */
2554 omethodsign, /* in @implementation body, after +/- */
2555 omethodtag, /* after method name */
2556 omethodcolon, /* after method colon */
2557 omethodparm, /* after method parameter */
2558 oignore /* wait for @end */
2559 } objdef;
2563 * Use this structure to keep info about the token read, and how it
2564 * should be tagged. Used by the make_C_tag function to build a tag.
2566 static struct tok
2568 char *line; /* string containing the token */
2569 int offset; /* where the token starts in LINE */
2570 int length; /* token length */
2572 The previous members can be used to pass strings around for generic
2573 purposes. The following ones specifically refer to creating tags. In this
2574 case the token contained here is the pattern that will be used to create a
2575 tag.
2577 bool valid; /* do not create a tag; the token should be
2578 invalidated whenever a state machine is
2579 reset prematurely */
2580 bool named; /* create a named tag */
2581 int lineno; /* source line number of tag */
2582 long linepos; /* source char number of tag */
2583 } token; /* latest token read */
2586 * Variables and functions for dealing with nested structures.
2587 * Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001)
2589 static void pushclass_above __P((int, char *, int));
2590 static void popclass_above __P((int));
2591 static void write_classname __P((linebuffer *, char *qualifier));
2593 static struct {
2594 char **cname; /* nested class names */
2595 int *cblev; /* nested class curly brace level */
2596 int nl; /* class nesting level (elements used) */
2597 int size; /* length of the array */
2598 } cstack; /* stack for nested declaration tags */
2599 /* Current struct nesting depth (namespace, class, struct, union, enum). */
2600 #define nestlev (cstack.nl)
2601 /* After struct keyword or in struct body, not inside a nested function. */
2602 #define instruct (structdef == snone && nestlev > 0 \
2603 && cblev == cstack.cblev[nestlev-1] + 1)
2605 static void
2606 pushclass_above (cblev, str, len)
2607 int cblev;
2608 char *str;
2609 int len;
2611 int nl;
2613 popclass_above (cblev);
2614 nl = cstack.nl;
2615 if (nl >= cstack.size)
2617 int size = cstack.size *= 2;
2618 xrnew (cstack.cname, size, char *);
2619 xrnew (cstack.cblev, size, int);
2621 assert (nl == 0 || cstack.cblev[nl-1] < cblev);
2622 cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
2623 cstack.cblev[nl] = cblev;
2624 cstack.nl = nl + 1;
2627 static void
2628 popclass_above (cblev)
2629 int cblev;
2631 int nl;
2633 for (nl = cstack.nl - 1;
2634 nl >= 0 && cstack.cblev[nl] >= cblev;
2635 nl--)
2637 if (cstack.cname[nl] != NULL)
2638 free (cstack.cname[nl]);
2639 cstack.nl = nl;
2643 static void
2644 write_classname (cn, qualifier)
2645 linebuffer *cn;
2646 char *qualifier;
2648 int i, len;
2649 int qlen = strlen (qualifier);
2651 if (cstack.nl == 0 || cstack.cname[0] == NULL)
2653 len = 0;
2654 cn->len = 0;
2655 cn->buffer[0] = '\0';
2657 else
2659 len = strlen (cstack.cname[0]);
2660 linebuffer_setlen (cn, len);
2661 strcpy (cn->buffer, cstack.cname[0]);
2663 for (i = 1; i < cstack.nl; i++)
2665 char *s;
2666 int slen;
2668 s = cstack.cname[i];
2669 if (s == NULL)
2670 continue;
2671 slen = strlen (s);
2672 len += slen + qlen;
2673 linebuffer_setlen (cn, len);
2674 strncat (cn->buffer, qualifier, qlen);
2675 strncat (cn->buffer, s, slen);
2680 static bool consider_token __P((char *, int, int, int *, int, int, bool *));
2681 static void make_C_tag __P((bool));
2684 * consider_token ()
2685 * checks to see if the current token is at the start of a
2686 * function or variable, or corresponds to a typedef, or
2687 * is a struct/union/enum tag, or #define, or an enum constant.
2689 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2690 * with args. C_EXTP points to which language we are looking at.
2692 * Globals
2693 * fvdef IN OUT
2694 * structdef IN OUT
2695 * definedef IN OUT
2696 * typdef IN OUT
2697 * objdef IN OUT
2700 static bool
2701 consider_token (str, len, c, c_extp, cblev, parlev, is_func_or_var)
2702 register char *str; /* IN: token pointer */
2703 register int len; /* IN: token length */
2704 register int c; /* IN: first char after the token */
2705 int *c_extp; /* IN, OUT: C extensions mask */
2706 int cblev; /* IN: curly brace level */
2707 int parlev; /* IN: parenthesis level */
2708 bool *is_func_or_var; /* OUT: function or variable found */
2710 /* When structdef is stagseen, scolonseen, or snone with cblev > 0,
2711 structtype is the type of the preceding struct-like keyword, and
2712 structcblev is the curly brace level where it has been seen. */
2713 static enum sym_type structtype;
2714 static int structcblev;
2715 static enum sym_type toktype;
2718 toktype = C_symtype (str, len, *c_extp);
2721 * Advance the definedef state machine.
2723 switch (definedef)
2725 case dnone:
2726 /* We're not on a preprocessor line. */
2727 if (toktype == st_C_gnumacro)
2729 fvdef = fdefunkey;
2730 return FALSE;
2732 break;
2733 case dsharpseen:
2734 if (toktype == st_C_define)
2736 definedef = ddefineseen;
2738 else
2740 definedef = dignorerest;
2742 return FALSE;
2743 case ddefineseen:
2745 * Make a tag for any macro, unless it is a constant
2746 * and constantypedefs is FALSE.
2748 definedef = dignorerest;
2749 *is_func_or_var = (c == '(');
2750 if (!*is_func_or_var && !constantypedefs)
2751 return FALSE;
2752 else
2753 return TRUE;
2754 case dignorerest:
2755 return FALSE;
2756 default:
2757 error ("internal error: definedef value.", (char *)NULL);
2761 * Now typedefs
2763 switch (typdef)
2765 case tnone:
2766 if (toktype == st_C_typedef)
2768 if (typedefs)
2769 typdef = tkeyseen;
2770 fvextern = FALSE;
2771 fvdef = fvnone;
2772 return FALSE;
2774 break;
2775 case tkeyseen:
2776 switch (toktype)
2778 case st_none:
2779 case st_C_typespec:
2780 case st_C_class:
2781 case st_C_struct:
2782 case st_C_enum:
2783 typdef = ttypeseen;
2784 break;
2786 break;
2787 case ttypeseen:
2788 if (structdef == snone && fvdef == fvnone)
2790 fvdef = fvnameseen;
2791 return TRUE;
2793 break;
2794 case tend:
2795 switch (toktype)
2797 case st_C_typespec:
2798 case st_C_class:
2799 case st_C_struct:
2800 case st_C_enum:
2801 return FALSE;
2803 return TRUE;
2807 * This structdef business is NOT invoked when we are ctags and the
2808 * file is plain C. This is because a struct tag may have the same
2809 * name as another tag, and this loses with ctags.
2811 switch (toktype)
2813 case st_C_javastruct:
2814 if (structdef == stagseen)
2815 structdef = scolonseen;
2816 return FALSE;
2817 case st_C_template:
2818 case st_C_class:
2819 if ((*c_extp & C_AUTO) /* automatic detection of C++ language */
2820 && cblev == 0
2821 && definedef == dnone && structdef == snone
2822 && typdef == tnone && fvdef == fvnone)
2823 *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
2824 if (toktype == st_C_template)
2825 break;
2826 /* FALLTHRU */
2827 case st_C_struct:
2828 case st_C_enum:
2829 if (parlev == 0
2830 && fvdef != vignore
2831 && (typdef == tkeyseen
2832 || (typedefs_or_cplusplus && structdef == snone)))
2834 structdef = skeyseen;
2835 structtype = toktype;
2836 structcblev = cblev;
2838 return FALSE;
2841 if (structdef == skeyseen)
2843 structdef = stagseen;
2844 return TRUE;
2847 if (typdef != tnone)
2848 definedef = dnone;
2850 /* Detect Objective C constructs. */
2851 switch (objdef)
2853 case onone:
2854 switch (toktype)
2856 case st_C_objprot:
2857 objdef = oprotocol;
2858 return FALSE;
2859 case st_C_objimpl:
2860 objdef = oimplementation;
2861 return FALSE;
2863 break;
2864 case oimplementation:
2865 /* Save the class tag for functions or variables defined inside. */
2866 objtag = savenstr (str, len);
2867 objdef = oinbody;
2868 return FALSE;
2869 case oprotocol:
2870 /* Save the class tag for categories. */
2871 objtag = savenstr (str, len);
2872 objdef = otagseen;
2873 *is_func_or_var = TRUE;
2874 return TRUE;
2875 case oparenseen:
2876 objdef = ocatseen;
2877 *is_func_or_var = TRUE;
2878 return TRUE;
2879 case oinbody:
2880 break;
2881 case omethodsign:
2882 if (parlev == 0)
2884 objdef = omethodtag;
2885 linebuffer_setlen (&token_name, len);
2886 strncpy (token_name.buffer, str, len);
2887 token_name.buffer[len] = '\0';
2888 return TRUE;
2890 return FALSE;
2891 case omethodcolon:
2892 if (parlev == 0)
2893 objdef = omethodparm;
2894 return FALSE;
2895 case omethodparm:
2896 if (parlev == 0)
2898 objdef = omethodtag;
2899 linebuffer_setlen (&token_name, token_name.len + len);
2900 strncat (token_name.buffer, str, len);
2901 return TRUE;
2903 return FALSE;
2904 case oignore:
2905 if (toktype == st_C_objend)
2907 /* Memory leakage here: the string pointed by objtag is
2908 never released, because many tests would be needed to
2909 avoid breaking on incorrect input code. The amount of
2910 memory leaked here is the sum of the lengths of the
2911 class tags.
2912 free (objtag); */
2913 objdef = onone;
2915 return FALSE;
2918 /* A function, variable or enum constant? */
2919 switch (toktype)
2921 case st_C_extern:
2922 fvextern = TRUE;
2923 /* FALLTHRU */
2924 case st_C_typespec:
2925 switch (fvdef)
2927 case finlist:
2928 case flistseen:
2929 case fignore:
2930 case vignore:
2931 break;
2932 default:
2933 fvdef = fvnone;
2935 return FALSE;
2936 case st_C_ignore:
2937 fvextern = FALSE;
2938 fvdef = vignore;
2939 return FALSE;
2940 case st_C_operator:
2941 fvdef = foperator;
2942 *is_func_or_var = TRUE;
2943 return TRUE;
2944 case st_none:
2945 if (constantypedefs
2946 && structdef == snone
2947 && structtype == st_C_enum && cblev > structcblev)
2948 return TRUE; /* enum constant */
2949 switch (fvdef)
2951 case fdefunkey:
2952 if (cblev > 0)
2953 break;
2954 fvdef = fdefunname; /* GNU macro */
2955 *is_func_or_var = TRUE;
2956 return TRUE;
2957 case fvnone:
2958 if ((strneq (str, "asm", 3) && endtoken (str[3]))
2959 || (strneq (str, "__asm__", 7) && endtoken (str[7])))
2961 fvdef = vignore;
2962 return FALSE;
2964 if (strneq (str+len-10, "::operator", 10))
2966 if (*c_extp & C_AUTO) /* automatic detection of C++ */
2967 *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
2968 fvdef = foperator;
2969 *is_func_or_var = TRUE;
2970 return TRUE;
2972 if (cblev > 0 && !instruct)
2973 break;
2974 fvdef = fvnameseen; /* function or variable */
2975 *is_func_or_var = TRUE;
2976 return TRUE;
2978 break;
2981 return FALSE;
2986 * C_entries often keeps pointers to tokens or lines which are older than
2987 * the line currently read. By keeping two line buffers, and switching
2988 * them at end of line, it is possible to use those pointers.
2990 static struct
2992 long linepos;
2993 linebuffer lb;
2994 } lbs[2];
2996 #define current_lb_is_new (newndx == curndx)
2997 #define switch_line_buffers() (curndx = 1 - curndx)
2999 #define curlb (lbs[curndx].lb)
3000 #define newlb (lbs[newndx].lb)
3001 #define curlinepos (lbs[curndx].linepos)
3002 #define newlinepos (lbs[newndx].linepos)
3004 #define plainc ((c_ext & C_EXT) == C_PLAIN)
3005 #define cplpl (c_ext & C_PLPL)
3006 #define cjava ((c_ext & C_JAVA) == C_JAVA)
3008 #define CNL_SAVE_DEFINEDEF() \
3009 do { \
3010 curlinepos = charno; \
3011 readline (&curlb, inf); \
3012 lp = curlb.buffer; \
3013 quotednl = FALSE; \
3014 newndx = curndx; \
3015 } while (0)
3017 #define CNL() \
3018 do { \
3019 CNL_SAVE_DEFINEDEF(); \
3020 if (savetoken.valid) \
3022 token = savetoken; \
3023 savetoken.valid = FALSE; \
3025 definedef = dnone; \
3026 } while (0)
3029 static void
3030 make_C_tag (isfun)
3031 bool isfun;
3033 /* This function should never be called when token.valid is FALSE, but
3034 we must protect against invalid input or internal errors. */
3035 if (!DEBUG && !token.valid)
3036 return;
3038 if (token.valid)
3039 make_tag (token_name.buffer, token_name.len, isfun, token.line,
3040 token.offset+token.length+1, token.lineno, token.linepos);
3041 else /* this case is optimised away if !DEBUG */
3042 make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
3043 token_name.len + 17, isfun, token.line,
3044 token.offset+token.length+1, token.lineno, token.linepos);
3046 token.valid = FALSE;
3051 * C_entries ()
3052 * This routine finds functions, variables, typedefs,
3053 * #define's, enum constants and struct/union/enum definitions in
3054 * C syntax and adds them to the list.
3056 static void
3057 C_entries (c_ext, inf)
3058 int c_ext; /* extension of C */
3059 FILE *inf; /* input file */
3061 register char c; /* latest char read; '\0' for end of line */
3062 register char *lp; /* pointer one beyond the character `c' */
3063 int curndx, newndx; /* indices for current and new lb */
3064 register int tokoff; /* offset in line of start of current token */
3065 register int toklen; /* length of current token */
3066 char *qualifier; /* string used to qualify names */
3067 int qlen; /* length of qualifier */
3068 int cblev; /* current curly brace level */
3069 int parlev; /* current parenthesis level */
3070 int typdefcblev; /* cblev where a typedef struct body begun */
3071 bool incomm, inquote, inchar, quotednl, midtoken;
3072 bool yacc_rules; /* in the rules part of a yacc file */
3073 struct tok savetoken; /* token saved during preprocessor handling */
3076 linebuffer_init (&lbs[0].lb);
3077 linebuffer_init (&lbs[1].lb);
3078 if (cstack.size == 0)
3080 cstack.size = (DEBUG) ? 1 : 4;
3081 cstack.nl = 0;
3082 cstack.cname = xnew (cstack.size, char *);
3083 cstack.cblev = xnew (cstack.size, int);
3086 tokoff = toklen = typdefcblev = 0; /* keep compiler quiet */
3087 curndx = newndx = 0;
3088 lp = curlb.buffer;
3089 *lp = 0;
3091 fvdef = fvnone; fvextern = FALSE; typdef = tnone;
3092 structdef = snone; definedef = dnone; objdef = onone;
3093 yacc_rules = FALSE;
3094 midtoken = inquote = inchar = incomm = quotednl = FALSE;
3095 token.valid = savetoken.valid = FALSE;
3096 cblev = 0;
3097 parlev = 0;
3098 if (cjava)
3099 { qualifier = "."; qlen = 1; }
3100 else
3101 { qualifier = "::"; qlen = 2; }
3104 while (!feof (inf))
3106 c = *lp++;
3107 if (c == '\\')
3109 /* If we're at the end of the line, the next character is a
3110 '\0'; don't skip it, because it's the thing that tells us
3111 to read the next line. */
3112 if (*lp == '\0')
3114 quotednl = TRUE;
3115 continue;
3117 lp++;
3118 c = ' ';
3120 else if (incomm)
3122 switch (c)
3124 case '*':
3125 if (*lp == '/')
3127 c = *lp++;
3128 incomm = FALSE;
3130 break;
3131 case '\0':
3132 /* Newlines inside comments do not end macro definitions in
3133 traditional cpp. */
3134 CNL_SAVE_DEFINEDEF ();
3135 break;
3137 continue;
3139 else if (inquote)
3141 switch (c)
3143 case '"':
3144 inquote = FALSE;
3145 break;
3146 case '\0':
3147 /* Newlines inside strings do not end macro definitions
3148 in traditional cpp, even though compilers don't
3149 usually accept them. */
3150 CNL_SAVE_DEFINEDEF ();
3151 break;
3153 continue;
3155 else if (inchar)
3157 switch (c)
3159 case '\0':
3160 /* Hmmm, something went wrong. */
3161 CNL ();
3162 /* FALLTHRU */
3163 case '\'':
3164 inchar = FALSE;
3165 break;
3167 continue;
3169 else
3170 switch (c)
3172 case '"':
3173 inquote = TRUE;
3174 switch (fvdef)
3176 case fdefunkey:
3177 case fstartlist:
3178 case finlist:
3179 case fignore:
3180 case vignore:
3181 break;
3182 default:
3183 fvextern = FALSE;
3184 fvdef = fvnone;
3186 continue;
3187 case '\'':
3188 inchar = TRUE;
3189 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
3191 fvextern = FALSE;
3192 fvdef = fvnone;
3194 continue;
3195 case '/':
3196 if (*lp == '*')
3198 lp++;
3199 incomm = TRUE;
3200 continue;
3202 else if (/* cplpl && */ *lp == '/')
3204 c = '\0';
3205 break;
3207 else
3208 break;
3209 case '%':
3210 if ((c_ext & YACC) && *lp == '%')
3212 /* Entering or exiting rules section in yacc file. */
3213 lp++;
3214 definedef = dnone; fvdef = fvnone; fvextern = FALSE;
3215 typdef = tnone; structdef = snone;
3216 midtoken = inquote = inchar = incomm = quotednl = FALSE;
3217 cblev = 0;
3218 yacc_rules = !yacc_rules;
3219 continue;
3221 else
3222 break;
3223 case '#':
3224 if (definedef == dnone)
3226 char *cp;
3227 bool cpptoken = TRUE;
3229 /* Look back on this line. If all blanks, or nonblanks
3230 followed by an end of comment, this is a preprocessor
3231 token. */
3232 for (cp = newlb.buffer; cp < lp-1; cp++)
3233 if (!iswhite (*cp))
3235 if (*cp == '*' && *(cp+1) == '/')
3237 cp++;
3238 cpptoken = TRUE;
3240 else
3241 cpptoken = FALSE;
3243 if (cpptoken)
3244 definedef = dsharpseen;
3245 } /* if (definedef == dnone) */
3247 continue;
3248 } /* switch (c) */
3251 /* Consider token only if some involved conditions are satisfied. */
3252 if (typdef != tignore
3253 && definedef != dignorerest
3254 && fvdef != finlist
3255 && structdef != sintemplate
3256 && (definedef != dnone
3257 || structdef != scolonseen))
3259 if (midtoken)
3261 if (endtoken (c))
3263 if (c == ':' && *lp == ':' && begtoken (lp[1]))
3264 /* This handles :: in the middle,
3265 but not at the beginning of an identifier.
3266 Also, space-separated :: is not recognised. */
3268 if (c_ext & C_AUTO) /* automatic detection of C++ */
3269 c_ext = (c_ext | C_PLPL) & ~C_AUTO;
3270 lp += 2;
3271 toklen += 2;
3272 c = lp[-1];
3273 goto still_in_token;
3275 else
3277 bool funorvar = FALSE;
3279 if (yacc_rules
3280 || consider_token (newlb.buffer + tokoff, toklen, c,
3281 &c_ext, cblev, parlev, &funorvar))
3283 if (fvdef == foperator)
3285 char *oldlp = lp;
3286 lp = skip_spaces (lp-1);
3287 if (*lp != '\0')
3288 lp += 1;
3289 while (*lp != '\0'
3290 && !iswhite (*lp) && *lp != '(')
3291 lp += 1;
3292 c = *lp++;
3293 toklen += lp - oldlp;
3295 token.named = FALSE;
3296 if (!plainc
3297 && nestlev > 0 && definedef == dnone)
3298 /* in struct body */
3300 write_classname (&token_name, qualifier);
3301 linebuffer_setlen (&token_name,
3302 token_name.len+qlen+toklen);
3303 strcat (token_name.buffer, qualifier);
3304 strncat (token_name.buffer,
3305 newlb.buffer + tokoff, toklen);
3306 token.named = TRUE;
3308 else if (objdef == ocatseen)
3309 /* Objective C category */
3311 int len = strlen (objtag) + 2 + toklen;
3312 linebuffer_setlen (&token_name, len);
3313 strcpy (token_name.buffer, objtag);
3314 strcat (token_name.buffer, "(");
3315 strncat (token_name.buffer,
3316 newlb.buffer + tokoff, toklen);
3317 strcat (token_name.buffer, ")");
3318 token.named = TRUE;
3320 else if (objdef == omethodtag
3321 || objdef == omethodparm)
3322 /* Objective C method */
3324 token.named = TRUE;
3326 else if (fvdef == fdefunname)
3327 /* GNU DEFUN and similar macros */
3329 bool defun = (newlb.buffer[tokoff] == 'F');
3330 int off = tokoff;
3331 int len = toklen;
3333 /* Rewrite the tag so that emacs lisp DEFUNs
3334 can be found by their elisp name */
3335 if (defun)
3337 off += 1;
3338 len -= 1;
3340 len = toklen;
3341 linebuffer_setlen (&token_name, len);
3342 strncpy (token_name.buffer,
3343 newlb.buffer + off, len);
3344 token_name.buffer[len] = '\0';
3345 if (defun)
3346 while (--len >= 0)
3347 if (token_name.buffer[len] == '_')
3348 token_name.buffer[len] = '-';
3349 token.named = defun;
3351 else
3353 linebuffer_setlen (&token_name, toklen);
3354 strncpy (token_name.buffer,
3355 newlb.buffer + tokoff, toklen);
3356 token_name.buffer[toklen] = '\0';
3357 /* Name macros and members. */
3358 token.named = (structdef == stagseen
3359 || typdef == ttypeseen
3360 || typdef == tend
3361 || (funorvar
3362 && definedef == dignorerest)
3363 || (funorvar
3364 && definedef == dnone
3365 && structdef == snone
3366 && cblev > 0));
3368 token.lineno = lineno;
3369 token.offset = tokoff;
3370 token.length = toklen;
3371 token.line = newlb.buffer;
3372 token.linepos = newlinepos;
3373 token.valid = TRUE;
3375 if (definedef == dnone
3376 && (fvdef == fvnameseen
3377 || fvdef == foperator
3378 || structdef == stagseen
3379 || typdef == tend
3380 || typdef == ttypeseen
3381 || objdef != onone))
3383 if (current_lb_is_new)
3384 switch_line_buffers ();
3386 else if (definedef != dnone
3387 || fvdef == fdefunname
3388 || instruct)
3389 make_C_tag (funorvar);
3391 midtoken = FALSE;
3393 } /* if (endtoken (c)) */
3394 else if (intoken (c))
3395 still_in_token:
3397 toklen++;
3398 continue;
3400 } /* if (midtoken) */
3401 else if (begtoken (c))
3403 switch (definedef)
3405 case dnone:
3406 switch (fvdef)
3408 case fstartlist:
3409 fvdef = finlist;
3410 continue;
3411 case flistseen:
3412 if (plainc || declarations)
3414 make_C_tag (TRUE); /* a function */
3415 fvdef = fignore;
3417 break;
3418 case fvnameseen:
3419 fvdef = fvnone;
3420 break;
3422 if (structdef == stagseen && !cjava)
3424 popclass_above (cblev);
3425 structdef = snone;
3427 break;
3428 case dsharpseen:
3429 savetoken = token;
3430 break;
3432 if (!yacc_rules || lp == newlb.buffer + 1)
3434 tokoff = lp - 1 - newlb.buffer;
3435 toklen = 1;
3436 midtoken = TRUE;
3438 continue;
3439 } /* if (begtoken) */
3440 } /* if must look at token */
3443 /* Detect end of line, colon, comma, semicolon and various braces
3444 after having handled a token.*/
3445 switch (c)
3447 case ':':
3448 if (yacc_rules && token.offset == 0 && token.valid)
3450 make_C_tag (FALSE); /* a yacc function */
3451 break;
3453 if (definedef != dnone)
3454 break;
3455 switch (objdef)
3457 case otagseen:
3458 objdef = oignore;
3459 make_C_tag (TRUE); /* an Objective C class */
3460 break;
3461 case omethodtag:
3462 case omethodparm:
3463 objdef = omethodcolon;
3464 linebuffer_setlen (&token_name, token_name.len + 1);
3465 strcat (token_name.buffer, ":");
3466 break;
3468 if (structdef == stagseen)
3470 structdef = scolonseen;
3471 break;
3473 /* Should be useless, but may be work as a safety net. */
3474 if (cplpl && fvdef == flistseen)
3476 make_C_tag (TRUE); /* a function */
3477 fvdef = fignore;
3478 break;
3480 break;
3481 case ';':
3482 if (definedef != dnone)
3483 break;
3484 switch (typdef)
3486 case tend:
3487 case ttypeseen:
3488 make_C_tag (FALSE); /* a typedef */
3489 typdef = tnone;
3490 fvdef = fvnone;
3491 break;
3492 case tnone:
3493 case tinbody:
3494 case tignore:
3495 switch (fvdef)
3497 case fignore:
3498 if (typdef == tignore || cplpl)
3499 fvdef = fvnone;
3500 break;
3501 case fvnameseen:
3502 if ((globals && cblev == 0 && (!fvextern || declarations))
3503 || (members && instruct))
3504 make_C_tag (FALSE); /* a variable */
3505 fvextern = FALSE;
3506 fvdef = fvnone;
3507 token.valid = FALSE;
3508 break;
3509 case flistseen:
3510 if (declarations
3511 && (typdef == tnone || (typdef != tignore && instruct)))
3512 make_C_tag (TRUE); /* a function declaration */
3513 /* FALLTHRU */
3514 default:
3515 fvextern = FALSE;
3516 fvdef = fvnone;
3517 if (declarations
3518 && cplpl && structdef == stagseen)
3519 make_C_tag (FALSE); /* forward declaration */
3520 else
3521 token.valid = FALSE;
3522 } /* switch (fvdef) */
3523 /* FALLTHRU */
3524 default:
3525 if (!instruct)
3526 typdef = tnone;
3528 if (structdef == stagseen)
3529 structdef = snone;
3530 break;
3531 case ',':
3532 if (definedef != dnone)
3533 break;
3534 switch (objdef)
3536 case omethodtag:
3537 case omethodparm:
3538 make_C_tag (TRUE); /* an Objective C method */
3539 objdef = oinbody;
3540 break;
3542 switch (fvdef)
3544 case fdefunkey:
3545 case foperator:
3546 case fstartlist:
3547 case finlist:
3548 case fignore:
3549 case vignore:
3550 break;
3551 case fdefunname:
3552 fvdef = fignore;
3553 break;
3554 case fvnameseen: /* a variable */
3555 if ((globals && cblev == 0 && (!fvextern || declarations))
3556 || (members && instruct))
3557 make_C_tag (FALSE);
3558 break;
3559 case flistseen: /* a function */
3560 if ((declarations && typdef == tnone && !instruct)
3561 || (members && typdef != tignore && instruct))
3563 make_C_tag (TRUE); /* a function declaration */
3564 fvdef = fvnameseen;
3566 else if (!declarations)
3567 fvdef = fvnone;
3568 token.valid = FALSE;
3569 break;
3570 default:
3571 fvdef = fvnone;
3573 if (structdef == stagseen)
3574 structdef = snone;
3575 break;
3576 case '[':
3577 if (definedef != dnone)
3578 break;
3579 if (structdef == stagseen)
3580 structdef = snone;
3581 switch (typdef)
3583 case ttypeseen:
3584 case tend:
3585 typdef = tignore;
3586 make_C_tag (FALSE); /* a typedef */
3587 break;
3588 case tnone:
3589 case tinbody:
3590 switch (fvdef)
3592 case foperator:
3593 case finlist:
3594 case fignore:
3595 case vignore:
3596 break;
3597 case fvnameseen:
3598 if ((members && cblev == 1)
3599 || (globals && cblev == 0
3600 && (!fvextern || declarations)))
3601 make_C_tag (FALSE); /* a variable */
3602 /* FALLTHRU */
3603 default:
3604 fvdef = fvnone;
3606 break;
3608 break;
3609 case '(':
3610 if (definedef != dnone)
3611 break;
3612 if (objdef == otagseen && parlev == 0)
3613 objdef = oparenseen;
3614 switch (fvdef)
3616 case fvnameseen:
3617 if (typdef == ttypeseen
3618 && *lp != '*'
3619 && !instruct)
3621 /* This handles constructs like:
3622 typedef void OperatorFun (int fun); */
3623 make_C_tag (FALSE);
3624 typdef = tignore;
3625 fvdef = fignore;
3626 break;
3628 /* FALLTHRU */
3629 case foperator:
3630 fvdef = fstartlist;
3631 break;
3632 case flistseen:
3633 fvdef = finlist;
3634 break;
3636 parlev++;
3637 break;
3638 case ')':
3639 if (definedef != dnone)
3640 break;
3641 if (objdef == ocatseen && parlev == 1)
3643 make_C_tag (TRUE); /* an Objective C category */
3644 objdef = oignore;
3646 if (--parlev == 0)
3648 switch (fvdef)
3650 case fstartlist:
3651 case finlist:
3652 fvdef = flistseen;
3653 break;
3655 if (!instruct
3656 && (typdef == tend
3657 || typdef == ttypeseen))
3659 typdef = tignore;
3660 make_C_tag (FALSE); /* a typedef */
3663 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3664 parlev = 0;
3665 break;
3666 case '{':
3667 if (definedef != dnone)
3668 break;
3669 if (typdef == ttypeseen)
3671 /* Whenever typdef is set to tinbody (currently only
3672 here), typdefcblev should be set to cblev. */
3673 typdef = tinbody;
3674 typdefcblev = cblev;
3676 switch (fvdef)
3678 case flistseen:
3679 make_C_tag (TRUE); /* a function */
3680 /* FALLTHRU */
3681 case fignore:
3682 fvdef = fvnone;
3683 break;
3684 case fvnone:
3685 switch (objdef)
3687 case otagseen:
3688 make_C_tag (TRUE); /* an Objective C class */
3689 objdef = oignore;
3690 break;
3691 case omethodtag:
3692 case omethodparm:
3693 make_C_tag (TRUE); /* an Objective C method */
3694 objdef = oinbody;
3695 break;
3696 default:
3697 /* Neutralize `extern "C" {' grot. */
3698 if (cblev == 0 && structdef == snone && nestlev == 0
3699 && typdef == tnone)
3700 cblev = -1;
3702 break;
3704 switch (structdef)
3706 case skeyseen: /* unnamed struct */
3707 pushclass_above (cblev, NULL, 0);
3708 structdef = snone;
3709 break;
3710 case stagseen: /* named struct or enum */
3711 case scolonseen: /* a class */
3712 pushclass_above (cblev, token.line+token.offset, token.length);
3713 structdef = snone;
3714 make_C_tag (FALSE); /* a struct or enum */
3715 break;
3717 cblev++;
3718 break;
3719 case '*':
3720 if (definedef != dnone)
3721 break;
3722 if (fvdef == fstartlist)
3724 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
3725 token.valid = FALSE;
3727 break;
3728 case '}':
3729 if (definedef != dnone)
3730 break;
3731 if (!ignoreindent && lp == newlb.buffer + 1)
3733 if (cblev != 0)
3734 token.valid = FALSE;
3735 cblev = 0; /* reset curly brace level if first column */
3736 parlev = 0; /* also reset paren level, just in case... */
3738 else if (cblev > 0)
3739 cblev--;
3740 else
3741 token.valid = FALSE; /* something gone amiss, token unreliable */
3742 popclass_above (cblev);
3743 structdef = snone;
3744 /* Only if typdef == tinbody is typdefcblev significant. */
3745 if (typdef == tinbody && cblev <= typdefcblev)
3747 assert (cblev == typdefcblev);
3748 typdef = tend;
3750 break;
3751 case '=':
3752 if (definedef != dnone)
3753 break;
3754 switch (fvdef)
3756 case foperator:
3757 case finlist:
3758 case fignore:
3759 case vignore:
3760 break;
3761 case fvnameseen:
3762 if ((members && cblev == 1)
3763 || (globals && cblev == 0 && (!fvextern || declarations)))
3764 make_C_tag (FALSE); /* a variable */
3765 /* FALLTHRU */
3766 default:
3767 fvdef = vignore;
3769 break;
3770 case '<':
3771 if (cplpl && structdef == stagseen)
3773 structdef = sintemplate;
3774 break;
3776 goto resetfvdef;
3777 case '>':
3778 if (structdef == sintemplate)
3780 structdef = stagseen;
3781 break;
3783 goto resetfvdef;
3784 case '+':
3785 case '-':
3786 if (objdef == oinbody && cblev == 0)
3788 objdef = omethodsign;
3789 break;
3791 /* FALLTHRU */
3792 resetfvdef:
3793 case '#': case '~': case '&': case '%': case '/': case '|':
3794 case '^': case '!': case '.': case '?': case ']':
3795 if (definedef != dnone)
3796 break;
3797 /* These surely cannot follow a function tag in C. */
3798 switch (fvdef)
3800 case foperator:
3801 case finlist:
3802 case fignore:
3803 case vignore:
3804 break;
3805 default:
3806 fvdef = fvnone;
3808 break;
3809 case '\0':
3810 if (objdef == otagseen)
3812 make_C_tag (TRUE); /* an Objective C class */
3813 objdef = oignore;
3815 /* If a macro spans multiple lines don't reset its state. */
3816 if (quotednl)
3817 CNL_SAVE_DEFINEDEF ();
3818 else
3819 CNL ();
3820 break;
3821 } /* switch (c) */
3823 } /* while not eof */
3825 free (lbs[0].lb.buffer);
3826 free (lbs[1].lb.buffer);
3830 * Process either a C++ file or a C file depending on the setting
3831 * of a global flag.
3833 static void
3834 default_C_entries (inf)
3835 FILE *inf;
3837 C_entries (cplusplus ? C_PLPL : C_AUTO, inf);
3840 /* Always do plain C. */
3841 static void
3842 plain_C_entries (inf)
3843 FILE *inf;
3845 C_entries (0, inf);
3848 /* Always do C++. */
3849 static void
3850 Cplusplus_entries (inf)
3851 FILE *inf;
3853 C_entries (C_PLPL, inf);
3856 /* Always do Java. */
3857 static void
3858 Cjava_entries (inf)
3859 FILE *inf;
3861 C_entries (C_JAVA, inf);
3864 /* Always do C*. */
3865 static void
3866 Cstar_entries (inf)
3867 FILE *inf;
3869 C_entries (C_STAR, inf);
3872 /* Always do Yacc. */
3873 static void
3874 Yacc_entries (inf)
3875 FILE *inf;
3877 C_entries (YACC, inf);
3881 /* Useful macros. */
3882 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3883 for (; /* loop initialization */ \
3884 !feof (file_pointer) /* loop test */ \
3885 && /* instructions at start of loop */ \
3886 (readline (&line_buffer, file_pointer), \
3887 char_pointer = line_buffer.buffer, \
3888 TRUE); \
3890 #define LOOKING_AT(cp, keyword) /* keyword is a constant string */ \
3891 (strneq ((cp), keyword, sizeof(keyword)-1) /* cp points at keyword */ \
3892 && notinname ((cp)[sizeof(keyword)-1]) /* end of keyword */ \
3893 && ((cp) = skip_spaces((cp)+sizeof(keyword)-1))) /* skip spaces */
3896 * Read a file, but do no processing. This is used to do regexp
3897 * matching on files that have no language defined.
3899 static void
3900 just_read_file (inf)
3901 FILE *inf;
3903 register char *dummy;
3905 LOOP_ON_INPUT_LINES (inf, lb, dummy)
3906 continue;
3910 /* Fortran parsing */
3912 static void F_takeprec __P((void));
3913 static void F_getit __P((FILE *));
3915 static void
3916 F_takeprec ()
3918 dbp = skip_spaces (dbp);
3919 if (*dbp != '*')
3920 return;
3921 dbp++;
3922 dbp = skip_spaces (dbp);
3923 if (strneq (dbp, "(*)", 3))
3925 dbp += 3;
3926 return;
3928 if (!ISDIGIT (*dbp))
3930 --dbp; /* force failure */
3931 return;
3934 dbp++;
3935 while (ISDIGIT (*dbp));
3938 static void
3939 F_getit (inf)
3940 FILE *inf;
3942 register char *cp;
3944 dbp = skip_spaces (dbp);
3945 if (*dbp == '\0')
3947 readline (&lb, inf);
3948 dbp = lb.buffer;
3949 if (dbp[5] != '&')
3950 return;
3951 dbp += 6;
3952 dbp = skip_spaces (dbp);
3954 if (!ISALPHA (*dbp) && *dbp != '_' && *dbp != '$')
3955 return;
3956 for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
3957 continue;
3958 make_tag (dbp, cp-dbp, TRUE,
3959 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3963 static void
3964 Fortran_functions (inf)
3965 FILE *inf;
3967 LOOP_ON_INPUT_LINES (inf, lb, dbp)
3969 if (*dbp == '%')
3970 dbp++; /* Ratfor escape to fortran */
3971 dbp = skip_spaces (dbp);
3972 if (*dbp == '\0')
3973 continue;
3974 switch (lowcase (*dbp))
3976 case 'i':
3977 if (nocase_tail ("integer"))
3978 F_takeprec ();
3979 break;
3980 case 'r':
3981 if (nocase_tail ("real"))
3982 F_takeprec ();
3983 break;
3984 case 'l':
3985 if (nocase_tail ("logical"))
3986 F_takeprec ();
3987 break;
3988 case 'c':
3989 if (nocase_tail ("complex") || nocase_tail ("character"))
3990 F_takeprec ();
3991 break;
3992 case 'd':
3993 if (nocase_tail ("double"))
3995 dbp = skip_spaces (dbp);
3996 if (*dbp == '\0')
3997 continue;
3998 if (nocase_tail ("precision"))
3999 break;
4000 continue;
4002 break;
4004 dbp = skip_spaces (dbp);
4005 if (*dbp == '\0')
4006 continue;
4007 switch (lowcase (*dbp))
4009 case 'f':
4010 if (nocase_tail ("function"))
4011 F_getit (inf);
4012 continue;
4013 case 's':
4014 if (nocase_tail ("subroutine"))
4015 F_getit (inf);
4016 continue;
4017 case 'e':
4018 if (nocase_tail ("entry"))
4019 F_getit (inf);
4020 continue;
4021 case 'b':
4022 if (nocase_tail ("blockdata") || nocase_tail ("block data"))
4024 dbp = skip_spaces (dbp);
4025 if (*dbp == '\0') /* assume un-named */
4026 make_tag ("blockdata", 9, TRUE,
4027 lb.buffer, dbp - lb.buffer, lineno, linecharno);
4028 else
4029 F_getit (inf); /* look for name */
4031 continue;
4038 * Ada parsing
4039 * Original code by
4040 * Philippe Waroquiers <philippe.waroquiers@eurocontrol.int> (1998)
4043 static void Ada_getit __P((FILE *, char *));
4045 /* Once we are positioned after an "interesting" keyword, let's get
4046 the real tag value necessary. */
4047 static void
4048 Ada_getit (inf, name_qualifier)
4049 FILE *inf;
4050 char *name_qualifier;
4052 register char *cp;
4053 char *name;
4054 char c;
4056 while (!feof (inf))
4058 dbp = skip_spaces (dbp);
4059 if (*dbp == '\0'
4060 || (dbp[0] == '-' && dbp[1] == '-'))
4062 readline (&lb, inf);
4063 dbp = lb.buffer;
4065 switch (lowcase(*dbp))
4067 case 'b':
4068 if (nocase_tail ("body"))
4070 /* Skipping body of procedure body or package body or ....
4071 resetting qualifier to body instead of spec. */
4072 name_qualifier = "/b";
4073 continue;
4075 break;
4076 case 't':
4077 /* Skipping type of task type or protected type ... */
4078 if (nocase_tail ("type"))
4079 continue;
4080 break;
4082 if (*dbp == '"')
4084 dbp += 1;
4085 for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
4086 continue;
4088 else
4090 dbp = skip_spaces (dbp);
4091 for (cp = dbp;
4092 (*cp != '\0'
4093 && (ISALPHA (*cp) || ISDIGIT (*cp) || *cp == '_' || *cp == '.'));
4094 cp++)
4095 continue;
4096 if (cp == dbp)
4097 return;
4099 c = *cp;
4100 *cp = '\0';
4101 name = concat (dbp, name_qualifier, "");
4102 *cp = c;
4103 make_tag (name, strlen (name), TRUE,
4104 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4105 free (name);
4106 if (c == '"')
4107 dbp = cp + 1;
4108 return;
4112 static void
4113 Ada_funcs (inf)
4114 FILE *inf;
4116 bool inquote = FALSE;
4117 bool skip_till_semicolumn = FALSE;
4119 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4121 while (*dbp != '\0')
4123 /* Skip a string i.e. "abcd". */
4124 if (inquote || (*dbp == '"'))
4126 dbp = etags_strchr ((inquote) ? dbp : dbp+1, '"');
4127 if (dbp != NULL)
4129 inquote = FALSE;
4130 dbp += 1;
4131 continue; /* advance char */
4133 else
4135 inquote = TRUE;
4136 break; /* advance line */
4140 /* Skip comments. */
4141 if (dbp[0] == '-' && dbp[1] == '-')
4142 break; /* advance line */
4144 /* Skip character enclosed in single quote i.e. 'a'
4145 and skip single quote starting an attribute i.e. 'Image. */
4146 if (*dbp == '\'')
4148 dbp++ ;
4149 if (*dbp != '\0')
4150 dbp++;
4151 continue;
4154 if (skip_till_semicolumn)
4156 if (*dbp == ';')
4157 skip_till_semicolumn = FALSE;
4158 dbp++;
4159 continue; /* advance char */
4162 /* Search for beginning of a token. */
4163 if (!begtoken (*dbp))
4165 dbp++;
4166 continue; /* advance char */
4169 /* We are at the beginning of a token. */
4170 switch (lowcase(*dbp))
4172 case 'f':
4173 if (!packages_only && nocase_tail ("function"))
4174 Ada_getit (inf, "/f");
4175 else
4176 break; /* from switch */
4177 continue; /* advance char */
4178 case 'p':
4179 if (!packages_only && nocase_tail ("procedure"))
4180 Ada_getit (inf, "/p");
4181 else if (nocase_tail ("package"))
4182 Ada_getit (inf, "/s");
4183 else if (nocase_tail ("protected")) /* protected type */
4184 Ada_getit (inf, "/t");
4185 else
4186 break; /* from switch */
4187 continue; /* advance char */
4189 case 'u':
4190 if (typedefs && !packages_only && nocase_tail ("use"))
4192 /* when tagging types, avoid tagging use type Pack.Typename;
4193 for this, we will skip everything till a ; */
4194 skip_till_semicolumn = TRUE;
4195 continue; /* advance char */
4198 case 't':
4199 if (!packages_only && nocase_tail ("task"))
4200 Ada_getit (inf, "/k");
4201 else if (typedefs && !packages_only && nocase_tail ("type"))
4203 Ada_getit (inf, "/t");
4204 while (*dbp != '\0')
4205 dbp += 1;
4207 else
4208 break; /* from switch */
4209 continue; /* advance char */
4212 /* Look for the end of the token. */
4213 while (!endtoken (*dbp))
4214 dbp++;
4216 } /* advance char */
4217 } /* advance line */
4222 * Unix and microcontroller assembly tag handling
4223 * Labels: /^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]/
4224 * Idea by Bob Weiner, Motorola Inc. (1994)
4226 static void
4227 Asm_labels (inf)
4228 FILE *inf;
4230 register char *cp;
4232 LOOP_ON_INPUT_LINES (inf, lb, cp)
4234 /* If first char is alphabetic or one of [_.$], test for colon
4235 following identifier. */
4236 if (ISALPHA (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4238 /* Read past label. */
4239 cp++;
4240 while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
4241 cp++;
4242 if (*cp == ':' || iswhite (*cp))
4243 /* Found end of label, so copy it and add it to the table. */
4244 make_tag (lb.buffer, cp - lb.buffer, TRUE,
4245 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4252 * Perl support
4253 * Perl sub names: /^sub[ \t\n]+[^ \t\n{]+/
4254 * Perl variable names: /^(my|local).../
4255 * Original code by Bart Robinson <lomew@cs.utah.edu> (1995)
4256 * Additions by Michael Ernst <mernst@alum.mit.edu> (1997)
4257 * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
4259 static void
4260 Perl_functions (inf)
4261 FILE *inf;
4263 char *package = savestr ("main"); /* current package name */
4264 register char *cp;
4266 LOOP_ON_INPUT_LINES (inf, lb, cp)
4268 skip_spaces(cp);
4270 if (LOOKING_AT (cp, "package"))
4272 free (package);
4273 get_tag (cp, &package);
4275 else if (LOOKING_AT (cp, "sub"))
4277 char *pos;
4278 char *sp = cp;
4280 while (!notinname (*cp))
4281 cp++;
4282 if (cp == sp)
4283 continue; /* nothing found */
4284 if ((pos = etags_strchr (sp, ':')) != NULL
4285 && pos < cp && pos[1] == ':')
4286 /* The name is already qualified. */
4287 make_tag (sp, cp - sp, TRUE,
4288 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4289 else
4290 /* Qualify it. */
4292 char savechar, *name;
4294 savechar = *cp;
4295 *cp = '\0';
4296 name = concat (package, "::", sp);
4297 *cp = savechar;
4298 make_tag (name, strlen(name), TRUE,
4299 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4300 free (name);
4303 else if (globals) /* only if we are tagging global vars */
4305 /* Skip a qualifier, if any. */
4306 bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
4307 /* After "my" or "local", but before any following paren or space. */
4308 char *varstart = cp;
4310 if (qual /* should this be removed? If yes, how? */
4311 && (*cp == '$' || *cp == '@' || *cp == '%'))
4313 varstart += 1;
4315 cp++;
4316 while (ISALNUM (*cp) || *cp == '_');
4318 else if (qual)
4320 /* Should be examining a variable list at this point;
4321 could insist on seeing an open parenthesis. */
4322 while (*cp != '\0' && *cp != ';' && *cp != '=' && *cp != ')')
4323 cp++;
4325 else
4326 continue;
4328 make_tag (varstart, cp - varstart, FALSE,
4329 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4336 * Python support
4337 * Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
4338 * Idea by Eric S. Raymond <esr@thyrsus.com> (1997)
4339 * More ideas by seb bacon <seb@jamkit.com> (2002)
4341 static void
4342 Python_functions (inf)
4343 FILE *inf;
4345 register char *cp;
4347 LOOP_ON_INPUT_LINES (inf, lb, cp)
4349 cp = skip_spaces (cp);
4350 if (LOOKING_AT (cp, "def") || LOOKING_AT (cp, "class"))
4352 char *name = cp;
4353 while (!notinname (*cp) && *cp != ':')
4354 cp++;
4355 make_tag (name, cp - name, TRUE,
4356 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4363 * PHP support
4364 * Look for:
4365 * - /^[ \t]*function[ \t\n]+[^ \t\n(]+/
4366 * - /^[ \t]*class[ \t\n]+[^ \t\n]+/
4367 * - /^[ \t]*define\(\"[^\"]+/
4368 * Only with --members:
4369 * - /^[ \t]*var[ \t\n]+\$[^ \t\n=;]/
4370 * Idea by Diez B. Roggisch (2001)
4372 static void
4373 PHP_functions (inf)
4374 FILE *inf;
4376 register char *cp, *name;
4377 bool search_identifier = FALSE;
4379 LOOP_ON_INPUT_LINES (inf, lb, cp)
4381 cp = skip_spaces (cp);
4382 name = cp;
4383 if (search_identifier
4384 && *cp != '\0')
4386 while (!notinname (*cp))
4387 cp++;
4388 make_tag (name, cp - name, TRUE,
4389 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4390 search_identifier = FALSE;
4392 else if (LOOKING_AT (cp, "function"))
4394 if(*cp == '&')
4395 cp = skip_spaces (cp+1);
4396 if(*cp != '\0')
4398 name = cp;
4399 while (!notinname (*cp))
4400 cp++;
4401 make_tag (name, cp - name, TRUE,
4402 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4404 else
4405 search_identifier = TRUE;
4407 else if (LOOKING_AT (cp, "class"))
4409 if (*cp != '\0')
4411 name = cp;
4412 while (*cp != '\0' && !iswhite (*cp))
4413 cp++;
4414 make_tag (name, cp - name, FALSE,
4415 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4417 else
4418 search_identifier = TRUE;
4420 else if (strneq (cp, "define", 6)
4421 && (cp = skip_spaces (cp+6))
4422 && *cp++ == '('
4423 && (*cp == '"' || *cp == '\''))
4425 char quote = *cp++;
4426 name = cp;
4427 while (*cp != quote && *cp != '\0')
4428 cp++;
4429 make_tag (name, cp - name, FALSE,
4430 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4432 else if (members
4433 && LOOKING_AT (cp, "var")
4434 && *cp == '$')
4436 name = cp;
4437 while (!notinname(*cp))
4438 cp++;
4439 make_tag (name, cp - name, FALSE,
4440 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4447 * Cobol tag functions
4448 * We could look for anything that could be a paragraph name.
4449 * i.e. anything that starts in column 8 is one word and ends in a full stop.
4450 * Idea by Corny de Souza (1993)
4452 static void
4453 Cobol_paragraphs (inf)
4454 FILE *inf;
4456 register char *bp, *ep;
4458 LOOP_ON_INPUT_LINES (inf, lb, bp)
4460 if (lb.len < 9)
4461 continue;
4462 bp += 8;
4464 /* If eoln, compiler option or comment ignore whole line. */
4465 if (bp[-1] != ' ' || !ISALNUM (bp[0]))
4466 continue;
4468 for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
4469 continue;
4470 if (*ep++ == '.')
4471 make_tag (bp, ep - bp, TRUE,
4472 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4478 * Makefile support
4479 * Ideas by Assar Westerlund <assar@sics.se> (2001)
4481 static void
4482 Makefile_targets (inf)
4483 FILE *inf;
4485 register char *bp;
4487 LOOP_ON_INPUT_LINES (inf, lb, bp)
4489 if (*bp == '\t' || *bp == '#')
4490 continue;
4491 while (*bp != '\0' && *bp != '=' && *bp != ':')
4492 bp++;
4493 if (*bp == ':' || (globals && *bp == '='))
4494 make_tag (lb.buffer, bp - lb.buffer, TRUE,
4495 lb.buffer, bp - lb.buffer + 1, lineno, linecharno);
4501 * Pascal parsing
4502 * Original code by Mosur K. Mohan (1989)
4504 * Locates tags for procedures & functions. Doesn't do any type- or
4505 * var-definitions. It does look for the keyword "extern" or
4506 * "forward" immediately following the procedure statement; if found,
4507 * the tag is skipped.
4509 static void
4510 Pascal_functions (inf)
4511 FILE *inf;
4513 linebuffer tline; /* mostly copied from C_entries */
4514 long save_lcno;
4515 int save_lineno, namelen, taglen;
4516 char c, *name;
4518 bool /* each of these flags is TRUE iff: */
4519 incomment, /* point is inside a comment */
4520 inquote, /* point is inside '..' string */
4521 get_tagname, /* point is after PROCEDURE/FUNCTION
4522 keyword, so next item = potential tag */
4523 found_tag, /* point is after a potential tag */
4524 inparms, /* point is within parameter-list */
4525 verify_tag; /* point has passed the parm-list, so the
4526 next token will determine whether this
4527 is a FORWARD/EXTERN to be ignored, or
4528 whether it is a real tag */
4530 save_lcno = save_lineno = namelen = taglen = 0; /* keep compiler quiet */
4531 name = NULL; /* keep compiler quiet */
4532 dbp = lb.buffer;
4533 *dbp = '\0';
4534 linebuffer_init (&tline);
4536 incomment = inquote = FALSE;
4537 found_tag = FALSE; /* have a proc name; check if extern */
4538 get_tagname = FALSE; /* found "procedure" keyword */
4539 inparms = FALSE; /* found '(' after "proc" */
4540 verify_tag = FALSE; /* check if "extern" is ahead */
4543 while (!feof (inf)) /* long main loop to get next char */
4545 c = *dbp++;
4546 if (c == '\0') /* if end of line */
4548 readline (&lb, inf);
4549 dbp = lb.buffer;
4550 if (*dbp == '\0')
4551 continue;
4552 if (!((found_tag && verify_tag)
4553 || get_tagname))
4554 c = *dbp++; /* only if don't need *dbp pointing
4555 to the beginning of the name of
4556 the procedure or function */
4558 if (incomment)
4560 if (c == '}') /* within { } comments */
4561 incomment = FALSE;
4562 else if (c == '*' && *dbp == ')') /* within (* *) comments */
4564 dbp++;
4565 incomment = FALSE;
4567 continue;
4569 else if (inquote)
4571 if (c == '\'')
4572 inquote = FALSE;
4573 continue;
4575 else
4576 switch (c)
4578 case '\'':
4579 inquote = TRUE; /* found first quote */
4580 continue;
4581 case '{': /* found open { comment */
4582 incomment = TRUE;
4583 continue;
4584 case '(':
4585 if (*dbp == '*') /* found open (* comment */
4587 incomment = TRUE;
4588 dbp++;
4590 else if (found_tag) /* found '(' after tag, i.e., parm-list */
4591 inparms = TRUE;
4592 continue;
4593 case ')': /* end of parms list */
4594 if (inparms)
4595 inparms = FALSE;
4596 continue;
4597 case ';':
4598 if (found_tag && !inparms) /* end of proc or fn stmt */
4600 verify_tag = TRUE;
4601 break;
4603 continue;
4605 if (found_tag && verify_tag && (*dbp != ' '))
4607 /* Check if this is an "extern" declaration. */
4608 if (*dbp == '\0')
4609 continue;
4610 if (lowcase (*dbp == 'e'))
4612 if (nocase_tail ("extern")) /* superfluous, really! */
4614 found_tag = FALSE;
4615 verify_tag = FALSE;
4618 else if (lowcase (*dbp) == 'f')
4620 if (nocase_tail ("forward")) /* check for forward reference */
4622 found_tag = FALSE;
4623 verify_tag = FALSE;
4626 if (found_tag && verify_tag) /* not external proc, so make tag */
4628 found_tag = FALSE;
4629 verify_tag = FALSE;
4630 make_tag (name, namelen, TRUE,
4631 tline.buffer, taglen, save_lineno, save_lcno);
4632 continue;
4635 if (get_tagname) /* grab name of proc or fn */
4637 char *cp;
4639 if (*dbp == '\0')
4640 continue;
4642 /* Find block name. */
4643 for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
4644 continue;
4646 /* Save all values for later tagging. */
4647 linebuffer_setlen (&tline, lb.len);
4648 strcpy (tline.buffer, lb.buffer);
4649 save_lineno = lineno;
4650 save_lcno = linecharno;
4651 name = tline.buffer + (dbp - lb.buffer);
4652 namelen = cp - dbp;
4653 taglen = cp - lb.buffer + 1;
4655 dbp = cp; /* set dbp to e-o-token */
4656 get_tagname = FALSE;
4657 found_tag = TRUE;
4658 continue;
4660 /* And proceed to check for "extern". */
4662 else if (!incomment && !inquote && !found_tag)
4664 /* Check for proc/fn keywords. */
4665 switch (lowcase (c))
4667 case 'p':
4668 if (nocase_tail ("rocedure")) /* c = 'p', dbp has advanced */
4669 get_tagname = TRUE;
4670 continue;
4671 case 'f':
4672 if (nocase_tail ("unction"))
4673 get_tagname = TRUE;
4674 continue;
4677 } /* while not eof */
4679 free (tline.buffer);
4684 * Lisp tag functions
4685 * look for (def or (DEF, quote or QUOTE
4688 static void L_getit __P((void));
4690 static void
4691 L_getit ()
4693 if (*dbp == '\'') /* Skip prefix quote */
4694 dbp++;
4695 else if (*dbp == '(')
4697 dbp++;
4698 /* Try to skip "(quote " */
4699 if (!LOOKING_AT (dbp, "quote") && !LOOKING_AT (dbp, "QUOTE"))
4700 /* Ok, then skip "(" before name in (defstruct (foo)) */
4701 dbp = skip_spaces (dbp);
4703 get_tag (dbp, NULL);
4706 static void
4707 Lisp_functions (inf)
4708 FILE *inf;
4710 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4712 if (dbp[0] != '(')
4713 continue;
4715 if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
4717 dbp = skip_non_spaces (dbp);
4718 dbp = skip_spaces (dbp);
4719 L_getit ();
4721 else
4723 /* Check for (foo::defmumble name-defined ... */
4725 dbp++;
4726 while (!notinname (*dbp) && *dbp != ':');
4727 if (*dbp == ':')
4730 dbp++;
4731 while (*dbp == ':');
4733 if (strneq (dbp, "def", 3) || strneq (dbp, "DEF", 3))
4735 dbp = skip_non_spaces (dbp);
4736 dbp = skip_spaces (dbp);
4737 L_getit ();
4746 * Postscript tag functions
4747 * Just look for lines where the first character is '/'
4748 * Also look at "defineps" for PSWrap
4749 * Ideas by:
4750 * Richard Mlynarik <mly@adoc.xerox.com> (1997)
4751 * Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
4753 static void
4754 Postscript_functions (inf)
4755 FILE *inf;
4757 register char *bp, *ep;
4759 LOOP_ON_INPUT_LINES (inf, lb, bp)
4761 if (bp[0] == '/')
4763 for (ep = bp+1;
4764 *ep != '\0' && *ep != ' ' && *ep != '{';
4765 ep++)
4766 continue;
4767 make_tag (bp, ep - bp, TRUE,
4768 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4770 else if (LOOKING_AT (bp, "defineps"))
4771 get_tag (bp, NULL);
4777 * Scheme tag functions
4778 * look for (def... xyzzy
4779 * (def... (xyzzy
4780 * (def ... ((...(xyzzy ....
4781 * (set! xyzzy
4782 * Original code by Ken Haase (1985?)
4785 static void
4786 Scheme_functions (inf)
4787 FILE *inf;
4789 register char *bp;
4791 LOOP_ON_INPUT_LINES (inf, lb, bp)
4793 if (strneq (bp, "(def", 4) || strneq (bp, "(DEF", 4))
4795 bp = skip_non_spaces (bp+4);
4796 /* Skip over open parens and white space */
4797 while (notinname (*bp))
4798 bp++;
4799 get_tag (bp, NULL);
4801 if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))
4802 get_tag (bp, NULL);
4807 /* Find tags in TeX and LaTeX input files. */
4809 /* TEX_toktab is a table of TeX control sequences that define tags.
4810 * Each entry records one such control sequence.
4812 * Original code from who knows whom.
4813 * Ideas by:
4814 * Stefan Monnier (2002)
4817 static linebuffer *TEX_toktab = NULL; /* Table with tag tokens */
4819 /* Default set of control sequences to put into TEX_toktab.
4820 The value of environment var TEXTAGS is prepended to this. */
4821 static char *TEX_defenv = "\
4822 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4823 :part:appendix:entry:index:def\
4824 :newcommand:renewcommand:newenvironment:renewenvironment";
4826 static void TEX_mode __P((FILE *));
4827 static void TEX_decode_env __P((char *, char *));
4829 static char TEX_esc = '\\';
4830 static char TEX_opgrp = '{';
4831 static char TEX_clgrp = '}';
4834 * TeX/LaTeX scanning loop.
4836 static void
4837 TeX_commands (inf)
4838 FILE *inf;
4840 char *cp;
4841 linebuffer *key;
4843 /* Select either \ or ! as escape character. */
4844 TEX_mode (inf);
4846 /* Initialize token table once from environment. */
4847 if (TEX_toktab == NULL)
4848 TEX_decode_env ("TEXTAGS", TEX_defenv);
4850 LOOP_ON_INPUT_LINES (inf, lb, cp)
4852 /* Look at each TEX keyword in line. */
4853 for (;;)
4855 /* Look for a TEX escape. */
4856 while (*cp++ != TEX_esc)
4857 if (cp[-1] == '\0' || cp[-1] == '%')
4858 goto tex_next_line;
4860 for (key = TEX_toktab; key->buffer != NULL; key++)
4861 if (strneq (cp, key->buffer, key->len))
4863 register char *p;
4864 int namelen, linelen;
4865 bool opgrp = FALSE;
4867 cp = skip_spaces (cp + key->len);
4868 if (*cp == TEX_opgrp)
4870 opgrp = TRUE;
4871 cp++;
4873 for (p = cp;
4874 (!iswhite (*p) && *p != '#' &&
4875 *p != TEX_opgrp && *p != TEX_clgrp);
4876 p++)
4877 continue;
4878 namelen = p - cp;
4879 linelen = lb.len;
4880 if (!opgrp || *p == TEX_clgrp)
4882 while (*p != '\0' && *p != TEX_opgrp && *p != TEX_clgrp)
4883 *p++;
4884 linelen = p - lb.buffer + 1;
4886 make_tag (cp, namelen, TRUE,
4887 lb.buffer, linelen, lineno, linecharno);
4888 goto tex_next_line; /* We only tag a line once */
4891 tex_next_line:
4896 #define TEX_LESC '\\'
4897 #define TEX_SESC '!'
4899 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4900 chars accordingly. */
4901 static void
4902 TEX_mode (inf)
4903 FILE *inf;
4905 int c;
4907 while ((c = getc (inf)) != EOF)
4909 /* Skip to next line if we hit the TeX comment char. */
4910 if (c == '%')
4911 while (c != '\n')
4912 c = getc (inf);
4913 else if (c == TEX_LESC || c == TEX_SESC )
4914 break;
4917 if (c == TEX_LESC)
4919 TEX_esc = TEX_LESC;
4920 TEX_opgrp = '{';
4921 TEX_clgrp = '}';
4923 else
4925 TEX_esc = TEX_SESC;
4926 TEX_opgrp = '<';
4927 TEX_clgrp = '>';
4929 /* If the input file is compressed, inf is a pipe, and rewind may fail.
4930 No attempt is made to correct the situation. */
4931 rewind (inf);
4934 /* Read environment and prepend it to the default string.
4935 Build token table. */
4936 static void
4937 TEX_decode_env (evarname, defenv)
4938 char *evarname;
4939 char *defenv;
4941 register char *env, *p;
4942 int i, len;
4944 /* Append default string to environment. */
4945 env = getenv (evarname);
4946 if (!env)
4947 env = defenv;
4948 else
4950 char *oldenv = env;
4951 env = concat (oldenv, defenv, "");
4954 /* Allocate a token table */
4955 for (len = 1, p = env; p;)
4956 if ((p = etags_strchr (p, ':')) && *++p != '\0')
4957 len++;
4958 TEX_toktab = xnew (len, linebuffer);
4960 /* Unpack environment string into token table. Be careful about */
4961 /* zero-length strings (leading ':', "::" and trailing ':') */
4962 for (i = 0; *env != '\0';)
4964 p = etags_strchr (env, ':');
4965 if (!p) /* End of environment string. */
4966 p = env + strlen (env);
4967 if (p - env > 0)
4968 { /* Only non-zero strings. */
4969 TEX_toktab[i].buffer = savenstr (env, p - env);
4970 TEX_toktab[i].len = p - env;
4971 i++;
4973 if (*p)
4974 env = p + 1;
4975 else
4977 TEX_toktab[i].buffer = NULL; /* Mark end of table. */
4978 TEX_toktab[i].len = 0;
4979 break;
4985 /* Texinfo support. Dave Love, Mar. 2000. */
4986 static void
4987 Texinfo_nodes (inf)
4988 FILE * inf;
4990 char *cp, *start;
4991 LOOP_ON_INPUT_LINES (inf, lb, cp)
4992 if (LOOKING_AT (cp, "@node"))
4994 start = cp;
4995 while (*cp != '\0' && *cp != ',')
4996 cp++;
4997 make_tag (start, cp - start, TRUE,
4998 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5003 /* Similar to LOOKING_AT but does not use notinname, does not skip */
5004 #define LOOKING_AT_NOCASE(cp, kw) /* kw is a constant string */ \
5005 (strncaseeq ((cp), kw, sizeof(kw)-1) /* cp points at kw */ \
5006 && ((cp) += sizeof(kw)-1)) /* skip spaces */
5009 * HTML support.
5010 * Contents of <title>, <h1>, <h2>, <h3> are tags.
5011 * Contents of <a name=xxx> are tags with name xxx.
5013 * Francesco Potortì, 2002.
5015 static void
5016 HTML_labels (inf)
5017 FILE * inf;
5019 bool getnext = FALSE; /* next text outside of HTML tags is a tag */
5020 bool skiptag = FALSE; /* skip to the end of the current HTML tag */
5021 bool intag = FALSE; /* inside an html tag, looking for ID= */
5022 bool inanchor = FALSE; /* when INTAG, is an anchor, look for NAME= */
5023 char *end;
5026 linebuffer_setlen (&token_name, 0); /* no name in buffer */
5028 LOOP_ON_INPUT_LINES (inf, lb, dbp)
5029 for (;;) /* loop on the same line */
5031 if (skiptag) /* skip HTML tag */
5033 while (*dbp != '\0' && *dbp != '>')
5034 dbp++;
5035 if (*dbp == '>')
5037 dbp += 1;
5038 skiptag = FALSE;
5039 continue; /* look on the same line */
5041 break; /* go to next line */
5044 else if (intag) /* look for "name=" or "id=" */
5046 while (*dbp != '\0' && *dbp != '>'
5047 && lowcase (*dbp) != 'n' && lowcase (*dbp) != 'i')
5048 dbp++;
5049 if (*dbp == '\0')
5050 break; /* go to next line */
5051 if (*dbp == '>')
5053 dbp += 1;
5054 intag = FALSE;
5055 continue; /* look on the same line */
5057 if ((inanchor && LOOKING_AT_NOCASE (dbp, "name="))
5058 || LOOKING_AT_NOCASE (dbp, "id="))
5060 bool quoted = (dbp[0] == '"');
5062 if (quoted)
5063 for (end = ++dbp; *end != '\0' && *end != '"'; end++)
5064 continue;
5065 else
5066 for (end = dbp; *end != '\0' && intoken (*end); end++)
5067 continue;
5068 linebuffer_setlen (&token_name, end - dbp);
5069 strncpy (token_name.buffer, dbp, end - dbp);
5070 token_name.buffer[end - dbp] = '\0';
5072 dbp = end;
5073 intag = FALSE; /* we found what we looked for */
5074 skiptag = TRUE; /* skip to the end of the tag */
5075 getnext = TRUE; /* then grab the text */
5076 continue; /* look on the same line */
5078 dbp += 1;
5081 else if (getnext) /* grab next tokens and tag them */
5083 dbp = skip_spaces (dbp);
5084 if (*dbp == '\0')
5085 break; /* go to next line */
5086 if (*dbp == '<')
5088 intag = TRUE;
5089 inanchor = (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]));
5090 continue; /* look on the same line */
5093 for (end = dbp + 1; *end != '\0' && *end != '<'; end++)
5094 continue;
5095 make_tag (token_name.buffer, token_name.len, TRUE,
5096 dbp, end - dbp, lineno, linecharno);
5097 linebuffer_setlen (&token_name, 0); /* no name in buffer */
5098 getnext = FALSE;
5099 break; /* go to next line */
5102 else /* look for an interesting HTML tag */
5104 while (*dbp != '\0' && *dbp != '<')
5105 dbp++;
5106 if (*dbp == '\0')
5107 break; /* go to next line */
5108 intag = TRUE;
5109 if (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]))
5111 inanchor = TRUE;
5112 continue; /* look on the same line */
5114 else if (LOOKING_AT_NOCASE (dbp, "<title>")
5115 || LOOKING_AT_NOCASE (dbp, "<h1>")
5116 || LOOKING_AT_NOCASE (dbp, "<h2>")
5117 || LOOKING_AT_NOCASE (dbp, "<h3>"))
5119 intag = FALSE;
5120 getnext = TRUE;
5121 continue; /* look on the same line */
5123 dbp += 1;
5130 * Prolog support
5132 * Assumes that the predicate or rule starts at column 0.
5133 * Only the first clause of a predicate or rule is added.
5134 * Original code by Sunichirou Sugou (1989)
5135 * Rewritten by Anders Lindgren (1996)
5137 static int prolog_pr __P((char *, char *));
5138 static void prolog_skip_comment __P((linebuffer *, FILE *));
5139 static int prolog_atom __P((char *, int));
5141 static void
5142 Prolog_functions (inf)
5143 FILE *inf;
5145 char *cp, *last;
5146 int len;
5147 int allocated;
5149 allocated = 0;
5150 len = 0;
5151 last = NULL;
5153 LOOP_ON_INPUT_LINES (inf, lb, cp)
5155 if (cp[0] == '\0') /* Empty line */
5156 continue;
5157 else if (iswhite (cp[0])) /* Not a predicate */
5158 continue;
5159 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
5160 prolog_skip_comment (&lb, inf);
5161 else if ((len = prolog_pr (cp, last)) > 0)
5163 /* Predicate or rule. Store the function name so that we
5164 only generate a tag for the first clause. */
5165 if (last == NULL)
5166 last = xnew(len + 1, char);
5167 else if (len + 1 > allocated)
5168 xrnew (last, len + 1, char);
5169 allocated = len + 1;
5170 strncpy (last, cp, len);
5171 last[len] = '\0';
5177 static void
5178 prolog_skip_comment (plb, inf)
5179 linebuffer *plb;
5180 FILE *inf;
5182 char *cp;
5186 for (cp = plb->buffer; *cp != '\0'; cp++)
5187 if (cp[0] == '*' && cp[1] == '/')
5188 return;
5189 readline (plb, inf);
5191 while (!feof(inf));
5195 * A predicate or rule definition is added if it matches:
5196 * <beginning of line><Prolog Atom><whitespace>(
5197 * or <beginning of line><Prolog Atom><whitespace>:-
5199 * It is added to the tags database if it doesn't match the
5200 * name of the previous clause header.
5202 * Return the size of the name of the predicate or rule, or 0 if no
5203 * header was found.
5205 static int
5206 prolog_pr (s, last)
5207 char *s;
5208 char *last; /* Name of last clause. */
5210 int pos;
5211 int len;
5213 pos = prolog_atom (s, 0);
5214 if (pos < 1)
5215 return 0;
5217 len = pos;
5218 pos = skip_spaces (s + pos) - s;
5220 if ((s[pos] == '.'
5221 || (s[pos] == '(' && (pos += 1))
5222 || (s[pos] == ':' && s[pos + 1] == '-' && (pos += 2)))
5223 && (last == NULL /* save only the first clause */
5224 || len != strlen (last)
5225 || !strneq (s, last, len)))
5227 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5228 return len;
5230 else
5231 return 0;
5235 * Consume a Prolog atom.
5236 * Return the number of bytes consumed, or -1 if there was an error.
5238 * A prolog atom, in this context, could be one of:
5239 * - An alphanumeric sequence, starting with a lower case letter.
5240 * - A quoted arbitrary string. Single quotes can escape themselves.
5241 * Backslash quotes everything.
5243 static int
5244 prolog_atom (s, pos)
5245 char *s;
5246 int pos;
5248 int origpos;
5250 origpos = pos;
5252 if (ISLOWER(s[pos]) || (s[pos] == '_'))
5254 /* The atom is unquoted. */
5255 pos++;
5256 while (ISALNUM(s[pos]) || (s[pos] == '_'))
5258 pos++;
5260 return pos - origpos;
5262 else if (s[pos] == '\'')
5264 pos++;
5266 for (;;)
5268 if (s[pos] == '\'')
5270 pos++;
5271 if (s[pos] != '\'')
5272 break;
5273 pos++; /* A double quote */
5275 else if (s[pos] == '\0')
5276 /* Multiline quoted atoms are ignored. */
5277 return -1;
5278 else if (s[pos] == '\\')
5280 if (s[pos+1] == '\0')
5281 return -1;
5282 pos += 2;
5284 else
5285 pos++;
5287 return pos - origpos;
5289 else
5290 return -1;
5295 * Support for Erlang
5297 * Generates tags for functions, defines, and records.
5298 * Assumes that Erlang functions start at column 0.
5299 * Original code by Anders Lindgren (1996)
5301 static int erlang_func __P((char *, char *));
5302 static void erlang_attribute __P((char *));
5303 static int erlang_atom __P((char *));
5305 static void
5306 Erlang_functions (inf)
5307 FILE *inf;
5309 char *cp, *last;
5310 int len;
5311 int allocated;
5313 allocated = 0;
5314 len = 0;
5315 last = NULL;
5317 LOOP_ON_INPUT_LINES (inf, lb, cp)
5319 if (cp[0] == '\0') /* Empty line */
5320 continue;
5321 else if (iswhite (cp[0])) /* Not function nor attribute */
5322 continue;
5323 else if (cp[0] == '%') /* comment */
5324 continue;
5325 else if (cp[0] == '"') /* Sometimes, strings start in column one */
5326 continue;
5327 else if (cp[0] == '-') /* attribute, e.g. "-define" */
5329 erlang_attribute (cp);
5330 last = NULL;
5332 else if ((len = erlang_func (cp, last)) > 0)
5335 * Function. Store the function name so that we only
5336 * generates a tag for the first clause.
5338 if (last == NULL)
5339 last = xnew (len + 1, char);
5340 else if (len + 1 > allocated)
5341 xrnew (last, len + 1, char);
5342 allocated = len + 1;
5343 strncpy (last, cp, len);
5344 last[len] = '\0';
5351 * A function definition is added if it matches:
5352 * <beginning of line><Erlang Atom><whitespace>(
5354 * It is added to the tags database if it doesn't match the
5355 * name of the previous clause header.
5357 * Return the size of the name of the function, or 0 if no function
5358 * was found.
5360 static int
5361 erlang_func (s, last)
5362 char *s;
5363 char *last; /* Name of last clause. */
5365 int pos;
5366 int len;
5368 pos = erlang_atom (s);
5369 if (pos < 1)
5370 return 0;
5372 len = pos;
5373 pos = skip_spaces (s + pos) - s;
5375 /* Save only the first clause. */
5376 if (s[pos++] == '('
5377 && (last == NULL
5378 || len != (int)strlen (last)
5379 || !strneq (s, last, len)))
5381 make_tag (s, len, TRUE, s, pos, lineno, linecharno);
5382 return len;
5385 return 0;
5390 * Handle attributes. Currently, tags are generated for defines
5391 * and records.
5393 * They are on the form:
5394 * -define(foo, bar).
5395 * -define(Foo(M, N), M+N).
5396 * -record(graph, {vtab = notable, cyclic = true}).
5398 static void
5399 erlang_attribute (s)
5400 char *s;
5402 char *cp = s;
5404 if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
5405 && *cp++ == '(')
5407 int len = erlang_atom (skip_spaces (cp));
5408 if (len > 0)
5409 make_tag (cp, len, TRUE, s, cp + len - s, lineno, linecharno);
5411 return;
5416 * Consume an Erlang atom (or variable).
5417 * Return the number of bytes consumed, or -1 if there was an error.
5419 static int
5420 erlang_atom (s)
5421 char *s;
5423 int pos = 0;
5425 if (ISALPHA (s[pos]) || s[pos] == '_')
5427 /* The atom is unquoted. */
5429 pos++;
5430 while (ISALNUM (s[pos]) || s[pos] == '_');
5432 else if (s[pos] == '\'')
5434 for (pos++; s[pos] != '\''; pos++)
5435 if (s[pos] == '\0' /* multiline quoted atoms are ignored */
5436 || (s[pos] == '\\' && s[++pos] == '\0'))
5437 return 0;
5438 pos++;
5441 return pos;
5445 #ifdef ETAGS_REGEXPS
5447 static char *scan_separators __P((char *));
5448 static void add_regex __P((char *, language *));
5449 static char *substitute __P((char *, char *, struct re_registers *));
5452 * Take a string like "/blah/" and turn it into "blah", verifying
5453 * that the first and last characters are the same, and handling
5454 * quoted separator characters. Actually, stops on the occurrence of
5455 * an unquoted separator. Also process \t, \n, etc. and turn into
5456 * appropriate characters. Works in place. Null terminates name string.
5457 * Returns pointer to terminating separator, or NULL for
5458 * unterminated regexps.
5460 static char *
5461 scan_separators (name)
5462 char *name;
5464 char sep = name[0];
5465 char *copyto = name;
5466 bool quoted = FALSE;
5468 for (++name; *name != '\0'; ++name)
5470 if (quoted)
5472 switch (*name)
5474 case 'a': *copyto++ = '\007'; break; /* BEL (bell) */
5475 case 'b': *copyto++ = '\b'; break; /* BS (back space) */
5476 case 'd': *copyto++ = 0177; break; /* DEL (delete) */
5477 case 'e': *copyto++ = 033; break; /* ESC (delete) */
5478 case 'f': *copyto++ = '\f'; break; /* FF (form feed) */
5479 case 'n': *copyto++ = '\n'; break; /* NL (new line) */
5480 case 'r': *copyto++ = '\r'; break; /* CR (carriage return) */
5481 case 't': *copyto++ = '\t'; break; /* TAB (horizontal tab) */
5482 case 'v': *copyto++ = '\v'; break; /* VT (vertical tab) */
5483 default:
5484 if (*name == sep)
5485 *copyto++ = sep;
5486 else
5488 /* Something else is quoted, so preserve the quote. */
5489 *copyto++ = '\\';
5490 *copyto++ = *name;
5492 break;
5494 quoted = FALSE;
5496 else if (*name == '\\')
5497 quoted = TRUE;
5498 else if (*name == sep)
5499 break;
5500 else
5501 *copyto++ = *name;
5503 if (*name != sep)
5504 name = NULL; /* signal unterminated regexp */
5506 /* Terminate copied string. */
5507 *copyto = '\0';
5508 return name;
5511 /* Look at the argument of --regex or --no-regex and do the right
5512 thing. Same for each line of a regexp file. */
5513 static void
5514 analyse_regex (regex_arg)
5515 char *regex_arg;
5517 if (regex_arg == NULL)
5519 free_regexps (); /* --no-regex: remove existing regexps */
5520 return;
5523 /* A real --regexp option or a line in a regexp file. */
5524 switch (regex_arg[0])
5526 /* Comments in regexp file or null arg to --regex. */
5527 case '\0':
5528 case ' ':
5529 case '\t':
5530 break;
5532 /* Read a regex file. This is recursive and may result in a
5533 loop, which will stop when the file descriptors are exhausted. */
5534 case '@':
5536 FILE *regexfp;
5537 linebuffer regexbuf;
5538 char *regexfile = regex_arg + 1;
5540 /* regexfile is a file containing regexps, one per line. */
5541 regexfp = fopen (regexfile, "r");
5542 if (regexfp == NULL)
5544 pfatal (regexfile);
5545 return;
5547 linebuffer_init (&regexbuf);
5548 while (readline_internal (&regexbuf, regexfp) > 0)
5549 analyse_regex (regexbuf.buffer);
5550 free (regexbuf.buffer);
5551 fclose (regexfp);
5553 break;
5555 /* Regexp to be used for a specific language only. */
5556 case '{':
5558 language *lang;
5559 char *lang_name = regex_arg + 1;
5560 char *cp;
5562 for (cp = lang_name; *cp != '}'; cp++)
5563 if (*cp == '\0')
5565 error ("unterminated language name in regex: %s", regex_arg);
5566 return;
5568 *cp++ = '\0';
5569 lang = get_language_from_langname (lang_name);
5570 if (lang == NULL)
5571 return;
5572 add_regex (cp, lang);
5574 break;
5576 /* Regexp to be used for any language. */
5577 default:
5578 add_regex (regex_arg, NULL);
5579 break;
5583 /* Separate the regexp pattern, compile it,
5584 and care for optional name and modifiers. */
5585 static void
5586 add_regex (regexp_pattern, lang)
5587 char *regexp_pattern;
5588 language *lang;
5590 static struct re_pattern_buffer zeropattern;
5591 char sep, *pat, *name, *modifiers;
5592 const char *err;
5593 struct re_pattern_buffer *patbuf;
5594 regexp *rp;
5595 bool
5596 force_explicit_name = TRUE, /* do not use implicit tag names */
5597 ignore_case = FALSE, /* case is significant */
5598 multi_line = FALSE, /* matches are done one line at a time */
5599 single_line = FALSE; /* dot does not match newline */
5602 if (strlen(regexp_pattern) < 3)
5604 error ("null regexp", (char *)NULL);
5605 return;
5607 sep = regexp_pattern[0];
5608 name = scan_separators (regexp_pattern);
5609 if (name == NULL)
5611 error ("%s: unterminated regexp", regexp_pattern);
5612 return;
5614 if (name[1] == sep)
5616 error ("null name for regexp \"%s\"", regexp_pattern);
5617 return;
5619 modifiers = scan_separators (name);
5620 if (modifiers == NULL) /* no terminating separator --> no name */
5622 modifiers = name;
5623 name = "";
5625 else
5626 modifiers += 1; /* skip separator */
5628 /* Parse regex modifiers. */
5629 for (; modifiers[0] != '\0'; modifiers++)
5630 switch (modifiers[0])
5632 case 'N':
5633 if (modifiers == name)
5634 error ("forcing explicit tag name but no name, ignoring", NULL);
5635 force_explicit_name = TRUE;
5636 break;
5637 case 'i':
5638 ignore_case = TRUE;
5639 break;
5640 case 's':
5641 single_line = TRUE;
5642 /* FALLTHRU */
5643 case 'm':
5644 multi_line = TRUE;
5645 need_filebuf = TRUE;
5646 break;
5647 default:
5649 char wrongmod [2];
5650 wrongmod[0] = modifiers[0];
5651 wrongmod[1] = '\0';
5652 error ("invalid regexp modifier `%s', ignoring", wrongmod);
5654 break;
5657 patbuf = xnew (1, struct re_pattern_buffer);
5658 *patbuf = zeropattern;
5659 if (ignore_case)
5661 static char lc_trans[CHARS];
5662 int i;
5663 for (i = 0; i < CHARS; i++)
5664 lc_trans[i] = lowcase (i);
5665 patbuf->translate = lc_trans; /* translation table to fold case */
5668 if (multi_line)
5669 pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
5670 else
5671 pat = regexp_pattern;
5673 if (single_line)
5674 re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
5675 else
5676 re_set_syntax (RE_SYNTAX_EMACS);
5678 err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
5679 if (multi_line)
5680 free (pat);
5681 if (err != NULL)
5683 error ("%s while compiling pattern", err);
5684 return;
5687 rp = p_head;
5688 p_head = xnew (1, regexp);
5689 p_head->pattern = savestr (regexp_pattern);
5690 p_head->p_next = rp;
5691 p_head->lang = lang;
5692 p_head->pat = patbuf;
5693 p_head->name = savestr (name);
5694 p_head->error_signaled = FALSE;
5695 p_head->force_explicit_name = force_explicit_name;
5696 p_head->ignore_case = ignore_case;
5697 p_head->multi_line = multi_line;
5701 * Do the substitutions indicated by the regular expression and
5702 * arguments.
5704 static char *
5705 substitute (in, out, regs)
5706 char *in, *out;
5707 struct re_registers *regs;
5709 char *result, *t;
5710 int size, dig, diglen;
5712 result = NULL;
5713 size = strlen (out);
5715 /* Pass 1: figure out how much to allocate by finding all \N strings. */
5716 if (out[size - 1] == '\\')
5717 fatal ("pattern error in \"%s\"", out);
5718 for (t = etags_strchr (out, '\\');
5719 t != NULL;
5720 t = etags_strchr (t + 2, '\\'))
5721 if (ISDIGIT (t[1]))
5723 dig = t[1] - '0';
5724 diglen = regs->end[dig] - regs->start[dig];
5725 size += diglen - 2;
5727 else
5728 size -= 1;
5730 /* Allocate space and do the substitutions. */
5731 assert (size >= 0);
5732 result = xnew (size + 1, char);
5734 for (t = result; *out != '\0'; out++)
5735 if (*out == '\\' && ISDIGIT (*++out))
5737 dig = *out - '0';
5738 diglen = regs->end[dig] - regs->start[dig];
5739 strncpy (t, in + regs->start[dig], diglen);
5740 t += diglen;
5742 else
5743 *t++ = *out;
5744 *t = '\0';
5746 assert (t <= result + size);
5747 assert (t - result == (int)strlen (result));
5749 return result;
5752 /* Deallocate all regexps. */
5753 static void
5754 free_regexps ()
5756 regexp *rp;
5757 while (p_head != NULL)
5759 rp = p_head->p_next;
5760 free (p_head->pattern);
5761 free (p_head->name);
5762 free (p_head);
5763 p_head = rp;
5765 return;
5769 * Reads the whole file as a single string from `filebuf' and looks for
5770 * multi-line regular expressions, creating tags on matches.
5771 * readline already dealt with normal regexps.
5773 * Idea by Ben Wing <ben@666.com> (2002).
5775 static void
5776 regex_tag_multiline ()
5778 char *buffer = filebuf.buffer;
5779 regexp *rp;
5780 char *name;
5782 for (rp = p_head; rp != NULL; rp = rp->p_next)
5784 int match = 0;
5786 if (!rp->multi_line)
5787 continue; /* skip normal regexps */
5789 /* Generic initialisations before parsing file from memory. */
5790 lineno = 1; /* reset global line number */
5791 charno = 0; /* reset global char number */
5792 linecharno = 0; /* reset global char number of line start */
5794 /* Only use generic regexps or those for the current language. */
5795 if (rp->lang != NULL && rp->lang != curfdp->lang)
5796 continue;
5798 while (match >= 0 && match < filebuf.len)
5800 match = re_search (rp->pat, buffer, filebuf.len, charno,
5801 filebuf.len - match, &rp->regs);
5802 switch (match)
5804 case -2:
5805 /* Some error. */
5806 if (!rp->error_signaled)
5808 error ("regexp stack overflow while matching \"%s\"",
5809 rp->pattern);
5810 rp->error_signaled = TRUE;
5812 break;
5813 case -1:
5814 /* No match. */
5815 break;
5816 default:
5817 if (match == rp->regs.end[0])
5819 if (!rp->error_signaled)
5821 error ("regexp matches the empty string: \"%s\"",
5822 rp->pattern);
5823 rp->error_signaled = TRUE;
5825 match = -3; /* exit from while loop */
5826 break;
5829 /* Match occurred. Construct a tag. */
5830 while (charno < rp->regs.end[0])
5831 if (buffer[charno++] == '\n')
5832 lineno++, linecharno = charno;
5833 name = rp->name;
5834 if (name[0] == '\0')
5835 name = NULL;
5836 else /* make a named tag */
5837 name = substitute (buffer, rp->name, &rp->regs);
5838 if (rp->force_explicit_name)
5839 /* Force explicit tag name, if a name is there. */
5840 pfnote (name, TRUE, buffer + linecharno,
5841 charno - linecharno + 1, lineno, linecharno);
5842 else
5843 make_tag (name, strlen (name), TRUE, buffer + linecharno,
5844 charno - linecharno + 1, lineno, linecharno);
5845 break;
5851 #endif /* ETAGS_REGEXPS */
5854 static bool
5855 nocase_tail (cp)
5856 char *cp;
5858 register int len = 0;
5860 while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
5861 cp++, len++;
5862 if (*cp == '\0' && !intoken (dbp[len]))
5864 dbp += len;
5865 return TRUE;
5867 return FALSE;
5870 static void
5871 get_tag (bp, namepp)
5872 register char *bp;
5873 char **namepp;
5875 register char *cp = bp;
5877 if (*bp != '\0')
5879 /* Go till you get to white space or a syntactic break */
5880 for (cp = bp + 1; !notinname (*cp); cp++)
5881 continue;
5882 make_tag (bp, cp - bp, TRUE,
5883 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
5886 if (namepp != NULL)
5887 *namepp = savenstr (bp, cp - bp);
5891 * Read a line of text from `stream' into `lbp', excluding the
5892 * newline or CR-NL, if any. Return the number of characters read from
5893 * `stream', which is the length of the line including the newline.
5895 * On DOS or Windows we do not count the CR character, if any before the
5896 * NL, in the returned length; this mirrors the behavior of Emacs on those
5897 * platforms (for text files, it translates CR-NL to NL as it reads in the
5898 * file).
5900 * If multi-line regular expressions are requested, each line read is
5901 * appended to `filebuf'.
5903 static long
5904 readline_internal (lbp, stream)
5905 linebuffer *lbp;
5906 register FILE *stream;
5908 char *buffer = lbp->buffer;
5909 register char *p = lbp->buffer;
5910 register char *pend;
5911 int chars_deleted;
5913 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
5915 for (;;)
5917 register int c = getc (stream);
5918 if (p == pend)
5920 /* We're at the end of linebuffer: expand it. */
5921 lbp->size *= 2;
5922 xrnew (buffer, lbp->size, char);
5923 p += buffer - lbp->buffer;
5924 pend = buffer + lbp->size;
5925 lbp->buffer = buffer;
5927 if (c == EOF)
5929 *p = '\0';
5930 chars_deleted = 0;
5931 break;
5933 if (c == '\n')
5935 if (p > buffer && p[-1] == '\r')
5937 p -= 1;
5938 #ifdef DOS_NT
5939 /* Assume CRLF->LF translation will be performed by Emacs
5940 when loading this file, so CRs won't appear in the buffer.
5941 It would be cleaner to compensate within Emacs;
5942 however, Emacs does not know how many CRs were deleted
5943 before any given point in the file. */
5944 chars_deleted = 1;
5945 #else
5946 chars_deleted = 2;
5947 #endif
5949 else
5951 chars_deleted = 1;
5953 *p = '\0';
5954 break;
5956 *p++ = c;
5958 lbp->len = p - buffer;
5960 if (need_filebuf /* we need filebuf for multi-line regexps */
5961 && chars_deleted > 0) /* not at EOF */
5963 while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
5965 /* Expand filebuf. */
5966 filebuf.size *= 2;
5967 xrnew (filebuf.buffer, filebuf.size, char);
5969 strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
5970 filebuf.len += lbp->len;
5971 filebuf.buffer[filebuf.len++] = '\n';
5972 filebuf.buffer[filebuf.len] = '\0';
5975 return lbp->len + chars_deleted;
5979 * Like readline_internal, above, but in addition try to match the
5980 * input line against relevant regular expressions and manage #line
5981 * directives.
5983 static void
5984 readline (lbp, stream)
5985 linebuffer *lbp;
5986 FILE *stream;
5988 long result;
5990 linecharno = charno; /* update global char number of line start */
5991 result = readline_internal (lbp, stream); /* read line */
5992 lineno += 1; /* increment global line number */
5993 charno += result; /* increment global char number */
5995 /* Honour #line directives. */
5996 if (!no_line_directive)
5998 static bool discard_until_line_directive;
6000 /* Check whether this is a #line directive. */
6001 if (result > 12 && strneq (lbp->buffer, "#line ", 6))
6003 int start, lno;
6005 if (DEBUG) start = 0; /* shut up the compiler */
6006 if (sscanf (lbp->buffer, "#line %d \"%n", &lno, &start) == 1)
6008 char *endp = lbp->buffer + start;
6010 assert (start > 0);
6011 while ((endp = etags_strchr (endp, '"')) != NULL
6012 && endp[-1] == '\\')
6013 endp++;
6014 if (endp != NULL)
6015 /* Ok, this is a real #line directive. Let's deal with it. */
6017 char *taggedabsname; /* absolute name of original file */
6018 char *taggedfname; /* name of original file as given */
6019 char *name; /* temp var */
6021 discard_until_line_directive = FALSE; /* found it */
6022 name = lbp->buffer + start;
6023 *endp = '\0';
6024 canonicalize_filename (name); /* for DOS */
6025 taggedabsname = absolute_filename (name, curfdp->infabsdir);
6026 if (filename_is_absolute (name)
6027 || filename_is_absolute (curfdp->infname))
6028 taggedfname = savestr (taggedabsname);
6029 else
6030 taggedfname = relative_filename (taggedabsname,tagfiledir);
6032 if (streq (curfdp->taggedfname, taggedfname))
6033 /* The #line directive is only a line number change. We
6034 deal with this afterwards. */
6035 free (taggedfname);
6036 else
6037 /* The tags following this #line directive should be
6038 attributed to taggedfname. In order to do this, set
6039 curfdp accordingly. */
6041 fdesc *fdp; /* file description pointer */
6043 /* Go look for a file description already set up for the
6044 file indicated in the #line directive. If there is
6045 one, use it from now until the next #line
6046 directive. */
6047 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6048 if (streq (fdp->infname, curfdp->infname)
6049 && streq (fdp->taggedfname, taggedfname))
6050 /* If we remove the second test above (after the &&)
6051 then all entries pertaining to the same file are
6052 coalesced in the tags file. If we use it, then
6053 entries pertaining to the same file but generated
6054 from different files (via #line directives) will
6055 go into separate sections in the tags file. These
6056 alternatives look equivalent. The first one
6057 destroys some apparently useless information. */
6059 curfdp = fdp;
6060 free (taggedfname);
6061 break;
6063 /* Else, if we already tagged the real file, skip all
6064 input lines until the next #line directive. */
6065 if (fdp == NULL) /* not found */
6066 for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
6067 if (streq (fdp->infabsname, taggedabsname))
6069 discard_until_line_directive = TRUE;
6070 free (taggedfname);
6071 break;
6073 /* Else create a new file description and use that from
6074 now on, until the next #line directive. */
6075 if (fdp == NULL) /* not found */
6077 fdp = fdhead;
6078 fdhead = xnew (1, fdesc);
6079 *fdhead = *curfdp; /* copy curr. file description */
6080 fdhead->next = fdp;
6081 fdhead->infname = savestr (curfdp->infname);
6082 fdhead->infabsname = savestr (curfdp->infabsname);
6083 fdhead->infabsdir = savestr (curfdp->infabsdir);
6084 fdhead->taggedfname = taggedfname;
6085 fdhead->usecharno = FALSE;
6086 fdhead->prop = NULL;
6087 fdhead->written = FALSE;
6088 curfdp = fdhead;
6091 free (taggedabsname);
6092 lineno = lno - 1;
6093 readline (lbp, stream);
6094 return;
6095 } /* if a real #line directive */
6096 } /* if #line is followed by a a number */
6097 } /* if line begins with "#line " */
6099 /* If we are here, no #line directive was found. */
6100 if (discard_until_line_directive)
6102 if (result > 0)
6104 /* Do a tail recursion on ourselves, thus discarding the contents
6105 of the line buffer. */
6106 readline (lbp, stream);
6107 return;
6109 /* End of file. */
6110 discard_until_line_directive = FALSE;
6111 return;
6113 } /* if #line directives should be considered */
6115 #ifdef ETAGS_REGEXPS
6117 int match;
6118 regexp *rp;
6119 char *name;
6121 /* Match against relevant regexps. */
6122 if (lbp->len > 0)
6123 for (rp = p_head; rp != NULL; rp = rp->p_next)
6125 /* Only use generic regexps or those for the current language.
6126 Also do not use multiline regexps, which is the job of
6127 regex_tag_multiline. */
6128 if ((rp->lang != NULL && rp->lang != fdhead->lang)
6129 || rp->multi_line)
6130 continue;
6132 match = re_match (rp->pat, lbp->buffer, lbp->len, 0, &rp->regs);
6133 switch (match)
6135 case -2:
6136 /* Some error. */
6137 if (!rp->error_signaled)
6139 error ("regexp stack overflow while matching \"%s\"",
6140 rp->pattern);
6141 rp->error_signaled = TRUE;
6143 break;
6144 case -1:
6145 /* No match. */
6146 break;
6147 case 0:
6148 /* Empty string matched. */
6149 if (!rp->error_signaled)
6151 error ("regexp matches the empty string: \"%s\"", rp->pattern);
6152 rp->error_signaled = TRUE;
6154 break;
6155 default:
6156 /* Match occurred. Construct a tag. */
6157 name = rp->name;
6158 if (name[0] == '\0')
6159 name = NULL;
6160 else /* make a named tag */
6161 name = substitute (lbp->buffer, rp->name, &rp->regs);
6162 if (rp->force_explicit_name)
6163 /* Force explicit tag name, if a name is there. */
6164 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
6165 else
6166 make_tag (name, strlen (name), TRUE,
6167 lbp->buffer, match, lineno, linecharno);
6168 break;
6172 #endif /* ETAGS_REGEXPS */
6177 * Return a pointer to a space of size strlen(cp)+1 allocated
6178 * with xnew where the string CP has been copied.
6180 static char *
6181 savestr (cp)
6182 char *cp;
6184 return savenstr (cp, strlen (cp));
6188 * Return a pointer to a space of size LEN+1 allocated with xnew where
6189 * the string CP has been copied for at most the first LEN characters.
6191 static char *
6192 savenstr (cp, len)
6193 char *cp;
6194 int len;
6196 register char *dp;
6198 dp = xnew (len + 1, char);
6199 strncpy (dp, cp, len);
6200 dp[len] = '\0';
6201 return dp;
6205 * Return the ptr in sp at which the character c last
6206 * appears; NULL if not found
6208 * Identical to POSIX strrchr, included for portability.
6210 static char *
6211 etags_strrchr (sp, c)
6212 register const char *sp;
6213 register int c;
6215 register const char *r;
6217 r = NULL;
6220 if (*sp == c)
6221 r = sp;
6222 } while (*sp++);
6223 return (char *)r;
6227 * Return the ptr in sp at which the character c first
6228 * appears; NULL if not found
6230 * Identical to POSIX strchr, included for portability.
6232 static char *
6233 etags_strchr (sp, c)
6234 register const char *sp;
6235 register int c;
6239 if (*sp == c)
6240 return (char *)sp;
6241 } while (*sp++);
6242 return NULL;
6246 * Compare two strings, ignoring case for alphabetic characters.
6248 * Same as BSD's strcasecmp, included for portability.
6250 static int
6251 etags_strcasecmp (s1, s2)
6252 register const char *s1;
6253 register const char *s2;
6255 while (*s1 != '\0'
6256 && (ISALPHA (*s1) && ISALPHA (*s2)
6257 ? lowcase (*s1) == lowcase (*s2)
6258 : *s1 == *s2))
6259 s1++, s2++;
6261 return (ISALPHA (*s1) && ISALPHA (*s2)
6262 ? lowcase (*s1) - lowcase (*s2)
6263 : *s1 - *s2);
6267 * Compare two strings, ignoring case for alphabetic characters.
6268 * Stop after a given number of characters
6270 * Same as BSD's strncasecmp, included for portability.
6272 static int
6273 etags_strncasecmp (s1, s2, n)
6274 register const char *s1;
6275 register const char *s2;
6276 register int n;
6278 while (*s1 != '\0' && n-- > 0
6279 && (ISALPHA (*s1) && ISALPHA (*s2)
6280 ? lowcase (*s1) == lowcase (*s2)
6281 : *s1 == *s2))
6282 s1++, s2++;
6284 if (n < 0)
6285 return 0;
6286 else
6287 return (ISALPHA (*s1) && ISALPHA (*s2)
6288 ? lowcase (*s1) - lowcase (*s2)
6289 : *s1 - *s2);
6292 /* Skip spaces, return new pointer. */
6293 static char *
6294 skip_spaces (cp)
6295 char *cp;
6297 while (iswhite (*cp))
6298 cp++;
6299 return cp;
6302 /* Skip non spaces, return new pointer. */
6303 static char *
6304 skip_non_spaces (cp)
6305 char *cp;
6307 while (*cp != '\0' && !iswhite (*cp))
6308 cp++;
6309 return cp;
6312 /* Print error message and exit. */
6313 void
6314 fatal (s1, s2)
6315 char *s1, *s2;
6317 error (s1, s2);
6318 exit (BAD);
6321 static void
6322 pfatal (s1)
6323 char *s1;
6325 perror (s1);
6326 exit (BAD);
6329 static void
6330 suggest_asking_for_help ()
6332 fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
6333 progname,
6334 #ifdef LONG_OPTIONS
6335 "--help"
6336 #else
6337 "-h"
6338 #endif
6340 exit (BAD);
6343 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
6344 static void
6345 error (s1, s2)
6346 const char *s1, *s2;
6348 fprintf (stderr, "%s: ", progname);
6349 fprintf (stderr, s1, s2);
6350 fprintf (stderr, "\n");
6353 /* Return a newly-allocated string whose contents
6354 concatenate those of s1, s2, s3. */
6355 static char *
6356 concat (s1, s2, s3)
6357 char *s1, *s2, *s3;
6359 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
6360 char *result = xnew (len1 + len2 + len3 + 1, char);
6362 strcpy (result, s1);
6363 strcpy (result + len1, s2);
6364 strcpy (result + len1 + len2, s3);
6365 result[len1 + len2 + len3] = '\0';
6367 return result;
6371 /* Does the same work as the system V getcwd, but does not need to
6372 guess the buffer size in advance. */
6373 static char *
6374 etags_getcwd ()
6376 #ifdef HAVE_GETCWD
6377 int bufsize = 200;
6378 char *path = xnew (bufsize, char);
6380 while (getcwd (path, bufsize) == NULL)
6382 if (errno != ERANGE)
6383 pfatal ("getcwd");
6384 bufsize *= 2;
6385 free (path);
6386 path = xnew (bufsize, char);
6389 canonicalize_filename (path);
6390 return path;
6392 #else /* not HAVE_GETCWD */
6393 #if MSDOS
6395 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
6397 getwd (path);
6399 for (p = path; *p != '\0'; p++)
6400 if (*p == '\\')
6401 *p = '/';
6402 else
6403 *p = lowcase (*p);
6405 return strdup (path);
6406 #else /* not MSDOS */
6407 linebuffer path;
6408 FILE *pipe;
6410 linebuffer_init (&path);
6411 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
6412 if (pipe == NULL || readline_internal (&path, pipe) == 0)
6413 pfatal ("pwd");
6414 pclose (pipe);
6416 return path.buffer;
6417 #endif /* not MSDOS */
6418 #endif /* not HAVE_GETCWD */
6421 /* Return a newly allocated string containing the file name of FILE
6422 relative to the absolute directory DIR (which should end with a slash). */
6423 static char *
6424 relative_filename (file, dir)
6425 char *file, *dir;
6427 char *fp, *dp, *afn, *res;
6428 int i;
6430 /* Find the common root of file and dir (with a trailing slash). */
6431 afn = absolute_filename (file, cwd);
6432 fp = afn;
6433 dp = dir;
6434 while (*fp++ == *dp++)
6435 continue;
6436 fp--, dp--; /* back to the first differing char */
6437 #ifdef DOS_NT
6438 if (fp == afn && afn[0] != '/') /* cannot build a relative name */
6439 return afn;
6440 #endif
6441 do /* look at the equal chars until '/' */
6442 fp--, dp--;
6443 while (*fp != '/');
6445 /* Build a sequence of "../" strings for the resulting relative file name. */
6446 i = 0;
6447 while ((dp = etags_strchr (dp + 1, '/')) != NULL)
6448 i += 1;
6449 res = xnew (3*i + strlen (fp + 1) + 1, char);
6450 res[0] = '\0';
6451 while (i-- > 0)
6452 strcat (res, "../");
6454 /* Add the file name relative to the common root of file and dir. */
6455 strcat (res, fp + 1);
6456 free (afn);
6458 return res;
6461 /* Return a newly allocated string containing the absolute file name
6462 of FILE given DIR (which should end with a slash). */
6463 static char *
6464 absolute_filename (file, dir)
6465 char *file, *dir;
6467 char *slashp, *cp, *res;
6469 if (filename_is_absolute (file))
6470 res = savestr (file);
6471 #ifdef DOS_NT
6472 /* We don't support non-absolute file names with a drive
6473 letter, like `d:NAME' (it's too much hassle). */
6474 else if (file[1] == ':')
6475 fatal ("%s: relative file names with drive letters not supported", file);
6476 #endif
6477 else
6478 res = concat (dir, file, "");
6480 /* Delete the "/dirname/.." and "/." substrings. */
6481 slashp = etags_strchr (res, '/');
6482 while (slashp != NULL && slashp[0] != '\0')
6484 if (slashp[1] == '.')
6486 if (slashp[2] == '.'
6487 && (slashp[3] == '/' || slashp[3] == '\0'))
6489 cp = slashp;
6491 cp--;
6492 while (cp >= res && !filename_is_absolute (cp));
6493 if (cp < res)
6494 cp = slashp; /* the absolute name begins with "/.." */
6495 #ifdef DOS_NT
6496 /* Under MSDOS and NT we get `d:/NAME' as absolute
6497 file name, so the luser could say `d:/../NAME'.
6498 We silently treat this as `d:/NAME'. */
6499 else if (cp[0] != '/')
6500 cp = slashp;
6501 #endif
6502 strcpy (cp, slashp + 3);
6503 slashp = cp;
6504 continue;
6506 else if (slashp[2] == '/' || slashp[2] == '\0')
6508 strcpy (slashp, slashp + 2);
6509 continue;
6513 slashp = etags_strchr (slashp + 1, '/');
6516 if (res[0] == '\0')
6517 return savestr ("/");
6518 else
6519 return res;
6522 /* Return a newly allocated string containing the absolute
6523 file name of dir where FILE resides given DIR (which should
6524 end with a slash). */
6525 static char *
6526 absolute_dirname (file, dir)
6527 char *file, *dir;
6529 char *slashp, *res;
6530 char save;
6532 canonicalize_filename (file);
6533 slashp = etags_strrchr (file, '/');
6534 if (slashp == NULL)
6535 return savestr (dir);
6536 save = slashp[1];
6537 slashp[1] = '\0';
6538 res = absolute_filename (file, dir);
6539 slashp[1] = save;
6541 return res;
6544 /* Whether the argument string is an absolute file name. The argument
6545 string must have been canonicalized with canonicalize_filename. */
6546 static bool
6547 filename_is_absolute (fn)
6548 char *fn;
6550 return (fn[0] == '/'
6551 #ifdef DOS_NT
6552 || (ISALPHA(fn[0]) && fn[1] == ':' && fn[2] == '/')
6553 #endif
6557 /* Translate backslashes into slashes. Works in place. */
6558 static void
6559 canonicalize_filename (fn)
6560 register char *fn;
6562 #ifdef DOS_NT
6563 /* Canonicalize drive letter case. */
6564 if (fn[0] != '\0' && fn[1] == ':' && ISLOWER (fn[0]))
6565 fn[0] = upcase (fn[0]);
6566 /* Convert backslashes to slashes. */
6567 for (; *fn != '\0'; fn++)
6568 if (*fn == '\\')
6569 *fn = '/';
6570 #else
6571 /* No action. */
6572 fn = NULL; /* shut up the compiler */
6573 #endif
6577 /* Initialize a linebuffer for use */
6578 static void
6579 linebuffer_init (lbp)
6580 linebuffer *lbp;
6582 lbp->size = (DEBUG) ? 3 : 200;
6583 lbp->buffer = xnew (lbp->size, char);
6584 lbp->buffer[0] = '\0';
6585 lbp->len = 0;
6588 /* Set the minimum size of a string contained in a linebuffer. */
6589 static void
6590 linebuffer_setlen (lbp, toksize)
6591 linebuffer *lbp;
6592 int toksize;
6594 while (lbp->size <= toksize)
6596 lbp->size *= 2;
6597 xrnew (lbp->buffer, lbp->size, char);
6599 lbp->len = toksize;
6602 /* Like malloc but get fatal error if memory is exhausted. */
6603 static PTR
6604 xmalloc (size)
6605 unsigned int size;
6607 PTR result = (PTR) malloc (size);
6608 if (result == NULL)
6609 fatal ("virtual memory exhausted", (char *)NULL);
6610 return result;
6613 static PTR
6614 xrealloc (ptr, size)
6615 char *ptr;
6616 unsigned int size;
6618 PTR result = (PTR) realloc (ptr, size);
6619 if (result == NULL)
6620 fatal ("virtual memory exhausted", (char *)NULL);
6621 return result;
6625 * Local Variables:
6626 * c-indentation-style: gnu
6627 * indent-tabs-mode: t
6628 * tab-width: 8
6629 * fill-column: 79
6630 * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
6631 * End: