From 6d9212674a314eb3886498c18c7dd49bdcf27f26 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Tue, 11 Nov 2008 00:48:17 +0000 Subject: [PATCH] Bug 560250 - Fully parse included modules For some things, like computing structure offsets to put into the typelib we need more than just the aliases from included modules. Do a completel parse of included modules and store in module->included_modules. Also add g_ir_find_node() to find node information from within the active set of modules and their includes. svn path=/trunk/; revision=874 --- girmodule.c | 4 +++ girmodule.h | 1 + girnode.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ girnode.h | 8 +++++ girparser.c | 100 ++++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 177 insertions(+), 22 deletions(-) diff --git a/girmodule.c b/girmodule.c index d7ca37bff..91cc02d8a 100644 --- a/girmodule.c +++ b/girmodule.c @@ -62,6 +62,10 @@ g_ir_module_free (GIrModule *module) g_list_free (module->entries); /* Don't free dependencies, we inherit that from the parser */ + /* FIXME: we leak the included modules themelves; they may be shared + * between multiple modules, so we would need refcounting */ + g_list_free (module->include_modules); + g_free (module); } diff --git a/girmodule.h b/girmodule.h index 56c7d4681..5008c4e97 100644 --- a/girmodule.h +++ b/girmodule.h @@ -36,6 +36,7 @@ struct _GIrModule gchar *shared_library; GList *dependencies; GList *entries; + GList *include_modules; }; GIrModule *g_ir_module_new (const gchar *name, diff --git a/girnode.c b/girnode.c index 632d5c349..b7f0cb275 100644 --- a/girnode.c +++ b/girnode.c @@ -1070,6 +1070,92 @@ find_entry (GIrModule *module, return idx; } +static GIrNode * +find_name_in_module (GIrModule *module, + const gchar *name) +{ + GList *l; + + for (l = module->entries; l; l = l->next) + { + GIrNode *node = (GIrNode *)l->data; + + if (strcmp (node->name, name) == 0) + return node; + } + + return NULL; +} + +gboolean +g_ir_find_node (GIrModule *module, + GList *modules, + const char *name, + GIrNode **node_out, + GIrModule **module_out) +{ + char **names = g_strsplit (name, ".", 0); + gint n_names = g_strv_length (names); + GIrNode *node = NULL; + GList *l; + + if (n_names == 0) + { + g_warning ("Name can't be empty"); + goto out; + } + + if (n_names > 2) + { + g_warning ("Too many name parts in '%s'", name); + goto out; + } + + if (n_names == 1) + { + *module_out = module; + node = find_name_in_module (module, names[0]); + } + else if (strcmp (names[0], module->name) == 0) + { + *module_out = module; + node = find_name_in_module (module, names[1]); + } + else + { + for (l = module->include_modules; l; l = l->next) + { + GIrModule *m = l->data; + + if (strcmp (names[0], m->name) == 0) + { + *module_out = m; + node = find_name_in_module (m, names[1]); + goto out; + } + } + + for (l = modules; l; l = l->next) + { + GIrModule *m = l->data; + + if (strcmp (names[0], m->name) == 0) + { + *module_out = m; + node = find_name_in_module (m, names[1]); + goto out; + } + } + } + + out: + g_strfreev (names); + + *node_out = node; + + return node != NULL; +} + static void serialize_type (GIrModule *module, GList *modules, diff --git a/girnode.h b/girnode.h index a0dd9ee07..bc24a11c6 100644 --- a/girnode.h +++ b/girnode.h @@ -23,6 +23,8 @@ #include +#include "girmodule.h" + G_BEGIN_DECLS typedef struct _GIrNode GIrNode; @@ -340,6 +342,12 @@ guint32 write_string (const gchar *str, const gchar * g_ir_node_param_direction_string (GIrNodeParam * node); const gchar * g_ir_node_type_to_string (GIrNodeTypeId type); +gboolean g_ir_find_node (GIrModule *module, + GList *modules, + const char *name, + GIrNode **node_out, + GIrModule **module_out); + G_END_DECLS #endif /* __G_IR_NODE_H__ */ diff --git a/girparser.c b/girparser.c index 50085c4cd..9221bb5d6 100644 --- a/girparser.c +++ b/girparser.c @@ -72,6 +72,7 @@ struct _ParseContext const char * const*includes; GList *modules; + GList *include_modules; gboolean prefix_aliases; GList *dependencies; GHashTable *aliases; @@ -87,6 +88,34 @@ struct _ParseContext int type_depth; }; +static void start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error); +static void end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error); +static void text_handler (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error); +static void cleanup (GMarkupParseContext *context, + GError *error, + gpointer user_data); + +static GMarkupParser parser = +{ + start_element_handler, + end_element_handler, + text_handler, + NULL, + cleanup +}; + static gboolean start_alias (GMarkupParseContext *context, const gchar *element_name, @@ -2116,7 +2145,31 @@ parse_include (GMarkupParseContext *context, gchar *buffer; gsize length; char *girpath; - + gboolean success = FALSE; + GList *l; + + for (l = ctx->include_modules; l; l = l->next) + { + GIrModule *m = l->data; + + if (strcmp (m->name, name) == 0) + { + if (strcmp (m->version, version) == 0) + { + return TRUE; + } + else + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Module '%s' imported with conflicting versions '%s' and '%s'", + name, m->version, version); + return FALSE; + } + } + } + girpath = locate_gir (name, version, ctx->includes); if (girpath == NULL) @@ -2147,21 +2200,32 @@ parse_include (GMarkupParseContext *context, sub_ctx.type_depth = 0; context = g_markup_parse_context_new (&firstpass_parser, 0, &sub_ctx, NULL); - + if (!g_markup_parse_context_parse (context, buffer, length, error)) - { - g_free (buffer); - return FALSE; - } - + goto out; + if (!g_markup_parse_context_end_parse (context, error)) - { - g_free (buffer); - return FALSE; - } - + goto out; + g_markup_parse_context_free (context); - return TRUE; + + context = g_markup_parse_context_new (&parser, 0, &sub_ctx, NULL); + if (!g_markup_parse_context_parse (context, buffer, length, error)) + goto out; + + if (!g_markup_parse_context_end_parse (context, error)) + goto out; + + success = TRUE; + + out: + ctx->include_modules = g_list_concat (ctx->include_modules, + sub_ctx.modules); + + g_markup_parse_context_free (context); + g_free (buffer); + + return success; } extern GLogLevelFlags logged_levels; @@ -2358,6 +2422,7 @@ start_element_handler (GMarkupParseContext *context, ctx->current_module = g_ir_module_new (name, version, shared_library); ctx->modules = g_list_append (ctx->modules, ctx->current_module); ctx->current_module->dependencies = ctx->dependencies; + ctx->current_module->include_modules = g_list_copy (ctx->include_modules); state_switch (ctx, STATE_NAMESPACE); goto out; @@ -2819,15 +2884,6 @@ cleanup (GMarkupParseContext *context, ctx->current_module = NULL; } -static GMarkupParser parser = -{ - start_element_handler, - end_element_handler, - text_handler, - NULL, - cleanup -}; - static GList * post_filter_varargs_functions (GList *list) {