(socket_connection): Remove AI_ADDRCONFIG.
[bpt/emacs.git] / lib-src / ebrowse.c
index e0f2f5c..ea230a9 100644 (file)
@@ -1,15 +1,13 @@
 /* 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, 2007 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
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GNU Emacs is distributed in the hope that it will be useful,
    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.  */
@@ -272,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.  */
 };
 
@@ -296,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.  */
 };
 
@@ -392,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".  */
 
@@ -413,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.  */
 
@@ -477,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));
@@ -500,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));
@@ -515,6 +532,9 @@ 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 *));
+void usage P_ ((int)) NO_RETURN;
+void version P_ (()) NO_RETURN;
 
 
 \f
@@ -526,20 +546,17 @@ 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);
 }
 
 
 /* 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 *
 xmalloc (nbytes)
@@ -548,8 +565,8 @@ xmalloc (nbytes)
   void *p = malloc (nbytes);
   if (p == NULL)
     {
-      yyerror ("out of memory");
-      exit (1);
+      yyerror ("out of memory", NULL);
+      exit (EXIT_FAILURE);
     }
   return p;
 }
@@ -565,13 +582,24 @@ xrealloc (p, 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.  */
 
@@ -622,7 +650,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)
@@ -664,7 +695,7 @@ add_link (super, sub)
     {
       lnk = (struct link *) xmalloc (sizeof *lnk);
       lnk2 = (struct link *) xmalloc (sizeof *lnk2);
-  
+
       lnk->sym = sub;
       lnk->next = p;
 
@@ -706,15 +737,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;
@@ -906,7 +937,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;
@@ -986,15 +1017,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;
@@ -1068,68 +1099,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;
 }
-  
 
-/* 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;
 }
 
 
@@ -1139,15 +1209,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;
 }
@@ -1204,7 +1276,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;
     }
 }
@@ -1219,7 +1291,7 @@ sym_scope_1 (p)
      struct sym *p;
 {
   int len;
-  
+
   if (p->namesp)
     sym_scope_1 (p->namesp);
 
@@ -1234,14 +1306,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;
 }
 
@@ -1258,10 +1330,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);
 
@@ -1314,13 +1386,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);
@@ -1500,7 +1572,7 @@ process_pp_line ()
          add_define (yytext, regexp, pos);
        }
     }
-  
+
   while (c && (c != '\n' || in_comment || in_string))
     {
       if (c == '\\')
@@ -1517,7 +1589,7 @@ process_pp_line ()
        }
       else if (c == '"')
        in_string = !in_string;
-      
+
       if (c == '\n')
        INCREMENT_LINENO;
 
@@ -1573,9 +1645,9 @@ 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)
@@ -1640,9 +1712,9 @@ 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;
                   break;
 
@@ -1796,7 +1868,7 @@ yylex ()
           else if (c == '.')
             {
               if (GET (c) != '.')
-                yyerror ("invalid token '..' ('...' assumed)");
+                yyerror ("invalid token '..' ('...' assumed)", NULL);
               UNGET ();
               return ELLIPSIS;
             }
@@ -1937,6 +2009,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.  */
@@ -1947,15 +2025,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.  */
@@ -1977,15 +2054,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);
 }
 
@@ -2115,7 +2193,7 @@ re_init_scanner ()
 {
   in = inbuffer;
   yyline = 1;
-  
+
   if (yytext == NULL)
     {
       int size = 256;
@@ -2304,7 +2382,6 @@ skip_to (token)
   return tk;
 }
 
-
 /* Skip over pairs of tokens (parentheses, square brackets,
    angle brackets, curly brackets) matching the current lookahead.  */
 
@@ -2318,19 +2395,19 @@ skip_matching ()
     case '{':
       close = '}';
       break;
-      
+
     case '(':
       close = ')';
       break;
-      
+
     case '<':
       close = '>';
       break;
-      
+
     case '[':
       close = ']';
       break;
-      
+
     default:
       abort ();
     }
@@ -2351,6 +2428,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.  */
 
@@ -2378,7 +2516,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 ();
@@ -2400,7 +2538,7 @@ parm_list (flags)
             {
              char *last_id;
              unsigned ident_type_hash = 0;
-             
+
              parse_qualified_param_ident_or_type (&last_id);
              if (last_id)
                {
@@ -2428,7 +2566,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 ();
@@ -2448,7 +2586,7 @@ parm_list (flags)
   if (LOOKING_AT (')'))
     {
       MATCH ();
-      
+
       if (LOOKING_AT (CONST))
         {
           /* We can overload the same function on `const' */
@@ -2533,7 +2671,7 @@ member (cls, vis)
         case EXPLICIT:
           SET_FLAG (flags, F_EXPLICIT);
           goto typeseen;
-          
+
         case MUTABLE:
           SET_FLAG (flags, F_MUTABLE);
           goto typeseen;
@@ -2572,9 +2710,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 = '~';
@@ -2586,7 +2724,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 '(':
@@ -2616,7 +2758,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;
@@ -2663,7 +2806,7 @@ member (cls, vis)
         {
           regexp = matching_regexp ();
           pos = BUFFER_POS ();
-          
+
           if (cls != NULL)
             {
               if (type_seen || !paren_seen)
@@ -2672,7 +2815,7 @@ member (cls, vis)
                add_member_decl (cls, id, regexp, pos, hash, 0, sc, vis, 0);
             }
         }
-      
+
       MATCH ();
       print_info ();
     }
@@ -2694,6 +2837,8 @@ member (cls, vis)
       skip_matching ();
       print_info ();
     }
+
+  xfree (id);
 }
 
 
@@ -2767,7 +2912,7 @@ struct sym *
 parse_classname ()
 {
   struct sym *last_class = NULL;
-  
+
   while (LOOKING_AT (IDENT))
     {
       last_class = add_sym (yytext, last_class);
@@ -2778,10 +2923,10 @@ parse_classname ()
           skip_matching ();
           SET_FLAG (last_class->flags, F_TEMPLATE);
         }
-      
+
       if (!LOOKING_AT (DCOLON))
         break;
-      
+
       MATCH ();
     }
 
@@ -2801,7 +2946,7 @@ operator_name (sc)
   static char *id = NULL;
   char *s;
   int len;
-  
+
   MATCH ();
 
   if (LOOKING_AT2 (NEW, DELETE))
@@ -2812,7 +2957,7 @@ operator_name (sc)
 
       s = token_string (LA1);
       MATCH ();
-      
+
       len = strlen (s) + 10;
       if (len > id_size)
        {
@@ -2822,12 +2967,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, "]");
@@ -2869,7 +3014,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;
@@ -2881,7 +3026,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 *
@@ -2889,9 +3034,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;
@@ -2908,20 +3054,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
@@ -2982,7 +3153,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 ();
@@ -3001,7 +3172,7 @@ class_definition (containing, tag, flags, nested)
         {
           switch (LA1)
             {
-            case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE: 
+            case VIRTUAL: case PUBLIC: case PROTECTED: case PRIVATE:
               MATCH ();
               break;
 
@@ -3063,6 +3234,54 @@ 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.  */
 
@@ -3095,7 +3314,7 @@ declaration (flags)
           sc = SC_TYPE;
           MATCH ();
           break;
-          
+
         case STATIC:
           sc = SC_STATIC;
           MATCH ();
@@ -3111,16 +3330,27 @@ declaration (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:
@@ -3132,7 +3362,7 @@ declaration (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 ();
@@ -3194,43 +3424,14 @@ declaration (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);
 }
 
 
@@ -3250,7 +3451,7 @@ globals (start_flags)
   for (;;)
     {
       char *prev_in = in;
-      
+
       switch (LA1)
         {
         case NAMESPACE:
@@ -3259,16 +3460,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 ('{'))
                   {
@@ -3278,6 +3480,8 @@ globals (start_flags)
                     leave_namespace ();
                     MATCH_IF ('}');
                   }
+
+               xfree (namespace_name);
               }
           }
           break;
@@ -3289,7 +3493,7 @@ globals (start_flags)
             {
               /* This is `extern "C"'.  */
               MATCH ();
-              
+
               if (LOOKING_AT ('{'))
                 {
                   MATCH ();
@@ -3300,7 +3504,7 @@ globals (start_flags)
                 SET_FLAG (flags, F_EXTERNC);
             }
           break;
-          
+
         case TEMPLATE:
           MATCH ();
           SKIP_MATCHING_IF ('<');
@@ -3340,7 +3544,7 @@ globals (start_flags)
 
         case '}':
           return 0;
-          
+
         default:
           declaration (flags);
           flags = start_flags;
@@ -3348,7 +3552,7 @@ globals (start_flags)
         }
 
       if (prev_in == in)
-        yyerror ("parse error");
+        yyerror ("parse error", NULL);
     }
 }
 
@@ -3379,10 +3583,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);
@@ -3416,7 +3620,7 @@ open_file (file)
   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)
@@ -3428,20 +3632,20 @@ open_file (file)
          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;
 }
 
@@ -3451,7 +3655,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\
@@ -3472,20 +3676,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-2007 Free Software Foundation, Inc.");
   puts ("This program is distributed under the same terms as Emacs.");
-  exit (0);
+  exit (EXIT_SUCCESS);
 }
 
 
@@ -3497,10 +3705,10 @@ process_file (file)
      char *file;
 {
   FILE *fp;
-  
+
   fp = open_file (file);
   if (fp)
-    {      
+    {
       int nread, nbytes;
 
       /* Give a progress indication if needed.  */
@@ -3523,7 +3731,7 @@ 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);
          if (nbytes <= 0)
            break;
@@ -3566,10 +3774,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);
@@ -3577,6 +3785,8 @@ read_line (fp)
     }
 
   buffer[i] = '\0';
+  if (i > 0 && buffer[i - 1] == '\r')
+    buffer[i - 1] = '\0';
   return buffer;
 }
 
@@ -3607,7 +3817,7 @@ main (argc, argv)
        case 'p':
          info_position = atoi (optarg);
          break;
-         
+
         case 'n':
           f_nested_classes = 0;
           break;
@@ -3615,13 +3825,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);
@@ -3690,11 +3900,51 @@ 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);
+             exit (EXIT_FAILURE);
+           }
+
+         rc = fseek (fp, 0, SEEK_END);
+         if (rc == -1)
+           {
+             yyerror ("error seeking in file `%s'", out_filename);
+             exit (EXIT_FAILURE);
+           }
+
+         rc = ftell (fp);
+         if (rc == -1)
+           {
+             yyerror ("error getting size of file `%s'", out_filename);
+             exit (EXIT_FAILURE);
+           }
+         
+         else if (rc == 0)
+           {
+             yyerror ("file `%s' is empty", out_filename);
+             /* It may be ok to use an empty file for appending.
+                exit (EXIT_FAILURE); */
+           }
+
+         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);
        }
     }
 
@@ -3719,7 +3969,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
@@ -3739,8 +3989,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 */