X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/be0dbdab007cf09a2cac30c89ad4d530b08abeae..4984edc7c449d68ad08785bbdc6a01675aeca6e7:/lib-src/ebrowse.c?ds=sidebyside diff --git a/lib-src/ebrowse.c b/lib-src/ebrowse.c index 5e70bcd163..94fa9114d2 100644 --- a/lib-src/ebrowse.c +++ b/lib-src/ebrowse.c @@ -1,10 +1,8 @@ /* ebrowse.c --- parsing files for the ebrowse C++ browser - Copyright (C) 1992-1999, 2000 Free Software Foundation Inc. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - Author: Gerd Moellmann - Maintainer: FSF - This file is part of GNU Emacs. GNU Emacs is free software; you can redistribute it and/or modify @@ -18,18 +16,31 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GNU Emacs; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + along with GNU Emacs; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif #include + +#ifdef HAVE_STDLIB_H #include +#endif + +#ifdef HAVE_STRING_H #include +#endif + #include #include #include "getopt.h" -#ifdef HAVE_CONFIG_H -#include +/* The SunOS compiler doesn't have SEEK_END. */ +#ifndef SEEK_END +#define SEEK_END 2 #endif /* Conditionalize function prototypes. */ @@ -57,11 +68,21 @@ /* The character used as a separator in path lists (like $PATH). */ +#if defined(__MSDOS__) +#define PATH_LIST_SEPARATOR ';' +#define FILENAME_EQ(X,Y) (strcasecmp(X,Y) == 0) +#else +#if defined(WINDOWSNT) +#define PATH_LIST_SEPARATOR ';' +#define FILENAME_EQ(X,Y) (stricmp(X,Y) == 0) +#else #define PATH_LIST_SEPARATOR ':' - +#define FILENAME_EQ(X,Y) (streq(X,Y)) +#endif +#endif /* The default output file name. */ -#define DEFAULT_OUTFILE "EBROWSE" +#define DEFAULT_OUTFILE "BROWSE" /* A version string written to the output file. Change this whenever the structure of the output file changes. */ @@ -262,6 +283,8 @@ struct link struct alias { struct alias *next; /* Next in list. */ + struct sym *namesp; /* Namespace in which defined. */ + struct link *aliasee; /* List of aliased namespaces (A::B::C...). */ char name[1]; /* Alias name. */ }; @@ -286,7 +309,6 @@ struct sym char *filename; /* File in which it can be found. */ char *sfilename; /* File in which members can be found. */ struct sym *namesp; /* Namespace in which defined. . */ - struct alias *namesp_aliases; /* List of aliases for namespaces. */ char name[1]; /* Name of the class. */ }; @@ -382,7 +404,7 @@ int inbuffer_size; #define BUFFER_POS() (in - inbuffer) -/* If current lookahead is CSTRING, the following points to the +/* If current lookahead is CSTRING, the following points to the first character in the string constant. Used for recognizing extern "C". */ @@ -403,6 +425,10 @@ struct sym *class_table[TABLE_SIZE]; struct member *member_table[TABLE_SIZE]; +/* Hash table for namespace aliases */ + +struct alias *namespace_alias_table[TABLE_SIZE]; + /* The special class symbol used to hold global functions, variables etc. */ @@ -467,13 +493,14 @@ void add_member_decl P_ ((struct sym *, char *, char *, int, unsigned, int, int, int, int)); void dump_roots P_ ((FILE *)); void *xmalloc P_ ((int)); +void xfree P_ ((void *)); void add_global_defn P_ ((char *, char *, int, unsigned, int, int, int)); void add_global_decl P_ ((char *, char *, int, unsigned, int, int, int)); void add_define P_ ((char *, char *, int)); void mark_inherited_virtual P_ ((void)); void leave_namespace P_ ((void)); void enter_namespace P_ ((char *)); -void register_namespace_alias P_ ((char *, char *)); +void register_namespace_alias P_ ((char *, struct link *)); void insert_keyword P_ ((char *, int)); void re_init_scanner P_ ((void)); void init_scanner P_ ((void)); @@ -490,7 +517,7 @@ struct member *find_member P_ ((struct sym *, char *, int, int, unsigned)); struct member *add_member P_ ((struct sym *, char *, int, int, unsigned)); void mark_virtual P_ ((struct sym *)); void mark_virtual P_ ((struct sym *)); -struct sym *make_namespace P_ ((char *)); +struct sym *make_namespace P_ ((char *, struct sym *)); char *sym_scope P_ ((struct sym *)); char *sym_scope_1 P_ ((struct sym *)); int skip_to P_ ((int)); @@ -498,13 +525,14 @@ void skip_matching P_ ((void)); void member P_ ((struct sym *, int)); void class_body P_ ((struct sym *, int)); void class_definition P_ ((struct sym *, int, int, int)); -void declaration P_ ((int, int)); +void declaration P_ ((int)); unsigned parm_list P_ ((int *)); char *operator_name P_ ((int *)); struct sym *parse_classname P_ ((void)); struct sym *parse_qualified_ident_or_type P_ ((char **)); void parse_qualified_param_ident_or_type P_ ((char **)); int globals P_ ((int)); +void yyerror P_ ((char *, char *)); @@ -516,12 +544,11 @@ int globals P_ ((int)); name and line number. */ void -yyerror (format, a1, a2, a3, a4, a5) - char *format; - int a1, a2, a3, a4, a5; +yyerror (format, s) + char *format, *s; { fprintf (stderr, "%s:%d: ", filename, yyline); - fprintf (stderr, format, a1, a2, a3, a4, a5); + fprintf (stderr, format, s); putc ('\n', stderr); } @@ -534,10 +561,12 @@ xmalloc (nbytes) int nbytes; { void *p = malloc (nbytes); - if (p) - return p; - yyerror ("out of memory"); - exit (1); + if (p == NULL) + { + yyerror ("out of memory", NULL); + exit (EXIT_FAILURE); + } + return p; } @@ -549,10 +578,23 @@ xrealloc (p, sz) int sz; { p = realloc (p, sz); + if (p == NULL) + { + yyerror ("out of memory", NULL); + exit (EXIT_FAILURE); + } + return p; +} + + +/* Like free but always check for null pointers.. */ + +void +xfree (p) + void *p; +{ if (p) - return p; - yyerror ("out of memory"); - exit (1); + free (p); } @@ -606,7 +648,10 @@ add_sym (name, nested_in_class) h %= TABLE_SIZE; for (sym = class_table[h]; sym; sym = sym->next) - if (streq (name, sym->name) && sym->namesp == scope) + if (streq (name, sym->name) + && ((!sym->namesp && !scope) + || (sym->namesp && scope + && streq (sym->namesp->name, scope->name)))) break; if (sym == NULL) @@ -648,7 +693,7 @@ add_link (super, sub) { lnk = (struct link *) xmalloc (sizeof *lnk); lnk2 = (struct link *) xmalloc (sizeof *lnk2); - + lnk->sym = sub; lnk->next = p; @@ -690,15 +735,15 @@ find_member (cls, name, var, sc, hash) case SC_FRIEND: list = &cls->friends; break; - + case SC_TYPE: list = &cls->types; break; - + case SC_STATIC: list = var ? &cls->static_vars : &cls->static_fns; break; - + default: list = var ? &cls->vars : &cls->fns; break; @@ -745,7 +790,7 @@ add_member_decl (cls, name, regexp, pos, hash, var, sc, vis, flags) m = add_member (cls, name, var, sc, hash); /* Have we seen a new filename? If so record that. */ - if (!cls->filename || !streq (cls->filename, filename)) + if (!cls->filename || !FILENAME_EQ (cls->filename, filename)) m->filename = filename; m->regexp = regexp; @@ -816,7 +861,7 @@ add_member_defn (cls, name, regexp, pos, hash, var, sc, flags) if (!cls->sfilename) cls->sfilename = filename; - if (!streq (cls->sfilename, filename)) + if (!FILENAME_EQ (cls->sfilename, filename)) m->def_filename = filename; m->def_regexp = regexp; @@ -890,7 +935,7 @@ add_global_defn (name, regexp, pos, hash, var, sc, flags) a bit set giving additional information about the member (see the F_* defines). */ -void +void add_global_decl (name, regexp, pos, hash, var, sc, flags) char *name, *regexp; int pos; @@ -915,7 +960,7 @@ add_global_decl (name, regexp, pos, hash, var, sc, flags) if (!found) { if (!global_symbols->filename - || !streq (global_symbols->filename, filename)) + || !FILENAME_EQ (global_symbols->filename, filename)) m->filename = filename; m->regexp = regexp; @@ -970,15 +1015,15 @@ add_member (cls, name, var, sc, hash) case SC_FRIEND: list = &cls->friends; break; - + case SC_TYPE: list = &cls->types; break; - + case SC_STATIC: list = var ? &cls->static_vars : &cls->static_fns; break; - + default: list = var ? &cls->vars : &cls->fns; break; @@ -1052,68 +1097,107 @@ mark_inherited_virtual () /* Create and return a symbol for a namespace with name NAME. */ struct sym * -make_namespace (name) +make_namespace (name, context) char *name; + struct sym *context; { struct sym *s = (struct sym *) xmalloc (sizeof *s + strlen (name)); bzero (s, sizeof *s); strcpy (s->name, name); s->next = all_namespaces; - s->namesp = current_namespace; + s->namesp = context; all_namespaces = s; return s; } -/* Find the symbol for namespace NAME. If not found, add a new symbol - for NAME to all_namespaces. */ +/* Find the symbol for namespace NAME. If not found, retrun NULL */ struct sym * -find_namespace (name) +check_namespace (name, context) char *name; + struct sym *context; { - struct sym *p; - + struct sym *p = NULL; + for (p = all_namespaces; p; p = p->next) { - if (streq (p->name, name)) - break; - else - { - struct alias *p2; - for (p2 = p->namesp_aliases; p2; p2 = p2->next) - if (streq (p2->name, name)) - break; - if (p2) + if (streq (p->name, name) && (p->namesp == context)) break; } + + return p; } +/* Find the symbol for namespace NAME. If not found, add a new symbol + for NAME to all_namespaces. */ + +struct sym * +find_namespace (name, context) + char *name; + struct sym *context; +{ + struct sym *p = check_namespace (name, context); + if (p == NULL) - p = make_namespace (name); + p = make_namespace (name, context); + + return p; +} + + +/* Find namespace alias with name NAME. If not found return NULL. */ + +struct link * +check_namespace_alias (name) + char *name; +{ + struct link *p = NULL; + struct alias *al; + unsigned h; + char *s; + + for (s = name, h = 0; *s; ++s) + h = (h << 1) ^ *s; + h %= TABLE_SIZE; + + for (al = namespace_alias_table[h]; al; al = al->next) + if (streq (name, al->name) && (al->namesp == current_namespace)) + { + p = al->aliasee; + break; + } return p; } - -/* Register the name NEW_NAME as an alias for namespace OLD_NAME. */ +/* Register the name NEW_NAME as an alias for namespace list OLD_NAME. */ void register_namespace_alias (new_name, old_name) - char *new_name, *old_name; + char *new_name; + struct link *old_name; { - struct sym *p = find_namespace (old_name); + unsigned h; + char *s; struct alias *al; - /* Is it already in the list of aliases? */ - for (al = p->namesp_aliases; al; al = al->next) - if (streq (new_name, p->name)) + for (s = new_name, h = 0; *s; ++s) + h = (h << 1) ^ *s; + h %= TABLE_SIZE; + + + /* Is it already in the table of aliases? */ + for (al = namespace_alias_table[h]; al; al = al->next) + if (streq (new_name, al->name) && (al->namesp == current_namespace)) return; al = (struct alias *) xmalloc (sizeof *al + strlen (new_name)); strcpy (al->name, new_name); - al->next = p->namesp_aliases; - p->namesp_aliases = al; + al->next = namespace_alias_table[h]; + al->namesp = current_namespace; + al->aliasee = old_name; + namespace_alias_table[h] = al; } @@ -1123,15 +1207,17 @@ void enter_namespace (name) char *name; { - struct sym *p = find_namespace (name); + struct sym *p = find_namespace (name, current_namespace); if (namespace_sp == namespace_stack_size) { int size = max (10, 2 * namespace_stack_size); - namespace_stack = (struct sym **) xrealloc (namespace_stack, size); + namespace_stack + = (struct sym **) xrealloc ((void *)namespace_stack, + size * sizeof *namespace_stack); namespace_stack_size = size; } - + namespace_stack[namespace_sp++] = current_namespace; current_namespace = p; } @@ -1188,7 +1274,7 @@ ensure_scope_buffer_room (len) if (scope_buffer_len + len >= scope_buffer_size) { int new_size = max (2 * scope_buffer_size, scope_buffer_len + len); - scope_buffer = (char *) xrealloc (new_size); + scope_buffer = (char *) xrealloc (scope_buffer, new_size); scope_buffer_size = new_size; } } @@ -1203,7 +1289,7 @@ sym_scope_1 (p) struct sym *p; { int len; - + if (p->namesp) sym_scope_1 (p->namesp); @@ -1218,14 +1304,14 @@ sym_scope_1 (p) ensure_scope_buffer_room (len + 1); strcat (scope_buffer, p->name); scope_buffer_len += len; - + if (HAS_FLAG (p->flags, F_TEMPLATE)) { ensure_scope_buffer_room (3); strcat (scope_buffer, "<>"); scope_buffer_len += 2; } - + return scope_buffer; } @@ -1242,10 +1328,10 @@ sym_scope (p) scope_buffer_size = 1024; scope_buffer = (char *) xmalloc (scope_buffer_size); } - + *scope_buffer = '\0'; scope_buffer_len = 0; - + if (p->namesp) sym_scope_1 (p->namesp); @@ -1298,13 +1384,13 @@ dump_sym (fp, root) { fputs (CLASS_STRUCT, fp); PUTSTR (root->name, fp); - + /* Print scope, if any. */ if (root->namesp) PUTSTR (sym_scope (root), fp); else PUTSTR (NULL, fp); - + /* Print flags. */ fprintf (fp, "%u", root->flags); PUTSTR (root->filename, fp); @@ -1446,7 +1532,7 @@ do { \ int process_pp_line () { - int in_comment = 0; + int in_comment = 0, in_string = 0; int c; char *p = yytext; @@ -1484,8 +1570,8 @@ process_pp_line () add_define (yytext, regexp, pos); } } - - while (c && (c != '\n' || in_comment)) + + while (c && (c != '\n' || in_comment || in_string)) { if (c == '\\') GET (c); @@ -1499,13 +1585,15 @@ process_pp_line () if (GET (c) == '/') in_comment = 0; } - + else if (c == '"') + in_string = !in_string; + if (c == '\n') INCREMENT_LINENO; GET (c); } - + return c; } @@ -1555,14 +1643,15 @@ yylex () if (!GET (c)) { if (end_char == '\'') - yyerror ("EOF in character constant"); + yyerror ("EOF in character constant", NULL); else - yyerror ("EOF in string constant"); + yyerror ("EOF in string constant", NULL); goto end_string; } else switch (c) { case '\n': + INCREMENT_LINENO; case 'a': case 'b': case 'f': @@ -1621,11 +1710,11 @@ yylex () case '\n': if (end_char == '\'') - yyerror ("newline in character constant"); + yyerror ("newline in character constant", NULL); else - yyerror ("newline in string constant"); + yyerror ("newline in string constant", NULL); INCREMENT_LINENO; - goto end_string; + break; default: break; @@ -1777,7 +1866,7 @@ yylex () else if (c == '.') { if (GET (c) != '.') - yyerror ("invalid token '..' ('...' assumed)"); + yyerror ("invalid token '..' ('...' assumed)", NULL); UNGET (); return ELLIPSIS; } @@ -1918,6 +2007,12 @@ yylex () } +/* Actually local to matching_regexp. These variables must be in + global scope for the case that `static' get's defined away. */ + +static char *matching_regexp_buffer, *matching_regexp_end_buf; + + /* Value is the string from the start of the line to the current position in the input buffer, or maybe a bit more if that string is shorter than min_regexp. */ @@ -1928,15 +2023,14 @@ matching_regexp () char *p; char *s; char *t; - static char *buffer, *end_buf; if (!f_regexps) return NULL; - if (buffer == NULL) + if (matching_regexp_buffer == NULL) { - buffer = (char *) xmalloc (max_regexp); - end_buf = &buffer[max_regexp] - 1; + matching_regexp_buffer = (char *) xmalloc (max_regexp); + matching_regexp_end_buf = &matching_regexp_buffer[max_regexp] - 1; } /* Scan back to previous newline of buffer start. */ @@ -1958,15 +2052,16 @@ matching_regexp () /* Copy from end to make sure significant portions are included. This implies that in the browser a regular expressing of the form `^.*{regexp}' has to be used. */ - for (s = end_buf - 1, t = in; s > buffer && t > p;) + for (s = matching_regexp_end_buf - 1, t = in; + s > matching_regexp_buffer && t > p;) { *--s = *--t; - if (*s == '"') + if (*s == '"' || *s == '\\') *--s = '\\'; } - *(end_buf - 1) = '\0'; + *(matching_regexp_end_buf - 1) = '\0'; return xstrdup (s); } @@ -2059,13 +2154,33 @@ token_string (t) case VOID: return "void"; case VOLATILE: return "volatile"; case WHILE: return "while"; + case MUTABLE: return "mutable"; + case BOOL: return "bool"; + case TRUE: return "true"; + case FALSE: return "false"; + case SIGNATURE: return "signature"; + case NAMESPACE: return "namespace"; + case EXPLICIT: return "explicit"; + case TYPENAME: return "typename"; + case CONST_CAST: return "const_cast"; + case DYNAMIC_CAST: return "dynamic_cast"; + case REINTERPRET_CAST: return "reinterpret_cast"; + case STATIC_CAST: return "static_cast"; + case TYPEID: return "typeid"; + case USING: return "using"; + case WCHAR: return "wchar_t"; case YYEOF: return "EOF"; - } - assert (t < 255); - b[0] = t; - b[1] = '\0'; - return b; + default: + if (t < 255) + { + b[0] = t; + b[1] = '\0'; + return b; + } + else + return "???"; + } } @@ -2076,7 +2191,7 @@ re_init_scanner () { in = inbuffer; yyline = 1; - + if (yytext == NULL) { int size = 256; @@ -2265,7 +2380,6 @@ skip_to (token) return tk; } - /* Skip over pairs of tokens (parentheses, square brackets, angle brackets, curly brackets) matching the current lookahead. */ @@ -2279,19 +2393,19 @@ skip_matching () case '{': close = '}'; break; - + case '(': close = ')'; break; - + case '<': close = '>'; break; - + case '[': close = ']'; break; - + default: abort (); } @@ -2312,6 +2426,67 @@ skip_matching () } } +void +skip_initializer () +{ + for (;;) + { + switch (LA1) + { + case ';': + case ',': + case YYEOF: + return; + + case '{': + case '[': + case '(': + skip_matching (); + break; + + default: + MATCH (); + break; + } + } +} + +/* Build qualified namespace alias (A::B::c) and return it. */ + +struct link * +match_qualified_namespace_alias () +{ + struct link *head = NULL; + struct link *cur = NULL; + struct link *tmp = NULL; + + for (;;) + { + MATCH (); + switch (LA1) + { + case IDENT: + tmp = (struct link *) xmalloc (sizeof *cur); + tmp->sym = find_namespace (yytext, cur); + tmp->next = NULL; + if (head) + { + cur = cur->next = tmp; + } + else + { + head = cur = tmp; + } + break; + case DCOLON: + /* Just skip */ + break; + default: + return head; + break; + } + } +} /* Re-initialize the parser by resetting the lookahead token. */ @@ -2339,7 +2514,7 @@ parm_list (flags) { switch (LA1) { - /* Skip over grouping parens or parameter lists in parameter + /* Skip over grouping parens or parameter lists in parameter declarations. */ case '(': skip_matching (); @@ -2359,14 +2534,18 @@ parm_list (flags) case IDENT: if (!type_seen) { - char *s; + char *last_id; unsigned ident_type_hash = 0; - - parse_qualified_param_ident_or_type (&s); - for (; *s; ++s) - ident_type_hash = (ident_type_hash << 1) ^ *s; - hash = (hash << 1) ^ ident_type_hash; - type_seen = 1; + + parse_qualified_param_ident_or_type (&last_id); + if (last_id) + { + /* LAST_ID null means something like `X::*'. */ + for (; *last_id; ++last_id) + ident_type_hash = (ident_type_hash << 1) ^ *last_id; + hash = (hash << 1) ^ ident_type_hash; + type_seen = 1; + } } else MATCH (); @@ -2385,7 +2564,7 @@ parm_list (flags) case DOUBLE: case ENUM: case FLOAT: case INT: case LONG: case SHORT: case SIGNED: case STRUCT: case UNION: case UNSIGNED: case VOLATILE: case WCHAR: - case ELLIPSIS: + case ELLIPSIS: type_seen = 1; hash = (hash << 1) ^ LA1; MATCH (); @@ -2405,7 +2584,7 @@ parm_list (flags) if (LOOKING_AT (')')) { MATCH (); - + if (LOOKING_AT (CONST)) { /* We can overload the same function on `const' */ @@ -2490,7 +2669,7 @@ member (cls, vis) case EXPLICIT: SET_FLAG (flags, F_EXPLICIT); goto typeseen; - + case MUTABLE: SET_FLAG (flags, F_MUTABLE); goto typeseen; @@ -2529,9 +2708,9 @@ member (cls, vis) break; case IDENT: - /* Remember IDENTS seen so far. Among these will be the member - name. */ - id = (char *) alloca (strlen (yytext) + 2); + /* Remember IDENTS seen so far. Among these will be the member + name. */ + id = (char *) xrealloc (id, strlen (yytext) + 2); if (tilde) { *id = '~'; @@ -2543,7 +2722,11 @@ member (cls, vis) break; case OPERATOR: - id = operator_name (&sc); + { + char *s = operator_name (&sc); + id = (char *) xrealloc (id, strlen (s) + 1); + strcpy (id, s); + } break; case '(': @@ -2573,7 +2756,8 @@ member (cls, vis) if (LOOKING_AT ('{') && id && cls) add_member_defn (cls, id, regexp, pos, hash, 0, sc, flags); - + + xfree (id); id = NULL; sc = SC_MEMBER; break; @@ -2620,7 +2804,7 @@ member (cls, vis) { regexp = matching_regexp (); pos = BUFFER_POS (); - + if (cls != NULL) { if (type_seen || !paren_seen) @@ -2629,7 +2813,7 @@ member (cls, vis) add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, 0); } } - + MATCH (); print_info (); } @@ -2651,6 +2835,8 @@ member (cls, vis) skip_matching (); print_info (); } + + xfree (id); } @@ -2724,7 +2910,7 @@ struct sym * parse_classname () { struct sym *last_class = NULL; - + while (LOOKING_AT (IDENT)) { last_class = add_sym (yytext, last_class); @@ -2735,10 +2921,10 @@ parse_classname () skip_matching (); SET_FLAG (last_class->flags, F_TEMPLATE); } - + if (!LOOKING_AT (DCOLON)) break; - + MATCH (); } @@ -2758,7 +2944,7 @@ operator_name (sc) static char *id = NULL; char *s; int len; - + MATCH (); if (LOOKING_AT2 (NEW, DELETE)) @@ -2769,7 +2955,7 @@ operator_name (sc) s = token_string (LA1); MATCH (); - + len = strlen (s) + 10; if (len > id_size) { @@ -2779,12 +2965,12 @@ operator_name (sc) } strcpy (id, s); - /* Vector new or delete? */ + /* Vector new or delete? */ if (LOOKING_AT ('[')) { strcat (id, "["); MATCH (); - + if (LOOKING_AT (']')) { strcat (id, "]"); @@ -2826,7 +3012,7 @@ operator_name (sc) MATCH (); /* If this is a simple operator like `+', stop now. */ - if (!isalpha (*s) && *s != '(' && *s != '[') + if (!isalpha ((unsigned char) *s) && *s != '(' && *s != '[') break; ++tokens_matched; @@ -2838,7 +3024,7 @@ operator_name (sc) /* This one consumes the last IDENT of a qualified member name like - `X::Y::z'. This IDENT is returned in LAST_ID. Value if the + `X::Y::z'. This IDENT is returned in LAST_ID. Value is the symbol structure for the ident. */ struct sym * @@ -2846,9 +3032,10 @@ parse_qualified_ident_or_type (last_id) char **last_id; { struct sym *cls = NULL; - static char *id = NULL; - static int id_size = 0; - + char *id = NULL; + size_t id_size = 0; + int enter = 0; + while (LOOKING_AT (IDENT)) { int len = strlen (yytext) + 1; @@ -2865,20 +3052,45 @@ parse_qualified_ident_or_type (last_id) if (LOOKING_AT (DCOLON)) { - cls = add_sym (id, cls); + struct sym *pcn = NULL; + struct link *pna = check_namespace_alias (id); + if (pna) + { + do + { + enter_namespace (pna->sym->name); + enter++; + pna = pna->next; + } + while (pna); + } + else if ((pcn = check_namespace (id, current_namespace))) + { + enter_namespace (pcn->name); + enter++; + } + else + cls = add_sym (id, cls); + *last_id = NULL; + xfree (id); + id = NULL; + id_size = 0; MATCH (); } else break; } + while (enter--) + leave_namespace(); + return cls; } /* This one consumes the last IDENT of a qualified member name like - `X::Y::z'. This IDENT is returned in LAST_ID. Value if the + `X::Y::z'. This IDENT is returned in LAST_ID. Value is the symbol structure for the ident. */ void @@ -2888,7 +3100,7 @@ parse_qualified_param_ident_or_type (last_id) struct sym *cls = NULL; static char *id = NULL; static int id_size = 0; - + while (LOOKING_AT (IDENT)) { int len = strlen (yytext) + 1; @@ -2931,7 +3143,6 @@ class_definition (containing, tag, flags, nested) int flags; int nested; { - register int token; struct sym *current; struct sym *base_class; @@ -2940,7 +3151,7 @@ class_definition (containing, tag, flags, nested) settings. */ if ((tag != CLASS && !f_structs) || (nested && !f_nested_classes)) current = NULL; - else + else { current = add_sym (yytext, containing); current->pos = BUFFER_POS (); @@ -2957,9 +3168,9 @@ class_definition (containing, tag, flags, nested) while (!done) { - switch (token = LA1) + switch (LA1) { - case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE: + case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE: MATCH (); break; @@ -3021,12 +3232,59 @@ class_definition (containing, tag, flags, nested) } } +/* Add to class *CLS information for the declaration of variable or + type *ID. If *CLS is null, this means a global declaration. SC is + the storage class of *ID. FLAGS is a bit set giving additional + information about the member (see the F_* defines). */ + +void +add_declarator (cls, id, flags, sc) + struct sym **cls; + char **id; + int flags, sc; +{ + if (LOOKING_AT2 (';', ',')) + { + /* The end of a member variable or of an access declaration + `X::f'. To distinguish between them we have to know whether + type information has been seen. */ + if (*id) + { + char *regexp = matching_regexp (); + int pos = BUFFER_POS (); + + if (*cls) + add_member_defn (*cls, *id, regexp, pos, 0, 1, SC_UNKNOWN, flags); + else + add_global_defn (*id, regexp, pos, 0, 1, sc, flags); + } + + MATCH (); + print_info (); + } + else if (LOOKING_AT ('{')) + { + if (sc == SC_TYPE && *id) + { + /* A named enumeration. */ + char *regexp = matching_regexp (); + int pos = BUFFER_POS (); + add_global_defn (*id, regexp, pos, 0, 1, sc, flags); + } + + skip_matching (); + print_info (); + } + + xfree (*id); + *id = NULL; + *cls = NULL; +} /* Parse a declaration. */ void -declaration (is_extern, flags) - int is_extern; +declaration (flags) int flags; { char *id = NULL; @@ -3054,7 +3312,7 @@ declaration (is_extern, flags) sc = SC_TYPE; MATCH (); break; - + case STATIC: sc = SC_STATIC; MATCH (); @@ -3070,16 +3328,27 @@ declaration (is_extern, flags) /* This is for the case `STARTWRAP class X : ...' or `declare (X, Y)\n class A : ...'. */ if (id) - return; + { + xfree (id); + return; + } case '=': - /* Assumed to be the start of an initialization in this context. - Skip over everything up to ';'. */ - skip_to (';'); + /* Assumed to be the start of an initialization in this + context. */ + skip_initializer (); break; + case ',': + add_declarator (&cls, &id, flags, sc); + break; + case OPERATOR: - id = operator_name (&sc); + { + char *s = operator_name (&sc); + id = (char *) xrealloc (id, strlen (s) + 1); + strcpy (id, s); + } break; case T_INLINE: @@ -3091,7 +3360,7 @@ declaration (is_extern, flags) MATCH (); if (LOOKING_AT (IDENT)) { - id = (char *) alloca (strlen (yytext) + 2); + id = (char *) xrealloc (id, strlen (yytext) + 2); *id = '~'; strcpy (id + 1, yytext); MATCH (); @@ -3153,43 +3422,14 @@ declaration (is_extern, flags) if (!cls && id && LOOKING_AT ('{')) add_global_defn (id, regexp, pos, hash, 0, sc, flags); + + xfree (id); id = NULL; break; } } - if (LOOKING_AT (';')) - { - /* The end of a member variable or of an access declaration - `X::f'. To distinguish between them we have to know whether - type information has been seen. */ - if (id) - { - char *regexp = matching_regexp (); - int pos = BUFFER_POS (); - - if (cls) - add_member_defn (cls, id, regexp, pos, 0, 1, SC_UNKNOWN, flags); - else - add_global_defn (id, regexp, pos, 0, 1, sc, flags); - } - - MATCH (); - print_info (); - } - else if (LOOKING_AT ('{')) - { - if (sc == SC_TYPE && id) - { - /* A named enumeration. */ - regexp = matching_regexp (); - pos = BUFFER_POS (); - add_global_defn (id, regexp, pos, 0, 1, sc, flags); - } - - skip_matching (); - print_info (); - } + add_declarator (&cls, &id, flags, sc); } @@ -3209,7 +3449,7 @@ globals (start_flags) for (;;) { char *prev_in = in; - + switch (LA1) { case NAMESPACE: @@ -3218,16 +3458,17 @@ globals (start_flags) if (LOOKING_AT (IDENT)) { - char *namespace_name - = (char *) alloca (strlen (yytext) + 1); - strcpy (namespace_name, yytext); + char *namespace_name = xstrdup (yytext); MATCH (); - + if (LOOKING_AT ('=')) { + struct link *qna = match_qualified_namespace_alias (); + if (qna) + register_namespace_alias (namespace_name, qna); + if (skip_to (';') == ';') MATCH (); - register_namespace_alias (namespace_name, yytext); } else if (LOOKING_AT ('{')) { @@ -3237,6 +3478,8 @@ globals (start_flags) leave_namespace (); MATCH_IF ('}'); } + + xfree (namespace_name); } } break; @@ -3248,7 +3491,7 @@ globals (start_flags) { /* This is `extern "C"'. */ MATCH (); - + if (LOOKING_AT ('{')) { MATCH (); @@ -3259,7 +3502,7 @@ globals (start_flags) SET_FLAG (flags, F_EXTERNC); } break; - + case TEMPLATE: MATCH (); SKIP_MATCHING_IF ('<'); @@ -3299,15 +3542,15 @@ globals (start_flags) case '}': return 0; - + default: - declaration (0, flags); + declaration (flags); flags = start_flags; break; } if (prev_in == in) - yyerror ("parse error"); + yyerror ("parse error", NULL); } } @@ -3338,10 +3581,10 @@ add_search_path (path_list) { char *start = path_list; struct search_path *p; - + while (*path_list && *path_list != PATH_LIST_SEPARATOR) ++path_list; - + p = (struct search_path *) xmalloc (sizeof *p); p->path = (char *) xmalloc (path_list - start + 1); memcpy (p->path, start, path_list - start); @@ -3374,32 +3617,33 @@ open_file (file) static char *buffer; static int buffer_size; struct search_path *path; - + int flen = strlen (file) + 1; /* +1 for the slash */ + filename = xstrdup (file); for (path = search_path; path && fp == NULL; path = path->next) { - int len = strlen (path->path); + int len = strlen (path->path) + flen; if (len + 1 >= buffer_size) { buffer_size = max (len + 1, 2 * buffer_size); buffer = (char *) xrealloc (buffer, buffer_size); } - + strcpy (buffer, path->path); strcat (buffer, "/"); strcat (buffer, file); fp = fopen (buffer, "r"); } - + /* Try the original file name. */ if (fp == NULL) fp = fopen (file, "r"); if (fp == NULL) - yyerror ("cannot open"); - + yyerror ("cannot open", NULL); + return fp; } @@ -3409,7 +3653,7 @@ open_file (file) #define USAGE "\ Usage: ebrowse [options] {files}\n\ \n\ - -a, --append append output\n\ + -a, --append append output to existing file\n\ -f, --files=FILES read input file names from FILE\n\ -I, --search-path=LIST set search path for input files\n\ -m, --min-regexp-length=N set minimum regexp length to N\n\ @@ -3430,20 +3674,24 @@ usage (error) int error; { puts (USAGE); - exit (error ? 1 : 0); + exit (error ? EXIT_FAILURE : EXIT_SUCCESS); } /* Display version and copyright info. The VERSION macro is set from the Makefile and contains the Emacs version. */ +#ifndef VERSION +# define VERSION "21" +#endif + void version () { printf ("ebrowse %s\n", VERSION); - puts ("Copyright (C) 1992-1999, 2000 Free Software Foundation, Inc."); + puts ("Copyright (C) 1992-2006 Free Software Foundation, Inc."); puts ("This program is distributed under the same terms as Emacs."); - exit (0); + exit (EXIT_SUCCESS); } @@ -3455,10 +3703,10 @@ process_file (file) char *file; { FILE *fp; - + fp = open_file (file); if (fp) - { + { int nread, nbytes; /* Give a progress indication if needed. */ @@ -3481,12 +3729,14 @@ process_file (file) inbuffer_size = nread + READ_CHUNK_SIZE + 1; inbuffer = (char *) xrealloc (inbuffer, inbuffer_size); } - + nbytes = fread (inbuffer + nread, 1, READ_CHUNK_SIZE, fp); - nread += nbytes; - if (nbytes < READ_CHUNK_SIZE) + if (nbytes <= 0) break; + nread += nbytes; } + if (nread < 0) + nread = 0; inbuffer[nread] = '\0'; /* Reinitialize scanner and parser for the new input file. */ @@ -3522,10 +3772,10 @@ read_line (fp) buffer[i++] = c; } - + if (c == EOF && i == 0) return NULL; - + if (i == buffer_size) { buffer_size = max (100, buffer_size * 2); @@ -3533,6 +3783,8 @@ read_line (fp) } buffer[i] = '\0'; + if (i > 0 && buffer[i - 1] == '\r') + buffer[i - 1] = '\0'; return buffer; } @@ -3563,7 +3815,7 @@ main (argc, argv) case 'p': info_position = atoi (optarg); break; - + case 'n': f_nested_classes = 0; break; @@ -3571,13 +3823,13 @@ main (argc, argv) case 'x': f_regexps = 0; break; - + /* Add the name of a file containing more input files. */ case 'f': if (n_input_files == input_filenames_size) { input_filenames_size = max (10, 2 * input_filenames_size); - input_filenames = (char **) xrealloc (input_filenames, + input_filenames = (char **) xrealloc ((void *)input_filenames, input_filenames_size); } input_filenames[n_input_files++] = xstrdup (optarg); @@ -3646,11 +3898,37 @@ main (argc, argv) /* Open output file */ if (*out_filename) { + if (f_append) + { + /* Check that the file to append to exists, and is not + empty. More specifically, it should be a valid file + produced by a previous run of ebrowse, but that's too + difficult to check. */ + FILE *fp; + int rc; + + fp = fopen (out_filename, "r"); + if (fp == NULL) + yyerror ("file `%s' must exist for --append", out_filename); + + rc = fseek (fp, 0, SEEK_END); + if (rc == -1) + yyerror ("error seeking in file `%s'", out_filename); + + rc = ftell (fp); + if (rc == -1) + yyerror ("error getting size of file `%s'", out_filename); + else if (rc == 0) + yyerror ("file `%s' is empty", out_filename); + + fclose (fp); + } + yyout = fopen (out_filename, f_append ? "a" : "w"); if (yyout == NULL) { yyerror ("cannot open output file `%s'", out_filename); - exit (1); + exit (EXIT_FAILURE); } } @@ -3675,7 +3953,7 @@ main (argc, argv) for (i = 0; i < n_input_files; ++i) { FILE *fp = fopen (input_filenames[i], "r"); - + if (fp == NULL) yyerror ("cannot open input file `%s'", input_filenames[i]); else @@ -3695,8 +3973,10 @@ main (argc, argv) if (yyout != stdout) fclose (yyout); - return 0; + return EXIT_SUCCESS; } +/* arch-tag: fc03b4bc-91a9-4c3d-b3b9-12a77fa86dd8 + (do not change this comment) */ -/* ebrowse.c ends here. */ +/* ebrowse.c ends here */