/* 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 <gerd@gnu.org>
- Maintainer: FSF
-
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
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 <config.h>
#endif
#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
#include <string.h>
+#endif
+
#include <ctype.h>
#include <assert.h>
#include "getopt.h"
+/* The SunOS compiler doesn't have SEEK_END. */
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
/* Conditionalize function prototypes. */
#ifdef PROTOTYPES /* From config.h. */
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. */
};
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. */
};
#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". */
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. */
void add_member_decl P_ ((struct sym *, char *, char *, int,
unsigned, int, int, int, int));
void dump_roots P_ ((FILE *));
-void *ymalloc P_ ((int));
+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));
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));
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 *));
\f
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);
}
/* Like malloc but print an error and exit if not enough memory is
- available. This isn't called `xmalloc' because src/m/alpha.h,
- and maybe others, contain an incompatible prototype for xmalloc
- and xrealloc. */
+ available. */
void *
-ymalloc (nbytes)
+xmalloc (nbytes)
int nbytes;
{
void *p = malloc (nbytes);
if (p == NULL)
{
- yyerror ("out of memory");
- exit (1);
+ yyerror ("out of memory", NULL);
+ exit (EXIT_FAILURE);
}
return p;
}
/* Like realloc but print an error and exit if out of memory. */
void *
-yrealloc (p, sz)
+xrealloc (p, sz)
void *p;
int sz;
{
p = realloc (p, sz);
if (p == NULL)
{
- yyerror ("out of memory");
- exit (1);
+ 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)
+ free (p);
+}
+
+
/* Like strdup, but print an error and exit if not enough memory is
available.. If S is null, return null. */
char *s;
{
if (s)
- s = strcpy (ymalloc (strlen (s) + 1), s);
+ s = strcpy (xmalloc (strlen (s) + 1), s);
return s;
}
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)
puts (name);
}
- sym = (struct sym *) ymalloc (sizeof *sym + strlen (name));
+ sym = (struct sym *) xmalloc (sizeof *sym + strlen (name));
bzero (sym, sizeof *sym);
strcpy (sym->name, name);
sym->namesp = scope;
/* Avoid duplicates. */
if (p == NULL || p->sym != sub)
{
- lnk = (struct link *) ymalloc (sizeof *lnk);
- lnk2 = (struct link *) ymalloc (sizeof *lnk2);
-
+ lnk = (struct link *) xmalloc (sizeof *lnk);
+ lnk2 = (struct link *) xmalloc (sizeof *lnk2);
+
lnk->sym = sub;
lnk->next = p;
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;
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;
int sc;
unsigned hash;
{
- struct member *m = (struct member *) ymalloc (sizeof *m + strlen (name));
+ struct member *m = (struct member *) xmalloc (sizeof *m + strlen (name));
struct member **list;
struct member *p;
struct member *prev;
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;
/* 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 *) ymalloc (sizeof *s + strlen (name));
+ 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;
}
-
-/* Register the name NEW_NAME as an alias for namespace OLD_NAME. */
+
+/* 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 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 *) ymalloc (sizeof *al + strlen (new_name));
+ 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;
}
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 **) yrealloc (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;
}
if (scope_buffer_len + len >= scope_buffer_size)
{
int new_size = max (2 * scope_buffer_size, scope_buffer_len + len);
- scope_buffer = (char *) yrealloc (new_size);
+ scope_buffer = (char *) xrealloc (scope_buffer, new_size);
scope_buffer_size = new_size;
}
}
struct sym *p;
{
int len;
-
+
if (p->namesp)
sym_scope_1 (p->namesp);
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;
}
if (!scope_buffer)
{
scope_buffer_size = 1024;
- scope_buffer = (char *) ymalloc (scope_buffer_size);
+ scope_buffer = (char *) xmalloc (scope_buffer_size);
}
-
+
*scope_buffer = '\0';
scope_buffer_len = 0;
-
+
if (p->namesp)
sym_scope_1 (p->namesp);
{
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);
int
process_pp_line ()
{
- int in_comment = 0;
+ int in_comment = 0, in_string = 0;
int c;
char *p = yytext;
add_define (yytext, regexp, pos);
}
}
-
- while (c && (c != '\n' || in_comment))
+
+ while (c && (c != '\n' || in_comment || in_string))
{
if (c == '\\')
GET (c);
if (GET (c) == '/')
in_comment = 0;
}
-
+ else if (c == '"')
+ in_string = !in_string;
+
if (c == '\n')
INCREMENT_LINENO;
GET (c);
}
-
+
return c;
}
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':
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;
if (p == yytext_end - 1)
{
int size = yytext_end - yytext;
- yytext = (char *) yrealloc (yytext, 2 * size);
+ yytext = (char *) xrealloc (yytext, 2 * size);
yytext_end = yytext + 2 * size;
p = yytext + size - 1;
}
else if (c == '.')
{
if (GET (c) != '.')
- yyerror ("invalid token '..' ('...' assumed)");
+ yyerror ("invalid token '..' ('...' assumed)", NULL);
UNGET ();
return ELLIPSIS;
}
}
+/* 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. */
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 *) ymalloc (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. */
/* 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);
}
{
in = inbuffer;
yyline = 1;
-
+
if (yytext == NULL)
{
int size = 256;
- yytext = (char *) ymalloc (size * sizeof *yytext);
+ yytext = (char *) xmalloc (size * sizeof *yytext);
yytext_end = yytext + size;
}
}
{
char *s;
unsigned h = 0;
- struct kw *k = (struct kw *) ymalloc (sizeof *k);
+ struct kw *k = (struct kw *) xmalloc (sizeof *k);
for (s = name; *s; ++s)
h = (h << 1) ^ *s;
/* Allocate the input buffer */
inbuffer_size = READ_CHUNK_SIZE + 1;
- inbuffer = in = (char *) ymalloc (inbuffer_size);
+ inbuffer = in = (char *) xmalloc (inbuffer_size);
yyline = 1;
/* Set up character class vectors. */
return tk;
}
-
/* Skip over pairs of tokens (parentheses, square brackets,
angle brackets, curly brackets) matching the current lookahead. */
case '{':
close = '}';
break;
-
+
case '(':
close = ')';
break;
-
+
case '<':
close = '>';
break;
-
+
case '[':
close = ']';
break;
-
+
default:
abort ();
}
}
}
+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. */
{
switch (LA1)
{
- /* Skip over grouping parens or parameter lists in parameter
+ /* Skip over grouping parens or parameter lists in parameter
declarations. */
case '(':
skip_matching ();
{
char *last_id;
unsigned ident_type_hash = 0;
-
+
parse_qualified_param_ident_or_type (&last_id);
if (last_id)
{
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 ();
if (LOOKING_AT (')'))
{
MATCH ();
-
+
if (LOOKING_AT (CONST))
{
/* We can overload the same function on `const' */
case EXPLICIT:
SET_FLAG (flags, F_EXPLICIT);
goto typeseen;
-
+
case MUTABLE:
SET_FLAG (flags, F_MUTABLE);
goto typeseen;
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 = '~';
break;
case OPERATOR:
- id = operator_name (&sc);
+ {
+ char *s = operator_name (&sc);
+ id = (char *) xrealloc (id, strlen (s) + 1);
+ strcpy (id, s);
+ }
break;
case '(':
if (LOOKING_AT ('{') && id && cls)
add_member_defn (cls, id, regexp, pos, hash, 0, sc, flags);
-
+
+ xfree (id);
id = NULL;
sc = SC_MEMBER;
break;
{
regexp = matching_regexp ();
pos = BUFFER_POS ();
-
+
if (cls != NULL)
{
if (type_seen || !paren_seen)
add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, 0);
}
}
-
+
MATCH ();
print_info ();
}
skip_matching ();
print_info ();
}
+
+ xfree (id);
}
parse_classname ()
{
struct sym *last_class = NULL;
-
+
while (LOOKING_AT (IDENT))
{
last_class = add_sym (yytext, last_class);
skip_matching ();
SET_FLAG (last_class->flags, F_TEMPLATE);
}
-
+
if (!LOOKING_AT (DCOLON))
break;
-
+
MATCH ();
}
static char *id = NULL;
char *s;
int len;
-
+
MATCH ();
if (LOOKING_AT2 (NEW, DELETE))
s = token_string (LA1);
MATCH ();
-
+
len = strlen (s) + 10;
if (len > id_size)
{
int new_size = max (len, 2 * id_size);
- id = (char *) yrealloc (id, new_size);
+ id = (char *) xrealloc (id, new_size);
id_size = new_size;
}
strcpy (id, s);
- /* Vector new or delete? */
+ /* Vector new or delete? */
if (LOOKING_AT ('['))
{
strcat (id, "[");
MATCH ();
-
+
if (LOOKING_AT (']'))
{
strcat (id, "]");
if (len > id_size)
{
int new_size = max (len, 2 * id_size);
- id = (char *) yrealloc (id, new_size);
+ id = (char *) xrealloc (id, new_size);
id_size = new_size;
}
strcpy (id, "operator");
if (len > id_size)
{
int new_size = max (len, 2 * id_size);
- id = (char *) yrealloc (id, new_size);
+ id = (char *) xrealloc (id, new_size);
id_size = new_size;
}
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;
/* 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 *
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;
if (len > id_size)
{
- id = (char *) yrealloc (id, len);
+ id = (char *) xrealloc (id, len);
id_size = len;
}
strcpy (id, yytext);
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
int len = strlen (yytext) + 1;
if (len > id_size)
{
- id = (char *) yrealloc (id, len);
+ id = (char *) xrealloc (id, len);
id_size = len;
}
strcpy (id, yytext);
settings. */
if ((tag != CLASS && !f_structs) || (nested && !f_nested_classes))
current = NULL;
- else
+ else
{
current = add_sym (yytext, containing);
current->pos = BUFFER_POS ();
{
switch (LA1)
{
- case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE:
+ case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE:
MATCH ();
break;
}
}
+/* 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. */
sc = SC_TYPE;
MATCH ();
break;
-
+
case STATIC:
sc = SC_STATIC;
MATCH ();
/* 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:
MATCH ();
if (LOOKING_AT (IDENT))
{
- id = (char *) alloca (strlen (yytext) + 2);
+ id = (char *) xrealloc (id, strlen (yytext) + 2);
*id = '~';
strcpy (id + 1, yytext);
MATCH ();
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);
}
for (;;)
{
char *prev_in = in;
-
+
switch (LA1)
{
case NAMESPACE:
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 ('{'))
{
leave_namespace ();
MATCH_IF ('}');
}
+
+ xfree (namespace_name);
}
}
break;
{
/* This is `extern "C"'. */
MATCH ();
-
+
if (LOOKING_AT ('{'))
{
MATCH ();
SET_FLAG (flags, F_EXTERNC);
}
break;
-
+
case TEMPLATE:
MATCH ();
SKIP_MATCHING_IF ('<');
case '}':
return 0;
-
+
default:
declaration (flags);
flags = start_flags;
}
if (prev_in == in)
- yyerror ("parse error");
+ yyerror ("parse error", NULL);
}
}
{
char *start = path_list;
struct search_path *p;
-
+
while (*path_list && *path_list != PATH_LIST_SEPARATOR)
++path_list;
-
- p = (struct search_path *) ymalloc (sizeof *p);
- p->path = (char *) ymalloc (path_list - start + 1);
+
+ p = (struct search_path *) xmalloc (sizeof *p);
+ p->path = (char *) xmalloc (path_list - start + 1);
memcpy (p->path, start, path_list - start);
p->path[path_list - start] = '\0';
p->next = NULL;
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)
if (len + 1 >= buffer_size)
{
buffer_size = max (len + 1, 2 * buffer_size);
- buffer = (char *) yrealloc (buffer, 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;
}
#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\
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);
}
char *file;
{
FILE *fp;
-
+
fp = open_file (file);
if (fp)
- {
+ {
int nread, nbytes;
/* Give a progress indication if needed. */
if (nread + READ_CHUNK_SIZE >= inbuffer_size)
{
inbuffer_size = nread + READ_CHUNK_SIZE + 1;
- inbuffer = (char *) yrealloc (inbuffer, inbuffer_size);
+ inbuffer = (char *) xrealloc (inbuffer, inbuffer_size);
}
-
+
nbytes = fread (inbuffer + nread, 1, READ_CHUNK_SIZE, fp);
if (nbytes <= 0)
break;
if (i >= buffer_size)
{
buffer_size = max (100, buffer_size * 2);
- buffer = (char *) yrealloc (buffer, buffer_size);
+ buffer = (char *) xrealloc (buffer, buffer_size);
}
buffer[i++] = c;
}
-
+
if (c == EOF && i == 0)
return NULL;
-
+
if (i == buffer_size)
{
buffer_size = max (100, buffer_size * 2);
- buffer = (char *) yrealloc (buffer, buffer_size);
+ buffer = (char *) xrealloc (buffer, buffer_size);
}
buffer[i] = '\0';
+ if (i > 0 && buffer[i - 1] == '\r')
+ buffer[i - 1] = '\0';
return buffer;
}
case 'p':
info_position = atoi (optarg);
break;
-
+
case 'n':
f_nested_classes = 0;
break;
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 **) yrealloc (input_filenames,
+ input_filenames = (char **) xrealloc ((void *)input_filenames,
input_filenames_size);
}
input_filenames[n_input_files++] = xstrdup (optarg);
/* 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);
}
}
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
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 */