diff GEMBASSY-1.0.3/gsoap/wsdl/types.cpp @ 0:8300eb051bea draft

Initial upload
author ktnyt
date Fri, 26 Jun 2015 05:19:29 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GEMBASSY-1.0.3/gsoap/wsdl/types.cpp	Fri Jun 26 05:19:29 2015 -0400
@@ -0,0 +1,3289 @@
+/*
+	types.cpp
+
+	Generate gSOAP types from XML schemas (e.g. embedded in WSDL).
+
+--------------------------------------------------------------------------------
+gSOAP XML Web services tools
+Copyright (C) 2001-2013, Robert van Engelen, Genivia Inc. All Rights Reserved.
+This software is released under one of the following licenses:
+GPL or Genivia's license for commercial use.
+--------------------------------------------------------------------------------
+GPL license.
+
+This program 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 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+Author contact information:
+engelen@genivia.com / engelen@acm.org
+--------------------------------------------------------------------------------
+A commercial use license is available from Genivia, Inc., contact@genivia.com
+--------------------------------------------------------------------------------
+
+*/
+
+#include "types.h"
+
+static char *getline(char *s, size_t n, FILE *fd);
+static const char *nonblank(const char *s);
+static const char *fill(char *t, int n, const char *s, int e);
+static const char *utf8(char *t, const char *s);
+static const char *cstring(const char *s);
+static const char *xstring(const char *s);
+static bool is_integer(const char *s);
+static LONG64 to_integer(const char *s);
+static void documentation(const char *text);
+static void operations(const char *t);
+
+static int comment_nest = 0; /* keep track of block comments to avoid nesting */
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Keywords and reserved words
+//
+////////////////////////////////////////////////////////////////////////////////
+
+static const char *keywords[] =
+{ "and",
+  "asm",
+  "auto",
+  "bool",
+  "break",
+  "case",
+  "catch",
+  "char",
+  "class",
+  "const",
+  "const_cast",
+  "continue",
+  "default",
+  "delete",
+  "do",
+  "double",
+  "dynamic_cast",
+  "else",	
+  "enum",
+  "errno",
+  "explicit",
+  "export",
+  "extern",
+  "false",
+  "FILE",
+  "float",
+  "for",
+  "friend",
+  "goto",
+  "if",
+  "inline",
+  "int",
+  "interface",
+  "long",
+  "LONG64",
+  "max",
+  "min",
+  "mustUnderstand",
+  "mutable",
+  "namespace",
+  "new",
+  "not",
+  "NULL",
+  "operator",
+  "or",
+  "private",
+  "protected",
+  "public",
+  "_QName",
+  "register",
+  "reinterpret_cast",
+  "restrict",
+  "return",
+  "short",
+  "signed",
+  "size_t",
+  "sizeof",
+  "soap",
+  "static",
+  "static_cast",
+  "struct",
+  "switch",
+  "template",
+  "this",
+  "throw",
+  "time_t",
+  "true",
+  "typedef",
+  "typeid",
+  "typeof",
+  "typename",
+  "ULONG64",
+  "union",
+  "unsigned",
+  "using",
+  "virtual",
+  "void",
+  "volatile",
+  "wchar_t",
+  "while",
+  "XML",
+  "_XML",
+  "xor",
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Types methods
+//
+////////////////////////////////////////////////////////////////////////////////
+
+Types::Types()
+{ init();
+}
+
+int Types::read(const char *file)
+{ FILE *fd;
+  char buf[1024], xsd[1024], def[1024], use[1024], ptr[1024], uri[1024];
+  const char *s;
+  short copy = 0;
+  strcpy(buf, file);
+  fd = fopen(buf, "r");
+  if (!fd && import_path)
+  { strcpy(buf, import_path);
+    strcat(buf, "/");
+    strcat(buf, file);
+    fd = fopen(buf, "r");
+  }
+  if (!fd)
+  { fprintf(stderr, "Cannot open file '%s'\n", buf);
+    return SOAP_EOF;
+  }
+  fprintf(stderr, "Reading type definitions from type map file '%s'\n", buf);
+  while (getline(buf, sizeof(buf), fd))
+  { s = buf;
+    if (copy)
+    { if (*s == ']')
+        copy = 0;
+      else
+        fprintf(stream, "%s\n", buf);
+    }
+    else if (*s == '[')
+      copy = 1;
+    else if (*s == '<')
+    { s = fill(uri, sizeof(uri), s+1, -1);
+      infile[infiles++] = estrdup(uri);
+      if (infiles >= MAXINFILES)
+      { fprintf(stderr, "wsdl2h: too many files\n");
+        exit(1);
+      }
+    }
+    else if (*s == '>')
+    { s = fill(uri, sizeof(uri), s+1, -1);
+      if (!outfile)
+      { outfile = estrdup(uri);
+        stream = fopen(outfile, "w");
+        if (!stream)
+        { fprintf(stderr, "Cannot write to %s\n", outfile);
+          exit(1);
+        }
+        if (cppnamespace)
+          fprintf(stream, "namespace %s {\n", cppnamespace);
+        fprintf(stderr, "Saving %s\n\n", outfile);
+      }
+    }
+    else if (*s && *s != '#')
+    { s = fill(xsd, sizeof(xsd), s, '=');
+      if (strstr(xsd, "__"))
+      { if (s && *s == '=')
+        { s = fill(use, sizeof(use), s+1, '|');
+          if (*xsd && *use)
+          { s = estrdup(xsd);
+            eqvtypemap[s] = estrdup(use);
+          }
+        }
+        else
+        { s = fill(def, sizeof(def), s, '|');
+          s = fill(use, sizeof(use), s, '|');
+          s = fill(ptr, sizeof(ptr), s, '|');
+          if (*xsd)
+          { s = estrdup(xsd);
+            if (*def == '$')
+            { const char *t = modtypemap[s];
+              if (t)
+              { char *r = (char*)emalloc(strlen(t) + strlen(def) + 1);
+                strcpy(r, t);
+                strcat(r, def);
+                free((void*)modtypemap[s]);
+                modtypemap[s] = r;
+              }
+              else
+                modtypemap[s] = estrdup(def);
+            }
+            else
+            { if (*def)
+              { if (strcmp(def, "..."))
+                  deftypemap[s] = estrdup(def);
+              }
+              else
+                deftypemap[s] = "";
+              if (*use)
+                usetypemap[s] = estrdupf(use);
+              else
+                usetypemap[s] = estrdupf(xsd);
+              if (*ptr)
+                ptrtypemap[s] = estrdupf(ptr);
+            }
+          }
+        }
+      }
+      else if (*xsd)
+      { s = fill(uri, sizeof(uri), s, 0);
+        if (uri[0] == '"')
+        { uri[strlen(uri) - 1] = '\0';
+          nsprefix(xsd, estrdup(uri + 1));
+        }
+        else if (uri[0] == '<')
+        { uri[strlen(uri) - 1] = '\0';
+          char *s = estrdup(uri + 1);
+          nsprefix(xsd, s);
+          exturis.insert(s);
+        }
+        else
+          nsprefix(xsd, estrdup(uri));
+      }
+    }
+  }
+  fclose(fd);
+  return SOAP_OK;
+}
+
+void Types::init()
+{ snum = 1;
+  unum = 1;
+  gnum = 1;
+  with_union = false;
+  fake_union = false;
+  knames.insert(keywords, keywords + sizeof(keywords)/sizeof(char*));
+  if (cflag)
+  { deftypemap["xsd__ur_type"] = "";
+    if (dflag)
+    { usetypemap["xsd__ur_type"] = "xsd__anyType";
+      ptrtypemap["xsd__ur_type"] = "xsd__anyType*";
+    }
+    else
+    { usetypemap["xsd__ur_type"] = "_XML";
+      ptrtypemap["xsd__ur_type"] = "_XML";
+    }
+  }
+  else
+  { deftypemap["xsd__ur_type"] = "class xsd__ur_type { _XML __item; struct soap *soap; };";
+    usetypemap["xsd__ur_type"] = "xsd__ur_type";
+  }
+  if (cflag)
+  { deftypemap["xsd__anyType"] = "";
+    if (dflag)
+    { usetypemap["xsd__anyType"] = "xsd__anyType";
+      ptrtypemap["xsd__anyType"] = "xsd__anyType*";
+    }
+    else
+    { usetypemap["xsd__anyType"] = "_XML";
+      ptrtypemap["xsd__anyType"] = "_XML";
+    }
+  }
+  else
+  { if (dflag)
+    { deftypemap["xsd__anyType"] = "";
+      usetypemap["xsd__anyType"] = "xsd__anyType";
+      ptrtypemap["xsd__anyType"] = "xsd__anyType*";
+    }
+    else
+    { deftypemap["xsd__anyType"] = "class xsd__anyType { _XML __item; struct soap *soap; };";
+      usetypemap["xsd__anyType"] = "xsd__anyType*";
+    }
+  }
+  deftypemap["xsd__any"] = "";
+  if (dflag)
+  { usetypemap["xsd__any"] = "xsd__anyType";
+    ptrtypemap["xsd__any"] = "xsd__anyType*";
+  }
+  else
+  { usetypemap["xsd__any"] = "_XML";
+    ptrtypemap["xsd__any"] = "_XML";
+  }
+  deftypemap["xsd__anyAttribute"] = "";
+  if (dflag)
+  { usetypemap["xsd__anyAttribute"] = "xsd__anyAttribute";
+    ptrtypemap["xsd__anyAttribute"] = "xsd__anyAttribute*";
+  }
+  else
+  { usetypemap["xsd__anyAttribute"] = "_XML";
+    ptrtypemap["xsd__anyAttribute"] = "_XML";
+  }
+  if (cflag)
+  { deftypemap["xsd__base64Binary"] = "struct xsd__base64Binary\n{\tunsigned char *__ptr;\n\tint __size;\n\tchar *id, *type, *options; // NOTE: non-NULL for DIMEM/MIME/MTOM XOP attachments only\n};";
+    usetypemap["xsd__base64Binary"] = "struct xsd__base64Binary";
+  }
+  else
+  { deftypemap["xsd__base64Binary"] = "class xsd__base64Binary\n{\tunsigned char *__ptr;\n\tint __size;\n\tchar *id, *type, *options; // NOTE: non-NULL for DIMEM/MIME/MTOM XOP attachments only\n\tstruct soap *soap;\n};";
+    usetypemap["xsd__base64Binary"] = "xsd__base64Binary";
+  }
+  if (cflag)
+  { if (eflag)
+      deftypemap["xsd__boolean"] = "enum xsd__boolean { false_, true_ };";
+    else
+      deftypemap["xsd__boolean"] = "enum xsd__boolean { xsd__boolean__false_, xsd__boolean__true_ };";
+    usetypemap["xsd__boolean"] = "enum xsd__boolean";
+  }
+  else
+  { deftypemap["xsd__boolean"] = "";
+    usetypemap["xsd__boolean"] = "bool";
+  }
+  deftypemap["xsd__byte"] = "typedef char xsd__byte;";
+  usetypemap["xsd__byte"] = "xsd__byte";
+  deftypemap["xsd__dateTime"] = "";
+  usetypemap["xsd__dateTime"] = "time_t";
+  deftypemap["xsd__double"] = "";
+  usetypemap["xsd__double"] = "double";
+  deftypemap["xsd__float"] = "";
+  usetypemap["xsd__float"] = "float";
+  if (cflag)
+  { deftypemap["xsd__hexBinary"] = "struct xsd__hexBinary { unsigned char *__ptr; int __size; };";
+    usetypemap["xsd__hexBinary"] = "struct xsd__hexBinary";
+  }
+  else
+  { deftypemap["xsd__hexBinary"] = "class xsd__hexBinary { unsigned char *__ptr; int __size; };";
+    usetypemap["xsd__hexBinary"] = "xsd__hexBinary";
+  }
+  deftypemap["xsd__int"] = "";
+  usetypemap["xsd__int"] = "int";
+  deftypemap["xsd__long"] = "";
+  usetypemap["xsd__long"] = "LONG64";
+  deftypemap["xsd__short"] = "";
+  usetypemap["xsd__short"] = "short";
+  if (cflag || sflag)
+  { deftypemap["xsd__string"] = "";
+    usetypemap["xsd__string"] = "char*";
+  }
+  else
+  { deftypemap["xsd__string"] = "";
+    usetypemap["xsd__string"] = "std::string";
+  }
+  if (cflag || sflag)
+  { deftypemap["xsd__QName"] = "";
+    usetypemap["xsd__QName"] = "_QName";
+    ptrtypemap["xsd__QName"] = "_QName";
+  }
+  else
+  { deftypemap["xsd__QName"] = "typedef std::string xsd__QName;";
+    usetypemap["xsd__QName"] = "xsd__QName";
+  }
+  deftypemap["xsd__unsignedByte"] = "typedef unsigned char xsd__unsignedByte;";
+  usetypemap["xsd__unsignedByte"] = "xsd__unsignedByte";
+  deftypemap["xsd__unsignedInt"] = "";
+  usetypemap["xsd__unsignedInt"] = "unsigned int";
+  deftypemap["xsd__unsignedLong"] = "";
+  usetypemap["xsd__unsignedLong"] = "ULONG64";
+  deftypemap["xsd__unsignedShort"] = "";
+  usetypemap["xsd__unsignedShort"] = "unsigned short";
+  if (cflag)
+  { deftypemap["SOAP_ENC__base64Binary"] = "struct SOAP_ENC__base64Binary { unsigned char *__ptr; int __size; };";
+    usetypemap["SOAP_ENC__base64Binary"] = "struct SOAP_ENC__base64Binary";
+    deftypemap["SOAP_ENC__base64"] = "struct SOAP_ENC__base64 { unsigned char *__ptr; int __size; };";
+    usetypemap["SOAP_ENC__base64"] = "struct SOAP_ENC__base64";
+  }
+  else
+  { deftypemap["SOAP_ENC__base64Binary"] = "class SOAP_ENC__base64Binary { unsigned char *__ptr; int __size; };";
+    usetypemap["SOAP_ENC__base64Binary"] = "SOAP_ENC__base64Binary";
+    deftypemap["SOAP_ENC__base64"] = "class SOAP_ENC__base64 { unsigned char *__ptr; int __size; };";
+    usetypemap["SOAP_ENC__base64"] = "SOAP_ENC__base64";
+  }
+  if (cflag)
+  { deftypemap["SOAP_ENC__boolean"] = "enum SOAP_ENC__boolean { false_, true_ };";
+    usetypemap["SOAP_ENC__boolean"] = "enum SOAP_ENC__boolean";
+  }
+  else
+  { deftypemap["SOAP_ENC__boolean"] = "typedef bool SOAP_ENC__boolean;";
+    usetypemap["SOAP_ENC__boolean"] = "SOAP_ENC__boolean";
+  }
+  deftypemap["SOAP_ENC__byte"] = "typedef char SOAP_ENC__byte;";
+  usetypemap["SOAP_ENC__byte"] = "SOAP_ENC__byte";
+  deftypemap["SOAP_ENC__dateTime"] = "typedef time_t SOAP_ENC__dateTime;";
+  usetypemap["SOAP_ENC__dateTime"] = "SOAP_ENC__dateTime";
+  deftypemap["SOAP_ENC__double"] = "typedef double SOAP_ENC__double;";
+  usetypemap["SOAP_ENC__double"] = "SOAP_ENC__double";
+  deftypemap["SOAP_ENC__float"] = "typedef float SOAP_ENC__float";
+  usetypemap["SOAP_ENC__float"] = "SOAP_ENC__float";
+  if (cflag)
+  { deftypemap["SOAP_ENC__hexBinary"] = "struct SOAP_ENC__hexBinary { unsigned char *__ptr; int __size; };";
+    usetypemap["SOAP_ENC__hexBinary"] = "struct SOAP_ENC__hexBinary";
+  }
+  else
+  { deftypemap["SOAP_ENC__hexBinary"] = "class SOAP_ENC__hexBinary { unsigned char *__ptr; int __size; };";
+    usetypemap["SOAP_ENC__hexBinary"] = "SOAP_ENC__hexBinary";
+  }
+  deftypemap["SOAP_ENC__int"] = "typedef int SOAP_ENC__int;";
+  usetypemap["SOAP_ENC__int"] = "SOAP_ENC__int";
+  deftypemap["SOAP_ENC__long"] = "typedef LONG64 SOAP_ENC__long;";
+  usetypemap["SOAP_ENC__long"] = "SOAP_ENC__long";
+  deftypemap["SOAP_ENC__short"] = "typedef short SOAP_ENC__short;";
+  usetypemap["SOAP_ENC__short"] = "SOAP_ENC__short";
+  if (cflag || sflag)
+  { deftypemap["SOAP_ENC__string"] = "";
+    usetypemap["SOAP_ENC__string"] = "char*";
+  }
+  else
+  { deftypemap["SOAP_ENC__string"] = "";
+    usetypemap["SOAP_ENC__string"] = "std::string";
+  }
+  deftypemap["SOAP_ENC__unsignedByte"] = "typedef unsigned char SOAP_ENC__unsignedByte;";
+  usetypemap["SOAP_ENC__unsignedByte"] = "SOAP_ENC__unsignedByte";
+  deftypemap["SOAP_ENC__unsignedInt"] = "typedef unsigned int SOAP_ENC__unsignedInt;";
+  usetypemap["SOAP_ENC__unsignedInt"] = "SOAP_ENC__unsignedInt";
+  deftypemap["SOAP_ENC__unsignedLong"] = "typedef ULONG64 SOAP_ENC__unsignedLong;";
+  usetypemap["SOAP_ENC__unsignedLong"] = "SOAP_ENC__unsignedLong";
+  deftypemap["SOAP_ENC__unsignedShort"] = "typedef unsigned short SOAP_ENC__unsignedShort;";
+  usetypemap["SOAP_ENC__unsignedShort"] = "SOAP_ENC__unsignedShort";
+  deftypemap["SOAP_ENC__Array"] = "";
+  usetypemap["SOAP_ENC__Array"] = "struct { _XML *__ptr; int __size; }";
+  deftypemap["_SOAP_ENC__arrayType"] = "";
+  deftypemap["SOAP_ENV__Header"] = "";
+  usetypemap["SOAP_ENV__Header"] = "struct SOAP_ENV__Header";
+  deftypemap["_SOAP_ENV__mustUnderstand"] = "";
+  if (cflag || sflag)
+    usetypemap["_SOAP_ENV__mustUnderstand"] = "char*";
+  else
+    usetypemap["_SOAP_ENV__mustUnderstand"] = "std::string";
+  deftypemap["SOAP_ENV__Fault"] = "";
+  usetypemap["SOAP_ENV__Fault"] = "struct SOAP_ENV__Fault";
+  deftypemap["SOAP_ENV__detail"] = "";
+  usetypemap["SOAP_ENV__detail"] = "struct SOAP_ENV__Detail";
+  deftypemap["SOAP_ENV__Detail"] = "";
+  usetypemap["SOAP_ENV__Detail"] = "struct SOAP_ENV__Detail";
+  deftypemap["SOAP_ENV__Code"] = "";
+  usetypemap["SOAP_ENV__Code"] = "struct SOAP_ENV__Code";
+  deftypemap["SOAP_ENV__Reason"] = "";
+  usetypemap["SOAP_ENV__Reason"] = "struct SOAP_ENV__Reason";
+  if (read(mapfile))
+    fprintf(stderr, "Problem reading type map file '%s'.\nUsing internal type definitions for %s instead.\n\n", mapfile, cflag?"C":"C++");
+}
+
+const char *Types::nsprefix(const char *prefix, const char *URI)
+{ if (URI)
+  { const char *s = uris[URI];
+    if (!s)
+    { size_t n;
+      if (!prefix || !*prefix || *prefix == '_')
+        s = schema_prefix;
+      else
+        s = estrdup(prefix);
+      if (!syms[s])
+        n = syms[s] = 1;
+      else
+        n = ++syms[s];
+      if (n != 1 || !prefix || !*prefix || *prefix == '_')
+      { char *t = (char*)emalloc(strlen(s) + 16);
+        sprintf(t, "%s%lu", s, (unsigned long)n);
+        s = t;
+      }
+      uris[URI] = s;
+      if (vflag)
+        fprintf(stderr, "namespace prefix %s = \"%s\"\n", s, URI);
+    }
+    // if *prefix == '_', then add prefix string to s
+    if (prefix && *prefix == '_')
+    { char *t = (char*)emalloc(strlen(s) + 2);
+      *t = '_';
+      strcpy(t + 1, s);
+      s = t;
+    }
+    return s;
+  }
+  return NULL;
+}
+
+const char *Types::prefix(const char *name)
+{ const char *s;
+  char *t;
+  if (*name == '"')
+  { s = strchr(name + 1, '"');
+    t = (char*)emalloc(s - name);
+    strncpy(t, name + 1, s - name - 1);
+    t[s - name - 1] = '\0';
+    return nsprefix(NULL, t);
+  }
+  s = strchr(name, ':');
+  if (s)
+  { t = (char*)emalloc(s - name + 1);
+    strncpy(t, name, s - name);
+    t[s - name] = '\0';
+    return t;
+  }
+  return NULL;
+}
+
+const char *Types::uri(const char *name)
+{ const char *s;
+  char *t;
+  if (*name == '"')
+  { s = strchr(name + 1, '"');
+    t = (char*)emalloc(s - name);
+    strncpy(t, name + 1, s - name - 1);
+    t[s - name - 1] = '\0';
+    return t;
+  }
+  s = strchr(name, ':');
+  if (s)
+  { struct Namespace *p = namespaces;
+    if (p)
+    { for (p += 6; p->id; p++)
+      { if (!strncmp(p->id, name, s - name) && !p->id[s - name])
+        { if (p->in && *p->in)
+            return p->in;
+          return p->ns;
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+// Find a C name for a QName. If the name has no qualifier, use URI. Suggest prefix for URI
+const char *Types::fname(const char *prefix, const char *URI, const char *qname, SetOfString *reserved, enum Lookup lookup, bool isqname)
+{ char buf[1024], *t;
+  const char *p, *s, *name;
+  if (!qname)
+  { fprintf(stream, "// Warning: internal error, no QName in fname()\n");
+    if (vflag)
+      fprintf(stderr, "Internal error, no QName in fname()\n");
+    qname = "?";
+  }
+  name = qname;
+  if (isqname)
+    s = strrchr(name, ':');
+  else
+    s = NULL;
+  if (s)
+  { name = s + 1;
+    if (qname[0] == '"' && qname[1] == '"')
+      s = NULL;
+    else if (*qname == '"')
+    { t = (char*)emalloc(s - qname - 1);
+      strncpy(t, qname + 1, s - qname - 2);
+      t[s - qname - 2] = '\0';
+      URI = t;
+    }
+    else if (!strncmp(qname, "xs:", 3))	// this hack is necessary since the nsmap table defines "xs" for "xsd"
+    { s = "xsd";
+      URI = NULL;
+    }
+    else
+    { t = (char*)emalloc(s - qname + 1);
+      strncpy(t, qname, s - qname);
+      t[s - qname] = '\0';
+      s = t;
+      URI = NULL;
+    }
+  }
+  if (URI)
+    p = nsprefix(prefix, URI);
+  else if (s)
+    p = s;
+  else
+    p = "";
+  s = NULL;
+  if (lookup == LOOKUP)
+  { if (qnames.find(Pair(p,name)) != qnames.end())
+      s = qnames[Pair(p,name)];
+  }
+  if (!s)
+  { t = buf;
+    if (!prefix || *prefix)
+    { s = p;
+      // no longer add '_' when URI != NULL, since nsprefix() will do this
+      if (prefix && *prefix == ':')
+        *t++ = ':';
+      else if (prefix && *prefix == '_')
+      { if (!URI)
+          *t++ = '_';
+        if (prefix[1] == '_') // ensures ns prefix starts with __
+        { strcpy(t, prefix + 1);
+          t += strlen(prefix + 1);
+        }
+      }
+      if (s && *s)
+      { for (; *s; s++)
+        { if (isalnum(*s))
+            *t++ = *s;
+          else if (*s == '-' && s[1] != '-' && s != p)
+            *t++ = '_';
+          else if (*s == '_')
+          { if (s == p)
+              *t++ = '_';
+            else if (!_flag)
+            { strcpy(t, "_USCORE");
+              t += 7;
+            }
+            else
+            { s = utf8(t, s);
+              t += 6;
+            }
+          }
+          else
+          { s = utf8(t, s);
+            t += 6;
+          }
+        }
+        if (!prefix || *prefix != '*')
+        { *t++ = '_';
+          *t++ = '_';
+        }
+      }
+      else if (isdigit(*name))
+        *t++ = '_';
+    }
+    for (s = name; *s; s++)
+    { if (isalnum(*s))
+        *t++ = *s;
+      else if (*s == '-' && s[1] != '-' && s[1] != '\0' && s != name)
+        *t++ = '_';
+      else if (!_flag && *s == '_')
+      { strcpy(t, "_USCORE");
+        t += 7;
+      }
+      else
+      { s = utf8(t, s);
+        t += 6;
+      }
+      if (t >= buf + sizeof(buf))
+        break;
+    }
+    *t = '\0';
+    while (knames.find(buf) != knames.end() || (reserved && reserved->find(buf) != reserved->end()))
+    { *t++ = '_';
+      *t = '\0';
+    }
+    if (isalpha(*buf) || *buf == '_' || *buf == ':')
+    { t = (char*)emalloc(strlen(buf) + 1);
+      strcpy(t, buf);
+    }
+    else
+    { t = (char*)emalloc(strlen(buf) + 2);
+      *t = '_';
+      strcpy(t + 1, buf);
+    }
+    if (lookup == LOOKUP)
+    { qnames[Pair(p,name)] = t;
+      if (vflag)
+      { cerr << "Mapping '" << p << ":" << name << "' to '" << t << "'" << endl;
+#ifdef DEBUG
+        for (MapOfPairToString::const_iterator i = qnames.begin(); i != qnames.end(); ++i)
+          cerr << "Map[" << (*i).first.first << ":" << (*i).first.second << "]='" << (*i).second << "'" << endl;
+#endif
+      }
+    }
+    s = t;
+  }
+  if (eqvtypemap.find(s) != eqvtypemap.end())
+    s = eqvtypemap[s];
+  return s;
+}
+
+bool Types::is_defined(const char *prefix, const char *URI, const char *qname)
+{ const char *t = fname(prefix, URI, qname, NULL, LOOKUP, true);
+  return usetypemap.find(t) != usetypemap.end();
+}
+
+const char *Types::aname(const char *prefix, const char *URI, const char *qname)
+{ return fname(prefix, URI, qname, NULL, NOLOOKUP, true);
+}
+
+const char *Types::cname(const char *prefix, const char *URI, const char *qname)
+{ return fname(prefix, URI, qname, NULL, LOOKUP, true);
+}
+
+const char *Types::tname(const char *prefix, const char *URI, const char *qname)
+{ const char *s, *t;
+  t = cname(prefix, URI, qname);
+  if (usetypemap.find(t) != usetypemap.end())
+  { s = usetypemap[t];
+    if (vflag)
+      cerr << "Mapping use of '" << t << "' to '" << s << "'" << endl;
+  }
+  else
+  { s = t;
+    fprintf(stream, "\n// Warning: undefined QName '%s' for type '%s' in namespace '%s' (FIXME: check WSDL and schema definitions)\n", qname?qname:"", t, URI?URI:"?");
+    if (vflag)
+      fprintf(stderr, "\nWarning: undefined QName '%s' for type '%s' in namespace '%s'\n", qname?qname:"", t, URI?URI:"?");
+  }
+  return s;
+}
+
+const char *Types::tnameptr(bool flag, const char *prefix, const char *URI, const char *qname)
+{ const char *s = pname(flag, prefix, URI, qname);
+  if (flag)
+  { if (!strncmp(s, "char*", 5))
+      return "char**";
+    if (!strchr(s, '*'))
+    { char *r = (char*)emalloc(strlen(s) + 2);
+      strcpy(r, s);
+      strcat(r, "*");
+      return r;
+    }
+  }
+  return s;
+}
+
+const char *Types::pname(bool flag, const char *prefix, const char *URI, const char *qname)
+{ const char *r, *s = NULL, *t;
+  t = cname(prefix, URI, qname);
+  if (flag)
+  { if (ptrtypemap.find(t) != ptrtypemap.end())
+      s = ptrtypemap[t];
+    else
+    { if (usetypemap.find(t) != usetypemap.end())
+        s = usetypemap[t];
+      if (!s)
+      { s = t;
+        fprintf(stream, "\n// Warning: undefined QName '%s' for pointer to type '%s' (FIXME: check WSDL and schema definitions)\n", qname, t);
+        if (vflag)
+          fprintf(stderr, "\nWarning: undefined QName '%s' for pointer to type '%s' in namespace '%s'\n", qname, t, URI?URI:"?");
+      }
+      r = s;
+      while (r && *r)
+      { r = strchr(r + 1, '*');
+        if (r && *(r-1) != '/' && *(r+1) != '/')
+          break;
+      }
+      if (!r)	// already pointer?
+      { char *p = (char*)emalloc(strlen(s) + 2);
+        strcpy(p, s);
+        strcat(p, "*");
+        s = p;
+      }
+      if (vflag)
+        cerr << "Mapping pointer to '" << t << "' to '" << s << "'" << endl;
+      ptrtypemap[t] = s;
+    }
+  }
+  else if (usetypemap.find(t) != usetypemap.end())
+    s = usetypemap[t];
+  else
+  { s = t;
+    fprintf(stream, "\n// Warning: undefined QName '%s' for type '%s' in namespace '%s' (FIXME: check WSDL and schema definitions)\n", qname, t, URI?URI:"?");
+    if (vflag)
+      fprintf(stderr, "\nWarning: undefined QName '%s' for type '%s' in namespace '%s'\n", qname, t, URI?URI:"?");
+  }
+  return s;
+}
+
+const char *Types::deftname(enum Type type, const char *pointer, bool is_pointer, const char *prefix, const char *URI, const char *qname)
+{ char buf[1024];
+  char *s;
+  const char *q = NULL, *t;
+  t = fname(prefix, URI, qname, NULL, LOOKUP, true);
+  if (deftypemap[t])
+  { if (vflag)
+      fprintf(stderr, "Name %s already defined (probably in %s file)\n", qname, mapfile);
+    return NULL;
+  }
+  if (usetypemap[t])
+  { if (vflag)
+      fprintf(stderr, "Name %s is mapped\n", qname);
+    return t;
+  }
+  switch (type)
+  { case ENUM:
+      q = "enum";
+      if (yflag)
+        knames.insert(t);
+      break;
+    case STRUCT:
+      q = "struct";
+      if (yflag)
+        knames.insert(t);
+      break;
+    case CLASS:
+    case TYPEDEF:
+      knames.insert(t);
+    default:
+      break;
+  }
+  if (q)
+  { strcpy(buf, q);
+    strcat(buf, " ");
+  }
+  else
+    buf[0] = '\0';
+  strcat(buf, t);
+  if (pointer)
+    strcat(buf, pointer);
+  s = (char*)emalloc(strlen(buf) + 1);
+  strcpy(s, buf);
+  usetypemap[t] = s;
+  if (pointer || is_pointer)
+    ptrtypemap[t] = s;
+  if (vflag)
+    cerr <<  "Defined '" << t << "' ('" << qname << "' in namespace '" << (URI?URI:prefix?prefix:"") << "') as '" << s << endl;
+  return t;
+}
+
+// get enumeration value. URI/type refers to the enum simpleType.
+const char *Types::ename(const char *type, const char *value, bool isqname)
+{ const char *s = enames[Pair(type,value)];
+  if (!s)
+  { s = fname(NULL, NULL, value, &rnames, NOLOOKUP, isqname);
+    if (!eflag && type && *type)
+    { // Add prefix to enum
+      if (!*s || (s[0] == '_' && s[1] == '\0'))
+        s = "_x0000";
+      char *buf = (char*)emalloc(strlen(type) + strlen(s) + 3);
+      // _xXXXX is OK here
+      if (s[0] == '_' && s[1] != 'x' && strncmp(s, "_USCORE", 7))
+        sprintf(buf, "%s_%s", type, s);
+      else
+        sprintf(buf, "%s__%s", type, s);
+      s = buf;
+    }
+    else
+      rnames.insert(s);
+    enames[Pair(type,value)] = s;
+  }
+  return s;
+}
+
+// get operation name
+const char *Types::oname(const char *prefix, const char *URI, const char *qname)
+{ const char *s = fname(prefix, URI, qname, NULL, LOOKUP, true);
+  if (s && usetypemap.find(s) != usetypemap.end())
+  { // Avoid name clash with structs/classes of the same name
+    onames.insert(s);
+  }
+  s = fname(prefix, URI, qname, &onames, NOLOOKUP, true);
+  onames.insert(s);
+  return s;
+}
+
+// generate struct name
+const char *Types::sname(const char *URI, const char *name)
+{ const char *s;
+  char *t;
+  if (!aflag && name)
+  { size_t len = 0;
+    for (VectorOfString::const_iterator i = scope.begin(); i != scope.end(); ++i)
+      len += strlen(*i) + 1;
+    t = (char*)emalloc(len + strlen(name) + 1);
+    *t = '\0';
+    for (VectorOfString::const_iterator j = scope.begin(); j != scope.end(); ++j)
+    { strcat(t, *j);
+      strcat(t, "-");
+    }
+    strcat(t, name);
+    s = fname("_", URI, t, &rnames, NOLOOKUP, true);
+    rnames.insert(s);
+  }
+  else if (URI)
+  { s = nsprefix(NULL, URI);
+    t = (char*)emalloc(strlen(s) + 16);
+    sprintf(t, "_%s__struct_%d", s, snum++);
+    s = t;
+  }
+  else
+  { t = (char*)emalloc(16);
+    sprintf(t, "struct_%d", snum++);
+    s = t;
+  }
+  return s;
+}
+
+// generate union name
+const char *Types::uname(const char *URI)
+{ const char *s;
+  char *t;
+  if (!aflag)
+  { size_t len = 0;
+    for (VectorOfString::const_iterator i = scope.begin(); i != scope.end(); ++i)
+      len += strlen(*i) + 1;
+    t = (char*)emalloc(len + 6);
+    strcpy(t, "union");
+    for (VectorOfString::const_iterator j = scope.begin(); j != scope.end(); ++j)
+    { strcat(t, "-");
+      strcat(t, *j);
+    }
+    s = fname("_", URI, t, &rnames, NOLOOKUP, true);
+    rnames.insert(s);
+  }
+  else if (URI)
+  { s = nsprefix(NULL, URI);
+    t = (char*)emalloc(strlen(s) + 16);
+    sprintf(t, "_%s__union_%d", s, unum++);
+    s = t;
+  }
+  else
+  { t = (char*)emalloc(16);
+    sprintf(t, "_union_%d", unum++);
+    s = t;
+  }
+  return s;
+}
+
+// generate enum name
+const char *Types::gname(const char *URI, const char *name)
+{ const char *s;
+  char *t;
+  if (!aflag && name)
+  { size_t len = 0;
+    for (VectorOfString::const_iterator i = scope.begin(); i != scope.end(); ++i)
+      len += strlen(*i) + 1;
+    t = (char*)emalloc(len + strlen(name) + 1);
+    *t = '\0';
+    for (VectorOfString::const_iterator j = scope.begin(); j != scope.end(); ++j)
+    { strcat(t, *j);
+      strcat(t, "-");
+    }
+    strcat(t, name);
+    s = fname("_", URI, t, &rnames, LOOKUP, true);
+    rnames.insert(s);
+  }
+  else if (URI)
+  { s = nsprefix(NULL, URI);
+    t = (char*)emalloc(strlen(s) + 16);
+    sprintf(t, "_%s__enum_%d", s, gnum++);
+    s = t;
+  }
+  else
+  { t = (char*)emalloc(16);
+    sprintf(t, "enum_%d", gnum++);
+    s = t;
+  }
+  return s;
+}
+
+// checks if nillable or minOccurs=0 (and no default value is present)
+bool Types::is_nillable(const xs__element& element)
+{ return !element.default_ && (element.nillable || (element.minOccurs && !strcmp(element.minOccurs, "0")));
+}
+
+bool Types::is_basetypeforunion(const char *prefix, const char *URI, const char *type)
+{ const char *t = tname(prefix, URI, type);
+  if (!strcmp(t, "std::string") || !strcmp(t, "std::wstring"))
+    return false;
+  return is_basetype(prefix, URI, type);
+}
+
+bool Types::is_basetype(const char *prefix, const char *URI, const char *type)
+{ const char *t = tname(prefix, URI, type);
+  if (!strncmp(t, "enum ", 5))
+    return true;
+  if (strstr(t, "__") && strcmp(t, "xsd__byte"))
+    return false;
+  return !strncmp(type, "xs:", 3) || !strncmp(type, "SOAP-ENC:", 9);
+}
+
+void Types::dump(FILE *fd)
+{ fprintf(fd, "\nTypes:\n");
+  for (MapOfStringToString::const_iterator i = usetypemap.begin(); i != usetypemap.end(); ++i)
+    fprintf(fd, "%s=%s\n", (*i).first, (*i).second?(*i).second:"(null)");
+  fprintf(fd, "\nPointers:\n");
+  for (MapOfStringToString::const_iterator j = ptrtypemap.begin(); j != ptrtypemap.end(); ++j)
+    fprintf(fd, "%s=%s\n", (*j).first, (*j).second?(*j).second:"(null)");
+}
+
+void Types::define(const char *URI, const char *name, const xs__complexType& complexType)
+{ // generate prototype for structs/classes and store name
+  const char *prefix = NULL;
+  if (complexType.name)
+    name = complexType.name;
+  else
+    prefix = "_";
+  if (complexType.complexContent
+   && complexType.complexContent->restriction
+   && !strcmp(complexType.complexContent->restriction->base, "SOAP-ENC:Array"))
+  { if (strcmp(schema_prefix, "ns"))
+      prefix = "*";
+    else
+      prefix = "";
+  }
+  if (cflag)
+  { const char *t = deftname(STRUCT, "*", true, prefix, URI, name);
+    if (t)
+    { if (yflag)
+        fprintf(stream, "\n/// Typedef synonym for struct %s.\ntypedef struct %s %s;\n", t, t, t);
+    }
+    else if (name)
+    { t = deftypemap[cname(prefix, URI, name)];
+      if (t)
+      { fprintf(stream, "\n/// Imported complexType \"%s\":%s from typemap %s.\n", URI, name, mapfile?mapfile:"");
+        document(complexType.annotation);
+        if (*t)
+          format(t);
+        else
+          fprintf(stream, "// complexType definition intentionally left blank.\n");
+      }
+    }
+  }
+  else 
+  { const char *t = deftname(CLASS, "*", true, prefix, URI, name);
+    if (t)
+      fprintf(stream, "\n//  Forward declaration of class %s.\nclass %s;\n", t, t);
+    else if (name)
+    { t = deftypemap[cname(prefix, URI, name)];
+      if (t)
+      { fprintf(stream, "\n/// Imported complexType \"%s\":%s from typemap %s.\n", URI, name, mapfile?mapfile:"");
+        document(complexType.annotation);
+        if (*t)
+          format(t);
+        else
+          fprintf(stream, "// complexType definition intentionally left blank.\n");
+      }
+    }
+  }
+}
+
+void Types::gen(const char *URI, const char *name, const xs__simpleType& simpleType, bool anonymous)
+{ const char *t = NULL;
+  const char *prefix = NULL;
+  if (simpleType.name)
+    name = simpleType.name;
+  else
+    prefix = "_";
+  if (!anonymous)
+  { t = deftypemap[cname(NULL, URI, name)];
+    if (t)
+    { fprintf(stream, "\n/// Imported simpleType \"%s\":%s from typemap %s.\n", URI, name, mapfile?mapfile:"");
+      document(simpleType.annotation);
+      if (*t)
+        format(t);
+      else
+        fprintf(stream, "// simpleType definition intentionally left blank.\n");
+      return;
+    }
+  }
+  if (simpleType.restriction)
+  { const char *base = simpleType.restriction->base;
+    if (!base && simpleType.restriction->simpleType)
+    { if (!anonymous)
+      { if (simpleType.restriction->simpleType->list && simpleType.restriction->length && simpleType.restriction->length->value)
+        { fprintf(stream, "\n/// \"%s\":%s is a simpleType restriction list with length %s.", URI?URI:"", name, simpleType.restriction->length->value);
+          document(simpleType.restriction->length->annotation);
+        }
+        else
+          fprintf(stream, "\n/// \"%s\":%s is a simpleType restriction.", URI?URI:"", name);
+      }
+      gen(URI, name, *simpleType.restriction->simpleType, anonymous);
+    }
+    else
+    { if (!base)
+        base = "xsd:string";
+      const char *baseURI = NULL;
+      if (simpleType.restriction->simpleTypePtr() && simpleType.restriction->simpleTypePtr()->schemaPtr())
+        baseURI = simpleType.restriction->simpleTypePtr()->schemaPtr()->targetNamespace;
+      if (!anonymous)
+        fprintf(stream, "\n/// \"%s\":%s is a simpleType restriction of %s.\n", URI?URI:"", name, base);
+      document(simpleType.annotation);
+      document(simpleType.restriction->annotation);
+      if (!simpleType.restriction->enumeration.empty())
+      { bool is_numeric = true; // check if all enumeration values are numeric
+        bool is_qname = !strcmp(base, "xs:QName");
+        if (!anonymous)
+        { t = deftname(ENUM, NULL, false, prefix, URI, name);
+          if (t && !eflag)
+            fprintf(stream, "/// Note: enum values are prefixed with '%s' to avoid name clashes, please use wsdl2h option -e to omit this prefix\n", t);
+        }
+        if (!t)
+          t = gname(URI, name);
+        if (!anonymous)
+          fprintf(stream, "enum %s\n{\n", t);
+        else
+          fprintf(stream, "    enum %s\n    {\n", t);
+        for (vector<xs__enumeration>::const_iterator enumeration1 = simpleType.restriction->enumeration.begin(); enumeration1 != simpleType.restriction->enumeration.end(); ++enumeration1)
+        { const char *s;
+          if ((s = (*enumeration1).value))
+            is_numeric &= is_integer(s);
+        }
+        SetOfString enumvals;
+        for (vector<xs__enumeration>::const_iterator enumeration2 = simpleType.restriction->enumeration.begin(); enumeration2 != simpleType.restriction->enumeration.end(); ++enumeration2)
+        { const char *s;
+          document((*enumeration2).annotation);
+          if ((s = (*enumeration2).value))
+          { if (!enumvals.count(s))
+            { enumvals.insert(s);
+              if (is_numeric)
+                fprintf(stream, "\t%s = %s,\t///< %s value=\"%s\"\n", ename(t, s, false), s, base, s);
+              else if (is_qname && (*enumeration2).value_)
+                fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration2).value_, true), base, (*enumeration2).value_);
+              else
+                fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, s, false), base, s);
+            }
+          }
+          else
+            fprintf(stream, "//\tunrecognized: enumeration '%s' has no value\n", name?name:"");
+        }
+        if (!anonymous)
+        { fprintf(stream, "};\n");
+          if (yflag)
+            fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t);
+          if (pflag && simpleType.name)
+          { const char *s = aname(prefix, URI, name);
+            knames.insert(s);
+            s = aname(prefix, URI, name);
+            fprintf(stream, "\n/// Class wrapper\n");
+            fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
+            fprintf(stream, elementformat, tname(prefix, URI, name), "__item;");
+            modify(s);
+            fprintf(stream, "\n};\n");
+          }
+        }
+        else
+          fprintf(stream, "    }\n");
+      }
+      else
+      { if (simpleType.restriction->length && simpleType.restriction->length->value)
+        { fprintf(stream, "/// Length of this string is exactly %s characters\n", simpleType.restriction->length->value);
+          document(simpleType.restriction->length->annotation);
+        }
+        else
+        { const char *a = NULL, *b = NULL;
+          if (simpleType.restriction->minLength)
+          { a = simpleType.restriction->minLength->value;
+            document(simpleType.restriction->minLength->annotation);
+          }
+          if (simpleType.restriction->maxLength)
+          { b = simpleType.restriction->maxLength->value;
+            document(simpleType.restriction->maxLength->annotation);
+          }
+          if (a || b)
+            fprintf(stream, "/// Length of this string is within %s..%s characters\n", a?a:"0", b?b:"");
+        }
+        if (simpleType.restriction->precision && simpleType.restriction->precision->value)
+          fprintf(stream, "/// %sprecision is %s (note: not automatically enforced)\n", simpleType.restriction->precision->fixed?"fixed ":"", simpleType.restriction->precision->value);
+        if (simpleType.restriction->scale && simpleType.restriction->scale->value)
+          fprintf(stream, "/// %sscale is %s (note: not automatically enforced)\n", simpleType.restriction->scale->fixed?"fixed ":"", simpleType.restriction->scale->value);
+        if (simpleType.restriction->totalDigits && simpleType.restriction->totalDigits->value)
+          fprintf(stream, "/// %snumber of total digits is %s (note: not automatically enforced)\n", simpleType.restriction->totalDigits->fixed?"fixed ":"", simpleType.restriction->totalDigits->value);
+        if (simpleType.restriction->fractionDigits && simpleType.restriction->fractionDigits->value)
+          fprintf(stream, "/// %snumber of fraction digits is %s (note: not automatically enforced)\n", simpleType.restriction->fractionDigits->fixed?"fixed ":"", simpleType.restriction->fractionDigits->value);
+        for (vector<xs__pattern>::const_iterator pattern1 = simpleType.restriction->pattern.begin(); pattern1 != simpleType.restriction->pattern.end(); ++pattern1)
+          fprintf(stream, "/// Content pattern is \"%s\" (note: not automatically enforced)\n", xstring((*pattern1).value));
+        const char *ai = NULL, *ae = NULL, *bi = NULL, *be = NULL;
+        if (simpleType.restriction->minInclusive)
+        { ai = simpleType.restriction->minInclusive->value;
+          document(simpleType.restriction->minInclusive->annotation);
+        }
+        else if (simpleType.restriction->minExclusive)
+        { ae = simpleType.restriction->minExclusive->value;
+          document(simpleType.restriction->minExclusive->annotation);
+        }
+        if (simpleType.restriction->maxInclusive)
+        { bi = simpleType.restriction->maxInclusive->value;
+          document(simpleType.restriction->maxInclusive->annotation);
+        }
+        else if (simpleType.restriction->maxExclusive)
+        { be = simpleType.restriction->maxExclusive->value;
+          document(simpleType.restriction->maxExclusive->annotation);
+        }
+        if (ai || ae || bi || be)
+        { fprintf(stream, "/// Value range is ");
+          if (ai)
+            fprintf(stream, "[%s..", ai);
+          else if (ae)
+            fprintf(stream, "(%s..", ae);
+          else
+            fprintf(stream, "[..");
+          if (bi)
+            fprintf(stream, "%s]\n", bi);
+          else if (be)
+            fprintf(stream, "%s)\n", be);
+          else
+            fprintf(stream, "]\n");
+        }
+        if (!simpleType.restriction->attribute.empty())
+        { if (!Wflag)
+            fprintf(stderr, "\nWarning: simpleType '%s' should not have attributes\n", name?name:"");
+        }
+        const char *s = tname(NULL, baseURI, base);
+        if (!anonymous)
+        { bool is_ptr = false;
+          is_ptr = (strchr(s, '*') != NULL) || (s == pname(true, NULL, baseURI, base));
+          t = deftname(TYPEDEF, NULL, is_ptr, prefix, URI, name);
+          if (t)
+            fprintf(stream, "typedef %s %s", s, t);
+        }
+        else
+        { t = "";
+          fprintf(stream, elementformat, s, "");
+          fprintf(stream, "\n");
+        }
+        if (t)
+        { if (!anonymous && !simpleType.restriction->pattern.empty())
+          { fprintf(stream, " \"");
+            for (vector<xs__pattern>::const_iterator pattern2 = simpleType.restriction->pattern.begin(); pattern2 != simpleType.restriction->pattern.end(); ++pattern2)
+            { if (pattern2 != simpleType.restriction->pattern.begin())
+                fprintf(stream, "|");
+              fprintf(stream, "%s", xstring((*pattern2).value));
+            }
+            fprintf(stream, "\"");
+          }
+          // add range info only when type is numeric
+          bool is_numeric = false, is_float = false;
+          if (!strncmp(s, "unsigned ", 9))
+            s += 9;
+          else if (!strncmp(s, "xsd__unsigned", 13))
+            s += 13;
+          else if (!strncmp(s, "xsd__", 5))
+            s += 5;
+          if (!strcmp(s, "double")
+           || !strcmp(s, "float"))
+            is_numeric = is_float = true;
+          else if (!strcmp(s, "bool")
+           || !strcmp(s, "byte")
+           || !strcmp(s, "Byte")
+           || !strcmp(s, "char")
+           || !strcmp(s, "double")
+           || !strcmp(s, "float")
+           || !strcmp(s, "int")
+           || !strcmp(s, "Int")
+           || !strcmp(s, "long")
+           || !strcmp(s, "Long")
+           || !strcmp(s, "LONG64")
+           || !strcmp(s, "short")
+           || !strcmp(s, "Short")
+           || !strcmp(s, "ULONG64"))
+            is_numeric = true;
+          if (!anonymous
+           && simpleType.restriction->minLength
+           && simpleType.restriction->minLength->value)
+            fprintf(stream, " %s", simpleType.restriction->minLength->value);
+          else if (is_numeric
+                && !anonymous
+                && simpleType.restriction->minInclusive
+                && simpleType.restriction->minInclusive->value
+                && is_integer(simpleType.restriction->minInclusive->value))
+            fprintf(stream, " %s", simpleType.restriction->minInclusive->value);
+          else if (is_float
+                && !anonymous
+                && simpleType.restriction->minExclusive
+                && simpleType.restriction->minExclusive->value
+                && is_integer(simpleType.restriction->minExclusive->value))
+            fprintf(stream, " %s", simpleType.restriction->minExclusive->value);
+          else if (is_numeric
+                && !anonymous
+                && simpleType.restriction->minExclusive
+                && simpleType.restriction->minExclusive->value
+                && is_integer(simpleType.restriction->minExclusive->value))
+            fprintf(stream, " " SOAP_LONG_FORMAT, to_integer(simpleType.restriction->minExclusive->value)+1);
+          if (!anonymous
+           && simpleType.restriction->maxLength
+           && simpleType.restriction->maxLength->value)
+            fprintf(stream, ":%s", simpleType.restriction->maxLength->value);
+          else if (is_numeric
+                && !anonymous
+                && simpleType.restriction->maxInclusive
+                && simpleType.restriction->maxInclusive->value
+                && is_integer(simpleType.restriction->maxInclusive->value))
+            fprintf(stream, ":%s", simpleType.restriction->maxInclusive->value);
+          else if (is_float
+                && !anonymous
+                && simpleType.restriction->maxExclusive
+                && simpleType.restriction->maxExclusive->value
+                && is_integer(simpleType.restriction->maxExclusive->value))
+            fprintf(stream, ":%s", simpleType.restriction->maxExclusive->value);
+          else if (is_numeric
+                && !anonymous
+                && simpleType.restriction->maxExclusive
+                && simpleType.restriction->maxExclusive->value
+                && is_integer(simpleType.restriction->maxExclusive->value))
+            fprintf(stream, ":" SOAP_LONG_FORMAT, to_integer(simpleType.restriction->maxExclusive->value)-1);
+          if (!anonymous)
+          { fprintf(stream, ";\n");
+            if (pflag && simpleType.name)
+            { const char *s = aname(prefix, URI, name);
+              knames.insert(s);
+              s = aname(prefix, URI, name);
+              fprintf(stream, "\n/// Class wrapper\n");
+              fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
+              fprintf(stream, elementformat, tname(prefix, URI, name), "__item;");
+              modify(s);
+              fprintf(stream, "\n};\n");
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (simpleType.list)
+  { if (simpleType.list->restriction && simpleType.list->restriction->base)
+    { if (!anonymous)
+      { fprintf(stream, "\n/// \"%s\":%s is a simpleType list restriction of %s.\n", URI?URI:"", name, simpleType.list->restriction->base);
+        fprintf(stream, "/// Note: this enumeration is a bitmask, so a set of values is supported (using | and & bit-ops on the bit vector).\n");
+      }
+      document(simpleType.annotation);
+      if (!anonymous)
+      { t = deftname(ENUM, NULL, false, prefix, URI, name);
+        if (t)
+          fprintf(stream, "enum * %s\n{\n", t);
+      }
+      else
+      { t = "";
+        fprintf(stream, "enum *\n{\n");
+      }
+      if (t)
+      { for (vector<xs__enumeration>::const_iterator enumeration = simpleType.list->restriction->enumeration.begin(); enumeration != simpleType.list->restriction->enumeration.end(); ++enumeration)
+        { if ((*enumeration).value)
+          { if (!strcmp(simpleType.list->restriction->base, "xs:QName") && (*enumeration).value_)
+              fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value_, true), simpleType.list->restriction->base, (*enumeration).value_);
+            else
+              fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value, false), simpleType.list->restriction->base, (*enumeration).value);
+          }
+          else
+            fprintf(stream, "//\tunrecognized: bitmask enumeration '%s' has no value\n", t);
+        }
+        if (!anonymous)
+        { fprintf(stream, "};\n");
+          if (yflag)
+            fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t);
+          if (pflag && simpleType.name)
+          { const char *s = aname(prefix, URI, name);
+            knames.insert(s);
+            s = aname(prefix, URI, name);
+            fprintf(stream, "\n/// Class wrapper\n");
+            fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
+            fprintf(stream, elementformat, tname(prefix, URI, name), "__item;");
+            modify(s);
+            fprintf(stream, "\n};\n");
+          }
+        }
+        else
+          fprintf(stream, "}\n");
+      }
+    }
+    else if (simpleType.list->itemType)
+    { const xs__simpleType *p = simpleType.list->itemTypePtr();
+      if (p
+       && p->restriction
+       && p->restriction->base
+       && !p->restriction->enumeration.empty()
+       && p->restriction->enumeration.size() <= 64)
+      { if (!anonymous)
+        { fprintf(stream, "\n/// \"%s\":%s is a simpleType list of %s.\n", URI?URI:"", name, simpleType.list->itemType);
+          fprintf(stream, "/// Note: this enumeration is a bitmask, so a set of values is supported (using | and & bit-ops on the bit vector).\n");
+        }
+        document(simpleType.annotation);
+        if (!anonymous)
+        { t = deftname(ENUM, NULL, false, prefix, URI, name);
+          if (t)
+            fprintf(stream, "enum * %s\n{\n", t);
+        }
+        else
+        { t = "";
+          fprintf(stream, "enum *\n{\n");
+        }
+        if (t)
+        { for (vector<xs__enumeration>::const_iterator enumeration = p->restriction->enumeration.begin(); enumeration != p->restriction->enumeration.end(); ++enumeration)
+          { if ((*enumeration).value)
+            { if (!strcmp(p->restriction->base, "xs:QName") && (*enumeration).value_)
+                fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value_, true), p->restriction->base, (*enumeration).value_);
+              else
+                fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value, false), p->restriction->base, (*enumeration).value);
+            }
+            else
+              fprintf(stream, "//\tunrecognized: bitmask enumeration '%s' has no value\n", t);
+          }
+          if (!anonymous)
+          { fprintf(stream, "};\n");
+            if (yflag)
+              fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t);
+            if (pflag && simpleType.name)
+            { const char *s = aname(prefix, URI, name);
+              knames.insert(s);
+              s = aname(prefix, URI, name);
+              fprintf(stream, "\n/// Class wrapper.\n");
+              fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
+              fprintf(stream, elementformat, tname(prefix, URI, name), "__item;");
+              modify(s);
+              fprintf(stream, "\n};\n");
+            }
+          }
+          else
+            fprintf(stream, "}\n");
+        }
+      }
+      else
+      { const char *s;
+        if (!strcmp(simpleType.list->itemType, "xs:QName"))
+          s = tname(NULL, NULL, "xsd:QName");
+        else
+          s = tname(NULL, NULL, "xsd:string");
+        if (!anonymous)
+        { fprintf(stream, "\n/// \"%s\":%s is a simpleType containing a whitespace separated list of %s.\n", URI?URI:"", name, simpleType.list->itemType);
+          t = deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, prefix, URI, name);
+        }
+        document(simpleType.annotation);
+        if (t)
+          fprintf(stream, "typedef %s %s;\n", s, t);
+        else
+        { fprintf(stream, elementformat, s, "");
+          fprintf(stream, "\n");
+        }
+      }
+    }
+    else
+    { if (!anonymous)
+      { fprintf(stream, "\n/// \"%s\":%s is a simpleType list.\n", URI?URI:"", name);
+        fprintf(stream, "/// Note: this enumeration is a bitmask, so a set of values is supported (using | and & bit-ops on the bit vector).\n");
+      }
+      document(simpleType.annotation);
+      if (!anonymous)
+      { t = deftname(ENUM, NULL, false, prefix, URI, name);
+        if (t && !eflag)
+          fprintf(stream, "/// Note: enum values are prefixed with '%s' to avoid name clashes, please use wsdl2h option -e to omit this prefix\n", t);
+      }
+      else
+        t = "";
+      if (t)
+      { fprintf(stream, "enum * %s\n{\n", t);
+        for (vector<xs__simpleType>::const_iterator simple = simpleType.list->simpleType.begin(); simple != simpleType.list->simpleType.end(); ++simple)
+        { if ((*simple).restriction && (*simple).restriction->base)
+          { for (vector<xs__enumeration>::const_iterator enumeration = (*simple).restriction->enumeration.begin(); enumeration != (*simple).restriction->enumeration.end(); ++enumeration)
+            { if ((*enumeration).value)
+              { if (!strcmp((*simple).restriction->base, "xs:QName") && (*enumeration).value_)
+                  fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value_, true), (*simple).restriction->base, (*enumeration).value_);
+                else
+                  fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value, false), (*simple).restriction->base, (*enumeration).value);
+              }
+              else
+                fprintf(stream, "//\tunrecognized: bitmask enumeration '%s' has no value\n", t);
+            }
+          }
+        }
+        if (!anonymous)
+        { fprintf(stream, "};\n");
+          if (yflag)
+            fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t);
+          if (pflag && simpleType.name)
+          { const char *s = aname(prefix, URI, name);
+            knames.insert(s);
+            s = aname(prefix, URI, name);
+            fprintf(stream, "\n/// Class wrapper.\n");
+            fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
+            fprintf(stream, elementformat, tname(prefix, URI, name), "__item;");
+            modify(s);
+            fprintf(stream, "\n};\n");
+          }
+        }
+        else
+          fprintf(stream, "}\n");
+      }
+    }
+  }
+  else if (simpleType.union_)
+  { if (simpleType.union_->memberTypes)
+    { const char *s = tname(NULL, NULL, "xsd:string");
+      if (!anonymous)
+        t = deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, prefix, URI, name);
+      fprintf(stream, "\n/// union of values \"%s\"\n", simpleType.union_->memberTypes);
+      if (t)
+        fprintf(stream, "typedef %s %s;\n", s, t);
+      else
+      { fprintf(stream, elementformat, s, "");
+        fprintf(stream, "\n");
+      }
+    }
+    else if (!simpleType.union_->simpleType.empty())
+    { const char *s = tname(NULL, NULL, "xsd:string");
+      fprintf(stream, "\n");
+      if (!anonymous)
+        t = deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, prefix, URI, name);
+      for (vector<xs__simpleType>::const_iterator simpleType1 = simpleType.union_->simpleType.begin(); simpleType1 != simpleType.union_->simpleType.end(); ++simpleType1)
+        if ((*simpleType1).restriction)
+        { fprintf(stream, "/// union of values from \"%s\"\n", (*simpleType1).restriction->base);
+          // TODO: are there any other types we should report here?
+        }
+      if (t)
+        fprintf(stream, "typedef %s %s;\n", s, t);
+      else
+      { fprintf(stream, elementformat, s, "");
+        fprintf(stream, "\n");
+      }
+    }
+    else
+      fprintf(stream, "//\tunrecognized\n");
+  }
+  else
+    fprintf(stream, "//\tunrecognized simpleType\n");
+}
+
+void Types::gen(const char *URI, const char *name, const xs__complexType& complexType, bool anonymous)
+{ const char *t = NULL;
+  const char *prefix = NULL;
+  bool soapflag = false;
+  if (complexType.name)
+    name = complexType.name;
+  else
+    prefix = "_";
+  if (anonymous && name)
+    t = sname(URI, name);
+  else if (name)
+  { t = cname(prefix, URI, name);
+    if (deftypemap[t])
+      return;
+  }
+  if (name)
+    scope.push_back(name);
+  if (complexType.simpleContent)
+  { if (!anonymous)
+      fprintf(stream, "\n/// \"%s\":%s is a%s complexType with simpleContent.\n", URI?URI:"", name, complexType.abstract?"n abstract":"");
+    document(complexType.annotation);
+    operations(t);
+    if (complexType.simpleContent->restriction)
+    { if (anonymous)
+      { if (cflag)
+          fprintf(stream, "    struct %s\n    {\n", t);
+        else
+          fprintf(stream, "    class %s\n    {\n", t);
+      }
+      else if (cflag)
+        fprintf(stream, "struct %s\n{\n", t);
+      else if (pflag && complexType.name)
+        fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t);
+      else
+        fprintf(stream, "class %s\n{ public:\n", t);
+      const char *base = "xs:string";
+      const char *baseURI = NULL;
+      const xs__complexType *p = &complexType; 
+      do
+      { if (!p->simpleContent)
+          break;
+        if (p->simpleContent->restriction)
+        { if (p->simpleContent->restriction->complexTypePtr())
+            p = p->simpleContent->restriction->complexTypePtr();
+          else
+          { base = p->simpleContent->restriction->base;   
+            if (p->simpleContent->restriction->simpleTypePtr() && p->simpleContent->restriction->simpleTypePtr()->schemaPtr())
+              baseURI = p->simpleContent->restriction->simpleTypePtr()->schemaPtr()->targetNamespace;
+            break;
+          }
+        }
+        else if (p->simpleContent->extension)
+        { if (p->simpleContent->extension->complexTypePtr())
+            p = p->simpleContent->extension->complexTypePtr();
+          else
+          { base = p->simpleContent->extension->base;   
+            if (p->simpleContent->extension->simpleTypePtr() && p->simpleContent->extension->simpleTypePtr()->schemaPtr())
+              baseURI = p->simpleContent->extension->simpleTypePtr()->schemaPtr()->targetNamespace;
+            break;
+          }
+        }
+        else
+          break;
+      }
+      while (p);
+      fprintf(stream, "/// __item wraps '%s' simpleContent.\n", base);
+      fprintf(stream, elementformat, tname(NULL, baseURI, base), "__item");
+      fprintf(stream, ";\n");
+      p = &complexType; 
+      bool flag = true;
+      do
+      { if (!p->simpleContent)
+          break;
+        if (p->simpleContent->restriction)
+        { // TODO: should only generate attribute when name is different?
+          gen(URI, p->simpleContent->restriction->attribute);
+          if (p->simpleContent->restriction->anyAttribute && flag)
+          { gen(URI, *p->simpleContent->restriction->anyAttribute);
+            flag = false;
+          }
+          if (p->simpleContent->restriction->complexTypePtr())
+            p = p->simpleContent->restriction->complexTypePtr();
+          else
+            break;
+        }
+        else if (p->simpleContent->extension)
+        { gen(URI, p->simpleContent->extension->attribute);
+          gen(URI, p->simpleContent->extension->attributeGroup);
+          if (p->simpleContent->extension->anyAttribute && flag)
+          { gen(URI, *p->simpleContent->extension->anyAttribute);
+            flag = false;
+          }
+          if (p->simpleContent->extension->complexTypePtr())
+            p = p->simpleContent->extension->complexTypePtr();
+          else
+            break;
+        }
+        else
+          break;
+      }
+      while (p);
+    }
+    else if (complexType.simpleContent->extension)
+    { const char *base = "xs:string";
+      const char *baseURI = NULL;
+      if (cflag || fflag || anonymous)
+      { if (anonymous)
+        { if (cflag)
+            fprintf(stream, "    struct %s\n    {\n", t);
+          else
+            fprintf(stream, "    class %s\n    {\n", t);
+        }
+        else if (cflag)
+          fprintf(stream, "struct %s\n{\n", t);
+        else if (pflag && complexType.name)
+          fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t);
+        else
+          fprintf(stream, "class %s\n{ public:\n", t);
+        const xs__complexType *p = &complexType; 
+        do
+        { if (!p->simpleContent)
+            break;
+          if (p->simpleContent->restriction)
+          { if (p->simpleContent->restriction->complexTypePtr())
+              p = p->simpleContent->restriction->complexTypePtr();
+            else
+            { base = p->simpleContent->restriction->base;   
+              if (p->simpleContent->restriction->simpleTypePtr() && p->simpleContent->restriction->simpleTypePtr()->schemaPtr())
+                baseURI = p->simpleContent->restriction->simpleTypePtr()->schemaPtr()->targetNamespace;
+              break;
+            }
+          }
+          else if (p->simpleContent->extension)
+          { if (p->simpleContent->extension->complexTypePtr())
+              p = p->simpleContent->extension->complexTypePtr();
+            else
+            { base = p->simpleContent->extension->base;   
+              if (p->simpleContent->extension->simpleTypePtr() && p->simpleContent->extension->simpleTypePtr()->schemaPtr())
+                baseURI = p->simpleContent->extension->simpleTypePtr()->schemaPtr()->targetNamespace;
+              break;
+            }
+          }
+          else
+            break;
+        }
+        while (p);
+        fprintf(stream, "/// __item wraps '%s' simpleContent.\n", base);
+        fprintf(stream, elementformat, tname(NULL, baseURI, base), "__item");
+        fprintf(stream, ";\n");
+        p = &complexType; 
+        bool flag = true;
+        do
+        { if (!p->simpleContent)
+            break;
+          if (p->simpleContent->restriction)
+          { gen(URI, p->simpleContent->restriction->attribute);
+            if (p->simpleContent->restriction->anyAttribute && flag)
+              gen(URI, *p->simpleContent->restriction->anyAttribute);
+            break;
+          }
+          else if (p->simpleContent->extension)
+          { gen(URI, p->simpleContent->extension->attribute);
+            gen(URI, p->simpleContent->extension->attributeGroup);
+            if (p->simpleContent->extension->anyAttribute && flag)
+            { gen(URI, *p->simpleContent->extension->anyAttribute);
+              flag = false;
+            }
+            if (p->simpleContent->extension->complexTypePtr())
+              p = p->simpleContent->extension->complexTypePtr();
+            else
+              break;
+          }
+          else
+            break;
+        }
+        while (p);
+      }
+      else
+      { base = complexType.simpleContent->extension->base;
+        if (
+        /* TODO: in future, may want to add check here for base type == class
+          complexType.simpleContent->extension->simpleTypePtr()
+          ||
+        */
+          complexType.simpleContent->extension->complexTypePtr())
+        { if (complexType.simpleContent->extension->complexTypePtr()->schemaPtr())
+            baseURI = complexType.simpleContent->extension->complexTypePtr()->schemaPtr()->targetNamespace;
+          fprintf(stream, "class %s : public %s\n{ public:\n", t, cname(NULL, baseURI, base));
+          soapflag = true;
+        }
+        else
+        { if (complexType.simpleContent->extension->simpleTypePtr() && complexType.simpleContent->extension->simpleTypePtr()->schemaPtr())
+            baseURI = complexType.simpleContent->extension->simpleTypePtr()->schemaPtr()->targetNamespace;
+          else if (complexType.simpleContent->extension->complexTypePtr() && complexType.simpleContent->extension->complexTypePtr()->schemaPtr())
+            baseURI = complexType.simpleContent->extension->complexTypePtr()->schemaPtr()->targetNamespace;
+          if (pflag && complexType.name)
+            fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t);
+          else
+            fprintf(stream, "class %s\n{ public:\n", t);
+          fprintf(stream, "/// __item wraps '%s' simpleContent.\n", base);
+          fprintf(stream, elementformat, tname(NULL, baseURI, base), "__item");
+          fprintf(stream, ";\n");
+        }
+        gen(URI, complexType.simpleContent->extension->attribute);
+        gen(URI, complexType.simpleContent->extension->attributeGroup);
+        if (complexType.simpleContent->extension->anyAttribute)
+          gen(URI, *complexType.simpleContent->extension->anyAttribute);
+      }
+    }
+    else
+      fprintf(stream, "//\tunrecognized\n");
+  }
+  else if (complexType.complexContent)
+  { if (complexType.complexContent->restriction)
+    { if (!anonymous)
+        fprintf(stream, "\n/// \"%s\":%s is a%s complexType with complexContent restriction of %s.\n", URI?URI:"", name, complexType.abstract?"n abstract":"", complexType.complexContent->restriction->base);
+      document(complexType.annotation);
+      operations(t);
+      if (!strcmp(complexType.complexContent->restriction->base, "SOAP-ENC:Array"))
+      { char *item = NULL, *type = NULL;
+        if (!complexType.complexContent->restriction->attribute.empty())
+        { xs__attribute& attribute = complexType.complexContent->restriction->attribute.front();
+          if (attribute.wsdl__arrayType)
+            type = attribute.wsdl__arrayType;
+        }
+        xs__seqchoice *s = complexType.complexContent->restriction->sequence;
+        if (s
+         && !s->__contents.empty()
+         && s->__contents.front().__union == SOAP_UNION_xs__union_content_element
+         && s->__contents.front().__content.element)
+        { xs__element& element = *s->__contents.front().__content.element;
+          if (!type)
+          { if (element.type)
+              type = element.type;
+            else if (element.simpleTypePtr())
+            { if (element.simpleTypePtr()->name)
+                type = element.simpleTypePtr()->name;
+              else if (element.simpleTypePtr()->restriction)
+                type = element.simpleTypePtr()->restriction->base;
+            }
+            else if (element.complexTypePtr())
+            { if (element.complexTypePtr()->name)
+                type = element.complexTypePtr()->name;
+              else if (element.complexTypePtr()->complexContent && element.complexTypePtr()->complexContent->restriction)
+                type = element.complexTypePtr()->complexContent->restriction->base;
+            }
+          }
+          item = element.name; // <sequence><element name="item" type="..."/></sequence>
+        }
+        gen_soap_array(name, t, item, type);
+      }
+      else
+      { if (anonymous)
+        { if (cflag)
+            fprintf(stream, "    struct %s\n    {\n", t);
+          else
+            fprintf(stream, "    class %s\n    {\n", t);
+        }
+        else if (cflag)
+          fprintf(stream, "struct %s\n{\n", t);
+        else if (pflag && complexType.name)
+          fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t);
+        else
+          fprintf(stream, "class %s\n{ public:\n", t);
+        if (complexType.complexContent->restriction->group)
+          gen(URI, *complexType.complexContent->restriction->group, NULL, NULL);
+        if (complexType.complexContent->restriction->all)
+          gen(URI, *complexType.complexContent->restriction->all, NULL, NULL);
+        if (complexType.complexContent->restriction->sequence)
+          gen(URI, *complexType.complexContent->restriction->sequence, NULL, NULL);
+        if (complexType.complexContent->restriction->choice)
+          gen(URI, name, *complexType.complexContent->restriction->choice, NULL, NULL);
+        gen(URI, complexType.complexContent->restriction->attribute);
+	bool flag = true;
+        if (complexType.complexContent->restriction->anyAttribute)
+        { gen(URI, *complexType.complexContent->restriction->anyAttribute);
+	  flag = false;
+	}
+        const xs__complexType *p = complexType.complexContent->restriction->complexTypePtr();
+        while (p)
+        { const char *pURI;
+	  if (p->schemaPtr())
+            pURI = p->schemaPtr()->targetNamespace;
+          else
+            pURI = URI;
+          const char *b = cname(NULL, pURI, p->name);
+          if (zflag && zflag <= 5)
+            fprintf(stream, "/// RESTRICTED FROM %s:\n", b);
+          else if (comment_nest == 0)
+            fprintf(stream, "/*  RESTRICTED FROM %s:\n", b);
+          else
+            fprintf(stream, "    RESTRICTED FROM %s:\n", b);
+          comment_nest++;
+          if (p->complexContent && p->complexContent->restriction)
+          { gen(URI, p->complexContent->restriction->attribute);
+            if (p->complexContent->restriction->anyAttribute && flag)
+            { gen(URI, *p->complexContent->restriction->anyAttribute);
+              flag = false;
+            }
+            p = p->complexContent->restriction->complexTypePtr();
+          }
+          else if (p->complexContent && p->complexContent->extension)
+          { gen(URI, p->complexContent->extension->attribute);
+            gen(URI, p->complexContent->extension->attributeGroup);
+            if (p->complexContent->extension->anyAttribute && flag)
+            { gen(URI, *p->complexContent->extension->anyAttribute);
+              flag = false;
+            }
+            p = p->complexContent->extension->complexTypePtr();
+          }
+          else
+          { gen(URI, p->attribute);
+            gen(URI, p->attributeGroup);
+            if (p->anyAttribute && flag)
+              gen(URI, *p->anyAttribute);
+            p = NULL;
+          }
+	  comment_nest--;
+          if (zflag && zflag <= 5)
+            fprintf(stream, "//  END OF RESTRICTED FROM %s\n", b);
+          else if (comment_nest == 0)
+            fprintf(stream, "    END OF RESTRICTED FROM %s */\n", b);
+          else
+            fprintf(stream, "    END OF RESTRICTED FROM %s\n", b);
+        }
+      }
+    }
+    else if (complexType.complexContent->extension)
+    { const char *base = complexType.complexContent->extension->base;
+      xs__complexType *p = complexType.complexContent->extension->complexTypePtr();
+      if (!anonymous)
+        fprintf(stream, "\n/// \"%s\":%s is a%s complexType with complexContent extension of %s.\n", URI?URI:"", name, complexType.abstract?"n abstract":"", base);
+      document(complexType.annotation);
+      operations(t);
+      if (anonymous)
+      { if (cflag)
+          fprintf(stream, "    struct %s\n    {\n", t);
+        else
+          fprintf(stream, "    class %s\n    {\n", t);
+      }
+      else if (cflag)
+        fprintf(stream, "struct %s\n{\n", t);
+      else if (fflag)
+        fprintf(stream, "class %s\n{ public:\n", t);
+      else // TODO: what to do if base class is in another namespace and elements must be qualified in XML payload?
+      { const char *baseURI = NULL;
+        if (p && p->schemaPtr())
+          baseURI = p->schemaPtr()->targetNamespace;
+        fprintf(stream, "class %s : public %s\n{ public:\n", t, cname(NULL, baseURI, base));
+        soapflag = true;
+      }
+      gen_inh(URI, p, anonymous);
+      if (complexType.complexContent->extension->group)
+        gen(URI, *complexType.complexContent->extension->group, NULL, NULL);
+      if (complexType.complexContent->extension->all)
+        gen(URI, *complexType.complexContent->extension->all, NULL, NULL);
+      if (complexType.complexContent->extension->sequence)
+        gen(URI, *complexType.complexContent->extension->sequence, NULL, NULL);
+      if (complexType.complexContent->extension->choice)
+        gen(URI, name, *complexType.complexContent->extension->choice, NULL, NULL);
+      gen(URI, complexType.complexContent->extension->attribute);
+      gen(URI, complexType.complexContent->extension->attributeGroup);
+      if (complexType.complexContent->extension->anyAttribute)
+        gen(URI, *complexType.complexContent->extension->anyAttribute);
+    }
+    else
+      fprintf(stream, "//\tunrecognized\n");
+  }
+  else
+  { if (!anonymous)
+      fprintf(stream, "\n/// \"%s\":%s is a%s complexType.\n", URI?URI:"", name, complexType.abstract?"n abstract":"");
+    document(complexType.annotation);
+    operations(t);
+    if (anonymous)
+    { if (cflag)
+        fprintf(stream, "    struct %s\n    {\n", t);
+      else
+        fprintf(stream, "    class %s\n    {\n", t);
+    }
+    else if (cflag)
+      fprintf(stream, "struct %s\n{\n", t);
+    else if (pflag && complexType.name)
+      fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t);
+    else
+      fprintf(stream, "class %s\n{ public:\n", t);
+    if (complexType.all)
+      gen(URI, *complexType.all, NULL, NULL);
+    else if (complexType.choice)
+      gen(URI, name, *complexType.choice, NULL, NULL);
+    else if (complexType.sequence)
+      gen(URI, *complexType.sequence, NULL, NULL);
+    else if (complexType.any)
+      gen(URI, *complexType.any, NULL, NULL);
+  }
+  gen(URI, complexType.attribute);
+  gen(URI, complexType.attributeGroup);
+  if (complexType.anyAttribute)
+    gen(URI, *complexType.anyAttribute);
+  if (complexType.mixed
+   || (   complexType.complexContent
+       && complexType.complexContent->extension
+       && complexType.complexContent->extension->complexTypePtr()
+       && complexType.complexContent->extension->complexTypePtr()->mixed
+      ))
+  { fprintf(stream, "/// TODO: this mixed complexType is user-definable.\n///       Consult the protocol documentation to change or insert declarations.\n///       Use wsdl2h option -d for xsd__anyType DOM (soap_dom_element).\n");
+    if (dflag)
+    { if (with_union)
+        fprintf(stream, pointerformat, "xsd__anyType", "__mixed");
+      else
+        fprintf(stream, elementformat, "xsd__anyType", "__mixed");
+      fprintf(stream, "0;\t///< Catch mixed content in DOM soap_dom_element linked node structure.\n");
+    }
+    else
+    { fprintf(stream, elementformat, "_XML", "__mixed");
+      fprintf(stream, "0;\t///< Catch mixed content in XML string\n");
+    }
+  }
+  if (t)
+    modify(t);
+  if (!anonymous)
+  { if (!cflag
+     && !(pflag && complexType.name)
+     && !soapflag)
+    { if (!complexType.complexContent || !complexType.complexContent->extension || !complexType.complexContent->extension->complexTypePtr())
+      { fprintf(stream, "/// A handle to the soap struct that manages this instance (automatically set)\n");
+        fprintf(stream, pointerformat, "struct soap", "soap");
+        fprintf(stream, ";\n");
+      }
+    }
+    fprintf(stream, "};\n");
+  }
+  scope.pop_back();
+}
+
+void Types::gen(const char *URI, const vector<xs__attribute>& attributes)
+{ for (vector<xs__attribute>::const_iterator attribute = attributes.begin(); attribute != attributes.end(); ++attribute)
+    gen(URI, *attribute);
+}
+
+void Types::gen(const char *URI, const xs__attribute& attribute)
+{ const char *name, *type, *nameURI = NULL, *typeURI = NULL, *nameprefix = NULL, *typeprefix = NULL;
+  name = attribute.name;
+  type = attribute.type;
+  bool is_optional = attribute.use != required && attribute.use != default_ && attribute.use != fixed_ && !attribute.default_;
+  document(attribute.annotation);
+  if (!URI)
+    URI = attribute.schemaPtr()->targetNamespace;
+  if (attribute.form)
+  { if (*attribute.form == qualified)
+      nameURI = URI;
+    else
+      nameprefix = ":";
+  }
+  if (URI && attribute.schemaPtr() && attribute.schemaPtr()->targetNamespace && strcmp(URI,  attribute.schemaPtr()->targetNamespace))
+    nameURI = attribute.schemaPtr()->targetNamespace; // handles attributeGroup defined in another namespace
+  if (attribute.attributePtr()) // attribute ref
+  { name = attribute.attributePtr()->name;
+    type = attribute.attributePtr()->type;
+    if (!type)
+    { type = name;
+      typeprefix = "_";
+    }
+    if (attribute.attributePtr()->schemaPtr())
+    { typeURI = attribute.attributePtr()->schemaPtr()->targetNamespace;
+      if (attribute.form && *attribute.form == unqualified)
+        nameprefix = ":";
+      else if (zflag != 3 && zflag != 2
+       && URI
+       && typeURI
+       && attribute.schemaPtr()->elementFormDefault == qualified
+       && !strcmp(URI, typeURI))
+        nameprefix = NULL;
+      else if (zflag == 3
+       && URI
+       && typeURI
+       && attribute.schemaPtr()->attributeFormDefault == unqualified
+       && !strcmp(URI, typeURI))
+        nameprefix = NULL;
+      else
+        nameURI = typeURI;
+    }
+    fprintf(stream, "/// Attribute reference %s.\n", attribute.ref);
+    document(attribute.attributePtr()->annotation);
+    fprintf(stream, attributeformat, pname(is_optional, typeprefix, typeURI, type), aname(nameprefix, nameURI, name)); // make sure no name - type clash
+  }
+  else if (name && type)
+  { fprintf(stream, "/// Attribute %s of type %s.\n", name, type);
+    fprintf(stream, attributeformat, pname(is_optional, NULL, URI, type), aname(nameprefix, nameURI, name)); // make sure no name - type clash
+  }
+  else if (name && attribute.simpleTypePtr())
+  { fprintf(stream, "@");
+    gen(URI, name, *attribute.simpleTypePtr(), true);
+    // 8/1/09 Changed (is_optional && !cflag && !sflag) to is_optional
+    fprintf(stream, is_optional ? pointerformat : elementformat, "", aname(nameprefix, nameURI, name));
+  }
+  else if (attribute.ref)
+  { fprintf(stream, "/// Imported attribute reference %s.\n", attribute.ref);
+    fprintf(stream, attributeformat, pname(is_optional, "_", NULL, attribute.ref), aname(NULL, NULL, attribute.ref));
+  }
+  else
+  { fprintf(stream, "/// Attribute '%s' has no type or ref: assuming string content.\n", name?name:"");
+    fprintf(stream, attributeformat, tname(NULL, NULL, "xs:string"), aname(NULL, nameURI, name));
+  }
+  switch (attribute.use)
+  { case prohibited:
+      fprintf(stream, " 0:0");
+      break;
+    case required:
+      fprintf(stream, " 1");
+      break;
+    default:
+      fprintf(stream, " 0");
+      break;
+  }
+  if (attribute.default_
+   || (attribute.fixed && !is_optional))
+  { const char *value, *QName;
+    if (attribute.default_)
+    { value = attribute.default_;
+      QName = attribute.default__;
+    }
+    else
+    { value = attribute.fixed;
+      QName = attribute.fixed_;
+    }
+    const char *t = NULL;
+    if (!type && attribute.simpleTypePtr())
+    { if (attribute.simpleTypePtr()->restriction && attribute.simpleTypePtr()->restriction->base)
+      { if (!attribute.simpleTypePtr()->restriction->enumeration.empty())
+        { const char *s;
+          if (is_integer(value))
+            fprintf(stream, " = %s", value);
+          else if (!*value)
+            fprintf(stream, " = 0");
+          else if ((s = enames[Pair(gname(URI, name),value)]))
+            fprintf(stream, " = %s", s);
+        }
+        else
+        { const char *baseURI = NULL;
+          if (attribute.simpleTypePtr()->restriction->simpleTypePtr() && attribute.simpleTypePtr()->restriction->simpleTypePtr()->schemaPtr())
+            baseURI = attribute.simpleTypePtr()->restriction->simpleTypePtr()->schemaPtr()->targetNamespace;
+          t = tname(NULL, baseURI, attribute.simpleTypePtr()->restriction->base);
+        }
+      }
+    }
+    if (type && !t)
+      t = tname(NULL, typeURI?typeURI:URI, type);
+    if (t)
+    { if (!strncmp(t, "unsigned ", 9))
+        t += 9;
+      else if (!strncmp(t, "xsd__unsigned", 13))
+        t += 13;
+      else if (!strncmp(t, "xsd__", 5))
+        t += 5;
+      if (!strcmp(t, "bool")
+       || !strcmp(t, "byte")
+       || !strcmp(t, "Byte")
+       || !strcmp(t, "char")
+       || !strcmp(t, "double")
+       || !strcmp(t, "float")
+       || !strcmp(t, "int")
+       || !strcmp(t, "Int")
+       || !strcmp(t, "long")
+       || !strcmp(t, "Long")
+       || !strcmp(t, "LONG64")
+       || !strcmp(t, "short")
+       || !strcmp(t, "Short")
+       || !strcmp(t, "ULONG64"))
+        fprintf(stream, " = %s", value);
+      else if (!strncmp(t, "enum ", 5))
+      { const char *s;
+        if (is_integer(value))
+          fprintf(stream, " = %s", value);
+        else if (!*value)
+          fprintf(stream, " = 0");
+        else if ((s = enames[Pair(t + 5,value)]))
+          fprintf(stream, " = %s", s);
+      }
+      else if (!strcmp(t, "char*")
+            || !strcmp(t, "char *")	// not elegant
+            || !strcmp(t, "std::string")
+            || !strcmp(t, "std::string*")
+            || !strcmp(t, "std::string *"))	// not elegant
+        fprintf(stream, " = \"%s\"", cstring(value));
+      else if (!strcmp(t, "xsd__QName") && QName)	// QName
+        fprintf(stream, " = \"%s\"", cstring(QName));
+    }
+    if (attribute.default_)
+      fprintf(stream, ";\t///< Default value=\"%s\".\n", value);
+    else
+      fprintf(stream, ";\t///< Fixed required value=\"%s\".\n", value);
+  }
+  else if (attribute.fixed) 
+    fprintf(stream, ";\t///< Fixed optional value=\"%s\".\n", attribute.fixed);
+  else if (attribute.use == required)
+    fprintf(stream, ";\t///< Required attribute.\n");
+  else if (attribute.use == prohibited)
+    fprintf(stream, ";\t///< Prohibited attribute.\n");
+  else
+    fprintf(stream, ";\t///< Optional attribute.\n");
+}
+
+void Types::gen(const char *URI, const vector<xs__attributeGroup>& attributeGroups)
+{ for (vector<xs__attributeGroup>::const_iterator attributeGroup = attributeGroups.begin(); attributeGroup != attributeGroups.end(); ++attributeGroup)
+  { const xs__attributeGroup *ag = &*attributeGroup;
+    if (ag->attributeGroupPtr()) // attributeGroup ref
+      ag = ag->attributeGroupPtr();
+    fprintf(stream, "/// Begin attributeGroup %s.\n", ag->name?ag->name:ag->ref?ag->ref:"");
+    gen(URI, ag->attribute);
+    gen(URI, ag->attributeGroup);
+    if (ag->anyAttribute)
+      gen(URI, *ag->anyAttribute);
+    fprintf(stream, "/// End of attributeGroup %s.\n", ag->name?ag->name:ag->ref?ag->ref:"");
+  }
+}
+
+void Types::gen(const char *URI, const vector<xs__all>& alls)
+{ for (vector<xs__all>::const_iterator all = alls.begin(); all != alls.end(); ++all)
+    gen(URI, *all, NULL, NULL);
+}
+
+void Types::gen(const char *URI, const xs__all& all, const char *minOccurs, const char *maxOccurs)
+{ bool tmp_union1 = with_union;
+  bool tmp_union2 = fake_union;
+  with_union = false;
+  fake_union = false;
+  gen(URI, all.element, minOccurs, maxOccurs);
+  with_union = tmp_union1;
+  fake_union = tmp_union2;
+}
+
+void Types::gen(const char *URI, const vector<xs__contents>& contents)
+{ for (vector<xs__contents>::const_iterator content = contents.begin(); content != contents.end(); ++content)
+  { switch ((*content).__union)
+    { case SOAP_UNION_xs__union_content_element:
+        if ((*content).__content.element)
+          gen(URI, *(*content).__content.element, true, NULL, NULL);
+        break;
+      case SOAP_UNION_xs__union_content_group:
+        if ((*content).__content.group)
+          gen(URI, *(*content).__content.group, NULL, NULL);
+        break;
+      case SOAP_UNION_xs__union_content_choice:
+        if ((*content).__content.choice)
+          gen(URI, NULL, *(*content).__content.choice, NULL, NULL);
+        break;
+      case SOAP_UNION_xs__union_content_sequence:
+        if ((*content).__content.sequence)
+          gen(URI, *(*content).__content.sequence, NULL, NULL);
+        break;
+      case SOAP_UNION_xs__union_content_any:
+        if ((*content).__content.any)
+          gen(URI, *(*content).__content.any, NULL, NULL);
+        break;
+    }
+  }
+}
+
+void Types::gen(const char *URI, const xs__seqchoice& sequence, const char *minOccurs, const char *maxOccurs)
+{ const char *s = NULL;
+  char *t = NULL;
+  bool tmp_union = with_union;
+  with_union = false;
+  if (sequence.minOccurs)
+    minOccurs = sequence.minOccurs;
+  if (sequence.maxOccurs)
+    maxOccurs = sequence.maxOccurs;
+  if ((minOccurs && strcmp(minOccurs, "1"))
+   || (maxOccurs && strcmp(maxOccurs, "1")))
+  { fprintf(stream, "/// SEQUENCE <xs:sequence");
+    if (minOccurs)
+      fprintf(stream, " minOccurs=\"%s\"", minOccurs);
+    if (maxOccurs)
+      fprintf(stream, " maxOccurs=\"%s\"", maxOccurs);
+    fprintf(stream, ">\n");
+    document(sequence.annotation);
+    s = sname(URI, "sequence");
+    t = (char*)emalloc(strlen(s)+2);
+    strcpy(t, "_");
+    strcat(t, s);
+    s = strstr(s, "__");
+    if (!s)
+      s = t;
+    if (cflag || sflag || zflag == 2)
+    { fprintf(stream, sizeformat, "int", s + 1);
+      if (!fake_union && minOccurs)
+        fprintf(stream, " %s", minOccurs);
+      if (maxOccurs
+       && strcmp(maxOccurs, "1")
+       && is_integer(maxOccurs))
+        fprintf(stream, ":%s", maxOccurs);
+      fprintf(stream, ";\n");
+    }
+    else
+    { fprintf(stream, elementformat, "std::vector<", "");
+      fprintf(stream, "\n");
+    }
+    if (cflag)
+      fprintf(stream, "    struct %s\n    {\n", t);
+    else
+      fprintf(stream, "    class %s\n    {\n", t);
+  }
+  else
+  { if (fake_union)
+      fprintf(stream, "/// SEQUENCE <xs:sequence>\n");
+    document(sequence.annotation);
+  }
+  gen(URI, sequence.__contents);
+  if (s)
+  { if (cflag || sflag || zflag == 2)
+      fprintf(stream, pointerformat, "}", s);
+    else
+    { fprintf(stream, elementformat, "}>", s);
+      if (!fake_union && minOccurs)
+        fprintf(stream, " %s", minOccurs);
+      if (maxOccurs
+       && strcmp(maxOccurs, "1")
+       && is_integer(maxOccurs))
+        fprintf(stream, ":%s", maxOccurs);
+    }
+    fprintf(stream, ";\n");
+  }
+  if (s || fake_union)
+    fprintf(stream, "//  END OF SEQUENCE\n");
+  with_union = tmp_union;
+}
+
+void Types::gen(const char *URI, const vector<xs__element>& elements, const char *minOccurs, const char *maxOccurs)
+{ for (vector<xs__element>::const_iterator element = elements.begin(); element != elements.end(); ++element)
+    gen(URI, *element, true, minOccurs, maxOccurs);
+}
+
+void Types::gen(const char *URI, const xs__element& element, bool substok, const char *minOccurs, const char *maxOccurs)
+{ const char *name, *type, *nameURI = NULL, *typeURI = NULL, *nameprefix = NULL, *typeprefix = NULL;
+  name = element.name;
+  type = element.type;
+  document(element.annotation);
+  if (!URI)
+    URI = element.schemaPtr()->targetNamespace;
+  if (element.minOccurs)
+    minOccurs = element.minOccurs;
+  if (element.maxOccurs)
+    maxOccurs = element.maxOccurs;
+  if (element.xmime__expectedContentTypes)
+    fprintf(stream, "/// MTOM attachment with content types %s.\n", element.xmime__expectedContentTypes);
+  if (element.form)
+  { if (*element.form == qualified)
+      nameURI = URI;
+    else
+      nameprefix = ":";
+  }
+  if (element.elementPtr()) // element ref
+  { name = element.elementPtr()->name;
+    type = element.elementPtr()->type;
+    if (!type)
+    { type = name;
+      typeprefix = "_";
+    }
+    if (element.elementPtr()->schemaPtr())
+    { typeURI = element.elementPtr()->schemaPtr()->targetNamespace;
+      if (element.form && *element.form == unqualified)
+        nameprefix = ":";
+      else if (zflag != 3 && zflag != 2
+       && URI
+       && typeURI
+       && element.schemaPtr()->elementFormDefault == qualified
+       && !strcmp(URI, typeURI))
+        nameprefix = NULL;
+      else if (zflag == 3
+       && URI
+       && typeURI
+       && element.schemaPtr()->elementFormDefault == unqualified
+       && !strcmp(URI, typeURI))
+        nameprefix = NULL;
+      else
+        nameURI = typeURI;
+    }
+    document(element.elementPtr()->annotation);
+    if (element.elementPtr()->xmime__expectedContentTypes)
+      fprintf(stream, "/// MTOM attachment with content types %s.\n", element.elementPtr()->xmime__expectedContentTypes);
+    if (substok && element.elementPtr()->abstract)
+    { fprintf(stream, "/// Reference %s to abstract element.\n", element.ref);
+      gen_substitutions(URI, element);
+    }
+    else if (substok
+          && element.elementPtr()->substitutionsPtr()
+          && !element.elementPtr()->substitutionsPtr()->empty())
+    { if (vflag)
+        fprintf(stderr, "\nWarning: element ref '%s' stands as the head of a substitutionGroup but is not declared abstract\n", element.ref);
+      gen_substitutions(URI, element);
+    }
+    else if (maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+    { const char *s = tnameptr(cflag && zflag != 1, typeprefix, typeURI, type);
+      if (cflag || sflag)
+      { fprintf(stream, "/// Size of the dynamic array of %s is %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, sizeformat, "int", aname(NULL, NULL, name));
+        fprintf(stream, " %s", fake_union ? "0" : minOccurs ? minOccurs : "1");
+        if (is_integer(maxOccurs))
+          fprintf(stream, ":%s", maxOccurs);
+        fprintf(stream, ";\n");
+        if (cflag && zflag != 1)
+        { fprintf(stream, "/// Array %s of length %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+          fprintf(stream, elementformat, s, aname(nameprefix, nameURI, name));
+        }
+        else
+        { fprintf(stream, "/// Pointer to array %s of length %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+          fprintf(stream, pointerformat, s, aname(nameprefix, nameURI, name));
+        }
+      }
+      else
+      { fprintf(stream, "/// Vector of %s element refs with length %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+        if (with_union)
+          fprintf(stream, pointervectorformat, s, aname(nameprefix, nameURI, name));
+        else
+          fprintf(stream, vectorformat, s, aname(nameprefix, nameURI, name));
+      }
+    }
+    else
+    { fprintf(stream, "/// Element reference %s.\n", element.ref);
+      fprintf(stream, elementformat, pname((with_union && !cflag && !is_basetypeforunion(typeprefix, typeURI, type)) || fake_union || is_nillable(element), typeprefix, typeURI, type), aname(nameprefix, nameURI, name));
+    }
+  }
+  else if (name && type)
+  { if (substok && element.abstract)
+    { fprintf(stream, "/// Abstract element %s of type %s.\n", name, type);
+      gen_substitutions(URI, element);
+    }
+    else if (substok
+          && element.substitutionsPtr()
+          && !element.substitutionsPtr()->empty())
+    { if (vflag)
+        fprintf(stderr, "\nWarning: element '%s' stands as the head of a substitutionGroup but is not declared abstract\n", name);
+      gen_substitutions(URI, element);
+    }
+    else if (maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+    { const char *s = tnameptr(cflag && zflag != 1, NULL, URI, type);
+      if (cflag || sflag)
+      { fprintf(stream, "/// Size of array of %s is %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, sizeformat, "int", aname(NULL, NULL, name));
+        fprintf(stream, " %s", fake_union ? "0" : minOccurs ? minOccurs : "1");
+        if (is_integer(maxOccurs))
+          fprintf(stream, ":%s", maxOccurs);
+        fprintf(stream, ";\n");
+        if (cflag && zflag != 1)
+        { fprintf(stream, "/// Array %s of length %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+          fprintf(stream, elementformat, s, aname(nameprefix, nameURI, name));
+        }
+        else
+        { fprintf(stream, "/// Pointer to array %s of length %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+          fprintf(stream, pointerformat, s, aname(nameprefix, nameURI, name));
+        }
+      }
+      else
+      { fprintf(stream, "/// Vector of %s with length %s..%s\n", s, minOccurs ? minOccurs : "1", maxOccurs);
+        if (with_union)
+          fprintf(stream, pointervectorformat, s, aname(nameprefix, nameURI, name));
+        else
+          fprintf(stream, vectorformat, s, aname(nameprefix, nameURI, name));
+      }
+    }
+    else
+    { fprintf(stream, "/// Element %s of type %s.\n", name, type);
+      fprintf(stream, elementformat, pname((with_union && !cflag && !is_basetypeforunion(NULL, URI, type)) || (fake_union && !element.default_) || is_nillable(element), NULL, URI, type), aname(nameprefix, nameURI, name));
+    }
+  }
+  else if (name && element.simpleTypePtr())
+  { const char *s = "";
+    document(element.simpleTypePtr()->annotation);
+    if (maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+    { if (cflag || sflag)
+      { fprintf(stream, "/// Size of %s array is %s..%s\n", name, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, sizeformat, "int", aname(NULL, NULL, name));
+        fprintf(stream, " %s", fake_union ? "0" : minOccurs ? minOccurs : "1");
+        if (is_integer(maxOccurs))
+          fprintf(stream, ":%s", maxOccurs);
+        fprintf(stream, ";\n");
+      }
+      else
+      { s = ">";
+        fprintf(stream, "/// Vector of %s with length %s..%s\n", name, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, vectorformat_open, "\n");
+      }
+    }
+    gen(URI, name, *element.simpleTypePtr(), true);
+    if (is_nillable(element)
+     || ((cflag || sflag ) && maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+     || (with_union && !cflag)
+     || (fake_union && !element.default_))
+      fprintf(stream, pointerformat, s, aname(nameprefix, nameURI, name));
+    else
+      fprintf(stream, elementformat, s, aname(nameprefix, nameURI, name));
+  }
+  else if (name && element.complexTypePtr())
+  { const char *s = "}";
+    document(element.complexTypePtr()->annotation);
+    if (maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+    { if (cflag || sflag)
+      { fprintf(stream, "/// Size of %s array is %s..%s\n", name, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, sizeformat, "int", aname(NULL, NULL, name));
+        fprintf(stream, " %s", fake_union ? "0" : minOccurs ? minOccurs : "1");
+        if (is_integer(maxOccurs))
+          fprintf(stream, ":%s", maxOccurs);
+        fprintf(stream, ";\n");
+      }
+      else
+      { s = "}>";
+        fprintf(stream, "/// Vector of %s with length %s..%s\n", name, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, vectorformat_open, "\n");
+      }
+    }
+    gen(URI, name, *element.complexTypePtr(), true);
+    if (is_nillable(element)
+     || ((cflag || sflag ) && maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+     || (with_union && !cflag)
+     || (fake_union && !element.default_))
+      fprintf(stream, pointerformat, s, aname(nameprefix, nameURI, name));
+    else
+      fprintf(stream, elementformat, s, aname(nameprefix, nameURI, name));
+  }
+  else if (element.ref)
+  { fprintf(stream, "/// Imported element reference %s.\n", element.ref);
+    if (maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+    { if (cflag || sflag)
+      { fprintf(stream, "/// Size of %s array is %s..%s\n", element.ref, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, sizeformat, "int", aname(NULL, NULL, element.ref));
+        fprintf(stream, " %s", fake_union ? "0" : minOccurs ? minOccurs : "1");
+        if (is_integer(maxOccurs))
+          fprintf(stream, ":%s", maxOccurs);
+        fprintf(stream, ";\n");
+        fprintf(stream, pointerformat, pname(true, "_", NULL, element.ref), aname(nameprefix, nameURI, element.ref));
+      }
+      else
+      { fprintf(stream, "/// Vector of %s with length %s..%s\n", element.ref, minOccurs ? minOccurs : "1", maxOccurs);
+        fprintf(stream, vectorformat, pname(false, "_", NULL, element.ref), aname(nameprefix, nameURI, element.ref));
+      }
+    }
+    else
+      fprintf(stream, elementformat, pname((with_union && !cflag) || fake_union || is_nillable(element), "_", NULL, element.ref), aname(nameprefix, nameURI, element.ref));
+  }
+  else if (name)
+  { fprintf(stream, "/// Element '%s' has no type or ref (empty or with XML content).\n", name?name:"");
+    if (maxOccurs && strcmp(maxOccurs, "1")) // maxOccurs != "1"
+    { if (cflag || sflag)
+      { fprintf(stream, sizeformat, "int", aname(NULL, NULL, name));
+        fprintf(stream, " %s", fake_union ? "0" : minOccurs ? minOccurs : "1");
+        if (is_integer(maxOccurs))
+          fprintf(stream, ":%s", maxOccurs);
+        fprintf(stream, ";\n");
+        fprintf(stream, "/// Pointer to array of XML.\n");
+        fprintf(stream, pointerformat, "_XML", aname(NULL, nameURI, name));
+      }
+      else
+      { fprintf(stream, "/// Vector of XML with length %s..%s\n", minOccurs ? minOccurs : "1", maxOccurs);
+        if (with_union)
+          fprintf(stream, pointervectorformat, "_XML", aname(NULL, nameURI, name));
+        else
+          fprintf(stream, vectorformat, "_XML", aname(NULL, nameURI, name));
+      }
+    }
+    else
+      fprintf(stream, elementformat, "_XML", aname(NULL, nameURI, name));
+  }
+  else
+    fprintf(stream, "/// Element has no name, type, or ref.");
+  if (!substok
+   || (   !(element.elementPtr() && element.elementPtr()->abstract)
+       && !(element.substitutionsPtr() && !element.substitutionsPtr()->empty())
+       && !(element.elementPtr() && element.elementPtr()->substitutionsPtr() && !element.elementPtr()->substitutionsPtr()->empty())
+      ))
+  { if (!fake_union && !minOccurs && !element.nillable && !element.default_ && !element.abstract)
+      fprintf(stream, " 1");
+    else if (!fake_union && minOccurs)
+      fprintf(stream, " %s", minOccurs);
+    if (maxOccurs && strcmp(maxOccurs, "1") && is_integer(maxOccurs))
+      fprintf(stream, ":%s", maxOccurs);
+    if (element.default_
+     || (   element.fixed
+         && !fake_union
+         && (!minOccurs || !strcmp(minOccurs, "1"))
+         && (!maxOccurs || !strcmp(maxOccurs, "1"))
+        ))
+    { // determine whether the element can be assigned a default value, this is dependent on the choice of mapping for primitive types
+      const char *value, *QName;
+      if (element.default_)
+      { value = element.default_;
+        QName = element.default__;
+      }
+      else
+      { value = element.fixed;
+        QName = element.fixed_;
+      }
+      if (type)
+      { const char *t = tname(NULL, typeURI?typeURI:URI, type);
+        if (!strncmp(t, "unsigned ", 9))
+          t += 9;
+        else if (!strncmp(t, "xsd__unsigned", 13))
+          t += 13;
+        else if (!strncmp(t, "xsd__", 5))
+          t += 5;
+        if (!strcmp(t, "bool")
+         || !strcmp(t, "byte")
+         || !strcmp(t, "Byte")
+         || !strcmp(t, "char")
+         || !strcmp(t, "double")
+         || !strcmp(t, "float")
+         || !strcmp(t, "int")
+         || !strcmp(t, "Int")
+         || !strcmp(t, "long")
+         || !strcmp(t, "Long")
+         || !strcmp(t, "LONG64")
+         || !strcmp(t, "short")
+         || !strcmp(t, "Short")
+         || !strcmp(t, "ULONG64"))
+          fprintf(stream, " = %s", value);
+        else if (!strncmp(t, "enum ", 5))
+        { const char *s;
+          if (is_integer(value))
+            fprintf(stream, " = %s", value);
+          else if (!*value)
+            fprintf(stream, " = 0");
+          else if ((s = enames[Pair(t + 5, value)]))
+            fprintf(stream, " = %s", s);
+        }
+        else if (!strcmp(t, "char*")
+              || !strcmp(t, "char *")	// not elegant
+              || !strcmp(t, "std::string")
+              || !strcmp(t, "std::string*")
+              || !strcmp(t, "std::string *"))	// not elegant
+          fprintf(stream, " = \"%s\"", cstring(value));
+        else if (!strcmp(t, "xsd__QName") && QName)	// QName
+          fprintf(stream, " = \"%s\"", cstring(QName));
+      }
+      if (element.default_)
+        fprintf(stream, ";\t///< Default value=\"%s\".\n", value);
+      else
+        fprintf(stream, ";\t///< Fixed required value=\"%s\".\n", value);
+    }
+    else if (element.nillable)
+      fprintf(stream, ";\t///< Nillable pointer.\n");
+    else if (!fake_union && (!minOccurs || !strcmp(minOccurs, "1")) && (!maxOccurs || !strcmp(maxOccurs, "1")))
+      fprintf(stream, ";\t///< Required element.\n");
+    else if (element.fixed)
+      fprintf(stream, ";\t///< Fixed optional value=\"%s\".\n", element.fixed);
+    else if (!fake_union && minOccurs && !strcmp(minOccurs, "0") && (!maxOccurs || !strcmp(maxOccurs, "1")))
+      fprintf(stream, ";\t///< Optional element.\n");
+    else
+      fprintf(stream, ";\n");
+  }
+}
+
+void Types::gen(const char *URI, const vector<xs__group>& groups)
+{ for (vector<xs__group>::const_iterator group = groups.begin(); group != groups.end(); ++group)
+    gen(URI, *group, NULL, NULL);
+}
+
+void Types::gen(const char *URI, const xs__group& group, const char *minOccurs, const char *maxOccurs)
+{ if (group.minOccurs)
+    minOccurs = group.minOccurs;
+  if (group.maxOccurs)
+    maxOccurs = group.maxOccurs;
+  if (group.groupPtr())
+  { if (group.schemaPtr() == group.groupPtr()->schemaPtr())
+      gen(URI, *group.groupPtr(), minOccurs, maxOccurs);
+    else
+      gen(group.groupPtr()->schemaPtr()->targetNamespace, *group.groupPtr(), minOccurs, maxOccurs);
+  }
+  else
+  { fprintf(stream, "/// GROUP <xs:group name=\"%s\"", group.name ? group.name : "");
+    if (minOccurs)
+      fprintf(stream, " minOccurs=\"%s\"", minOccurs);
+    if (maxOccurs)
+      fprintf(stream, " maxOccurs=\"%s\"", maxOccurs);
+    fprintf(stream, ">\n");
+    document(group.annotation);
+    if (group.all)
+      gen(URI, *group.all, minOccurs, maxOccurs);
+    else if (group.choice)
+      gen(URI, NULL, *group.choice, minOccurs, maxOccurs);
+    else if (group.sequence)
+      gen(URI, *group.sequence, minOccurs, maxOccurs);
+    fprintf(stream, "//  END OF GROUP\n");
+  }
+}
+
+void Types::gen(const char *URI, const char *name, const xs__seqchoice& choice, const char *minOccurs, const char *maxOccurs)
+{ const char *r = NULL, *s = NULL, *t = NULL;
+  bool use_union = !uflag;
+  bool wrap_union = false;
+  bool tmp_union;
+  if (!URI && choice.schemaPtr())
+    URI = choice.schemaPtr()->targetNamespace;
+  fprintf(stream, "/// CHOICE <xs:choice");
+  if (choice.minOccurs)
+    minOccurs = choice.minOccurs;
+  if (choice.maxOccurs)
+    maxOccurs = choice.maxOccurs;
+  if (minOccurs)
+    fprintf(stream, " minOccurs=\"%s\"", minOccurs);
+  if (maxOccurs)
+    fprintf(stream, " maxOccurs=\"%s\"", maxOccurs);
+  fprintf(stream, ">\n");
+  document(choice.annotation);
+  for (vector<xs__contents>::const_iterator c1 = choice.__contents.begin(); c1 != choice.__contents.end(); ++c1)
+  { if ((*c1).__union == SOAP_UNION_xs__union_content_group
+     || (*c1).__union == SOAP_UNION_xs__union_content_sequence)
+    { fprintf(stream, "/// Note: <xs:choice> with embedded <xs:sequence> or <xs:group> prevents the use of a union\n");
+      use_union = false;
+      break;
+    }
+  }
+  if (use_union && (cflag || sflag))
+  { for (vector<xs__contents>::const_iterator c2 = choice.__contents.begin(); c2 != choice.__contents.end(); ++c2)
+    { if ((*c2).__union == SOAP_UNION_xs__union_content_element
+       && (*c2).__content.element
+       && (*c2).__content.element->maxOccurs
+       && strcmp((*c2).__content.element->maxOccurs, "1"))
+      { fprintf(stream, "/// Note: <xs:choice> of element with maxOccurs>1 prevents the use of a union\n");
+        use_union = false;
+        break;
+      }
+    }
+  }
+  t = uname(URI);
+  s = strstr(t, "__union");
+  if (s)
+    r = s + 7;
+  if (!r || !*r)
+  { r = t;
+    s = "__union";
+  }
+  if (maxOccurs && strcmp(maxOccurs, "1"))
+  { if (with_union)
+    { // Generate a wrapper when we need a union within a union
+      wrap_union = true;
+      fprintf(stream, "    struct __%s\n    {\n", t);
+    }
+    fprintf(stream, sizeformat, "int", r);
+    fprintf(stream, " %s", minOccurs ? minOccurs : "0");
+    if (is_integer(maxOccurs))
+      fprintf(stream, ":%s", maxOccurs);
+    fprintf(stream, ";\n");
+    if (cflag)
+      fprintf(stream, "    struct _%s\n    {\n", t);
+    else
+      fprintf(stream, "    class _%s\n    {\n", t);
+  }
+  if (use_union)
+  { if (!with_union || wrap_union)
+    { fprintf(stream, choiceformat, "int", r);
+      if (minOccurs)
+        fprintf(stream, " %s", minOccurs);
+      fprintf(stream, ";\t///< Union %s selector: set to SOAP_UNION_%s_<fieldname>%s\n", t, t, minOccurs && !strcmp(minOccurs, "0") ? " or 0" : "");
+      if (name)
+        fprintf(stream, "/// Union for choice in type %s\n", cname(NULL, URI, name));
+      fprintf(stream, "    union %s\n    {\n", t);
+    }
+    tmp_union = with_union;
+    with_union = true;
+  }
+  else
+  { tmp_union = fake_union;
+    fake_union = true;
+  }
+  gen(URI, choice.__contents);
+  if (use_union)
+  { with_union = tmp_union;
+    if (!with_union || wrap_union)
+      fprintf(stream, elementformat, "}", s+2);
+  }
+  else
+    fake_union = tmp_union;
+  if (maxOccurs && strcmp(maxOccurs, "1"))
+  { if (use_union)
+      fprintf(stream, ";\n");
+    fprintf(stream, pointerformat, "}", s);
+  }
+  fprintf(stream, ";\n");
+  if (wrap_union)
+  { fprintf(stream, elementformat, "}", s);
+    fprintf(stream, ";\n");
+  }
+  fprintf(stream, "//  END OF CHOICE\n");
+}
+
+void Types::gen(const char *URI, const vector<xs__any>& anys)
+{ for (vector<xs__any>::const_iterator any = anys.begin(); any != anys.end(); ++any)
+    gen(URI, *any, NULL, NULL);
+}
+
+void Types::gen(const char *URI, const xs__any& any, const char *minOccurs, const char *maxOccurs)
+{ fprintf(stream, "/// TODO: <any");
+  if (any.namespace_)
+    fprintf(stream, " namespace=\"%s\"", any.namespace_);
+  if (any.minOccurs)
+    minOccurs = any.minOccurs;
+  if (any.maxOccurs)
+    maxOccurs = any.maxOccurs;
+  if (minOccurs)
+    fprintf(stream, " minOccurs=\"%s\"", minOccurs);
+  if (maxOccurs)
+    fprintf(stream, " maxOccurs=\"%s\"", maxOccurs);
+  fprintf(stream, ">\n/// TODO: Schema extensibility is user-definable.\n///       Consult the protocol documentation to change or insert declarations.\n///       Use wsdl2h option -x to remove this element.\n///       Use wsdl2h option -d for xsd__anyType DOM (soap_dom_element).\n");
+  if (!xflag)
+  { if (maxOccurs && strcmp(maxOccurs, "1"))
+    { fprintf(stream, "/// Size of the array of XML or DOM nodes is %s..%s\n", minOccurs ? minOccurs : "1", maxOccurs);
+      if (cflag || sflag)
+      { if (!with_union)
+        { fprintf(stream, sizeformat, "int", "");
+          fprintf(stream, "0;\n");
+          fprintf(stream, elementformat, pname(true, NULL, NULL, "xsd:any"), "__any");
+        }
+        else
+          fprintf(stream, elementformat, tname(NULL, NULL, "xsd:any"), "__any");
+      }
+      else if (with_union)
+        fprintf(stream, pointervectorformat, tname(NULL, NULL, "xsd:any"), "__any");
+      else
+        fprintf(stream, vectorformat, tname(NULL, NULL, "xsd:any"), "__any");
+    }
+    else
+      fprintf(stream, elementformat, pname(with_union, NULL, NULL, "xsd:any"), "__any");
+    if (dflag)
+      fprintf(stream, "0;\t///< Catch any element content in DOM.\n");
+    else
+      fprintf(stream, "0;\t///< Catch any element content in XML string.\n");
+  }
+}
+
+void Types::gen(const char *URI, const xs__anyAttribute& anyAttribute)
+{ if (anyAttribute.namespace_)
+    fprintf(stream, "/// <anyAttribute namespace=\"%s\">\n", anyAttribute.namespace_);
+  fprintf(stream, "/// TODO: Schema extensibility is user-definable.\n///       Consult the protocol documentation to change or insert declarations.\n///       Use wsdl2h option -x to remove this attribute.\n///       Use wsdl2h option -d for xsd__anyAttribute DOM (soap_dom_attribute).\n");
+  if (!xflag)
+  { const char *t = tname(NULL, NULL, "xsd:anyAttribute");
+    fprintf(stream, attributeformat, t, "__anyAttribute");
+    if (dflag)
+      fprintf(stream, ";\t///< Store anyAttribute content in DOM soap_dom_attribute linked node structure.\n");
+    else
+      fprintf(stream, ";\t///< A placeholder that has no effect: please see comment.\n");
+  }
+}
+
+void Types::gen_inh(const char *URI, const xs__complexType *complexType, bool anonymous)
+{ const xs__complexType *p = complexType;
+  if (!p)
+    return;
+  const char *pURI;
+  if (p->schemaPtr())
+    pURI = p->schemaPtr()->targetNamespace;
+  else
+    pURI = URI;
+  const char *b = cname(NULL, pURI, p->name);
+  if (p->complexContent && p->complexContent->extension)
+    gen_inh(URI, p->complexContent->extension->complexTypePtr(), anonymous);
+  if (cflag || fflag || anonymous)
+    fprintf(stream, "/// INHERITED FROM %s:\n", b);
+  else if (comment_nest == 0)
+    fprintf(stream, "/*  INHERITED FROM %s:\n", b);
+  else
+    fprintf(stream, "    INHERITED FROM %s:\n", b);
+  comment_nest++;
+  if (cflag || fflag)
+    pURI = URI; // if base ns != derived ns then qualify elts
+  if (p->complexContent && p->complexContent->extension)
+  { if (p->complexContent->extension->group)
+      gen(pURI, *p->complexContent->extension->group, NULL, NULL);
+    if (p->complexContent->extension->all)
+      gen(pURI, *p->complexContent->extension->all, NULL, NULL);
+    if (p->complexContent->extension->sequence)
+      gen(pURI, *p->complexContent->extension->sequence, NULL, NULL);
+    if (p->complexContent->extension->choice)
+      gen(pURI, p->name, *p->complexContent->extension->choice, NULL, NULL);
+    gen(pURI, p->complexContent->extension->attribute);
+    gen(pURI, p->complexContent->extension->attributeGroup);
+    if (p->complexContent->extension->anyAttribute)
+      gen(pURI, *p->complexContent->extension->anyAttribute);
+  }
+  else
+  { if (p->all)
+      gen(pURI, p->all->element, NULL, NULL);
+    else if (p->all)
+      gen(pURI, *p->all, NULL, NULL);
+    else if (p->choice)
+      gen(pURI, p->name, *p->choice, NULL, NULL);
+    else if (p->sequence)
+      gen(pURI, *p->sequence, NULL, NULL);
+    else if (p->any)
+      gen(pURI, *p->any, NULL, NULL);
+    gen(pURI, p->attribute);
+    gen(pURI, p->attributeGroup);
+    if (p->anyAttribute)
+      gen(pURI, *p->anyAttribute);
+  }
+  modify(b);
+  comment_nest--;
+  if (cflag || fflag || anonymous)
+    fprintf(stream, "//  END OF INHERITED FROM %s\n", b);
+  else if (comment_nest == 0)
+    fprintf(stream, "    END OF INHERITED FROM %s */\n", b);
+  else
+    fprintf(stream, "    END OF INHERITED FROM %s\n", b);
+}
+
+void Types::gen_soap_array(const char *name, const char *t, const char *item, const char *type)
+{ char *tmp = NULL, *dims = NULL, size[8];
+  if (type)
+  { tmp = (char*)emalloc(strlen(type) + 1);
+    strcpy(tmp, type);
+  }
+  *size = '\0';
+  if (tmp)
+    dims = strrchr(tmp, '[');
+  if (dims)
+    *dims++ = '\0';
+  fprintf(stream, "/// SOAP encoded array of %s\n", tmp ? tmp : "xs:anyType");
+  if (cflag)
+    fprintf(stream, "struct %s\n{\n", t);
+  else if (pflag)
+    fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t);
+  else
+    fprintf(stream, "class %s\n{ public:\n", t);
+  if (dims)
+  { char *s = strchr(dims, ']');
+    if (s && s != dims)
+      sprintf(size, "[%d]", (int)(s - dims + 1));
+  }
+  if (tmp)
+  { if (strchr(tmp, '[') != NULL)
+    { gen_soap_array(NULL, "", item, tmp);
+      fprintf(stream, arrayformat, "}", item ? aname(NULL, NULL, item) : "");
+      fprintf(stream, ";\n");
+    }
+    else
+    { const char *s = pname(!is_basetype(NULL, NULL, tmp), NULL, NULL, tmp);
+      fprintf(stream, "/// Pointer to array of %s.\n", s);
+      fprintf(stream, arrayformat, s, item ? aname(NULL, NULL, item) : "");
+      fprintf(stream, ";\n");
+    }
+    if (*size)
+      fprintf(stream, "/// Size of the multidimensional dynamic array with dimensions=%s\n", size);
+    else 
+      fprintf(stream, "/// Size of the dynamic array.\n");
+    fprintf(stream, arraysizeformat, "int", size);
+    fprintf(stream, ";\n/// Offset for partially transmitted arrays (uncomment only when required).\n");
+    fprintf(stream, arrayoffsetformat, "int", size);
+    fprintf(stream, ";\n");
+  }
+  else
+  { // TODO: how to handle generic SOAP array? E.g. as an array of anyType?
+    fprintf(stream, "// TODO: add declarations to handle generic SOAP-ENC:Array (array of anyType)\n");
+  }
+}
+
+void Types::gen_substitutions(const char *URI, const xs__element &element)
+{ const std::vector<xs__element*> *substitutions;
+  const char *name;
+  const char *r = NULL, *s = NULL;
+  bool use_union = !uflag;
+  bool wrap_union = false;
+  bool tmp_union;
+  bool abstract = false;
+  if (!URI && element.schemaPtr())
+    URI = element.schemaPtr()->targetNamespace;
+  if (element.elementPtr())
+  { name = element.elementPtr()->name;
+    substitutions = element.elementPtr()->substitutionsPtr();
+    abstract = element.elementPtr()->abstract;
+    if (!abstract && element.elementPtr()->complexTypePtr())
+      abstract = element.elementPtr()->complexTypePtr()->abstract;
+  }
+  else
+  { name = element.name;
+    substitutions = element.substitutionsPtr();
+    abstract = element.abstract;
+    if (!abstract && element.complexTypePtr())
+      abstract = element.complexTypePtr()->abstract;
+  }
+  fprintf(stream, "/// CHOICE OF SUBSTITUTIONS <xs:element substitutionGroup=\"%s\"", name);
+  if (element.minOccurs)
+    fprintf(stream, " minOccurs=\"%s\"", element.minOccurs);
+  if (element.maxOccurs)
+    fprintf(stream, " maxOccurs=\"%s\"", element.maxOccurs);
+  fprintf(stream, "> with elements");
+  for (std::vector<xs__element*>::const_iterator i1 = substitutions->begin(); i1 != substitutions->end(); ++i1)
+    fprintf(stream, " <%s>", (*i1)->name);
+  fprintf(stream, "\n");
+  if (use_union)
+  { const char *t = uname(URI);
+    // TODO: could reuse the union instead of generating a new one each time!
+    s = strstr(t, "__union");
+    if (!s)
+      s = "__union";
+    r = aname(NULL, NULL, name);
+    if (element.maxOccurs && strcmp(element.maxOccurs, "1"))
+    { if (with_union)
+      { // Generate a wrapper when we need a union within a union
+        wrap_union = true;
+        fprintf(stream, "    struct __%s\n    {\n", t);
+      }
+      fprintf(stream, sizeformat, "int", r);
+      fprintf(stream, " %s", element.minOccurs ? element.minOccurs : "0");
+      if (is_integer(element.maxOccurs))
+        fprintf(stream, ":%s", element.maxOccurs);
+      fprintf(stream, ";\n");
+      if (cflag)
+        fprintf(stream, "    struct _%s\n    {\n", t);
+      else
+        fprintf(stream, "    class _%s\n    {\n", t);
+    }
+    if (!with_union || wrap_union)
+    { fprintf(stream, choiceformat, "int", r);
+      fprintf(stream, " %s", element.minOccurs ? element.minOccurs : "0");
+      fprintf(stream, ";\t///< Union %s selector: set to SOAP_UNION_%s_<fieldname>%s\n", t, t, element.minOccurs && !strcmp(element.minOccurs, "0") ? " or 0" : "");
+      fprintf(stream, "/// Union for substitutionGroup=\"%s\"\n", name);
+      fprintf(stream, "    union %s\n    {\n", t);
+    }
+    tmp_union = with_union;
+    with_union = true;
+  }
+  else
+  { tmp_union = fake_union;
+    fake_union = true;
+  }
+  if (!abstract)
+    gen(URI, element, false, NULL, NULL);
+  for (vector<xs__element*>::const_iterator i2 = substitutions->begin(); i2 != substitutions->end(); ++i2)
+     gen(URI, *(*i2), true, NULL, NULL); // substitutions are recursive?
+  if (use_union)
+  { with_union = tmp_union;
+    if (!with_union || wrap_union)
+    { fprintf(stream, elementformat, "}", s);
+      fprintf(stream, ";\n");
+    }
+    if (element.maxOccurs && strcmp(element.maxOccurs, "1"))
+    { fprintf(stream, ";\n");
+      fprintf(stream, pointerformat, "}", s);
+      fprintf(stream, ";\n");
+    }
+    if (wrap_union)
+    { fprintf(stream, elementformat, "}", s);
+      fprintf(stream, ";\n");
+    }
+  }
+  else
+    fake_union = tmp_union;
+  fprintf(stream, "//  END OF CHOICE OF SUBSTITUTIONS\n");
+}
+
+void Types::document(const xs__annotation *annotation)
+{ if (annotation && annotation->documentation)
+  { fprintf(stream, "/// @brief");
+    documentation(annotation->documentation);
+  }
+}
+
+void Types::modify(const char *name)
+{ // TODO: consider support removal of elements/attributes with ns__X = $- Y
+  const char *s = modtypemap[name];
+  if (s)
+  { while (*s)
+    { if (*s++ == '$')
+        fprintf(stream, "/// Member declared in %s\n   ", mapfile);
+      s = format(s);
+    }
+  }
+}
+
+const char* Types::format(const char *text)
+{ const char *s = text;
+  if (!s)
+    return NULL;
+  while (*s && *s != '$')
+  { if (*s == '\\')
+    { switch (s[1])
+      { case 'n': 
+          fputc('\n', stream);
+          break;
+        case 't': 
+          fputc('\t', stream);
+          break;
+        default:
+          fputc(s[1], stream);
+      }
+      s++;
+    }
+    else
+      fputc(*s, stream);
+    s++;
+  }
+  fputc('\n', stream);
+  return s;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Type map file parsing
+//
+////////////////////////////////////////////////////////////////////////////////
+
+static char *getline(char *s, size_t n, FILE *fd)
+{ int c;
+  char *t = s;
+  if (n)
+    n--;
+  for (;;)
+  { c = fgetc(fd);
+    if (c == '\r')
+      continue;
+    if (c == '\\')
+    { c = fgetc(fd);
+      if (c == '\r')
+        c = fgetc(fd);
+      if (c < ' ')
+        continue;
+      if (n)
+      { *t++ = '\\';
+        n--;
+      }
+    }
+    if (c == '\n' || c == EOF)
+      break;
+    if (n)
+    { *t++ = c;
+      n--;
+    }
+  }
+  *t++ = '\0';
+  if (!*s && c == EOF)
+    return NULL;
+  return s;
+}
+
+static const char *nonblank(const char *s)
+{ while (*s && isspace(*s))
+    s++;
+  return s;
+}
+
+static const char *fill(char *t, int n, const char *s, int e)
+{ int i = n;
+  s = nonblank(s);
+  while (*s && *s != e && --i)
+    *t++ = *s++;
+  while (*s && *s != e)
+    s++;
+  if (*s)
+    s++;
+  i = n - i;
+  if (i == 0)
+    *t = '\0';
+  else
+  { while (isspace(*--t) && i--)
+      ;
+    t[1] = '\0';
+  }
+  return s;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Miscellaneous
+//
+////////////////////////////////////////////////////////////////////////////////
+
+static const char *utf8(char *t, const char *s)
+{ unsigned int c = 0;
+  unsigned int c1, c2, c3, c4;
+  c = (unsigned char)*s;
+  if (c >= 0x80)
+  { c1 = (unsigned char)*++s;
+    if (c1 < 0x80)
+      s--;
+    else
+    { c1 &= 0x3F;
+      if (c < 0xE0)
+        c = ((c & 0x1F) << 6) | c1;
+      else
+      { c2 = (unsigned char)*++s & 0x3F;
+        if (c < 0xF0)
+          c = ((c & 0x0F) << 12) | (c1 << 6) | c2;
+        else
+        { c3 = (unsigned char)*++s & 0x3F;
+          if (c < 0xF8)
+            c = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
+          else
+          { c4 = (unsigned char)*++s & 0x3F;
+            if (c < 0xFC)
+              c = ((c & 0x03) << 24) | (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
+            else
+              c = ((c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | (*++s & 0x3F);
+          }
+        }
+      }
+    }
+  }
+  sprintf(t, "_x%.4x", c);
+  return s;
+}
+
+static const char *cstring(const char *s)
+{ size_t n;
+  char *t;
+  const char *r;
+  for (n = 0, r = s; *r; n++, r++)
+    if (*r == '"' || *r == '\\')
+      n++;
+    else if (*r < 32)
+      n += 3;
+  r = t = (char*)emalloc(n + 1);
+  for (; *s; s++)
+  { if (*s == '"' || *s == '\\')
+    { *t++ = '\\';
+      *t++ = *s;
+    }
+    else if (*s < 32)
+    { sprintf(t, "\\%03o", (unsigned int)(unsigned char)*s);
+      t += 4;
+    }
+    else
+      *t++ = *s;
+  }
+  *t = '\0';
+  return r;
+}
+
+static const char *xstring(const char *s)
+{ size_t n;
+  char *t;
+  const char *r;
+  for (n = 0, r = s; *r; n++, r++)
+  { if (*r < 32 || *r >= 127)
+      n += 4;
+    else if (*r == '<' || *r == '>')
+      n += 3;
+    else if (*r == '&')
+      n += 4;
+    else if (*r == '"')
+      n += 5;
+    else if (*r == '\\')
+      n += 1;
+  }
+  r = t = (char*)emalloc(n + 1);
+  for (; *s; s++)
+  { if (*s < 32 || *s >= 127)
+    { sprintf(t, "&#%.2x;", (unsigned char)*s);
+      t += 5;
+    }
+    else if (*s == '<')
+    { strcpy(t, "&lt;");
+      t += 4;
+    }
+    else if (*s == '>')
+    { strcpy(t, "&gt;");
+      t += 4;
+    }
+    else if (*s == '&')
+    { strcpy(t, "&amp;");
+      t += 5;
+    }
+    else if (*s == '"')
+    { strcpy(t, "&quot;");
+      t += 6;
+    }
+    else if (*s == '\\')
+    { strcpy(t, "\\\\");
+      t += 2;
+    }
+    else
+      *t++ = *s;
+  }
+  *t = '\0';
+  return r;
+}
+
+static LONG64 to_integer(const char *s)
+{ LONG64 n;
+#ifdef HAVE_STRTOLL
+  char *r;
+  n = soap_strtoll(s, &r, 10);
+#else
+# ifdef HAVE_SSCANF
+  sscanf(s, SOAP_LONG_FORMAT, &n);
+# endif
+#endif
+  return n;
+}
+
+static bool is_integer(const char *s)
+{ if ((*s == '-' || *s == '+') && s[1])
+    s++;
+  if (!*s || strlen(s) > 20)
+    return false;
+  while (*s && isdigit(*s))
+    s++;
+  return *s == '\0';
+}
+
+static void documentation(const char *text)
+{ const char *s = text;
+  bool flag = true;
+  if (!s)
+    return;
+  while (*s)
+  { switch (*s)
+    { case '\n':
+      case '\t':
+      case ' ':
+        flag = true;
+        break;
+      default:
+        if (*s > 32)
+        { if (flag)
+          { fputc(' ', stream);
+            flag = false;
+          }
+          fputc(*s, stream);
+        }
+    }
+    s++;
+  }
+  fputc('\n', stream);
+}
+
+static void operations(const char *t)
+{ if (!cflag)
+    fprintf(stream, "/// class %s operations:\n/// - soap_new_%s(soap*) allocate\n/// - soap_new_%s(soap*, int num) allocate array\n/// - soap_new_req_%s(soap*, ...) allocate, set required members\n/// - soap_new_set_%s(soap*, ...) allocate, set all public members\n/// - int soap_read_%s(soap*, %s*) deserialize from a stream\n/// - int soap_write_%s(soap, %s*) serialize to a stream\n", t, t, t, t, t, t, t, t, t);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Allocation
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void *emalloc(size_t size)
+{ void *p = malloc(size);
+  if (!p)
+  { fprintf(stderr, "\nError: Malloc failed\n");
+    exit(1);
+  }
+  return p;
+}
+
+char *estrdup(const char *s)
+{ char *t = (char*)emalloc(strlen(s) + 1);
+  strcpy(t, s);
+  return t;
+}
+
+char *estrdupf(const char *s)
+{ char *t = (char*)emalloc(strlen(s) + 1);
+  char *p;
+  for (p = t; *s; s++)
+  { if (s[0] == '/' && s[1] == '*')
+    { for (s += 2; s[0] && s[1]; s++)
+      { if (s[0] == '*' && s[1] == '/')
+        { s++;
+          break;
+        }
+      }
+      continue;
+    }
+    *p++ = *s;
+  }
+  *p = '\0';
+  return t;
+}