From: Francesco Potortì Date: Thu, 7 Dec 1995 09:10:54 +0000 (+0000) Subject: * etags.c (Cplusplus_suffixes): Add .M suffix for Objective C++. X-Git-Tag: emacs-19.34~2164 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=d8913c1c1c382de36f85ded59aab03b637a08023;p=emacs.git * etags.c (Cplusplus_suffixes): Add .M suffix for Objective C++. (gperf): Added keywords for Objective C and GNU macros. (sym_type): Added values to account for Objective C and GNU macros. (begtk): The '@' character can start a token. (objdef, methodlen, objtag): New variables for Objective C. (consider_token, C_entries): Added code for Objective C. (plain_C_suffixes): Add .m and .lm for Objective C. (Yacc_suffixes): Add .ym for Objective yacc. (GROW_LINEBUFFER): New macro. (consider_token, C_entries, Pascal_functions): Use the new macro. (consider_token): Take one more argument. Caller changed. (consider_token): Use the hashing function to spot GNU macros. (C_entries): Consider // as a comment start even in plain C for the sake of Objective C parsing. (pfnote): Don't make a tag for ctags if there is no name. (getit, Asm_labels, Perl_functions, Pascal_functions, L_getit, get_scheme, prolog_getit): Name the tag in ctags mode. (pfnote): Truncate ctags lines to 50 chars, like it worked once. (Perl_interpreters): Accept "@PERL@" as an interpreter. (suggest_asking_for_help): New function. (main, get_language_from_name): Use suggest_asking_for_help. (main): Let get_language_from_name make language existence check. (streq, strneq): Check the arguments #if DEBUG. --- diff --git a/lib-src/etags.c b/lib-src/etags.c index 61218c90f1d..7a7c30b157d 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -25,17 +25,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ * Gnu Emacs TAGS format and modifications by RMS? * Sam Kendall added C++. * Francesco Potorti` reorganised C and C++ based on work by Joe Wells. -#ifdef ETAGS_REGEXPS * Regexp tags by Tom Tromey. -#endif * * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. */ -char pot_etags_version[] = "@(#) pot revision number is 11.45"; +char pot_etags_version[] = "@(#) pot revision number is 11.53"; #define TRUE 1 #define FALSE 0 + #ifndef DEBUG # define DEBUG FALSE #endif @@ -102,8 +101,8 @@ extern int errno; #define C_STAR 0x00003 /* C* */ #define YACC 0x10000 /* yacc file */ -#define streq(s,t) (strcmp (s, t) == 0) -#define strneq(s,t,n) (strncmp (s, t, n) == 0) +#define streq(s,t) ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strcmp(s,t)) +#define strneq(s,t,n) ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strncmp(s,t,n)) #define lowcase(c) tolower ((unsigned char)c) @@ -129,7 +128,7 @@ extern int errno; typedef int logical; typedef struct nd_st -{ /* sorting structure */ +{ /* sorting structure */ char *name; /* function or type name */ char *file; /* file name */ logical is_func; /* use pattern or line no */ @@ -194,6 +193,7 @@ void add_regex (); #endif void add_node (); void error (); +void suggest_asking_for_help (); void fatal (), pfatal (); void find_entries (); void free_tree (); @@ -228,6 +228,9 @@ NODE *head; /* the head of the binary tree of tags */ * `readline' reads a line from a stream into a linebuffer and works * regardless of the length of the line. */ +#define GROW_LINEBUFFER(buf,toksize) \ +while (buf.size < toksize) \ + buf.buffer = (char *) xrealloc (buf.buffer, buf.size *= 2) struct linebuffer { long size; @@ -235,7 +238,7 @@ struct linebuffer }; struct linebuffer lb; /* the current line */ -struct linebuffer token_name; /* used by C_entries as temporary area */ +struct linebuffer token_name; /* used by C_entries as a temporary area */ struct { long linepos; @@ -245,12 +248,14 @@ struct /* boolean "functions" (see init) */ logical _wht[0177], _etk[0177], _itk[0177], _btk[0177]; char - *white = " \f\t\n\013", /* white chars */ - *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */ - /* token starting chars */ - *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~", - /* valid in-token chars */ - *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789"; + /* white chars */ + *white = " \f\t\n\013", + /* token ending chars */ + *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", + /* token starting chars */ + *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@", + /* valid in-token chars */ + *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789"; logical append_to_tagfile; /* -a: append to tags */ /* The following three default to TRUE for etags, but to FALSE for ctags. */ @@ -334,52 +339,45 @@ char *Asm_suffixes [] = { "a", /* Unix assembler */ char *default_C_suffixes [] = { "c", "h", NULL }; -/* C++ file */ +/* .M is for Objective C++ files. */ char *Cplusplus_suffixes [] = - { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx", NULL }; + { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx", "M", NULL}; -/* C* file */ char *Cstar_suffixes [] = { "cs", "hs", NULL }; -/* Fortran */ char *Fortran_suffixes [] = { "F", "f", "f90", "for", NULL }; -/* Lisp source code */ char *Lisp_suffixes [] = { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL }; -/* Pascal file */ char *Pascal_suffixes [] = { "p", "pas", NULL }; -/* Perl file */ char *Perl_suffixes [] = { "pl", "pm", NULL }; char *Perl_interpreters [] = - { "perl", NULL }; + { "perl", "@PERL@", NULL }; -/* Pro*C file. */ char *plain_C_suffixes [] = - { "pc", NULL }; + { "pc", /* Pro*C file */ + "m", /* Objective C file */ + "lm", /* Objective lex file */ + NULL }; -/* Prolog source code */ char *Prolog_suffixes [] = { "prolog", NULL }; -/* Scheme source code */ -/* FIXME Can't do the `SCM' or `scm' prefix with a version number */ +/* Can't do the `SCM' or `scm' prefix with a version number. */ char *Scheme_suffixes [] = { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "t", NULL }; -/* TeX/LaTeX source code */ char *TeX_suffixes [] = - { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL }; + { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL }; -/* Yacc file */ char *Yacc_suffixes [] = - { "y", NULL }; + { "y", "ym", NULL }; /* .ym is Objective yacc file */ /* Table of language names and corresponding functions, file suffixes and interpreter names. @@ -395,22 +393,22 @@ struct lang_entry struct lang_entry lang_names [] = { - { "asm", Asm_labels, Asm_suffixes }, - { "c", default_C_entries, default_C_suffixes }, - { "c++", Cplusplus_entries, Cplusplus_suffixes }, - { "c*", Cstar_entries, Cstar_suffixes }, - { "fortran", Fortran_functions, Fortran_suffixes }, - { "lisp", Lisp_functions, Lisp_suffixes }, - { "pascal", Pascal_functions, Pascal_suffixes }, - { "perl", Perl_functions, Perl_suffixes, Perl_interpreters }, - { "proc", plain_C_entries, plain_C_suffixes }, - { "prolog", Prolog_functions, Prolog_suffixes }, - { "scheme" , Scheme_functions, Scheme_suffixes }, - { "tex", TeX_functions, TeX_suffixes }, - { "yacc", Yacc_entries, Yacc_suffixes }, - { "auto", NULL }, /* default guessing scheme */ - { "none", just_read_file }, /* regexp matching only */ - { NULL, NULL } /* end of list */ + { "asm", Asm_labels, Asm_suffixes, NULL }, + { "c", default_C_entries, default_C_suffixes, NULL }, + { "c++", Cplusplus_entries, Cplusplus_suffixes, NULL }, + { "c*", Cstar_entries, Cstar_suffixes, NULL }, + { "fortran", Fortran_functions, Fortran_suffixes, NULL }, + { "lisp", Lisp_functions, Lisp_suffixes, NULL }, + { "pascal", Pascal_functions, Pascal_suffixes, NULL }, + { "perl", Perl_functions, Perl_suffixes, Perl_interpreters }, + { "proc", plain_C_entries, plain_C_suffixes, NULL }, + { "prolog", Prolog_functions, Prolog_suffixes, NULL }, + { "scheme", Scheme_functions, Scheme_suffixes, NULL }, + { "tex", TeX_functions, TeX_suffixes, NULL }, + { "yacc", Yacc_entries, Yacc_suffixes, NULL }, + { "auto", NULL }, /* default guessing scheme */ + { "none", just_read_file }, /* regexp matching only */ + { NULL, NULL } /* end of list */ }; @@ -763,7 +761,7 @@ main (argc, argv) { fprintf (stderr, "%s: -%c option may only be given once.\n", progname, opt); - goto usage; + suggest_asking_for_help (); } tagfile = optarg; break; @@ -773,12 +771,6 @@ main (argc, argv) break; case 'l': argbuffer[current_arg].function = get_language_from_name (optarg); - if (argbuffer[current_arg].function == NULL) - { - fprintf (stderr, "%s: language \"%s\" not recognized.\n", - progname, optarg); - goto usage; - } argbuffer[current_arg].arg_type = at_language; ++current_arg; break; @@ -831,7 +823,7 @@ main (argc, argv) break; #endif /* CTAGS */ default: - goto usage; + suggest_asking_for_help (); } } @@ -846,11 +838,7 @@ main (argc, argv) if (nincluded_files == 0 && file_count == 0) { fprintf (stderr, "%s: No input files specified.\n", progname); - - usage: - fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n", - progname); - exit (BAD); + suggest_asking_for_help (); } if (tagfile == NULL) @@ -992,15 +980,22 @@ get_language_from_name (name) { struct lang_entry *lang; - if (name == NULL) - return NULL; - for (lang = lang_names; lang->name != NULL; lang++) - { - if (streq (name, lang->name)) - return lang->function; - } + if (name != NULL) + for (lang = lang_names; lang->name != NULL; lang++) + { + if (streq (name, lang->name)) + return lang->function; + } - return NULL; + fprintf (stderr, "%s: language \"%s\" not recognized.\n", + progname, optarg); + suggest_asking_for_help (); + + /* This point should never be reached. The function should either + return a function pointer or never return. Note that a NULL + pointer cannot be considered as an error, as it means that the + language has not been explicitely imposed by the user ("auto"). */ + return NULL; /* avoid warnings from compiler */ } @@ -1145,6 +1140,7 @@ find_entries (file, inf) NODE *old_last_node; extern NODE *last_node; + /* Memory leakage here: the memory block pointed by curfile is never released. The amount of memory leaked here is the sum of the lengths of the input file names. */ @@ -1222,14 +1218,19 @@ find_entries (file, inf) /* Record a tag. */ void pfnote (name, is_func, linestart, linelen, lno, cno) - char *name; /* tag name, if different from definition */ + char *name; /* tag name, or NULL if unnamed */ logical is_func; /* tag is a function */ char *linestart; /* start of the line where tag is */ int linelen; /* length of the line where tag is */ int lno; /* line number */ long cno; /* character number */ { - register NODE *np = xnew (1, NODE); + register NODE *np; + + if (CTAGS && name == NULL) + return; + + np = xnew (1, NODE); /* If ctags mode, change name "main" to M. */ if (CTAGS && !cxref_style && streq (name, "main")) @@ -1253,7 +1254,15 @@ pfnote (name, is_func, linestart, linelen, lno, cno) uncomment the +1 below. */ np->cno = cno /* + 1 */ ; np->left = np->right = NULL; - np->pat = savenstr (linestart, ((CTAGS && !cxref_style) ? 50 : linelen)); + if (CTAGS && !cxref_style) + { + if (strlen (linestart) < 50) + np->pat = concat (linestart, "$", ""); + else + np->pat = savenstr (linestart, 50); + } + else + np->pat = savenstr (linestart, linelen); add_node (np, &head); } @@ -1369,36 +1378,44 @@ put_entries (node) fprintf (tagf, "%s\177%d,%d\n", node->pat, node->lno, node->cno); } - else if (!cxref_style) + else { - fprintf (tagf, "%s\t%s\t", - node->name, node->file); - - if (node->is_func) - { /* a function */ - putc (searchar, tagf); - putc ('^', tagf); + if (node->name == NULL) + error ("internal error: NULL name in ctags mode.", 0); - for (sp = node->pat; *sp; sp++) - { - if (*sp == '\\' || *sp == searchar) - putc ('\\', tagf); - putc (*sp, tagf); - } - putc (searchar, tagf); + if (cxref_style) + { + if (vgrind_style) + fprintf (stdout, "%s %s %d\n", + node->name, node->file, (node->lno + 63) / 64); + else + fprintf (stdout, "%-16s %3d %-16s %s\n", + node->name, node->lno, node->file, node->pat); } else - { /* a typedef; text pattern inadequate */ - fprintf (tagf, "%d", node->lno); + { + fprintf (tagf, "%s\t%s\t", node->name, node->file); + + if (node->is_func) + { /* a function */ + putc (searchar, tagf); + putc ('^', tagf); + + for (sp = node->pat; *sp; sp++) + { + if (*sp == '\\' || *sp == searchar) + putc ('\\', tagf); + putc (*sp, tagf); + } + putc (searchar, tagf); + } + else + { /* a typedef; text pattern inadequate */ + fprintf (tagf, "%d", node->lno); + } + putc ('\n', tagf); } - putc ('\n', tagf); } - else if (vgrind_style) - fprintf (stdout, "%s %s %d\n", - node->name, node->file, (node->lno + 63) / 64); - else - fprintf (stdout, "%-16s %3d %-16s %s\n", - node->name, node->lno, node->file, node->pat); /* Output subentries that follow this one */ put_entries (node->right); @@ -1454,7 +1471,8 @@ total_size_of_entries (node) */ enum sym_type { - st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec + st_none, st_C_objprot, st_C_objimpl, st_C_objend, st_C_gnumacro, + st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec, }; /* Feed stuff between (but not including) %[ and %] lines to: @@ -1462,6 +1480,10 @@ enum sym_type %[ struct C_stab_entry { char *name; int c_ext; enum sym_type type; } %% +@interface, 0, st_C_objprot +@protocol, 0, st_C_objprot +@implementation,0, st_C_objimpl +@end, 0, st_C_objend class, C_PLPL, st_C_struct domain, C_STAR, st_C_struct union, 0, st_C_struct @@ -1483,6 +1505,15 @@ extern, 0, st_C_typespec static, 0, st_C_typespec const, 0, st_C_typespec volatile, 0, st_C_typespec +# DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach). +DEFUN, 0, st_C_gnumacro +SYSCALL, 0, st_C_gnumacro +ENTRY, 0, st_C_gnumacro +PSEUDO, 0, st_C_gnumacro +# These are defined inside C functions, so currently they are not met. +# EXFUN used in glibc, DEFVAR_* in emacs. +#EXFUN, 0, st_C_gnumacro +#DEFVAR_, 0, st_C_gnumacro %] and replace lines between %< and %> with its output. */ /*%<*/ @@ -1493,12 +1524,12 @@ and replace lines between %< and %> with its output. */ struct C_stab_entry { char *name; int c_ext; enum sym_type type; }; #define MIN_WORD_LENGTH 3 -#define MAX_WORD_LENGTH 8 -#define MIN_HASH_VALUE 10 -#define MAX_HASH_VALUE 62 +#define MAX_WORD_LENGTH 15 +#define MIN_HASH_VALUE 7 +#define MAX_HASH_VALUE 63 /* - 21 keywords - 53 is the maximum key range + 29 keywords + 57 is the maximum key range */ static int @@ -1508,19 +1539,19 @@ hash (str, len) { static unsigned char hash_table[] = { - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 2, 62, 7, - 6, 9, 15, 30, 62, 24, 62, 62, 1, 24, - 7, 27, 13, 62, 19, 26, 18, 27, 1, 62, - 62, 62, 62, 62, 62, 62, 62, 62, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 17, 63, 63, 63, 4, 14, + 4, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 8, 63, 63, 0, 23, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 28, 63, 28, + 10, 31, 27, 18, 63, 6, 63, 63, 26, 1, + 11, 2, 29, 63, 29, 16, 26, 13, 15, 63, + 63, 63, 63, 63, 63, 63, 63, 63, }; return len + hash_table[str[2]] + hash_table[str[0]]; } @@ -1533,43 +1564,47 @@ in_word_set (str, len) static struct C_stab_entry wordlist[] = { - {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, - {"",}, - {"volatile", 0, st_C_typespec}, - {"",}, - {"long", 0, st_C_typespec}, - {"char", 0, st_C_typespec}, - {"class", C_PLPL, st_C_struct}, - {"",}, {"",}, {"",}, {"",}, - {"const", 0, st_C_typespec}, - {"",}, {"",}, {"",}, {"",}, - {"auto", 0, st_C_typespec}, - {"",}, {"",}, - {"define", 0, st_C_define}, - {"",}, - {"void", 0, st_C_typespec}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"SYSCALL", 0, st_C_gnumacro}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"DEFUN", 0, st_C_gnumacro}, {"",}, {"",}, {"",}, - {"extern", 0, st_C_typespec}, - {"static", 0, st_C_typespec}, - {"",}, {"domain", C_STAR, st_C_struct}, - {"",}, - {"typedef", 0, st_C_typedef}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"short", 0, st_C_typespec}, + {"union", 0, st_C_struct}, + {"void", 0, st_C_typespec}, + {"",}, {"",}, + {"PSEUDO", 0, st_C_gnumacro}, {"double", 0, st_C_typespec}, - {"enum", 0, st_C_enum}, - {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, + {"@end", 0, st_C_objend}, + {"@implementation", 0, st_C_objimpl}, + {"float", 0, st_C_typespec}, {"int", 0, st_C_typespec}, {"",}, - {"float", 0, st_C_typespec}, + {"unsigned", 0, st_C_typespec}, + {"@interface", 0, st_C_objprot}, + {"",}, + {"signed", 0, st_C_typespec}, + {"long", 0, st_C_typespec}, + {"ENTRY", 0, st_C_gnumacro}, + {"define", 0, st_C_define}, + {"const", 0, st_C_typespec}, {"",}, {"",}, {"",}, + {"enum", 0, st_C_enum}, + {"volatile", 0, st_C_typespec}, + {"static", 0, st_C_typespec}, {"struct", 0, st_C_struct}, - {"",}, {"",}, {"",}, {"",}, - {"union", 0, st_C_struct}, - {"",}, - {"short", 0, st_C_typespec}, + {"",}, {"",}, {"",}, + {"@protocol", 0, st_C_objprot}, {"",}, {"",}, - {"unsigned", 0, st_C_typespec}, - {"signed", 0, st_C_typespec}, + {"auto", 0, st_C_typespec}, + {"",}, + {"char", 0, st_C_typespec}, + {"class", C_PLPL, st_C_struct}, + {"typedef", 0, st_C_typedef}, + {"extern", 0, st_C_typespec}, }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) @@ -1580,7 +1615,7 @@ in_word_set (str, len) { register char *s = wordlist[key].name; - if (*s == *str && strneq (str + 1, s + 1, len - 1)) + if (*s == *str && !strncmp (str + 1, s + 1, len - 1)) return &wordlist[key]; } } @@ -1605,7 +1640,7 @@ C_symtype(str, len, c_ext) * C functions are recognized using a simple finite automaton. * funcdef is its state variable. */ -typedef enum +enum { fnone, /* nothing seen */ ftagseen, /* function-like tag seen */ @@ -1613,23 +1648,21 @@ typedef enum finlist, /* in parameter list */ flistseen, /* after parameter list */ fignore /* before open brace */ -} FUNCST; -FUNCST funcdef; +} funcdef; /* * typedefs are recognized using a simple finite automaton. * typeddef is its state variable. */ -typedef enum +enum { tnone, /* nothing seen */ ttypedseen, /* typedef keyword seen */ tinbody, /* inside typedef body */ tend, /* just before typedef tag */ tignore /* junk after typedef tag */ -} TYPEDST; -TYPEDST typdef; +} typdef; /* @@ -1637,15 +1670,14 @@ TYPEDST typdef; * using another simple finite automaton. `structdef' is its state * variable. */ -typedef enum +enum { snone, /* nothing seen yet */ skeyseen, /* struct-like keyword seen */ stagseen, /* struct-like tag seen */ scolonseen, /* colon seen after struct-like tag */ sinbody /* in struct body: recognize member func defs*/ -} STRUCTST; -STRUCTST structdef; +} structdef; /* * When structdef is stagseen, scolonseen, or sinbody, structtag is the @@ -1655,17 +1687,40 @@ STRUCTST structdef; char *structtag = ""; enum sym_type structtype; +/* + * When objdef is different from onone, objtag is the name of the class. + */ +char *objtag = ""; + /* * Yet another little state machine to deal with preprocessor lines. */ -typedef enum +enum { dnone, /* nothing seen */ dsharpseen, /* '#' seen as first char on line */ ddefineseen, /* '#' and 'define' seen */ dignorerest /* ignore rest of line */ -} DEFINEST; -DEFINEST definedef; +} definedef; + +/* + * State machine for Objective C protocols and implementations. + */ +enum +{ + onone, /* nothing seen */ + oprotocol, /* @interface or @protocol seen */ + oimplementation, /* @implementations seen */ + otagseen, /* class name seen */ + oparenseen, /* parenthesis before category seen */ + ocatseen, /* category name seen */ + oinbody, /* in @implementation body */ + omethodsign, /* in @implementation body, after +/- */ + omethodtag, /* after method name */ + omethodcolon, /* after method colon */ + omethodparm, /* after method parameter */ + oignore, /* wait for @end */ +} objdef; /* * Set this to TRUE, and the next token considered is called a function. @@ -1678,6 +1733,11 @@ logical next_token_is_func; */ logical yacc_rules; +/* + * methodlen is the length of the method name stored in token_name. + */ +int methodlen; + /* * consider_token () * checks to see if the current token is at the start of a @@ -1697,16 +1757,18 @@ logical yacc_rules; * structdef IN OUT * definedef IN OUT * typdef IN OUT + * objdef IN OUT * next_token_is_func IN OUT */ logical -consider_token (str, len, c, c_ext, cblev, is_func) +consider_token (str, len, c, c_ext, cblev, parlev, is_func) register char *str; /* IN: token pointer */ register int len; /* IN: token length */ register char c; /* IN: first char after the token */ int c_ext; /* IN: C extensions mask */ int cblev; /* IN: curly brace level */ + int parlev; /* IN: parenthesis level */ logical *is_func; /* OUT: function found */ { enum sym_type toktype = C_symtype (str, len, c_ext); @@ -1831,22 +1893,11 @@ consider_token (str, len, c, c_ext, cblev, is_func) } /* Detect GNU macros. */ - if (definedef == dnone) - if (strneq (str, "DEFUN", len) /* Used in emacs */ -#if FALSE - These are defined inside C functions, so currently they - are not met anyway. - || strneq (str, "EXFUN", len) /* Used in glibc */ - || strneq (str, "DEFVAR_", 7) /* Used in emacs */ -#endif - || strneq (str, "SYSCALL", len) /* Used in glibc (mach) */ - || strneq (str, "ENTRY", len) /* Used in glibc */ - || strneq (str, "PSEUDO", len)) /* Used in glibc */ - - { - next_token_is_func = TRUE; - return FALSE; - } + if (definedef == dnone && toktype == st_C_gnumacro) + { + next_token_is_func = TRUE; + return FALSE; + } if (next_token_is_func) { next_token_is_func = FALSE; @@ -1855,6 +1906,78 @@ consider_token (str, len, c, c_ext, cblev, is_func) return TRUE; } + /* + * Detecting Objective C constructs. + */ + switch (objdef) + { + case onone: + switch (toktype) + { + case st_C_objprot: + objdef = oprotocol; + return FALSE; + case st_C_objimpl: + objdef = oimplementation; + return FALSE; + } + break; + case oimplementation: + /* Save the class tag for functions that may be defined inside. */ + objtag = savenstr (str, len); + objdef = oinbody; + return FALSE; + case oprotocol: + /* Save the class tag for categories. */ + objtag = savenstr (str, len); + objdef = otagseen; + *is_func = TRUE; + return TRUE; + case oparenseen: + objdef = ocatseen; + *is_func = TRUE; + return TRUE; + case oinbody: + break; + case omethodsign: + if (parlev == 0) + { + objdef = omethodtag; + methodlen = len; + GROW_LINEBUFFER (token_name, methodlen+1); + strncpy (token_name.buffer, str, len); + token_name.buffer[methodlen] = '\0'; + return TRUE; + } + return FALSE; + case omethodcolon: + if (parlev == 0) + objdef = omethodparm; + return FALSE; + case omethodparm: + if (parlev == 0) + { + objdef = omethodtag; + methodlen =+ len; + GROW_LINEBUFFER (token_name, methodlen+1); + strncat (token_name.buffer, str, len); + return TRUE; + } + return FALSE; + case oignore: + if (toktype == st_C_objend) + { + /* Memory leakage here: the string pointed by objtag is + never released, because many tests would be needed to + avoid breaking on incorrect input code. The amount of + memory leaked here is the sum of the lenghts of the + class tags. + free (objtag); */ + objdef = onone; + } + return FALSE; + } + /* A function? */ switch (toktype) { @@ -1922,16 +2045,14 @@ do { \ definedef = dnone; \ } while (0) +/* Ideally this macro should never be called wihen tok.valid is FALSE, + but this would mean that the state machines always guess right. */ #define make_tag(isfun) do \ -{ \ - if (tok.valid) \ - { \ - char *name = NULL; \ - if (tok.named) \ - name = savestr (token_name.buffer); \ - pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \ - } \ - else if (DEBUG) abort (); \ +if (tok.valid) { \ + char *name = NULL; \ + if (CTAGS || tok.named) \ + name = savestr (token_name.buffer); \ + pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \ tok.valid = FALSE; \ } while (0) @@ -1959,7 +2080,8 @@ C_entries (c_ext, inf) lp = curlb.buffer; *lp = 0; - definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone; + funcdef = fnone; typdef = tnone; structdef = snone; + definedef = dnone; objdef = onone; next_token_is_func = yacc_rules = FALSE; midtoken = inquote = inchar = incomm = quotednl = FALSE; tok.valid = savetok.valid = FALSE; @@ -2052,9 +2174,9 @@ C_entries (c_ext, inf) incomm = TRUE; continue; } - else if (cplpl && *lp == '/') + else if (/* cplpl && */ *lp == '/') { - c = 0; + c = '\0'; break; } else @@ -2114,7 +2236,7 @@ C_entries (c_ext, inf) { if (endtoken (c)) { - if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1))) + if (c == ':' && cplpl && *lp == ':' && begtoken(*(lp + 1))) { /* * This handles :: in the middle, but not at the @@ -2128,37 +2250,43 @@ C_entries (c_ext, inf) logical is_func = FALSE; if (yacc_rules - || consider_token (newlb.buffer + tokoff, toklen, - c, c_ext, cblev, &is_func)) + || consider_token (newlb.buffer + tokoff, toklen, c, + c_ext, cblev, parlev, &is_func)) { if (structdef == sinbody && definedef == dnone && is_func) /* function defined in C++ class body */ { - int strsize = strlen(structtag) + 2 + toklen + 1; - while (token_name.size < strsize) - { - token_name.size *= 2; - token_name.buffer - = (char *) xrealloc (token_name.buffer, - token_name.size); - } + GROW_LINEBUFFER (token_name, + strlen(structtag)+2+toklen+1); strcpy (token_name.buffer, structtag); strcat (token_name.buffer, "::"); strncat (token_name.buffer, newlb.buffer+tokoff, toklen); tok.named = TRUE; } + else if (objdef == ocatseen) + /* Objective C category */ + { + GROW_LINEBUFFER (token_name, + strlen(objtag)+2+toklen+1); + strcpy (token_name.buffer, objtag); + strcat (token_name.buffer, "("); + strncat (token_name.buffer, + newlb.buffer+tokoff, toklen); + strcat (token_name.buffer, ")"); + tok.named = TRUE; + } + else if (objdef == omethodtag + || objdef == omethodparm) + /* Objective C method */ + { + tok.named = TRUE; + } else { - while (token_name.size < toklen + 1) - { - token_name.size *= 2; - token_name.buffer - = (char *) xrealloc (token_name.buffer, - token_name.size); - } + GROW_LINEBUFFER (token_name, toklen+1); strncpy (token_name.buffer, newlb.buffer+tokoff, toklen); token_name.buffer[toklen] = '\0'; @@ -2179,7 +2307,8 @@ C_entries (c_ext, inf) if (definedef == dnone && (funcdef == ftagseen || structdef == stagseen - || typdef == tend)) + || typdef == tend + || objdef != onone)) { if (current_lb_is_new) switch_line_buffers (); @@ -2238,6 +2367,20 @@ C_entries (c_ext, inf) case ':': if (definedef != dnone) break; + switch (objdef) + { + case otagseen: + objdef = oignore; + make_tag (TRUE); + break; + case omethodtag: + case omethodparm: + objdef = omethodcolon; + methodlen += 1; + GROW_LINEBUFFER (token_name, methodlen+1); + strcat (token_name.buffer, ":"); + break; + } if (structdef == stagseen) structdef = scolonseen; else @@ -2281,6 +2424,14 @@ C_entries (c_ext, inf) case ',': if (definedef != dnone) break; + switch (objdef) + { + case omethodtag: + case omethodparm: + make_tag (TRUE); + objdef = oinbody; + break; + } if (funcdef != finlist && funcdef != fignore) funcdef = fnone; if (structdef == stagseen) @@ -2303,6 +2454,8 @@ C_entries (c_ext, inf) case '(': if (definedef != dnone) break; + if (objdef == otagseen && parlev == 0) + objdef = oparenseen; switch (funcdef) { case fnone: @@ -2333,6 +2486,11 @@ C_entries (c_ext, inf) case ')': if (definedef != dnone) break; + if (objdef == ocatseen && parlev == 1) + { + make_tag (TRUE); + objdef = oignore; + } if (--parlev == 0) { switch (funcdef) @@ -2377,9 +2535,22 @@ C_entries (c_ext, inf) funcdef = fnone; break; case fnone: - /* Neutralize `extern "C" {' grot and look inside structs. */ - if (cblev == 0 && structdef == snone && typdef == tnone) - cblev = -1; + switch (objdef) + { + case otagseen: + make_tag (TRUE); + objdef = oignore; + break; + case omethodtag: + case omethodparm: + make_tag (TRUE); + objdef = oinbody; + break; + default: + /* Neutralize `extern "C" {' grot and look inside structs. */ + if (cblev == 0 && structdef == snone && typdef == tnone) + cblev = -1; + } } cblev++; break; @@ -2415,8 +2586,15 @@ C_entries (c_ext, inf) structtag = ""; } break; - case '=': - case '#': case '+': case '-': case '~': case '&': case '%': case '/': + case '+': + case '-': + if (objdef == oinbody && cblev == 0) + { + objdef = omethodsign; + break; + } + /* FALLTHRU */ + case '=': case '#': case '~': case '&': case '%': case '/': case '|': case '^': case '!': case '<': case '>': case '.': case '?': if (definedef != dnone) break; @@ -2425,6 +2603,11 @@ C_entries (c_ext, inf) funcdef = fnone; break; case '\0': + if (objdef == otagseen) + { + make_tag (TRUE); + objdef = oignore; + } /* If a macro spans multiple lines don't reset its state. */ if (quotednl) CNL_SAVE_DEFINEDEF; @@ -2553,7 +2736,8 @@ getit (inf) && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$'))); cp++) continue; - pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); + pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE, + lb.buffer, cp - lb.buffer + 1, lineno, linecharno); } void @@ -2669,7 +2853,7 @@ Asm_labels (inf) if (*cp == ':' || isspace (*cp)) { /* Found end of label, so copy it and add it to the table. */ - pfnote (NULL, TRUE, + pfnote ((CTAGS) ? savenstr(lb.buffer, cp-lb.buffer) : NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); } } @@ -2702,7 +2886,7 @@ Perl_functions (inf) cp++; while (*cp && ! isspace(*cp) && *cp != '{') cp++; - pfnote (NULL, TRUE, + pfnote ((CTAGS) ? savenstr (lb.buffer, cp-lb.buffer) : NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); } } @@ -2731,7 +2915,7 @@ Pascal_functions (inf) struct linebuffer tline; /* mostly copied from C_entries */ long save_lcno; int save_lineno, save_len; - char c; + char c, *cp, *namebuf; logical /* each of these flags is TRUE iff: */ incomment, /* point is inside a comment */ @@ -2845,32 +3029,27 @@ Pascal_functions (inf) { found_tag = FALSE; verify_tag = FALSE; - pfnote (NULL, TRUE, + pfnote (namebuf, TRUE, tline.buffer, save_len, save_lineno, save_lcno); continue; } } if (get_tagname) /* grab name of proc or fn */ { - int size; - if (*dbp == '\0') continue; /* save all values for later tagging */ - size = strlen (lb.buffer) + 1; - while (size > tline.size) - { - tline.size *= 2; - tline.buffer = (char *) xrealloc (tline.buffer, tline.size); - } + GROW_LINEBUFFER (tline, strlen (lb.buffer) + 1); strcpy (tline.buffer, lb.buffer); save_lineno = lineno; save_lcno = linecharno; /* grab block name */ - for (dbp++; *dbp && (!endtoken (*dbp)); dbp++) + for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++) continue; + namebuf = (CTAGS) ? savenstr (dbp, cp-dbp) : NULL; + dbp = cp; /* set dbp to e-o-token */ save_len = dbp - lb.buffer + 1; get_tagname = FALSE; found_tag = TRUE; @@ -2943,7 +3122,8 @@ L_getit () if (cp == dbp) return; - pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); + pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE, + lb.buffer, cp - lb.buffer + 1, lineno, linecharno); } void @@ -3060,7 +3240,8 @@ get_scheme () *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++) continue; - pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno); + pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE, + lb.buffer, cp - lb.buffer + 1, lineno, linecharno); } /* Find tags in TeX and LaTeX input files. */ @@ -3319,7 +3500,8 @@ prolog_getit (s) else s++; } - pfnote (NULL, TRUE, save_s, s-save_s, lineno, linecharno); + pfnote ((CTAGS) ? savenstr (save_s, s-save_s) : NULL, TRUE, + save_s, s-save_s, lineno, linecharno); } /* It is assumed that prolog predicate starts from column 0. */ @@ -3604,10 +3786,10 @@ readline (linebuffer, stream) FILE *stream; { /* Read new line. */ - int i; long result = readline_internal (linebuffer, stream); - #ifdef ETAGS_REGEXPS + int i; + /* Match against all listed patterns. */ for (i = 0; i < num_patterns; ++i) { @@ -3754,6 +3936,14 @@ pfatal (s1) exit (BAD); } +void +suggest_asking_for_help () +{ + fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n", + progname); + exit (BAD); +} + /* Print error message. `s1' is printf control string, `s2' is arg for it. */ void error (s1, s2)