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)))
177 #define xstrncpy(d_,s_,l_) \
181 strncat((dst_),(s_),(l_)-1); \
187 typedef void Lang_function(FILE *);
191 Lang_function *function;
196 typedef struct node_st { /* sorting structure */
197 char *name; /* function or type name */
199 short int construct; /* Construct type for the OO-Browser */
201 char *file; /* file name */
202 bool is_func; /* use pattern or line no */
203 bool been_warned; /* set if noticed dup */
204 int lno; /* line number tag is on */
205 long cno; /* character number line starts on */
206 char *pat; /* search pattern */
207 struct node_st *left, *right; /* left and right sons */
211 /* If you add to this array, you must add a corresponding entry to the
213 static char *oo_browser_default_classes[] =
214 /* Lack of square brackets around some of these entries are intentional. */
215 { "null", "class", "method", "[constant]", "[enumeration]", "[enum_label]",
216 "extern", "[function]", "[macro]", "objc", "[structure]", "[type]",
217 "[union]", "[variable]"
220 /* If you add to this enum, you must add a corresponding entry to the
222 enum oo_browser_constructs { C_NULL, C_CLASS, C_METHOD, C_CONSTANT,
224 C_ENUM_LABEL, C_EXTERN, C_FUNCTION, C_MACRO,
225 C_OBJC, C_STRUCTURE, C_TYPE, C_UNION, C_VARIABLE
228 enum oo_browser_constructs oo_browser_construct = C_NULL;
232 * A `linebuffer' is a structure which holds a line of text.
233 * `readline_internal' reads a line from a stream into a linebuffer
234 * and works regardless of the length of the line.
235 * SIZE is the size of BUFFER, LEN is the length of the string in
236 * BUFFER after readline reads it.
244 extern char *getenv PP((const char *envvar));
246 /* Many compilers barf on this:
247 Lang_function Asm_labels;
248 so let's write it this way */
249 void Asm_labels PP((FILE * inf));
250 void C_entries PP((int c_ext, FILE * inf));
251 void default_C_entries PP((FILE * inf));
252 void plain_C_entries PP((FILE * inf));
253 void Cjava_entries PP((FILE * inf));
254 void Cplusplus_entries PP((FILE * inf));
255 void Yacc_entries PP((FILE * inf));
256 void Cobol_paragraphs PP((FILE * inf));
257 void Cstar_entries PP((FILE * inf));
258 void Erlang_functions PP((FILE * inf));
259 void Fortran_functions PP((FILE * inf));
260 void Lisp_functions PP((FILE * inf));
261 void Pascal_functions PP((FILE * inf));
262 void Perl_functions PP((FILE * inf));
263 void Postscript_functions PP((FILE * inf));
264 void Prolog_functions PP((FILE * inf));
265 void Python_functions PP((FILE * inf));
266 void Scheme_functions PP((FILE * inf));
267 void TeX_functions PP((FILE * inf));
268 void just_read_file PP((FILE * inf));
270 void print_language_names PP((void));
271 void print_version PP((void));
272 void print_help PP((void));
274 language *get_language_from_name PP((char *name));
275 language *get_language_from_interpreter PP((char *interpreter));
276 language *get_language_from_suffix PP((char *suffix));
277 int total_size_of_entries PP((node * np));
278 long readline PP((linebuffer * lbp, FILE * stream));
279 long readline_internal PP((linebuffer * lbp, FILE * stream));
281 void analyse_regex PP((char *regex_arg));
282 void add_regex PP((char *regexp_pattern, language * lang));
283 void free_patterns PP((void));
284 #endif /* ETAGS_REGEXPS */
285 void error PP((const char *s1, const char *s2));
286 void suggest_asking_for_help PP((void));
287 void fatal PP((char *s1, char *s2));
288 void pfatal PP((char *s1));
289 void add_node PP((node * np, node ** cur_node_p));
291 void init PP((void));
292 void initbuffer PP((linebuffer * lbp));
293 void find_entries PP((char *file, FILE * inf));
294 void free_tree PP((node * np));
296 PP((char *name, bool is_func, char *linestart, int linelen, int lno, long cno));
298 PP((char *name, int namelen, bool is_func, char *linestart, int linelen,
300 void process_file PP((char *file));
301 void put_entries PP((node * np));
302 void takeprec PP((void));
304 char *concat PP((char *s1, char *s2, char *s3));
305 char *skip_spaces PP((char *cp));
306 char *skip_non_spaces PP((char *cp));
307 char *savenstr PP((char *cp, int len));
308 char *savestr PP((char *cp));
309 char *etags_getcwd PP((void));
310 char *relative_filename PP((char *file, char *dir));
311 char *absolute_filename PP((char *file, char *dir));
312 char *absolute_dirname PP((char *file, char *dir));
313 bool filename_is_absolute PP((char *fn));
314 void canonicalize_filename PP((char *fn));
315 void grow_linebuffer PP((linebuffer * lbp, int toksize));
316 long *xmalloc PP((unsigned int size));
317 long *xrealloc PP((char *ptr, unsigned int size));
320 #define etags_strrchr strrchr
323 * Return the ptr in sp at which the character c last
324 * appears; NULL if not found
326 * Identical to POSIX strrchr, included for portability.
329 etags_strrchr (sp, c)
330 register const char *sp;
333 register const char *r;
346 #define etags_strchr strchr
349 * Return the ptr in sp at which the character c first
350 * appears; NULL if not found
352 * Identical to POSIX strchr, included for portability.
356 register const char *sp;
368 char searchar = '/'; /* use /.../ searches */
370 char *tagfile; /* output file */
371 char *progname; /* name this program was invoked with */
372 char *cwd; /* current working directory */
373 char *tagfiledir; /* directory of tagfile */
374 FILE *tagf; /* ioptr for tags file */
376 char *curfile; /* current input file name */
377 language *curlang; /* current language */
379 int lineno; /* line number of current line */
380 long charno; /* current character number */
381 long linecharno; /* charno of start of current line */
382 char *dbp; /* pointer to start of current tag */
383 node *head; /* the head of the binary tree of tags */
385 linebuffer lb; /* the current line */
386 linebuffer token_name; /* used by C_entries as a temporary area */
389 linebuffer lb; /* used by C_entries instead of lb */
392 /* boolean "functions" (see init) */
393 bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
396 *white = " \f\t\n\r",
398 *nonam = " \f\t\n\r(=,[;",
399 /* token ending chars */
400 *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
401 /* token starting chars */
402 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
403 /* valid in-token chars */
404 *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
406 bool append_to_tagfile; /* -a: append to tags */
407 /* The following four default to TRUE for etags, but to FALSE for ctags. */
408 bool typedefs; /* -t: create tags for C typedefs */
409 bool typedefs_and_cplusplus; /* -T: create tags for C typedefs, level */
410 /* 0 struct/enum/union decls, and C++ */
411 /* member functions. */
412 bool constantypedefs; /* -d: create tags for C #define, enum */
413 /* constants and variables. */
414 /* -D: opposite of -d. Default under ctags. */
415 bool globals; /* create tags for global variables */
416 bool members; /* create tags for C member variables */
417 bool update; /* -u: update tags */
418 bool vgrind_style; /* -v: create vgrind style index output */
419 bool no_warnings; /* -w: suppress warnings */
420 bool cxref_style; /* -x: create cxref style output */
421 bool cplusplus; /* .[hc] means C++, not C */
422 bool noindentypedefs; /* -I: ignore indentation in C */
424 bool oo_browser_format; /* -O: OO-Browser tags format */
428 struct option longopts[] = {
429 {"append", no_argument, NULL, 'a'},
430 {"backward-search", no_argument, NULL, 'B'},
431 {"c++", no_argument, NULL, 'C'},
432 {"cxref", no_argument, NULL, 'x'},
433 {"defines", no_argument, NULL, 'd'},
434 {"no-defines", no_argument, NULL, 'D'},
435 {"globals", no_argument, &globals, TRUE},
436 {"no-globals", no_argument, &globals, FALSE},
437 {"help", no_argument, NULL, 'h'},
438 {"help", no_argument, NULL, 'H'},
439 {"ignore-indentation", no_argument, NULL, 'I'},
440 {"include", required_argument, NULL, 'i'},
441 {"language", required_argument, NULL, 'l'},
442 {"members", no_argument, &members, TRUE},
443 {"no-members", no_argument, &members, FALSE},
444 {"no-warn", no_argument, NULL, 'w'},
445 {"output", required_argument, NULL, 'o'},
447 {"oo-browser", no_argument, NULL, 'O'},
450 {"regex", required_argument, NULL, 'r'},
451 {"no-regex", no_argument, NULL, 'R'},
452 #endif /* ETAGS_REGEXPS */
453 {"typedefs", no_argument, NULL, 't'},
454 {"typedefs-and-c++", no_argument, NULL, 'T'},
455 {"update", no_argument, NULL, 'u'},
456 {"version", no_argument, NULL, 'V'},
457 {"vgrind", no_argument, NULL, 'v'},
460 #endif /* LONG_OPTIONS */
463 /* Structure defining a regular expression. Elements are
464 the compiled pattern, and the name string. */
465 typedef struct pattern {
466 struct pattern *p_next;
469 struct re_pattern_buffer *pattern;
470 struct re_registers regs;
475 /* Array of all regexps. */
476 pattern *p_head = NULL;
477 #endif /* ETAGS_REGEXPS */
483 /* Non-NULL if language fixed. */
484 language *forced_lang = NULL;
487 char *Asm_suffixes[] = { "a", /* Unix assembler */
488 "asm", /* Microcontroller assembly */
489 "def", /* BSO/Tasking definition includes */
490 "inc", /* Microcontroller include files */
491 "ins", /* Microcontroller include files */
492 "s", "sa", /* Unix assembler */
493 "src", /* BSO/Tasking C compiler output */
497 /* Note that .c and .h can be considered C++, if the --c++ flag was
498 given. That is why default_C_entries is called here. */
499 char *default_C_suffixes[] = { "c", "h", NULL };
501 char *Cplusplus_suffixes[] =
502 { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
503 "M", /* Objective C++ */
504 "pdb", /* Postscript with C syntax */
508 char *Cjava_suffixes[] = { "java", NULL };
510 char *Cobol_suffixes[] = { "COB", "cob", NULL };
512 char *Cstar_suffixes[] = { "cs", "hs", NULL };
514 char *Erlang_suffixes[] = { "erl", "hrl", NULL };
516 char *Fortran_suffixes[] = { "F", "f", "f90", "for", NULL };
518 char *Lisp_suffixes[] = { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
520 char *Pascal_suffixes[] = { "p", "pas", NULL };
522 char *Perl_suffixes[] = { "pl", "pm", NULL };
523 char *Perl_interpreters[] = { "perl", "@PERL@", NULL };
525 char *plain_C_suffixes[] = { "pc", /* Pro*C file */
526 "m", /* Objective C file */
527 "lm", /* Objective lex file */
531 char *Postscript_suffixes[] = { "ps", NULL };
533 char *Prolog_suffixes[] = { "prolog", NULL };
535 char *Python_suffixes[] = { "py", NULL };
537 /* Can't do the `SCM' or `scm' prefix with a version number. */
538 char *Scheme_suffixes[] =
539 { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "ss", "t", NULL };
541 char *TeX_suffixes[] =
542 { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
544 char *Yacc_suffixes[] = { "y", "ym", NULL }; /* .ym is Objective yacc file */
547 * Table of languages.
549 * It is ok for a given function to be listed under more than one
550 * name. I just didn't.
553 language lang_names[] = {
554 {"asm", Asm_labels, Asm_suffixes, NULL},
555 {"c", default_C_entries, default_C_suffixes, NULL},
556 {"c++", Cplusplus_entries, Cplusplus_suffixes, NULL},
557 {"c*", Cstar_entries, Cstar_suffixes, NULL},
558 {"cobol", Cobol_paragraphs, Cobol_suffixes, NULL},
559 {"erlang", Erlang_functions, Erlang_suffixes, NULL},
560 {"fortran", Fortran_functions, Fortran_suffixes, NULL},
561 {"java", Cjava_entries, Cjava_suffixes, NULL},
562 {"lisp", Lisp_functions, Lisp_suffixes, NULL},
563 {"pascal", Pascal_functions, Pascal_suffixes, NULL},
564 {"perl", Perl_functions, Perl_suffixes, Perl_interpreters},
565 {"postscript", Postscript_functions, Postscript_suffixes, NULL},
566 {"proc", plain_C_entries, plain_C_suffixes, NULL},
567 {"prolog", Prolog_functions, Prolog_suffixes, NULL},
568 {"python", Python_functions, Python_suffixes, NULL},
569 {"scheme", Scheme_functions, Scheme_suffixes, NULL},
570 {"tex", TeX_functions, TeX_suffixes, NULL},
571 {"yacc", Yacc_entries, Yacc_suffixes, NULL},
572 {"auto", NULL}, /* default guessing scheme */
573 {"none", just_read_file}, /* regexp matching only */
574 {NULL, NULL} /* end of list */
577 void print_language_names()
582 puts("\nThese are the currently supported languages, along with the\n\
583 default file name suffixes:");
584 for (lang = lang_names; lang->name != NULL; lang++) {
585 printf("\t%s\t", lang->name);
586 if (lang->suffixes != NULL)
587 for (ext = lang->suffixes; *ext != NULL; ext++)
588 printf(" .%s", *ext);
591 puts("Where `auto' means use default language for files based on file\n\
592 name suffix, and `none' means only do regexp processing on files.\n\
593 If no language is specified and no matching suffix is found,\n\
594 the first line of the file is read for a sharp-bang (#!) sequence\n\
595 followed by the name of an interpreter. If no such sequence is found,\n\
596 Fortran is tried first; if no tags are found, C is tried next.");
600 # define VERSION "20"
604 printf("%s (GNU Emacs %s)\n", (CTAGS) ? "ctags" : "etags", VERSION);
605 puts("Copyright (C) 1996 Free Software Foundation, Inc. and Ken Arnold");
606 puts("This program is distributed under the same terms as Emacs");
613 printf("Usage: %s [options] [[regex-option ...] file-name] ...\n\
615 These are the options accepted by %s.\n", progname, progname);
617 puts("You may use unambiguous abbreviations for the long option names.");
619 puts("Long option names do not work with this executable, as it is not\n\
620 linked with GNU getopt.");
621 #endif /* LONG_OPTIONS */
622 puts("A - as file name means read names from stdin (one per line).");
625 (" Absolute names are stored in the output file as they are.\n\
626 Relative ones are stored relative to the output file's directory.");
629 puts("-a, --append\n\
630 Append tag entries to existing tags file.");
633 puts("-B, --backward-search\n\
634 Write the search commands for the tag entries using '?', the\n\
635 backward-search command instead of '/', the forward-search command.");
638 Treat files whose name suffix defaults to C language as C++ files.");
641 puts("-d, --defines\n\
642 Create tag entries for C #define constants and enum constants, too.");
644 puts("-D, --no-defines\n\
645 Don't create tag entries for C #define constants and enum constants.\n\
646 This makes the tags file smaller.");
649 puts("-i FILE, --include=FILE\n\
650 Include a note in tag file indicating that, when searching for\n\
651 a tag, one should also consult the tags file FILE after\n\
652 checking the current file.");
653 puts("-l LANG, --language=LANG\n\
654 Force the following files to be considered as written in the\n\
655 named language up to the next --language=LANG option.");
660 Create tag entries for global variables in some languages.");
662 puts("--no-globals\n\
663 Do not create tag entries for global variables in some\n\
664 languages. This makes the tags file smaller.");
666 Create tag entries for member variables in C and derived languages.");
669 puts("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
670 Make a tag for each line matching pattern REGEXP in the\n\
671 following files. regexfile is a file containing one REGEXP\n\
672 per line. REGEXP is anchored (as if preceded by ^).\n\
673 The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
674 named tags can be created with:\n\
675 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
676 puts("-R, --no-regex\n\
677 Don't create tags from regexps for the following files.");
678 #endif /* ETAGS_REGEXPS */
679 puts("-o FILE, --output=FILE\n\
680 Write the tags to FILE.");
682 puts("-O, --oo-browser\n\
683 Generate a specialized tags format used only by the Altrasoft OO-Browser.");
685 puts("-I, --ignore-indentation\n\
686 Don't rely on indentation quite as much as normal. Currently,\n\
687 this means not to assume that a closing brace in the first\n\
688 column is the final brace of a function or structure\n\
689 definition in C and C++.");
692 puts("-t, --typedefs\n\
693 Generate tag entries for C typedefs.");
694 puts("-T, --typedefs-and-c++\n\
695 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
696 and C++ member functions.");
697 puts("-u, --update\n\
698 Update the tag entries for the given files, leaving tag\n\
699 entries for other files in place. Currently, this is\n\
700 implemented by deleting the existing entries for the given\n\
701 files and then rewriting the new entries at the end of the\n\
702 tags file. It is often faster to simply rebuild the entire\n\
703 tag file than to use this.");
704 puts("-v, --vgrind\n\
705 Generates an index of items intended for human consumption,\n\
706 similar to the output of vgrind. The index is sorted, and\n\
707 gives the page number of each item.");
708 puts("-w, --no-warn\n\
709 Suppress warning messages about entries defined in multiple\n\
712 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
713 The output uses line numbers instead of page numbers, but\n\
714 beyond that the differences are cosmetic; try both to see\n\
718 puts("-V, --version\n\
719 Print the version of the program.\n\
721 Print this help message.");
723 print_language_names();
726 puts("Report bugs to bug-gnu-emacs@prep.ai.mit.edu");
737 /* This structure helps us allow mixing of --lang and file names. */
739 enum argument_type arg_type;
744 #ifdef VMS /* VMS specific functions */
748 /* This is a BUG! ANY arbitrary limit is a BUG!
749 Won't someone please fix this? */
750 #define MAX_FILE_SPEC_LEN 255
753 char body[MAX_FILE_SPEC_LEN + 1];
757 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
758 returning in each successive call the next file name matching the input
759 spec. The function expects that each in_spec passed
760 to it will be processed to completion; in particular, up to and
761 including the call following that in which the last matching name
762 is returned, the function ignores the value of in_spec, and will
763 only start processing a new spec with the following call.
764 If an error occurs, on return out_spec contains the value
765 of in_spec when the error occurred.
767 With each successive file name returned in out_spec, the
768 function's return value is one. When there are no more matching
769 names the function returns zero. If on the first call no file
770 matches in_spec, or there is any other error, -1 is returned.
775 #define OUTSIZE MAX_FILE_SPEC_LEN
776 short fn_exp(out, in)
780 static long context = 0;
781 static struct dsc$descriptor_s o;
782 static struct dsc$descriptor_s i;
783 static bool pass1 = TRUE;
789 o.dsc$a_pointer = (char *)out;
790 o.dsc$w_length = (short)OUTSIZE;
791 i.dsc$a_pointer = in;
792 i.dsc$w_length = (short)strlen(in);
793 i.dsc$b_dtype = DSC$K_DTYPE_T;
794 i.dsc$b_class = DSC$K_CLASS_S;
795 o.dsc$b_dtype = DSC$K_DTYPE_VT;
796 o.dsc$b_class = DSC$K_CLASS_VS;
798 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL) {
799 out->body[out->curlen] = EOS;
801 } else if (status == RMS$_NMF)
804 strcpy(out->body, in);
807 lib$find_file_end(&context);
813 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
814 name of each file specified by the provided arg expanding wildcards.
816 char *gfnames(arg, p_error)
820 static vspec filename = { MAX_FILE_SPEC_LEN, "\0" };
822 switch (fn_exp(&filename, arg)) {
825 return filename.body;
831 return filename.body;
835 #ifndef OLD /* Newer versions of VMS do provide `system'. */
839 error("%s", "system() function not implemented under VMS");
843 #define VERSION_DELIM ';'
844 char *massage_name(s)
850 if (*s == VERSION_DELIM) {
859 int main(int argc, char *argv[])
862 unsigned int nincluded_files;
863 char **included_files;
866 int current_arg, file_count;
867 linebuffer filename_lb;
874 included_files = xnew(argc, char *);
878 /* Allocate enough no matter what happens. Overkill, but each one
880 argbuffer = xnew(argc, argument);
883 /* Set syntax for regular expression routines. */
884 re_set_syntax(RE_SYNTAX_EMACS | RE_INTERVALS);
885 #endif /* ETAGS_REGEXPS */
888 * If etags, always find typedefs and structure tags. Why not?
889 * Also default is to find macro constants, enum constants and
893 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
904 optstring = "-aCdDf:Il:o:r:RStTi:BuvxwVhH";
906 optstring = "-aCdDf:Il:o:r:RStTi:BOuvxwVhH";
910 optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
912 optstring = "-aCdDf:Il:o:StTi:BOuvxwVhH";
914 #endif /* ETAGS_REGEXPS */
917 optstring = optstring + 1;
918 #endif /* LONG_OPTIONS */
920 opt = getopt_long(argc, argv, optstring, longopts, 0);
926 /* If getopt returns 0, then it has already processed a
927 long-named option. We should do nothing. */
931 /* This means that a file name has been seen. Record it. */
932 argbuffer[current_arg].arg_type = at_filename;
933 argbuffer[current_arg].what = optarg;
938 /* Common options. */
940 append_to_tagfile = TRUE;
946 constantypedefs = TRUE;
949 constantypedefs = FALSE;
951 case 'f': /* for compatibility with old makefiles */
954 /* convert char to string, to call error with */
957 error("-%s option may only be given once.",
959 suggest_asking_for_help();
965 oo_browser_format = TRUE;
969 case 'S': /* for backward compatibility */
970 noindentypedefs = TRUE;
974 language *lang = get_language_from_name(optarg);
976 argbuffer[current_arg].lang = lang;
977 argbuffer[current_arg].arg_type =
985 argbuffer[current_arg].arg_type = at_regexp;
986 argbuffer[current_arg].what = optarg;
990 argbuffer[current_arg].arg_type = at_regexp;
991 argbuffer[current_arg].what = NULL;
994 #endif /* ETAGS_REGEXPS */
1006 typedefs = typedefs_and_cplusplus = TRUE;
1011 included_files[nincluded_files++] = optarg;
1014 /* Ctags options. */
1022 vgrind_style = TRUE;
1023 /*FALLTHRU*/ case 'x':
1031 suggest_asking_for_help();
1035 for (; optind < argc; ++optind) {
1036 argbuffer[current_arg].arg_type = at_filename;
1037 argbuffer[current_arg].what = argv[optind];
1042 if (nincluded_files == 0 && file_count == 0) {
1043 error("no input files specified.", 0);
1044 suggest_asking_for_help();
1047 if (tagfile == NULL)
1048 tagfile = CTAGS ? "tags" : "TAGS";
1049 cwd = etags_getcwd(); /* the current working directory */
1050 if (cwd[strlen(cwd) - 1] != '/') {
1052 cwd = concat(oldcwd, "/", "");
1055 if (streq(tagfile, "-"))
1058 tagfiledir = absolute_dirname(tagfile, cwd);
1060 init(); /* set up boolean "functions" */
1063 initbuffer(&token_name);
1064 initbuffer(&lbs[0].lb);
1065 initbuffer(&lbs[1].lb);
1066 initbuffer(&filename_lb);
1069 if (streq(tagfile, "-")) {
1072 tagf = fopen(tagfile, append_to_tagfile ? "a" : "w");
1078 * Loop through files finding functions.
1080 for (i = 0; i < current_arg; ++i) {
1081 switch (argbuffer[i].arg_type) {
1083 forced_lang = argbuffer[i].lang;
1085 #ifdef ETAGS_REGEXPS
1087 analyse_regex(argbuffer[i].what);
1093 gfnames(argbuffer[i].what, &got_err)) != NULL) {
1095 error("can't find file %s\n",
1099 this_file = massage_name(this_file);
1102 this_file = argbuffer[i].what;
1105 oo_browser_clear_all_globals();
1107 /* Input file named "-" means read file names from stdin
1108 (one per line) and use them. */
1109 if (streq(this_file, "-"))
1110 while (readline_internal(&filename_lb, stdin) >
1114 oo_browser_clear_some_globals();
1116 process_file(filename_lb.buffer);
1121 process_file(this_file);
1131 #ifdef ETAGS_REGEXPS
1133 #endif /* ETAGS_REGEXPS */
1136 while (nincluded_files-- > 0)
1137 fprintf(tagf, "\f\n%s,include\n", *included_files++);
1143 /* If CTAGS, we are here. process_file did not write the tags yet,
1144 because we want them ordered. Let's do it now. */
1153 for (i = 0; i < current_arg; ++i) {
1154 if (argbuffer[i].arg_type != at_filename)
1156 sz = snprintf(cmd, sizeof(cmd),
1157 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1158 tagfile, argbuffer[i].what, tagfile);
1159 if(sz >= 0 && (size_t)sz < sizeof(cmd))
1160 fatal("failed to build shell command line", (char *)NULL);
1161 if (system(cmd) != GOOD)
1162 fatal("failed to execute shell command", (char *)NULL);
1164 append_to_tagfile = TRUE;
1167 tagf = fopen(tagfile, append_to_tagfile ? "a" : "w");
1175 int sz = snprintf(cmd, sizeof(cmd), "sort %s -o %s", tagfile, tagfile);
1176 if(sz >= 0 && (size_t)sz < sizeof(cmd))
1177 fatal("failed to build sort command line", (char *)NULL);
1184 * Return a language given the name.
1186 language *get_language_from_name(name)
1192 error("empty language name", (char *)NULL);
1194 for (lang = lang_names; lang->name != NULL; lang++)
1195 if (streq(name, lang->name))
1197 error("unknown language \"%s\"", name);
1204 * Return a language given the interpreter name.
1206 language *get_language_from_interpreter(interpreter)
1212 if (interpreter == NULL)
1214 for (lang = lang_names; lang->name != NULL; lang++)
1215 if (lang->interpreters != NULL)
1216 for (iname = lang->interpreters; *iname != NULL;
1218 if (streq(*iname, interpreter))
1225 * Return a language given the file suffix.
1227 language *get_language_from_suffix(suffix)
1235 for (lang = lang_names; lang->name != NULL; lang++)
1236 if (lang->suffixes != NULL)
1237 for (ext = lang->suffixes; *ext != NULL; ext++)
1238 if (streq(*ext, suffix))
1245 * This routine is called on each file argument.
1247 void process_file(file)
1250 struct stat stat_buf;
1253 canonicalize_filename(file);
1254 if (streq(file, tagfile) && !streq(tagfile, "-")) {
1255 error("skipping inclusion of %s in self.", file);
1258 inf = fopen(file, "r");
1259 if (stat(file, &stat_buf) == 0 && !S_ISREG(stat_buf.st_mode)) {
1260 error("skipping %s: it is not a regular file.", file);
1270 find_entries(file, inf);
1275 if (filename_is_absolute(file)) {
1276 /* file is an absolute file name. Canonicalise it. */
1277 filename = absolute_filename(file, cwd);
1279 /* file is a file name relative to cwd. Make it relative
1280 to the directory of the tags file. */
1281 filename = relative_filename(file, tagfiledir);
1284 if (oo_browser_format)
1285 fprintf(tagf, "\f\n%s\n", filename);
1288 fprintf(tagf, "\f\n%s,%d\n", filename,
1289 total_size_of_entries(head));
1298 * This routine sets up the boolean pseudo-functions which work
1299 * by setting boolean flags dependent upon the corresponding character.
1300 * Every char which is NOT in that string is not a white char. Therefore,
1301 * all of the array "_wht" is set to FALSE, and then the elements
1302 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1303 * of a char is TRUE if it is the string "white", else FALSE.
1310 for (i = 0; i < CHARS; i++)
1311 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) =
1312 endtoken(i) = FALSE;
1313 for (sp = white; *sp != '\0'; sp++)
1314 iswhite(*sp) = TRUE;
1315 for (sp = nonam; *sp != '\0'; sp++)
1316 notinname(*sp) = TRUE;
1317 for (sp = begtk; *sp != '\0'; sp++)
1318 begtoken(*sp) = TRUE;
1319 for (sp = midtk; *sp != '\0'; sp++)
1320 intoken(*sp) = TRUE;
1321 for (sp = endtk; *sp != '\0'; sp++)
1322 endtoken(*sp) = TRUE;
1323 iswhite('\0') = iswhite('\n');
1324 notinname('\0') = notinname('\n');
1325 begtoken('\0') = begtoken('\n');
1326 intoken('\0') = intoken('\n');
1327 endtoken('\0') = endtoken('\n');
1331 * This routine opens the specified file and calls the function
1332 * which finds the function and type definitions.
1334 node *last_node = NULL;
1336 void find_entries(file, inf)
1342 node *old_last_node;
1344 curfile = savestr(file);
1346 /* If user specified a language, use it. */
1348 if (lang != NULL && lang->function != NULL) {
1350 lang->function(inf);
1356 cp = etags_strrchr(file, '.');
1359 lang = get_language_from_suffix(cp);
1360 if (lang != NULL && lang->function != NULL) {
1362 lang->function(inf);
1369 /* Look for sharp-bang as the first two characters. */
1370 if (readline_internal(&lb, inf) > 0
1371 && lb.len >= 2 && lb.buffer[0] == '#' && lb.buffer[1] == '!') {
1374 /* Set lp to point at the first char after the last slash in the
1375 line or, if no slashes, at the first nonblank. Then set cp to
1376 the first successive blank and terminate the string. */
1377 lp = etags_strrchr(lb.buffer + 2, '/');
1381 lp = skip_spaces(lb.buffer + 2);
1382 cp = skip_non_spaces(lp);
1385 if (strlen(lp) > 0) {
1386 lang = get_language_from_interpreter(lp);
1387 if (lang != NULL && lang->function != NULL) {
1389 lang->function(inf);
1399 old_last_node = last_node;
1400 curlang = get_language_from_name("fortran");
1401 Fortran_functions(inf);
1403 /* No Fortran entries found. Try C. */
1404 if (old_last_node == last_node) {
1406 curlang = get_language_from_name(cplusplus ? "c++" : "c");
1407 default_C_entries(inf);
1415 void pfnote(name, is_func, linestart, linelen, lno, cno)
1416 char *name; /* tag name, or NULL if unnamed */
1417 bool is_func; /* tag is a function */
1418 char *linestart; /* start of the line where tag is */
1419 int linelen; /* length of the line where tag is */
1420 int lno; /* line number */
1421 long cno; /* character number */
1425 if (CTAGS && name == NULL)
1430 /* If ctags mode, change name "main" to M<thisfilename>. */
1431 if (CTAGS && !cxref_style && streq(name, "main")) {
1432 register char *fp = etags_strrchr(curfile, '/');
1433 np->name = concat("M", fp == 0 ? curfile : fp + 1, "");
1434 fp = etags_strrchr(np->name, '.');
1435 if (fp && fp[1] != '\0' && fp[2] == '\0')
1439 np->been_warned = FALSE;
1441 np->is_func = is_func;
1443 /* Our char numbers are 0-base, because of C language tradition?
1444 ctags compatibility? old versions compatibility? I don't know.
1445 Anyway, since emacs's are 1-base we expect etags.el to take care
1446 of the difference. If we wanted to have 1-based numbers, we would
1447 uncomment the +1 below. */
1448 np->cno = cno /* + 1 */ ;
1449 np->left = np->right = NULL;
1450 if (CTAGS && !cxref_style) {
1451 if (strlen(linestart) < 50)
1452 np->pat = concat(linestart, "$", "");
1454 np->pat = savenstr(linestart, 50);
1456 np->pat = savenstr(linestart, linelen);
1459 if (oo_browser_format)
1460 np->construct = oo_browser_construct;
1461 oo_browser_construct = C_NULL;
1462 oo_browser_check_and_clear_structtype();
1465 add_node(np, &head);
1468 /* Date: Wed, 22 Jan 1997 02:56:31 -0500 [last amended 18 Sep 1997]
1469 * From: Sam Kendall <kendall@mv.mv.com>
1470 * Subject: Proposal for firming up the TAGS format specification
1471 * To: F.Potorti@cnuce.cnr.it
1473 * pfnote should emit the optimized form [unnamed tag] only if:
1474 * 1. name does not contain any of the characters " \t\r\n(),;";
1475 * 2. linestart contains name as either a rightmost, or rightmost but
1476 * one character, substring;
1477 * 3. the character, if any, immediately before name in linestart must
1478 * be one of the characters " \t(),;";
1479 * 4. the character, if any, immediately after name in linestart must
1480 * also be one of the characters " \t(),;".
1482 * The real implementation uses the notinname() macro, which recognises
1483 * characters slightly different form " \t\r\n(),;". See the variable
1486 #define traditional_tag_style TRUE
1487 void new_pfnote(name, namelen, is_func, linestart, linelen, lno, cno)
1488 char *name; /* tag name, or NULL if unnamed */
1489 int namelen; /* tag length */
1490 bool is_func; /* tag is a function */
1491 char *linestart; /* start of the line where tag is */
1492 int linelen; /* length of the line where tag is */
1493 int lno; /* line number */
1494 long cno; /* character number */
1501 for (cp = name; !notinname(*cp); cp++)
1503 if (*cp == '\0') { /* rule #1 */
1504 cp = linestart + linelen - namelen;
1505 if (notinname(linestart[linelen - 1]))
1506 cp -= 1; /* rule #4 */
1508 if (!oo_browser_format && cp >= linestart /* rule #2 */
1510 if (cp >= linestart /* rule #2 */
1512 && (cp == linestart || notinname(cp[-1])) /* rule #3 */
1513 &&strneq(name, cp, namelen)) /* rule #2 */
1514 named = FALSE; /* use unnamed tag */
1519 name = savenstr(name, namelen);
1522 pfnote(name, is_func, linestart, linelen, lno, cno);
1527 * recurse on left children, iterate on right children.
1533 register node *node_right = np->right;
1534 free_tree(np->left);
1535 if (np->name != NULL)
1545 * Adds a node to the tree of nodes. In etags mode, we don't keep
1546 * it sorted; we just keep a linear list. In ctags mode, maintain
1547 * an ordered tree, with no attempt at balancing.
1549 * add_node is the only function allowed to add nodes, so it can
1552 void add_node(np, cur_node_p)
1553 node *np, **cur_node_p;
1556 register node *cur_node = *cur_node_p;
1558 if (cur_node == NULL) {
1566 if (last_node == NULL)
1567 fatal("internal error in add_node", (char *)NULL);
1568 last_node->right = np;
1572 dif = strcmp(np->name, cur_node->name);
1575 * If this tag name matches an existing one, then
1576 * do not add the node, but maybe print a warning.
1579 if (streq(np->file, cur_node->file)) {
1582 "Duplicate entry in file %s, line %d: %s\n",
1583 np->file, lineno, np->name);
1585 "Second entry ignored\n");
1587 } else if (!cur_node->been_warned && !no_warnings) {
1590 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1591 np->file, cur_node->file, np->name);
1592 cur_node->been_warned = TRUE;
1597 /* Actually add the node */
1598 add_node(np, dif < 0 ? &cur_node->left : &cur_node->right);
1603 /* Default class name for the current OO-Browser tag. */
1604 static char *oo_browser_class;
1605 /* Prefix character to use in OO-Browser listings for the current tag. */
1606 static char oo_browser_prefix;
1609 void put_entries(node * np)
1616 /* Output subentries that precede this one */
1617 put_entries(np->left);
1619 /* Output this entry */
1623 if (oo_browser_format) {
1624 /* Omit C++ `class' and `method' entries as well as Objective-C
1625 entries from this OO-Browser tags file since the browser handles
1626 them independently of this file. Omit `extern' variable declarations
1627 as they are unused by the OO-Browser. */
1628 if (np->construct != C_CLASS
1629 && np->construct != C_METHOD
1630 && np->construct != C_EXTERN
1631 && np->construct != C_OBJC) {
1633 oo_browser_default_classes[np->construct];
1634 switch (np->construct) {
1642 oo_browser_prefix = '=';
1646 oo_browser_prefix = '-';
1651 if (np->name != NULL)
1652 fprintf(tagf, "%s@%c %s@%s\n",
1654 oo_browser_prefix, np->name,
1657 fprintf(tagf, "%s@%c ???@%s\n",
1659 oo_browser_prefix, np->pat);
1663 if (np->name != NULL)
1664 fprintf(tagf, "%s\177%s\001%d,%ld\n",
1665 np->pat, np->name, np->lno, np->cno);
1667 fprintf(tagf, "%s\177%d,%ld\n",
1668 np->pat, np->lno, np->cno);
1673 if (np->name == NULL)
1674 error("internal error: NULL name in ctags mode.",
1679 fprintf(stdout, "%s %s %d\n",
1681 (np->lno + 63) / 64);
1683 fprintf(stdout, "%-16s %3d %-16s %s\n",
1684 np->name, np->lno, np->file, np->pat);
1686 fprintf(tagf, "%s\t%s\t", np->name, np->file);
1688 if (np->is_func) { /* a function */
1689 putc(searchar, tagf);
1692 for (sp = np->pat; *sp; sp++) {
1693 if (*sp == '\\' || *sp == searchar)
1697 putc(searchar, tagf);
1698 } else { /* a typedef; text pattern inadequate */
1699 fprintf(tagf, "%d", np->lno);
1705 /* Output subentries that follow this one */
1706 put_entries(np->right);
1709 /* Length of a number's decimal representation. */
1710 int number_len PP((long num));
1715 while ((num /= 10) > 0)
1721 * Return total number of characters that put_entries will output for
1722 * the nodes in the subtree of the specified node. Works only if
1723 * we are not ctags, but called only in that case. This count
1724 * is irrelevant with the new tags.el, but is still supplied for
1725 * backward compatibility.
1727 int total_size_of_entries(np)
1735 for (total = 0; np != NULL; np = np->right) {
1736 /* Count left subentries. */
1737 total += total_size_of_entries(np->left);
1739 /* Count this entry */
1740 total += strlen(np->pat) + 1;
1742 number_len((long)np->lno) + 1 + number_len(np->cno) + 1;
1743 if (np->name != NULL)
1744 total += 1 + strlen(np->name); /* \001name */
1751 * The C symbol tables.
1755 st_C_objprot, st_C_objimpl, st_C_objend,
1759 st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec,
1762 , st_C_union, st_C_class, st_C_extern, st_C_inline
1766 /* Feed stuff between (but not including) %[ and %] lines to:
1767 gperf -c -k 1,3 -o -p -r -t
1769 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1771 @interface, 0, st_C_objprot
1772 @protocol, 0, st_C_objprot
1773 @implementation,0, st_C_objimpl
1774 @end, 0, st_C_objend
1775 import, C_JAVA, st_C_ignore
1776 package, C_JAVA, st_C_ignore
1777 friend, C_PLPL, st_C_ignore
1778 extends, C_JAVA, st_C_javastruct
1779 implements, C_JAVA, st_C_javastruct
1780 interface, C_JAVA, st_C_struct
1781 class, C_PLPL, st_C_class
1782 namespace, C_PLPL, st_C_struct
1783 domain, C_STAR, st_C_struct
1784 union, 0, st_C_union
1785 struct, 0, st_C_struct
1787 typedef, 0, st_C_typedef
1788 define, 0, st_C_define
1789 inline, 0, st_C_inline
1790 bool, C_PLPL, st_C_typespec
1791 long, 0, st_C_typespec
1792 short, 0, st_C_typespec
1793 int, 0, st_C_typespec
1794 char, 0, st_C_typespec
1795 float, 0, st_C_typespec
1796 double, 0, st_C_typespec
1797 signed, 0, st_C_typespec
1798 unsigned, 0, st_C_typespec
1799 auto, 0, st_C_typespec
1800 void, 0, st_C_typespec
1801 extern, 0, st_C_extern
1802 static, 0, st_C_typespec
1803 const, 0, st_C_const
1804 volatile, 0, st_C_typespec
1805 explicit, C_PLPL, st_C_typespec
1806 mutable, C_PLPL, st_C_typespec
1807 typename, C_PLPL, st_C_typespec
1808 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
1809 DEFUN, 0, st_C_gnumacro
1810 SYSCALL, 0, st_C_gnumacro
1811 ENTRY, 0, st_C_gnumacro
1812 PSEUDO, 0, st_C_gnumacro
1813 # These are defined inside C functions, so currently they are not met.
1814 # EXFUN used in glibc, DEFVAR_* in emacs.
1815 #EXFUN, 0, st_C_gnumacro
1816 #DEFVAR_, 0, st_C_gnumacro
1818 and replace lines between %< and %> with its output. */
1820 /* C code produced by gperf version 2.5 (GNU C++ version) */
1821 /* Command-line: gperf -c -k 1,3 -o -p -r -t */
1822 struct C_stab_entry {
1828 #define TOTAL_KEYWORDS 41
1829 #define MIN_WORD_LENGTH 3
1830 #define MAX_WORD_LENGTH 15
1831 #define MIN_HASH_VALUE 13
1832 #define MAX_HASH_VALUE 129
1833 /* maximum key range = 117, duplicates = 0 */
1835 static unsigned int hash(char *str, unsigned int len)
1837 static unsigned char asso_values[] = {
1838 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1839 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1840 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1841 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1842 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1843 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1844 130, 130, 130, 130, 13, 130, 130, 130, 33, 32,
1845 47, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1846 5, 130, 130, 20, 32, 130, 130, 130, 130, 130,
1847 130, 130, 130, 130, 130, 130, 130, 47, 55, 8,
1848 15, 33, 61, 38, 130, 60, 130, 130, 2, 9,
1849 10, 62, 59, 130, 28, 27, 50, 19, 3, 130,
1850 130, 130, 130, 130, 130, 130, 130, 130,
1853 asso_values[(unsigned char)str[2]] +
1854 asso_values[(unsigned char)str[0]];
1857 static struct C_stab_entry *in_word_set(char *str, unsigned int len)
1859 static struct C_stab_entry wordlist[] = {
1860 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1861 {"",}, {"",}, {"",}, {"",},
1862 {"volatile", 0, st_C_typespec},
1864 {"long", 0, st_C_typespec},
1865 {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1866 {"const", 0, st_C_const},
1867 {"",}, {"",}, {"",},
1868 {"@end", 0, st_C_objend},
1869 {"namespace", C_PLPL, st_C_struct},
1871 {"domain", C_STAR, st_C_struct},
1873 {"@interface", 0, st_C_objprot},
1874 {"",}, {"",}, {"",},
1875 {"@implementation", 0, st_C_objimpl},
1877 {"double", 0, st_C_typespec},
1879 {"PSEUDO", 0, st_C_gnumacro},
1880 {"",}, {"",}, {"",},
1881 {"SYSCALL", 0, st_C_gnumacro},
1883 {"@protocol", 0, st_C_objprot},
1884 {"",}, {"",}, {"",},
1885 {"unsigned", 0, st_C_typespec},
1887 {"enum", 0, st_C_enum},
1889 {"char", 0, st_C_typespec},
1890 {"class", C_PLPL, st_C_class},
1891 {"struct", 0, st_C_struct},
1892 {"",}, {"",}, {"",}, {"",},
1893 {"mutable", C_PLPL, st_C_typespec},
1894 {"void", 0, st_C_typespec},
1895 {"inline", 0, st_C_inline},
1896 {"ENTRY", 0, st_C_gnumacro},
1898 {"signed", 0, st_C_typespec},
1900 {"package", C_JAVA, st_C_ignore},
1901 {"",}, {"",}, {"",}, {"",}, {"",},
1902 {"static", 0, st_C_typespec},
1904 {"define", 0, st_C_define},
1906 {"union", 0, st_C_union},
1907 {"DEFUN", 0, st_C_gnumacro},
1908 {"",}, {"",}, {"",},
1909 {"extern", 0, st_C_extern},
1910 {"extends", C_JAVA, st_C_javastruct},
1911 {"",}, {"",}, {"",},
1912 {"short", 0, st_C_typespec},
1913 {"",}, {"",}, {"",}, {"",}, {"",},
1914 {"explicit", C_PLPL, st_C_typespec},
1915 {"auto", 0, st_C_typespec},
1916 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1918 {"int", 0, st_C_typespec},
1920 {"typedef", 0, st_C_typedef},
1921 {"typename", C_PLPL, st_C_typespec},
1923 {"interface", C_JAVA, st_C_struct},
1925 {"bool", C_PLPL, st_C_typespec},
1926 {"",}, {"",}, {"",},
1927 {"import", C_JAVA, st_C_ignore},
1929 {"friend", C_PLPL, st_C_ignore},
1930 {"float", 0, st_C_typespec},
1931 {"implements", C_JAVA, st_C_javastruct},
1934 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) {
1935 register int key = hash(str, len);
1937 if (key <= MAX_HASH_VALUE && key >= 0) {
1938 register char *s = wordlist[key].name;
1940 if (*s == *str && !strncmp(str + 1, s + 1, len - 1))
1941 return &wordlist[key];
1949 enum sym_type C_symtype PP((char *str, int len, int c_ext));
1950 enum sym_type C_symtype(str, len, c_ext)
1955 register struct C_stab_entry *se = in_word_set(str, len);
1957 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1963 * C functions and variables are recognized using a simple
1964 * finite automaton. fvdef is its state variable.
1967 fvnone, /* nothing seen */
1968 fvnameseen, /* function or variable name seen */
1969 fstartlist, /* func: just after open parenthesis */
1970 finlist, /* func: in parameter list */
1971 flistseen, /* func: after parameter list */
1972 fignore, /* func: before open brace */
1973 vignore /* var-like: ignore until ';' */
1977 * typedefs are recognized using a simple finite automaton.
1978 * typdef is its state variable.
1981 tnone, /* nothing seen */
1982 ttypedseen, /* typedef keyword seen */
1983 tinbody, /* inside typedef body */
1984 tend, /* just before typedef tag */
1985 tignore /* junk after typedef tag */
1989 * struct-like structures (enum, struct and union) are recognized
1990 * using another simple finite automaton. `structdef' is its state
1994 snone, /* nothing seen yet */
1995 skeyseen, /* struct-like keyword seen */
1996 stagseen, /* struct-like tag seen */
1997 scolonseen, /* colon seen after struct-like tag */
1998 sinbody /* in struct body: recognize member func defs */
2002 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
2003 * struct tag, and structtype is the type of the preceding struct-like
2006 char *structtag = "<uninited>";
2007 enum sym_type structtype;
2010 void oo_browser_check_and_clear_structtype(void)
2012 /* Allow for multiple enum_label tags. */
2013 if (structtype != st_C_enum)
2014 structtype = st_none;
2019 * When objdef is different from onone, objtag is the name of the class.
2021 char *objtag = "<uninited>";
2024 * Yet another little state machine to deal with preprocessor lines.
2027 dnone, /* nothing seen */
2028 dsharpseen, /* '#' seen as first char on line */
2029 ddefineseen, /* '#' and 'define' seen */
2030 dignorerest /* ignore rest of line */
2034 * State machine for Objective C protocols and implementations.
2035 * Tom R.Hageman <tom@basil.icce.rug.nl>
2038 onone, /* nothing seen */
2039 oprotocol, /* @interface or @protocol seen */
2040 oimplementation, /* @implementations seen */
2041 otagseen, /* class name seen */
2042 oparenseen, /* parenthesis before category seen */
2043 ocatseen, /* category name seen */
2044 oinbody, /* in @implementation body */
2045 omethodsign, /* in @implementation body, after +/- */
2046 omethodtag, /* after method name */
2047 omethodcolon, /* after method colon */
2048 omethodparm, /* after method parameter */
2049 oignore /* wait for @end */
2053 * Use this structure to keep info about the token read, and how it
2054 * should be tagged. Used by the make_C_tag function to build a tag.
2066 token tok; /* latest token read */
2069 * Set this to TRUE, and the next token considered is called a function.
2070 * Used only for GNU emacs's function-defining macros.
2072 bool next_token_is_func;
2075 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
2080 * methodlen is the length of the method name stored in token_name.
2085 void oo_browser_clear_all_globals(void)
2087 /* Initialize globals so there is no carry over between files. */
2088 oo_browser_construct = C_NULL;
2094 structtype = st_none;
2095 next_token_is_func = yacc_rules = FALSE;
2098 void oo_browser_clear_some_globals(void)
2100 oo_browser_construct = C_NULL;
2101 structtype = st_none;
2107 * checks to see if the current token is at the start of a
2108 * function or variable, or corresponds to a typedef, or
2109 * is a struct/union/enum tag, or #define, or an enum constant.
2111 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2112 * with args. C_EXT is which language we are looking at.
2114 * In the future we will need some way to adjust where the end of
2115 * the token is; for instance, implementing the C++ keyword
2116 * `operator' properly will adjust the end of the token to be after
2117 * whatever follows `operator'.
2125 * next_token_is_func IN OUT
2127 bool consider_token PP((char *str, int len, int c, int c_ext,
2128 int cblev, int parlev, bool * is_func_or_var));
2129 bool consider_token(str, len, c, c_ext, cblev, parlev, is_func_or_var)
2130 register char *str; /* IN: token pointer */
2131 register int len; /* IN: token length */
2132 register int c; /* IN: first char after the token */
2133 int c_ext; /* IN: C extensions mask */
2134 int cblev; /* IN: curly brace level */
2135 int parlev; /* IN: parenthesis level */
2136 bool *is_func_or_var; /* OUT: function or variable found */
2138 enum sym_type toktype = C_symtype(str, len, c_ext);
2141 switch ((unsigned int)toktype) {
2143 set_construct(C_STRUCTURE);
2146 set_construct(C_UNION);
2149 set_construct(C_CLASS);
2152 set_construct(C_ENUMERATION);
2155 set_construct(C_TYPE);
2158 set_construct(C_EXTERN);
2161 set_construct(C_FUNCTION);
2171 * Advance the definedef state machine.
2173 switch (definedef) {
2175 /* We're not on a preprocessor line. */
2178 if (toktype == st_C_define) {
2179 definedef = ddefineseen;
2181 definedef = dignorerest;
2186 * Make a tag for any macro, unless it is a constant
2187 * and constantypedefs is FALSE.
2189 definedef = dignorerest;
2191 *is_func_or_var = (c == '(');
2194 char *p = str + len * sizeof(char);
2197 /* This must be a macro since there is no
2198 whitespace between the opening parenthesis
2199 and the definition name. */
2200 *is_func_or_var = TRUE;
2202 *is_func_or_var = FALSE;
2204 /* Handle possible whitespace between macro tag and opening
2205 parenthesis and ensure this is an actual macro.
2206 -- Bob Weiner, Altrasoft, 11/19/1997 */
2207 while (*p && isspace(*p))
2212 /* Skip over nested parentheses. */
2216 while (*++p && depth > 0 && *p != '\n') {
2229 /* If this is a macro, we have just passed
2230 the arguments and there will be more on
2231 the line before the NULL character that marks
2232 the end of the line token. */
2233 while (*p == ' ' || *p == '\t')
2236 *is_func_or_var = TRUE;
2241 set_construct((*is_func_or_var) ? C_MACRO : C_CONSTANT);
2243 if (!*is_func_or_var && !constantypedefs)
2250 error("internal error: definedef value.", (char *)NULL);
2258 if (toktype == st_C_typedef) {
2260 typdef = ttypedseen;
2266 switch ((unsigned int)toktype) {
2268 set_construct(C_CONSTANT);
2289 /* Do not return here, so the structdef stuff has a chance. */
2292 switch ((unsigned int)toktype) {
2294 set_construct(C_CONSTANT);
2320 * This structdef business is currently only invoked when cblev==0.
2321 * It should be recursively invoked whatever the curly brace level,
2322 * and a stack of states kept, to allow for definitions of structs
2325 * This structdef business is NOT invoked when we are ctags and the
2326 * file is plain C. This is because a struct tag may have the same
2327 * name as another tag, and this loses with ctags.
2329 switch ((unsigned int)toktype) {
2330 case st_C_javastruct:
2331 if (structdef == stagseen)
2332 structdef = scolonseen;
2341 if (typdef == ttypedseen
2342 || (typedefs_and_cplusplus && cblev == 0
2343 && structdef == snone)) {
2344 structdef = skeyseen;
2345 structtype = toktype;
2354 if (structdef == skeyseen) {
2355 /* Save the tag for struct/union/class, for functions and variables
2356 that may be defined inside. */
2358 if (structtype == st_C_struct)
2360 if (structtype == st_C_struct
2361 || structtype == st_C_union || structtype == st_C_class)
2363 structtag = savenstr(str, len);
2365 structtag = "<enum>";
2366 structdef = stagseen;
2370 /* Avoid entering fvdef stuff if typdef is going on. */
2371 if (typdef != tnone) {
2376 /* Detect GNU macros.
2378 DEFUN note for writers of emacs C code:
2379 The DEFUN macro, used in emacs C source code, has a first arg
2380 that is a string (the lisp function name), and a second arg that
2381 is a C function name. Since etags skips strings, the second arg
2382 is tagged. This is unfortunate, as it would be better to tag the
2383 first arg. The simplest way to deal with this problem would be
2384 to name the tag with a name built from the function name, by
2385 removing the initial 'F' character and substituting '-' for '_'.
2386 Anyway, this assumes that the conventions of naming lisp
2387 functions will never change. Currently, this method is not
2388 implemented, so writers of emacs code are recommended to put the
2389 first two args of a DEFUN on the same line. */
2390 if (definedef == dnone && toktype == st_C_gnumacro) {
2391 next_token_is_func = TRUE;
2394 if (next_token_is_func) {
2395 next_token_is_func = FALSE;
2397 *is_func_or_var = TRUE;
2401 /* Detect Objective C constructs. */
2404 switch ((unsigned int)toktype) {
2407 set_construct(C_OBJC);
2413 set_construct(C_OBJC);
2415 objdef = oimplementation;
2423 case oimplementation:
2424 /* Save the class tag for functions or variables defined inside. */
2425 objtag = savenstr(str, len);
2429 /* Save the class tag for categories. */
2430 objtag = savenstr(str, len);
2432 *is_func_or_var = TRUE;
2436 *is_func_or_var = TRUE;
2442 objdef = omethodtag;
2444 grow_linebuffer(&token_name, methodlen + 1);
2445 xstrncpy(token_name.buffer, str, methodlen+1);
2446 token_name.buffer[methodlen] = '\0';
2447 token_name.len = methodlen;
2453 objdef = omethodparm;
2457 objdef = omethodtag;
2459 grow_linebuffer(&token_name, methodlen + 1);
2460 strncat(token_name.buffer, str, len);
2461 token_name.len = methodlen;
2466 if (toktype == st_C_objend) {
2467 /* Memory leakage here: the string pointed by objtag is
2468 never released, because many tests would be needed to
2469 avoid breaking on incorrect input code. The amount of
2470 memory leaked here is the sum of the lengths of the
2485 /* A function, variable or enum constant? */
2486 switch ((unsigned int)toktype) {
2488 set_construct(C_CONSTANT);
2494 if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
2495 fvdef = fvnone; /* should be useless */
2501 if (constantypedefs && structdef == sinbody
2502 && structtype == st_C_enum)
2505 oo_browser_construct = C_ENUM_LABEL;
2511 if (fvdef == fvnone) {
2512 fvdef = fvnameseen; /* function or variable */
2513 *is_func_or_var = TRUE;
2527 * This routine finds functions, variables, typedefs,
2528 * #define's, enum constants and struct/union/enum definitions in
2529 * #C syntax and adds them to the list.
2531 #define current_lb_is_new (newndx == curndx)
2532 #define switch_line_buffers() (curndx = 1 - curndx)
2534 #define curlb (lbs[curndx].lb)
2535 #define othlb (lbs[1-curndx].lb)
2536 #define newlb (lbs[newndx].lb)
2537 #define curlinepos (lbs[curndx].linepos)
2538 #define othlinepos (lbs[1-curndx].linepos)
2539 #define newlinepos (lbs[newndx].linepos)
2541 #define CNL_SAVE_DEFINEDEF() \
2543 curlinepos = charno; \
2545 linecharno = charno; \
2546 charno += readline (&curlb, inf); \
2547 lp = curlb.buffer; \
2554 CNL_SAVE_DEFINEDEF(); \
2555 if (savetok.valid) \
2558 savetok.valid = FALSE; \
2560 definedef = dnone; \
2563 void make_C_tag PP((bool isfun));
2564 void make_C_tag(isfun)
2567 /* This function should never be called when tok.valid is FALSE, but
2568 we must protect against invalid input or internal errors. */
2570 if (traditional_tag_style) {
2571 /* This was the original code. Now we call new_pfnote instead,
2572 which uses the new method for naming tags (see new_pfnote). */
2575 if (CTAGS || tok.named)
2576 name = savestr(token_name.buffer);
2578 tok.buffer, tok.linelen, tok.lineno,
2581 new_pfnote(token_name.buffer, token_name.len, isfun,
2582 tok.buffer, tok.linelen, tok.lineno,
2589 void C_entries(c_ext, inf)
2590 int c_ext; /* extension of C */
2591 FILE *inf; /* input file */
2593 register char c; /* latest char read; '\0' for end of line */
2594 register char *lp; /* pointer one beyond the character `c' */
2595 int curndx, newndx; /* indices for current and new lb */
2596 register int tokoff; /* offset in line of start of current token */
2597 register int toklen; /* length of current token */
2598 char *qualifier; /* string used to qualify names */
2599 int qlen; /* length of qualifier */
2600 int cblev; /* current curly brace level */
2601 int parlev; /* current parenthesis level */
2602 bool incomm, inquote, inchar, quotednl, midtoken;
2604 token savetok; /* token saved during preprocessor handling */
2606 /* initialise savetok */
2607 memset(&savetok, 0, sizeof(token));
2609 tokoff = toklen = 0; /* keep compiler quiet */
2610 curndx = newndx = 0;
2621 next_token_is_func = yacc_rules = FALSE;
2622 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2623 tok.valid = savetok.valid = FALSE;
2626 cplpl = (c_ext & C_PLPL) == C_PLPL;
2627 cjava = (c_ext & C_JAVA) == C_JAVA;
2636 while (!feof(inf)) {
2639 /* If we're at the end of the line, the next character is a
2640 '\0'; don't skip it, because it's the thing that tells us
2641 to read the next line. */
2648 } else if (incomm) {
2657 /* Newlines inside comments do not end macro definitions in
2659 CNL_SAVE_DEFINEDEF();
2665 } else if (inquote) {
2671 /* Newlines inside strings do not end macro definitions
2672 in traditional cpp, even though compilers don't
2673 usually accept them. */
2674 CNL_SAVE_DEFINEDEF();
2680 } else if (inchar) {
2683 /* Hmmm, something went wrong. */
2697 if (fvdef != finlist && fvdef != fignore
2698 && fvdef != vignore)
2703 if (fvdef != finlist && fvdef != fignore
2704 && fvdef != vignore)
2712 } else if ( /* cplpl && */ *lp == '/') {
2718 if ((c_ext & YACC) && *lp == '%') {
2719 /* entering or exiting rules section in yacc file */
2725 next_token_is_func = FALSE;
2726 midtoken = inquote = inchar = incomm =
2729 yacc_rules = !yacc_rules;
2734 if (definedef == dnone) {
2736 bool cpptoken = TRUE;
2738 /* Look back on this line. If all blanks, or nonblanks
2739 followed by an end of comment, this is a preprocessor
2741 for (cp = newlb.buffer; cp < lp - 1;
2743 if (!iswhite(*cp)) {
2754 definedef = dsharpseen;
2756 /* if (definedef == dnone) */
2762 /* Consider token only if some complicated conditions are satisfied. */
2763 if ((definedef != dnone
2764 || (cblev == 0 && structdef != scolonseen)
2765 || (cblev == 1 && cplpl && structdef == sinbody)
2766 || (structdef == sinbody && structtype == st_C_enum))
2767 && typdef != tignore
2768 && definedef != dignorerest && fvdef != finlist) {
2771 if (c == ':' && cplpl && *lp == ':'
2772 && begtoken(*(lp + 1))) {
2774 * This handles :: in the middle, but not at the
2775 * beginning of an identifier.
2780 set_construct(C_METHOD);
2783 bool funorvar = FALSE;
2786 || consider_token(newlb.
2796 if (structdef == sinbody
2799 /* function or var defined in C++ class body */
2829 oo_browser_construct
2832 } else if (objdef ==
2834 /* Objective C category */
2867 oo_browser_construct
2870 } else if (objdef ==
2874 /* Objective C method */
2879 oo_browser_construct
2904 /* Also name #define constants,
2905 enumerations and enum_labels.
2906 Conditionalize `funorvar' reference
2907 here or #defines will appear without
2909 -- Bob Weiner, Altrasoft, 4/25/1998 */
2911 ((oo_browser_format || funorvar)
2919 (oo_browser_construct
2923 oo_browser_construct
2936 tok.lineno = lineno;
2938 tokoff + toklen + 1;
2945 if (definedef == dnone
2954 if (current_lb_is_new)
2963 } /* if (endtoken (c)) */
2964 else if (intoken(c)) {
2968 } /* if (midtoken) */
2969 else if (begtoken(c)) {
2970 switch (definedef) {
2972 switch ((unsigned int)fvdef) {
2978 set_construct(C_MACRO);
2980 make_C_tag(TRUE); /* a function */
2991 if (structdef == stagseen && !cjava)
3003 if (!yacc_rules || lp == newlb.buffer + 1) {
3004 tokoff = lp - 1 - newlb.buffer;
3009 } /* if (begtoken) */
3012 /* if must look at token */
3013 /* Detect end of line, colon, comma, semicolon and various braces
3014 after having handled a token. */
3017 if (definedef != dnone)
3019 switch ((unsigned int)objdef) {
3022 make_C_tag(TRUE); /* an Objective C class */
3026 objdef = omethodcolon;
3028 grow_linebuffer(&token_name, methodlen + 1);
3029 strcat(token_name.buffer, ":");
3030 token_name.len = methodlen;
3037 if (structdef == stagseen)
3038 structdef = scolonseen;
3040 switch ((unsigned int)fvdef) {
3043 make_C_tag(FALSE); /* a yacc function */
3057 if (definedef != dnone)
3060 switch ((unsigned int)typdef) {
3063 set_construct(C_TYPE);
3065 make_C_tag(FALSE); /* a typedef */
3070 switch ((unsigned int)fvdef) {
3074 if ((globals && cblev == 0)
3075 || (members && cblev == 1))
3077 make_C_tag(FALSE); /* a variable */
3079 /* if (constantypedefs && structdef == snone)*/
3082 switch ((unsigned int)structtype) {
3084 set_construct(C_ENUMERATION);
3087 set_construct(C_CLASS);
3090 set_construct(C_VARIABLE);
3094 /* Force reset of st_C_enum structtype value. */
3095 structtype = st_none;
3101 /* The following instruction invalidates the token.
3102 Probably the token should be invalidated in all
3103 other cases where some state machine is reset. */
3106 if (structdef == stagseen)
3110 if (definedef != dnone)
3112 switch ((unsigned int)objdef) {
3115 make_C_tag(TRUE); /* an Objective C method */
3123 switch ((unsigned int)fvdef) {
3129 if ((globals && cblev == 0)
3130 || (members && cblev == 1))
3131 make_C_tag(FALSE); /* a variable */
3136 if (structdef == stagseen)
3140 if (definedef != dnone)
3142 if (cblev == 0 && typdef == tend) {
3144 set_construct(C_TYPE);
3147 make_C_tag(FALSE); /* a typedef */
3150 switch ((unsigned int)fvdef) {
3157 if ((globals && cblev == 0)
3158 || (members && cblev == 1))
3159 make_C_tag(FALSE); /* a variable */
3161 if (constantypedefs && structdef == snone) {
3163 switch ((unsigned int)structtype) {
3165 set_construct(C_ENUMERATION);
3168 set_construct(C_CLASS);
3171 set_construct(C_VARIABLE);
3175 /* Force reset of st_C_enum structtype value. */
3176 structtype = st_none;
3186 if (structdef == stagseen)
3190 if (definedef != dnone)
3192 if (objdef == otagseen && parlev == 0)
3193 objdef = oparenseen;
3194 switch ((unsigned int)fvdef) {
3199 if (tok.valid && *lp != '*') {
3200 /* This handles constructs like:
3201 typedef void OperatorFun (int fun); */
3204 set_construct(C_TYPE);
3216 } /* switch (typdef) */
3232 if (definedef != dnone)
3234 if (objdef == ocatseen && parlev == 1) {
3235 make_C_tag(TRUE); /* an Objective C category */
3238 if (--parlev == 0) {
3239 switch ((unsigned int)fvdef) {
3249 if (cblev == 0 && typdef == tend) {
3251 set_construct(C_TYPE);
3254 make_C_tag(FALSE); /* a typedef */
3256 } else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3260 if (definedef != dnone)
3262 if (typdef == ttypedseen)
3264 switch (structdef) {
3265 case skeyseen: /* unnamed struct */
3266 structdef = sinbody;
3267 structtag = "_anonymous_";
3270 case scolonseen: /* named struct */
3271 structdef = sinbody;
3272 make_C_tag(FALSE); /* a struct */
3281 switch ((unsigned int)fvdef) {
3284 set_construct(C_FUNCTION);
3285 /* Ensure function name is recorded.
3286 -- Bob Weiner, Altrasoft */
3289 make_C_tag(TRUE); /* a function */
3295 switch ((unsigned int)objdef) {
3297 make_C_tag(TRUE); /* an Objective C class */
3302 make_C_tag(TRUE); /* an Objective C method */
3306 /* Neutralize `extern "C" {' grot. */
3307 if (cblev == 0 && structdef == snone
3319 if (definedef != dnone)
3321 if (fvdef == fstartlist)
3322 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
3325 if (definedef != dnone)
3327 if (!noindentypedefs && lp == newlb.buffer + 1) {
3328 cblev = 0; /* reset curly brace level if first column */
3329 parlev = 0; /* also reset paren level, just in case... */
3330 } else if (cblev > 0)
3333 if (typdef == tinbody)
3335 /* Memory leakage here: the string pointed by structtag is
3336 never released, because I fear to miss something and
3337 break things while freeing the area. The amount of
3338 memory leaked here is the sum of the lengths of the
3340 if (structdef == sinbody)
3341 free (structtag); */
3344 structtag = "<error>";
3346 /* Next line added to avoid any state carryover between
3347 functions. -- Bob Weiner, Altrasoft, 11/19/1997 */
3349 oo_browser_construct = C_NULL;
3354 if (definedef != dnone)
3366 if ((globals && cblev == 0)
3367 || (members && cblev == 1))
3369 make_C_tag(FALSE); /* a variable */
3373 switch ((unsigned int)structtype) {
3379 set_construct(C_CLASS);
3382 /* a global variable */
3388 /* ootags categorizes each tag found whereas etags doesn't.
3389 Set the is_method flag if this tag has been marked as
3390 such by an earlier section of code.
3391 -- Steve Baur, Altrasoft, 5/7/1998 */
3393 (oo_browser_construct ==
3397 /* Force reset of st_C_enum structtype value. */
3398 structtype = st_none;
3407 fvdef = is_method ? fignore : vignore;
3418 if (objdef == oinbody && cblev == 0) {
3419 objdef = omethodsign;
3436 if (definedef != dnone)
3441 /* The above characters cannot follow a function tag in C, so
3442 unmark this as a function entry. For C++, these characters
3443 may follow an `operator' function construct, so skip the
3444 unmarking conditional below.
3445 -- Steve Baur, Altrasoft, 5/7/1998 */
3446 if (fvdef != finlist && fvdef != fignore
3447 && fvdef != vignore)
3454 if (objdef == otagseen) {
3455 make_C_tag(TRUE); /* an Objective C class */
3458 /* If a macro spans multiple lines don't reset its state. */
3460 CNL_SAVE_DEFINEDEF();
3470 } /* while not eof */
3474 * Process either a C++ file or a C file depending on the setting
3477 void default_C_entries(inf)
3480 C_entries(cplusplus ? C_PLPL : 0, inf);
3483 /* Always do plain ANSI C. */
3484 void plain_C_entries(inf)
3490 /* Always do C++. */
3491 void Cplusplus_entries(inf)
3494 C_entries(C_PLPL, inf);
3497 /* Always do Java. */
3498 void Cjava_entries(inf)
3501 C_entries(C_JAVA, inf);
3505 void Cstar_entries(inf)
3508 C_entries(C_STAR, inf);
3511 /* Always do Yacc. */
3512 void Yacc_entries(inf)
3515 C_entries(YACC, inf);
3518 /* A useful macro. */
3519 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3520 for (lineno = charno = 0; /* loop initialization */ \
3521 !feof (file_pointer) /* loop test */ \
3522 && (lineno++, /* instructions at start of loop */ \
3523 linecharno = charno, \
3524 charno += readline (&line_buffer, file_pointer), \
3525 char_pointer = lb.buffer, \
3530 * Read a file, but do no processing. This is used to do regexp
3531 * matching on files that have no language defined.
3533 void just_read_file(inf)
3536 register char *dummy;
3538 LOOP_ON_INPUT_LINES(inf, lb, dummy)
3540 (void)dummy; // Silence set-not-read warning.
3543 /* Fortran parsing */
3545 bool tail PP((char *cp));
3549 register int len = 0;
3551 while (*cp && lowcase(*cp) == lowcase(dbp[len]))
3553 if (*cp == '\0' && !intoken(dbp[len])) {
3562 dbp = skip_spaces(dbp);
3566 dbp = skip_spaces(dbp);
3567 if (strneq(dbp, "(*)", 3)) {
3571 if (!isdigit(*dbp)) {
3572 --dbp; /* force failure */
3577 while (isdigit(*dbp));
3580 void getit PP((FILE * inf));
3586 dbp = skip_spaces(dbp);
3589 linecharno = charno;
3590 charno += readline(&lb, inf);
3595 dbp = skip_spaces(dbp);
3598 && *dbp != '_' && *dbp != '$')
3600 for (cp = dbp + 1; *cp && intoken(*cp); cp++)
3602 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
3603 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3606 void Fortran_functions(inf)
3609 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
3611 dbp++; /* Ratfor escape to fortran */
3612 dbp = skip_spaces(dbp);
3615 switch (lowcase(*dbp)) {
3617 if (tail("integer"))
3625 if (tail("logical"))
3629 if (tail("complex") || tail("character"))
3633 if (tail("double")) {
3634 dbp = skip_spaces(dbp);
3637 if (tail("precision"))
3645 dbp = skip_spaces(dbp);
3648 switch (lowcase(*dbp)) {
3650 if (tail("function"))
3654 if (tail("subroutine"))
3662 if (tail("program")) {
3666 if (tail("procedure"))
3676 * Bob Weiner, Motorola Inc., 4/3/94
3677 * Unix and microcontroller assembly tag handling
3678 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3680 void Asm_labels(FILE * inf)
3684 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3685 /* If first char is alphabetic or one of [_.$], test for colon
3686 following identifier. */
3687 if (isalpha(*cp) || *cp == '_' || *cp == '.' || *cp == '$') {
3688 /* Read past label. */
3690 while (isalnum(*cp) || *cp == '_' || *cp == '.'
3693 if (*cp == ':' || isspace(*cp)) {
3694 /* Found end of label, so copy it and add it to the table. */
3697 cp - lb.buffer) : NULL, TRUE,
3698 lb.buffer, cp - lb.buffer + 1, lineno,
3706 * Perl support by Bart Robinson <lomew@cs.utah.edu>
3707 * enhanced by Michael Ernst <mernst@alum.mit.edu>
3708 * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
3709 * Perl variable names: /^(my|local).../
3711 void Perl_functions(inf)
3716 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3718 && *cp++ == 'u' && *cp++ == 'b' && isspace(*cp++)) {
3719 cp = skip_spaces(cp);
3722 && !isspace(*cp) && *cp != '{'
3727 cp - lb.buffer) : NULL, TRUE,
3728 lb.buffer, cp - lb.buffer + 1, lineno,
3731 } else if (globals /* only if tagging global vars is enabled */
3732 && ((cp = lb.buffer, *cp++ == 'm' && *cp++ == 'y')
3737 && *cp++ == 'a' && *cp++ == 'l'))
3738 && (*cp == '(' || isspace(*cp))) {
3739 /* After "my" or "local", but before any following paren or space. */
3740 char *varname = NULL;
3742 cp = skip_spaces(cp);
3743 if (*cp == '$' || *cp == '@' || *cp == '%') {
3744 char *varstart = ++cp;
3745 while (isalnum(*cp) || *cp == '_')
3747 varname = savenstr(varstart, cp - varstart);
3749 /* Should be examining a variable list at this point;
3750 could insist on seeing an open parenthesis. */
3751 while (*cp != '\0' && *cp != ';' && *cp != '='
3756 /* Perhaps I should back cp up one character, so the TAGS table
3757 doesn't mention (and so depend upon) the following char. */
3758 pfnote((CTAGS) ? savenstr(lb.buffer, cp - lb.buffer) :
3759 varname, FALSE, lb.buffer, cp - lb.buffer + 1,
3760 lineno, linecharno);
3766 * Python support by Eric S. Raymond <esr@thyrsus.com>
3767 * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3769 void Python_functions(inf)
3774 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3776 && *cp++ == 'e' && *cp++ == 'f' && isspace(*cp++)) {
3777 cp = skip_spaces(cp);
3778 while (*cp != '\0' && !isspace(*cp) && *cp != '('
3781 pfnote((char *)NULL, TRUE,
3782 lb.buffer, cp - lb.buffer + 1, lineno,
3790 && *cp++ == 's' && *cp++ == 's' && isspace(*cp++)) {
3791 cp = skip_spaces(cp);
3792 while (*cp != '\0' && !isspace(*cp) && *cp != '('
3795 pfnote((char *)NULL, TRUE,
3796 lb.buffer, cp - lb.buffer + 1, lineno,
3802 /* Idea by Corny de Souza
3803 * Cobol tag functions
3804 * We could look for anything that could be a paragraph name.
3805 * i.e. anything that starts in column 8 is one word and ends in a full stop.
3807 void Cobol_paragraphs(inf)
3810 register char *bp, *ep;
3812 LOOP_ON_INPUT_LINES(inf, lb, bp) {
3817 /* If eoln, compiler option or comment ignore whole line. */
3818 if (bp[-1] != ' ' || !isalnum(bp[0]))
3821 for (ep = bp; isalnum(*ep) || *ep == '-'; ep++)
3824 pfnote((CTAGS) ? savenstr(bp, ep - bp) : NULL, TRUE,
3825 lb.buffer, ep - lb.buffer + 1, lineno,
3830 /* Added by Mosur Mohan, 4/22/88 */
3831 /* Pascal parsing */
3834 * Locates tags for procedures & functions. Doesn't do any type- or
3835 * var-definitions. It does look for the keyword "extern" or
3836 * "forward" immediately following the procedure statement; if found,
3837 * the tag is skipped.
3839 void Pascal_functions(inf)
3842 linebuffer tline; /* mostly copied from C_entries */
3844 int save_lineno, save_len;
3845 char c, *cp, *namebuf;
3847 bool /* each of these flags is TRUE iff: */
3848 incomment, /* point is inside a comment */
3849 inquote, /* point is inside '..' string */
3850 get_tagname, /* point is after PROCEDURE/FUNCTION
3851 keyword, so next item = potential tag */
3852 found_tag, /* point is after a potential tag */
3853 inparms, /* point is within parameter-list */
3854 verify_tag; /* point has passed the parm-list, so the
3855 next token will determine whether this
3856 is a FORWARD/EXTERN to be ignored, or
3857 whether it is a real tag */
3859 save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3860 namebuf = NULL; /* keep compiler quiet */
3867 incomment = inquote = FALSE;
3868 found_tag = FALSE; /* have a proc name; check if extern */
3869 get_tagname = FALSE; /* have found "procedure" keyword */
3870 inparms = FALSE; /* found '(' after "proc" */
3871 verify_tag = FALSE; /* check if "extern" is ahead */
3873 while (!feof(inf)) { /* long main loop to get next char */
3875 if (c == '\0') { /* if end of line */
3877 linecharno = charno;
3878 charno += readline(&lb, inf);
3882 if (!((found_tag && verify_tag)
3884 c = *dbp++; /* only if don't need *dbp pointing
3885 to the beginning of the name of
3886 the procedure or function */
3889 if (c == '}') /* within { } comments */
3891 else if (c == '*' && *dbp == ')') { /* within (* *) comments */
3896 } else if (inquote) {
3903 inquote = TRUE; /* found first quote */
3905 case '{': /* found open { comment */
3909 if (*dbp == '*') { /* found open (* comment */
3912 } else if (found_tag) /* found '(' after tag, i.e., parm-list */
3915 case ')': /* end of parms list */
3920 if (found_tag && !inparms) { /* end of proc or fn stmt */
3928 if (found_tag && verify_tag && (*dbp != ' ')) {
3929 /* check if this is an "extern" declaration */
3932 if (lowcase(*dbp == 'e')) {
3933 if (tail("extern")) { /* superfluous, really! */
3937 } else if (lowcase(*dbp) == 'f') {
3938 if (tail("forward")) { /* check for forward reference */
3943 if (found_tag && verify_tag) { /* not external proc, so make tag */
3946 pfnote(namebuf, TRUE,
3947 tline.buffer, save_len, save_lineno,
3952 if (get_tagname) { /* grab name of proc or fn */
3956 /* save all values for later tagging */
3957 grow_linebuffer(&tline, lb.len + 1);
3958 xstrncpy(tline.buffer, lb.buffer, lb.len + 1);
3959 save_lineno = lineno;
3960 save_lcno = linecharno;
3962 /* grab block name */
3963 for (cp = dbp + 1; *cp != '\0' && !endtoken(*cp); cp++)
3965 namebuf = (CTAGS) ? savenstr(dbp, cp - dbp) : NULL;
3966 dbp = cp; /* set dbp to e-o-token */
3967 save_len = dbp - lb.buffer + 1;
3968 get_tagname = FALSE;
3972 /* and proceed to check for "extern" */
3973 } else if (!incomment && !inquote && !found_tag) {
3974 /* check for proc/fn keywords */
3975 switch (lowcase(c)) {
3977 if (tail("rocedure")) /* c = 'p', dbp has advanced */
3981 if (tail("unction"))
3988 } /* while not eof */
3994 * lisp tag functions
3995 * look for (def or (DEF, quote or QUOTE
3997 int L_isdef PP((char *strp));
3999 register char *strp;
4001 return ((strp[1] == 'd' || strp[1] == 'D')
4002 && (strp[2] == 'e' || strp[2] == 'E')
4003 && (strp[3] == 'f' || strp[3] == 'F'));
4005 int L_isquote PP((char *strp));
4007 register char *strp;
4009 return ((*++strp == 'q' || *strp == 'Q')
4010 && (*++strp == 'u' || *strp == 'U')
4011 && (*++strp == 'o' || *strp == 'O')
4012 && (*++strp == 't' || *strp == 'T')
4013 && (*++strp == 'e' || *strp == 'E')
4014 && isspace(*++strp));
4017 void L_getit PP((void));
4022 if (*dbp == '\'') /* Skip prefix quote */
4024 else if (*dbp == '(') {
4026 dbp += 7; /* Skip "(quote " */
4028 dbp += 1; /* Skip "(" before name in (defstruct (foo)) */
4029 dbp = skip_spaces(dbp);
4032 for (cp = dbp /*+1 */ ;
4033 *cp != '\0' && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
4038 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
4039 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4042 void Lisp_functions(inf)
4045 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
4046 if (dbp[0] == '(') {
4048 dbp = skip_non_spaces(dbp);
4049 dbp = skip_spaces(dbp);
4052 /* Check for (foo::defmumble name-defined ... */
4055 while (*dbp != '\0' && !isspace(*dbp)
4056 && *dbp != ':' && *dbp != '('
4061 while (*dbp == ':');
4063 if (L_isdef(dbp - 1)) {
4064 dbp = skip_non_spaces(dbp);
4065 dbp = skip_spaces(dbp);
4075 * Postscript tag functions
4076 * Just look for lines where the first character is '/'
4077 * Richard Mlynarik <mly@adoc.xerox.com>
4079 void Postscript_functions(inf)
4082 register char *bp, *ep;
4084 LOOP_ON_INPUT_LINES(inf, lb, bp) {
4087 *ep != '\0' && *ep != ' ' && *ep != '{'; ep++)
4089 pfnote((CTAGS) ? savenstr(bp, ep - bp) : NULL, TRUE,
4090 lb.buffer, ep - lb.buffer + 1, lineno,
4097 * Scheme tag functions
4098 * look for (def... xyzzy
4099 * look for (def... (xyzzy
4100 * look for (def ... ((...(xyzzy ....
4101 * look for (set! xyzzy
4104 void get_scheme PP((void));
4106 void Scheme_functions(inf)
4109 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
4110 if (dbp[0] == '(' && (dbp[1] == 'D' || dbp[1] == 'd')
4111 && (dbp[2] == 'E' || dbp[2] == 'e')
4112 && (dbp[3] == 'F' || dbp[3] == 'f')) {
4113 dbp = skip_non_spaces(dbp);
4114 /* Skip over open parens and white space */
4115 while (isspace(*dbp) || *dbp == '(')
4119 if (dbp[0] == '(' && (dbp[1] == 'S' || dbp[1] == 's')
4120 && (dbp[2] == 'E' || dbp[2] == 'e')
4121 && (dbp[3] == 'T' || dbp[3] == 't')
4122 && (dbp[4] == '!' || dbp[4] == '!')
4123 && (isspace(dbp[5]))) {
4124 dbp = skip_non_spaces(dbp);
4125 dbp = skip_spaces(dbp);
4137 /* Go till you get to white space or a syntactic break */
4139 *cp != '\0' && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
4141 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
4142 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4145 /* Find tags in TeX and LaTeX input files. */
4147 /* TEX_toktab is a table of TeX control sequences that define tags.
4148 Each TEX_tabent records one such control sequence.
4149 CONVERT THIS TO USE THE Stab TYPE!! */
4155 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
4157 /* Default set of control sequences to put into TEX_toktab.
4158 The value of environment var TEXTAGS is prepended to this. */
4160 char *TEX_defenv = "\
4161 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4162 :part:appendix:entry:index";
4164 void TEX_mode PP((FILE * inf));
4165 struct TEX_tabent *TEX_decode_env PP((char *evarname, char *defenv));
4166 int TEX_Token PP((char *cp));
4168 char TEX_esc = '\\';
4169 char TEX_opgrp = '{';
4170 char TEX_clgrp = '}';
4173 * TeX/LaTeX scanning loop.
4175 void TeX_functions(inf)
4181 /* Select either \ or ! as escape character. */
4184 /* Initialize token table once from environment. */
4186 TEX_toktab = TEX_decode_env("TEXTAGS", TEX_defenv);
4188 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4190 /* Look at each esc in line. */
4191 while ((cp = etags_strchr(cp, TEX_esc)) != NULL) {
4194 linecharno += cp - lasthit;
4196 i = TEX_Token(lasthit);
4198 /* We seem to include the TeX command in the tag name.
4200 for (p = lasthit + TEX_toktab[i].len;
4201 *p != '\0' && *p != TEX_clgrp;
4204 pfnote( /*savenstr (lasthit, p-lasthit) */
4206 lb.buffer, lb.len, lineno, linecharno);
4207 break; /* We only tag a line once */
4213 #define TEX_LESC '\\'
4214 #define TEX_SESC '!'
4217 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4218 chars accordingly. */
4224 while ((c = getc(inf)) != EOF) {
4225 /* Skip to next line if we hit the TeX comment char. */
4229 else if (c == TEX_LESC || c == TEX_SESC)
4233 if (c == TEX_LESC) {
4245 /* Read environment and prepend it to the default string.
4246 Build token table. */
4247 struct TEX_tabent *TEX_decode_env(evarname, defenv)
4251 register char *env, *p;
4253 struct TEX_tabent *tab;
4256 /* Append default string to environment. */
4257 env = getenv(evarname);
4262 env = concat(oldenv, defenv, "");
4266 /* Allocate a token table */
4267 for (size = 1, p = env; p;)
4268 if ((p = etags_strchr(p, ':')) && *++p != '\0')
4270 /* Add 1 to leave room for null terminator. */
4271 tab = xnew(size + 1, struct TEX_tabent);
4273 /* Unpack environment string into token table. Be careful about */
4274 /* zero-length strings (leading ':', "::" and trailing ':') */
4275 for (i = 0; *env;) {
4276 p = etags_strchr(env, ':');
4277 if (!p) /* End of environment string. */
4278 p = env + strlen(env);
4279 if (p - env > 0) { /* Only non-zero strings. */
4280 tab[i].name = savenstr(env, p - env);
4281 tab[i].len = strlen(tab[i].name);
4287 tab[i].name = NULL; /* Mark end of table. */
4295 /* If the text at CP matches one of the tag-defining TeX command names,
4296 return the pointer to the first occurrence of that command in TEX_toktab.
4297 Otherwise return -1.
4298 Keep the capital `T' in `token' for dumb truncating compilers
4299 (this distinguishes it from `TEX_toktab' */
4305 for (i = 0; TEX_toktab[i].len > 0; i++)
4306 if (strneq(TEX_toktab[i].name, cp, TEX_toktab[i].len))
4312 * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4314 * Assumes that the predicate starts at column 0.
4315 * Only the first clause of a predicate is added.
4317 int prolog_pred PP((char *s, char *last));
4318 void prolog_skip_comment PP((linebuffer * plb, FILE * inf));
4319 int prolog_atom PP((char *s, int pos));
4321 void Prolog_functions(inf)
4332 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4333 if (cp[0] == '\0') /* Empty line */
4335 else if (isspace(cp[0])) /* Not a predicate */
4337 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
4338 prolog_skip_comment(&lb, inf);
4339 else if ((len = prolog_pred(cp, last)) > 0) {
4340 /* Predicate. Store the function name so that we only
4341 generate a tag for the first clause. */
4343 last = xnew(len + 1, char);
4344 else if (len + 1 > allocated)
4345 last = xrnew(last, len + 1, char);
4346 allocated = len + 1;
4347 xstrncpy(last, cp, allocated);
4353 void prolog_skip_comment(plb, inf)
4360 for (cp = plb->buffer; *cp != '\0'; cp++)
4361 if (cp[0] == '*' && cp[1] == '/')
4364 linecharno += readline(plb, inf);
4370 * A predicate definition is added if it matches:
4371 * <beginning of line><Prolog Atom><whitespace>(
4373 * It is added to the tags database if it doesn't match the
4374 * name of the previous clause header.
4376 * Return the size of the name of the predicate, or 0 if no header
4379 int prolog_pred(s, last)
4381 char *last; /* Name of last clause. */
4386 pos = prolog_atom(s, 0);
4391 pos = skip_spaces(s + pos) - s;
4393 if ((s[pos] == '(') || (s[pos] == '.')) {
4397 /* Save only the first clause. */
4398 if (last == NULL || len != (int)strlen(last)
4399 || !strneq(s, last, len)) {
4400 pfnote((CTAGS) ? savenstr(s, len) : NULL, TRUE,
4401 s, pos, lineno, linecharno);
4409 * Consume a Prolog atom.
4410 * Return the number of bytes consumed, or -1 if there was an error.
4412 * A prolog atom, in this context, could be one of:
4413 * - An alphanumeric sequence, starting with a lower case letter.
4414 * - A quoted arbitrary string. Single quotes can escape themselves.
4415 * Backslash quotes everything.
4417 int prolog_atom(s, pos)
4425 if (islower(s[pos]) || (s[pos] == '_')) {
4426 /* The atom is unquoted. */
4428 while (isalnum(s[pos]) || (s[pos] == '_')) {
4431 return pos - origpos;
4432 } else if (s[pos] == '\'') {
4436 if (s[pos] == '\'') {
4440 pos++; /* A double quote */
4441 } else if (s[pos] == '\0')
4442 /* Multiline quoted atoms are ignored. */
4444 else if (s[pos] == '\\') {
4445 if (s[pos + 1] == '\0')
4451 return pos - origpos;
4457 * Support for Erlang -- Anders Lindgren, Feb 1996.
4459 * Generates tags for functions, defines, and records.
4461 * Assumes that Erlang functions start at column 0.
4463 int erlang_func PP((char *s, char *last));
4464 void erlang_attribute PP((char *s));
4465 int erlang_atom PP((char *s, int pos));
4467 void Erlang_functions(inf)
4478 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4479 if (cp[0] == '\0') /* Empty line */
4481 else if (isspace(cp[0])) /* Not function nor attribute */
4483 else if (cp[0] == '%') /* comment */
4485 else if (cp[0] == '"') /* Sometimes, strings start in column one */
4487 else if (cp[0] == '-') { /* attribute, e.g. "-define" */
4488 erlang_attribute(cp);
4491 } else if ((len = erlang_func(cp, last)) > 0) {
4493 * Function. Store the function name so that we only
4494 * generates a tag for the first clause.
4497 last = xnew(len + 1, char);
4498 else if (len + 1 > allocated)
4499 last = xrnew(last, len + 1, char);
4500 allocated = len + 1;
4501 xstrncpy(last, cp, allocated);
4508 * A function definition is added if it matches:
4509 * <beginning of line><Erlang Atom><whitespace>(
4511 * It is added to the tags database if it doesn't match the
4512 * name of the previous clause header.
4514 * Return the size of the name of the function, or 0 if no function
4517 int erlang_func(s, last)
4519 char *last; /* Name of last clause. */
4524 pos = erlang_atom(s, 0);
4529 pos = skip_spaces(s + pos) - s;
4531 /* Save only the first clause. */
4532 if (s[pos++] == '(' && (last == NULL || len != (int)strlen(last)
4533 || !strneq(s, last, len))) {
4534 pfnote((CTAGS) ? savenstr(s, len) : NULL, TRUE,
4535 s, pos, lineno, linecharno);
4543 * Handle attributes. Currently, tags are generated for defines
4546 * They are on the form:
4547 * -define(foo, bar).
4548 * -define(Foo(M, N), M+N).
4549 * -record(graph, {vtab = notable, cyclic = true}).
4551 void erlang_attribute(s)
4557 if (strneq(s, "-define", 7) || strneq(s, "-record", 7)) {
4558 pos = skip_spaces(s + 7) - s;
4559 if (s[pos++] == '(') {
4560 pos = skip_spaces(s + pos) - s;
4561 len = erlang_atom(s, pos);
4563 pfnote((CTAGS) ? savenstr(&s[pos], len) : NULL,
4564 TRUE, s, pos + len, lineno, linecharno);
4571 * Consume an Erlang atom (or variable).
4572 * Return the number of bytes consumed, or -1 if there was an error.
4574 int erlang_atom(s, pos)
4582 if (isalpha(s[pos]) || s[pos] == '_') {
4583 /* The atom is unquoted. */
4585 while (isalnum(s[pos]) || s[pos] == '_')
4587 return pos - origpos;
4588 } else if (s[pos] == '\'') {
4592 if (s[pos] == '\'') {
4595 } else if (s[pos] == '\0')
4596 /* Multiline quoted atoms are ignored. */
4598 else if (s[pos] == '\\') {
4599 if (s[pos + 1] == '\0')
4605 return pos - origpos;
4610 #ifdef ETAGS_REGEXPS
4612 /* Take a string like "/blah/" and turn it into "blah", making sure
4613 that the first and last characters are the same, and handling
4614 quoted separator characters. Actually, stops on the occurrence of
4615 an unquoted separator. Also turns "\t" into a Tab character.
4616 Returns pointer to terminating separator. Works in place. Null
4617 terminates name string. */
4618 char *scan_separators PP((char *name));
4619 char *scan_separators(name)
4623 char *copyto = name;
4624 bool quoted = FALSE;
4626 for (++name; *name != '\0'; ++name) {
4630 else if (*name == sep)
4633 /* Something else is quoted, so preserve the quote. */
4638 } else if (*name == '\\')
4640 else if (*name == sep)
4646 /* Terminate copied string. */
4651 /* Look at the argument of --regex or --no-regex and do the right
4652 thing. Same for each line of a regexp file. */
4653 void analyse_regex(regex_arg)
4656 if (regex_arg == NULL) {
4657 free_patterns(); /* --no-regex: remove existing regexps */
4660 /* A real --regexp option or a line in a regexp file. */
4661 switch (regex_arg[0]) {
4662 /* Comments in regexp file or null arg to --regex. */
4668 /* Read a regex file. This is recursive and may result in a
4669 loop, which will stop when the file descriptors are exhausted. */
4673 linebuffer regexbuf;
4674 char *regexfile = regex_arg + 1;
4676 /* regexfile is a file containing regexps, one per line. */
4677 regexfp = fopen(regexfile, "r");
4678 if (regexfp == NULL) {
4682 initbuffer(®exbuf);
4683 while (readline_internal(®exbuf, regexfp) > 0)
4684 analyse_regex(regexbuf.buffer);
4685 free(regexbuf.buffer);
4690 /* Regexp to be used for a specific language only. */
4694 char *lang_name = regex_arg + 1;
4697 for (cp = lang_name; *cp != '}'; cp++)
4700 ("unterminated language name in regex: %s",
4705 lang = get_language_from_name(lang_name);
4708 add_regex(cp + 1, lang);
4712 /* Regexp to be used for any language. */
4714 add_regex(regex_arg, NULL);
4719 /* Turn a name, which is an ed-style (but Emacs syntax) regular
4720 expression, into a real regular expression by compiling it. */
4721 void add_regex(regexp_pattern, lang)
4722 char *regexp_pattern;
4727 struct re_pattern_buffer *patbuf;
4730 if (regexp_pattern[strlen(regexp_pattern) - 1] != regexp_pattern[0]) {
4731 error("%s: unterminated regexp", regexp_pattern);
4734 name = scan_separators(regexp_pattern);
4735 if (regexp_pattern[0] == '\0') {
4736 error("null regexp", (char *)NULL);
4739 (void)scan_separators(name);
4741 patbuf = xnew(1, struct re_pattern_buffer);
4742 patbuf->translate = NULL;
4743 patbuf->fastmap = NULL;
4744 patbuf->buffer = NULL;
4745 patbuf->allocated = 0;
4748 re_compile_pattern(regexp_pattern, strlen(regexp_pattern), patbuf);
4750 error("%s while compiling pattern", err);
4755 p_head = xnew(1, pattern);
4756 p_head->regex = savestr(regexp_pattern);
4757 p_head->p_next = pp;
4758 p_head->language = lang;
4759 p_head->pattern = patbuf;
4760 p_head->name_pattern = savestr(name);
4761 p_head->error_signaled = FALSE;
4765 * Do the substitutions indicated by the regular expression and
4768 char *substitute PP((char *in, char *out, struct re_registers * regs));
4769 char *substitute(in, out, regs)
4771 struct re_registers *regs;
4774 int size, dig, diglen;
4779 /* Pass 1: figure out how much to allocate by finding all \N strings. */
4780 if (out[size - 1] == '\\')
4781 fatal("pattern error in \"%s\"", out);
4782 for (t = etags_strchr(out, '\\');
4783 t != NULL; t = etags_strchr(t + 2, '\\'))
4784 if (isdigit(t[1])) {
4786 diglen = regs->end[dig] - regs->start[dig];
4791 /* Allocate space and do the substitutions. */
4792 size_t avail = size + 1;
4793 result = xnew(avail, char);
4795 for (t = result; *out != '\0'; out++)
4796 if (*out == '\\' && isdigit(*++out)) {
4797 /* Using "dig2" satisfies my debugger. Bleah. */
4799 diglen = regs->end[dig] - regs->start[dig];
4800 xstrncpy(t, in + regs->start[dig], avail);
4809 if (DEBUG && (t > result + size || t - result != strlen(result)))
4815 /* Deallocate all patterns. */
4816 void free_patterns()
4819 while (p_head != NULL) {
4820 pp = p_head->p_next;
4821 free(p_head->regex);
4822 free(p_head->name_pattern);
4829 #endif /* ETAGS_REGEXPS */
4830 /* Initialize a linebuffer for use */
4831 void initbuffer(lbp)
4835 lbp->buffer = xnew(200, char);
4839 * Read a line of text from `stream' into `lbp', excluding the
4840 * newline or CR-NL, if any. Return the number of characters read from
4841 * `stream', which is the length of the line including the newline.
4843 * On DOS or Windows we do not count the CR character, if any, before the
4844 * NL, in the returned length; this mirrors the behavior of emacs on those
4845 * platforms (for text files, it translates CR-NL to NL as it reads in the
4848 long readline_internal(lbp, stream)
4850 register FILE *stream;
4852 char *buffer = lbp->buffer;
4853 register char *p = lbp->buffer;
4854 register char *pend;
4857 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
4860 register int c = getc(stream);
4862 /* We're at the end of linebuffer: expand it. */
4864 buffer = xrnew(buffer, lbp->size, char);
4865 p += buffer - lbp->buffer;
4866 pend = buffer + lbp->size;
4867 lbp->buffer = buffer;
4875 if (p > buffer && p[-1] == '\r') {
4886 lbp->len = p - buffer;
4888 return lbp->len + chars_deleted;
4892 * Like readline_internal, above, but in addition try to match the
4893 * input line against relevant regular expressions.
4895 long readline(lbp, stream)
4899 /* Read new line. */
4900 long result = readline_internal(lbp, stream);
4901 #ifdef ETAGS_REGEXPS
4905 /* Match against relevant patterns. */
4907 for (pp = p_head; pp != NULL; pp = pp->p_next) {
4908 /* Only use generic regexps or those for the current language. */
4909 if (pp->language != NULL && pp->language != curlang)
4913 re_match(pp->pattern, lbp->buffer, lbp->len, 0,
4918 if (!pp->error_signaled) {
4919 error("error while matching \"%s\"",
4921 pp->error_signaled = TRUE;
4928 /* Match occurred. Construct a tag. */
4929 if (pp->name_pattern[0] != '\0') {
4930 /* Make a named tag. */
4931 char *name = substitute(lbp->buffer,
4936 pfnote(name, TRUE, lbp->buffer,
4940 /* Make an unnamed tag. */
4941 pfnote((char *)NULL, TRUE,
4942 lbp->buffer, match, lineno,
4948 #endif /* ETAGS_REGEXPS */
4954 * Return a pointer to a space of size strlen(cp)+1 allocated
4955 * with xnew where the string CP has been copied.
4960 return savenstr(cp, strlen(cp));
4964 * Return a pointer to a space of size LEN+1 allocated with xnew where
4965 * the string CP has been copied for at most the first LEN characters.
4967 char *savenstr(cp, len)
4973 dp = xnew(len + 1, char);
4974 xstrncpy(dp, cp, len+1);
4979 /* Skip spaces, return new pointer. */
4980 char *skip_spaces(cp)
4983 while (isspace(*cp)) /* isspace('\0')==FALSE */
4988 /* Skip non spaces, return new pointer. */
4989 char *skip_non_spaces(cp)
4992 while (!iswhite(*cp)) /* iswhite('\0')==TRUE */
4997 /* Print error message and exit. */
5012 void suggest_asking_for_help()
5014 fprintf(stderr, "\tTry `%s %s' for a complete list of options.\n",
5025 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
5027 const char *s1, *s2;
5029 fprintf(stderr, "%s: ", progname);
5030 fprintf(stderr, s1, s2);
5031 fprintf(stderr, "\n");
5034 /* Return a newly-allocated string whose contents
5035 concatenate those of s1, s2, s3. */
5036 char *concat(s1, s2, s3)
5039 int len1 = strlen(s1), len2 = strlen(s2), len3 = strlen(s3);
5040 char *result = xnew(len1 + len2 + len3 + 1, char);
5043 strcpy(result + len1, s2);
5044 strcpy(result + len1 + len2, s3);
5045 result[len1 + len2 + len3] = '\0';
5050 /* Does the same work as the system V getcwd, but does not need to
5051 guess the buffer size in advance. */
5052 char *etags_getcwd()
5056 char *path = xnew(bufsize, char);
5058 while (getcwd(path, bufsize) == NULL) {
5059 if (errno != ERANGE)
5063 path = xnew(bufsize, char);
5066 canonicalize_filename(path);
5069 #else /* not HAVE_GETCWD */
5074 pipe = (FILE *) popen("pwd 2>/dev/null", "r");
5075 if (pipe == NULL || readline_internal(&path, pipe) == 0)
5080 #endif /* not HAVE_GETCWD */
5083 /* Return a newly allocated string containing the file name of FILE
5084 relative to the absolute directory DIR (which should end with a slash). */
5085 char *relative_filename(file, dir)
5088 char *fp, *dp, *afn, *res;
5092 /* Find the common root of file and dir (with a trailing slash). */
5093 afn = absolute_filename(file, cwd);
5096 while (*fp++ == *dp++)
5098 fp--, dp--; /* back to the first differing char */
5099 do /* look at the equal chars until '/' */
5102 fp ++; /* Advance past the '/' */
5104 /* Build a sequence of "../" strings for the resulting relative file name. */
5106 while ((dp = etags_strchr(dp + 1, '/')) != NULL)
5108 res_left = 3 * i + strlen(fp);
5109 res = xnew( res_left + 1, char);
5111 for ( ; i-- > 0 ; res_left -= 4 )
5112 strncat(res, "../", res_left );
5114 /* Add the file name relative to the common root of file and dir. */
5115 strncat(res, fp, res_left);
5121 /* Return a newly allocated string containing the absolute file name
5122 of FILE given DIR (which should end with a slash). */
5123 char *absolute_filename(file, dir)
5126 char *slashp, *cp, *res;
5128 if (filename_is_absolute(file))
5129 res = savestr(file);
5131 res = concat(dir, file, "");
5133 /* Delete the "/dirname/.." and "/." substrings. */
5134 slashp = etags_strchr(res, '/');
5135 while (slashp != NULL && slashp[0] != '\0') {
5136 if (slashp[1] == '.') {
5137 if (slashp[2] == '.'
5138 && (slashp[3] == '/' || slashp[3] == '\0')) {
5142 while (cp >= res && !filename_is_absolute(cp));
5144 cp = slashp; /* the absolute name begins with "/.." */
5145 strcpy(cp, slashp + 3);
5148 } else if (slashp[2] == '/' || slashp[2] == '\0') {
5149 strcpy(slashp, slashp + 2);
5154 slashp = etags_strchr(slashp + 1, '/');
5158 return savestr("/");
5163 /* Return a newly allocated string containing the absolute
5164 file name of dir where FILE resides given DIR (which should
5165 end with a slash). */
5166 char *absolute_dirname(file, dir)
5172 canonicalize_filename(file);
5173 slashp = etags_strrchr(file, '/');
5175 return savestr(dir);
5178 res = absolute_filename(file, dir);
5184 /* Whether the argument string is an absolute file name. The argument
5185 string must have been canonicalized with canonicalize_filename. */
5186 bool filename_is_absolute(fn)
5189 return (fn[0] == '/');
5192 /* Translate backslashes into slashes. Works in place. */
5193 void canonicalize_filename(fn)
5199 /* Increase the size of a linebuffer. */
5200 void grow_linebuffer(lbp, toksize)
5204 while (lbp->size < toksize)
5206 lbp->buffer = xrnew(lbp->buffer, lbp->size, char);
5209 /* Like malloc but get fatal error if memory is exhausted. */
5213 long *result = (long *)malloc(size);
5215 fatal("virtual memory exhausted", (char *)NULL);
5219 long *xrealloc(ptr, size)
5223 long *result = (long *)realloc(ptr, size);
5225 fatal("virtual memory exhausted", (char *)NULL);