From 4b46863128534422dc37dbafe6b1e0138c70b2fc Mon Sep 17 00:00:00 2001 From: "shaver%netscape.com" Date: Thu, 18 Feb 1999 17:43:38 +0000 Subject: [PATCH] Add dependency on libxpt and NSPR for typelib generation. Only output |static const IID()| if we have an IID defined. Output forward declarations. Initial -m typelib stuff (handles methods, barely). --- xpcom/tools/xpidl/Makefile.in | 2 +- xpcom/tools/xpidl/xpidl.c | 2 +- xpcom/tools/xpidl/xpidl_header.c | 31 +- xpcom/tools/xpidl/xpidl_typelib.c | 460 +++++++++++++++++++++++++++- xpcom/typelib/xpidl/Makefile.in | 2 +- xpcom/typelib/xpidl/xpidl.c | 2 +- xpcom/typelib/xpidl/xpidl_header.c | 31 +- xpcom/typelib/xpidl/xpidl_typelib.c | 460 +++++++++++++++++++++++++++- 8 files changed, 968 insertions(+), 22 deletions(-) diff --git a/xpcom/tools/xpidl/Makefile.in b/xpcom/tools/xpidl/Makefile.in index 42851701a0a..85f96d60893 100644 --- a/xpcom/tools/xpidl/Makefile.in +++ b/xpcom/tools/xpidl/Makefile.in @@ -39,7 +39,7 @@ include $(topsrcdir)/config/config.mk CFLAGS += $(shell glib-config --cflags) # XXX need configure test -EX_LIBS = -lIDL $(shell glib-config --libs) +EX_LIBS = -lIDL -L$(DIST)/bin -lxpt $(NSPR_LIBS) $(shell glib-config --libs) PROGS = $(OBJDIR)/xpidl diff --git a/xpcom/tools/xpidl/xpidl.c b/xpcom/tools/xpidl/xpidl.c index 36935db00bc..f54dd3c07b2 100644 --- a/xpcom/tools/xpidl/xpidl.c +++ b/xpcom/tools/xpidl/xpidl.c @@ -106,7 +106,7 @@ main(int argc, char *argv[]) break; switch (argv[i][1]) { case '-': - argc++; + argc++; /* pretend we didn't see this */ /* fall through */ case 0: /* - is a legal input filename (stdin) */ goto done_options; diff --git a/xpcom/tools/xpidl/xpidl_header.c b/xpcom/tools/xpidl/xpidl_header.c index 0e0797fdc12..dcd7fd3d498 100644 --- a/xpcom/tools/xpidl/xpidl_header.c +++ b/xpcom/tools/xpidl/xpidl_header.c @@ -123,13 +123,15 @@ interface(TreeState *state) } } fputs(" {\n" - " public: \n" - " static const nsIID& IID() {\n" - " static nsIID iid = ", - state->file); - if (!output_classname_iid_define(state->file, className)) - return FALSE; - fputs(";\n return iid;\n }\n", state->file); + " public: \n", state->file); + if (iid) { + fputs(" static const nsIID& IID() {\n" + " static nsIID iid = ", + state->file); + if (!output_classname_iid_define(state->file, className)) + return FALSE; + fputs(";\n return iid;\n }\n", state->file); + } state->tree = IDL_INTERFACE(iface).body; @@ -322,6 +324,20 @@ xpcom_param(TreeState *state) return TRUE; } +/* + * A forward declaration, usually an interface. + */ +static gboolean +forward_dcl(TreeState *state) +{ + IDL_tree iface = state->tree; + char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str; + if (!className) + return FALSE; + fprintf(state->file, "class %s; /* forward decl */\n", className); + return TRUE; +} + /* * A method is an `operation', therefore a method decl is an `op dcl'. * I blame Elliot. @@ -395,6 +411,7 @@ xpidl_header_dispatch(void) table[IDLN_LIST] = list; table[IDLN_ATTR_DCL] = attr_dcl; table[IDLN_OP_DCL] = op_dcl; + table[IDLN_FORWARD_DCL] = forward_dcl; table[IDLN_TYPE_ENUM] = do_enum; table[IDLN_INTERFACE] = interface; table[IDLN_CODEFRAG] = codefrag; diff --git a/xpcom/tools/xpidl/xpidl_typelib.c b/xpcom/tools/xpidl/xpidl_typelib.c index d594db4f871..22b65f6aa19 100644 --- a/xpcom/tools/xpidl/xpidl_typelib.c +++ b/xpcom/tools/xpidl/xpidl_typelib.c @@ -22,6 +22,458 @@ */ #include "xpidl.h" +#include +#include + +struct priv_data { + XPTHeader *header; + uint16 ifaces; + GHashTable *interface_map; + XPTInterfaceDescriptor *current; + uint16 next_method; +}; + +#define HEADER(state) (((struct priv_data *)state->priv)->header) +#define IFACES(state) (((struct priv_data *)state->priv)->ifaces) +#define IFACE_MAP(state) (((struct priv_data *)state->priv)->interface_map) +#define CURRENT(state) (((struct priv_data *)state->priv)->current) +#define NEXT_METH(state) (((struct priv_data *)state->priv)->next_method) + +/* + * If p is an ident for an interface, and we don't have an entry in the + * interface map yet, add one. + */ +static gboolean +add_interface_maybe(IDL_tree p, IDL_tree scope, gpointer user_data) +{ + TreeState *state = user_data; + IDL_tree up; + if (IDL_NODE_TYPE(p) == IDLN_IDENT) { + if ((IDL_NODE_TYPE((up = IDL_NODE_UP(p))) == IDLN_INTERFACE)) { + char *iface = IDL_IDENT(p).str; + if (!g_hash_table_lookup(IFACE_MAP(state), iface)) { + /* XXX should we parse here and store a struct nsID *? */ + char *iid = (char *)IDL_tree_property_get(up, "uuid"); + if (iid) + iid = strdup(iid); + g_hash_table_insert(IFACE_MAP(state), iface, iid); + IFACES(state)++; +#ifdef DEBUG_shaver + fprintf(stderr, "adding interface #%d: %s/%s\n", IFACES(state), + iface, iid ? iid : ""); +#endif + } + } else { +#ifdef DEBUG_shaver + fprintf(stderr, "ident %s isn't an interface (%s)\n", + IDL_IDENT(p).str, IDL_NODE_TYPE_NAME(up)); +#endif + } + } + + return PR_TRUE; +} + +/* Find all the interfaces referenced in the tree (uses add_interface_maybe) */ +static gboolean +find_interfaces(IDL_tree p, IDL_tree scope, gpointer user_data) +{ + IDL_tree node = NULL; + + switch (IDL_NODE_TYPE(p)) { + case IDLN_ATTR_DCL: + node = IDL_ATTR_DCL(p).param_type_spec; + break; + case IDLN_OP_DCL: + IDL_tree_walk_in_order(IDL_OP_DCL(p).parameter_dcls, find_interfaces, + user_data); + node = IDL_OP_DCL(p).op_type_spec; + break; + case IDLN_PARAM_DCL: + node = IDL_PARAM_DCL(p).param_type_spec; + break; + case IDLN_INTERFACE: + node = IDL_INTERFACE(p).inheritance_spec; + if (node) + xpidl_list_foreach(node, add_interface_maybe, user_data); + node = IDL_INTERFACE(p).ident; + break; + default: + node = NULL; + } + + if (node && IDL_NODE_TYPE(node) == IDLN_IDENT) + add_interface_maybe(node, scope, user_data); + + return TRUE; +} + +/* parse str and fill id */ +static gboolean +fill_iid(struct nsID *id, char *str) +{ + /* XXX parse! */ + memset(id, 0, sizeof(struct nsID)); + return TRUE; +} + +/* fill the interface_directory IDE table from the interface_map */ +static gboolean +fill_ide_table(gpointer key, gpointer value, gpointer user_data) +{ + TreeState *state = user_data; + char *interface = key, *iid = value; + struct nsID id = { + 0x00112233, + 0x4455, + 0x6677, + {0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} + }; + XPTInterfaceDirectoryEntry *ide; + +#if 0 + if (!fill_iid(&id, iid)) { + /* XXX report error */ + return FALSE; + } +#endif + + ide = &(HEADER(state)->interface_directory[IFACES(state)]); + if (!XPT_FillInterfaceDirectoryEntry(ide, &id, interface, NULL, NULL)) { + /* XXX report error */ + return FALSE;; + } + + IFACES(state)++; + if (iid) + free(iid); + return TRUE; +} + +/* sort the IDE block as per the typelib spec: IID order, unresolved first */ +static void +sort_ide_block(TreeState *state) +{ + XPTInterfaceDirectoryEntry *ide; + int i; + + /* XXX we should sort, but for now just enumerate */ + for (i = 0; i < IFACES(state); i++) { + ide = HEADER(state)->interface_directory + i; + g_hash_table_insert(IFACE_MAP(state), ide->name, (void *)(i + 1)); + } + + return; +} + +static gboolean +typelib_list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +pass_1(TreeState *state) +{ + gboolean ok = FALSE; + if (state->tree) { + state->priv = calloc(1, sizeof(struct priv_data)); + if (!state->priv) + return PR_FALSE; + IFACES(state) = 0; + IFACE_MAP(state) = g_hash_table_new(g_str_hash, g_str_equal); + if (!IFACE_MAP(state)) { + /* XXX report error */ + free(state->priv); + return FALSE; + } + + /* find all interfaces, top-level and referenced by others */ +#ifdef DEBUG_shaver + fprintf(stderr, "finding interfaces\n"); +#endif + IDL_tree_walk_in_order(state->tree, find_interfaces, state); +#ifdef DEBUG_shaver + fprintf(stderr, "found %d interfaces\n", IFACES(state)); +#endif + HEADER(state) = XPT_NewHeader(IFACES(state)); + HEADER(state)->annotations = + XPT_NewAnnotation(XPT_ANN_LAST | XPT_ANN_PRIVATE, + XPT_NewStringZ("xpidl 0.99.1"), + XPT_NewStringZ("I should put something here.")); + + /* fill IDEs from hash table */ + IFACES(state) = 0; +#ifdef DEBUG_shaver + fprintf(stderr, "filling IDE table\n"); +#endif + g_hash_table_foreach_remove(IFACE_MAP(state), fill_ide_table, state); + + /* sort the IDEs by IID order and store indices in the interface map */ + sort_ide_block(state); + + ok = TRUE; + } else { + /* write the typelib */ + char *data; + uint32 len, header_sz; + XPTState *xstate = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + XPTCursor curs, *cursor = &curs; +#ifdef DEBUG_shaver + fprintf(stderr, "writing the typelib\n"); +#endif + + header_sz = XPT_SizeOfHeaderBlock(HEADER(state)); + + if (!xstate || + !XPT_MakeCursor(xstate, XPT_HEADER, header_sz, cursor)) + goto destroy_header; + + if (!XPT_DoHeader(cursor, &HEADER(state))) + goto destroy; + + XPT_GetXDRData(xstate, XPT_HEADER, &data, &len); + fwrite(data, len, 1, state->file); + XPT_GetXDRData(xstate, XPT_DATA, &data, &len); + fwrite(data, len, 1, state->file); + + ok = TRUE; + + destroy: + XPT_DestroyXDRState(xstate); + destroy_header: + /* XXX XPT_DestroyHeader(HEADER(state)) */ + +#ifdef DEBUG_shaver + fprintf(stderr, "writing typelib was %ssuccessful\n", + ok ? "" : "not "); +#endif + } + + return ok; + +} + +static XPTInterfaceDirectoryEntry * +FindInterfaceByName(XPTInterfaceDirectoryEntry *ides, uint16 num_interfaces, + const char *name) +{ + int i; + for (i = 0; i < num_interfaces; i++) { + if (!strcmp(ides[i].name, name)) + return &ides[i]; + } + return NULL; +} + +static gboolean +typelib_interface(TreeState *state) +{ + IDL_tree iface = state->tree, iter; + char *name = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + XPTInterfaceDirectoryEntry *ide; + XPTInterfaceDescriptor *id; + uint16 parent_id = 0; + + ide = FindInterfaceByName(HEADER(state)->interface_directory, + HEADER(state)->num_interfaces, name); + if (!ide) { + fprintf(stderr, + "ERROR: didn't find interface %s in IDE block. Giving up.\n", + name); + return FALSE; + } + + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + char *parent; + if (IDL_LIST(iter).next) { + fprintf(stderr, "ERROR: more than one parent interface for %s\n", + name); + return FALSE; + } + parent = IDL_IDENT(IDL_LIST(iter).data).str; + parent_id = (uint16)(uint32)g_hash_table_lookup(IFACE_MAP(state), + parent); + if (!parent_id) { + fprintf(stderr, "ERROR: no index found for %s. Giving up.\n", + parent); + return FALSE; + } + } + + id = XPT_NewInterfaceDescriptor(parent_id, 0, 0); + if (!id) + return FALSE; + + CURRENT(state) = ide->interface_descriptor = id; + NEXT_METH(state) = 0; + + state->tree = IDL_INTERFACE(iface).body; + if (state->tree && !xpidl_process_node(state)) + return FALSE; + return TRUE; +} + +static gboolean +fill_pd_from_type(TreeState *state, XPTParamDescriptor *pd, uint8 flags, + IDL_tree type) +{ + IDL_tree up; + + pd->flags = flags; + if (type) { + switch (IDL_NODE_TYPE(type)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type).f_type; + switch(IDL_TYPE_INTEGER(type).f_type) { + case IDL_INTEGER_TYPE_SHORT: + pd->type.prefix.flags = sign ? TD_INT16 : TD_UINT16; + break; + case IDL_INTEGER_TYPE_LONG: + pd->type.prefix.flags = sign ? TD_INT32 : TD_UINT32; + break; + case IDL_INTEGER_TYPE_LONGLONG: + pd->type.prefix.flags = sign ? TD_INT64 : TD_UINT64; + break; + } + break; + } + case IDLN_TYPE_CHAR: + pd->type.prefix.flags = TD_CHAR; + break; + case IDLN_TYPE_WIDE_CHAR: + pd->type.prefix.flags = TD_WCHAR; + break; + case IDLN_TYPE_STRING: + pd->type.prefix.flags = TD_PSTRING; /* XXXshaver string-type? */ + break; + case IDLN_TYPE_WIDE_STRING: + pd->type.prefix.flags = TD_PWSTRING; + break; + case IDLN_TYPE_BOOLEAN: + pd->type.prefix.flags = TD_BOOL; + break; + case IDLN_NATIVE: + pd->type.prefix.flags = TD_VOID | XPT_TDP_POINTER; + break; + case IDLN_IDENT: + if (!(up = IDL_NODE_UP(type))) { + fprintf(stderr, "FATAL: orphan ident %s in param list\n", + IDL_IDENT(type).str); + return FALSE; + } + switch (IDL_NODE_TYPE(up)) { + case IDLN_INTERFACE: { + XPTInterfaceDirectoryEntry *ide, + *ides = HEADER(state)->interface_directory; + uint16 num_ifaces = HEADER(state)->num_interfaces; + char *className = IDL_IDENT(IDL_INTERFACE(up).ident).str; + + pd->type.prefix.flags = TD_INTERFACE_TYPE; + ide = FindInterfaceByName(ides, num_ifaces, className); + if (!ide || ide < ides || ide > ides + num_ifaces) { + fprintf(stderr, "FATAL: unknown iface %s in params\n", + className); + return FALSE; + } + pd->type.type.interface = ide - ides + 1; +#ifdef DEBUG_shaver + fprintf(stderr, "DBG: index %d for %s\n", + pd->type.type.interface, className); +#endif + break; + } + default: + fprintf(stderr, "Can't yet handle %s ident in param list\n", + IDL_NODE_TYPE_NAME(up)); + return FALSE; + } + break; + default: + fprintf(stderr, "Can't yet handle %s in param list\n", + IDL_NODE_TYPE_NAME(type)); + return FALSE; + } + } else { + pd->type.prefix.flags = TD_VOID; + } + + return TRUE; +} + +static gboolean +fill_pd_from_param(TreeState *state, XPTParamDescriptor *pd, IDL_tree tree) +{ + uint8 flags = 0; + + switch (IDL_PARAM_DCL(tree).attr) { + case IDL_PARAM_IN: + flags = XPT_PD_IN; + break; + case IDL_PARAM_OUT: + flags = XPT_PD_OUT; + break; + case IDL_PARAM_INOUT: + flags = XPT_PD_IN | XPT_PD_OUT; + break; + } + /* XXXshaver retval */ + + return fill_pd_from_type(state, pd, flags, + IDL_PARAM_DCL(tree).param_type_spec); +} + +static gboolean +typelib_op_dcl(TreeState *state) +{ + XPTInterfaceDescriptor *id = CURRENT(state); + XPTMethodDescriptor *meth; + struct _IDL_OP_DCL *op = &IDL_OP_DCL(state->tree); + IDL_tree iter; + uint16 num_args = 0; + uint8 op_flags = 0; + + if (!XPT_InterfaceDescriptorAddMethods(id, 1)) + return PR_FALSE; + + meth = &id->method_descriptors[NEXT_METH(state)]; + + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) + num_args++; /* count params */ + if (op->f_noscript) + op_flags |= XPT_MD_HIDDEN; + if (op->f_varargs) + op_flags |= XPT_MD_VARARGS; + /* XXXshaver constructor? */ + +#ifdef DEBUG_shaver + fprintf(stdout, "DBG: adding method %s (nargs %d)\n", + IDL_IDENT(op->ident).str, num_args); +#endif + if (!XPT_FillMethodDescriptor(meth, op_flags, IDL_IDENT(op->ident).str, + num_args)) + return PR_FALSE; + + for (num_args = 0, iter = op->parameter_dcls; iter; + iter = IDL_LIST(iter).next, num_args++) { + if (!fill_pd_from_param(state, &meth->params[num_args], + IDL_LIST(iter).data)) + return PR_FALSE; + } + + if (!fill_pd_from_type(state, meth->result, XPT_PD_RETVAL, + op->op_type_spec)) + return PR_FALSE; + + NEXT_METH(state)++; + return PR_TRUE; +} nodeHandler * xpidl_typelib_dispatch(void) @@ -30,8 +482,12 @@ xpidl_typelib_dispatch(void) static gboolean initialized = FALSE; if (!initialized) { - /* Initialize non-NULL elements */ - initialized = TRUE; + /* Initialize non-NULL elements */ + table[IDLN_NONE] = pass_1; + table[IDLN_LIST] = typelib_list; + table[IDLN_INTERFACE] = typelib_interface; + table[IDLN_OP_DCL] = typelib_op_dcl; + initialized = TRUE; } return table; diff --git a/xpcom/typelib/xpidl/Makefile.in b/xpcom/typelib/xpidl/Makefile.in index 42851701a0a..85f96d60893 100644 --- a/xpcom/typelib/xpidl/Makefile.in +++ b/xpcom/typelib/xpidl/Makefile.in @@ -39,7 +39,7 @@ include $(topsrcdir)/config/config.mk CFLAGS += $(shell glib-config --cflags) # XXX need configure test -EX_LIBS = -lIDL $(shell glib-config --libs) +EX_LIBS = -lIDL -L$(DIST)/bin -lxpt $(NSPR_LIBS) $(shell glib-config --libs) PROGS = $(OBJDIR)/xpidl diff --git a/xpcom/typelib/xpidl/xpidl.c b/xpcom/typelib/xpidl/xpidl.c index 36935db00bc..f54dd3c07b2 100644 --- a/xpcom/typelib/xpidl/xpidl.c +++ b/xpcom/typelib/xpidl/xpidl.c @@ -106,7 +106,7 @@ main(int argc, char *argv[]) break; switch (argv[i][1]) { case '-': - argc++; + argc++; /* pretend we didn't see this */ /* fall through */ case 0: /* - is a legal input filename (stdin) */ goto done_options; diff --git a/xpcom/typelib/xpidl/xpidl_header.c b/xpcom/typelib/xpidl/xpidl_header.c index 0e0797fdc12..dcd7fd3d498 100644 --- a/xpcom/typelib/xpidl/xpidl_header.c +++ b/xpcom/typelib/xpidl/xpidl_header.c @@ -123,13 +123,15 @@ interface(TreeState *state) } } fputs(" {\n" - " public: \n" - " static const nsIID& IID() {\n" - " static nsIID iid = ", - state->file); - if (!output_classname_iid_define(state->file, className)) - return FALSE; - fputs(";\n return iid;\n }\n", state->file); + " public: \n", state->file); + if (iid) { + fputs(" static const nsIID& IID() {\n" + " static nsIID iid = ", + state->file); + if (!output_classname_iid_define(state->file, className)) + return FALSE; + fputs(";\n return iid;\n }\n", state->file); + } state->tree = IDL_INTERFACE(iface).body; @@ -322,6 +324,20 @@ xpcom_param(TreeState *state) return TRUE; } +/* + * A forward declaration, usually an interface. + */ +static gboolean +forward_dcl(TreeState *state) +{ + IDL_tree iface = state->tree; + char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str; + if (!className) + return FALSE; + fprintf(state->file, "class %s; /* forward decl */\n", className); + return TRUE; +} + /* * A method is an `operation', therefore a method decl is an `op dcl'. * I blame Elliot. @@ -395,6 +411,7 @@ xpidl_header_dispatch(void) table[IDLN_LIST] = list; table[IDLN_ATTR_DCL] = attr_dcl; table[IDLN_OP_DCL] = op_dcl; + table[IDLN_FORWARD_DCL] = forward_dcl; table[IDLN_TYPE_ENUM] = do_enum; table[IDLN_INTERFACE] = interface; table[IDLN_CODEFRAG] = codefrag; diff --git a/xpcom/typelib/xpidl/xpidl_typelib.c b/xpcom/typelib/xpidl/xpidl_typelib.c index d594db4f871..22b65f6aa19 100644 --- a/xpcom/typelib/xpidl/xpidl_typelib.c +++ b/xpcom/typelib/xpidl/xpidl_typelib.c @@ -22,6 +22,458 @@ */ #include "xpidl.h" +#include +#include + +struct priv_data { + XPTHeader *header; + uint16 ifaces; + GHashTable *interface_map; + XPTInterfaceDescriptor *current; + uint16 next_method; +}; + +#define HEADER(state) (((struct priv_data *)state->priv)->header) +#define IFACES(state) (((struct priv_data *)state->priv)->ifaces) +#define IFACE_MAP(state) (((struct priv_data *)state->priv)->interface_map) +#define CURRENT(state) (((struct priv_data *)state->priv)->current) +#define NEXT_METH(state) (((struct priv_data *)state->priv)->next_method) + +/* + * If p is an ident for an interface, and we don't have an entry in the + * interface map yet, add one. + */ +static gboolean +add_interface_maybe(IDL_tree p, IDL_tree scope, gpointer user_data) +{ + TreeState *state = user_data; + IDL_tree up; + if (IDL_NODE_TYPE(p) == IDLN_IDENT) { + if ((IDL_NODE_TYPE((up = IDL_NODE_UP(p))) == IDLN_INTERFACE)) { + char *iface = IDL_IDENT(p).str; + if (!g_hash_table_lookup(IFACE_MAP(state), iface)) { + /* XXX should we parse here and store a struct nsID *? */ + char *iid = (char *)IDL_tree_property_get(up, "uuid"); + if (iid) + iid = strdup(iid); + g_hash_table_insert(IFACE_MAP(state), iface, iid); + IFACES(state)++; +#ifdef DEBUG_shaver + fprintf(stderr, "adding interface #%d: %s/%s\n", IFACES(state), + iface, iid ? iid : ""); +#endif + } + } else { +#ifdef DEBUG_shaver + fprintf(stderr, "ident %s isn't an interface (%s)\n", + IDL_IDENT(p).str, IDL_NODE_TYPE_NAME(up)); +#endif + } + } + + return PR_TRUE; +} + +/* Find all the interfaces referenced in the tree (uses add_interface_maybe) */ +static gboolean +find_interfaces(IDL_tree p, IDL_tree scope, gpointer user_data) +{ + IDL_tree node = NULL; + + switch (IDL_NODE_TYPE(p)) { + case IDLN_ATTR_DCL: + node = IDL_ATTR_DCL(p).param_type_spec; + break; + case IDLN_OP_DCL: + IDL_tree_walk_in_order(IDL_OP_DCL(p).parameter_dcls, find_interfaces, + user_data); + node = IDL_OP_DCL(p).op_type_spec; + break; + case IDLN_PARAM_DCL: + node = IDL_PARAM_DCL(p).param_type_spec; + break; + case IDLN_INTERFACE: + node = IDL_INTERFACE(p).inheritance_spec; + if (node) + xpidl_list_foreach(node, add_interface_maybe, user_data); + node = IDL_INTERFACE(p).ident; + break; + default: + node = NULL; + } + + if (node && IDL_NODE_TYPE(node) == IDLN_IDENT) + add_interface_maybe(node, scope, user_data); + + return TRUE; +} + +/* parse str and fill id */ +static gboolean +fill_iid(struct nsID *id, char *str) +{ + /* XXX parse! */ + memset(id, 0, sizeof(struct nsID)); + return TRUE; +} + +/* fill the interface_directory IDE table from the interface_map */ +static gboolean +fill_ide_table(gpointer key, gpointer value, gpointer user_data) +{ + TreeState *state = user_data; + char *interface = key, *iid = value; + struct nsID id = { + 0x00112233, + 0x4455, + 0x6677, + {0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} + }; + XPTInterfaceDirectoryEntry *ide; + +#if 0 + if (!fill_iid(&id, iid)) { + /* XXX report error */ + return FALSE; + } +#endif + + ide = &(HEADER(state)->interface_directory[IFACES(state)]); + if (!XPT_FillInterfaceDirectoryEntry(ide, &id, interface, NULL, NULL)) { + /* XXX report error */ + return FALSE;; + } + + IFACES(state)++; + if (iid) + free(iid); + return TRUE; +} + +/* sort the IDE block as per the typelib spec: IID order, unresolved first */ +static void +sort_ide_block(TreeState *state) +{ + XPTInterfaceDirectoryEntry *ide; + int i; + + /* XXX we should sort, but for now just enumerate */ + for (i = 0; i < IFACES(state); i++) { + ide = HEADER(state)->interface_directory + i; + g_hash_table_insert(IFACE_MAP(state), ide->name, (void *)(i + 1)); + } + + return; +} + +static gboolean +typelib_list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +pass_1(TreeState *state) +{ + gboolean ok = FALSE; + if (state->tree) { + state->priv = calloc(1, sizeof(struct priv_data)); + if (!state->priv) + return PR_FALSE; + IFACES(state) = 0; + IFACE_MAP(state) = g_hash_table_new(g_str_hash, g_str_equal); + if (!IFACE_MAP(state)) { + /* XXX report error */ + free(state->priv); + return FALSE; + } + + /* find all interfaces, top-level and referenced by others */ +#ifdef DEBUG_shaver + fprintf(stderr, "finding interfaces\n"); +#endif + IDL_tree_walk_in_order(state->tree, find_interfaces, state); +#ifdef DEBUG_shaver + fprintf(stderr, "found %d interfaces\n", IFACES(state)); +#endif + HEADER(state) = XPT_NewHeader(IFACES(state)); + HEADER(state)->annotations = + XPT_NewAnnotation(XPT_ANN_LAST | XPT_ANN_PRIVATE, + XPT_NewStringZ("xpidl 0.99.1"), + XPT_NewStringZ("I should put something here.")); + + /* fill IDEs from hash table */ + IFACES(state) = 0; +#ifdef DEBUG_shaver + fprintf(stderr, "filling IDE table\n"); +#endif + g_hash_table_foreach_remove(IFACE_MAP(state), fill_ide_table, state); + + /* sort the IDEs by IID order and store indices in the interface map */ + sort_ide_block(state); + + ok = TRUE; + } else { + /* write the typelib */ + char *data; + uint32 len, header_sz; + XPTState *xstate = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + XPTCursor curs, *cursor = &curs; +#ifdef DEBUG_shaver + fprintf(stderr, "writing the typelib\n"); +#endif + + header_sz = XPT_SizeOfHeaderBlock(HEADER(state)); + + if (!xstate || + !XPT_MakeCursor(xstate, XPT_HEADER, header_sz, cursor)) + goto destroy_header; + + if (!XPT_DoHeader(cursor, &HEADER(state))) + goto destroy; + + XPT_GetXDRData(xstate, XPT_HEADER, &data, &len); + fwrite(data, len, 1, state->file); + XPT_GetXDRData(xstate, XPT_DATA, &data, &len); + fwrite(data, len, 1, state->file); + + ok = TRUE; + + destroy: + XPT_DestroyXDRState(xstate); + destroy_header: + /* XXX XPT_DestroyHeader(HEADER(state)) */ + +#ifdef DEBUG_shaver + fprintf(stderr, "writing typelib was %ssuccessful\n", + ok ? "" : "not "); +#endif + } + + return ok; + +} + +static XPTInterfaceDirectoryEntry * +FindInterfaceByName(XPTInterfaceDirectoryEntry *ides, uint16 num_interfaces, + const char *name) +{ + int i; + for (i = 0; i < num_interfaces; i++) { + if (!strcmp(ides[i].name, name)) + return &ides[i]; + } + return NULL; +} + +static gboolean +typelib_interface(TreeState *state) +{ + IDL_tree iface = state->tree, iter; + char *name = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + XPTInterfaceDirectoryEntry *ide; + XPTInterfaceDescriptor *id; + uint16 parent_id = 0; + + ide = FindInterfaceByName(HEADER(state)->interface_directory, + HEADER(state)->num_interfaces, name); + if (!ide) { + fprintf(stderr, + "ERROR: didn't find interface %s in IDE block. Giving up.\n", + name); + return FALSE; + } + + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + char *parent; + if (IDL_LIST(iter).next) { + fprintf(stderr, "ERROR: more than one parent interface for %s\n", + name); + return FALSE; + } + parent = IDL_IDENT(IDL_LIST(iter).data).str; + parent_id = (uint16)(uint32)g_hash_table_lookup(IFACE_MAP(state), + parent); + if (!parent_id) { + fprintf(stderr, "ERROR: no index found for %s. Giving up.\n", + parent); + return FALSE; + } + } + + id = XPT_NewInterfaceDescriptor(parent_id, 0, 0); + if (!id) + return FALSE; + + CURRENT(state) = ide->interface_descriptor = id; + NEXT_METH(state) = 0; + + state->tree = IDL_INTERFACE(iface).body; + if (state->tree && !xpidl_process_node(state)) + return FALSE; + return TRUE; +} + +static gboolean +fill_pd_from_type(TreeState *state, XPTParamDescriptor *pd, uint8 flags, + IDL_tree type) +{ + IDL_tree up; + + pd->flags = flags; + if (type) { + switch (IDL_NODE_TYPE(type)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type).f_type; + switch(IDL_TYPE_INTEGER(type).f_type) { + case IDL_INTEGER_TYPE_SHORT: + pd->type.prefix.flags = sign ? TD_INT16 : TD_UINT16; + break; + case IDL_INTEGER_TYPE_LONG: + pd->type.prefix.flags = sign ? TD_INT32 : TD_UINT32; + break; + case IDL_INTEGER_TYPE_LONGLONG: + pd->type.prefix.flags = sign ? TD_INT64 : TD_UINT64; + break; + } + break; + } + case IDLN_TYPE_CHAR: + pd->type.prefix.flags = TD_CHAR; + break; + case IDLN_TYPE_WIDE_CHAR: + pd->type.prefix.flags = TD_WCHAR; + break; + case IDLN_TYPE_STRING: + pd->type.prefix.flags = TD_PSTRING; /* XXXshaver string-type? */ + break; + case IDLN_TYPE_WIDE_STRING: + pd->type.prefix.flags = TD_PWSTRING; + break; + case IDLN_TYPE_BOOLEAN: + pd->type.prefix.flags = TD_BOOL; + break; + case IDLN_NATIVE: + pd->type.prefix.flags = TD_VOID | XPT_TDP_POINTER; + break; + case IDLN_IDENT: + if (!(up = IDL_NODE_UP(type))) { + fprintf(stderr, "FATAL: orphan ident %s in param list\n", + IDL_IDENT(type).str); + return FALSE; + } + switch (IDL_NODE_TYPE(up)) { + case IDLN_INTERFACE: { + XPTInterfaceDirectoryEntry *ide, + *ides = HEADER(state)->interface_directory; + uint16 num_ifaces = HEADER(state)->num_interfaces; + char *className = IDL_IDENT(IDL_INTERFACE(up).ident).str; + + pd->type.prefix.flags = TD_INTERFACE_TYPE; + ide = FindInterfaceByName(ides, num_ifaces, className); + if (!ide || ide < ides || ide > ides + num_ifaces) { + fprintf(stderr, "FATAL: unknown iface %s in params\n", + className); + return FALSE; + } + pd->type.type.interface = ide - ides + 1; +#ifdef DEBUG_shaver + fprintf(stderr, "DBG: index %d for %s\n", + pd->type.type.interface, className); +#endif + break; + } + default: + fprintf(stderr, "Can't yet handle %s ident in param list\n", + IDL_NODE_TYPE_NAME(up)); + return FALSE; + } + break; + default: + fprintf(stderr, "Can't yet handle %s in param list\n", + IDL_NODE_TYPE_NAME(type)); + return FALSE; + } + } else { + pd->type.prefix.flags = TD_VOID; + } + + return TRUE; +} + +static gboolean +fill_pd_from_param(TreeState *state, XPTParamDescriptor *pd, IDL_tree tree) +{ + uint8 flags = 0; + + switch (IDL_PARAM_DCL(tree).attr) { + case IDL_PARAM_IN: + flags = XPT_PD_IN; + break; + case IDL_PARAM_OUT: + flags = XPT_PD_OUT; + break; + case IDL_PARAM_INOUT: + flags = XPT_PD_IN | XPT_PD_OUT; + break; + } + /* XXXshaver retval */ + + return fill_pd_from_type(state, pd, flags, + IDL_PARAM_DCL(tree).param_type_spec); +} + +static gboolean +typelib_op_dcl(TreeState *state) +{ + XPTInterfaceDescriptor *id = CURRENT(state); + XPTMethodDescriptor *meth; + struct _IDL_OP_DCL *op = &IDL_OP_DCL(state->tree); + IDL_tree iter; + uint16 num_args = 0; + uint8 op_flags = 0; + + if (!XPT_InterfaceDescriptorAddMethods(id, 1)) + return PR_FALSE; + + meth = &id->method_descriptors[NEXT_METH(state)]; + + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) + num_args++; /* count params */ + if (op->f_noscript) + op_flags |= XPT_MD_HIDDEN; + if (op->f_varargs) + op_flags |= XPT_MD_VARARGS; + /* XXXshaver constructor? */ + +#ifdef DEBUG_shaver + fprintf(stdout, "DBG: adding method %s (nargs %d)\n", + IDL_IDENT(op->ident).str, num_args); +#endif + if (!XPT_FillMethodDescriptor(meth, op_flags, IDL_IDENT(op->ident).str, + num_args)) + return PR_FALSE; + + for (num_args = 0, iter = op->parameter_dcls; iter; + iter = IDL_LIST(iter).next, num_args++) { + if (!fill_pd_from_param(state, &meth->params[num_args], + IDL_LIST(iter).data)) + return PR_FALSE; + } + + if (!fill_pd_from_type(state, meth->result, XPT_PD_RETVAL, + op->op_type_spec)) + return PR_FALSE; + + NEXT_METH(state)++; + return PR_TRUE; +} nodeHandler * xpidl_typelib_dispatch(void) @@ -30,8 +482,12 @@ xpidl_typelib_dispatch(void) static gboolean initialized = FALSE; if (!initialized) { - /* Initialize non-NULL elements */ - initialized = TRUE; + /* Initialize non-NULL elements */ + table[IDLN_NONE] = pass_1; + table[IDLN_LIST] = typelib_list; + table[IDLN_INTERFACE] = typelib_interface; + table[IDLN_OP_DCL] = typelib_op_dcl; + initialized = TRUE; } return table;