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)
3542 /* Fortran parsing */
3544 bool tail PP((char *cp));
3548 register int len = 0;
3550 while (*cp && lowcase(*cp) == lowcase(dbp[len]))
3552 if (*cp == '\0' && !intoken(dbp[len])) {
3561 dbp = skip_spaces(dbp);
3565 dbp = skip_spaces(dbp);
3566 if (strneq(dbp, "(*)", 3)) {
3570 if (!isdigit(*dbp)) {
3571 --dbp; /* force failure */
3576 while (isdigit(*dbp));
3579 void getit PP((FILE * inf));
3585 dbp = skip_spaces(dbp);
3588 linecharno = charno;
3589 charno += readline(&lb, inf);
3594 dbp = skip_spaces(dbp);
3597 && *dbp != '_' && *dbp != '$')
3599 for (cp = dbp + 1; *cp && intoken(*cp); cp++)
3601 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
3602 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3605 void Fortran_functions(inf)
3608 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
3610 dbp++; /* Ratfor escape to fortran */
3611 dbp = skip_spaces(dbp);
3614 switch (lowcase(*dbp)) {
3616 if (tail("integer"))
3624 if (tail("logical"))
3628 if (tail("complex") || tail("character"))
3632 if (tail("double")) {
3633 dbp = skip_spaces(dbp);
3636 if (tail("precision"))
3644 dbp = skip_spaces(dbp);
3647 switch (lowcase(*dbp)) {
3649 if (tail("function"))
3653 if (tail("subroutine"))
3661 if (tail("program")) {
3665 if (tail("procedure"))
3675 * Bob Weiner, Motorola Inc., 4/3/94
3676 * Unix and microcontroller assembly tag handling
3677 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3679 void Asm_labels(FILE * inf)
3683 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3684 /* If first char is alphabetic or one of [_.$], test for colon
3685 following identifier. */
3686 if (isalpha(*cp) || *cp == '_' || *cp == '.' || *cp == '$') {
3687 /* Read past label. */
3689 while (isalnum(*cp) || *cp == '_' || *cp == '.'
3692 if (*cp == ':' || isspace(*cp)) {
3693 /* Found end of label, so copy it and add it to the table. */
3696 cp - lb.buffer) : NULL, TRUE,
3697 lb.buffer, cp - lb.buffer + 1, lineno,
3705 * Perl support by Bart Robinson <lomew@cs.utah.edu>
3706 * enhanced by Michael Ernst <mernst@alum.mit.edu>
3707 * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
3708 * Perl variable names: /^(my|local).../
3710 void Perl_functions(inf)
3715 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3717 && *cp++ == 'u' && *cp++ == 'b' && isspace(*cp++)) {
3718 cp = skip_spaces(cp);
3721 && !isspace(*cp) && *cp != '{'
3726 cp - lb.buffer) : NULL, TRUE,
3727 lb.buffer, cp - lb.buffer + 1, lineno,
3730 } else if (globals /* only if tagging global vars is enabled */
3731 && ((cp = lb.buffer, *cp++ == 'm' && *cp++ == 'y')
3736 && *cp++ == 'a' && *cp++ == 'l'))
3737 && (*cp == '(' || isspace(*cp))) {
3738 /* After "my" or "local", but before any following paren or space. */
3739 char *varname = NULL;
3741 cp = skip_spaces(cp);
3742 if (*cp == '$' || *cp == '@' || *cp == '%') {
3743 char *varstart = ++cp;
3744 while (isalnum(*cp) || *cp == '_')
3746 varname = savenstr(varstart, cp - varstart);
3748 /* Should be examining a variable list at this point;
3749 could insist on seeing an open parenthesis. */
3750 while (*cp != '\0' && *cp != ';' && *cp != '='
3755 /* Perhaps I should back cp up one character, so the TAGS table
3756 doesn't mention (and so depend upon) the following char. */
3757 pfnote((CTAGS) ? savenstr(lb.buffer, cp - lb.buffer) :
3758 varname, FALSE, lb.buffer, cp - lb.buffer + 1,
3759 lineno, linecharno);
3765 * Python support by Eric S. Raymond <esr@thyrsus.com>
3766 * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3768 void Python_functions(inf)
3773 LOOP_ON_INPUT_LINES(inf, lb, cp) {
3775 && *cp++ == 'e' && *cp++ == 'f' && isspace(*cp++)) {
3776 cp = skip_spaces(cp);
3777 while (*cp != '\0' && !isspace(*cp) && *cp != '('
3780 pfnote((char *)NULL, TRUE,
3781 lb.buffer, cp - lb.buffer + 1, lineno,
3789 && *cp++ == 's' && *cp++ == 's' && isspace(*cp++)) {
3790 cp = skip_spaces(cp);
3791 while (*cp != '\0' && !isspace(*cp) && *cp != '('
3794 pfnote((char *)NULL, TRUE,
3795 lb.buffer, cp - lb.buffer + 1, lineno,
3801 /* Idea by Corny de Souza
3802 * Cobol tag functions
3803 * We could look for anything that could be a paragraph name.
3804 * i.e. anything that starts in column 8 is one word and ends in a full stop.
3806 void Cobol_paragraphs(inf)
3809 register char *bp, *ep;
3811 LOOP_ON_INPUT_LINES(inf, lb, bp) {
3816 /* If eoln, compiler option or comment ignore whole line. */
3817 if (bp[-1] != ' ' || !isalnum(bp[0]))
3820 for (ep = bp; isalnum(*ep) || *ep == '-'; ep++)
3823 pfnote((CTAGS) ? savenstr(bp, ep - bp) : NULL, TRUE,
3824 lb.buffer, ep - lb.buffer + 1, lineno,
3829 /* Added by Mosur Mohan, 4/22/88 */
3830 /* Pascal parsing */
3833 * Locates tags for procedures & functions. Doesn't do any type- or
3834 * var-definitions. It does look for the keyword "extern" or
3835 * "forward" immediately following the procedure statement; if found,
3836 * the tag is skipped.
3838 void Pascal_functions(inf)
3841 linebuffer tline; /* mostly copied from C_entries */
3843 int save_lineno, save_len;
3844 char c, *cp, *namebuf;
3846 bool /* each of these flags is TRUE iff: */
3847 incomment, /* point is inside a comment */
3848 inquote, /* point is inside '..' string */
3849 get_tagname, /* point is after PROCEDURE/FUNCTION
3850 keyword, so next item = potential tag */
3851 found_tag, /* point is after a potential tag */
3852 inparms, /* point is within parameter-list */
3853 verify_tag; /* point has passed the parm-list, so the
3854 next token will determine whether this
3855 is a FORWARD/EXTERN to be ignored, or
3856 whether it is a real tag */
3858 save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3859 namebuf = NULL; /* keep compiler quiet */
3866 incomment = inquote = FALSE;
3867 found_tag = FALSE; /* have a proc name; check if extern */
3868 get_tagname = FALSE; /* have found "procedure" keyword */
3869 inparms = FALSE; /* found '(' after "proc" */
3870 verify_tag = FALSE; /* check if "extern" is ahead */
3872 while (!feof(inf)) { /* long main loop to get next char */
3874 if (c == '\0') { /* if end of line */
3876 linecharno = charno;
3877 charno += readline(&lb, inf);
3881 if (!((found_tag && verify_tag)
3883 c = *dbp++; /* only if don't need *dbp pointing
3884 to the beginning of the name of
3885 the procedure or function */
3888 if (c == '}') /* within { } comments */
3890 else if (c == '*' && *dbp == ')') { /* within (* *) comments */
3895 } else if (inquote) {
3902 inquote = TRUE; /* found first quote */
3904 case '{': /* found open { comment */
3908 if (*dbp == '*') { /* found open (* comment */
3911 } else if (found_tag) /* found '(' after tag, i.e., parm-list */
3914 case ')': /* end of parms list */
3919 if (found_tag && !inparms) { /* end of proc or fn stmt */
3927 if (found_tag && verify_tag && (*dbp != ' ')) {
3928 /* check if this is an "extern" declaration */
3931 if (lowcase(*dbp == 'e')) {
3932 if (tail("extern")) { /* superfluous, really! */
3936 } else if (lowcase(*dbp) == 'f') {
3937 if (tail("forward")) { /* check for forward reference */
3942 if (found_tag && verify_tag) { /* not external proc, so make tag */
3945 pfnote(namebuf, TRUE,
3946 tline.buffer, save_len, save_lineno,
3951 if (get_tagname) { /* grab name of proc or fn */
3955 /* save all values for later tagging */
3956 grow_linebuffer(&tline, lb.len + 1);
3957 xstrncpy(tline.buffer, lb.buffer, lb.len + 1);
3958 save_lineno = lineno;
3959 save_lcno = linecharno;
3961 /* grab block name */
3962 for (cp = dbp + 1; *cp != '\0' && !endtoken(*cp); cp++)
3964 namebuf = (CTAGS) ? savenstr(dbp, cp - dbp) : NULL;
3965 dbp = cp; /* set dbp to e-o-token */
3966 save_len = dbp - lb.buffer + 1;
3967 get_tagname = FALSE;
3971 /* and proceed to check for "extern" */
3972 } else if (!incomment && !inquote && !found_tag) {
3973 /* check for proc/fn keywords */
3974 switch (lowcase(c)) {
3976 if (tail("rocedure")) /* c = 'p', dbp has advanced */
3980 if (tail("unction"))
3987 } /* while not eof */
3993 * lisp tag functions
3994 * look for (def or (DEF, quote or QUOTE
3996 int L_isdef PP((char *strp));
3998 register char *strp;
4000 return ((strp[1] == 'd' || strp[1] == 'D')
4001 && (strp[2] == 'e' || strp[2] == 'E')
4002 && (strp[3] == 'f' || strp[3] == 'F'));
4004 int L_isquote PP((char *strp));
4006 register char *strp;
4008 return ((*++strp == 'q' || *strp == 'Q')
4009 && (*++strp == 'u' || *strp == 'U')
4010 && (*++strp == 'o' || *strp == 'O')
4011 && (*++strp == 't' || *strp == 'T')
4012 && (*++strp == 'e' || *strp == 'E')
4013 && isspace(*++strp));
4016 void L_getit PP((void));
4021 if (*dbp == '\'') /* Skip prefix quote */
4023 else if (*dbp == '(') {
4025 dbp += 7; /* Skip "(quote " */
4027 dbp += 1; /* Skip "(" before name in (defstruct (foo)) */
4028 dbp = skip_spaces(dbp);
4031 for (cp = dbp /*+1 */ ;
4032 *cp != '\0' && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
4037 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
4038 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4041 void Lisp_functions(inf)
4044 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
4045 if (dbp[0] == '(') {
4047 dbp = skip_non_spaces(dbp);
4048 dbp = skip_spaces(dbp);
4051 /* Check for (foo::defmumble name-defined ... */
4054 while (*dbp != '\0' && !isspace(*dbp)
4055 && *dbp != ':' && *dbp != '('
4060 while (*dbp == ':');
4062 if (L_isdef(dbp - 1)) {
4063 dbp = skip_non_spaces(dbp);
4064 dbp = skip_spaces(dbp);
4074 * Postscript tag functions
4075 * Just look for lines where the first character is '/'
4076 * Richard Mlynarik <mly@adoc.xerox.com>
4078 void Postscript_functions(inf)
4081 register char *bp, *ep;
4083 LOOP_ON_INPUT_LINES(inf, lb, bp) {
4086 *ep != '\0' && *ep != ' ' && *ep != '{'; ep++)
4088 pfnote((CTAGS) ? savenstr(bp, ep - bp) : NULL, TRUE,
4089 lb.buffer, ep - lb.buffer + 1, lineno,
4096 * Scheme tag functions
4097 * look for (def... xyzzy
4098 * look for (def... (xyzzy
4099 * look for (def ... ((...(xyzzy ....
4100 * look for (set! xyzzy
4103 void get_scheme PP((void));
4105 void Scheme_functions(inf)
4108 LOOP_ON_INPUT_LINES(inf, lb, dbp) {
4109 if (dbp[0] == '(' && (dbp[1] == 'D' || dbp[1] == 'd')
4110 && (dbp[2] == 'E' || dbp[2] == 'e')
4111 && (dbp[3] == 'F' || dbp[3] == 'f')) {
4112 dbp = skip_non_spaces(dbp);
4113 /* Skip over open parens and white space */
4114 while (isspace(*dbp) || *dbp == '(')
4118 if (dbp[0] == '(' && (dbp[1] == 'S' || dbp[1] == 's')
4119 && (dbp[2] == 'E' || dbp[2] == 'e')
4120 && (dbp[3] == 'T' || dbp[3] == 't')
4121 && (dbp[4] == '!' || dbp[4] == '!')
4122 && (isspace(dbp[5]))) {
4123 dbp = skip_non_spaces(dbp);
4124 dbp = skip_spaces(dbp);
4136 /* Go till you get to white space or a syntactic break */
4138 *cp != '\0' && *cp != '(' && *cp != ')' && !isspace(*cp); cp++)
4140 pfnote((CTAGS) ? savenstr(dbp, cp - dbp) : NULL, TRUE,
4141 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4144 /* Find tags in TeX and LaTeX input files. */
4146 /* TEX_toktab is a table of TeX control sequences that define tags.
4147 Each TEX_tabent records one such control sequence.
4148 CONVERT THIS TO USE THE Stab TYPE!! */
4154 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
4156 /* Default set of control sequences to put into TEX_toktab.
4157 The value of environment var TEXTAGS is prepended to this. */
4159 char *TEX_defenv = "\
4160 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4161 :part:appendix:entry:index";
4163 void TEX_mode PP((FILE * inf));
4164 struct TEX_tabent *TEX_decode_env PP((char *evarname, char *defenv));
4165 int TEX_Token PP((char *cp));
4167 char TEX_esc = '\\';
4168 char TEX_opgrp = '{';
4169 char TEX_clgrp = '}';
4172 * TeX/LaTeX scanning loop.
4174 void TeX_functions(inf)
4180 /* Select either \ or ! as escape character. */
4183 /* Initialize token table once from environment. */
4185 TEX_toktab = TEX_decode_env("TEXTAGS", TEX_defenv);
4187 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4189 /* Look at each esc in line. */
4190 while ((cp = etags_strchr(cp, TEX_esc)) != NULL) {
4193 linecharno += cp - lasthit;
4195 i = TEX_Token(lasthit);
4197 /* We seem to include the TeX command in the tag name.
4199 for (p = lasthit + TEX_toktab[i].len;
4200 *p != '\0' && *p != TEX_clgrp;
4203 pfnote( /*savenstr (lasthit, p-lasthit) */
4205 lb.buffer, lb.len, lineno, linecharno);
4206 break; /* We only tag a line once */
4212 #define TEX_LESC '\\'
4213 #define TEX_SESC '!'
4216 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4217 chars accordingly. */
4223 while ((c = getc(inf)) != EOF) {
4224 /* Skip to next line if we hit the TeX comment char. */
4228 else if (c == TEX_LESC || c == TEX_SESC)
4232 if (c == TEX_LESC) {
4244 /* Read environment and prepend it to the default string.
4245 Build token table. */
4246 struct TEX_tabent *TEX_decode_env(evarname, defenv)
4250 register char *env, *p;
4252 struct TEX_tabent *tab;
4255 /* Append default string to environment. */
4256 env = getenv(evarname);
4261 env = concat(oldenv, defenv, "");
4265 /* Allocate a token table */
4266 for (size = 1, p = env; p;)
4267 if ((p = etags_strchr(p, ':')) && *++p != '\0')
4269 /* Add 1 to leave room for null terminator. */
4270 tab = xnew(size + 1, struct TEX_tabent);
4272 /* Unpack environment string into token table. Be careful about */
4273 /* zero-length strings (leading ':', "::" and trailing ':') */
4274 for (i = 0; *env;) {
4275 p = etags_strchr(env, ':');
4276 if (!p) /* End of environment string. */
4277 p = env + strlen(env);
4278 if (p - env > 0) { /* Only non-zero strings. */
4279 tab[i].name = savenstr(env, p - env);
4280 tab[i].len = strlen(tab[i].name);
4286 tab[i].name = NULL; /* Mark end of table. */
4294 /* If the text at CP matches one of the tag-defining TeX command names,
4295 return the pointer to the first occurrence of that command in TEX_toktab.
4296 Otherwise return -1.
4297 Keep the capital `T' in `token' for dumb truncating compilers
4298 (this distinguishes it from `TEX_toktab' */
4304 for (i = 0; TEX_toktab[i].len > 0; i++)
4305 if (strneq(TEX_toktab[i].name, cp, TEX_toktab[i].len))
4311 * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4313 * Assumes that the predicate starts at column 0.
4314 * Only the first clause of a predicate is added.
4316 int prolog_pred PP((char *s, char *last));
4317 void prolog_skip_comment PP((linebuffer * plb, FILE * inf));
4318 int prolog_atom PP((char *s, int pos));
4320 void Prolog_functions(inf)
4331 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4332 if (cp[0] == '\0') /* Empty line */
4334 else if (isspace(cp[0])) /* Not a predicate */
4336 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
4337 prolog_skip_comment(&lb, inf);
4338 else if ((len = prolog_pred(cp, last)) > 0) {
4339 /* Predicate. Store the function name so that we only
4340 generate a tag for the first clause. */
4342 last = xnew(len + 1, char);
4343 else if (len + 1 > allocated)
4344 last = xrnew(last, len + 1, char);
4345 allocated = len + 1;
4346 xstrncpy(last, cp, allocated);
4352 void prolog_skip_comment(plb, inf)
4359 for (cp = plb->buffer; *cp != '\0'; cp++)
4360 if (cp[0] == '*' && cp[1] == '/')
4363 linecharno += readline(plb, inf);
4369 * A predicate definition is added if it matches:
4370 * <beginning of line><Prolog Atom><whitespace>(
4372 * It is added to the tags database if it doesn't match the
4373 * name of the previous clause header.
4375 * Return the size of the name of the predicate, or 0 if no header
4378 int prolog_pred(s, last)
4380 char *last; /* Name of last clause. */
4385 pos = prolog_atom(s, 0);
4390 pos = skip_spaces(s + pos) - s;
4392 if ((s[pos] == '(') || (s[pos] == '.')) {
4396 /* Save only the first clause. */
4397 if (last == NULL || len != (int)strlen(last)
4398 || !strneq(s, last, len)) {
4399 pfnote((CTAGS) ? savenstr(s, len) : NULL, TRUE,
4400 s, pos, lineno, linecharno);
4408 * Consume a Prolog atom.
4409 * Return the number of bytes consumed, or -1 if there was an error.
4411 * A prolog atom, in this context, could be one of:
4412 * - An alphanumeric sequence, starting with a lower case letter.
4413 * - A quoted arbitrary string. Single quotes can escape themselves.
4414 * Backslash quotes everything.
4416 int prolog_atom(s, pos)
4424 if (islower(s[pos]) || (s[pos] == '_')) {
4425 /* The atom is unquoted. */
4427 while (isalnum(s[pos]) || (s[pos] == '_')) {
4430 return pos - origpos;
4431 } else if (s[pos] == '\'') {
4435 if (s[pos] == '\'') {
4439 pos++; /* A double quote */
4440 } else if (s[pos] == '\0')
4441 /* Multiline quoted atoms are ignored. */
4443 else if (s[pos] == '\\') {
4444 if (s[pos + 1] == '\0')
4450 return pos - origpos;
4456 * Support for Erlang -- Anders Lindgren, Feb 1996.
4458 * Generates tags for functions, defines, and records.
4460 * Assumes that Erlang functions start at column 0.
4462 int erlang_func PP((char *s, char *last));
4463 void erlang_attribute PP((char *s));
4464 int erlang_atom PP((char *s, int pos));
4466 void Erlang_functions(inf)
4477 LOOP_ON_INPUT_LINES(inf, lb, cp) {
4478 if (cp[0] == '\0') /* Empty line */
4480 else if (isspace(cp[0])) /* Not function nor attribute */
4482 else if (cp[0] == '%') /* comment */
4484 else if (cp[0] == '"') /* Sometimes, strings start in column one */
4486 else if (cp[0] == '-') { /* attribute, e.g. "-define" */
4487 erlang_attribute(cp);
4490 } else if ((len = erlang_func(cp, last)) > 0) {
4492 * Function. Store the function name so that we only
4493 * generates a tag for the first clause.
4496 last = xnew(len + 1, char);
4497 else if (len + 1 > allocated)
4498 last = xrnew(last, len + 1, char);
4499 allocated = len + 1;
4500 xstrncpy(last, cp, allocated);
4507 * A function definition is added if it matches:
4508 * <beginning of line><Erlang Atom><whitespace>(
4510 * It is added to the tags database if it doesn't match the
4511 * name of the previous clause header.
4513 * Return the size of the name of the function, or 0 if no function
4516 int erlang_func(s, last)
4518 char *last; /* Name of last clause. */
4523 pos = erlang_atom(s, 0);
4528 pos = skip_spaces(s + pos) - s;
4530 /* Save only the first clause. */
4531 if (s[pos++] == '(' && (last == NULL || len != (int)strlen(last)
4532 || !strneq(s, last, len))) {
4533 pfnote((CTAGS) ? savenstr(s, len) : NULL, TRUE,
4534 s, pos, lineno, linecharno);
4542 * Handle attributes. Currently, tags are generated for defines
4545 * They are on the form:
4546 * -define(foo, bar).
4547 * -define(Foo(M, N), M+N).
4548 * -record(graph, {vtab = notable, cyclic = true}).
4550 void erlang_attribute(s)
4556 if (strneq(s, "-define", 7) || strneq(s, "-record", 7)) {
4557 pos = skip_spaces(s + 7) - s;
4558 if (s[pos++] == '(') {
4559 pos = skip_spaces(s + pos) - s;
4560 len = erlang_atom(s, pos);
4562 pfnote((CTAGS) ? savenstr(&s[pos], len) : NULL,
4563 TRUE, s, pos + len, lineno, linecharno);
4570 * Consume an Erlang atom (or variable).
4571 * Return the number of bytes consumed, or -1 if there was an error.
4573 int erlang_atom(s, pos)
4581 if (isalpha(s[pos]) || s[pos] == '_') {
4582 /* The atom is unquoted. */
4584 while (isalnum(s[pos]) || s[pos] == '_')
4586 return pos - origpos;
4587 } else if (s[pos] == '\'') {
4591 if (s[pos] == '\'') {
4594 } else if (s[pos] == '\0')
4595 /* Multiline quoted atoms are ignored. */
4597 else if (s[pos] == '\\') {
4598 if (s[pos + 1] == '\0')
4604 return pos - origpos;
4609 #ifdef ETAGS_REGEXPS
4611 /* Take a string like "/blah/" and turn it into "blah", making sure
4612 that the first and last characters are the same, and handling
4613 quoted separator characters. Actually, stops on the occurrence of
4614 an unquoted separator. Also turns "\t" into a Tab character.
4615 Returns pointer to terminating separator. Works in place. Null
4616 terminates name string. */
4617 char *scan_separators PP((char *name));
4618 char *scan_separators(name)
4622 char *copyto = name;
4623 bool quoted = FALSE;
4625 for (++name; *name != '\0'; ++name) {
4629 else if (*name == sep)
4632 /* Something else is quoted, so preserve the quote. */
4637 } else if (*name == '\\')
4639 else if (*name == sep)
4645 /* Terminate copied string. */
4650 /* Look at the argument of --regex or --no-regex and do the right
4651 thing. Same for each line of a regexp file. */
4652 void analyse_regex(regex_arg)
4655 if (regex_arg == NULL) {
4656 free_patterns(); /* --no-regex: remove existing regexps */
4659 /* A real --regexp option or a line in a regexp file. */
4660 switch (regex_arg[0]) {
4661 /* Comments in regexp file or null arg to --regex. */
4667 /* Read a regex file. This is recursive and may result in a
4668 loop, which will stop when the file descriptors are exhausted. */
4672 linebuffer regexbuf;
4673 char *regexfile = regex_arg + 1;
4675 /* regexfile is a file containing regexps, one per line. */
4676 regexfp = fopen(regexfile, "r");
4677 if (regexfp == NULL) {
4681 initbuffer(®exbuf);
4682 while (readline_internal(®exbuf, regexfp) > 0)
4683 analyse_regex(regexbuf.buffer);
4684 free(regexbuf.buffer);
4689 /* Regexp to be used for a specific language only. */
4693 char *lang_name = regex_arg + 1;
4696 for (cp = lang_name; *cp != '}'; cp++)
4699 ("unterminated language name in regex: %s",
4704 lang = get_language_from_name(lang_name);
4707 add_regex(cp + 1, lang);
4711 /* Regexp to be used for any language. */
4713 add_regex(regex_arg, NULL);
4718 /* Turn a name, which is an ed-style (but Emacs syntax) regular
4719 expression, into a real regular expression by compiling it. */
4720 void add_regex(regexp_pattern, lang)
4721 char *regexp_pattern;
4726 struct re_pattern_buffer *patbuf;
4729 if (regexp_pattern[strlen(regexp_pattern) - 1] != regexp_pattern[0]) {
4730 error("%s: unterminated regexp", regexp_pattern);
4733 name = scan_separators(regexp_pattern);
4734 if (regexp_pattern[0] == '\0') {
4735 error("null regexp", (char *)NULL);
4738 (void)scan_separators(name);
4740 patbuf = xnew(1, struct re_pattern_buffer);
4741 patbuf->translate = NULL;
4742 patbuf->fastmap = NULL;
4743 patbuf->buffer = NULL;
4744 patbuf->allocated = 0;
4747 re_compile_pattern(regexp_pattern, strlen(regexp_pattern), patbuf);
4749 error("%s while compiling pattern", err);
4754 p_head = xnew(1, pattern);
4755 p_head->regex = savestr(regexp_pattern);
4756 p_head->p_next = pp;
4757 p_head->language = lang;
4758 p_head->pattern = patbuf;
4759 p_head->name_pattern = savestr(name);
4760 p_head->error_signaled = FALSE;
4764 * Do the substitutions indicated by the regular expression and
4767 char *substitute PP((char *in, char *out, struct re_registers * regs));
4768 char *substitute(in, out, regs)
4770 struct re_registers *regs;
4773 int size, dig, diglen;
4778 /* Pass 1: figure out how much to allocate by finding all \N strings. */
4779 if (out[size - 1] == '\\')
4780 fatal("pattern error in \"%s\"", out);
4781 for (t = etags_strchr(out, '\\');
4782 t != NULL; t = etags_strchr(t + 2, '\\'))
4783 if (isdigit(t[1])) {
4785 diglen = regs->end[dig] - regs->start[dig];
4790 /* Allocate space and do the substitutions. */
4791 size_t avail = size + 1;
4792 result = xnew(avail, char);
4794 for (t = result; *out != '\0'; out++)
4795 if (*out == '\\' && isdigit(*++out)) {
4796 /* Using "dig2" satisfies my debugger. Bleah. */
4798 diglen = regs->end[dig] - regs->start[dig];
4799 xstrncpy(t, in + regs->start[dig], avail);
4808 if (DEBUG && (t > result + size || t - result != strlen(result)))
4814 /* Deallocate all patterns. */
4815 void free_patterns()
4818 while (p_head != NULL) {
4819 pp = p_head->p_next;
4820 free(p_head->regex);
4821 free(p_head->name_pattern);
4828 #endif /* ETAGS_REGEXPS */
4829 /* Initialize a linebuffer for use */
4830 void initbuffer(lbp)
4834 lbp->buffer = xnew(200, char);
4838 * Read a line of text from `stream' into `lbp', excluding the
4839 * newline or CR-NL, if any. Return the number of characters read from
4840 * `stream', which is the length of the line including the newline.
4842 * On DOS or Windows we do not count the CR character, if any, before the
4843 * NL, in the returned length; this mirrors the behavior of emacs on those
4844 * platforms (for text files, it translates CR-NL to NL as it reads in the
4847 long readline_internal(lbp, stream)
4849 register FILE *stream;
4851 char *buffer = lbp->buffer;
4852 register char *p = lbp->buffer;
4853 register char *pend;
4856 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
4859 register int c = getc(stream);
4861 /* We're at the end of linebuffer: expand it. */
4863 buffer = xrnew(buffer, lbp->size, char);
4864 p += buffer - lbp->buffer;
4865 pend = buffer + lbp->size;
4866 lbp->buffer = buffer;
4874 if (p > buffer && p[-1] == '\r') {
4885 lbp->len = p - buffer;
4887 return lbp->len + chars_deleted;
4891 * Like readline_internal, above, but in addition try to match the
4892 * input line against relevant regular expressions.
4894 long readline(lbp, stream)
4898 /* Read new line. */
4899 long result = readline_internal(lbp, stream);
4900 #ifdef ETAGS_REGEXPS
4904 /* Match against relevant patterns. */
4906 for (pp = p_head; pp != NULL; pp = pp->p_next) {
4907 /* Only use generic regexps or those for the current language. */
4908 if (pp->language != NULL && pp->language != curlang)
4912 re_match(pp->pattern, lbp->buffer, lbp->len, 0,
4917 if (!pp->error_signaled) {
4918 error("error while matching \"%s\"",
4920 pp->error_signaled = TRUE;
4927 /* Match occurred. Construct a tag. */
4928 if (pp->name_pattern[0] != '\0') {
4929 /* Make a named tag. */
4930 char *name = substitute(lbp->buffer,
4935 pfnote(name, TRUE, lbp->buffer,
4939 /* Make an unnamed tag. */
4940 pfnote((char *)NULL, TRUE,
4941 lbp->buffer, match, lineno,
4947 #endif /* ETAGS_REGEXPS */
4953 * Return a pointer to a space of size strlen(cp)+1 allocated
4954 * with xnew where the string CP has been copied.
4959 return savenstr(cp, strlen(cp));
4963 * Return a pointer to a space of size LEN+1 allocated with xnew where
4964 * the string CP has been copied for at most the first LEN characters.
4966 char *savenstr(cp, len)
4972 dp = xnew(len + 1, char);
4973 xstrncpy(dp, cp, len+1);
4978 /* Skip spaces, return new pointer. */
4979 char *skip_spaces(cp)
4982 while (isspace(*cp)) /* isspace('\0')==FALSE */
4987 /* Skip non spaces, return new pointer. */
4988 char *skip_non_spaces(cp)
4991 while (!iswhite(*cp)) /* iswhite('\0')==TRUE */
4996 /* Print error message and exit. */
5011 void suggest_asking_for_help()
5013 fprintf(stderr, "\tTry `%s %s' for a complete list of options.\n",
5024 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
5026 const char *s1, *s2;
5028 fprintf(stderr, "%s: ", progname);
5029 fprintf(stderr, s1, s2);
5030 fprintf(stderr, "\n");
5033 /* Return a newly-allocated string whose contents
5034 concatenate those of s1, s2, s3. */
5035 char *concat(s1, s2, s3)
5038 int len1 = strlen(s1), len2 = strlen(s2), len3 = strlen(s3);
5039 char *result = xnew(len1 + len2 + len3 + 1, char);
5042 strcpy(result + len1, s2);
5043 strcpy(result + len1 + len2, s3);
5044 result[len1 + len2 + len3] = '\0';
5049 /* Does the same work as the system V getcwd, but does not need to
5050 guess the buffer size in advance. */
5051 char *etags_getcwd()
5055 char *path = xnew(bufsize, char);
5057 while (getcwd(path, bufsize) == NULL) {
5058 if (errno != ERANGE)
5062 path = xnew(bufsize, char);
5065 canonicalize_filename(path);
5068 #else /* not HAVE_GETCWD */
5073 pipe = (FILE *) popen("pwd 2>/dev/null", "r");
5074 if (pipe == NULL || readline_internal(&path, pipe) == 0)
5079 #endif /* not HAVE_GETCWD */
5082 /* Return a newly allocated string containing the file name of FILE
5083 relative to the absolute directory DIR (which should end with a slash). */
5084 char *relative_filename(file, dir)
5087 char *fp, *dp, *afn, *res;
5091 /* Find the common root of file and dir (with a trailing slash). */
5092 afn = absolute_filename(file, cwd);
5095 while (*fp++ == *dp++)
5097 fp--, dp--; /* back to the first differing char */
5098 do /* look at the equal chars until '/' */
5101 fp ++; /* Advance past the '/' */
5103 /* Build a sequence of "../" strings for the resulting relative file name. */
5105 while ((dp = etags_strchr(dp + 1, '/')) != NULL)
5107 res_left = 3 * i + strlen(fp);
5108 res = xnew( res_left + 1, char);
5110 for ( ; i-- > 0 ; res_left -= 4 )
5111 strncat(res, "../", res_left );
5113 /* Add the file name relative to the common root of file and dir. */
5114 strncat(res, fp, res_left);
5120 /* Return a newly allocated string containing the absolute file name
5121 of FILE given DIR (which should end with a slash). */
5122 char *absolute_filename(file, dir)
5125 char *slashp, *cp, *res;
5127 if (filename_is_absolute(file))
5128 res = savestr(file);
5130 res = concat(dir, file, "");
5132 /* Delete the "/dirname/.." and "/." substrings. */
5133 slashp = etags_strchr(res, '/');
5134 while (slashp != NULL && slashp[0] != '\0') {
5135 if (slashp[1] == '.') {
5136 if (slashp[2] == '.'
5137 && (slashp[3] == '/' || slashp[3] == '\0')) {
5141 while (cp >= res && !filename_is_absolute(cp));
5143 cp = slashp; /* the absolute name begins with "/.." */
5144 strcpy(cp, slashp + 3);
5147 } else if (slashp[2] == '/' || slashp[2] == '\0') {
5148 strcpy(slashp, slashp + 2);
5153 slashp = etags_strchr(slashp + 1, '/');
5157 return savestr("/");
5162 /* Return a newly allocated string containing the absolute
5163 file name of dir where FILE resides given DIR (which should
5164 end with a slash). */
5165 char *absolute_dirname(file, dir)
5171 canonicalize_filename(file);
5172 slashp = etags_strrchr(file, '/');
5174 return savestr(dir);
5177 res = absolute_filename(file, dir);
5183 /* Whether the argument string is an absolute file name. The argument
5184 string must have been canonicalized with canonicalize_filename. */
5185 bool filename_is_absolute(fn)
5188 return (fn[0] == '/');
5191 /* Translate backslashes into slashes. Works in place. */
5192 void canonicalize_filename(fn)
5198 /* Increase the size of a linebuffer. */
5199 void grow_linebuffer(lbp, toksize)
5203 while (lbp->size < toksize)
5205 lbp->buffer = xrnew(lbp->buffer, lbp->size, char);
5208 /* Like malloc but get fatal error if memory is exhausted. */
5212 long *result = (long *)malloc(size);
5214 fatal("virtual memory exhausted", (char *)NULL);
5218 long *xrealloc(ptr, size)
5222 long *result = (long *)realloc(ptr, size);
5224 fatal("virtual memory exhausted", (char *)NULL);