1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984, 87, 88, 89, 93, 94, 95
3 Free Software Foundation, Inc. and Ken Arnold
5 This file is not considered part of SXEmacs.
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 3 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, see <http://www.gnu.org/licenses/>. */
22 * Ctags originally by Ken Arnold.
23 * Fortran added by Jim Kleckner.
24 * Ed Pelegri-Llopart added C typedefs.
25 * Gnu Emacs TAGS format and modifications by RMS?
26 * Sam Kendall added C++.
27 * Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
28 * Regexp tags by Tom Tromey.
30 * Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer.
33 char pot_etags_version[] = "@(#) pot revision number is 12.28";
35 /* Prototyping magic snarfed from gmalloc.c */
36 #if defined (__cplusplus) || defined (__STDC__)
40 #define __ptr_t void *
41 #else /* Not C++ or ANSI C. */
47 #define __ptr_t char *
48 #endif /* C++ or ANSI C. */
52 /* On some systems, Emacs defines static as nothing for the sake
53 of unexec. We don't want that here since we don't use unexec. */
55 # define ETAGS_REGEXPS /* use the regexp features */
56 #endif /* HAVE_CONFIG_H */
65 #if defined (STDC_HEADERS)
74 extern char *getcwd();
76 #endif /* HAVE_UNISTD_H */
81 #include <sys/types.h>
84 #if !defined (S_ISREG) && defined (S_IFREG)
85 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
94 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
96 extern int optind, opterr;
98 # error "ootags cannot be built without getopt, preferably getopt_long"
99 #endif /* LONG_OPTIONS */
103 #endif /* ETAGS_REGEXPS */
105 /* Define CTAGS to make the program "ctags" compatible with the usual one.
106 Leave it undefined to make the program "etags", which makes emacs-style
107 tag tables and tags typedefs, #defines and struct/union/enum by default. */
115 /* Exit codes for success and failure. */
125 #define C_PLPL 0x00001 /* C++ */
126 #define C_STAR 0x00003 /* C* */
127 #define C_JAVA 0x00005 /* JAVA */
128 #define YACC 0x10000 /* yacc file */
130 #define streq(s,t) ((DEBUG && (s) == NULL && (t) == NULL \
131 && (abort (), 1)) || !strcmp (s, t))
132 #define strneq(s,t,n) ((DEBUG && (s) == NULL && (t) == NULL \
133 && (abort (), 1)) || !strncmp (s, t, n))
135 #define lowcase(c) tolower ((char)c)
137 #define CHARS 256 /* 2^sizeof(char) */
138 #define CHAR(x) ((unsigned int)x & (CHARS - 1))
139 #define iswhite(c) (_wht[CHAR(c)]) /* c is white */
140 #define notinname(c) (_nin[CHAR(c)]) /* c is not in a name */
141 #define begtoken(c) (_btk[CHAR(c)]) /* c can start token */
142 #define intoken(c) (_itk[CHAR(c)]) /* c can be in token */
143 #define endtoken(c) (_etk[CHAR(c)]) /* c ends tokens */
146 /*#undef OO_BROWSER*/
147 /* Due to the way this file is constructed, this unfortunately doesn't */
148 /* work except for documentation purposes. -slb */
153 #define set_construct(construct) \
154 if (!oo_browser_construct) oo_browser_construct = construct
155 void oo_browser_clear_all_globals(void);
156 void oo_browser_clear_some_globals(void);
157 void oo_browser_check_and_clear_structtype(void);
161 * xnew, xrnew -- allocate, reallocate storage
163 * SYNOPSIS: Type *xnew (int n, Type);
164 * Type *xrnew (OldPointer, int n, Type);
167 # include "chkmalloc.h"
168 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
169 (n) * sizeof (Type)))
170 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
171 (op), (n) * sizeof (Type)))
173 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
174 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
179 typedef void Lang_function(FILE *);
183 Lang_function *function;
188 typedef struct node_st { /* sorting structure */
189 char *name; /* function or type name */
191 short int construct; /* Construct type for the OO-Browser */
193 char *file; /* file name */
194 bool is_func; /* use pattern or line no */
195 bool been_warned; /* set if noticed dup */
196 int lno; /* line number tag is on */
197 long cno; /* character number line starts on */
198 char *pat; /* search pattern */
199 struct node_st *left, *right; /* left and right sons */
203 /* If you add to this array, you must add a corresponding entry to the
205 static char *oo_browser_default_classes[] =
206 /* Lack of square brackets around some of these entries are intentional. */
207 { "null", "class", "method", "[constant]", "[enumeration]", "[enum_label]",
208 "extern", "[function]", "[macro]", "objc", "[structure]", "[type]",
209 "[union]", "[variable]"
212 /* If you add to this enum, you must add a corresponding entry to the
214 enum oo_browser_constructs { C_NULL, C_CLASS, C_METHOD, C_CONSTANT,
216 C_ENUM_LABEL, C_EXTERN, C_FUNCTION, C_MACRO,
217 C_OBJC, C_STRUCTURE, C_TYPE, C_UNION, C_VARIABLE
220 enum oo_browser_constructs oo_browser_construct = C_NULL;
224 * A `linebuffer' is a structure which holds a line of text.
225 * `readline_internal' reads a line from a stream into a linebuffer
226 * and works regardless of the length of the line.
227 * SIZE is the size of BUFFER, LEN is the length of the string in
228 * BUFFER after readline reads it.
236 extern char *getenv PP((const char *envvar));
238 /* Many compilers barf on this:
239 Lang_function Asm_labels;
240 so let's write it this way */
241 void Asm_labels PP((FILE * inf));
242 void C_entries PP((int c_ext, FILE * inf));
243 void default_C_entries PP((FILE * inf));
244 void plain_C_entries PP((FILE * inf));
245 void Cjava_entries PP((FILE * inf));
246 void Cplusplus_entries PP((FILE * inf));
247 void Yacc_entries PP((FILE * inf));
248 void Cobol_paragraphs PP((FILE * inf));
249 void Cstar_entries PP((FILE * inf));
250 void Erlang_functions PP((FILE * inf));
251 void Fortran_functions PP((FILE * inf));
252 void Lisp_functions PP((FILE * inf));
253 void Pascal_functions PP((FILE * inf));
254 void Perl_functions PP((FILE * inf));
255 void Postscript_functions PP((FILE * inf));
256 void Prolog_functions PP((FILE * inf));
257 void Python_functions PP((FILE * inf));
258 void Scheme_functions PP((FILE * inf));
259 void TeX_functions PP((FILE * inf));
260 void just_read_file PP((FILE * inf));
262 void print_language_names PP((void));
263 void print_version PP((void));
264 void print_help PP((void));
266 language *get_language_from_name PP((char *name));
267 language *get_language_from_interpreter PP((char *interpreter));
268 language *get_language_from_suffix PP((char *suffix));
269 int total_size_of_entries PP((node * np));
270 long readline PP((linebuffer * lbp, FILE * stream));
271 long readline_internal PP((linebuffer * lbp, FILE * stream));
273 void analyse_regex PP((char *regex_arg));
274 void add_regex PP((char *regexp_pattern, language * lang));
275 void free_patterns PP((void));
276 #endif /* ETAGS_REGEXPS */
277 void error PP((const char *s1, const char *s2));
278 void suggest_asking_for_help PP((void));
279 void fatal PP((char *s1, char *s2));
280 void pfatal PP((char *s1));
281 void add_node PP((node * np, node ** cur_node_p));
283 void init PP((void));
284 void initbuffer PP((linebuffer * lbp));
285 void find_entries PP((char *file, FILE * inf));
286 void free_tree PP((node * np));
288 PP((char *name, bool is_func, char *linestart, int linelen, int lno, long cno));
290 PP((char *name, int namelen, bool is_func, char *linestart, int linelen,
292 void process_file PP((char *file));
293 void put_entries PP((node * np));
294 void takeprec PP((void));
296 char *concat PP((char *s1, char *s2, char *s3));
297 char *skip_spaces PP((char *cp));
298 char *skip_non_spaces PP((char *cp));
299 char *savenstr PP((char *cp, int len));
300 char *savestr PP((char *cp));
301 char *etags_strchr PP((char *sp, int c));
302 char *etags_strrchr PP((char *sp, int c));
303 char *etags_getcwd PP((void));
304 char *relative_filename PP((char *file, char *dir));
305 char *absolute_filename PP((char *file, char *dir));
306 char *absolute_dirname PP((char *file, char *dir));
307 bool filename_is_absolute PP((char *fn));
308 void canonicalize_filename PP((char *fn));
309 void grow_linebuffer PP((linebuffer * lbp, int toksize));
310 long *xmalloc PP((unsigned int size));
311 long *xrealloc PP((char *ptr, unsigned int size));
313 char searchar = '/'; /* use /.../ searches */
315 char *tagfile; /* output file */
316 char *progname; /* name this program was invoked with */
317 char *cwd; /* current working directory */
318 char *tagfiledir; /* directory of tagfile */
319 FILE *tagf; /* ioptr for tags file */
321 char *curfile; /* current input file name */
322 language *curlang; /* current language */
324 int lineno; /* line number of current line */
325 long charno; /* current character number */
326 long linecharno; /* charno of start of current line */
327 char *dbp; /* pointer to start of current tag */
328 node *head; /* the head of the binary tree of tags */
330 linebuffer lb; /* the current line */
331 linebuffer token_name; /* used by C_entries as a temporary area */
334 linebuffer lb; /* used by C_entries instead of lb */
337 /* boolean "functions" (see init) */
338 bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
341 *white = " \f\t\n\r",
343 *nonam = " \f\t\n\r(=,[;",
344 /* token ending chars */
345 *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
346 /* token starting chars */
347 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
348 /* valid in-token chars */
349 *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
351 bool append_to_tagfile; /* -a: append to tags */
352 /* The following four default to TRUE for etags, but to FALSE for ctags. */
353 bool typedefs; /* -t: create tags for C typedefs */
354 bool typedefs_and_cplusplus; /* -T: create tags for C typedefs, level */
355 /* 0 struct/enum/union decls, and C++ */
356 /* member functions. */
357 bool constantypedefs; /* -d: create tags for C #define, enum */
358 /* constants and variables. */
359 /* -D: opposite of -d. Default under ctags. */
360 bool globals; /* create tags for global variables */
361 bool members; /* create tags for C member variables */
362 bool update; /* -u: update tags */
363 bool vgrind_style; /* -v: create vgrind style index output */
364 bool no_warnings; /* -w: suppress warnings */
365 bool cxref_style; /* -x: create cxref style output */
366 bool cplusplus; /* .[hc] means C++, not C */
367 bool noindentypedefs; /* -I: ignore indentation in C */
369 bool oo_browser_format; /* -O: OO-Browser tags format */
373 struct option longopts[] = {
374 {"append", no_argument, NULL, 'a'},
375 {"backward-search", no_argument, NULL, 'B'},
376 {"c++", no_argument, NULL, 'C'},
377 {"cxref", no_argument, NULL, 'x'},
378 {"defines", no_argument, NULL, 'd'},
379 {"no-defines", no_argument, NULL, 'D'},
380 {"globals", no_argument, &globals, TRUE},
381 {"no-globals", no_argument, &globals, FALSE},
382 {"help", no_argument, NULL, 'h'},
383 {"help", no_argument, NULL, 'H'},
384 {"ignore-indentation", no_argument, NULL, 'I'},
385 {"include", required_argument, NULL, 'i'},
386 {"language", required_argument, NULL, 'l'},
387 {"members", no_argument, &members, TRUE},
388 {"no-members", no_argument, &members, FALSE},
389 {"no-warn", no_argument, NULL, 'w'},
390 {"output", required_argument, NULL, 'o'},
392 {"oo-browser", no_argument, NULL, 'O'},
395 {"regex", required_argument, NULL, 'r'},
396 {"no-regex", no_argument, NULL, 'R'},
397 #endif /* ETAGS_REGEXPS */
398 {"typedefs", no_argument, NULL, 't'},
399 {"typedefs-and-c++", no_argument, NULL, 'T'},
400 {"update", no_argument, NULL, 'u'},
401 {"version", no_argument, NULL, 'V'},
402 {"vgrind", no_argument, NULL, 'v'},
405 #endif /* LONG_OPTIONS */
408 /* Structure defining a regular expression. Elements are
409 the compiled pattern, and the name string. */
410 typedef struct pattern {
411 struct pattern *p_next;
414 struct re_pattern_buffer *pattern;
415 struct re_registers regs;
420 /* Array of all regexps. */
421 pattern *p_head = NULL;
422 #endif /* ETAGS_REGEXPS */
428 /* Non-NULL if language fixed. */
429 language *forced_lang = NULL;
432 char *Asm_suffixes[] = { "a", /* Unix assembler */
433 "asm", /* Microcontroller assembly */
434 "def", /* BSO/Tasking definition includes */
435 "inc", /* Microcontroller include files */
436 "ins", /* Microcontroller include files */
437 "s", "sa", /* Unix assembler */
438 "src", /* BSO/Tasking C compiler output */
442 /* Note that .c and .h can be considered C++, if the --c++ flag was
443 given. That is why default_C_entries is called here. */
444 char *default_C_suffixes[] = { "c", "h", NULL };
446 char *Cplusplus_suffixes[] =
447 { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
448 "M", /* Objective C++ */
449 "pdb", /* Postscript with C syntax */
453 char *Cjava_suffixes[] = { "java", NULL };
455 char *Cobol_suffixes[] = { "COB", "cob", NULL };
457 char *Cstar_suffixes[] = { "cs", "hs", NULL };
459 char *Erlang_suffixes[] = { "erl", "hrl", NULL };
461 char *Fortran_suffixes[] = { "F", "f", "f90", "for", NULL };
463 char *Lisp_suffixes[] = { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
465 char *Pascal_suffixes[] = { "p", "pas", NULL };
467 char *Perl_suffixes[] = { "pl", "pm", NULL };
468 char *Perl_interpreters[] = { "perl", "@PERL@", NULL };
470 char *plain_C_suffixes[] = { "pc", /* Pro*C file */
471 "m", /* Objective C file */
472 "lm", /* Objective lex file */
476 char *Postscript_suffixes[] = { "ps", NULL };
478 char *Prolog_suffixes[] = { "prolog", NULL };
480 char *Python_suffixes[] = { "py", NULL };
482 /* Can't do the `SCM' or `scm' prefix with a version number. */
483 char *Scheme_suffixes[] =
484 { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "ss", "t", NULL };
486 char *TeX_suffixes[] =
487 { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
489 char *Yacc_suffixes[] = { "y", "ym", NULL }; /* .ym is Objective yacc file */
492 * Table of languages.
494 * It is ok for a given function to be listed under more than one
495 * name. I just didn't.
498 language lang_names[] = {
499 {"asm", Asm_labels, Asm_suffixes, NULL},
500 {"c", default_C_entries, default_C_suffixes, NULL},
501 {"c++", Cplusplus_entries, Cplusplus_suffixes, NULL},
502 {"c*", Cstar_entries, Cstar_suffixes, NULL},
503 {"cobol", Cobol_paragraphs, Cobol_suffixes, NULL},
504 {"erlang", Erlang_functions, Erlang_suffixes, NULL},
505 {"fortran", Fortran_functions, Fortran_suffixes, NULL},
506 {"java", Cjava_entries, Cjava_suffixes, NULL},
507 {"lisp", Lisp_functions, Lisp_suffixes, NULL},
508 {"pascal", Pascal_functions, Pascal_suffixes, NULL},
509 {"perl", Perl_functions, Perl_suffixes, Perl_interpreters},
510 {"postscript", Postscript_functions, Postscript_suffixes, NULL},
511 {"proc", plain_C_entries, plain_C_suffixes, NULL},
512 {"prolog", Prolog_functions, Prolog_suffixes, NULL},
513 {"python", Python_functions, Python_suffixes, NULL},
514 {"scheme", Scheme_functions, Scheme_suffixes, NULL},
515 {"tex", TeX_functions, TeX_suffixes, NULL},
516 {"yacc", Yacc_entries, Yacc_suffixes, NULL},
517 {"auto", NULL}, /* default guessing scheme */
518 {"none", just_read_file}, /* regexp matching only */
519 {NULL, NULL} /* end of list */
522 void print_language_names()
527 puts("\nThese are the currently supported languages, along with the\n\
528 default file name suffixes:");
529 for (lang = lang_names; lang->name != NULL; lang++) {
530 printf("\t%s\t", lang->name);
531 if (lang->suffixes != NULL)
532 for (ext = lang->suffixes; *ext != NULL; ext++)
533 printf(" .%s", *ext);
536 puts("Where `auto' means use default language for files based on file\n\
537 name suffix, and `none' means only do regexp processing on files.\n\
538 If no language is specified and no matching suffix is found,\n\
539 the first line of the file is read for a sharp-bang (#!) sequence\n\
540 followed by the name of an interpreter. If no such sequence is found,\n\
541 Fortran is tried first; if no tags are found, C is tried next.");
545 # define VERSION "20"
549 printf("%s (GNU Emacs %s)\n", (CTAGS) ? "ctags" : "etags", VERSION);
550 puts("Copyright (C) 1996 Free Software Foundation, Inc. and Ken Arnold");
551 puts("This program is distributed under the same terms as Emacs");
558 printf("Usage: %s [options] [[regex-option ...] file-name] ...\n\
560 These are the options accepted by %s.\n", progname, progname);
562 puts("You may use unambiguous abbreviations for the long option names.");
564 puts("Long option names do not work with this executable, as it is not\n\
565 linked with GNU getopt.");
566 #endif /* LONG_OPTIONS */
567 puts("A - as file name means read names from stdin (one per line).");
570 (" Absolute names are stored in the output file as they are.\n\
571 Relative ones are stored relative to the output file's directory.");
574 puts("-a, --append\n\
575 Append tag entries to existing tags file.");
578 puts("-B, --backward-search\n\
579 Write the search commands for the tag entries using '?', the\n\
580 backward-search command instead of '/', the forward-search command.");
583 Treat files whose name suffix defaults to C language as C++ files.");
586 puts("-d, --defines\n\
587 Create tag entries for C #define constants and enum constants, too.");
589 puts("-D, --no-defines\n\
590 Don't create tag entries for C #define constants and enum constants.\n\
591 This makes the tags file smaller.");
594 puts("-i FILE, --include=FILE\n\
595 Include a note in tag file indicating that, when searching for\n\
596 a tag, one should also consult the tags file FILE after\n\
597 checking the current file.");
598 puts("-l LANG, --language=LANG\n\
599 Force the following files to be considered as written in the\n\
600 named language up to the next --language=LANG option.");
605 Create tag entries for global variables in some languages.");
607 puts("--no-globals\n\
608 Do not create tag entries for global variables in some\n\
609 languages. This makes the tags file smaller.");
611 Create tag entries for member variables in C and derived languages.");
614 puts("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
615 Make a tag for each line matching pattern REGEXP in the\n\
616 following files. regexfile is a file containing one REGEXP\n\
617 per line. REGEXP is anchored (as if preceded by ^).\n\
618 The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
619 named tags can be created with:\n\
620 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
621 puts("-R, --no-regex\n\
622 Don't create tags from regexps for the following files.");
623 #endif /* ETAGS_REGEXPS */
624 puts("-o FILE, --output=FILE\n\
625 Write the tags to FILE.");
627 puts("-O, --oo-browser\n\
628 Generate a specialized tags format used only by the Altrasoft OO-Browser.");
630 puts("-I, --ignore-indentation\n\
631 Don't rely on indentation quite as much as normal. Currently,\n\
632 this means not to assume that a closing brace in the first\n\
633 column is the final brace of a function or structure\n\
634 definition in C and C++.");
637 puts("-t, --typedefs\n\
638 Generate tag entries for C typedefs.");
639 puts("-T, --typedefs-and-c++\n\
640 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
641 and C++ member functions.");
642 puts("-u, --update\n\
643 Update the tag entries for the given files, leaving tag\n\
644 entries for other files in place. Currently, this is\n\
645 implemented by deleting the existing entries for the given\n\
646 files and then rewriting the new entries at the end of the\n\
647 tags file. It is often faster to simply rebuild the entire\n\
648 tag file than to use this.");
649 puts("-v, --vgrind\n\
650 Generates an index of items intended for human consumption,\n\
651 similar to the output of vgrind. The index is sorted, and\n\
652 gives the page number of each item.");
653 puts("-w, --no-warn\n\
654 Suppress warning messages about entries defined in multiple\n\
657 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
658 The output uses line numbers instead of page numbers, but\n\
659 beyond that the differences are cosmetic; try both to see\n\
663 puts("-V, --version\n\
664 Print the version of the program.\n\
666 Print this help message.");
668 print_language_names();
671 puts("Report bugs to bug-gnu-emacs@prep.ai.mit.edu");
682 /* This structure helps us allow mixing of --lang and file names. */
684 enum argument_type arg_type;
689 #ifdef VMS /* VMS specific functions */
693 /* This is a BUG! ANY arbitrary limit is a BUG!
694 Won't someone please fix this? */
695 #define MAX_FILE_SPEC_LEN 255
698 char body[MAX_FILE_SPEC_LEN + 1];
702 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
703 returning in each successive call the next file name matching the input
704 spec. The function expects that each in_spec passed
705 to it will be processed to completion; in particular, up to and
706 including the call following that in which the last matching name
707 is returned, the function ignores the value of in_spec, and will
708 only start processing a new spec with the following call.
709 If an error occurs, on return out_spec contains the value
710 of in_spec when the error occurred.
712 With each successive file name returned in out_spec, the
713 function's return value is one. When there are no more matching
714 names the function returns zero. If on the first call no file
715 matches in_spec, or there is any other error, -1 is returned.
720 #define OUTSIZE MAX_FILE_SPEC_LEN
721 short fn_exp(out, in)
725 static long context = 0;
726 static struct dsc$descriptor_s o;
727 static struct dsc$descriptor_s i;
728 static bool pass1 = TRUE;
734 o.dsc$a_pointer = (char *)out;
735 o.dsc$w_length = (short)OUTSIZE;
736 i.dsc$a_pointer = in;
737 i.dsc$w_length = (short)strlen(in);
738 i.dsc$b_dtype = DSC$K_DTYPE_T;
739 i.dsc$b_class = DSC$K_CLASS_S;
740 o.dsc$b_dtype = DSC$K_DTYPE_VT;
741 o.dsc$b_class = DSC$K_CLASS_VS;
743 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL) {
744 out->body[out->curlen] = EOS;
746 } else if (status == RMS$_NMF)
749 strcpy(out->body, in);
752 lib$find_file_end(&context);
758 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
759 name of each file specified by the provided arg expanding wildcards.
761 char *gfnames(arg, p_error)
765 static vspec filename = { MAX_FILE_SPEC_LEN, "\0" };
767 switch (fn_exp(&filename, arg)) {
770 return filename.body;
776 return filename.body;
780 #ifndef OLD /* Newer versions of VMS do provide `system'. */
784 error("%s", "system() function not implemented under VMS");
788 #define VERSION_DELIM ';'
789 char *massage_name(s)
795 if (*s == VERSION_DELIM) {
804 int main(int argc, char *argv[])
807 unsigned int nincluded_files;
808 char **included_files;
811 int current_arg, file_count;
812 linebuffer filename_lb;
819 included_files = xnew(argc, char *);
823 /* Allocate enough no matter what happens. Overkill, but each one
825 argbuffer = xnew(argc, argument);
828 /* Set syntax for regular expression routines. */
829 re_set_syntax(RE_SYNTAX_EMACS | RE_INTERVALS);
830 #endif /* ETAGS_REGEXPS */
833 * If etags, always find typedefs and structure tags. Why not?
834 * Also default is to find macro constants, enum constants and
838 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
849 optstring = "-aCdDf:Il:o:r:RStTi:BuvxwVhH";
851 optstring = "-aCdDf:Il:o:r:RStTi:BOuvxwVhH";
855 optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
857 optstring = "-aCdDf:Il:o:StTi:BOuvxwVhH";
859 #endif /* ETAGS_REGEXPS */
862 optstring = optstring + 1;
863 #endif /* LONG_OPTIONS */
865 opt = getopt_long(argc, argv, optstring, longopts, 0);
871 /* If getopt returns 0, then it has already processed a
872 long-named option. We should do nothing. */
876 /* This means that a file name has been seen. Record it. */
877 argbuffer[current_arg].arg_type = at_filename;
878 argbuffer[current_arg].what = optarg;
883 /* Common options. */
885 append_to_tagfile = TRUE;
891 constantypedefs = TRUE;
894 constantypedefs = FALSE;
896 case 'f': /* for compatibility with old makefiles */
899 /* convert char to string, to call error with */
901 sprintf(buf, "%c", opt);
902 error("-%s option may only be given once.",
904 suggest_asking_for_help();
910 oo_browser_format = TRUE;
914 case 'S': /* for backward compatibility */
915 noindentypedefs = TRUE;
919 language *lang = get_language_from_name(optarg);
921 argbuffer[current_arg].lang = lang;
922 argbuffer[current_arg].arg_type =
930 argbuffer[current_arg].arg_type = at_regexp;
931 argbuffer[current_arg].what = optarg;
935 argbuffer[current_arg].arg_type = at_regexp;
936 argbuffer[current_arg].what = NULL;
939 #endif /* ETAGS_REGEXPS */
951 typedefs = typedefs_and_cplusplus = TRUE;
956 included_files[nincluded_files++] = optarg;
968 /*FALLTHRU*/ case 'x':
976 suggest_asking_for_help();
980 for (; optind < argc; ++optind) {
981 argbuffer[current_arg].arg_type = at_filename;
982 argbuffer[current_arg].what = argv[optind];
987 if (nincluded_files == 0 && file_count == 0) {
988 error("no input files specified.", 0);
989 suggest_asking_for_help();
993 tagfile = CTAGS ? "tags" : "TAGS";
994 cwd = etags_getcwd(); /* the current working directory */
995 if (cwd[strlen(cwd) - 1] != '/') {
997 cwd = concat(oldcwd, "/", "");
1000 if (streq(tagfile, "-"))
1003 tagfiledir = absolute_dirname(tagfile, cwd);
1005 init(); /* set up boolean "functions" */
1008 initbuffer(&token_name);
1009 initbuffer(&lbs[0].lb);
1010 initbuffer(&lbs[1].lb);
1011 initbuffer(&filename_lb);
1014 if (streq(tagfile, "-")) {
1017 tagf = fopen(tagfile, append_to_tagfile ? "a" : "w");
1023 * Loop through files finding functions.
1025 for (i = 0; i < current_arg; ++i) {
1026 switch (argbuffer[i].arg_type) {
1028 forced_lang = argbuffer[i].lang;
1030 #ifdef ETAGS_REGEXPS
1032 analyse_regex(argbuffer[i].what);
1038 gfnames(argbuffer[i].what, &got_err)) != NULL) {
1040 error("can't find file %s\n",
1044 this_file = massage_name(this_file);
1047 this_file = argbuffer[i].what;
1050 oo_browser_clear_all_globals();
1052 /* Input file named "-" means read file names from stdin
1053 (one per line) and use them. */
1054 if (streq(this_file, "-"))
1055 while (readline_internal(&filename_lb, stdin) >
1059 oo_browser_clear_some_globals();
1061 process_file(filename_lb.buffer);
1066 process_file(this_file);
1076 #ifdef ETAGS_REGEXPS
1078 #endif /* ETAGS_REGEXPS */
1081 while (nincluded_files-- > 0)
1082 fprintf(tagf, "\f\n%s,include\n", *included_files++);
1088 /* If CTAGS, we are here. process_file did not write the tags yet,
1089 because we want them ordered. Let's do it now. */
1097 for (i = 0; i < current_arg; ++i) {
1098 if (argbuffer[i].arg_type != at_filename)
1101 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1102 tagfile, argbuffer[i].what, tagfile);
1103 if (system(cmd) != GOOD)
1104 fatal("failed to execute shell command", (char *)NULL);
1106 append_to_tagfile = TRUE;
1109 tagf = fopen(tagfile, append_to_tagfile ? "a" : "w");
1117 sprintf(cmd, "sort %s -o %s", tagfile, tagfile);
1124 * Return a language given the name.
1126 language *get_language_from_name(name)
1132 error("empty language name", (char *)NULL);
1134 for (lang = lang_names; lang->name != NULL; lang++)
1135 if (streq(name, lang->name))
1137 error("unknown language \"%s\"", name);
1144 * Return a language given the interpreter name.
1146 language *get_language_from_interpreter(interpreter)
1152 if (interpreter == NULL)
1154 for (lang = lang_names; lang->name != NULL; lang++)
1155 if (lang->interpreters != NULL)
1156 for (iname = lang->interpreters; *iname != NULL;
1158 if (streq(*iname, interpreter))
1165 * Return a language given the file suffix.
1167 language *get_language_from_suffix(suffix)
1175 for (lang = lang_names; lang->name != NULL; lang++)
1176 if (lang->suffixes != NULL)
1177 for (ext = lang->suffixes; *ext != NULL; ext++)
1178 if (streq(*ext, suffix))
1185 * This routine is called on each file argument.
1187 void process_file(file)
1190 struct stat stat_buf;
1193 canonicalize_filename(file);
1194 if (stat(file, &stat_buf) == 0 && !S_ISREG(stat_buf.st_mode)) {
1195 error("skipping %s: it is not a regular file.", file);
1198 if (streq(file, tagfile) && !streq(tagfile, "-")) {
1199 error("skipping inclusion of %s in self.", file);
1202 inf = fopen(file, "r");
1208 find_entries(file, inf);
1213 if (filename_is_absolute(file)) {
1214 /* file is an absolute file name. Canonicalise it. */
1215 filename = absolute_filename(file, cwd);
1217 /* file is a file name relative to cwd. Make it relative
1218 to the directory of the tags file. */
1219 filename = relative_filename(file, tagfiledir);
1222 if (oo_browser_format)
1223 fprintf(tagf, "\f\n%s\n", filename);
1226 fprintf(tagf, "\f\n%s,%d\n", filename,
1227 total_size_of_entries(head));
1236 * This routine sets up the boolean pseudo-functions which work
1237 * by setting boolean flags dependent upon the corresponding character.
1238 * Every char which is NOT in that string is not a white char. Therefore,
1239 * all of the array "_wht" is set to FALSE, and then the elements
1240 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1241 * of a char is TRUE if it is the string "white", else FALSE.
1248 for (i = 0; i < CHARS; i++)
1249 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) =
1250 endtoken(i) = FALSE;
1251 for (sp = white; *sp != '\0'; sp++)
1252 iswhite(*sp) = TRUE;
1253 for (sp = nonam; *sp != '\0'; sp++)
1254 notinname(*sp) = TRUE;
1255 for (sp = begtk; *sp != '\0'; sp++)
1256 begtoken(*sp) = TRUE;
1257 for (sp = midtk; *sp != '\0'; sp++)
1258 intoken(*sp) = TRUE;
1259 for (sp = endtk; *sp != '\0'; sp++)
1260 endtoken(*sp) = TRUE;
1261 iswhite('\0') = iswhite('\n');
1262 notinname('\0') = notinname('\n');
1263 begtoken('\0') = begtoken('\n');
1264 intoken('\0') = intoken('\n');
1265 endtoken('\0') = endtoken('\n');
1269 * This routine opens the specified file and calls the function
1270 * which finds the function and type definitions.
1272 node *last_node = NULL;
1274 void find_entries(file, inf)
1280 node *old_last_node;
1282 curfile = savestr(file);
1284 /* If user specified a language, use it. */
1286 if (lang != NULL && lang->function != NULL) {
1288 lang->function(inf);
1294 cp = etags_strrchr(file, '.');
1297 lang = get_language_from_suffix(cp);
1298 if (lang != NULL && lang->function != NULL) {
1300 lang->function(inf);
1307 /* Look for sharp-bang as the first two characters. */
1308 if (readline_internal(&lb, inf) > 0
1309 && lb.len >= 2 && lb.buffer[0] == '#' && lb.buffer[1] == '!') {
1312 /* Set lp to point at the first char after the last slash in the
1313 line or, if no slashes, at the first nonblank. Then set cp to
1314 the first successive blank and terminate the string. */
1315 lp = etags_strrchr(lb.buffer + 2, '/');
1319 lp = skip_spaces(lb.buffer + 2);
1320 cp = skip_non_spaces(lp);
1323 if (strlen(lp) > 0) {
1324 lang = get_language_from_interpreter(lp);
1325 if (lang != NULL && lang->function != NULL) {
1327 lang->function(inf);
1337 old_last_node = last_node;
1338 curlang = get_language_from_name("fortran");
1339 Fortran_functions(inf);
1341 /* No Fortran entries found. Try C. */
1342 if (old_last_node == last_node) {
1344 curlang = get_language_from_name(cplusplus ? "c++" : "c");
1345 default_C_entries(inf);
1353 void pfnote(name, is_func, linestart, linelen, lno, cno)
1354 char *name; /* tag name, or NULL if unnamed */
1355 bool is_func; /* tag is a function */
1356 char *linestart; /* start of the line where tag is */
1357 int linelen; /* length of the line where tag is */
1358 int lno; /* line number */
1359 long cno; /* character number */
1363 if (CTAGS && name == NULL)
1368 /* If ctags mode, change name "main" to M<thisfilename>. */
1369 if (CTAGS && !cxref_style && streq(name, "main")) {
1370 register char *fp = etags_strrchr(curfile, '/');
1371 np->name = concat("M", fp == 0 ? curfile : fp + 1, "");
1372 fp = etags_strrchr(np->name, '.');
1373 if (fp && fp[1] != '\0' && fp[2] == '\0')
1377 np->been_warned = FALSE;
1379 np->is_func = is_func;
1381 /* Our char numbers are 0-base, because of C language tradition?
1382 ctags compatibility? old versions compatibility? I don't know.
1383 Anyway, since emacs's are 1-base we expect etags.el to take care
1384 of the difference. If we wanted to have 1-based numbers, we would
1385 uncomment the +1 below. */
1386 np->cno = cno /* + 1 */ ;
1387 np->left = np->right = NULL;
1388 if (CTAGS && !cxref_style) {
1389 if (strlen(linestart) < 50)
1390 np->pat = concat(linestart, "$", "");
1392 np->pat = savenstr(linestart, 50);
1394 np->pat = savenstr(linestart, linelen);
1397 if (oo_browser_format)
1398 np->construct = oo_browser_construct;
1399 oo_browser_construct = C_NULL;
1400 oo_browser_check_and_clear_structtype();
1403 add_node(np, &head);
1406 /* Date: Wed, 22 Jan 1997 02:56:31 -0500 [last amended 18 Sep 1997]
1407 * From: Sam Kendall <kendall@mv.mv.com>
1408 * Subject: Proposal for firming up the TAGS format specification
1409 * To: F.Potorti@cnuce.cnr.it
1411 * pfnote should emit the optimized form [unnamed tag] only if:
1412 * 1. name does not contain any of the characters " \t\r\n(),;";
1413 * 2. linestart contains name as either a rightmost, or rightmost but
1414 * one character, substring;
1415 * 3. the character, if any, immediately before name in linestart must
1416 * be one of the characters " \t(),;";
1417 * 4. the character, if any, immediately after name in linestart must
1418 * also be one of the characters " \t(),;".
1420 * The real implementation uses the notinname() macro, which recognises
1421 * characters slightly different form " \t\r\n(),;". See the variable
1424 #define traditional_tag_style TRUE
1425 void new_pfnote(name, namelen, is_func, linestart, linelen, lno, cno)
1426 char *name; /* tag name, or NULL if unnamed */
1427 int namelen; /* tag length */
1428 bool is_func; /* tag is a function */
1429 char *linestart; /* start of the line where tag is */
1430 int linelen; /* length of the line where tag is */
1431 int lno; /* line number */
1432 long cno; /* character number */
1439 for (cp = name; !notinname(*cp); cp++)
1441 if (*cp == '\0') { /* rule #1 */
1442 cp = linestart + linelen - namelen;
1443 if (notinname(linestart[linelen - 1]))
1444 cp -= 1; /* rule #4 */
1446 if (!oo_browser_format && cp >= linestart /* rule #2 */
1448 if (cp >= linestart /* rule #2 */
1450 && (cp == linestart || notinname(cp[-1])) /* rule #3 */
1451 &&strneq(name, cp, namelen)) /* rule #2 */
1452 named = FALSE; /* use unnamed tag */
1457 name = savenstr(name, namelen);
1460 pfnote(name, is_func, linestart, linelen, lno, cno);
1465 * recurse on left children, iterate on right children.
1471 register node *node_right = np->right;
1472 free_tree(np->left);
1473 if (np->name != NULL)
1483 * Adds a node to the tree of nodes. In etags mode, we don't keep
1484 * it sorted; we just keep a linear list. In ctags mode, maintain
1485 * an ordered tree, with no attempt at balancing.
1487 * add_node is the only function allowed to add nodes, so it can
1490 void add_node(np, cur_node_p)
1491 node *np, **cur_node_p;
1494 register node *cur_node = *cur_node_p;
1496 if (cur_node == NULL) {
1504 if (last_node == NULL)
1505 fatal("internal error in add_node", (char *)NULL);
1506 last_node->right = np;
1510 dif = strcmp(np->name, cur_node->name);
1513 * If this tag name matches an existing one, then
1514 * do not add the node, but maybe print a warning.
1517 if (streq(np->file, cur_node->file)) {
1520 "Duplicate entry in file %s, line %d: %s\n",
1521 np->file, lineno, np->name);
1523 "Second entry ignored\n");
1525 } else if (!cur_node->been_warned && !no_warnings) {
1528 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1529 np->file, cur_node->file, np->name);
1530 cur_node->been_warned = TRUE;
1535 /* Actually add the node */
1536 add_node(np, dif < 0 ? &cur_node->left : &cur_node->right);
1541 /* Default class name for the current OO-Browser tag. */
1542 static char *oo_browser_class;
1543 /* Prefix character to use in OO-Browser listings for the current tag. */
1544 static char oo_browser_prefix;
1547 void put_entries(node * np)
1554 /* Output subentries that precede this one */
1555 put_entries(np->left);
1557 /* Output this entry */
1561 if (oo_browser_format) {
1562 /* Omit C++ `class' and `method' entries as well as Objective-C
1563 entries from this OO-Browser tags file since the browser handles
1564 them independently of this file. Omit `extern' variable declarations
1565 as they are unused by the OO-Browser. */
1566 if (np->construct != C_CLASS
1567 && np->construct != C_METHOD
1568 && np->construct != C_EXTERN
1569 && np->construct != C_OBJC) {
1571 oo_browser_default_classes[np->construct];
1572 switch (np->construct) {
1580 oo_browser_prefix = '=';
1584 oo_browser_prefix = '-';
1589 if (np->name != NULL)
1590 fprintf(tagf, "%s@%c %s@%s\n",
1592 oo_browser_prefix, np->name,
1595 fprintf(tagf, "%s@%c ???@%s\n",
1597 oo_browser_prefix, np->pat);
1601 if (np->name != NULL)
1602 fprintf(tagf, "%s\177%s\001%d,%ld\n",
1603 np->pat, np->name, np->lno, np->cno);
1605 fprintf(tagf, "%s\177%d,%ld\n",
1606 np->pat, np->lno, np->cno);
1611 if (np->name == NULL)
1612 error("internal error: NULL name in ctags mode.",
1617 fprintf(stdout, "%s %s %d\n",
1619 (np->lno + 63) / 64);
1621 fprintf(stdout, "%-16s %3d %-16s %s\n",
1622 np->name, np->lno, np->file, np->pat);
1624 fprintf(tagf, "%s\t%s\t", np->name, np->file);
1626 if (np->is_func) { /* a function */
1627 putc(searchar, tagf);
1630 for (sp = np->pat; *sp; sp++) {
1631 if (*sp == '\\' || *sp == searchar)
1635 putc(searchar, tagf);
1636 } else { /* a typedef; text pattern inadequate */
1637 fprintf(tagf, "%d", np->lno);
1643 /* Output subentries that follow this one */
1644 put_entries(np->right);
1647 /* Length of a number's decimal representation. */
1648 int number_len PP((long num));
1653 while ((num /= 10) > 0)
1659 * Return total number of characters that put_entries will output for
1660 * the nodes in the subtree of the specified node. Works only if
1661 * we are not ctags, but called only in that case. This count
1662 * is irrelevant with the new tags.el, but is still supplied for
1663 * backward compatibility.
1665 int total_size_of_entries(np)
1673 for (total = 0; np != NULL; np = np->right) {
1674 /* Count left subentries. */
1675 total += total_size_of_entries(np->left);
1677 /* Count this entry */
1678 total += strlen(np->pat) + 1;
1680 number_len((long)np->lno) + 1 + number_len(np->cno) + 1;
1681 if (np->name != NULL)
1682 total += 1 + strlen(np->name); /* \001name */
1689 * The C symbol tables.
1693 st_C_objprot, st_C_objimpl, st_C_objend,
1697 st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec,
1700 , st_C_union, st_C_class, st_C_extern, st_C_inline
1704 /* Feed stuff between (but not including) %[ and %] lines to:
1705 gperf -c -k 1,3 -o -p -r -t
1707 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1709 @interface, 0, st_C_objprot
1710 @protocol, 0, st_C_objprot
1711 @implementation,0, st_C_objimpl
1712 @end, 0, st_C_objend
1713 import, C_JAVA, st_C_ignore
1714 package, C_JAVA, st_C_ignore
1715 friend, C_PLPL, st_C_ignore
1716 extends, C_JAVA, st_C_javastruct
1717 implements, C_JAVA, st_C_javastruct
1718 interface, C_JAVA, st_C_struct
1719 class, C_PLPL, st_C_class
1720 namespace, C_PLPL, st_C_struct
1721 domain, C_STAR, st_C_struct
1722 union, 0, st_C_union
1723 struct, 0, st_C_struct
1725 typedef, 0, st_C_typedef
1726 define, 0, st_C_define
1727 inline, 0, st_C_inline
1728 bool, C_PLPL, st_C_typespec
1729 long, 0, st_C_typespec
1730 short, 0, st_C_typespec
1731 int, 0, st_C_typespec
1732 char, 0, st_C_typespec
1733 float, 0, st_C_typespec
1734 double, 0, st_C_typespec
1735 signed, 0, st_C_typespec
1736 unsigned, 0, st_C_typespec
1737 auto, 0, st_C_typespec
1738 void, 0, st_C_typespec
1739 extern, 0, st_C_extern
1740 static, 0, st_C_typespec
1741 const, 0, st_C_const
1742 volatile, 0, st_C_typespec
1743 explicit, C_PLPL, st_C_typespec
1744 mutable, C_PLPL, st_C_typespec
1745 typename, C_PLPL, st_C_typespec
1746 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
1747 DEFUN, 0, st_C_gnumacro
1748 SYSCALL, 0, st_C_gnumacro
1749 ENTRY, 0, st_C_gnumacro
1750 PSEUDO, 0, st_C_gnumacro
1751 # These are defined inside C functions, so currently they are not met.
1752 # EXFUN used in glibc, DEFVAR_* in emacs.
1753 #EXFUN, 0, st_C_gnumacro
1754 #DEFVAR_, 0, st_C_gnumacro
1756 and replace lines between %< and %> with its output. */
1758 /* C code produced by gperf version 2.5 (GNU C++ version) */
1759 /* Command-line: gperf -c -k 1,3 -o -p -r -t */
1760 struct C_stab_entry {
1766 #define TOTAL_KEYWORDS 41
1767 #define MIN_WORD_LENGTH 3
1768 #define MAX_WORD_LENGTH 15
1769 #define MIN_HASH_VALUE 13
1770 #define MAX_HASH_VALUE 129
1771 /* maximum key range = 117, duplicates = 0 */
1773 static unsigned int hash(char *str, unsigned int len)
1775 static unsigned char asso_values[] = {
1776 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1777 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1778 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1779 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1780 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1781 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1782 130, 130, 130, 130, 13, 130, 130, 130, 33, 32,
1783 47, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1784 5, 130, 130, 20, 32, 130, 130, 130, 130, 130,
1785 130, 130, 130, 130, 130, 130, 130, 47, 55, 8,
1786 15, 33, 61, 38, 130, 60, 130, 130, 2, 9,
1787 10, 62, 59, 130, 28, 27, 50, 19, 3, 130,
1788 130, 130, 130, 130, 130, 130, 130, 130,
1791 asso_values[(unsigned char)str[2]] +
1792 asso_values[(unsigned char)str[0]];
1795 static struct C_stab_entry *in_word_set(char *str, unsigned int len)
1797 static struct C_stab_entry wordlist[] = {
1798 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1799 {"",}, {"",}, {"",}, {"",},
1800 {"volatile", 0, st_C_typespec},
1802 {"long", 0, st_C_typespec},
1803 {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1804 {"const", 0, st_C_const},
1805 {"",}, {"",}, {"",},
1806 {"@end", 0, st_C_objend},
1807 {"namespace", C_PLPL, st_C_struct},
1809 {"domain", C_STAR, st_C_struct},
1811 {"@interface", 0, st_C_objprot},
1812 {"",}, {"",}, {"",},
1813 {"@implementation", 0, st_C_objimpl},
1815 {"double", 0, st_C_typespec},
1817 {"PSEUDO", 0, st_C_gnumacro},
1818 {"",}, {"",}, {"",},
1819 {"SYSCALL", 0, st_C_gnumacro},
1821 {"@protocol", 0, st_C_objprot},
1822 {"",}, {"",}, {"",},
1823 {"unsigned", 0, st_C_typespec},
1825 {"enum", 0, st_C_enum},
1827 {"char", 0, st_C_typespec},
1828 {"class", C_PLPL, st_C_class},
1829 {"struct", 0, st_C_struct},
1830 {"",}, {"",}, {"",}, {"",},
1831 {"mutable", C_PLPL, st_C_typespec},
1832 {"void", 0, st_C_typespec},
1833 {"inline", 0, st_C_inline},
1834 {"ENTRY", 0, st_C_gnumacro},
1836 {"signed", 0, st_C_typespec},
1838 {"package", C_JAVA, st_C_ignore},
1839 {"",}, {"",}, {"",}, {"",}, {"",},
1840 {"static", 0, st_C_typespec},
1842 {"define", 0, st_C_define},
1844 {"union", 0, st_C_union},
1845 {"DEFUN", 0, st_C_gnumacro},
1846 {"",}, {"",}, {"",},
1847 {"extern", 0, st_C_extern},
1848 {"extends", C_JAVA, st_C_javastruct},
1849 {"",}, {"",}, {"",},
1850 {"short", 0, st_C_typespec},
1851 {"",}, {"",}, {"",}, {"",}, {"",},
1852 {"explicit", C_PLPL, st_C_typespec},
1853 {"auto", 0, st_C_typespec},
1854 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1856 {"int", 0, st_C_typespec},
1858 {"typedef", 0, st_C_typedef},
1859 {"typename", C_PLPL, st_C_typespec},
1861 {"interface", C_JAVA, st_C_struct},
1863 {"bool", C_PLPL, st_C_typespec},
1864 {"",}, {"",}, {"",},
1865 {"import", C_JAVA, st_C_ignore},
1867 {"friend", C_PLPL, st_C_ignore},
1868 {"float", 0, st_C_typespec},
1869 {"implements", C_JAVA, st_C_javastruct},
1872 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) {
1873 register int key = hash(str, len);
1875 if (key <= MAX_HASH_VALUE && key >= 0) {
1876 register char *s = wordlist[key].name;
1878 if (*s == *str && !strncmp(str + 1, s + 1, len - 1))
1879 return &wordlist[key];
1887 enum sym_type C_symtype PP((char *str, int len, int c_ext));
1888 enum sym_type C_symtype(str, len, c_ext)
1893 register struct C_stab_entry *se = in_word_set(str, len);
1895 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1901 * C functions and variables are recognized using a simple
1902 * finite automaton. fvdef is its state variable.
1905 fvnone, /* nothing seen */
1906 fvnameseen, /* function or variable name seen */
1907 fstartlist, /* func: just after open parenthesis */
1908 finlist, /* func: in parameter list */
1909 flistseen, /* func: after parameter list */
1910 fignore, /* func: before open brace */
1911 vignore /* var-like: ignore until ';' */
1915 * typedefs are recognized using a simple finite automaton.
1916 * typdef is its state variable.
1919 tnone, /* nothing seen */
1920 ttypedseen, /* typedef keyword seen */
1921 tinbody, /* inside typedef body */
1922 tend, /* just before typedef tag */
1923 tignore /* junk after typedef tag */
1927 * struct-like structures (enum, struct and union) are recognized
1928 * using another simple finite automaton. `structdef' is its state
1932 snone, /* nothing seen yet */
1933 skeyseen, /* struct-like keyword seen */
1934 stagseen, /* struct-like tag seen */
1935 scolonseen, /* colon seen after struct-like tag */
1936 sinbody /* in struct body: recognize member func defs */
1940 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1941 * struct tag, and structtype is the type of the preceding struct-like
1944 char *structtag = "<uninited>";
1945 enum sym_type structtype;
1948 void oo_browser_check_and_clear_structtype(void)
1950 /* Allow for multiple enum_label tags. */
1951 if (structtype != st_C_enum)
1952 structtype = st_none;
1957 * When objdef is different from onone, objtag is the name of the class.
1959 char *objtag = "<uninited>";
1962 * Yet another little state machine to deal with preprocessor lines.
1965 dnone, /* nothing seen */
1966 dsharpseen, /* '#' seen as first char on line */
1967 ddefineseen, /* '#' and 'define' seen */
1968 dignorerest /* ignore rest of line */
1972 * State machine for Objective C protocols and implementations.
1973 * Tom R.Hageman <tom@basil.icce.rug.nl>
1976 onone, /* nothing seen */
1977 oprotocol, /* @interface or @protocol seen */
1978 oimplementation, /* @implementations seen */
1979 otagseen, /* class name seen */
1980 oparenseen, /* parenthesis before category seen */
1981 ocatseen, /* category name seen */
1982 oinbody, /* in @implementation body */
1983 omethodsign, /* in @implementation body, after +/- */
1984 omethodtag, /* after method name */
1985 omethodcolon, /* after method colon */
1986 omethodparm, /* after method parameter */
1987 oignore /* wait for @end */
1991 * Use this structure to keep info about the token read, and how it
1992 * should be tagged. Used by the make_C_tag function to build a tag.
2004 token tok; /* latest token read */
2007 * Set this to TRUE, and the next token considered is called a function.
2008 * Used only for GNU emacs's function-defining macros.
2010 bool next_token_is_func;
2013 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
2018 * methodlen is the length of the method name stored in token_name.
2023 void oo_browser_clear_all_globals(void)
2025 /* Initialize globals so there is no carry over between files. */
2026 oo_browser_construct = C_NULL;
2032 structtype = st_none;
2033 next_token_is_func = yacc_rules = FALSE;
2036 void oo_browser_clear_some_globals(void)
2038 oo_browser_construct = C_NULL;
2039 structtype = st_none;
2045 * checks to see if the current token is at the start of a
2046 * function or variable, or corresponds to a typedef, or
2047 * is a struct/union/enum tag, or #define, or an enum constant.
2049 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2050 * with args. C_EXT is which language we are looking at.
2052 * In the future we will need some way to adjust where the end of
2053 * the token is; for instance, implementing the C++ keyword
2054 * `operator' properly will adjust the end of the token to be after
2055 * whatever follows `operator'.
2063 * next_token_is_func IN OUT
2065 bool consider_token PP((char *str, int len, int c, int c_ext,
2066 int cblev, int parlev, bool * is_func_or_var));
2067 bool consider_token(str, len, c, c_ext, cblev, parlev, is_func_or_var)
2068 register char *str; /* IN: token pointer */
2069 register int len; /* IN: token length */
2070 register int c; /* IN: first char after the token */
2071 int c_ext; /* IN: C extensions mask */
2072 int cblev; /* IN: curly brace level */
2073 int parlev; /* IN: parenthesis level */
2074 bool *is_func_or_var; /* OUT: function or variable found */
2076 enum sym_type toktype = C_symtype(str, len, c_ext);
2079 switch ((unsigned int)toktype) {
2081 set_construct(C_STRUCTURE);
2084 set_construct(C_UNION);
2087 set_construct(C_CLASS);
2090 set_construct(C_ENUMERATION);
2093 set_construct(C_TYPE);
2096 set_construct(C_EXTERN);
2099 set_construct(C_FUNCTION);
2109 * Advance the definedef state machine.
2111 switch (definedef) {
2113 /* We're not on a preprocessor line. */
2116 if (toktype == st_C_define) {
2117 definedef = ddefineseen;
2119 definedef = dignorerest;
2124 * Make a tag for any macro, unless it is a constant
2125 * and constantypedefs is FALSE.
2127 definedef = dignorerest;
2129 *is_func_or_var = (c == '(');
2132 char *p = str + len * sizeof(char);
2135 /* This must be a macro since there is no
2136 whitespace between the opening parenthesis
2137 and the definition name. */
2138 *is_func_or_var = TRUE;
2140 *is_func_or_var = FALSE;
2142 /* Handle possible whitespace between macro tag and opening
2143 parenthesis and ensure this is an actual macro.
2144 -- Bob Weiner, Altrasoft, 11/19/1997 */
2145 while (*p && isspace(*p))
2150 /* Skip over nested parentheses. */
2154 while (*++p && depth > 0 && *p != '\n') {
2167 /* If this is a macro, we have just passed
2168 the arguments and there will be more on
2169 the line before the NULL character that marks
2170 the end of the line token. */
2171 while (*p == ' ' || *p == '\t')
2174 *is_func_or_var = TRUE;
2179 set_construct((*is_func_or_var) ? C_MACRO : C_CONSTANT);
2181 if (!*is_func_or_var && !constantypedefs)
2188 error("internal error: definedef value.", (char *)NULL);
2196 if (toktype == st_C_typedef) {
2198 typdef = ttypedseen;
2204 switch ((unsigned int)toktype) {
2206 set_construct(C_CONSTANT);
2227 /* Do not return here, so the structdef stuff has a chance. */
2230 switch ((unsigned int)toktype) {
2232 set_construct(C_CONSTANT);
2258 * This structdef business is currently only invoked when cblev==0.
2259 * It should be recursively invoked whatever the curly brace level,
2260 * and a stack of states kept, to allow for definitions of structs
2263 * This structdef business is NOT invoked when we are ctags and the
2264 * file is plain C. This is because a struct tag may have the same
2265 * name as another tag, and this loses with ctags.
2267 switch ((unsigned int)toktype) {
2268 case st_C_javastruct:
2269 if (structdef == stagseen)
2270 structdef = scolonseen;
2279 if (typdef == ttypedseen
2280 || (typedefs_and_cplusplus && cblev == 0
2281 && structdef == snone)) {
2282 structdef = skeyseen;
2283 structtype = toktype;
2292 if (structdef == skeyseen) {
2293 /* Save the tag for struct/union/class, for functions and variables
2294 that may be defined inside. */
2296 if (structtype == st_C_struct)
2298 if (structtype == st_C_struct
2299 || structtype == st_C_union || structtype == st_C_class)
2301 structtag = savenstr(str, len);
2303 structtag = "<enum>";
2304 structdef = stagseen;
2308 /* Avoid entering fvdef stuff if typdef is going on. */
2309 if (typdef != tnone) {
2314 /* Detect GNU macros.
2316 DEFUN note for writers of emacs C code:
2317 The DEFUN macro, used in emacs C source code, has a first arg
2318 that is a string (the lisp function name), and a second arg that
2319 is a C function name. Since etags skips strings, the second arg
2320 is tagged. This is unfortunate, as it would be better to tag the
2321 first arg. The simplest way to deal with this problem would be
2322 to name the tag with a name built from the function name, by
2323 removing the initial 'F' character and substituting '-' for '_'.
2324 Anyway, this assumes that the conventions of naming lisp
2325 functions will never change. Currently, this method is not
2326 implemented, so writers of emacs code are recommended to put the
2327 first two args of a DEFUN on the same line. */
2328 if (definedef == dnone && toktype == st_C_gnumacro) {
2329 next_token_is_func = TRUE;
2332 if (next_token_is_func) {
2333 next_token_is_func = FALSE;
2335 *is_func_or_var = TRUE;
2339 /* Detect Objective C constructs. */
2342 switch ((unsigned int)toktype) {
2345 set_construct(C_OBJC);
2351 set_construct(C_OBJC);
2353 objdef = oimplementation;
2361 case oimplementation:
2362 /* Save the class tag for functions or variables defined inside. */
2363 objtag = savenstr(str, len);
2367 /* Save the class tag for categories. */
2368 objtag = savenstr(str, len);
2370 *is_func_or_var = TRUE;
2374 *is_func_or_var = TRUE;
2380 objdef = omethodtag;
2382 grow_linebuffer(&token_name, methodlen + 1);
2383 strncpy(token_name.buffer, str, len);
2384 token_name.buffer[methodlen] = '\0';
2385 token_name.len = methodlen;
2391 objdef = omethodparm;
2395 objdef = omethodtag;
2397 grow_linebuffer(&token_name, methodlen + 1);
2398 strncat(token_name.buffer, str, len);
2399 token_name.len = methodlen;
2404 if (toktype == st_C_objend) {
2405 /* Memory leakage here: the string pointed by objtag is
2406 never released, because many tests would be needed to
2407 avoid breaking on incorrect input code. The amount of
2408 memory leaked here is the sum of the lengths of the
2423 /* A function, variable or enum constant? */
2424 switch ((unsigned int)toktype) {
2426 set_construct(C_CONSTANT);
2432 if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
2433 fvdef = fvnone; /* should be useless */
2439 if (constantypedefs && structdef == sinbody
2440 && structtype == st_C_enum)
2443 oo_browser_construct = C_ENUM_LABEL;
2449 if (fvdef == fvnone) {
2450 fvdef = fvnameseen; /* function or variable */
2451 *is_func_or_var = TRUE;
2465 * This routine finds functions, variables, typedefs,
2466 * #define's, enum constants and struct/union/enum definitions in
2467 * #C syntax and adds them to the list.
2469 #define current_lb_is_new (newndx == curndx)
2470 #define switch_line_buffers() (curndx = 1 - curndx)
2472 #define curlb (lbs[curndx].lb)
2473 #define othlb (lbs[1-curndx].lb)
2474 #define newlb (lbs[newndx].lb)
2475 #define curlinepos (lbs[curndx].linepos)
2476 #define othlinepos (lbs[1-curndx].linepos)
2477 #define newlinepos (lbs[newndx].linepos)
2479 #define CNL_SAVE_DEFINEDEF() \
2481 curlinepos = charno; \
2483 linecharno = charno; \
2484 charno += readline (&curlb, inf); \
2485 lp = curlb.buffer; \
2492 CNL_SAVE_DEFINEDEF(); \
2493 if (savetok.valid) \
2496 savetok.valid = FALSE; \
2498 definedef = dnone; \
2501 void make_C_tag PP((bool isfun));
2502 void make_C_tag(isfun)
2505 /* This function should never be called when tok.valid is FALSE, but
2506 we must protect against invalid input or internal errors. */
2508 if (traditional_tag_style) {
2509 /* This was the original code. Now we call new_pfnote instead,
2510 which uses the new method for naming tags (see new_pfnote). */
2513 if (CTAGS || tok.named)
2514 name = savestr(token_name.buffer);
2516 tok.buffer, tok.linelen, tok.lineno,
2519 new_pfnote(token_name.buffer, token_name.len, isfun,
2520 tok.buffer, tok.linelen, tok.lineno,
2527 void C_entries(c_ext, inf)
2528 int c_ext; /* extension of C */
2529 FILE *inf; /* input file */
2531 register char c; /* latest char read; '\0' for end of line */
2532 register char *lp; /* pointer one beyond the character `c' */
2533 int curndx, newndx; /* indices for current and new lb */
2534 register int tokoff; /* offset in line of start of current token */
2535 register int toklen; /* length of current token */
2536 char *qualifier; /* string used to qualify names */
2537 int qlen; /* length of qualifier */
2538 int cblev; /* current curly brace level */
2539 int parlev; /* current parenthesis level */
2540 bool incomm, inquote, inchar, quotednl, midtoken;
2542 token savetok; /* token saved during preprocessor handling */
2544 /* initialise savetok */
2545 memset(&savetok, 0, sizeof(token));
2547 tokoff = toklen = 0; /* keep compiler quiet */
2548 curndx = newndx = 0;
2559 next_token_is_func = yacc_rules = FALSE;
2560 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2561 tok.valid = savetok.valid = FALSE;
2564 cplpl = (c_ext & C_PLPL) == C_PLPL;
2565 cjava = (c_ext & C_JAVA) == C_JAVA;
2574 while (!feof(inf)) {
2577 /* If we're at the end of the line, the next character is a
2578 '\0'; don't skip it, because it's the thing that tells us
2579 to read the next line. */
2586 } else if (incomm) {
2595 /* Newlines inside comments do not end macro definitions in
2597 CNL_SAVE_DEFINEDEF();
2603 } else if (inquote) {
2609 /* Newlines inside strings do not end macro definitions
2610 in traditional cpp, even though compilers don't
2611 usually accept them. */
2612 CNL_SAVE_DEFINEDEF();
2618 } else if (inchar) {
2621 /* Hmmm, something went wrong. */
2635 if (fvdef != finlist && fvdef != fignore
2636 && fvdef != vignore)
2641 if (fvdef != finlist && fvdef != fignore
2642 && fvdef != vignore)
2650 } else if ( /* cplpl && */ *lp == '/') {
2656 if ((c_ext & YACC) && *lp == '%') {
2657 /* entering or exiting rules section in yacc file */
2663 next_token_is_func = FALSE;
2664 midtoken = inquote = inchar = incomm =
2667 yacc_rules = !yacc_rules;
2672 if (definedef == dnone) {
2674 bool cpptoken = TRUE;
2676 /* Look back on this line. If all blanks, or nonblanks
2677 followed by an end of comment, this is a preprocessor
2679 for (cp = newlb.buffer; cp < lp - 1;
2681 if (!iswhite(*cp)) {
2692 definedef = dsharpseen;
2694 /* if (definedef == dnone) */
2700 /* Consider token only if some complicated conditions are satisfied. */
2701 if ((definedef != dnone
2702 || (cblev == 0 && structdef != scolonseen)
2703 || (cblev == 1 && cplpl && structdef == sinbody)
2704 || (structdef == sinbody && structtype == st_C_enum))
2705 && typdef != tignore
2706 && definedef != dignorerest && fvdef != finlist) {
2709 if (c == ':' && cplpl && *lp == ':'
2710 && begtoken(*(lp + 1))) {
2712 * This handles :: in the middle, but not at the
2713 * beginning of an identifier.
2718 set_construct(C_METHOD);
2721 bool funorvar = FALSE;
2724 || consider_token(newlb.
2734 if (structdef == sinbody
2737 /* function or var defined in C++ class body */
2767 oo_browser_construct
2770 } else if (objdef ==
2772 /* Objective C category */
2805 oo_browser_construct
2808 } else if (objdef ==
2812 /* Objective C method */
2817 oo_browser_construct
2846 /* Also name #define constants,
2847 enumerations and enum_labels.
2848 Conditionalize `funorvar' reference
2849 here or #defines will appear without
2851 -- Bob Weiner, Altrasoft, 4/25/1998 */
2853 ((oo_browser_format || funorvar)
2861 (oo_browser_construct
2865 oo_browser_construct
2878 tok.lineno = lineno;
2880 tokoff + toklen + 1;
2887 if (definedef == dnone
2896 if (current_lb_is_new)
2905 } /* if (endtoken (c)) */
2906 else if (intoken(c)) {
2910 } /* if (midtoken) */
2911 else if (begtoken(c)) {
2912 switch (definedef) {
2914 switch ((unsigned int)fvdef) {
2920 set_construct(C_MACRO);
2922 make_C_tag(TRUE); /* a function */
2933 if (structdef == stagseen && !cjava)
2945 if (!yacc_rules || lp == newlb.buffer + 1) {
2946 tokoff = lp - 1 - newlb.buffer;
2951 } /* if (begtoken) */
2954 /* if must look at token */
2955 /* Detect end of line, colon, comma, semicolon and various braces
2956 after having handled a token. */
2959 if (definedef != dnone)
2961 switch ((unsigned int)objdef) {
2964 make_C_tag(TRUE); /* an Objective C class */
2968 objdef = omethodcolon;
2970 grow_linebuffer(&token_name, methodlen + 1);
2971 strcat(token_name.buffer, ":");
2972 token_name.len = methodlen;
2979 if (structdef == stagseen)
2980 structdef = scolonseen;
2982 switch ((unsigned int)fvdef) {
2985 make_C_tag(FALSE); /* a yacc function */
2999 if (definedef != dnone)
3002 switch ((unsigned int)typdef) {
3005 set_construct(C_TYPE);
3007 make_C_tag(FALSE); /* a typedef */
3012 switch ((unsigned int)fvdef) {
3016 if ((globals && cblev == 0)
3017 || (members && cblev == 1))
3019 make_C_tag(FALSE); /* a variable */
3021 /* if (constantypedefs && structdef == snone)*/
3024 switch ((unsigned int)structtype) {
3026 set_construct(C_ENUMERATION);
3029 set_construct(C_CLASS);
3032 set_construct(C_VARIABLE);
3036 /* Force reset of st_C_enum structtype value. */
3037 structtype = st_none;
3043 /* The following instruction invalidates the token.
3044 Probably the token should be invalidated in all
3045 other cases where some state machine is reset. */
3048 if (structdef == stagseen)
3052 if (definedef != dnone)
3054 switch ((unsigned int)objdef) {
3057 make_C_tag(TRUE); /* an Objective C method */
3065 switch ((unsigned int)fvdef) {
3071 if ((globals && cblev == 0)
3072 || (members && cblev == 1))
3073 make_C_tag(FALSE); /* a variable */
3078 if (structdef == stagseen)
3082 if (definedef != dnone)
3084 if (cblev == 0 && typdef == tend) {
3086 set_construct(C_TYPE);
3089 make_C_tag(FALSE); /* a typedef */
3092 switch ((unsigned int)fvdef) {
3099 if ((globals && cblev == 0)
3100 || (members && cblev == 1))
3101 make_C_tag(FALSE); /* a variable */
3103 if (constantypedefs && structdef == snone) {
3105 switch ((unsigned int)structtype) {
3107 set_construct(C_ENUMERATION);
3110 set_construct(C_CLASS);
3113 set_construct(C_VARIABLE);
3117 /* Force reset of st_C_enum structtype value. */
3118 structtype = st_none;
3128 if (structdef == stagseen)
3132 if (definedef != dnone)
3134 if (objdef == otagseen && parlev == 0)
3135 objdef = oparenseen;
3136 switch ((unsigned int)fvdef) {
3141 if (tok.valid && *lp != '*') {
3142 /* This handles constructs like:
3143 typedef void OperatorFun (int fun); */
3146 set_construct(C_TYPE);
3158 } /* switch (typdef) */
3174 if (definedef != dnone)
3176 if (objdef == ocatseen && parlev == 1) {
3177 make_C_tag(TRUE); /* an Objective C category */
3180 if (--parlev == 0) {
3181 switch ((unsigned int)fvdef) {
3191 if (cblev == 0 && typdef == tend) {
3193 set_construct(C_TYPE);
3196 make_C_tag(FALSE); /* a typedef */
3198 } else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3202 if (definedef != dnone)
3204 if (typdef == ttypedseen)
3206 switch (structdef) {
3207 case skeyseen: /* unnamed struct */
3208 structdef = sinbody;
3209 structtag = "_anonymous_";
3212 case scolonseen: /* named struct */
3213 structdef = sinbody;
3214 make_C_tag(FALSE); /* a struct */
3223 switch ((unsigned int)fvdef) {
3226 set_construct(C_FUNCTION);
3227 /* Ensure function name is recorded.
3228 -- Bob Weiner, Altrasoft */
3231 make_C_tag(TRUE); /* a function */
3237 switch ((unsigned int)objdef) {
3239 make_C_tag(TRUE); /* an Objective C class */
3244 make_C_tag(TRUE); /* an Objective C method */
3248 /* Neutralize `extern "C" {' grot. */
3249 if (cblev == 0 && structdef == snone
3261 if (definedef != dnone)
3263 if (fvdef == fstartlist)
3264 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
3267 if (definedef != dnone)
3269 if (!noindentypedefs && lp == newlb.buffer + 1) {
3270 cblev = 0; /* reset curly brace level if first column */
3271 parlev = 0; /* also reset paren level, just in case... */
3272 } else if (cblev > 0)
3275 if (typdef == tinbody)
3277 /* Memory leakage here: the string pointed by structtag is
3278 never released, because I fear to miss something and
3279 break things while freeing the area. The amount of
3280 memory leaked here is the sum of the lengths of the
3282 if (structdef == sinbody)
3283 free (structtag); */
3286 structtag = "<error>";
3288 /* Next line added to avoid any state carryover between
3289 functions. -- Bob Weiner, Altrasoft, 11/19/1997 */
3291 oo_browser_construct = C_NULL;
3296 if (definedef != dnone)
3308 if ((globals && cblev == 0)
3309 || (members && cblev == 1))
3311 make_C_tag(FALSE); /* a variable */
3315 switch ((unsigned int)structtype) {
3321 set_construct(C_CLASS);
3324 /* a global variable */
3330 /* ootags categorizes each tag found whereas etags doesn't.
3331 Set the is_method flag if this tag has been marked as
3332 such by an earlier section of code.
3333 -- Steve Baur, Altrasoft, 5/7/1998 */
3335 (oo_browser_construct ==
3339 /* Force reset of st_C_enum structtype value. */
3340 structtype = st_none;
3349 fvdef = is_method ? fignore : vignore;
3360 if (objdef == oinbody && cblev == 0) {
3361 objdef = omethodsign;
3378 if (definedef != dnone)
3383 /* The above characters cannot follow a function tag in C, so
3384 unmark this as a function entry. For C++, these characters
3385 may follow an `operator' function construct, so skip the
3386 unmarking conditional below.
3387 -- Steve Baur, Altrasoft, 5/7/1998 */
3388 if (fvdef != finlist && fvdef != fignore
3389 && fvdef != vignore)
3396 if (objdef == otagseen) {
3397 make_C_tag(TRUE); /* an Objective C class */
3400 /* If a macro spans multiple lines don't reset its state. */
3402 CNL_SAVE_DEFINEDEF();
3412 } /* while not eof */
3416 * Process either a C++ file or a C file depending on the setting
3419 void default_C_entries(inf)
3422 C_entries(cplusplus ? C_PLPL : 0, inf);
3425 /* Always do plain ANSI C. */
3426 void plain_C_entries(inf)
3432 /* Always do C++. */
3433 void Cplusplus_entries(inf)
3436 C_entries(C_PLPL, inf);
3439 /* Always do Java. */
3440 void Cjava_entries(inf)
3443 C_entries(C_JAVA, inf);
3447 void Cstar_entries(inf)
3450 C_entries(C_STAR, inf);
3453 /* Always do Yacc. */
3454 void Yacc_entries(inf)
3457 C_entries(YACC, inf);
3460 /* A useful macro. */
3461 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3462 for (lineno = charno = 0; /* loop initialization */ \
3463 !feof (file_pointer) /* loop test */ \
3464 && (lineno++, /* instructions at start of loop */ \
3465 linecharno = charno, \
3466 charno += readline (&line_buffer, file_pointer), \
3467 char_pointer = lb.buffer, \
3472 * Read a file, but do no processing. This is used to do regexp
3473 * matching on files that have no language defined.
3475 void just_read_file(inf)
3478 register char *dummy;
3480 LOOP_ON_INPUT_LINES(inf, lb, dummy)
3484 /* Fortran parsing */
3486 bool tail PP((char *cp));
3490 register int len = 0;
3492 while (*cp && lowcase(*cp) == lowcase(dbp[len]))
3494 if (*cp == '\0' && !intoken(dbp[len])) {
3503 dbp = skip_spaces(dbp);
3507 dbp = skip_spaces(dbp);
3508 if (strneq(dbp, "(*)", 3)) {
3512 if (!isdigit(*dbp)) {
3513 --dbp; /* force failure */
3518 while (isdigit(*dbp));
3521 void getit PP((FILE * inf));
3527 dbp = skip_spaces(dbp);
3530 linecharno = charno;
3531 charno += readline(&lb, inf);
3536 dbp = skip_spaces(dbp);
3539 && *dbp != '_' && *dbp != '$')
3541 for (cp = dbp + 1; *cp && intoken(*cp); cp++)
3543 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
3544 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3547 void Fortran_functions(inf)
3550 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
3552 dbp++; /* Ratfor escape to fortran */
3553 dbp = skip_spaces(dbp);
3556 switch (lowcase(*dbp)) {
3558 if (tail("integer"))
3566 if (tail("logical"))
3570 if (tail("complex") || tail("character"))
3574 if (tail("double")) {
3575 dbp = skip_spaces(dbp);
3578 if (tail("precision"))
3586 dbp = skip_spaces(dbp);
3589 switch (lowcase(*dbp)) {
3591 if (tail("function"))
3595 if (tail("subroutine"))
3603 if (tail("program")) {
3607 if (tail("procedure"))
3617 * Bob Weiner, Motorola Inc., 4/3/94
3618 * Unix and microcontroller assembly tag handling
3619 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3621 void Asm_labels(FILE * inf)
3625 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3626 /* If first char is alphabetic or one of [_.$], test for colon
3627 following identifier. */
3628 if (isalpha(*cp) || *cp == '_' || *cp == '.' || *cp == '$') {
3629 /* Read past label. */
3631 while (isalnum(*cp) || *cp == '_' || *cp == '.'
3634 if (*cp == ':' || isspace(*cp)) {
3635 /* Found end of label, so copy it and add it to the table. */
3638 cp - lb.buffer) : NULL, TRUE,
3639 lb.buffer, cp - lb.buffer + 1, lineno,
3647 * Perl support by Bart Robinson <lomew@cs.utah.edu>
3648 * enhanced by Michael Ernst <mernst@alum.mit.edu>
3649 * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
3650 * Perl variable names: /^(my|local).../
3652 void Perl_functions(inf)
3657 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3659 && *cp++ == 'u' && *cp++ == 'b' && isspace(*cp++)) {
3660 cp = skip_spaces(cp);
3663 && !isspace(*cp) && *cp != '{'
3668 cp - lb.buffer) : NULL, TRUE,
3669 lb.buffer, cp - lb.buffer + 1, lineno,
3672 } else if (globals /* only if tagging global vars is enabled */
3673 && ((cp = lb.buffer, *cp++ == 'm' && *cp++ == 'y')
3678 && *cp++ == 'a' && *cp++ == 'l'))
3679 && (*cp == '(' || isspace(*cp))) {
3680 /* After "my" or "local", but before any following paren or space. */
3681 char *varname = NULL;
3683 cp = skip_spaces(cp);
3684 if (*cp == '$' || *cp == '@' || *cp == '%') {
3685 char *varstart = ++cp;
3686 while (isalnum(*cp) || *cp == '_')
3688 varname = savenstr(varstart, cp - varstart);
3690 /* Should be examining a variable list at this point;
3691 could insist on seeing an open parenthesis. */
3692 while (*cp != '\0' && *cp != ';' && *cp != '='
3697 /* Perhaps I should back cp up one character, so the TAGS table
3698 doesn't mention (and so depend upon) the following char. */
3699 pfnote((CTAGS) ? savenstr(lb.buffer, cp - lb.buffer) :
3700 varname, FALSE, lb.buffer, cp - lb.buffer + 1,
3701 lineno, linecharno);
3707 * Python support by Eric S. Raymond <esr@thyrsus.com>
3708 * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3710 void Python_functions(inf)
3715 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3717 && *cp++ == 'e' && *cp++ == 'f' && isspace(*cp++)) {
3718 cp = skip_spaces(cp);
3719 while (*cp != '\0' && !isspace(*cp) && *cp != '('
3722 pfnote((char *)NULL, TRUE,
3723 lb.buffer, cp - lb.buffer + 1, lineno,
3731 && *cp++ == 's' && *cp++ == 's' && isspace(*cp++)) {
3732 cp = skip_spaces(cp);
3733 while (*cp != '\0' && !isspace(*cp) && *cp != '('
3736 pfnote((char *)NULL, TRUE,
3737 lb.buffer, cp - lb.buffer + 1, lineno,
3743 /* Idea by Corny de Souza
3744 * Cobol tag functions
3745 * We could look for anything that could be a paragraph name.
3746 * i.e. anything that starts in column 8 is one word and ends in a full stop.
3748 void Cobol_paragraphs(inf)
3751 register char *bp, *ep;
3753 LOOP_ON_INPUT_LINES(inf, lb, bp) {
3758 /* If eoln, compiler option or comment ignore whole line. */
3759 if (bp[-1] != ' ' || !isalnum(bp[0]))
3762 for (ep = bp; isalnum(*ep) || *ep == '-'; ep++)
3765 pfnote((CTAGS) ? savenstr(bp, ep - bp) : NULL, TRUE,
3766 lb.buffer, ep - lb.buffer + 1, lineno,
3771 /* Added by Mosur Mohan, 4/22/88 */
3772 /* Pascal parsing */
3775 * Locates tags for procedures & functions. Doesn't do any type- or
3776 * var-definitions. It does look for the keyword "extern" or
3777 * "forward" immediately following the procedure statement; if found,
3778 * the tag is skipped.
3780 void Pascal_functions(inf)
3783 linebuffer tline; /* mostly copied from C_entries */
3785 int save_lineno, save_len;
3786 char c, *cp, *namebuf;
3788 bool /* each of these flags is TRUE iff: */
3789 incomment, /* point is inside a comment */
3790 inquote, /* point is inside '..' string */
3791 get_tagname, /* point is after PROCEDURE/FUNCTION
3792 keyword, so next item = potential tag */
3793 found_tag, /* point is after a potential tag */
3794 inparms, /* point is within parameter-list */
3795 verify_tag; /* point has passed the parm-list, so the
3796 next token will determine whether this
3797 is a FORWARD/EXTERN to be ignored, or
3798 whether it is a real tag */
3800 save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3801 namebuf = NULL; /* keep compiler quiet */
3808 incomment = inquote = FALSE;
3809 found_tag = FALSE; /* have a proc name; check if extern */
3810 get_tagname = FALSE; /* have found "procedure" keyword */
3811 inparms = FALSE; /* found '(' after "proc" */
3812 verify_tag = FALSE; /* check if "extern" is ahead */
3814 while (!feof(inf)) { /* long main loop to get next char */
3816 if (c == '\0') { /* if end of line */
3818 linecharno = charno;
3819 charno += readline(&lb, inf);
3823 if (!((found_tag && verify_tag)
3825 c = *dbp++; /* only if don't need *dbp pointing
3826 to the beginning of the name of
3827 the procedure or function */
3830 if (c == '}') /* within { } comments */
3832 else if (c == '*' && *dbp == ')') { /* within (* *) comments */
3837 } else if (inquote) {
3844 inquote = TRUE; /* found first quote */
3846 case '{': /* found open { comment */
3850 if (*dbp == '*') { /* found open (* comment */
3853 } else if (found_tag) /* found '(' after tag, i.e., parm-list */
3856 case ')': /* end of parms list */
3861 if (found_tag && !inparms) { /* end of proc or fn stmt */
3869 if (found_tag && verify_tag && (*dbp != ' ')) {
3870 /* check if this is an "extern" declaration */
3873 if (lowcase(*dbp == 'e')) {
3874 if (tail("extern")) { /* superfluous, really! */
3878 } else if (lowcase(*dbp) == 'f') {
3879 if (tail("forward")) { /* check for forward reference */
3884 if (found_tag && verify_tag) { /* not external proc, so make tag */
3887 pfnote(namebuf, TRUE,
3888 tline.buffer, save_len, save_lineno,
3893 if (get_tagname) { /* grab name of proc or fn */
3897 /* save all values for later tagging */
3898 grow_linebuffer(&tline, lb.len + 1);
3899 strcpy(tline.buffer, lb.buffer);
3900 save_lineno = lineno;
3901 save_lcno = linecharno;
3903 /* grab block name */
3904 for (cp = dbp + 1; *cp != '\0' && !endtoken(*cp); cp++)
3906 namebuf = (CTAGS) ? savenstr(dbp, cp - dbp) : NULL;
3907 dbp = cp; /* set dbp to e-o-token */
3908 save_len = dbp - lb.buffer + 1;
3909 get_tagname = FALSE;
3913 /* and proceed to check for "extern" */
3914 } else if (!incomment && !inquote && !found_tag) {
3915 /* check for proc/fn keywords */
3916 switch (lowcase(c)) {
3918 if (tail("rocedure")) /* c = 'p', dbp has advanced */
3922 if (tail("unction"))
3929 } /* while not eof */
3935 * lisp tag functions
3936 * look for (def or (DEF, quote or QUOTE
3938 int L_isdef PP((char *strp));
3940 register char *strp;
3942 return ((strp[1] == 'd' || strp[1] == 'D')
3943 && (strp[2] == 'e' || strp[2] == 'E')
3944 && (strp[3] == 'f' || strp[3] == 'F'));
3946 int L_isquote PP((char *strp));
3948 register char *strp;
3950 return ((*++strp == 'q' || *strp == 'Q')
3951 && (*++strp == 'u' || *strp == 'U')
3952 && (*++strp == 'o' || *strp == 'O')
3953 && (*++strp == 't' || *strp == 'T')
3954 && (*++strp == 'e' || *strp == 'E')
3955 && isspace(*++strp));
3958 void L_getit PP((void));
3963 if (*dbp == '\'') /* Skip prefix quote */
3965 else if (*dbp == '(') {
3967 dbp += 7; /* Skip "(quote " */
3969 dbp += 1; /* Skip "(" before name in (defstruct (foo)) */
3970 dbp = skip_spaces(dbp);
3973 for (cp = dbp /*+1 */ ;
3974 *cp != '\0' && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
3979 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
3980 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3983 void Lisp_functions(inf)
3986 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
3987 if (dbp[0] == '(') {
3989 dbp = skip_non_spaces(dbp);
3990 dbp = skip_spaces(dbp);
3993 /* Check for (foo::defmumble name-defined ... */
3996 while (*dbp != '\0' && !isspace(*dbp)
3997 && *dbp != ':' && *dbp != '('
4002 while (*dbp == ':');
4004 if (L_isdef(dbp - 1)) {
4005 dbp = skip_non_spaces(dbp);
4006 dbp = skip_spaces(dbp);
4016 * Postscript tag functions
4017 * Just look for lines where the first character is '/'
4018 * Richard Mlynarik <mly@adoc.xerox.com>
4020 void Postscript_functions(inf)
4023 register char *bp, *ep;
4025 LOOP_ON_INPUT_LINES(inf, lb, bp) {
4028 *ep != '\0' && *ep != ' ' && *ep != '{'; ep++)
4030 pfnote((CTAGS) ? savenstr(bp, ep - bp) : NULL, TRUE,
4031 lb.buffer, ep - lb.buffer + 1, lineno,
4038 * Scheme tag functions
4039 * look for (def... xyzzy
4040 * look for (def... (xyzzy
4041 * look for (def ... ((...(xyzzy ....
4042 * look for (set! xyzzy
4045 void get_scheme PP((void));
4047 void Scheme_functions(inf)
4050 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
4051 if (dbp[0] == '(' && (dbp[1] == 'D' || dbp[1] == 'd')
4052 && (dbp[2] == 'E' || dbp[2] == 'e')
4053 && (dbp[3] == 'F' || dbp[3] == 'f')) {
4054 dbp = skip_non_spaces(dbp);
4055 /* Skip over open parens and white space */
4056 while (isspace(*dbp) || *dbp == '(')
4060 if (dbp[0] == '(' && (dbp[1] == 'S' || dbp[1] == 's')
4061 && (dbp[2] == 'E' || dbp[2] == 'e')
4062 && (dbp[3] == 'T' || dbp[3] == 't')
4063 && (dbp[4] == '!' || dbp[4] == '!')
4064 && (isspace(dbp[5]))) {
4065 dbp = skip_non_spaces(dbp);
4066 dbp = skip_spaces(dbp);
4078 /* Go till you get to white space or a syntactic break */
4080 *cp != '\0' && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
4082 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
4083 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4086 /* Find tags in TeX and LaTeX input files. */
4088 /* TEX_toktab is a table of TeX control sequences that define tags.
4089 Each TEX_tabent records one such control sequence.
4090 CONVERT THIS TO USE THE Stab TYPE!! */
4096 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
4098 /* Default set of control sequences to put into TEX_toktab.
4099 The value of environment var TEXTAGS is prepended to this. */
4101 char *TEX_defenv = "\
4102 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4103 :part:appendix:entry:index";
4105 void TEX_mode PP((FILE * inf));
4106 struct TEX_tabent *TEX_decode_env PP((char *evarname, char *defenv));
4107 int TEX_Token PP((char *cp));
4109 char TEX_esc = '\\';
4110 char TEX_opgrp = '{';
4111 char TEX_clgrp = '}';
4114 * TeX/LaTeX scanning loop.
4116 void TeX_functions(inf)
4122 /* Select either \ or ! as escape character. */
4125 /* Initialize token table once from environment. */
4127 TEX_toktab = TEX_decode_env("TEXTAGS", TEX_defenv);
4129 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4131 /* Look at each esc in line. */
4132 while ((cp = etags_strchr(cp, TEX_esc)) != NULL) {
4135 linecharno += cp - lasthit;
4137 i = TEX_Token(lasthit);
4139 /* We seem to include the TeX command in the tag name.
4141 for (p = lasthit + TEX_toktab[i].len;
4142 *p != '\0' && *p != TEX_clgrp;
4145 pfnote( /*savenstr (lasthit, p-lasthit) */
4147 lb.buffer, lb.len, lineno, linecharno);
4148 break; /* We only tag a line once */
4154 #define TEX_LESC '\\'
4155 #define TEX_SESC '!'
4158 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4159 chars accordingly. */
4165 while ((c = getc(inf)) != EOF) {
4166 /* Skip to next line if we hit the TeX comment char. */
4170 else if (c == TEX_LESC || c == TEX_SESC)
4174 if (c == TEX_LESC) {
4186 /* Read environment and prepend it to the default string.
4187 Build token table. */
4188 struct TEX_tabent *TEX_decode_env(evarname, defenv)
4192 register char *env, *p;
4194 struct TEX_tabent *tab;
4197 /* Append default string to environment. */
4198 env = getenv(evarname);
4203 env = concat(oldenv, defenv, "");
4207 /* Allocate a token table */
4208 for (size = 1, p = env; p;)
4209 if ((p = etags_strchr(p, ':')) && *++p != '\0')
4211 /* Add 1 to leave room for null terminator. */
4212 tab = xnew(size + 1, struct TEX_tabent);
4214 /* Unpack environment string into token table. Be careful about */
4215 /* zero-length strings (leading ':', "::" and trailing ':') */
4216 for (i = 0; *env;) {
4217 p = etags_strchr(env, ':');
4218 if (!p) /* End of environment string. */
4219 p = env + strlen(env);
4220 if (p - env > 0) { /* Only non-zero strings. */
4221 tab[i].name = savenstr(env, p - env);
4222 tab[i].len = strlen(tab[i].name);
4228 tab[i].name = NULL; /* Mark end of table. */
4236 /* If the text at CP matches one of the tag-defining TeX command names,
4237 return the pointer to the first occurrence of that command in TEX_toktab.
4238 Otherwise return -1.
4239 Keep the capital `T' in `token' for dumb truncating compilers
4240 (this distinguishes it from `TEX_toktab' */
4246 for (i = 0; TEX_toktab[i].len > 0; i++)
4247 if (strneq(TEX_toktab[i].name, cp, TEX_toktab[i].len))
4253 * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4255 * Assumes that the predicate starts at column 0.
4256 * Only the first clause of a predicate is added.
4258 int prolog_pred PP((char *s, char *last));
4259 void prolog_skip_comment PP((linebuffer * plb, FILE * inf));
4260 int prolog_atom PP((char *s, int pos));
4262 void Prolog_functions(inf)
4273 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4274 if (cp[0] == '\0') /* Empty line */
4276 else if (isspace(cp[0])) /* Not a predicate */
4278 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
4279 prolog_skip_comment(&lb, inf);
4280 else if ((len = prolog_pred(cp, last)) > 0) {
4281 /* Predicate. Store the function name so that we only
4282 generate a tag for the first clause. */
4284 last = xnew(len + 1, char);
4285 else if (len + 1 > allocated)
4286 last = xrnew(last, len + 1, char);
4287 allocated = len + 1;
4288 strncpy(last, cp, len);
4294 void prolog_skip_comment(plb, inf)
4301 for (cp = plb->buffer; *cp != '\0'; cp++)
4302 if (cp[0] == '*' && cp[1] == '/')
4305 linecharno += readline(plb, inf);
4311 * A predicate definition is added if it matches:
4312 * <beginning of line><Prolog Atom><whitespace>(
4314 * It is added to the tags database if it doesn't match the
4315 * name of the previous clause header.
4317 * Return the size of the name of the predicate, or 0 if no header
4320 int prolog_pred(s, last)
4322 char *last; /* Name of last clause. */
4327 pos = prolog_atom(s, 0);
4332 pos = skip_spaces(s + pos) - s;
4334 if ((s[pos] == '(') || (s[pos] == '.')) {
4338 /* Save only the first clause. */
4339 if (last == NULL || len != (int)strlen(last)
4340 || !strneq(s, last, len)) {
4341 pfnote((CTAGS) ? savenstr(s, len) : NULL, TRUE,
4342 s, pos, lineno, linecharno);
4350 * Consume a Prolog atom.
4351 * Return the number of bytes consumed, or -1 if there was an error.
4353 * A prolog atom, in this context, could be one of:
4354 * - An alphanumeric sequence, starting with a lower case letter.
4355 * - A quoted arbitrary string. Single quotes can escape themselves.
4356 * Backslash quotes everything.
4358 int prolog_atom(s, pos)
4366 if (islower(s[pos]) || (s[pos] == '_')) {
4367 /* The atom is unquoted. */
4369 while (isalnum(s[pos]) || (s[pos] == '_')) {
4372 return pos - origpos;
4373 } else if (s[pos] == '\'') {
4377 if (s[pos] == '\'') {
4381 pos++; /* A double quote */
4382 } else if (s[pos] == '\0')
4383 /* Multiline quoted atoms are ignored. */
4385 else if (s[pos] == '\\') {
4386 if (s[pos + 1] == '\0')
4392 return pos - origpos;
4398 * Support for Erlang -- Anders Lindgren, Feb 1996.
4400 * Generates tags for functions, defines, and records.
4402 * Assumes that Erlang functions start at column 0.
4404 int erlang_func PP((char *s, char *last));
4405 void erlang_attribute PP((char *s));
4406 int erlang_atom PP((char *s, int pos));
4408 void Erlang_functions(inf)
4419 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4420 if (cp[0] == '\0') /* Empty line */
4422 else if (isspace(cp[0])) /* Not function nor attribute */
4424 else if (cp[0] == '%') /* comment */
4426 else if (cp[0] == '"') /* Sometimes, strings start in column one */
4428 else if (cp[0] == '-') { /* attribute, e.g. "-define" */
4429 erlang_attribute(cp);
4431 } else if ((len = erlang_func(cp, last)) > 0) {
4433 * Function. Store the function name so that we only
4434 * generates a tag for the first clause.
4437 last = xnew(len + 1, char);
4438 else if (len + 1 > allocated)
4439 last = xrnew(last, len + 1, char);
4440 allocated = len + 1;
4441 strncpy(last, cp, len);
4448 * A function definition is added if it matches:
4449 * <beginning of line><Erlang Atom><whitespace>(
4451 * It is added to the tags database if it doesn't match the
4452 * name of the previous clause header.
4454 * Return the size of the name of the function, or 0 if no function
4457 int erlang_func(s, last)
4459 char *last; /* Name of last clause. */
4464 pos = erlang_atom(s, 0);
4469 pos = skip_spaces(s + pos) - s;
4471 /* Save only the first clause. */
4472 if (s[pos++] == '(' && (last == NULL || len != (int)strlen(last)
4473 || !strneq(s, last, len))) {
4474 pfnote((CTAGS) ? savenstr(s, len) : NULL, TRUE,
4475 s, pos, lineno, linecharno);
4483 * Handle attributes. Currently, tags are generated for defines
4486 * They are on the form:
4487 * -define(foo, bar).
4488 * -define(Foo(M, N), M+N).
4489 * -record(graph, {vtab = notable, cyclic = true}).
4491 void erlang_attribute(s)
4497 if (strneq(s, "-define", 7) || strneq(s, "-record", 7)) {
4498 pos = skip_spaces(s + 7) - s;
4499 if (s[pos++] == '(') {
4500 pos = skip_spaces(s + pos) - s;
4501 len = erlang_atom(s, pos);
4503 pfnote((CTAGS) ? savenstr(&s[pos], len) : NULL,
4504 TRUE, s, pos + len, lineno, linecharno);
4511 * Consume an Erlang atom (or variable).
4512 * Return the number of bytes consumed, or -1 if there was an error.
4514 int erlang_atom(s, pos)
4522 if (isalpha(s[pos]) || s[pos] == '_') {
4523 /* The atom is unquoted. */
4525 while (isalnum(s[pos]) || s[pos] == '_')
4527 return pos - origpos;
4528 } else if (s[pos] == '\'') {
4532 if (s[pos] == '\'') {
4535 } else if (s[pos] == '\0')
4536 /* Multiline quoted atoms are ignored. */
4538 else if (s[pos] == '\\') {
4539 if (s[pos + 1] == '\0')
4545 return pos - origpos;
4550 #ifdef ETAGS_REGEXPS
4552 /* Take a string like "/blah/" and turn it into "blah", making sure
4553 that the first and last characters are the same, and handling
4554 quoted separator characters. Actually, stops on the occurrence of
4555 an unquoted separator. Also turns "\t" into a Tab character.
4556 Returns pointer to terminating separator. Works in place. Null
4557 terminates name string. */
4558 char *scan_separators PP((char *name));
4559 char *scan_separators(name)
4563 char *copyto = name;
4564 bool quoted = FALSE;
4566 for (++name; *name != '\0'; ++name) {
4570 else if (*name == sep)
4573 /* Something else is quoted, so preserve the quote. */
4578 } else if (*name == '\\')
4580 else if (*name == sep)
4586 /* Terminate copied string. */
4591 /* Look at the argument of --regex or --no-regex and do the right
4592 thing. Same for each line of a regexp file. */
4593 void analyse_regex(regex_arg)
4596 if (regex_arg == NULL)
4597 free_patterns(); /* --no-regex: remove existing regexps */
4599 /* A real --regexp option or a line in a regexp file. */
4600 switch (regex_arg[0]) {
4601 /* Comments in regexp file or null arg to --regex. */
4607 /* Read a regex file. This is recursive and may result in a
4608 loop, which will stop when the file descriptors are exhausted. */
4612 linebuffer regexbuf;
4613 char *regexfile = regex_arg + 1;
4615 /* regexfile is a file containing regexps, one per line. */
4616 regexfp = fopen(regexfile, "r");
4617 if (regexfp == NULL) {
4621 initbuffer(®exbuf);
4622 while (readline_internal(®exbuf, regexfp) > 0)
4623 analyse_regex(regexbuf.buffer);
4624 free(regexbuf.buffer);
4629 /* Regexp to be used for a specific language only. */
4633 char *lang_name = regex_arg + 1;
4636 for (cp = lang_name; *cp != '}'; cp++)
4639 ("unterminated language name in regex: %s",
4644 lang = get_language_from_name(lang_name);
4647 add_regex(cp + 1, lang);
4651 /* Regexp to be used for any language. */
4653 add_regex(regex_arg, NULL);
4658 /* Turn a name, which is an ed-style (but Emacs syntax) regular
4659 expression, into a real regular expression by compiling it. */
4660 void add_regex(regexp_pattern, lang)
4661 char *regexp_pattern;
4666 struct re_pattern_buffer *patbuf;
4669 if (regexp_pattern[strlen(regexp_pattern) - 1] != regexp_pattern[0]) {
4670 error("%s: unterminated regexp", regexp_pattern);
4673 name = scan_separators(regexp_pattern);
4674 if (regexp_pattern[0] == '\0') {
4675 error("null regexp", (char *)NULL);
4678 (void)scan_separators(name);
4680 patbuf = xnew(1, struct re_pattern_buffer);
4681 patbuf->translate = NULL;
4682 patbuf->fastmap = NULL;
4683 patbuf->buffer = NULL;
4684 patbuf->allocated = 0;
4687 re_compile_pattern(regexp_pattern, strlen(regexp_pattern), patbuf);
4689 error("%s while compiling pattern", err);
4694 p_head = xnew(1, pattern);
4695 p_head->regex = savestr(regexp_pattern);
4696 p_head->p_next = pp;
4697 p_head->language = lang;
4698 p_head->pattern = patbuf;
4699 p_head->name_pattern = savestr(name);
4700 p_head->error_signaled = FALSE;
4704 * Do the substitutions indicated by the regular expression and
4707 char *substitute PP((char *in, char *out, struct re_registers * regs));
4708 char *substitute(in, out, regs)
4710 struct re_registers *regs;
4713 int size, dig, diglen;
4718 /* Pass 1: figure out how much to allocate by finding all \N strings. */
4719 if (out[size - 1] == '\\')
4720 fatal("pattern error in \"%s\"", out);
4721 for (t = etags_strchr(out, '\\');
4722 t != NULL; t = etags_strchr(t + 2, '\\'))
4723 if (isdigit(t[1])) {
4725 diglen = regs->end[dig] - regs->start[dig];
4730 /* Allocate space and do the substitutions. */
4731 result = xnew(size + 1, char);
4733 for (t = result; *out != '\0'; out++)
4734 if (*out == '\\' && isdigit(*++out)) {
4735 /* Using "dig2" satisfies my debugger. Bleah. */
4737 diglen = regs->end[dig] - regs->start[dig];
4738 strncpy(t, in + regs->start[dig], diglen);
4744 if (DEBUG && (t > result + size || t - result != strlen(result)))
4750 /* Deallocate all patterns. */
4751 void free_patterns()
4754 while (p_head != NULL) {
4755 pp = p_head->p_next;
4756 free(p_head->regex);
4757 free(p_head->name_pattern);
4764 #endif /* ETAGS_REGEXPS */
4765 /* Initialize a linebuffer for use */
4766 void initbuffer(lbp)
4770 lbp->buffer = xnew(200, char);
4774 * Read a line of text from `stream' into `lbp', excluding the
4775 * newline or CR-NL, if any. Return the number of characters read from
4776 * `stream', which is the length of the line including the newline.
4778 * On DOS or Windows we do not count the CR character, if any, before the
4779 * NL, in the returned length; this mirrors the behavior of emacs on those
4780 * platforms (for text files, it translates CR-NL to NL as it reads in the
4783 long readline_internal(lbp, stream)
4785 register FILE *stream;
4787 char *buffer = lbp->buffer;
4788 register char *p = lbp->buffer;
4789 register char *pend;
4792 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
4795 register int c = getc(stream);
4797 /* We're at the end of linebuffer: expand it. */
4799 buffer = xrnew(buffer, lbp->size, char);
4800 p += buffer - lbp->buffer;
4801 pend = buffer + lbp->size;
4802 lbp->buffer = buffer;
4810 if (p > buffer && p[-1] == '\r') {
4821 lbp->len = p - buffer;
4823 return lbp->len + chars_deleted;
4827 * Like readline_internal, above, but in addition try to match the
4828 * input line against relevant regular expressions.
4830 long readline(lbp, stream)
4834 /* Read new line. */
4835 long result = readline_internal(lbp, stream);
4836 #ifdef ETAGS_REGEXPS
4840 /* Match against relevant patterns. */
4842 for (pp = p_head; pp != NULL; pp = pp->p_next) {
4843 /* Only use generic regexps or those for the current language. */
4844 if (pp->language != NULL && pp->language != curlang)
4848 re_match(pp->pattern, lbp->buffer, lbp->len, 0,
4853 if (!pp->error_signaled) {
4854 error("error while matching \"%s\"",
4856 pp->error_signaled = TRUE;
4863 /* Match occurred. Construct a tag. */
4864 if (pp->name_pattern[0] != '\0') {
4865 /* Make a named tag. */
4866 char *name = substitute(lbp->buffer,
4871 pfnote(name, TRUE, lbp->buffer,
4875 /* Make an unnamed tag. */
4876 pfnote((char *)NULL, TRUE,
4877 lbp->buffer, match, lineno,
4883 #endif /* ETAGS_REGEXPS */
4889 * Return a pointer to a space of size strlen(cp)+1 allocated
4890 * with xnew where the string CP has been copied.
4895 return savenstr(cp, strlen(cp));
4899 * Return a pointer to a space of size LEN+1 allocated with xnew where
4900 * the string CP has been copied for at most the first LEN characters.
4902 char *savenstr(cp, len)
4908 dp = xnew(len + 1, char);
4909 strncpy(dp, cp, len);
4915 * Return the ptr in sp at which the character c last
4916 * appears; NULL if not found
4918 * Identical to System V strrchr, included for portability.
4920 char *etags_strrchr(sp, c)
4935 * Return the ptr in sp at which the character c first
4936 * appears; NULL if not found
4938 * Identical to System V strchr, included for portability.
4940 char *etags_strchr(sp, c)
4951 /* Skip spaces, return new pointer. */
4952 char *skip_spaces(cp)
4955 while (isspace(*cp)) /* isspace('\0')==FALSE */
4960 /* Skip non spaces, return new pointer. */
4961 char *skip_non_spaces(cp)
4964 while (!iswhite(*cp)) /* iswhite('\0')==TRUE */
4969 /* Print error message and exit. */
4984 void suggest_asking_for_help()
4986 fprintf(stderr, "\tTry `%s %s' for a complete list of options.\n",
4997 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
4999 const char *s1, *s2;
5001 fprintf(stderr, "%s: ", progname);
5002 fprintf(stderr, s1, s2);
5003 fprintf(stderr, "\n");
5006 /* Return a newly-allocated string whose contents
5007 concatenate those of s1, s2, s3. */
5008 char *concat(s1, s2, s3)
5011 int len1 = strlen(s1), len2 = strlen(s2), len3 = strlen(s3);
5012 char *result = xnew(len1 + len2 + len3 + 1, char);
5015 strcpy(result + len1, s2);
5016 strcpy(result + len1 + len2, s3);
5017 result[len1 + len2 + len3] = '\0';
5022 /* Does the same work as the system V getcwd, but does not need to
5023 guess the buffer size in advance. */
5024 char *etags_getcwd()
5028 char *path = xnew(bufsize, char);
5030 while (getcwd(path, bufsize) == NULL) {
5031 if (errno != ERANGE)
5035 path = xnew(bufsize, char);
5038 canonicalize_filename(path);
5041 #else /* not HAVE_GETCWD */
5046 pipe = (FILE *) popen("pwd 2>/dev/null", "r");
5047 if (pipe == NULL || readline_internal(&path, pipe) == 0)
5052 #endif /* not HAVE_GETCWD */
5055 /* Return a newly allocated string containing the file name of FILE
5056 relative to the absolute directory DIR (which should end with a slash). */
5057 char *relative_filename(file, dir)
5060 char *fp, *dp, *afn, *res;
5063 /* Find the common root of file and dir (with a trailing slash). */
5064 afn = absolute_filename(file, cwd);
5067 while (*fp++ == *dp++)
5069 fp--, dp--; /* back to the first differing char */
5070 do /* look at the equal chars until '/' */
5074 /* Build a sequence of "../" strings for the resulting relative file name. */
5076 while ((dp = etags_strchr(dp + 1, '/')) != NULL)
5078 res = xnew(3 * i + strlen(fp + 1) + 1, char);
5083 /* Add the file name relative to the common root of file and dir. */
5084 strcat(res, fp + 1);
5090 /* Return a newly allocated string containing the absolute file name
5091 of FILE given DIR (which should end with a slash). */
5092 char *absolute_filename(file, dir)
5095 char *slashp, *cp, *res;
5097 if (filename_is_absolute(file))
5098 res = savestr(file);
5100 res = concat(dir, file, "");
5102 /* Delete the "/dirname/.." and "/." substrings. */
5103 slashp = etags_strchr(res, '/');
5104 while (slashp != NULL && slashp[0] != '\0') {
5105 if (slashp[1] == '.') {
5106 if (slashp[2] == '.'
5107 && (slashp[3] == '/' || slashp[3] == '\0')) {
5111 while (cp >= res && !filename_is_absolute(cp));
5113 cp = slashp; /* the absolute name begins with "/.." */
5114 strcpy(cp, slashp + 3);
5117 } else if (slashp[2] == '/' || slashp[2] == '\0') {
5118 strcpy(slashp, slashp + 2);
5123 slashp = etags_strchr(slashp + 1, '/');
5127 return savestr("/");
5132 /* Return a newly allocated string containing the absolute
5133 file name of dir where FILE resides given DIR (which should
5134 end with a slash). */
5135 char *absolute_dirname(file, dir)
5141 canonicalize_filename(file);
5142 slashp = etags_strrchr(file, '/');
5144 return savestr(dir);
5147 res = absolute_filename(file, dir);
5153 /* Whether the argument string is an absolute file name. The argument
5154 string must have been canonicalized with canonicalize_filename. */
5155 bool filename_is_absolute(fn)
5158 return (fn[0] == '/');
5161 /* Translate backslashes into slashes. Works in place. */
5162 void canonicalize_filename(fn)
5168 /* Increase the size of a linebuffer. */
5169 void grow_linebuffer(lbp, toksize)
5173 while (lbp->size < toksize)
5175 lbp->buffer = xrnew(lbp->buffer, lbp->size, char);
5178 /* Like malloc but get fatal error if memory is exhausted. */
5182 long *result = (long *)malloc(size);
5184 fatal("virtual memory exhausted", (char *)NULL);
5188 long *xrealloc(ptr, size)
5192 long *result = (long *)realloc(ptr, size);
5194 fatal("virtual memory exhausted", (char *)NULL);