/* ebrowse.c --- parsing files for the ebrowse C++ browser
- Copyright (C) 1992-1999, 2000 Free Software Foundation Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99,
+ 2000, 2001, 2002 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, 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"
-#ifdef HAVE_CONFIG_H
-#include <config.h>
+/* The SunOS compiler doesn't have SEEK_END. */
+#ifndef SEEK_END
+#define SEEK_END 2
#endif
/* Conditionalize function prototypes. */
/* 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. */
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. */
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));
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);
}
void *p = malloc (nbytes);
if (p == NULL)
{
- yyerror ("out of memory");
+ yyerror ("out of memory", NULL);
exit (1);
}
return p;
p = realloc (p, sz);
if (p == NULL)
{
- yyerror ("out of memory");
+ yyerror ("out of memory", NULL);
exit (1);
}
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. */
{
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;
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;
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;
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;
if (!found)
{
if (!global_symbols->filename
- || !streq (global_symbols->filename, filename))
+ || !FILENAME_EQ (global_symbols->filename, filename))
m->filename = filename;
m->regexp = regexp;
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 *) 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 *) 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 **) 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;
}
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;
}
}
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;
}
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);
{
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;
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 *) 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. */
/* 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);
}
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 "???";
+ }
}
{
in = inbuffer;
yyline = 1;
-
+
if (yytext == NULL)
{
int size = 256;
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. */
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 ();
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)
{
}
strcpy (id, s);
- /* Vector new or delete? */
+ /* Vector new or delete? */
if (LOOKING_AT ('['))
{
strcat (id, "[");
MATCH ();
-
+
if (LOOKING_AT (']'))
{
strcat (id, "]");
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 (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
struct sym *cls = NULL;
static char *id = NULL;
static int id_size = 0;
-
+
while (LOOKING_AT (IDENT))
{
int len = strlen (yytext) + 1;
}
}
+/* 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 *) xmalloc (sizeof *p);
p->path = (char *) xmalloc (path_list - start + 1);
memcpy (p->path, start, path_list - start);
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;
}
#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\
/* 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-1999, 2000, 2001 Free Software Foundation, Inc.");
puts ("This program is distributed under the same terms as Emacs.");
exit (0);
}
char *file;
{
FILE *fp;
-
+
fp = open_file (file);
if (fp)
- {
+ {
int nread, nbytes;
/* Give a progress indication if needed. */
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. */
buffer[i++] = c;
}
-
+
if (c == EOF && i == 0)
return NULL;
-
+
if (i == buffer_size)
{
buffer_size = max (100, buffer_size * 2);
}
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 **) xrealloc (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)
{
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