/***************************************************************************
    begin       : Thu Jul 02 2009
    copyright   : (C) 2018 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *          Please see toplevel file COPYING for license details           *
 ***************************************************************************/



#include "tm_builder_c.h"

#include <gwenhywfar/debug.h>

#include <ctype.h>
#include <string.h>



/* DEBUG */
/*DBG_ERROR(0, "Member %s has flags %x", Typemaker2_Member_GetName(tm), Typemaker2_Member_GetFlags(tm));*/



static int _buildFieldIds(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  char numbuf[16];

  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE)) {
        GWEN_Buffer_AppendString(tbuf, "#define ");
        s=Typemaker2_Member_GetFieldId(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");

        snprintf(numbuf, sizeof(numbuf)-1, "%d",
                 Typemaker2_Member_GetMemberPosition(tm));
        GWEN_Buffer_AppendString(tbuf, numbuf);
        GWEN_Buffer_AppendString(tbuf, "\n");
      }

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "#define ");
  s=Typemaker2_Type_GetFieldCountId(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " ");

  snprintf(numbuf, sizeof(numbuf)-1, "%d",
           Typemaker2_Type_GetNonVolatileMemberCount(ty));
  GWEN_Buffer_AppendString(tbuf, numbuf);
  GWEN_Buffer_AppendString(tbuf, "\n");

  Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



/** writes typedef line into public header and also writes includes */
static int _buildTypedef(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  uint32_t flags;
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_HEADER_LIST *hl;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  /* add some system headers */
  GWEN_Buffer_AppendString(tbuf, "/* needed system headers */\n");
  GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/types.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/list1.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST2)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/list2.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/tree.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/tree2.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_INHERIT)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/inherit.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_IDMAP)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/idmap.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_DB)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/db.h>\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_XML)
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/xml.h>\n");
  if ((flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) || (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS))
    GWEN_Buffer_AppendString(tbuf, "#include <gwenhywfar/gwensignal.h>\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  /* handle pre-headers */
  hl=Typemaker2_Type_GetHeaders(ty);
  if (hl) {
    TYPEMAKER2_HEADER *h;

    h=Typemaker2_Header_List_First(hl);
    if (h) {
      GWEN_Buffer_AppendString(tbuf, "/* pre-headers */\n");
      while (h) {
        if (Typemaker2_Header_GetLocation(h)==Typemaker2_HeaderLocation_Pre) {
          GWEN_Buffer_AppendString(tbuf, "#include ");

          if (Typemaker2_Header_GetType(h)==Typemaker2_HeaderType_System) {
            GWEN_Buffer_AppendString(tbuf, "<");
            GWEN_Buffer_AppendString(tbuf, Typemaker2_Header_GetFileName(h));
            GWEN_Buffer_AppendString(tbuf, ">");
          }
          else {
            GWEN_Buffer_AppendString(tbuf, "\"");
            GWEN_Buffer_AppendString(tbuf, Typemaker2_Header_GetFileName(h));
            GWEN_Buffer_AppendString(tbuf, "\"");
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
        }
        h=Typemaker2_Header_List_Next(h);
      }
      GWEN_Buffer_AppendString(tbuf, "\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_OBJECT) {
    GWEN_Buffer_AppendString(tbuf, "#include <aqdatabase/aqdb.h>\n");
  }

  GWEN_Buffer_AppendString(tbuf, "typedef struct ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " ");
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, ";\n");

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_LIST_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_LIST_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST2) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_LIST2_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_LIST2_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_CONSTLIST2) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_CONSTLIST2_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_CONSTLIST2_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_TREE_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_TREE_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_TREE2_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_TREE2_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_INHERIT) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_INHERIT_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_INHERIT_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_IDMAP) {
    if (Typemaker2_TypeManager_GetApiDeclaration(tym)) {
      GWEN_Buffer_AppendString(tbuf, "GWEN_IDMAP_FUNCTION_LIB_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
    else {
      GWEN_Buffer_AppendString(tbuf, "GWEN_IDMAP_FUNCTION_DEFS(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ", ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ")\n");
    }
  }
  GWEN_Buffer_AppendString(tbuf, "\n");


  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_OBJECT) {
    GWEN_Buffer_AppendString(tbuf, "#include <aqdatabase/aqdb_db.h>\n");
  }
  GWEN_Buffer_AppendString(tbuf, "\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildPostHeaders(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  TYPEMAKER2_TYPEMANAGER *tym GWEN_UNUSED;
  TYPEMAKER2_HEADER_LIST *hl;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* handle post-headers */
  hl=Typemaker2_Type_GetHeaders(ty);
  if (hl) {
    TYPEMAKER2_HEADER *h;

    h=Typemaker2_Header_List_First(hl);
    if (h) {
      GWEN_Buffer_AppendString(tbuf, "/* post-headers */\n");
      while (h) {
        if (Typemaker2_Header_GetLocation(h)==Typemaker2_HeaderLocation_Post) {
          GWEN_Buffer_AppendString(tbuf, "#include ");

          if (Typemaker2_Header_GetType(h)==Typemaker2_HeaderType_System) {
            GWEN_Buffer_AppendString(tbuf, "<");
            GWEN_Buffer_AppendString(tbuf, Typemaker2_Header_GetFileName(h));
            GWEN_Buffer_AppendString(tbuf, ">");
          }
          else {
            GWEN_Buffer_AppendString(tbuf, "\"");
            GWEN_Buffer_AppendString(tbuf, Typemaker2_Header_GetFileName(h));
            GWEN_Buffer_AppendString(tbuf, "\"");
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
        }
        h=Typemaker2_Header_List_Next(h);
      }
    }
    GWEN_Buffer_AppendString(tbuf, "\n");
  }

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildEndHeaders(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  TYPEMAKER2_TYPEMANAGER *tym GWEN_UNUSED;
  TYPEMAKER2_HEADER_LIST *hl;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* handle post-headers */
  hl=Typemaker2_Type_GetHeaders(ty);
  if (hl) {
    TYPEMAKER2_HEADER *h;

    h=Typemaker2_Header_List_First(hl);
    if (h) {
      GWEN_Buffer_AppendString(tbuf, "/* end-headers */\n");
      while (h) {
        if (Typemaker2_Header_GetLocation(h)==Typemaker2_HeaderLocation_HeaderEnd) {
          GWEN_Buffer_AppendString(tbuf, "#include ");

          if (Typemaker2_Header_GetType(h)==Typemaker2_HeaderType_System) {
            GWEN_Buffer_AppendString(tbuf, "<");
            GWEN_Buffer_AppendString(tbuf, Typemaker2_Header_GetFileName(h));
            GWEN_Buffer_AppendString(tbuf, ">");
          }
          else {
            GWEN_Buffer_AppendString(tbuf, "\"");
            GWEN_Buffer_AppendString(tbuf, Typemaker2_Header_GetFileName(h));
            GWEN_Buffer_AppendString(tbuf, "\"");
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
        }
        h=Typemaker2_Header_List_Next(h);
      }
    }
    GWEN_Buffer_AppendString(tbuf, "\n");
  }

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildStruct(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  uint32_t flags;
  TYPEMAKER2_VIRTUALFN_LIST *fns;

  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  GWEN_Buffer_AppendString(tbuf, "struct ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " {\n");

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_INHERIT) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_INHERIT_ELEMENT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_LIST_ELEMENT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_TREE_ELEMENT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_TREE2_ELEMENT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if ((flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) || (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS)) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_SIGNALOBJECT *_signalObject;");
    GWEN_Buffer_AppendString(tbuf, "\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_REFCOUNT)
    GWEN_Buffer_AppendString(tbuf, "  int _refCount;\n");


  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;
      int typeIsWritten=0;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      GWEN_Buffer_AppendString(tbuf, "  ");

      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
        TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
        const char *s;

        assert(te);
        s=Typemaker2_Enum_GetType(te);
        if (s && *s) {
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " ");
          typeIsWritten=1;
        }
      }

      if (!typeIsWritten) {
        if ((Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) &&
            (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_CONST))
          GWEN_Buffer_AppendString(tbuf, "const ");

        s=Typemaker2_Type_GetIdentifier(mty);
        if (!(s && *s)) {
          const char *xx;

          xx=Typemaker2_Member_GetName(tm);
          DBG_ERROR(0, "Member [%s] has no identifier", xx?xx:"(unnamed)");
          GWEN_Buffer_free(tbuf);
          return GWEN_ERROR_BAD_DATA;
        }
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");

        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer)
          GWEN_Buffer_AppendString(tbuf, "*");
      }

      s=Typemaker2_Member_GetName(tm);
      GWEN_Buffer_AppendString(tbuf, s);
      if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
        char numbuf[32];

        snprintf(numbuf, sizeof(numbuf)-1, "[%d]",
                 Typemaker2_Member_GetMaxLen(tm));
        GWEN_Buffer_AppendString(tbuf, numbuf);
      }

      GWEN_Buffer_AppendString(tbuf, ";");
      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE)
        GWEN_Buffer_AppendString(tbuf, " /* volatile */");
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  /* add virtual functions */
  fns=Typemaker2_Type_GetVirtualFns(ty);
  assert(fns);
  if (Typemaker2_VirtualFn_List_GetCount(fns)) {
    const char *s;
    TYPEMAKER2_VIRTUALFN *vf;

    vf=Typemaker2_VirtualFn_List_First(fns);
    while (vf) {
      GWEN_Buffer_AppendString(tbuf, "  ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        DBG_ERROR(0, "Virtual function has no name");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      while (*s)
        GWEN_Buffer_AppendByte(tbuf, toupper(*(s++)));
      GWEN_Buffer_AppendString(tbuf, "_FN ");

      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        DBG_ERROR(0, "Virtual function has no name");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendByte(tbuf, tolower(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "Fn;\n");

      vf=Typemaker2_VirtualFn_List_Next(vf);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "};\n");

  Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildMacroFunctions(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  uint32_t flags;
  /* TYPEMAKER2_TYPEMANAGER *tym; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  GWEN_Buffer_AppendString(tbuf, "/* macro functions */\n");

  flags=Typemaker2_Type_GetFlags(ty);
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_LIST_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST2) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_LIST2_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_CONSTLIST2) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_CONSTLIST2_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_TREE_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_TREE2_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_INHERIT) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_INHERIT_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_IDMAP) {
    GWEN_Buffer_AppendString(tbuf, "GWEN_IDMAP_FUNCTIONS(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }
  GWEN_Buffer_AppendString(tbuf, "\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildConstructor(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  uint32_t flags;
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_VIRTUALFN_LIST *tvfl;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  /* prototype */
  if (Typemaker2_Type_GetUsePrivateConstructor(ty)) {
    GWEN_Buffer_AppendString(tbuf, "/** Private constructor. */\n");
  }
  else {
    GWEN_Buffer_AppendString(tbuf, "/** Constructor. */\n");
    s=Typemaker2_TypeManager_GetApiDeclaration(tym);
    if (s) {
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " ");
    }
  }

  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  /* created structs are always pointers */
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  if (Typemaker2_Type_GetUsePrivateConstructor(ty))
    GWEN_Buffer_AppendString(tbuf, "_");
  GWEN_Buffer_AppendString(tbuf, "_new(void)");
  GWEN_Buffer_AppendString(tbuf, ";\n");
  if (Typemaker2_Type_GetUsePrivateConstructor(ty))
    Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  else
    Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  if (Typemaker2_Type_GetUsePrivateConstructor(ty))
    GWEN_Buffer_AppendString(tbuf, "_");
  GWEN_Buffer_AppendString(tbuf, "_new(void)");
  GWEN_Buffer_AppendString(tbuf, " {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  GWEN_NEW_OBJECT(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_REFCOUNT)
    GWEN_Buffer_AppendString(tbuf, "  p_struct->_refCount=1;\n");

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_INHERIT) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_INHERIT_INIT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_LIST_INIT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_TREE_INIT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2) {
    GWEN_Buffer_AppendString(tbuf, "  GWEN_TREE2_INIT(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct,");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  if ((flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) || (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS)) {
    GWEN_Buffer_AppendString(tbuf, "  p_struct->_signalObject=GWEN_SignalObject_new();\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) {
    TYPEMAKER2_SIGNAL_LIST *slist;

    GWEN_Buffer_AppendString(tbuf, "  /* generate pre-defined signals */\n");
    slist=Typemaker2_Type_GetSignals(ty);
    if (slist) {
      TYPEMAKER2_SIGNAL *sig;

      sig=Typemaker2_Signal_List_First(slist);
      while (sig) {
        s=Typemaker2_Signal_GetName(sig);
        GWEN_Buffer_AppendString(tbuf, "  /* signal \"");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        GWEN_Buffer_AppendString(tbuf, "  GWEN_Signal_new(p_struct->_signalObject, NULL, ");
        /* name */
        GWEN_Buffer_AppendString(tbuf, "\"");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\", ");

        /* param type 1 */
        s=Typemaker2_Signal_GetParamType1(sig);
        GWEN_Buffer_AppendString(tbuf, "\"");
        GWEN_Buffer_AppendString(tbuf, s?s:"none");
        GWEN_Buffer_AppendString(tbuf, "\", ");

        /* param type 2 */
        s=Typemaker2_Signal_GetParamType2(sig);
        GWEN_Buffer_AppendString(tbuf, "\"");
        GWEN_Buffer_AppendString(tbuf, s?s:"none");
        GWEN_Buffer_AppendString(tbuf, "\");\n");

        sig=Typemaker2_Signal_List_Next(sig);
      }
    }
  }


  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS) {
    TYPEMAKER2_SLOT_LIST *slist;

    GWEN_Buffer_AppendString(tbuf, "  /* generate pre-defined slots */\n");
    slist=Typemaker2_Type_GetSlots(ty);
    if (slist) {
      TYPEMAKER2_SLOT *slot;

      slot=Typemaker2_Slot_List_First(slist);
      while (slot) {
        s=Typemaker2_Slot_GetName(slot);
        GWEN_Buffer_AppendString(tbuf, "  /* slot \"");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        GWEN_Buffer_AppendString(tbuf, "  GWEN_Slot_new(p_struct->_signalObject, NULL, ");
        /* name */
        GWEN_Buffer_AppendString(tbuf, "\"");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\", ");

        /* param type 1 */
        s=Typemaker2_Slot_GetParamType1(slot);
        GWEN_Buffer_AppendString(tbuf, "\"");
        GWEN_Buffer_AppendString(tbuf, s?s:"none");
        GWEN_Buffer_AppendString(tbuf, "\", ");

        /* param type 2 */
        s=Typemaker2_Slot_GetParamType2(slot);
        GWEN_Buffer_AppendString(tbuf, "\"");
        GWEN_Buffer_AppendString(tbuf, s?s:"none");
        GWEN_Buffer_AppendString(tbuf, "\", ");

        /* callback function */
        s=Typemaker2_Type_GetPrefix(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_SlotCallback_");
        s=Typemaker2_Slot_GetName(slot);
        GWEN_Buffer_AppendByte(tbuf, toupper(*s));
        GWEN_Buffer_AppendString(tbuf, s+1);
        GWEN_Buffer_AppendString(tbuf, ", (void*) p_struct");
        GWEN_Buffer_AppendString(tbuf, ");\n");



        slot=Typemaker2_Slot_List_Next(slot);
      }
    }
  }


  GWEN_Buffer_AppendString(tbuf, "  /* members */\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;
    int rv;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;
      GWEN_BUFFER *dstbuf;

      dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
      GWEN_Buffer_AppendString(dstbuf, "p_struct->");
      s=Typemaker2_Member_GetName(tm);
      GWEN_Buffer_AppendString(dstbuf, s);

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      GWEN_Buffer_AppendString(tbuf, "  ");

      rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                               NULL, /* no source */
                                               GWEN_Buffer_GetStart(dstbuf),
                                               tbuf);
      if (rv<0) {
        DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
        GWEN_Buffer_free(dstbuf);
        GWEN_Buffer_free(tbuf);
        return rv;
      }
      GWEN_Buffer_free(dstbuf);

      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  tvfl=Typemaker2_Type_GetVirtualFns(ty);
  if (tvfl) {
    TYPEMAKER2_VIRTUALFN *tvf;

    GWEN_Buffer_AppendString(tbuf, "  /* virtual functions */\n");
    tvf=Typemaker2_VirtualFn_List_First(tvfl);
    while (tvf) {
      const char *fname;
      const char *fpreset;

      fname=Typemaker2_VirtualFn_GetName(tvf);
      fpreset=Typemaker2_VirtualFn_GetPreset(tvf);
      if (fname && *fname && fpreset && *fpreset) {
        GWEN_Buffer_AppendString(tbuf, "  ");
        GWEN_Buffer_AppendString(tbuf, "p_struct->");
        GWEN_Buffer_AppendByte(tbuf, tolower(*fname));
        GWEN_Buffer_AppendString(tbuf, fname+1);
        GWEN_Buffer_AppendString(tbuf, "Fn=");
        GWEN_Buffer_AppendString(tbuf, fpreset);
        GWEN_Buffer_AppendString(tbuf, ";\n");
      }
      tvf=Typemaker2_VirtualFn_List_Next(tvf);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "\n");
  GWEN_Buffer_AppendString(tbuf, "  return p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildDestructor(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  uint32_t flags;
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  /* prototype */
  GWEN_Buffer_AppendString(tbuf, "/** Destructor. */\n");
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_free(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* insert freeHook prototype, if needed */
  s=Typemaker2_Type_GetFreeHook(ty);
  if (s && *s) {
    GWEN_Buffer_AppendString(tbuf, "static void ");
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, "(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");
    Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);
  }


  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_free(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct) {\n");

  GWEN_Buffer_AppendString(tbuf, "  if (p_struct) {\n");

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_REFCOUNT) {
    GWEN_Buffer_AppendString(tbuf, "  assert(p_struct->_refCount);\n");
    GWEN_Buffer_AppendString(tbuf, "  if (p_struct->_refCount==1) {\n");
  }

  if ((flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) || (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS)) {
    GWEN_Buffer_AppendString(tbuf, "    GWEN_SignalObject_free(p_struct->_signalObject);\n");
  }

  /* insert freeHook, if any */
  s=Typemaker2_Type_GetFreeHook(ty);
  if (s && *s) {
    GWEN_Buffer_AppendString(tbuf, "    ");
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, "(p_struct);\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_INHERIT) {
    GWEN_Buffer_AppendString(tbuf, "    GWEN_INHERIT_FINI(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
    GWEN_Buffer_AppendString(tbuf, "    GWEN_LIST_FINI(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE) {
    GWEN_Buffer_AppendString(tbuf, "    GWEN_TREE_FINI(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct)\n");
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2) {
    GWEN_Buffer_AppendString(tbuf, "    GWEN_TREE2_FINI(");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ", p_struct, ");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, ")\n");
  }

  GWEN_Buffer_AppendString(tbuf, "  /* members */\n");
  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN) {
        /* destruct, but only if the member is owned */
        if (1) {
          GWEN_BUFFER *dstbuf;
          int rv;

          dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(dstbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(dstbuf, s);

          GWEN_Buffer_AppendString(tbuf, "    ");
          rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                  GWEN_Buffer_GetStart(dstbuf),
                                                  NULL, /* no dest */
                                                  tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(dstbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_AppendString(tbuf, "\n");
        }
      }

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_REFCOUNT) {
    GWEN_Buffer_AppendString(tbuf, "    p_struct->_refCount=0;\n");
  }

  GWEN_Buffer_AppendString(tbuf, "    GWEN_FREE_OBJECT(p_struct);\n");
  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_REFCOUNT) {
    GWEN_Buffer_AppendString(tbuf, "  }\n");
    GWEN_Buffer_AppendString(tbuf, "  else\n");
    GWEN_Buffer_AppendString(tbuf, "    p_struct->_refCount--;\n");
  }
  GWEN_Buffer_AppendString(tbuf, "  }\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildGetter(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  uint32_t flags;
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
  flags=Typemaker2_Type_GetFlags(ty);

  /* probably add getter for signalObject */
  if ((flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) || (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS)) {
    /* prototype */
    s=Typemaker2_TypeManager_GetApiDeclaration(tym);
    if (s && *s) {
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " ");
    }

    GWEN_Buffer_AppendString(tbuf, "GWEN_SIGNALOBJECT *");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, "_GetSignalObject(const ");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");


    Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

    /* implementation */
    GWEN_Buffer_AppendString(tbuf, "GWEN_SIGNALOBJECT *");
    s=Typemaker2_Type_GetPrefix(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, "_GetSignalObject(const ");
    s=Typemaker2_Type_GetIdentifier(ty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *p_struct) {\n");

    GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
    GWEN_Buffer_AppendString(tbuf, "  return p_struct->_signalObject;\n");

    GWEN_Buffer_AppendString(tbuf, "}\n");

    Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

  }

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      if (!(Typemaker2_Member_GetGetFlags(tm) & TYPEMAKER2_FLAGS_OMIT)) {
        TYPEMAKER2_TYPE *mty;

        mty=Typemaker2_Member_GetTypePtr(tm);
        assert(mty);

        /* prototype */
        GWEN_Buffer_AppendString(tbuf,
                                 "/** Getter.\n"
                                 " * Use this function to get the member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" (see @ref ");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ")\n*/\n");

        s=Typemaker2_TypeManager_GetApiDeclaration(tym);
        if (s && Typemaker2_Member_GetAccess(tm)<=TypeMaker2_Access_Protected) {
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " ");
        }
        if ((Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
             Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) &&
            (Typemaker2_Member_GetGetFlags(tm) & TYPEMAKER2_FLAGS_CONST))
          GWEN_Buffer_AppendString(tbuf, "const ");
        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
          TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
          const char *s;

          assert(te);
          s=Typemaker2_Enum_GetType(te);
          if (s && *s) {
            GWEN_Buffer_AppendString(tbuf, s);
          }
          else {
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
          }
        }
        else {
          s=Typemaker2_Type_GetIdentifier(mty);
          GWEN_Buffer_AppendString(tbuf, s);
        }
        GWEN_Buffer_AppendString(tbuf, " ");
        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
            Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array)
          GWEN_Buffer_AppendString(tbuf, "*");

        s=Typemaker2_Type_GetPrefix(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_Get");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendByte(tbuf, toupper(*s));
        GWEN_Buffer_AppendString(tbuf, s+1);

        GWEN_Buffer_AppendString(tbuf, "(");
        if (!(Typemaker2_Member_GetGetFlags(tm) & TYPEMAKER2_FLAGS_NOCONSTOBJECT))
          GWEN_Buffer_AppendString(tbuf, "const ");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");

        switch (Typemaker2_Member_GetAccess(tm)) {
        case TypeMaker2_Access_Public:
          Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Library:
          Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Protected:
          Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Private:
          Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        default:
          DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
          GWEN_Buffer_free(tbuf);
          return GWEN_ERROR_BAD_DATA;
        }
        GWEN_Buffer_Reset(tbuf);

        /* implementation */
        if ((Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
             Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) &&
            (Typemaker2_Member_GetGetFlags(tm) & TYPEMAKER2_FLAGS_CONST))
          GWEN_Buffer_AppendString(tbuf, "const ");
        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
          TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
          const char *s;

          assert(te);
          s=Typemaker2_Enum_GetType(te);
          if (s && *s) {
            GWEN_Buffer_AppendString(tbuf, s);
          }
          else {
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
          }
        }
        else {
          s=Typemaker2_Type_GetIdentifier(mty);
          GWEN_Buffer_AppendString(tbuf, s);
        }
        GWEN_Buffer_AppendString(tbuf, " ");
        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
            Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array)
          GWEN_Buffer_AppendString(tbuf, "*");

        s=Typemaker2_Type_GetPrefix(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_Get");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendByte(tbuf, toupper(*s));
        GWEN_Buffer_AppendString(tbuf, s+1);

        GWEN_Buffer_AppendString(tbuf, "(");
        if (!(Typemaker2_Member_GetGetFlags(tm) & TYPEMAKER2_FLAGS_NOCONSTOBJECT))
          GWEN_Buffer_AppendString(tbuf, "const ");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " *p_struct) {\n");

        GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
        GWEN_Buffer_AppendString(tbuf, "  return p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ";\n");

        GWEN_Buffer_AppendString(tbuf, "}\n");

        Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
        GWEN_Buffer_Reset(tbuf);
      }

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  return 0;
}



static int _buildSetter(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      if (!(Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_OMIT)) {
        TYPEMAKER2_TYPE *mty;
        int typeIsWritten=0;

        mty=Typemaker2_Member_GetTypePtr(tm);
        assert(mty);

        /* prototype */
        GWEN_Buffer_AppendString(tbuf,
                                 "/** Setter.\n"
                                 " * Use this function to set the member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" (see @ref ");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ")\n*/\n");

        s=Typemaker2_TypeManager_GetApiDeclaration(tym);
        if (s && Typemaker2_Member_GetAccess(tm)<=TypeMaker2_Access_Protected) {
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " ");
        }
        GWEN_Buffer_AppendString(tbuf, "void ");
        s=Typemaker2_Type_GetPrefix(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_Set");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendByte(tbuf, toupper(*s));
        GWEN_Buffer_AppendString(tbuf, s+1);

        GWEN_Buffer_AppendString(tbuf, "(");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

        typeIsWritten=0;
        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
          TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
          const char *s;

          assert(te);
          s=Typemaker2_Enum_GetType(te);
          if (s && *s) {
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " ");
            GWEN_Buffer_AppendString(tbuf, " p_src");
            typeIsWritten=1;
          }
        }

        if (!typeIsWritten) {
          if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
              Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
            if (Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_CONST ||
                Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_DUP)
              GWEN_Buffer_AppendString(tbuf, "const ");
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " *p_src");
          }
          else {
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " p_src");
          }
        }
        GWEN_Buffer_AppendString(tbuf, ");\n");

        switch (Typemaker2_Member_GetAccess(tm)) {
        case TypeMaker2_Access_Public:
          Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Library:
          Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Protected:
          Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Private:
          Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        default:
          DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
          GWEN_Buffer_free(tbuf);
          return GWEN_ERROR_BAD_DATA;
        }
        GWEN_Buffer_Reset(tbuf);

        /* add special functions for flags */
        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_WITH_FLAGS) {
          GWEN_Buffer_AppendString(tbuf,
                                   "/** Add flags.\n"
                                   " * Use this function to add flags to the member \"");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "\"\n*/\n");
          s=Typemaker2_TypeManager_GetApiDeclaration(tym);
          if (s && Typemaker2_Member_GetAccess(tm)<=TypeMaker2_Access_Protected) {
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " ");
          }
          GWEN_Buffer_AppendString(tbuf, "void ");
          s=Typemaker2_Type_GetPrefix(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "_Add");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);

          GWEN_Buffer_AppendString(tbuf, "(");
          s=Typemaker2_Type_GetIdentifier(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

          typeIsWritten=0;
          if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
            TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
            const char *s;

            assert(te);
            s=Typemaker2_Enum_GetType(te);
            if (s && *s) {
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " ");
              GWEN_Buffer_AppendString(tbuf, " p_src");
              typeIsWritten=1;
            }
          }

          if (!typeIsWritten) {
            if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
                Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
              if (Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_CONST ||
                  Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_DUP)
                GWEN_Buffer_AppendString(tbuf, "const ");
              s=Typemaker2_Type_GetIdentifier(mty);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " *p_src");
            }
            else {
              s=Typemaker2_Type_GetIdentifier(mty);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " p_src");
            }
          }
          GWEN_Buffer_AppendString(tbuf, ");\n");

          switch (Typemaker2_Member_GetAccess(tm)) {
          case TypeMaker2_Access_Public:
            Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          case TypeMaker2_Access_Library:
            Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          case TypeMaker2_Access_Protected:
            Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          case TypeMaker2_Access_Private:
            Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          default:
            DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
            GWEN_Buffer_free(tbuf);
            return GWEN_ERROR_BAD_DATA;
          }
          GWEN_Buffer_Reset(tbuf);

          GWEN_Buffer_AppendString(tbuf,
                                   "/** Sub flags.\n"
                                   " * Use this function to sub flags from the member \"");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "\"\n*/\n");
          s=Typemaker2_TypeManager_GetApiDeclaration(tym);
          if (s && Typemaker2_Member_GetAccess(tm)<=TypeMaker2_Access_Protected) {
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " ");
          }
          GWEN_Buffer_AppendString(tbuf, "void ");
          s=Typemaker2_Type_GetPrefix(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "_Sub");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);

          GWEN_Buffer_AppendString(tbuf, "(");
          s=Typemaker2_Type_GetIdentifier(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

          typeIsWritten=0;
          if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
            TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
            const char *s;

            assert(te);
            s=Typemaker2_Enum_GetType(te);
            if (s && *s) {
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " ");
              GWEN_Buffer_AppendString(tbuf, " p_src");
              typeIsWritten=1;
            }
          }

          if (!typeIsWritten) {
            if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
                Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
              if (Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_CONST ||
                  Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_DUP)
                GWEN_Buffer_AppendString(tbuf, "const ");
              s=Typemaker2_Type_GetIdentifier(mty);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " *p_src");
            }
            else {
              s=Typemaker2_Type_GetIdentifier(mty);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " p_src");
            }
          }
          GWEN_Buffer_AppendString(tbuf, ");\n");

          switch (Typemaker2_Member_GetAccess(tm)) {
          case TypeMaker2_Access_Public:
            Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          case TypeMaker2_Access_Library:
            Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          case TypeMaker2_Access_Protected:
            Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          case TypeMaker2_Access_Private:
            Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          default:
            DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
            GWEN_Buffer_free(tbuf);
            return GWEN_ERROR_BAD_DATA;
          }
          GWEN_Buffer_Reset(tbuf);
        }


        /* implementation */
        GWEN_Buffer_AppendString(tbuf, "void ");
        s=Typemaker2_Type_GetPrefix(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_Set");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendByte(tbuf, toupper(*s));
        GWEN_Buffer_AppendString(tbuf, s+1);

        GWEN_Buffer_AppendString(tbuf, "(");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

        typeIsWritten=0;
        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
          TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
          const char *s;

          assert(te);
          s=Typemaker2_Enum_GetType(te);
          if (s && *s) {
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " ");
            GWEN_Buffer_AppendString(tbuf, " p_src");
            typeIsWritten=1;
          }
        }

        if (!typeIsWritten) {
          if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
              Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
            if (Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_CONST ||
                Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_DUP)
              GWEN_Buffer_AppendString(tbuf, "const ");
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " *p_src");
          }
          else {
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " p_src");
          }
        }
        GWEN_Buffer_AppendString(tbuf, ") {\n");

        GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN) {

          if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
            GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, ") {\n");
          }

          /* free */
          if (1) {
            GWEN_BUFFER *srcbuf;
            int rv;

            srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(srcbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(srcbuf, s);

            GWEN_Buffer_AppendString(tbuf, "    ");
            rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                    GWEN_Buffer_GetStart(srcbuf),
                                                    NULL, /* no dest */
                                                    tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(srcbuf);
          }

          if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
            GWEN_Buffer_AppendString(tbuf, "  }\n");
          }
        } /* if own */

        if (Typemaker2_Member_GetSetFlags(tm) & TYPEMAKER2_FLAGS_DUP) {
          if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer)
            GWEN_Buffer_AppendString(tbuf, "  if (p_src) {\n");

          /* dup */
          if (1) {
            GWEN_BUFFER *dstbuf;
            int rv;

            dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(dstbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(dstbuf, s);

            GWEN_Buffer_AppendString(tbuf, "    ");
            rv=Typemaker2_Builder_Invoke_DupFn(tb, ty, tm,
                                               "p_src",
                                               GWEN_Buffer_GetStart(dstbuf),
                                               tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(dstbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(dstbuf);
          }

          if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
            GWEN_Buffer_AppendString(tbuf, "  }\n");
            GWEN_Buffer_AppendString(tbuf, "  else {\n");

            /* construct */
            if (1) {
              GWEN_BUFFER *dstbuf;
              int rv;

              dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(dstbuf, "p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(dstbuf, s);

              GWEN_Buffer_AppendString(tbuf, "    ");
              rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                                       NULL,
                                                       GWEN_Buffer_GetStart(dstbuf),
                                                       tbuf);
              if (rv<0) {
                DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                GWEN_Buffer_free(dstbuf);
                GWEN_Buffer_free(tbuf);
                return rv;
              }
              GWEN_Buffer_AppendString(tbuf, "\n");
              GWEN_Buffer_free(dstbuf);
            }
            else {
              GWEN_Buffer_AppendString(tbuf, "    p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " = ");
              s=Typemaker2_Member_GetPresetValue(tm);
              if (s && *s)
                GWEN_Buffer_AppendString(tbuf, s);
              else
                GWEN_Buffer_AppendString(tbuf, "NULL");
              GWEN_Buffer_AppendString(tbuf, ";\n");
            }

            GWEN_Buffer_AppendString(tbuf, "  }\n");
          }
        }
        else {
          if (1) {
            GWEN_BUFFER *dstbuf;
            int rv;

            dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(dstbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(dstbuf, s);

            GWEN_Buffer_AppendString(tbuf, "  ");
            rv=Typemaker2_Builder_Invoke_AssignFn(tb, ty, tm,
                                                  "p_src",
                                                  GWEN_Buffer_GetStart(dstbuf),
                                                  tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(dstbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(dstbuf);
          }
        }

        GWEN_Buffer_AppendString(tbuf, "}\n");

        Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
        GWEN_Buffer_Reset(tbuf);

        if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_WITH_FLAGS) {
          /* add flags */
          GWEN_Buffer_AppendString(tbuf, "void ");
          s=Typemaker2_Type_GetPrefix(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "_Add");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);

          GWEN_Buffer_AppendString(tbuf, "(");
          s=Typemaker2_Type_GetIdentifier(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

          typeIsWritten=0;
          if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
            TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
            const char *s;

            assert(te);
            s=Typemaker2_Enum_GetType(te);
            if (s && *s) {
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " ");
              GWEN_Buffer_AppendString(tbuf, " p_src");
              typeIsWritten=1;
            }
          }

          if (!typeIsWritten) {
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " p_src");
          }
          GWEN_Buffer_AppendString(tbuf, ") {\n");

          GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
          GWEN_Buffer_AppendString(tbuf, "  p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "|=p_src;\n");
          GWEN_Buffer_AppendString(tbuf, "}\n");

          Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
          GWEN_Buffer_Reset(tbuf);

          /* sub flags */
          GWEN_Buffer_AppendString(tbuf, "void ");
          s=Typemaker2_Type_GetPrefix(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "_Sub");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);

          GWEN_Buffer_AppendString(tbuf, "(");
          s=Typemaker2_Type_GetIdentifier(ty);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

          typeIsWritten=0;
          if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_ENUM) {
            TYPEMAKER2_ENUM *te=Typemaker2_Member_GetEnumPtr(tm);
            const char *s;

            assert(te);
            s=Typemaker2_Enum_GetType(te);
            if (s && *s) {
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, " ");
              GWEN_Buffer_AppendString(tbuf, " p_src");
              typeIsWritten=1;
            }
          }

          if (!typeIsWritten) {
            s=Typemaker2_Type_GetIdentifier(mty);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, " p_src");
          }
          GWEN_Buffer_AppendString(tbuf, ") {\n");

          GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
          GWEN_Buffer_AppendString(tbuf, "  p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "&=~p_src;\n");
          GWEN_Buffer_AppendString(tbuf, "}\n");

          Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
          GWEN_Buffer_Reset(tbuf);
        }
      }

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  return 0;
}



static int _buildReadDb(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadDb(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_DB_NODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadDb(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_DB_NODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      GWEN_Buffer_AppendString(tbuf, "  /* member \"");
      s=Typemaker2_Member_GetName(tm);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\" */\n");

      /* release previous value */
      if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer &&
          (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN)) {
        GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ") {\n");

        /* free */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "    ");
          rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                  GWEN_Buffer_GetStart(srcbuf),
                                                  NULL, /* no dest */
                                                  tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }
        GWEN_Buffer_AppendString(tbuf, "  }\n");
      }

      /* read form object */
      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE) {
        GWEN_BUFFER *dstbuf;
        int rv;

        /* volatile */
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" is volatile, just presetting */\n");

        dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
        GWEN_Buffer_AppendString(dstbuf, "p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(dstbuf, s);

        GWEN_Buffer_AppendString(tbuf, "  ");
        rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                                 NULL, /* no source */
                                                 GWEN_Buffer_GetStart(dstbuf),
                                                 tbuf);
        if (rv<0) {
          DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_free(tbuf);
          return rv;
        }
        GWEN_Buffer_AppendString(tbuf, "\n");
        GWEN_Buffer_free(dstbuf);
      }
      else {
        /* not volatile */
        if (1) { /* from object */
          GWEN_BUFFER *dstbuf;
          int rv;

          dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(dstbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(dstbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_FromDbFn(tb, ty, tm,
                                                NULL, /* no source */
                                                GWEN_Buffer_GetStart(dstbuf),
                                                tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(dstbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_AppendString(tbuf, "\n");
        }

        /* add preset code for the case when a pointer is NULL */
        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
          GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "==NULL) {");

          if (1) {
            GWEN_BUFFER *dstbuf;
            int rv;

            dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(dstbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(dstbuf, s);

            GWEN_Buffer_AppendString(tbuf, "  ");
            rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                                     NULL, /* no source */
                                                     GWEN_Buffer_GetStart(dstbuf),
                                                     tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(dstbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(dstbuf);
          }

          GWEN_Buffer_AppendString(tbuf, "  }\n");
        }
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildWriteDb(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteDb(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_DB_NODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteDb(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_DB_NODE *p_db) {\n");

  if (Typemaker2_Type_GetNonVolatileMemberCount(ty)) {
    GWEN_Buffer_AppendString(tbuf, "  int p_rv;\n");
    GWEN_Buffer_AppendString(tbuf, "\n");
  }
  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE)) {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        /* toDb */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_ToDbFn(tb, ty, tm,
                                              GWEN_Buffer_GetStart(srcbuf),
                                              NULL, /* no dest */
                                              tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }

        GWEN_Buffer_AppendString(tbuf, "  if (p_rv<0) {\n");
        GWEN_Buffer_AppendString(tbuf, "    DBG_INFO(GWEN_LOGDOMAIN, \"here (%d)\\n\", p_rv);\n");
        GWEN_Buffer_AppendString(tbuf, "    return p_rv;\n");
        GWEN_Buffer_AppendString(tbuf, "  }\n");

      }
      else {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" is volatile, not writing to db */\n");
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildToDb(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toDb(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_DB_NODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toDb(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_DB_NODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  return ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteDb(p_struct, p_db);\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildFromDb(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_fromDb(GWEN_DB_NODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_fromDb(GWEN_DB_NODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "  p_struct=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  if (Typemaker2_Type_GetUsePrivateConstructor(ty)) {
    GWEN_Buffer_AppendByte(tbuf, '_');
  }
  GWEN_Buffer_AppendString(tbuf, "_new();\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadDb(p_struct, p_db);\n");

  GWEN_Buffer_AppendString(tbuf, "  return p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildReadXml(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadXml(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_XMLNODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadXml(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_XMLNODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      GWEN_Buffer_AppendString(tbuf, "  /* member \"");
      s=Typemaker2_Member_GetName(tm);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\" */\n");

      /* release previous value */
      if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer &&
          (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN)) {
        GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ") {\n");

        /* free */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "    ");
          rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                  GWEN_Buffer_GetStart(srcbuf),
                                                  NULL, /* no dest */
                                                  tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }
        GWEN_Buffer_AppendString(tbuf, "  }\n");
      }

      /* read form object */
      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE) {
        GWEN_BUFFER *dstbuf;
        int rv;

        /* volatile */
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" is volatile, just presetting */\n");

        dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
        GWEN_Buffer_AppendString(dstbuf, "p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(dstbuf, s);

        GWEN_Buffer_AppendString(tbuf, "  ");
        rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                                 NULL, /* no source */
                                                 GWEN_Buffer_GetStart(dstbuf),
                                                 tbuf);
        if (rv<0) {
          DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_free(tbuf);
          return rv;
        }
        GWEN_Buffer_AppendString(tbuf, "\n");
        GWEN_Buffer_free(dstbuf);
      }
      else {
        /* not volatile */
        if (1) { /* from object */
          GWEN_BUFFER *dstbuf;
          int rv;

          dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(dstbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(dstbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_FromXmlFn(tb, ty, tm,
                                                 NULL, /* no source */
                                                 GWEN_Buffer_GetStart(dstbuf),
                                                 tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(dstbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_AppendString(tbuf, "\n");
        }

        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
          GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "==NULL) {");

          if (1) {
            GWEN_BUFFER *dstbuf;
            int rv;

            /* preset */
            GWEN_Buffer_AppendString(tbuf, "  /* preset member \"");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, "\" if empty */\n");

            dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(dstbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(dstbuf, s);

            GWEN_Buffer_AppendString(tbuf, "  ");
            rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                                     NULL, /* no source */
                                                     GWEN_Buffer_GetStart(dstbuf),
                                                     tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(dstbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(dstbuf);
          }

          GWEN_Buffer_AppendString(tbuf, "  }\n");
        }
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildWriteXml(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteXml(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_XMLNODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteXml(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_XMLNODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE)) {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        /* toXml */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_ToXmlFn(tb, ty, tm,
                                               GWEN_Buffer_GetStart(srcbuf),
                                               NULL, /* no dest */
                                               tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }

      }
      else {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" is volatile, not writing to xml */\n");
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildToXml(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toXml(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_XMLNODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toXml(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_XMLNODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteXml(p_struct, p_db);\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildFromXml(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_fromXml(GWEN_XMLNODE *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_fromXml(GWEN_XMLNODE *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "  p_struct=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  if (Typemaker2_Type_GetUsePrivateConstructor(ty)) {
    GWEN_Buffer_AppendByte(tbuf, '_');
  }
  GWEN_Buffer_AppendString(tbuf, "_new();\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadXml(p_struct, p_db);\n");

  GWEN_Buffer_AppendString(tbuf, "  return p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildReadObject(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadObject(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, const AQDB_OBJECT *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadObject(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, const AQDB_OBJECT *p_db) {\n");

  if (Typemaker2_Type_GetNonVolatileMemberCount(ty)) {
    GWEN_Buffer_AppendString(tbuf, "  int p_rv;\n");
    GWEN_Buffer_AppendString(tbuf, "\n");
  }
  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      GWEN_Buffer_AppendString(tbuf, "  /* member \"");
      s=Typemaker2_Member_GetName(tm);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\" */\n");

      /* release previous value */
      if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer &&
          (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN)) {
        GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ") {\n");

        /* free */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "    ");
          rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                  GWEN_Buffer_GetStart(srcbuf),
                                                  NULL, /* no dest */
                                                  tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }
        GWEN_Buffer_AppendString(tbuf, "  }\n");
      }

      /* read form object */
      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE) {
        GWEN_BUFFER *dstbuf;
        int rv;

        /* volatile */
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" is volatile, just presetting */\n");

        dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
        GWEN_Buffer_AppendString(dstbuf, "p_struct->");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(dstbuf, s);

        GWEN_Buffer_AppendString(tbuf, "  ");
        rv=Typemaker2_Builder_Invoke_ConstructFn(tb, ty, tm,
                                                 NULL, /* no source */
                                                 GWEN_Buffer_GetStart(dstbuf),
                                                 tbuf);
        if (rv<0) {
          DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_free(tbuf);
          return rv;
        }
        GWEN_Buffer_AppendString(tbuf, "\n");
        GWEN_Buffer_free(dstbuf);
      }
      else {
        /* not volatile */
        if (1) { /* from object */
          GWEN_BUFFER *dstbuf;
          int rv;

          dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(dstbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(dstbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_FromObjectFn(tb, ty, tm,
                                                    NULL, /* no source */
                                                    GWEN_Buffer_GetStart(dstbuf),
                                                    tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(dstbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_free(dstbuf);
          GWEN_Buffer_AppendString(tbuf, "\n");
        }

        GWEN_Buffer_AppendString(tbuf, "  if (p_rv<0) {\n");
        GWEN_Buffer_AppendString(tbuf, "    DBG_INFO(GWEN_LOGDOMAIN, \"here (%d)\\n\", p_rv);\n");
        GWEN_Buffer_AppendString(tbuf, "    return p_rv;\n");
        GWEN_Buffer_AppendString(tbuf, "  }\n");
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildWriteObject(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteObject(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, AQDB_OBJECT *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteObject(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, AQDB_OBJECT *p_db) {\n");

  if (Typemaker2_Type_GetNonVolatileMemberCount(ty)) {
    GWEN_Buffer_AppendString(tbuf, "  int p_rv;\n");
    GWEN_Buffer_AppendString(tbuf, "\n");
  }
  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE)) {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        /* toObject */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_ToObjectFn(tb, ty, tm,
                                                  GWEN_Buffer_GetStart(srcbuf),
                                                  NULL, /* no dest */
                                                  tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }

        GWEN_Buffer_AppendString(tbuf, "  if (p_rv<0) {\n");
        GWEN_Buffer_AppendString(tbuf, "    DBG_INFO(GWEN_LOGDOMAIN, \"here (%d)\\n\", p_rv);\n");
        GWEN_Buffer_AppendString(tbuf, "    return p_rv;\n");
        GWEN_Buffer_AppendString(tbuf, "  }\n");

      }
      else {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" is volatile, not writing to object */\n");
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildToObject(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toObject(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, AQDB_OBJECT *p_db);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toObject(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, AQDB_OBJECT *p_db) {\n");

  GWEN_Buffer_AppendString(tbuf, "  return ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_WriteObject(p_struct, p_db);\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildFromObject(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_fromObject(const AQDB_OBJECT *p_db, ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " **pp_struct);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_fromObject(const AQDB_OBJECT *p_db, ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " **pp_struct) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "  int p_rv;\n");

  GWEN_Buffer_AppendString(tbuf, "  p_struct=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  if (Typemaker2_Type_GetUsePrivateConstructor(ty)) {
    GWEN_Buffer_AppendByte(tbuf, '_');
  }
  GWEN_Buffer_AppendString(tbuf, "_new();\n");

  GWEN_Buffer_AppendString(tbuf, "  p_rv=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_ReadObject(p_struct, p_db);\n");

  GWEN_Buffer_AppendString(tbuf, "  if (p_rv<0) {\n");
  GWEN_Buffer_AppendString(tbuf, "    DBG_INFO(GWEN_LOGDOMAIN, \"here (%d)\", p_rv);\n");
  GWEN_Buffer_AppendString(tbuf, "    ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_free(p_struct);\n");
  GWEN_Buffer_AppendString(tbuf, "    return p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "  }\n");

  GWEN_Buffer_AppendString(tbuf, "  *pp_struct=p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildCreateColumnList(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "AQDB_COLUMN_LIST *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateColumnList();\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "AQDB_COLUMN_LIST *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateColumnList() {\n");

  if (Typemaker2_Type_GetNonVolatileMemberCount(ty)==0) {
    GWEN_Buffer_AppendString(tbuf, "  return NULL;\n");
  }
  else {
    GWEN_Buffer_AppendString(tbuf, "  AQDB_COLUMN_LIST *p_cl;\n");
    GWEN_Buffer_AppendString(tbuf, "  AQDB_COLUMN *p_c;\n");
    GWEN_Buffer_AppendString(tbuf, "\n");

    GWEN_Buffer_AppendString(tbuf, "  p_cl=AQDB_Column_List_new();\n");
    GWEN_Buffer_AppendString(tbuf, "\n");

    tml=Typemaker2_Type_GetMembers(ty);
    if (tml) {
      TYPEMAKER2_MEMBER *tm;

      tm=Typemaker2_Member_List_First(tml);
      while (tm) {
        TYPEMAKER2_TYPE *mty;

        mty=Typemaker2_Member_GetTypePtr(tm);
        assert(mty);

        if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_VOLATILE)) {
          char numbuf[32];
          int l;

          GWEN_Buffer_AppendString(tbuf, "  /* member \"");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "\" */\n");

          GWEN_Buffer_AppendString(tbuf, "  p_c=AQDB_Column_new(");
          s=Typemaker2_Type_GetAqDbType(mty);
          if (s && *s) {
            GWEN_Buffer_AppendString(tbuf, s);
          }
          else {
            DBG_ERROR(GWEN_LOGDOMAIN, "Type has no AQDB type element");
            GWEN_Buffer_free(tbuf);
            return GWEN_ERROR_BAD_DATA;
          }

          GWEN_Buffer_AppendString(tbuf, ", \"");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "\", ");

          l=Typemaker2_Member_GetMaxLen(tm);
          if (l==0) {
            DBG_ERROR(GWEN_LOGDOMAIN, "Member [%s] has no maxlen attribute",
                      Typemaker2_Member_GetName(tm));
            GWEN_Buffer_free(tbuf);
            return GWEN_ERROR_BAD_DATA;
          }
          snprintf(numbuf, sizeof(numbuf)-1, "%d", l);
          numbuf[sizeof(numbuf)-1]=0;
          GWEN_Buffer_AppendString(tbuf, numbuf);
          GWEN_Buffer_AppendString(tbuf, ");\n");
          GWEN_Buffer_AppendString(tbuf, "  AQDB_Column_List_Add(p_c, p_cl);\n");
        }
        else {
          GWEN_Buffer_AppendString(tbuf, "  /* member \"");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, "\" is volatile, not adding to column list */\n");
        }
        GWEN_Buffer_AppendString(tbuf, "\n");

        tm=Typemaker2_Member_List_Next(tm);
      }
    }
    GWEN_Buffer_AppendString(tbuf, "  return p_cl;\n");
  }

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildDup(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_dup(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_dup(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_src) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_src);\n");
  GWEN_Buffer_AppendString(tbuf, "  p_struct=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  if (Typemaker2_Type_GetUsePrivateConstructor(ty)) {
    GWEN_Buffer_AppendByte(tbuf, '_');
  }
  GWEN_Buffer_AppendString(tbuf, "_new();\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_NODUP)) {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
          if (Typemaker2_Member_GetDupFlags(tm) & TYPEMAKER2_FLAGS_ASSIGN) {
            /* assign */
            if (1) {
              GWEN_BUFFER *dstbuf;
              GWEN_BUFFER *srcbuf;
              int rv;

              dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(dstbuf, "p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(dstbuf, s);

              srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(srcbuf, "p_src->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(srcbuf, s);

              GWEN_Buffer_AppendString(tbuf, "    ");
              rv=Typemaker2_Builder_Invoke_AssignFn(tb, ty, tm,
                                                    GWEN_Buffer_GetStart(srcbuf),
                                                    GWEN_Buffer_GetStart(dstbuf),
                                                    tbuf);
              if (rv<0) {
                DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                GWEN_Buffer_free(srcbuf);
                GWEN_Buffer_free(dstbuf);
                GWEN_Buffer_free(tbuf);
                return rv;
              }
              GWEN_Buffer_AppendString(tbuf, "\n");
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(dstbuf);
            }
          }
          else {
            if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN) {
              GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, ") {\n");

              /* free */
              if (1) {
                GWEN_BUFFER *srcbuf;
                int rv;

                srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
                GWEN_Buffer_AppendString(srcbuf, "p_struct->");
                s=Typemaker2_Member_GetName(tm);
                GWEN_Buffer_AppendString(srcbuf, s);

                GWEN_Buffer_AppendString(tbuf, "    ");
                rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                        GWEN_Buffer_GetStart(srcbuf),
                                                        NULL, /* no dest */
                                                        tbuf);
                if (rv<0) {
                  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                  GWEN_Buffer_free(srcbuf);
                  GWEN_Buffer_free(tbuf);
                  return rv;
                }
                GWEN_Buffer_AppendString(tbuf, "\n");
                GWEN_Buffer_free(srcbuf);
              }

              /* preset with NULL */
              GWEN_Buffer_AppendString(tbuf, "    p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, "=NULL;\n");

              GWEN_Buffer_AppendString(tbuf, "  }\n");
            }
            else {
              /* preset with NULL */
              GWEN_Buffer_AppendString(tbuf, "  p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, "=NULL;\n");
            }

            GWEN_Buffer_AppendString(tbuf, "  if (p_src->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, ") {\n");

            /* dup */
            if (1) {
              GWEN_BUFFER *dstbuf;
              GWEN_BUFFER *srcbuf;
              int rv;

              dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(dstbuf, "p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(dstbuf, s);

              srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(srcbuf, "p_src->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(srcbuf, s);

              GWEN_Buffer_AppendString(tbuf, "    ");
              rv=Typemaker2_Builder_Invoke_DupFn(tb, ty, tm,
                                                 GWEN_Buffer_GetStart(srcbuf),
                                                 GWEN_Buffer_GetStart(dstbuf),
                                                 tbuf);
              if (rv<0) {
                DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                GWEN_Buffer_free(srcbuf);
                GWEN_Buffer_free(dstbuf);
                GWEN_Buffer_free(tbuf);
                return rv;
              }
              GWEN_Buffer_AppendString(tbuf, "\n");
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(dstbuf);
            }
            GWEN_Buffer_AppendString(tbuf, "  }\n");
          }

        } /* if pointer */
        else {
          /* dup */
          if (1) {
            GWEN_BUFFER *dstbuf;
            GWEN_BUFFER *srcbuf;
            int rv;

            dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(dstbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(dstbuf, s);

            srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(srcbuf, "p_src->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(srcbuf, s);

            GWEN_Buffer_AppendString(tbuf, "  ");
            rv=Typemaker2_Builder_Invoke_DupFn(tb, ty, tm,
                                               GWEN_Buffer_GetStart(srcbuf),
                                               GWEN_Buffer_GetStart(dstbuf),
                                               tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(dstbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(dstbuf);
          }
        }

      } /* if !nodup */
      else {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" has nodup flag, not copying */\n");
      }

      GWEN_Buffer_AppendString(tbuf, "\n");
      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "  return p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildCopy(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_MEMBER_LIST *tml;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_copy(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, const ");
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_src);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_copy(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, const ");
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_src) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
  GWEN_Buffer_AppendString(tbuf, "  assert(p_src);\n");

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (!(Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_NOCOPY)) {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

#if 0
        /* release previous value */
        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer &&
            (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN)) {
          GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(tbuf, s);
          GWEN_Buffer_AppendString(tbuf, ") {\n");

          /* free */
          if (1) {
            GWEN_BUFFER *srcbuf;
            int rv;

            srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(srcbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(srcbuf, s);

            GWEN_Buffer_AppendString(tbuf, "    ");
            rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                    GWEN_Buffer_GetStart(srcbuf),
                                                    NULL, /* no dest */
                                                    tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(srcbuf);
          }
          GWEN_Buffer_AppendString(tbuf, "  }\n");
        }
#endif


        if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer) {
          if (Typemaker2_Member_GetCopyFlags(tm) & TYPEMAKER2_FLAGS_ASSIGN) {
            /* assign */
            if (1) {
              GWEN_BUFFER *dstbuf;
              GWEN_BUFFER *srcbuf;
              int rv;

              dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(dstbuf, "p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(dstbuf, s);

              srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(srcbuf, "p_src->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(srcbuf, s);

              GWEN_Buffer_AppendString(tbuf, "    ");
              rv=Typemaker2_Builder_Invoke_AssignFn(tb, ty, tm,
                                                    GWEN_Buffer_GetStart(srcbuf),
                                                    GWEN_Buffer_GetStart(dstbuf),
                                                    tbuf);
              if (rv<0) {
                DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                GWEN_Buffer_free(srcbuf);
                GWEN_Buffer_free(dstbuf);
                GWEN_Buffer_free(tbuf);
                return rv;
              }
              GWEN_Buffer_AppendString(tbuf, "\n");
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(dstbuf);
            }
          }
          else {
            if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_OWN) {
              GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, ") {\n");

              /* free */
              if (1) {
                GWEN_BUFFER *srcbuf;
                int rv;

                srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
                GWEN_Buffer_AppendString(srcbuf, "p_struct->");
                s=Typemaker2_Member_GetName(tm);
                GWEN_Buffer_AppendString(srcbuf, s);

                GWEN_Buffer_AppendString(tbuf, "    ");
                rv=Typemaker2_Builder_Invoke_DestructFn(tb, ty, tm,
                                                        GWEN_Buffer_GetStart(srcbuf),
                                                        NULL, /* no dest */
                                                        tbuf);
                if (rv<0) {
                  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                  GWEN_Buffer_free(srcbuf);
                  GWEN_Buffer_free(tbuf);
                  return rv;
                }
                GWEN_Buffer_AppendString(tbuf, "\n");
                GWEN_Buffer_free(srcbuf);
              }

              /* preset with NULL */
              GWEN_Buffer_AppendString(tbuf, "    p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, "=NULL;\n");

              GWEN_Buffer_AppendString(tbuf, "  }\n");
            }
            else {
              /* preset with NULL */
              GWEN_Buffer_AppendString(tbuf, "  p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(tbuf, s);
              GWEN_Buffer_AppendString(tbuf, "=NULL;\n");
            }

            GWEN_Buffer_AppendString(tbuf, "  if (p_src->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(tbuf, s);
            GWEN_Buffer_AppendString(tbuf, ") {\n");

            /* dup */
            if (1) {
              GWEN_BUFFER *dstbuf;
              GWEN_BUFFER *srcbuf;
              int rv;

              dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(dstbuf, "p_struct->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(dstbuf, s);

              srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
              GWEN_Buffer_AppendString(srcbuf, "p_src->");
              s=Typemaker2_Member_GetName(tm);
              GWEN_Buffer_AppendString(srcbuf, s);

              GWEN_Buffer_AppendString(tbuf, "    ");
              rv=Typemaker2_Builder_Invoke_DupFn(tb, ty, tm,
                                                 GWEN_Buffer_GetStart(srcbuf),
                                                 GWEN_Buffer_GetStart(dstbuf),
                                                 tbuf);
              if (rv<0) {
                DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                GWEN_Buffer_free(srcbuf);
                GWEN_Buffer_free(dstbuf);
                GWEN_Buffer_free(tbuf);
                return rv;
              }
              GWEN_Buffer_AppendString(tbuf, "\n");
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(dstbuf);
            }
            GWEN_Buffer_AppendString(tbuf, "  }\n");
          }

        } /* if pointer */
        else {
          /* copy */
          if (1) {
            GWEN_BUFFER *dstbuf;
            GWEN_BUFFER *srcbuf;
            int rv;

            dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(dstbuf, "p_struct->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(dstbuf, s);

            srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
            GWEN_Buffer_AppendString(srcbuf, "p_src->");
            s=Typemaker2_Member_GetName(tm);
            GWEN_Buffer_AppendString(srcbuf, s);

            GWEN_Buffer_AppendString(tbuf, "  ");
            rv=Typemaker2_Builder_Invoke_DupFn(tb, ty, tm,
                                               GWEN_Buffer_GetStart(srcbuf),
                                               GWEN_Buffer_GetStart(dstbuf),
                                               tbuf);
            if (rv<0) {
              DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
              GWEN_Buffer_free(srcbuf);
              GWEN_Buffer_free(dstbuf);
              GWEN_Buffer_free(tbuf);
              return rv;
            }
            GWEN_Buffer_AppendString(tbuf, "\n");
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(dstbuf);
          }
        }

      } /* if !nocopy */
      else {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" has NOCOPY flag, not copying */\n");
      }

      GWEN_Buffer_AppendString(tbuf, "\n");
      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  GWEN_Buffer_AppendString(tbuf, "  return p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildList1Dup(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  GWEN_Buffer_AppendString(tbuf, "/* list1 functions */\n");
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_dup(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_src);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "/* list1 functions */\n");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_dup(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_src) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_dest;\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_elem;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_src);\n");
  GWEN_Buffer_AppendString(tbuf, "  p_dest=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_new();\n");

  GWEN_Buffer_AppendString(tbuf, "  p_elem=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_First(p_src);\n");

  GWEN_Buffer_AppendString(tbuf, "  while(p_elem) {\n");
  GWEN_Buffer_AppendString(tbuf, "    ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_cpy;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "    p_cpy=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_dup(p_elem);\n");

  GWEN_Buffer_AppendString(tbuf, "    ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Add(p_cpy, p_dest);\n");

  GWEN_Buffer_AppendString(tbuf, "    p_elem=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Next(p_elem);\n");
  GWEN_Buffer_AppendString(tbuf, "  }\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  return p_dest;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildCreateTable(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateTable(AQDB_DB *p_db, const char *p_name, uint32_t p_flags);");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateTable(AQDB_DB *p_db, const char *p_name, uint32_t p_flags) {\n");

  GWEN_Buffer_AppendString(tbuf, "  AQDB_COLUMN_LIST *p_cl;\n");
  GWEN_Buffer_AppendString(tbuf, "  int p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  p_cl=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateColumnList();\n");

  GWEN_Buffer_AppendString(tbuf, "  p_rv=AQDB_DB_CreateTable(p_db, p_name, p_flags, p_cl);\n");
  GWEN_Buffer_AppendString(tbuf, "  AQDB_Column_List_free(p_cl);\n");
  GWEN_Buffer_AppendString(tbuf, "  if (p_rv<0) {\n");
  GWEN_Buffer_AppendString(tbuf, "    DBG_INFO(GWEN_LOGDOMAIN, \"here (%d)\", p_rv);\n");
  GWEN_Buffer_AppendString(tbuf, "    return p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "  }\n");

  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildCreateObject(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateObject(AQDB_DB *p_db, AQDB_ID p_tableId, AQDB_ID p_id, AQDB_OBJECT **pp_o);\n");
  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "int ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CreateObject(AQDB_DB *p_db, AQDB_ID p_tableId, AQDB_ID p_id, AQDB_OBJECT **pp_o) {\n");

  GWEN_Buffer_AppendString(tbuf, "  AQDB_OBJECT *p_o;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  p_o=AQDB_Object_new(p_tableId, p_id, ");
  s=Typemaker2_Type_GetFieldCountId(ty);
  if (s && *s) {
  }
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, ");\n");
  GWEN_Buffer_AppendString(tbuf, "  *pp_o=p_o;\n");
  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildDefineEnums(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_ENUM_LIST *enums;
  /* TYPEMAKER2_TYPEMANAGER *tym; */
  /* uint32_t flags; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  enums=Typemaker2_Type_GetEnums(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(enums);
  if (Typemaker2_Enum_List_GetCount(enums)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_ENUM *te;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    te=Typemaker2_Enum_List_First(enums);
    while (te) {
      const char *prefix;
      const char *etype;
      TYPEMAKER2_ITEM *ti;
      int access=TypeMaker2_Access_Public;

      prefix=Typemaker2_Enum_GetPrefix(te);
      if (prefix==NULL || *prefix==0) {
        DBG_ERROR(GWEN_LOGDOMAIN, "No prefix in enum definition");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }

      etype=Typemaker2_Enum_GetType(te);
      if (etype && *etype)
        GWEN_Buffer_AppendString(tbuf, "typedef enum {\n");
      else
        GWEN_Buffer_AppendString(tbuf, "enum {\n");

      GWEN_Buffer_AppendString(tbuf, "  ");
      if (prefix)
        GWEN_Buffer_AppendString(tbuf, prefix);
      GWEN_Buffer_AppendString(tbuf, "Unknown = -1");
      ti=Typemaker2_Item_List_First(Typemaker2_Enum_GetItems(te));
      if (ti)
        GWEN_Buffer_AppendString(tbuf, ",");
      GWEN_Buffer_AppendString(tbuf, "\n");
      while (ti) {
        GWEN_Buffer_AppendString(tbuf, "  ");
        if (prefix)
          GWEN_Buffer_AppendString(tbuf, prefix);
        s=Typemaker2_Item_GetName(ti);
        if (s && *s) {
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);
        }
        s=Typemaker2_Item_GetValue(ti);
        if (s) {
          GWEN_Buffer_AppendString(tbuf, " = ");
          GWEN_Buffer_AppendString(tbuf, s);
        }

        ti=Typemaker2_Item_List_Next(ti);
        if (ti)
          GWEN_Buffer_AppendString(tbuf, ",");
        GWEN_Buffer_AppendString(tbuf, "\n");
      }
      GWEN_Buffer_AppendString(tbuf, "}");

      if (etype && *etype) {
        GWEN_Buffer_AppendString(tbuf, " ");
        GWEN_Buffer_AppendString(tbuf, etype);
      }

      GWEN_Buffer_AppendString(tbuf, ";\n");
      GWEN_Buffer_AppendString(tbuf, "\n");

      switch (access) {
      case TypeMaker2_Access_Public:
        Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Library:
        Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Protected:
        Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Private:
        Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      default:
        DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_Reset(tbuf);

      te=Typemaker2_Enum_List_Next(te);
    }
  }

  return 0;
}



int _buildDefineVirtualFns(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty, const char *loc)
{
  TYPEMAKER2_VIRTUALFN_LIST *fns;
  /* TYPEMAKER2_TYPEMANAGER *tym; */
  /*uint32_t flags; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  fns=Typemaker2_Type_GetVirtualFns(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(fns);
  if (Typemaker2_VirtualFn_List_GetCount(fns)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_VIRTUALFN *vf;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    if (loc && *loc) {
      GWEN_Buffer_AppendString(tbuf, "/* definitions for virtual functions (");
      GWEN_Buffer_AppendString(tbuf, loc);
      GWEN_Buffer_AppendString(tbuf, ") */\n");
    }
    else
      GWEN_Buffer_AppendString(tbuf, "/* definitions for virtual functions */\n");

    vf=Typemaker2_VirtualFn_List_First(fns);
    while (vf) {
      s=Typemaker2_VirtualFn_GetLocation(vf);
      if (!(s && *s))
        s="pre";
      if (s && loc && strcasecmp(s, loc)==0) {
        int access=Typemaker2_VirtualFn_GetAccess(vf);
        TYPEMAKER2_VIRTUALFN_PARAM_LIST *plist;
        int i;

        GWEN_Buffer_AppendString(tbuf, "typedef ");
        s=Typemaker2_VirtualFn_GetReturnType(vf);
        if (!(s && *s)) {
          GWEN_Buffer_free(tbuf);
          return GWEN_ERROR_BAD_DATA;
        }
        GWEN_Buffer_AppendString(tbuf, s);

        GWEN_Buffer_AppendString(tbuf, "  (*");
        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "_");

        s=Typemaker2_VirtualFn_GetName(vf);
        if (!(s && *s)) {
          GWEN_Buffer_free(tbuf);
          return GWEN_ERROR_BAD_DATA;
        }
        while (*s) {
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          s++;
        }
        GWEN_Buffer_AppendString(tbuf, "_FN)(");

        if (Typemaker2_VirtualFn_GetFlags(vf) & TYPEMAKER2_FLAGS_CONST)
          GWEN_Buffer_AppendString(tbuf, "const ");

        s=Typemaker2_Type_GetIdentifier(ty);
        GWEN_Buffer_AppendString(tbuf, s);
        /* created structs are always pointers */
        GWEN_Buffer_AppendString(tbuf, " *p_struct");

        plist=Typemaker2_VirtualFn_GetParamTypeList(vf);
        if (plist) {
          TYPEMAKER2_VIRTUALFN_PARAM *prm;

          i=1;
          prm=Typemaker2_VirtualFn_Param_List_First(plist);
          while (prm) {
            const char *paramName;
            const char *paramType;

            GWEN_Buffer_AppendString(tbuf, ", ");

            paramName=Typemaker2_VirtualFn_Param_GetName(prm);
            paramType=Typemaker2_VirtualFn_Param_GetType(prm);

            GWEN_Buffer_AppendString(tbuf, paramType);
            GWEN_Buffer_AppendString(tbuf, " ");

            if (paramName)
              GWEN_Buffer_AppendString(tbuf, paramName);
            else {
              char numbuf[64];

              snprintf(numbuf, sizeof(numbuf)-1, "param%d", i);
              numbuf[sizeof(numbuf)-1]=0;
              GWEN_Buffer_AppendString(tbuf, numbuf);
            }

            prm=Typemaker2_VirtualFn_Param_List_Next(prm);
            i++;
          }
        }

        GWEN_Buffer_AppendString(tbuf, ");\n");

        switch (access) {
        case TypeMaker2_Access_Public:
          Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Library:
          Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Protected:
          Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        case TypeMaker2_Access_Private:
          Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
          break;
        default:
          DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
          GWEN_Buffer_free(tbuf);
          return GWEN_ERROR_BAD_DATA;
        }
        GWEN_Buffer_Reset(tbuf);
      }

      vf=Typemaker2_VirtualFn_List_Next(vf);
    }
  }

  return 0;
}



int _buildProtoVirtualFns(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_VIRTUALFN_LIST *fns;
  TYPEMAKER2_TYPEMANAGER *tym;
  /* uint32_t flags; */

  tym=Typemaker2_Builder_GetTypeManager(tb);
  fns=Typemaker2_Type_GetVirtualFns(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(fns);
  if (Typemaker2_VirtualFn_List_GetCount(fns)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_VIRTUALFN *vf;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    GWEN_Buffer_AppendString(tbuf, "/* prototypes for virtual functions */\n");
    vf=Typemaker2_VirtualFn_List_First(fns);
    while (vf) {
      int access=Typemaker2_VirtualFn_GetAccess(vf);
      TYPEMAKER2_VIRTUALFN_PARAM_LIST *plist;
      int i;

      /* write APIDOC */
      GWEN_Buffer_AppendString(tbuf, "/**\n");
      s=Typemaker2_VirtualFn_GetDescr(vf);
      if (s && *s) {
        int len;

        GWEN_Buffer_AppendString(tbuf, " * ");
        GWEN_Buffer_AppendString(tbuf, s);
        len=strlen(s);
        if (s[len-1]!='\n')
          GWEN_Buffer_AppendString(tbuf, "\n");
      }

      s=Typemaker2_VirtualFn_GetReturnTypeDescr(vf);
      if (s && *s) {
        int len;

        GWEN_Buffer_AppendString(tbuf, " * @return ");
        GWEN_Buffer_AppendString(tbuf, s);
        len=strlen(s);
        if (s[len-1]!='\n')
          GWEN_Buffer_AppendString(tbuf, "\n");
      }


      i=1;
      plist=Typemaker2_VirtualFn_GetParamTypeList(vf);
      if (plist) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        i=1;
        prm=Typemaker2_VirtualFn_Param_List_First(plist);
        while (prm) {
          const char *paramDescr;

          paramDescr=Typemaker2_VirtualFn_Param_GetDescr(prm);
          if (paramDescr && *paramDescr) {
            const char *paramName;
            int len;

            GWEN_Buffer_AppendString(tbuf, " * @param ");
            paramName=Typemaker2_VirtualFn_Param_GetName(prm);
            if (paramName)
              GWEN_Buffer_AppendString(tbuf, paramName);
            else {
              char numbuf[64];

              snprintf(numbuf, sizeof(numbuf)-1, "param%d", i);
              numbuf[sizeof(numbuf)-1]=0;
              GWEN_Buffer_AppendString(tbuf, numbuf);
            }

            GWEN_Buffer_AppendString(tbuf, " ");
            GWEN_Buffer_AppendString(tbuf, paramDescr);
            len=strlen(paramDescr);
            if (paramDescr[len-1]!='\n')
              GWEN_Buffer_AppendString(tbuf, "\n");
          }

          i++;
          prm=Typemaker2_VirtualFn_Param_List_Next(prm);
        }
      }
      GWEN_Buffer_AppendString(tbuf, " */\n");


      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s && *s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }

      s=Typemaker2_VirtualFn_GetReturnType(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " ");

      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");

      if (Typemaker2_VirtualFn_GetFlags(vf) & TYPEMAKER2_FLAGS_CONST)
        GWEN_Buffer_AppendString(tbuf, "const ");

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      /* created structs are always pointers */
      GWEN_Buffer_AppendString(tbuf, " *p_struct");


      i=1;
      plist=Typemaker2_VirtualFn_GetParamTypeList(vf);
      if (plist) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        i=1;
        prm=Typemaker2_VirtualFn_Param_List_First(plist);
        while (prm) {
          const char *paramName;
          const char *paramType;

          GWEN_Buffer_AppendString(tbuf, ", ");

          paramName=Typemaker2_VirtualFn_Param_GetName(prm);
          paramType=Typemaker2_VirtualFn_Param_GetType(prm);

          GWEN_Buffer_AppendString(tbuf, paramType);
          GWEN_Buffer_AppendString(tbuf, " ");

          if (paramName)
            GWEN_Buffer_AppendString(tbuf, paramName);
          else {
            char numbuf[64];

            snprintf(numbuf, sizeof(numbuf)-1, "param%d", i);
            numbuf[sizeof(numbuf)-1]=0;
            GWEN_Buffer_AppendString(tbuf, numbuf);
          }

          prm=Typemaker2_VirtualFn_Param_List_Next(prm);
          i++;
        }
      }
      GWEN_Buffer_AppendString(tbuf, ");\n");


      switch (access) {
      case TypeMaker2_Access_Public:
        Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Library:
        Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Protected:
        Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Private:
        Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      default:
        DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_Reset(tbuf);

      vf=Typemaker2_VirtualFn_List_Next(vf);
    }
  }

  return 0;
}



int _buildCodeVirtualFns(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_VIRTUALFN_LIST *fns;
  /* TYPEMAKER2_TYPEMANAGER *tym; */
  /* uint32_t flags; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  fns=Typemaker2_Type_GetVirtualFns(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(fns);
  if (Typemaker2_VirtualFn_List_GetCount(fns)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_VIRTUALFN *vf;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    GWEN_Buffer_AppendString(tbuf, "/* code for virtual functions */\n");
    vf=Typemaker2_VirtualFn_List_First(fns);
    while (vf) {
      TYPEMAKER2_VIRTUALFN_PARAM_LIST *plist;
      int i;

      s=Typemaker2_VirtualFn_GetReturnType(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " ");

      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");

      if (Typemaker2_VirtualFn_GetFlags(vf) & TYPEMAKER2_FLAGS_CONST)
        GWEN_Buffer_AppendString(tbuf, "const ");

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      /* created structs are always pointers */
      GWEN_Buffer_AppendString(tbuf, " *p_struct");


      i=1;
      plist=Typemaker2_VirtualFn_GetParamTypeList(vf);
      if (plist) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        i=1;
        prm=Typemaker2_VirtualFn_Param_List_First(plist);
        while (prm) {
          const char *paramName;
          const char *paramType;

          GWEN_Buffer_AppendString(tbuf, ", ");

          paramName=Typemaker2_VirtualFn_Param_GetName(prm);
          paramType=Typemaker2_VirtualFn_Param_GetType(prm);

          GWEN_Buffer_AppendString(tbuf, paramType);
          GWEN_Buffer_AppendString(tbuf, " ");

          if (paramName)
            GWEN_Buffer_AppendString(tbuf, paramName);
          else {
            char numbuf[64];

            snprintf(numbuf, sizeof(numbuf)-1, "param%d", i);
            numbuf[sizeof(numbuf)-1]=0;
            GWEN_Buffer_AppendString(tbuf, numbuf);
          }

          prm=Typemaker2_VirtualFn_Param_List_Next(prm);
          i++;
        }
      }
      GWEN_Buffer_AppendString(tbuf, ") {\n");

      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  if (p_struct->");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        DBG_ERROR(0, "Virtual functions has no name");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "Fn)\n");
      GWEN_Buffer_AppendString(tbuf, "    return p_struct->");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "Fn(p_struct");

      i=1;
      plist=Typemaker2_VirtualFn_GetParamTypeList(vf);
      if (plist) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        i=1;
        prm=Typemaker2_VirtualFn_Param_List_First(plist);
        while (prm) {
          const char *paramName;

          GWEN_Buffer_AppendString(tbuf, ", ");

          paramName=Typemaker2_VirtualFn_Param_GetName(prm);

          if (paramName)
            GWEN_Buffer_AppendString(tbuf, paramName);
          else {
            char numbuf[64];

            snprintf(numbuf, sizeof(numbuf)-1, "param%d", i);
            numbuf[sizeof(numbuf)-1]=0;
            GWEN_Buffer_AppendString(tbuf, numbuf);
          }

          prm=Typemaker2_VirtualFn_Param_List_Next(prm);
          i++;
        }
      }
      GWEN_Buffer_AppendString(tbuf, ");\n");

      GWEN_Buffer_AppendString(tbuf, "  else\n");
      GWEN_Buffer_AppendString(tbuf, "    return ");
      s=Typemaker2_VirtualFn_GetDefaultReturnValue(vf);
      if (!(s && *s)) {
        DBG_ERROR(0, "No default return value");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, ";\n");
      GWEN_Buffer_AppendString(tbuf, "}\n");

      Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
      GWEN_Buffer_Reset(tbuf);

      vf=Typemaker2_VirtualFn_List_Next(vf);
    }
  }

  return 0;
}



int _buildProtoSetterVirtualFns(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_VIRTUALFN_LIST *fns;
  TYPEMAKER2_TYPEMANAGER *tym;
  /* uint32_t flags; */

  tym=Typemaker2_Builder_GetTypeManager(tb);
  fns=Typemaker2_Type_GetVirtualFns(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(fns);
  if (Typemaker2_VirtualFn_List_GetCount(fns)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_VIRTUALFN *vf;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    GWEN_Buffer_AppendString(tbuf, "/* setters for virtual functions */\n");
    vf=Typemaker2_VirtualFn_List_First(fns);
    while (vf) {
      int access=Typemaker2_VirtualFn_GetAccess(vf);

      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s && *s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      while (*s)
        GWEN_Buffer_AppendByte(tbuf, toupper(*(s++)));
      GWEN_Buffer_AppendString(tbuf, "_FN ");

      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_Set");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "Fn(");

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      /* created structs are always pointers */
      GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      while (*s)
        GWEN_Buffer_AppendByte(tbuf, toupper(*(s++)));
      GWEN_Buffer_AppendString(tbuf, "_FN fn);\n");

      switch (access) {
      case TypeMaker2_Access_Public:
        Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Library:
        Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Protected:
        Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Private:
        Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      default:
        DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_Reset(tbuf);

      vf=Typemaker2_VirtualFn_List_Next(vf);
    }
  }

  return 0;
}



int _buildSetterVirtualFns(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_VIRTUALFN_LIST *fns;
  /* TYPEMAKER2_TYPEMANAGER *tym; */
  /* uint32_t flags; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  fns=Typemaker2_Type_GetVirtualFns(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(fns);
  if (Typemaker2_VirtualFn_List_GetCount(fns)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_VIRTUALFN *vf;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    GWEN_Buffer_AppendString(tbuf, "/* setters for virtual functions */\n");
    vf=Typemaker2_VirtualFn_List_First(fns);
    while (vf) {

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");

      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      while (*s)
        GWEN_Buffer_AppendByte(tbuf, toupper(*(s++)));
      GWEN_Buffer_AppendString(tbuf, "_FN ");

      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_Set");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "Fn(");

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      /* created structs are always pointers */
      GWEN_Buffer_AppendString(tbuf, " *p_struct, ");

      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      while (*s)
        GWEN_Buffer_AppendByte(tbuf, toupper(*(s++)));
      GWEN_Buffer_AppendString(tbuf, "_FN fn){\n");

      GWEN_Buffer_AppendString(tbuf, "  ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      while (*s)
        GWEN_Buffer_AppendByte(tbuf, toupper(*(s++)));
      GWEN_Buffer_AppendString(tbuf, "_FN oldFn;\n\n");

      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  oldFn=p_struct->");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "Fn;\n");

      GWEN_Buffer_AppendString(tbuf, "  p_struct->");
      s=Typemaker2_VirtualFn_GetName(vf);
      if (!(s && *s)) {
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "Fn=fn;\n");
      GWEN_Buffer_AppendString(tbuf, "  return oldFn;\n");
      GWEN_Buffer_AppendString(tbuf, "}\n");

      Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
      GWEN_Buffer_Reset(tbuf);

      vf=Typemaker2_VirtualFn_List_Next(vf);
    }
  }

  return 0;
}



static int _setEnumStringFns(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_ENUM_LIST *enums;
  /* TYPEMAKER2_TYPEMANAGER *tym; */
  /* uint32_t flags; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  enums=Typemaker2_Type_GetEnums(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(enums);
  if (Typemaker2_Enum_List_GetCount(enums)) {
    TYPEMAKER2_ENUM *te;

    te=Typemaker2_Enum_List_First(enums);
    while (te) {
      const char *prefix;
      GWEN_BUFFER *tbuf;

      prefix=Typemaker2_Enum_GetPrefix(te);
      if (prefix==NULL || *prefix==0) {
        DBG_ERROR(GWEN_LOGDOMAIN, "No prefix in enum definition");
        return GWEN_ERROR_BAD_DATA;
      }

      tbuf=GWEN_Buffer_new(0, 256, 0, 1);
      if (prefix && *prefix) {
        GWEN_Buffer_AppendString(tbuf, prefix);
        if (prefix[strlen(prefix)-1]!='_')
          GWEN_Buffer_AppendString(tbuf, "_");
      }
      GWEN_Buffer_AppendString(tbuf, "fromString");
      Typemaker2_Enum_SetFromStringFn(te, GWEN_Buffer_GetStart(tbuf));
      GWEN_Buffer_Reset(tbuf);

      if (prefix && *prefix) {
        GWEN_Buffer_AppendString(tbuf, prefix);
        if (prefix[strlen(prefix)-1]!='_')
          GWEN_Buffer_AppendString(tbuf, "_");
      }
      GWEN_Buffer_AppendString(tbuf, "toString");
      Typemaker2_Enum_SetToStringFn(te, GWEN_Buffer_GetStart(tbuf));
      GWEN_Buffer_free(tbuf);

      te=Typemaker2_Enum_List_Next(te);
    }
  }

  return 0;
}



static int _buildEnumFromString(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_ENUM_LIST *enums;
  TYPEMAKER2_TYPEMANAGER *tym;
  /* uint32_t flags; */

  tym=Typemaker2_Builder_GetTypeManager(tb);
  enums=Typemaker2_Type_GetEnums(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(enums);
  if (Typemaker2_Enum_List_GetCount(enums)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_ENUM *te;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    te=Typemaker2_Enum_List_First(enums);
    while (te) {
      const char *prefix;
      const char *etype;
      TYPEMAKER2_ITEM *ti;
      int acc=TypeMaker2_Access_Public;
      int i;

      prefix=Typemaker2_Enum_GetPrefix(te);
      if (prefix==NULL || *prefix==0) {
        DBG_ERROR(GWEN_LOGDOMAIN, "No prefix in enum definition");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }

      etype=Typemaker2_Enum_GetType(te);

      /* prototype */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      if (etype && *etype) {
        GWEN_Buffer_AppendString(tbuf, etype);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      else
        GWEN_Buffer_AppendString(tbuf, "int ");
      if (prefix && *prefix) {
        GWEN_Buffer_AppendString(tbuf, prefix);
        if (prefix[strlen(prefix)-1]!='_')
          GWEN_Buffer_AppendString(tbuf, "_");
      }
      GWEN_Buffer_AppendString(tbuf, "fromString(const char *p_s);\n");
      switch (acc) {
      case TypeMaker2_Access_Public:
        Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Library:
        Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Protected:
        Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Private:
        Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      default:
        DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_Reset(tbuf);

      /* implementation */
      if (etype && *etype) {
        GWEN_Buffer_AppendString(tbuf, etype);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      else
        GWEN_Buffer_AppendString(tbuf, "int ");
      if (prefix && *prefix) {
        GWEN_Buffer_AppendString(tbuf, prefix);
        if (prefix[strlen(prefix)-1]!='_')
          GWEN_Buffer_AppendString(tbuf, "_");
      }
      GWEN_Buffer_AppendString(tbuf, "fromString(const char *p_s) {\n");

      GWEN_Buffer_AppendString(tbuf, "  if (p_s && *p_s) {\n");

      i=0;
      ti=Typemaker2_Item_List_First(Typemaker2_Enum_GetItems(te));
      while (ti) {
        GWEN_Buffer_AppendString(tbuf, "    ");
        if (i++)
          GWEN_Buffer_AppendString(tbuf, "else ");
        GWEN_Buffer_AppendString(tbuf, "if (strcasecmp(p_s, \"");
        s=Typemaker2_Item_GetName(ti);
        if (s && *s) {
          GWEN_Buffer_AppendByte(tbuf, tolower(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);
        }
        GWEN_Buffer_AppendString(tbuf, "\")==0)\n");
        GWEN_Buffer_AppendString(tbuf, "      return ");
        if (prefix)
          GWEN_Buffer_AppendString(tbuf, prefix);
        s=Typemaker2_Item_GetName(ti);
        if (s && *s) {
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);
        }
        GWEN_Buffer_AppendString(tbuf, ";\n");

        ti=Typemaker2_Item_List_Next(ti);
      }
      GWEN_Buffer_AppendString(tbuf, "  }\n");
      GWEN_Buffer_AppendString(tbuf, "  return ");
      if (prefix)
        GWEN_Buffer_AppendString(tbuf, prefix);
      GWEN_Buffer_AppendString(tbuf, "Unknown;\n");
      GWEN_Buffer_AppendString(tbuf, "}\n");

      Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
      GWEN_Buffer_Reset(tbuf);
      te=Typemaker2_Enum_List_Next(te);
    }
    GWEN_Buffer_free(tbuf);
  } /* if enums */

  return 0;
}



static int _buildEnumToString(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_ENUM_LIST *enums;
  TYPEMAKER2_TYPEMANAGER *tym;
  /* uint32_t flags; */

  tym=Typemaker2_Builder_GetTypeManager(tb);
  enums=Typemaker2_Type_GetEnums(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(enums);
  if (Typemaker2_Enum_List_GetCount(enums)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_ENUM *te;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    te=Typemaker2_Enum_List_First(enums);
    while (te) {
      const char *prefix;
      const char *etype;
      TYPEMAKER2_ITEM *ti;
      int acc=TypeMaker2_Access_Public;

      prefix=Typemaker2_Enum_GetPrefix(te);
      if (prefix==NULL || *prefix==0) {
        DBG_ERROR(GWEN_LOGDOMAIN, "No prefix in enum definition");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }

      etype=Typemaker2_Enum_GetType(te);

      /* prototype */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      GWEN_Buffer_AppendString(tbuf, "const char *");
      if (prefix && *prefix) {
        GWEN_Buffer_AppendString(tbuf, prefix);
        if (prefix[strlen(prefix)-1]!='_')
          GWEN_Buffer_AppendString(tbuf, "_");
      }
      GWEN_Buffer_AppendString(tbuf, "toString(");
      if (etype && *etype)
        GWEN_Buffer_AppendString(tbuf, etype);
      else
        GWEN_Buffer_AppendString(tbuf, "int");
      GWEN_Buffer_AppendString(tbuf, " p_i);\n");

      switch (acc) {
      case TypeMaker2_Access_Public:
        Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Library:
        Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Protected:
        Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Private:
        Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      default:
        DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_Reset(tbuf);

      /* implementation */
      GWEN_Buffer_AppendString(tbuf, "const char *");
      if (prefix && *prefix) {
        GWEN_Buffer_AppendString(tbuf, prefix);
        if (prefix[strlen(prefix)-1]!='_')
          GWEN_Buffer_AppendString(tbuf, "_");
      }
      GWEN_Buffer_AppendString(tbuf, "toString(");
      if (etype && *etype)
        GWEN_Buffer_AppendString(tbuf, etype);
      else
        GWEN_Buffer_AppendString(tbuf, "int");
      GWEN_Buffer_AppendString(tbuf, " p_i) {\n");

      GWEN_Buffer_AppendString(tbuf, "  switch(p_i) {\n");
      ti=Typemaker2_Item_List_First(Typemaker2_Enum_GetItems(te));
      while (ti) {
        GWEN_Buffer_AppendString(tbuf, "    case ");
        if (prefix)
          GWEN_Buffer_AppendString(tbuf, prefix);
        s=Typemaker2_Item_GetName(ti);
        if (s && *s) {
          GWEN_Buffer_AppendByte(tbuf, toupper(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);
        }
        GWEN_Buffer_AppendString(tbuf, ": return \"");
        s=Typemaker2_Item_GetName(ti);
        if (s && *s) {
          GWEN_Buffer_AppendByte(tbuf, tolower(*s));
          GWEN_Buffer_AppendString(tbuf, s+1);
        }
        GWEN_Buffer_AppendString(tbuf, "\";\n");

        ti=Typemaker2_Item_List_Next(ti);
      }

      /* handle "unknown" */
      GWEN_Buffer_AppendString(tbuf, "    case ");
      if (prefix)
        GWEN_Buffer_AppendString(tbuf, prefix);
      GWEN_Buffer_AppendString(tbuf, "Unknown:\n");

      /* handle default */
      GWEN_Buffer_AppendString(tbuf, "    default: return \"unknown\";\n");
      GWEN_Buffer_AppendString(tbuf, "  }\n");
      GWEN_Buffer_AppendString(tbuf, "}\n");

      Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
      GWEN_Buffer_Reset(tbuf);
      te=Typemaker2_Enum_List_Next(te);
    }
    GWEN_Buffer_free(tbuf);
  } /* if enums */

  return 0;
}



static int _buildList1GetByMember(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty, TYPEMAKER2_MEMBER *tm)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_TYPE *mty;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  mty=Typemaker2_Member_GetTypePtr(tm);
  assert(mty);

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }

  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Get");
  GWEN_Buffer_AppendString(tbuf, "By");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_list, ");
  if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
      Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
    GWEN_Buffer_AppendString(tbuf, " const ");
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *");
  }
  else {
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "p_cmp);\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Get");
  GWEN_Buffer_AppendString(tbuf, "By");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_list, ");
  if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
      Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
    GWEN_Buffer_AppendString(tbuf, " const ");
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *");
  }
  else {
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "p_cmp) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_list);\n");
  GWEN_Buffer_AppendString(tbuf, "  p_struct = ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_First(p_list);\n");
  GWEN_Buffer_AppendString(tbuf, "  while(p_struct) {\n");
  GWEN_Buffer_AppendString(tbuf, "    int p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "    ");
  if (1) {
    GWEN_BUFFER *dstbuf;
    GWEN_BUFFER *srcbuf;
    int rv;

    srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(srcbuf, "p_cmp");

    dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(dstbuf, "p_struct->");
    s=Typemaker2_Member_GetName(tm);
    GWEN_Buffer_AppendString(dstbuf, s);

    rv=Typemaker2_Builder_Invoke_CompareFn(tb, ty, tm,
                                           GWEN_Buffer_GetStart(srcbuf),
                                           GWEN_Buffer_GetStart(dstbuf),
                                           tbuf);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      GWEN_Buffer_free(srcbuf);
      GWEN_Buffer_free(dstbuf);
      GWEN_Buffer_free(tbuf);
      return rv;
    }
    GWEN_Buffer_AppendString(tbuf, "\n");
    GWEN_Buffer_free(srcbuf);
    GWEN_Buffer_free(dstbuf);
  }


  GWEN_Buffer_AppendString(tbuf, "    if (p_rv == 0)\n");
  GWEN_Buffer_AppendString(tbuf, "      return p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "    p_struct = ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Next(p_struct);\n");

  GWEN_Buffer_AppendString(tbuf, "  }\n");

  GWEN_Buffer_AppendString(tbuf, "  return NULL;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildTreeGetByMember(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty, TYPEMAKER2_MEMBER *tm)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_TYPE *mty;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  mty=Typemaker2_Member_GetTypePtr(tm);
  assert(mty);

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }

  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree_Get");
  GWEN_Buffer_AppendString(tbuf, "By");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_TREE *p_tree, ");
  if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
      Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
    GWEN_Buffer_AppendString(tbuf, " const ");
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *");
  }
  else {
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "p_cmp);\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree_Get");
  GWEN_Buffer_AppendString(tbuf, "By");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_TREE *p_tree, ");
  if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
      Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
    GWEN_Buffer_AppendString(tbuf, " const ");
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *");
  }
  else {
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "p_cmp) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_tree);\n");
  GWEN_Buffer_AppendString(tbuf, "  p_struct = ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree_GetFirst(p_tree);\n");
  GWEN_Buffer_AppendString(tbuf, "  while(p_struct) {\n");
  GWEN_Buffer_AppendString(tbuf, "    int p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "    ");
  if (1) {
    GWEN_BUFFER *dstbuf;
    GWEN_BUFFER *srcbuf;
    int rv;

    srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(srcbuf, "p_cmp");

    dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(dstbuf, "p_struct->");
    s=Typemaker2_Member_GetName(tm);
    GWEN_Buffer_AppendString(dstbuf, s);

    rv=Typemaker2_Builder_Invoke_CompareFn(tb, ty, tm,
                                           GWEN_Buffer_GetStart(srcbuf),
                                           GWEN_Buffer_GetStart(dstbuf),
                                           tbuf);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      GWEN_Buffer_free(srcbuf);
      GWEN_Buffer_free(dstbuf);
      GWEN_Buffer_free(tbuf);
      return rv;
    }
    GWEN_Buffer_AppendString(tbuf, "\n");
    GWEN_Buffer_free(srcbuf);
    GWEN_Buffer_free(dstbuf);
  }


  GWEN_Buffer_AppendString(tbuf, "    if (p_rv == 0)\n");
  GWEN_Buffer_AppendString(tbuf, "      return p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "    p_struct = ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree_GetBelow(p_struct);\n");

  GWEN_Buffer_AppendString(tbuf, "  }\n");

  GWEN_Buffer_AppendString(tbuf, "  return NULL;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildTree2GetByMember(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty, TYPEMAKER2_MEMBER *tm)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_TYPE *mty;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  mty=Typemaker2_Member_GetTypePtr(tm);
  assert(mty);

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }

  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree2_Get");
  GWEN_Buffer_AppendString(tbuf, "By");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_object, ");
  if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
      Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
    GWEN_Buffer_AppendString(tbuf, " const ");
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *");
  }
  else {
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "p_cmp);\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree2_Get");
  GWEN_Buffer_AppendString(tbuf, "By");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_object, ");
  if (Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Pointer ||
      Typemaker2_Type_GetType(mty)==TypeMaker2_Type_Array) {
    GWEN_Buffer_AppendString(tbuf, " const ");
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " *");
  }
  else {
    s=Typemaker2_Type_GetIdentifier(mty);
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "p_cmp) {\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_object);\n");
  GWEN_Buffer_AppendString(tbuf, "  p_struct = ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree2_GetFirstChild(p_object);\n");
  GWEN_Buffer_AppendString(tbuf, "  while(p_struct) {\n");
  GWEN_Buffer_AppendString(tbuf, "    int p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "    ");
  if (1) {
    GWEN_BUFFER *dstbuf;
    GWEN_BUFFER *srcbuf;
    int rv;

    srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(srcbuf, "p_cmp");

    dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(dstbuf, "p_struct->");
    s=Typemaker2_Member_GetName(tm);
    GWEN_Buffer_AppendString(dstbuf, s);

    rv=Typemaker2_Builder_Invoke_CompareFn(tb, ty, tm,
                                           GWEN_Buffer_GetStart(srcbuf),
                                           GWEN_Buffer_GetStart(dstbuf),
                                           tbuf);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      GWEN_Buffer_free(srcbuf);
      GWEN_Buffer_free(dstbuf);
      GWEN_Buffer_free(tbuf);
      return rv;
    }
    GWEN_Buffer_AppendString(tbuf, "\n");
    GWEN_Buffer_free(srcbuf);
    GWEN_Buffer_free(dstbuf);
  }


  GWEN_Buffer_AppendString(tbuf, "    if (p_rv == 0)\n");
  GWEN_Buffer_AppendString(tbuf, "      return p_struct;\n");

  GWEN_Buffer_AppendString(tbuf, "    p_struct = ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Tree2_GetBelow(p_struct);\n");

  GWEN_Buffer_AppendString(tbuf, "  }\n");

  GWEN_Buffer_AppendString(tbuf, "  return NULL;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildGetByMember(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  TYPEMAKER2_MEMBER_LIST *tml;
  uint32_t flags;
  /* TYPEMAKER2_TYPEMANAGER *tym; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;
      int rv;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_WITH_GETBYMEMBER) {
        if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
          rv=_buildList1GetByMember(tb, ty, tm);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            return rv;
          }
        }

        if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE) {
          rv=_buildTreeGetByMember(tb, ty, tm);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            return rv;
          }
        }

        if (flags & TYPEMAKER2_TYPEFLAGS_WITH_TREE2) {
          rv=_buildTree2GetByMember(tb, ty, tm);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            return rv;
          }
        }

      }
      tm=Typemaker2_Member_List_Next(tm);
    }
    GWEN_Buffer_AppendString(tbuf, "  return p_cl;\n");
  }

  return 0;
}



static int _buildList1SortByMember(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty, TYPEMAKER2_MEMBER *tm)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_TYPE *mty;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  mty=Typemaker2_Member_GetTypePtr(tm);
  assert(mty);

  /* ==== prototypes  ========================================================*/
  /* ---- _List_SortByMember  ----------------------------------------------- */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }

  /* return type */
  GWEN_Buffer_AppendString(tbuf, "void ");

  /* function name */
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_SortBy");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);

  /* argument list */
  GWEN_Buffer_AppendString(tbuf, "(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_list, int p_ascending);\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);


  /* ----  _List_Compare_Member --------------------------------------------- */
  /* return type */
  GWEN_Buffer_AppendString(tbuf, "int GWENHYWFAR_CB ");

  /* function name */
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Compare_");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);

  /* argument list */
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_a, ");
  GWEN_Buffer_AppendString(tbuf, "const ");
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_b, ");
  GWEN_Buffer_AppendString(tbuf, "int p_ascending);\n");

  Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);


  /* ==== implementations =================================================== */
  /* ---- _List_SortByMember  ----------------------------------------------- */
  /* return type */
  GWEN_Buffer_AppendString(tbuf, "void ");

  /* function name */
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_SortBy");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);

  /* argument list */
  GWEN_Buffer_AppendString(tbuf, "(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST *p_list, int p_ascending) {\n");


  GWEN_Buffer_AppendString(tbuf, "  ");

  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_LIST_SORT_FN oldSortFn;\n");

  GWEN_Buffer_AppendString(tbuf, "\n");
  GWEN_Buffer_AppendString(tbuf, "  oldSortFn=");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_SetSortFn(p_list, ");

  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Compare_");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);
  GWEN_Buffer_AppendString(tbuf, ");\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Sort(p_list, p_ascending);\n");

  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_SetSortFn(p_list, oldSortFn);\n");

  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);


  /* ----  _List_Compare_Member --------------------------------------------- */
  /* return type */
  GWEN_Buffer_AppendString(tbuf, "int GWENHYWFAR_CB ");

  /* function name */
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_List_Compare_");
  s=Typemaker2_Member_GetName(tm);
  GWEN_Buffer_AppendByte(tbuf, toupper(*s));
  GWEN_Buffer_AppendString(tbuf, s+1);

  /* argument list */
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_a, ");
  GWEN_Buffer_AppendString(tbuf, "const ");
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_b, ");
  GWEN_Buffer_AppendString(tbuf, "int p_ascending) {\n");

  GWEN_Buffer_AppendString(tbuf, "  int p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  if (1) {
    GWEN_BUFFER *dstbuf;
    GWEN_BUFFER *srcbuf;
    int rv;

    srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(srcbuf, "p_a->");
    s=Typemaker2_Member_GetName(tm);
    GWEN_Buffer_AppendString(srcbuf, s);


    dstbuf=GWEN_Buffer_new(0, 256, 0, 1);
    GWEN_Buffer_AppendString(dstbuf, "p_b->");
    s=Typemaker2_Member_GetName(tm);
    GWEN_Buffer_AppendString(dstbuf, s);

    rv=Typemaker2_Builder_Invoke_CompareFn(tb, ty, tm,
                                           GWEN_Buffer_GetStart(srcbuf),
                                           GWEN_Buffer_GetStart(dstbuf),
                                           tbuf);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      GWEN_Buffer_free(srcbuf);
      GWEN_Buffer_free(dstbuf);
      GWEN_Buffer_free(tbuf);
      return rv;
    }
    GWEN_Buffer_AppendString(tbuf, "\n");
    GWEN_Buffer_free(srcbuf);
    GWEN_Buffer_free(dstbuf);
  }

  GWEN_Buffer_AppendString(tbuf, "  if (p_ascending)\n");
  GWEN_Buffer_AppendString(tbuf, "    return p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "  else\n");
  GWEN_Buffer_AppendString(tbuf, "    return -p_rv;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildSortByMember(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_MEMBER_LIST *tml;
  uint32_t flags;
  /* TYPEMAKER2_TYPEMANAGER *tym; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */

  flags=Typemaker2_Type_GetFlags(ty);

  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;
      int rv;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_SORTBYMEMBER) {
        if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
          rv=_buildList1SortByMember(tb, ty, tm);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            return rv;
          }
        }
      }
      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  return 0;
}



static int _buildDefineDefines(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_DEFINE_LIST *defines;
  /* TYPEMAKER2_TYPEMANAGER *tym; */
  /* uint32_t flags; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  defines=Typemaker2_Type_GetDefines(ty);
  /* flags=Typemaker2_Type_GetFlags(ty); */

  assert(defines);
  if (Typemaker2_Define_List_GetCount(defines)) {
    GWEN_BUFFER *tbuf;
    const char *s;
    TYPEMAKER2_DEFINE *td;

    tbuf=GWEN_Buffer_new(0, 256, 0, 1);

    td=Typemaker2_Define_List_First(defines);
    while (td) {
      const char *prefix;
      TYPEMAKER2_ITEM *ti;
      int access=TypeMaker2_Access_Public;
      int j=Typemaker2_Define_GetStartValue(td);

      GWEN_Buffer_AppendString(tbuf, "/* define ");
      s=Typemaker2_Define_GetId(td);
      if (s && *s)
        GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " */\n");

      prefix=Typemaker2_Define_GetPrefix(td);
      if (prefix==NULL || *prefix==0) {
        DBG_ERROR(GWEN_LOGDOMAIN, "No prefix in define definition");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }

      ti=Typemaker2_Item_List_First(Typemaker2_Define_GetItems(td));
      while (ti) {
        GWEN_Buffer_AppendString(tbuf, "#define ");
        if (prefix)
          GWEN_Buffer_AppendString(tbuf, prefix);
        s=Typemaker2_Item_GetName(ti);
        if (s && *s) {
          GWEN_Buffer_AppendString(tbuf, s);
        }
        s=Typemaker2_Item_GetValue(ti);
        if (s) {
          GWEN_Buffer_AppendString(tbuf, " ");
          GWEN_Buffer_AppendString(tbuf, s);
        }
        else {
          char numbuf[32];
          int k=0;

          switch (Typemaker2_Define_GetMode(td)) {
          case Typemaker2_Define_Mode_BitField:
            k=1<<j;
            break;
          case Typemaker2_Define_Mode_Sequence:
          default:
            k=j;
          }
          snprintf(numbuf, sizeof(numbuf)-1, "%d", k);
          numbuf[sizeof(numbuf)-1]=0;
          GWEN_Buffer_AppendString(tbuf, " ");
          GWEN_Buffer_AppendString(tbuf, numbuf);
          j++;
        }

        GWEN_Buffer_AppendString(tbuf, "\n");
        ti=Typemaker2_Item_List_Next(ti);
      }
      GWEN_Buffer_AppendString(tbuf, "\n");

      switch (access) {
      case TypeMaker2_Access_Public:
        Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Library:
        Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Protected:
        Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      case TypeMaker2_Access_Private:
        Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
        break;
      default:
        DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
        GWEN_Buffer_free(tbuf);
        return GWEN_ERROR_BAD_DATA;
      }
      GWEN_Buffer_Reset(tbuf);

      td=Typemaker2_Define_List_Next(td);
    }
  }
  return 0;
}



static int _buildToHashString(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_MEMBER_LIST *tml;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }

  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toHashString");
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_BUFFER *p_buffer);\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_toHashString");
  GWEN_Buffer_AppendString(tbuf, "(const ");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_BUFFER *p_buffer) {\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");


  tml=Typemaker2_Type_GetMembers(ty);
  if (tml) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(tml);
    while (tm) {
      TYPEMAKER2_TYPE *mty;

      mty=Typemaker2_Member_GetTypePtr(tm);
      assert(mty);

      if (Typemaker2_Member_GetFlags(tm) & TYPEMAKER2_FLAGS_WITH_HASH) {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" */\n");

        /* toHashString */
        if (1) {
          GWEN_BUFFER *srcbuf;
          int rv;

          srcbuf=GWEN_Buffer_new(0, 256, 0, 1);
          GWEN_Buffer_AppendString(srcbuf, "p_struct->");
          s=Typemaker2_Member_GetName(tm);
          GWEN_Buffer_AppendString(srcbuf, s);

          GWEN_Buffer_AppendString(tbuf, "  ");
          rv=Typemaker2_Builder_Invoke_ToHashStringFn(tb, ty, tm,
                                                      GWEN_Buffer_GetStart(srcbuf),
                                                      NULL, /* no dest */
                                                      tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(srcbuf);
            GWEN_Buffer_free(tbuf);
            return rv;
          }
          GWEN_Buffer_AppendString(tbuf, "\n");
          GWEN_Buffer_free(srcbuf);
        }

        GWEN_Buffer_AppendString(tbuf, "  GWEN_Buffer_AppendByte(p_buffer, \':\');\n");
      }
      else {
        GWEN_Buffer_AppendString(tbuf, "  /* member \"");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, "\" does not have the with_hash flag, ignoring */\n");
      }

      tm=Typemaker2_Member_List_Next(tm);
    }
  }


  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildInlines(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  uint32_t flags;
  /* TYPEMAKER2_TYPEMANAGER *tym; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  while (ty) {
    TYPEMAKER2_INLINE *ti;

    ti=Typemaker2_Inline_List_First(Typemaker2_Type_GetInlines(ty));
    while (ti) {
      if ((flags & Typemaker2_Inline_GetTypeFlagsMask(ti))==Typemaker2_Inline_GetTypeFlagsValue(ti)) {
        const char *content;

        content=Typemaker2_Inline_GetContent(ti);
        if (content && *content) {
          GWEN_DB_NODE *db;
          int rv;

          db=Typemaker2_Builder_CreateDbForCall(tb, ty, NULL, NULL, NULL);
          assert(db);
          rv=Typemaker2_Builder_ReplaceVars(content, db, tbuf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_Buffer_free(tbuf);
            return rv;
          }

          /* include code */
          switch (Typemaker2_Inline_GetLocation(ti)) {
          case Typemaker2_InlineLocation_Header:
            switch (Typemaker2_Inline_GetAccess(ti)) {
            case TypeMaker2_Access_Public:
              Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
              break;
            case TypeMaker2_Access_Library:
              Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
              break;
            case TypeMaker2_Access_Protected:
              Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
              break;
            case TypeMaker2_Access_Private:
              Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
              break;
            default:
              DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
              GWEN_Buffer_free(tbuf);
              return GWEN_ERROR_BAD_DATA;
            }
            break;

          case Typemaker2_InlineLocation_Code:
            Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
            break;
          }
        }
        GWEN_Buffer_Reset(tbuf);
      }

      ti=Typemaker2_Inline_List_Next(ti);
    }
    ty=Typemaker2_Type_GetExtendsPtr(ty);
  }

  return 0;
}



static int _buildMemberInlines(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  uint32_t flags;
  /* TYPEMAKER2_TYPEMANAGER *tym; */

  /* tym=Typemaker2_Builder_GetTypeManager(tb); */
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  flags=Typemaker2_Type_GetFlags(ty);

  while (ty) {
    TYPEMAKER2_MEMBER_LIST *tml;

    tml=Typemaker2_Type_GetMembers(ty);
    if (tml) {
      TYPEMAKER2_MEMBER *tm;

      tm=Typemaker2_Member_List_First(tml);
      while (tm) {
        TYPEMAKER2_TYPE *mty;

        mty=Typemaker2_Member_GetTypePtr(tm);
        if (mty) {
          TYPEMAKER2_INLINE *ti;

          /* get inlines from member type */
          ti=Typemaker2_Inline_List_First(Typemaker2_Type_GetInlines(mty));
          while (ti) {
            if ((flags & Typemaker2_Inline_GetTypeFlagsMask(ti))==Typemaker2_Inline_GetTypeFlagsValue(ti)) {
              const char *content;

              content=Typemaker2_Inline_GetContent(ti);
              if (content && *content) {
                GWEN_DB_NODE *db;
                int rv;

                /* replace vars in context of the struct type, not the particular member type */
                db=Typemaker2_Builder_CreateDbForCall(tb, ty, tm, NULL, NULL);
                assert(db);
                rv=Typemaker2_Builder_ReplaceVars(content, db, tbuf);
                if (rv<0) {
                  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
                  GWEN_Buffer_free(tbuf);
                  return rv;
                }

                /* include code */
                switch (Typemaker2_Inline_GetLocation(ti)) {
                case Typemaker2_InlineLocation_Header:
                  switch (Typemaker2_Inline_GetAccess(ti)) {
                  case TypeMaker2_Access_Public:
                    Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
                    break;
                  case TypeMaker2_Access_Library:
                    Typemaker2_Builder_AddLibraryDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
                    break;
                  case TypeMaker2_Access_Protected:
                    Typemaker2_Builder_AddProtectedDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
                    break;
                  case TypeMaker2_Access_Private:
                    Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
                    break;
                  default:
                    DBG_ERROR(GWEN_LOGDOMAIN, "Invalid access type");
                    GWEN_Buffer_free(tbuf);
                    return GWEN_ERROR_BAD_DATA;
                  }
                  break;

                case Typemaker2_InlineLocation_Code:
                  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
                  break;
                }
              }
              GWEN_Buffer_Reset(tbuf);
            }

            ti=Typemaker2_Inline_List_Next(ti);
          }
        } /* if mty */

        tm=Typemaker2_Member_List_Next(tm);
      } /* while tm */
    } /* if tml */

    ty=Typemaker2_Type_GetExtendsPtr(ty);
  }

  return 0;
}



static int _buildAttach(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  /* prototype */
  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Attach(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);

  /* implementation */
  GWEN_Buffer_AppendString(tbuf, "void ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Attach(");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, " *p_struct) {\n");

  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
  GWEN_Buffer_AppendString(tbuf, "  assert(p_struct->_refCount);\n");
  GWEN_Buffer_AppendString(tbuf, "  p_struct->_refCount++;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");

  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildSignalFunctions(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  /* uint32_t flags; */
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_SIGNAL_LIST *sigList;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* flags=Typemaker2_Type_GetFlags(ty); */

  sigList=Typemaker2_Type_GetSignals(ty);
  if (sigList) {
    TYPEMAKER2_SIGNAL *sig;

    /* prototype */
    GWEN_Buffer_AppendString(tbuf, "/* signal functions */\n");
    sig=Typemaker2_Signal_List_First(sigList);
    while (sig) {

      /* SignalConnect */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      GWEN_Buffer_AppendString(tbuf, "int ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_SignalConnect_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_SLOT *slot);\n");

      /* SignalDisconnect */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      GWEN_Buffer_AppendString(tbuf, "int ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_SignalDisconnect_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_SLOT *slot);\n");

      /* GetSignal */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      GWEN_Buffer_AppendString(tbuf, "GWEN_SIGNAL *");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_GetSignal_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(const ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");


      /* EmitSignal */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      GWEN_Buffer_AppendString(tbuf, "int ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_EmitSignal_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct");
      s=Typemaker2_Signal_GetParamType1(sig);            /* param 1 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, ", ");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " param1");
      }
      s=Typemaker2_Signal_GetParamType2(sig);            /* param 2 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, ", ");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " param2");
      }
      if (Typemaker2_Signal_GetFlags(sig) & TYPEMAKER2_SIGNAL_FLAGS_USE_PARAM3) {
        GWEN_Buffer_AppendString(tbuf, ", int param3");
      }
      if (Typemaker2_Signal_GetFlags(sig) & TYPEMAKER2_SIGNAL_FLAGS_USE_PARAM4) {
        GWEN_Buffer_AppendString(tbuf, ", int param4");
      }
      GWEN_Buffer_AppendString(tbuf, ");\n");


      sig=Typemaker2_Signal_List_Next(sig);
    }
    Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

    /* implementation */
    GWEN_Buffer_AppendString(tbuf, "/* signal functions */\n");
    sig=Typemaker2_Signal_List_First(sigList);
    while (sig) {

      /* SignalConnect */
      GWEN_Buffer_AppendString(tbuf, "int ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_SignalConnect_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_SLOT *slot) {\n");

      GWEN_Buffer_AppendString(tbuf, "  GWEN_SIGNAL *sig;\n");
      GWEN_Buffer_AppendString(tbuf, "\n");
      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  sig=GWEN_SignalObject_FindSignal(p_struct->_signalObject, ");
      s=Typemaker2_Signal_GetName(sig);       /* name */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType1(sig); /* param 1 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType2(sig); /* param 2 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\");\n");
      GWEN_Buffer_AppendString(tbuf, "  if (sig)\n");
      GWEN_Buffer_AppendString(tbuf, "    return GWEN_Signal_Connect(sig, slot);\n");
      GWEN_Buffer_AppendString(tbuf, "  else\n");
      GWEN_Buffer_AppendString(tbuf, "    return GWEN_ERROR_NOT_FOUND;\n");

      GWEN_Buffer_AppendString(tbuf, "}\n");
      GWEN_Buffer_AppendString(tbuf, "\n");

      /* SignalDisconnect */
      GWEN_Buffer_AppendString(tbuf, "int ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_SignalDisconnect_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct, GWEN_SLOT *slot) {\n");

      GWEN_Buffer_AppendString(tbuf, "  GWEN_SIGNAL *sig;\n");
      GWEN_Buffer_AppendString(tbuf, "\n");
      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  sig=GWEN_SignalObject_FindSignal(p_struct->_signalObject, ");
      s=Typemaker2_Signal_GetName(sig);       /* name */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType1(sig); /* param 1 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType2(sig); /* param 2 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\");\n");
      GWEN_Buffer_AppendString(tbuf, "  if (sig)\n");
      GWEN_Buffer_AppendString(tbuf, "    return GWEN_Signal_Disconnect(sig, slot);\n");
      GWEN_Buffer_AppendString(tbuf, "  else\n");
      GWEN_Buffer_AppendString(tbuf, "    return GWEN_ERROR_NOT_FOUND;\n");

      GWEN_Buffer_AppendString(tbuf, "}\n");
      GWEN_Buffer_AppendString(tbuf, "\n");


      /* GetSignal */
      GWEN_Buffer_AppendString(tbuf, "GWEN_SIGNAL *");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_GetSignal_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(const ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct) {\n");

      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  return GWEN_SignalObject_FindSignal(p_struct->_signalObject, ");
      s=Typemaker2_Signal_GetName(sig);       /* name */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType1(sig); /* param 1 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType2(sig); /* param 2 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\");\n");

      GWEN_Buffer_AppendString(tbuf, "}\n");
      GWEN_Buffer_AppendString(tbuf, "\n");


      /* EmitSignal */
      GWEN_Buffer_AppendString(tbuf, "int ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_EmitSignal_");
      s=Typemaker2_Signal_GetName(sig);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct");
      s=Typemaker2_Signal_GetParamType1(sig);            /* param 1 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, ", ");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " param1");
      }
      s=Typemaker2_Signal_GetParamType2(sig);            /* param 2 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, ", ");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " param2");
      }
      if (Typemaker2_Signal_GetFlags(sig) & TYPEMAKER2_SIGNAL_FLAGS_USE_PARAM3) {
        GWEN_Buffer_AppendString(tbuf, ", int param3");
      }
      if (Typemaker2_Signal_GetFlags(sig) & TYPEMAKER2_SIGNAL_FLAGS_USE_PARAM4) {
        GWEN_Buffer_AppendString(tbuf, ", int param4");
      }
      GWEN_Buffer_AppendString(tbuf, "){\n");

      GWEN_Buffer_AppendString(tbuf, "  GWEN_SIGNAL *sig;\n");
      GWEN_Buffer_AppendString(tbuf, "\n");
      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  sig=GWEN_SignalObject_FindSignal(p_struct->_signalObject, ");
      s=Typemaker2_Signal_GetName(sig);       /* name */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\", ");

      s=Typemaker2_Signal_GetParamType1(sig); /* param 1 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Signal_GetParamType2(sig); /* param 2 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\");\n");

      GWEN_Buffer_AppendString(tbuf, "  if (sig) \n");
      GWEN_Buffer_AppendString(tbuf, "    return GWEN_Signal_Emit(sig, ");
      s=Typemaker2_Signal_GetParamType1(sig);            /* param 1 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, "(void*) ");
        GWEN_Buffer_AppendString(tbuf, "param1, ");
      }
      else
        GWEN_Buffer_AppendString(tbuf, "NULL, ");
      s=Typemaker2_Signal_GetParamType2(sig);            /* param 2 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, "(void*) ");
        GWEN_Buffer_AppendString(tbuf, " param2, ");
      }
      else
        GWEN_Buffer_AppendString(tbuf, "NULL, ");
      if (Typemaker2_Signal_GetFlags(sig) & TYPEMAKER2_SIGNAL_FLAGS_USE_PARAM3)
        GWEN_Buffer_AppendString(tbuf, "param3, ");
      else
        GWEN_Buffer_AppendString(tbuf, "0, ");
      if (Typemaker2_Signal_GetFlags(sig) & TYPEMAKER2_SIGNAL_FLAGS_USE_PARAM4)
        GWEN_Buffer_AppendString(tbuf, "param4");
      else
        GWEN_Buffer_AppendString(tbuf, "0");
      GWEN_Buffer_AppendString(tbuf, ");\n");


      GWEN_Buffer_AppendString(tbuf, "  else\n");
      GWEN_Buffer_AppendString(tbuf, "    return 0;\n");

      GWEN_Buffer_AppendString(tbuf, "}\n");
      GWEN_Buffer_AppendString(tbuf, "\n");


      sig=Typemaker2_Signal_List_Next(sig);
    }
    Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

  }
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildSlotFunctions(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_TYPEMANAGER *tym;
  TYPEMAKER2_SLOT_LIST *slotList;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  slotList=Typemaker2_Type_GetSlots(ty);
  if (slotList) {
    TYPEMAKER2_SLOT *slot;

    /* private prototypes */
    GWEN_Buffer_AppendString(tbuf, "/* slot functions */\n");
    slot=Typemaker2_Slot_List_First(slotList);
    while (slot) {

      /* callback function */
      GWEN_Buffer_AppendString(tbuf, "static int GWENHYWFAR_CB ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_SlotCallback_");
      s=Typemaker2_Slot_GetName(slot);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(GWEN_SLOT *slot, void *userData, void *p1, void *p2, int p3, int p4);\n");

      slot=Typemaker2_Slot_List_Next(slot);
    }

    Typemaker2_Builder_AddPrivateDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

    /* public prototypes */
    GWEN_Buffer_AppendString(tbuf, "/* slot functions */\n");
    slot=Typemaker2_Slot_List_First(slotList);
    while (slot) {
      /* GetSlot */
      s=Typemaker2_TypeManager_GetApiDeclaration(tym);
      if (s) {
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, " ");
      }
      GWEN_Buffer_AppendString(tbuf, "GWEN_SLOT *");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_GetSlot_");
      s=Typemaker2_Slot_GetName(slot);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(const ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct);\n");


      slot=Typemaker2_Slot_List_Next(slot);
    }
    Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

    /* implementation */
    GWEN_Buffer_AppendString(tbuf, "/* slot functions */\n");
    slot=Typemaker2_Slot_List_First(slotList);
    while (slot) {

      /* callback function */
      GWEN_Buffer_AppendString(tbuf, "static int GWENHYWFAR_CB ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_SlotCallback_");
      s=Typemaker2_Slot_GetName(slot);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(GWEN_SLOT *slot, void *userData, void *p1, void *p2, int p3, int p4) {\n");

      GWEN_Buffer_AppendString(tbuf, "  ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct;\n");

      GWEN_Buffer_AppendString(tbuf, "\n");
      GWEN_Buffer_AppendString(tbuf, "  p_struct=(");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "*) userData;\n");

      GWEN_Buffer_AppendString(tbuf, "  return ");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_");
      s=Typemaker2_Slot_GetName(slot);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(p_struct");

      s=Typemaker2_Slot_GetParamType1(slot); /* param 1 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, ", (");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ") p1");
      }
      s=Typemaker2_Slot_GetParamType2(slot); /* param 2 */
      if (s && *s && strcasecmp(s, "none")) {
        GWEN_Buffer_AppendString(tbuf, ", (");
        GWEN_Buffer_AppendString(tbuf, s);
        GWEN_Buffer_AppendString(tbuf, ") p2");
      }
      if (Typemaker2_Slot_GetFlags(slot) & TYPEMAKER2_SLOT_FLAGS_USE_PARAM3)
        GWEN_Buffer_AppendString(tbuf, ", p3");
      if (Typemaker2_Slot_GetFlags(slot) & TYPEMAKER2_SLOT_FLAGS_USE_PARAM4)
        GWEN_Buffer_AppendString(tbuf, ", p4");

      GWEN_Buffer_AppendString(tbuf, ");\n");

      GWEN_Buffer_AppendString(tbuf, "}\n\n");


      /* GetSlot */
      GWEN_Buffer_AppendString(tbuf, "GWEN_SLOT *");
      s=Typemaker2_Type_GetPrefix(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "_GetSlot_");
      s=Typemaker2_Slot_GetName(slot);
      GWEN_Buffer_AppendByte(tbuf, toupper(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);
      GWEN_Buffer_AppendString(tbuf, "(const ");
      s=Typemaker2_Type_GetIdentifier(ty);
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, " *p_struct) {\n");

      GWEN_Buffer_AppendString(tbuf, "  assert(p_struct);\n");
      GWEN_Buffer_AppendString(tbuf, "  return GWEN_SignalObject_FindSlot(p_struct->_signalObject, ");
      s=Typemaker2_Slot_GetName(slot);       /* name */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s);
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Slot_GetParamType1(slot); /* param 1 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\", ");
      s=Typemaker2_Slot_GetParamType2(slot); /* param 2 */
      GWEN_Buffer_AppendString(tbuf, "\"");
      GWEN_Buffer_AppendString(tbuf, s?s:"none");
      GWEN_Buffer_AppendString(tbuf, "\");\n");

      GWEN_Buffer_AppendString(tbuf, "}\n");
      GWEN_Buffer_AppendString(tbuf, "\n");

      slot=Typemaker2_Slot_List_Next(slot);
    }
    Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
    GWEN_Buffer_Reset(tbuf);

  }
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildCacheFunctions(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_TYPEMANAGER *tym;

  tym=Typemaker2_Builder_GetTypeManager(tb);
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  /* public prototypes */
  GWEN_Buffer_AppendString(tbuf, "/* cache functions */\n");

  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int GWENHYWFAR_CB ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CacheFn_Attach(void *ptr);\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  s=Typemaker2_TypeManager_GetApiDeclaration(tym);
  if (s) {
    GWEN_Buffer_AppendString(tbuf, s);
    GWEN_Buffer_AppendString(tbuf, " ");
  }
  GWEN_Buffer_AppendString(tbuf, "int GWENHYWFAR_CB ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CacheFn_Free(void *ptr);\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_Reset(tbuf);


  /* implementations */
  GWEN_Buffer_AppendString(tbuf, "/* cache functions */\n");

  GWEN_Buffer_AppendString(tbuf, "int GWENHYWFAR_CB ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CacheFn_Attach(void *ptr) {\n");
  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_Attach((");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "*) ptr);\n");
  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");
  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "int GWENHYWFAR_CB ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_CacheFn_Free(void *ptr){\n");
  GWEN_Buffer_AppendString(tbuf, "  ");
  s=Typemaker2_Type_GetPrefix(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "_free((");
  s=Typemaker2_Type_GetIdentifier(ty);
  GWEN_Buffer_AppendString(tbuf, s);
  GWEN_Buffer_AppendString(tbuf, "*) ptr);\n");
  GWEN_Buffer_AppendString(tbuf, "  return 0;\n");
  GWEN_Buffer_AppendString(tbuf, "}\n");
  GWEN_Buffer_AppendString(tbuf, "\n");


  Typemaker2_Builder_AddCode(tb, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);

  return 0;
}



static int _buildGroupApiDoc(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty,
                             TYPEMAKER2_GROUP *grp, int depth, GWEN_BUFFER *buf)
{
  char numbuf[32];
  const char *s;
  TYPEMAKER2_GROUP *childGrp;
  TYPEMAKER2_MEMBER_LIST *members;
  const char *sTypeIdentifier;
  const char *sTypePrefix;

  sTypeIdentifier=Typemaker2_Type_GetIdentifier(ty);
  sTypePrefix=Typemaker2_Type_GetPrefix(ty);

  /* write title */
  GWEN_Buffer_AppendString(buf, "\n\n");
  GWEN_Buffer_AppendString(buf, "<h");
  snprintf(numbuf, sizeof(numbuf)-1, "%d", depth);
  numbuf[sizeof(numbuf)-1]=0;
  GWEN_Buffer_AppendString(buf, numbuf);
  GWEN_Buffer_AppendString(buf, ">");
  s=Typemaker2_Group_GetTitle(grp);
  if (s && *s)
    GWEN_Buffer_AppendString(buf, s);
  else
    GWEN_Buffer_AppendString(buf, "Unnamed Group");
  GWEN_Buffer_AppendString(buf, "</h");
  GWEN_Buffer_AppendString(buf, numbuf);
  GWEN_Buffer_AppendString(buf, ">\n");
  GWEN_Buffer_AppendString(buf, "\n");

  s=Typemaker2_Group_GetDescription(grp);
  if (s && *s) {
    GWEN_DB_NODE *dbCall;
    int rv;

    dbCall=Typemaker2_Builder_CreateDbForCall(tb, ty, NULL, NULL, NULL);
    assert(dbCall);
    rv=Typemaker2_Builder_ReplaceVars(s, dbCall, buf);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      GWEN_DB_Group_free(dbCall);
      GWEN_Buffer_free(buf);
      return rv;
    }
    GWEN_DB_Group_free(dbCall);
    GWEN_Buffer_AppendString(buf, "\n");
  }

  /* write member docs */
  members=Typemaker2_Type_GetMembers(ty);
  if (members) {
    TYPEMAKER2_MEMBER *tm;

    tm=Typemaker2_Member_List_First(members);
    while (tm) {

      if (Typemaker2_Member_GetGroupPtr(tm)==grp) {
        const char *sMemberName;

        /* write APIDOC for member */
        sMemberName=Typemaker2_Member_GetName(tm);

        /* write anchor */
        GWEN_Buffer_AppendString(buf, "\n\n@anchor ");
        GWEN_Buffer_AppendString(buf, sTypeIdentifier);
        GWEN_Buffer_AppendString(buf, "_");
        GWEN_Buffer_AppendString(buf, sMemberName);
        GWEN_Buffer_AppendString(buf, "\n");

        /* write name */
        GWEN_Buffer_AppendString(buf, "<h");
        snprintf(numbuf, sizeof(numbuf)-1, "%d", depth+1);
        numbuf[sizeof(numbuf)-1]=0;
        GWEN_Buffer_AppendString(buf, numbuf);
        GWEN_Buffer_AppendString(buf, ">");
        s=Typemaker2_Member_GetName(tm);
        GWEN_Buffer_AppendString(buf, s);
        GWEN_Buffer_AppendString(buf, "</h");
        GWEN_Buffer_AppendString(buf, numbuf);
        GWEN_Buffer_AppendString(buf, ">\n");
        GWEN_Buffer_AppendString(buf, "\n");

        /* add description, if any */
        s=Typemaker2_Member_GetDescription(tm);
        if (s && *s) {
          GWEN_DB_NODE *dbCall;
          int rv;

          dbCall=Typemaker2_Builder_CreateDbForCall(tb, ty, tm, NULL, NULL);
          assert(dbCall);
          rv=Typemaker2_Builder_ReplaceVars(s, dbCall, buf);
          if (rv<0) {
            DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
            GWEN_DB_Group_free(dbCall);
            GWEN_Buffer_free(buf);
            return rv;
          }
          GWEN_DB_Group_free(dbCall);
          GWEN_Buffer_AppendString(buf, "\n");
        }

        /* add setter/getter info */
        GWEN_Buffer_AppendString(buf, "<p>");
        GWEN_Buffer_AppendString(buf, "Set this property with @ref ");
        GWEN_Buffer_AppendString(buf, sTypePrefix);
        GWEN_Buffer_AppendString(buf, "_Set");
        GWEN_Buffer_AppendByte(buf, toupper(*sMemberName));
        GWEN_Buffer_AppendString(buf, sMemberName+1);
        GWEN_Buffer_AppendString(buf, "(), get it with @ref ");
        GWEN_Buffer_AppendString(buf, sTypePrefix);
        GWEN_Buffer_AppendString(buf, "_Get");
        GWEN_Buffer_AppendByte(buf, toupper(*sMemberName));
        GWEN_Buffer_AppendString(buf, sMemberName+1);
        GWEN_Buffer_AppendString(buf, "().");
        GWEN_Buffer_AppendString(buf, "</p>\n");
      }
      tm=Typemaker2_Member_List_Next(tm);
    }
  }

  /* write children groups */
  childGrp=Typemaker2_Group_Tree_GetFirstChild(grp);
  while (childGrp) {
    int rv;

    rv=_buildGroupApiDoc(tb, ty, childGrp, depth+1, buf);
    if (rv<0) {
      DBG_ERROR(0, "here (%d)", rv);
      return rv;
    }
    childGrp=Typemaker2_Group_Tree_GetNext(childGrp);
  }

  return 0;
}




static int _buildApiDoc(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_GROUP_TREE *groupTree;
  TYPEMAKER2_GROUP *grp;
  GWEN_BUFFER *tbuf;
  const char *sTypeIdentifier;

  sTypeIdentifier=Typemaker2_Type_GetIdentifier(ty);

  groupTree=Typemaker2_Type_GetGroupTree(ty);

  tbuf=GWEN_Buffer_new(0, 256, 0, 1);

  GWEN_Buffer_AppendString(tbuf, "/** @page P_");
  GWEN_Buffer_AppendString(tbuf, sTypeIdentifier);
  GWEN_Buffer_AppendString(tbuf, " Structure ");
  GWEN_Buffer_AppendString(tbuf, sTypeIdentifier);

  GWEN_Buffer_AppendString(tbuf, "\n");

  GWEN_Buffer_AppendString(tbuf, "<p>This page describes the properties of ");
  GWEN_Buffer_AppendString(tbuf, sTypeIdentifier);
  GWEN_Buffer_AppendString(tbuf, ".</p>\n");

  GWEN_Buffer_AppendString(tbuf, "\n");


  grp=Typemaker2_Group_Tree_GetFirst(groupTree);
  while (grp) {
    _buildGroupApiDoc(tb, ty, grp, 1, tbuf);
    grp=Typemaker2_Group_Tree_GetNext(grp);
  }
  GWEN_Buffer_AppendString(tbuf, "\n");
  GWEN_Buffer_AppendString(tbuf, "*/\n");

  Typemaker2_Builder_AddPublicDeclaration(tb, GWEN_Buffer_GetStart(tbuf));

  GWEN_Buffer_free(tbuf);

  return 0;
}




static int _addVirtualFnsFromSlots(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  GWEN_BUFFER *tbuf;
  const char *s;
  TYPEMAKER2_VIRTUALFN_LIST *fnList;
  TYPEMAKER2_SLOT_LIST *slotList;

  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
  fnList=Typemaker2_Type_GetVirtualFns(ty);

  slotList=Typemaker2_Type_GetSlots(ty);
  if (slotList) {
    TYPEMAKER2_SLOT *slot;

    slot=Typemaker2_Slot_List_First(slotList);
    while (slot) {
      TYPEMAKER2_VIRTUALFN *fn;
      TYPEMAKER2_VIRTUALFN_PARAM_LIST *plist;

      /* callback function */
      s=Typemaker2_Slot_GetName(slot);
      GWEN_Buffer_AppendByte(tbuf, tolower(*s));
      GWEN_Buffer_AppendString(tbuf, s+1);

      fn=Typemaker2_VirtualFn_new();
      plist=Typemaker2_VirtualFn_GetParamTypeList(fn);

      /* name */
      Typemaker2_VirtualFn_SetName(fn, GWEN_Buffer_GetStart(tbuf));

      s=Typemaker2_Slot_GetParamType1(slot); /* param 1 */
      if (s && *s && strcasecmp(s, "none")) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        prm=Typemaker2_VirtualFn_Param_new();
        Typemaker2_VirtualFn_Param_SetType(prm, s);
        Typemaker2_VirtualFn_Param_List_Add(prm, plist);
      }
      s=Typemaker2_Slot_GetParamType2(slot); /* param 2 */
      if (s && *s && strcasecmp(s, "none")) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        prm=Typemaker2_VirtualFn_Param_new();
        Typemaker2_VirtualFn_Param_SetType(prm, s);
        Typemaker2_VirtualFn_Param_List_Add(prm, plist);
      }
      if (Typemaker2_Slot_GetFlags(slot) & TYPEMAKER2_SLOT_FLAGS_USE_PARAM3) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        prm=Typemaker2_VirtualFn_Param_new();
        Typemaker2_VirtualFn_Param_SetType(prm, "int");
        Typemaker2_VirtualFn_Param_List_Add(prm, plist);
      }
      if (Typemaker2_Slot_GetFlags(slot) & TYPEMAKER2_SLOT_FLAGS_USE_PARAM4) {
        TYPEMAKER2_VIRTUALFN_PARAM *prm;

        prm=Typemaker2_VirtualFn_Param_new();
        Typemaker2_VirtualFn_Param_SetType(prm, "int");
        Typemaker2_VirtualFn_Param_List_Add(prm, plist);
      }

      Typemaker2_VirtualFn_SetAccess(fn, TypeMaker2_Access_Public);
      Typemaker2_VirtualFn_SetLocation(fn, "post");
      Typemaker2_VirtualFn_SetReturnType(fn, "int");
      Typemaker2_VirtualFn_SetDefaultReturnValue(fn, "GWEN_ERROR_NOT_IMPLEMENTED");

      Typemaker2_VirtualFn_AddFlags(fn, TYPEMAKER2_VIRTUALFN_FLAGS_FROMSLOT);

      Typemaker2_VirtualFn_List_Add(fn, fnList);

      slot=Typemaker2_Slot_List_Next(slot);
    }
  }
  GWEN_Buffer_free(tbuf);

  return 0;
}



static void _delVirtualFnsFromSlots(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  TYPEMAKER2_VIRTUALFN_LIST *fnList;

  fnList=Typemaker2_Type_GetVirtualFns(ty);
  if (fnList) {
    TYPEMAKER2_VIRTUALFN *fn;

    fn=Typemaker2_VirtualFn_List_First(fnList);
    while (fn) {
      TYPEMAKER2_VIRTUALFN *fnNext;

      fnNext=Typemaker2_VirtualFn_List_Next(fn);
      if (Typemaker2_VirtualFn_GetFlags(fn) & TYPEMAKER2_VIRTUALFN_FLAGS_FROMSLOT) {
        Typemaker2_VirtualFn_List_Del(fn);
        Typemaker2_VirtualFn_free(fn);
      }
      fn=fnNext;
    }
  }
}




static int Typemaker2_Builder_C_Build(TYPEMAKER2_BUILDER *tb, TYPEMAKER2_TYPE *ty)
{
  int rv;
  uint32_t flags;

  flags=Typemaker2_Type_GetFlags(ty);

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS) {
    _delVirtualFnsFromSlots(tb, ty);
    rv=_addVirtualFnsFromSlots(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }


  rv=_setEnumStringFns(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_OBJECT) {
    rv=_buildFieldIds(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  rv=_buildApiDoc(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildDefineDefines(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildTypedef(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildDefineEnums(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildDefineVirtualFns(tb, ty, "pre");
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildPostHeaders(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildDefineVirtualFns(tb, ty, "post");
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildStruct(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildMacroFunctions(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildEnumFromString(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildEnumToString(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildConstructor(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildDestructor(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_REFCOUNT) {
    rv=_buildAttach(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  if (!(flags & TYPEMAKER2_TYPEFLAGS_NODUP)) {
    rv=_buildDup(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  if (!(flags & TYPEMAKER2_TYPEFLAGS_NOCOPY)) {
    rv=_buildCopy(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  rv=_buildGetter(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildSetter(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildProtoVirtualFns(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildCodeVirtualFns(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildProtoSetterVirtualFns(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildSetterVirtualFns(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_LIST1) {
    if (!(flags & TYPEMAKER2_TYPEFLAGS_NODUP)) {
      rv=_buildList1Dup(tb, ty);
      if (rv<0) {
        DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
        return rv;
      }
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_DB) {
    rv=_buildReadDb(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildWriteDb(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildFromDb(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildToDb(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_XML) {
    rv=_buildReadXml(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildWriteXml(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildToXml(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildFromXml(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_OBJECT) {
    rv=_buildReadObject(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildWriteObject(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildToObject(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildFromObject(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildCreateColumnList(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildCreateTable(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }

    rv=_buildCreateObject(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  rv=_buildGetByMember(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_HASH) {
    rv=_buildToHashString(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  rv=_buildMemberInlines(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }


  rv=_buildSortByMember(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }


  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_SIGNALS) {
    rv=_buildSignalFunctions(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_SLOTS) {
    rv=_buildSlotFunctions(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  if (flags & TYPEMAKER2_TYPEFLAGS_WITH_CACHEFNS) {
    rv=_buildCacheFunctions(tb, ty);
    if (rv<0) {
      DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
      return rv;
    }
  }

  rv=_buildInlines(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  rv=_buildEndHeaders(tb, ty);
  if (rv<0) {
    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
    return rv;
  }

  return 0;
}



TYPEMAKER2_BUILDER *Typemaker2_Builder_C_new()
{
  TYPEMAKER2_BUILDER *tb;

  tb=Typemaker2_Builder_new();
  Typemaker2_Builder_SetBuildFn(tb, Typemaker2_Builder_C_Build);

  return tb;
}





