diff --git a/ginfo.c b/ginfo.c index 4625e8504..e7d07dbb3 100644 --- a/ginfo.c +++ b/ginfo.c @@ -174,18 +174,14 @@ g_info_from_entry (GTypelib *typelib, result = g_irepository_find_by_name (repository, namespace, name); if (result == NULL) { - GIUnresolvedInfo *unresolved; - - unresolved = g_new0 (GIUnresolvedInfo, 1); - - unresolved->type = GI_INFO_TYPE_UNRESOLVED; - unresolved->ref_count = 1; - unresolved->container = NULL; - unresolved->name = name; - unresolved->namespace = namespace; - - result = (GIBaseInfo*)unresolved; + char **all_namespaces = g_irepository_get_namespaces (repository); + char *namespaces_str = g_strjoinv (", ", all_namespaces); + g_critical ("Failed to find namespace: %s name: %s (currently loaded namespaces: %s)", namespace, + name, namespaces_str); + g_strfreev (all_namespaces); + g_free (namespaces_str); } + return result; } return result; @@ -294,14 +290,6 @@ g_base_info_get_name (GIBaseInfo *info) } break; - case GI_INFO_TYPE_UNRESOLVED: - { - GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; - - return unresolved->name; - } - break; - case GI_INFO_TYPE_TYPE: default: ; g_assert_not_reached (); @@ -318,13 +306,6 @@ g_base_info_get_namespace (GIBaseInfo *info) g_assert (info->ref_count > 0); - if (info->type == GI_INFO_TYPE_UNRESOLVED) - { - GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; - - return unresolved->namespace; - } - return g_typelib_get_string (info->typelib, header->namespace); } diff --git a/girepository.c b/girepository.c index e87df1c3f..be8ddca33 100644 --- a/girepository.c +++ b/girepository.c @@ -30,12 +30,11 @@ static GStaticMutex globals_lock = G_STATIC_MUTEX_INIT; static GIRepository *default_repository = NULL; -static GHashTable *default_typelib = NULL; static GSList *search_path = NULL; struct _GIRepositoryPrivate { - GHashTable *typelib; /* (string) namespace -> GTypelib */ + GHashTable *typelibs; /* (string) namespace -> GTypelib */ }; G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT); @@ -52,7 +51,7 @@ g_irepository_finalize (GObject *object) { GIRepository *repository = G_IREPOSITORY (object); - g_hash_table_destroy (repository->priv->typelib); + g_hash_table_destroy (repository->priv->typelibs); (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository)); } @@ -77,11 +76,10 @@ init_globals () if (default_repository == NULL) { default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL); - if (default_typelib == NULL) - default_typelib = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) g_typelib_free); - default_repository->priv->typelib = default_typelib; + default_repository->priv->typelibs + = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) g_typelib_free); } if (search_path == NULL) @@ -102,6 +100,13 @@ init_globals () g_static_mutex_unlock (&globals_lock); } +void +g_irepository_prepend_search_path (const char *directory) +{ + init_globals (); + search_path = g_slist_prepend (search_path, g_strdup (directory)); +} + static char * build_typelib_key (const char *name, const char *source) { @@ -111,46 +116,79 @@ build_typelib_key (const char *name, const char *source) return g_string_free (str, FALSE); } -static const gchar * -register_internal (GIRepository *repository, - const char *source, - GTypelib *typelib) +static char ** +get_typelib_dependencies (GTypelib *typelib) { Header *header; - const gchar *name; - GHashTable *table; - GError *error = NULL; - - g_return_val_if_fail (typelib != NULL, NULL); - + const char *dependencies_glob; + header = (Header *)typelib->data; - g_return_val_if_fail (header != NULL, NULL); + if (header->dependencies == 0) + return NULL; + dependencies_glob = g_typelib_get_string (typelib, header->dependencies); + return g_strsplit (dependencies_glob, "|", 0); +} + +static GIRepository * +get_repository (GIRepository *repository) +{ if (repository != NULL) { - if (repository->priv->typelib == NULL) - repository->priv->typelib = g_hash_table_new_full (g_str_hash, g_str_equal, + if (repository->priv->typelibs == NULL) + repository->priv->typelibs = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) NULL, (GDestroyNotify) g_typelib_free); - table = repository->priv->typelib; + return repository; } else { init_globals (); - table = default_typelib; + return default_repository; } +} + +static const char * +register_internal (GIRepository *repository, + const char *source, + GTypelib *typelib, + GError **error) +{ + Header *header; + const gchar *name; + const char *dependencies_glob; + char **dependencies; + + g_return_val_if_fail (typelib != NULL, FALSE); + + header = (Header *)typelib->data; + + g_return_val_if_fail (header != NULL, FALSE); name = g_typelib_get_string (typelib, header->namespace); - if (g_hash_table_lookup (table, name)) + dependencies = get_typelib_dependencies (typelib); + if (dependencies != NULL) { - g_printerr ("typelib (%p) for '%s' already registered\n", - typelib, name); - - return NULL; + int i; + + for (i = 0; dependencies[i]; i++) + { + char *dependency = dependencies[i]; + + if (!g_irepository_require (repository, dependency, error)) + { + g_strfreev (dependencies); + return NULL; + } + } + g_strfreev (dependencies); } - g_hash_table_insert (table, build_typelib_key (name, source), (void *)typelib); + + g_assert (g_hash_table_lookup (repository->priv->typelibs, name) == NULL); + g_hash_table_insert (repository->priv->typelibs, + build_typelib_key (name, source), (void *)typelib); if (typelib->module == NULL) typelib->module = g_module_open (NULL, 0); @@ -158,28 +196,47 @@ register_internal (GIRepository *repository, return name; } -const gchar * -g_irepository_register (GIRepository *repository, - GTypelib *typelib) +char ** +g_irepository_get_dependencies (GIRepository *repository, + const char *namespace) { - return register_internal (repository, "", typelib); + GTypelib *typelib; + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + + typelib = g_hash_table_lookup (repository->priv->typelibs, namespace); + g_return_val_if_fail (typelib != NULL, NULL); + + return get_typelib_dependencies (typelib); +} + +const char * +g_irepository_load_typelib (GIRepository *repository, + GTypelib *typelib, + GError **error) +{ + Header *header; + const char *namespace; + + repository = get_repository (repository); + + header = (Header *) typelib->data; + namespace = g_typelib_get_string (typelib, header->namespace); + + if (g_hash_table_lookup (repository->priv->typelibs, namespace)) + return namespace; + return register_internal (repository, "", typelib, error); } void g_irepository_unregister (GIRepository *repository, const gchar *namespace) { - GHashTable *table; + repository = get_repository (repository); - if (repository != NULL) - table = repository->priv->typelib; - else - { - init_globals (); - table = default_typelib; - } - - if (!g_hash_table_remove (table, namespace)) + if (!g_hash_table_remove (repository->priv->typelibs, namespace)) { g_printerr ("namespace '%s' not registered\n", namespace); } @@ -189,24 +246,15 @@ gboolean g_irepository_is_registered (GIRepository *repository, const gchar *namespace) { - GHashTable *table; + repository = get_repository (repository); - if (repository != NULL) - table = repository->priv->typelib; - else - { - init_globals (); - table = default_typelib; - } - - return g_hash_table_lookup (table, namespace) != NULL; + return g_hash_table_lookup (repository->priv->typelibs, namespace) != NULL; } GIRepository * g_irepository_get_default (void) { - init_globals (); - return default_repository; + return get_repository (NULL); } static void @@ -225,19 +273,21 @@ g_irepository_get_n_infos (GIRepository *repository, const gchar *namespace) { gint n_interfaces = 0; + + repository = get_repository (repository); if (namespace) { GTypelib *typelib; - typelib = g_hash_table_lookup (repository->priv->typelib, namespace); + typelib = g_hash_table_lookup (repository->priv->typelibs, namespace); if (typelib) n_interfaces = ((Header *)typelib->data)->n_local_entries; } else { - g_hash_table_foreach (repository->priv->typelib, + g_hash_table_foreach (repository->priv->typelibs, count_interfaces, &n_interfaces); } @@ -323,6 +373,8 @@ g_irepository_get_info (GIRepository *repository, { IfaceData data; + repository = get_repository (repository); + data.name = NULL; data.type = NULL; data.index = index + 1; @@ -332,13 +384,13 @@ g_irepository_get_info (GIRepository *repository, { GTypelib *typelib; - typelib = g_hash_table_lookup (repository->priv->typelib, namespace); + typelib = g_hash_table_lookup (repository->priv->typelibs, namespace); if (typelib) find_interface ((void *)namespace, typelib, &data); } else - g_hash_table_foreach (repository->priv->typelib, find_interface, &data); + g_hash_table_foreach (repository->priv->typelibs, find_interface, &data); return data.iface; } @@ -349,12 +401,14 @@ g_irepository_find_by_gtype (GIRepository *repository, { IfaceData data; + repository = get_repository (repository); + data.name = NULL; data.type = g_type_name (type); data.index = -1; data.iface = NULL; - g_hash_table_foreach (repository->priv->typelib, find_interface, &data); + g_hash_table_foreach (repository->priv->typelibs, find_interface, &data); return data.iface; } @@ -377,6 +431,8 @@ g_irepository_find_by_name (GIRepository *repository, { IfaceData data; + repository = get_repository (repository); + data.name = name; data.type = NULL; data.index = -1; @@ -386,13 +442,13 @@ g_irepository_find_by_name (GIRepository *repository, { GTypelib *typelib; - typelib = g_hash_table_lookup (repository->priv->typelib, namespace); + typelib = g_hash_table_lookup (repository->priv->typelibs, namespace); if (typelib) find_interface ((void *)namespace, typelib, &data); } else - g_hash_table_foreach (repository->priv->typelib, find_interface, &data); + g_hash_table_foreach (repository->priv->typelibs, find_interface, &data); return data.iface; } @@ -424,7 +480,9 @@ g_irepository_get_namespaces (GIRepository *repository) gchar **names; gint i; - g_hash_table_foreach (repository->priv->typelib, collect_namespaces, &list); + repository = get_repository (repository); + + g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list); names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1)); i = 0; @@ -442,7 +500,9 @@ g_irepository_get_shared_library (GIRepository *repository, GTypelib *typelib; Header *header; - typelib = g_hash_table_lookup (repository->priv->typelib, namespace); + repository = get_repository (repository); + + typelib = g_hash_table_lookup (repository->priv->typelibs, namespace); if (!typelib) return NULL; header = (Header *) typelib->data; @@ -471,7 +531,9 @@ g_irepository_get_typelib_path (GIRepository *repository, { gpointer orig_key, value; - if (!g_hash_table_lookup_extended (repository->priv->typelib, namespace, + repository = get_repository (repository); + + if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace, &orig_key, &value)) return NULL; return ((char*)orig_key) + strlen ((char *) orig_key) + 1; @@ -488,9 +550,9 @@ g_irepository_get_typelib_path (GIRepository *repository, * search for a ".typelib" file using the repository search * path. * - * Returns: Namespace if successful, NULL otherwise + * Returns: %TRUE if successful, %NULL otherwise */ -const gchar * +gboolean g_irepository_require (GIRepository *repository, const gchar *namespace, GError **error) @@ -506,17 +568,12 @@ g_irepository_require (GIRepository *repository, guint32 shlib; GHashTable *table; - if (repository != NULL) - table = repository->priv->typelib; - else - { - init_globals (); - table = default_typelib; - } + repository = get_repository (repository); + table = repository->priv->typelibs; /* don't bother loading a namespace if already registered */ if (g_hash_table_lookup (table, namespace)) - return namespace; + return TRUE; fname = g_strconcat (namespace, ".typelib", NULL); @@ -544,7 +601,7 @@ g_irepository_require (GIRepository *repository, "namespace '%s' which doesn't match the file name", full_path, namespace, typelib_namespace); g_free (full_path); - return NULL; + return FALSE; } break; } @@ -556,14 +613,18 @@ g_irepository_require (GIRepository *repository, "Typelib file for namespace '%s' was not found in search" " path or could not be openened", namespace); g_free (full_path); - return NULL; + return FALSE; } g_free (fname); - g_hash_table_remove (table, namespace); - register_internal (repository, full_path, typelib); + if (!register_internal (repository, full_path, typelib, error)) + { + g_typelib_free (typelib); + g_free (full_path); + return FALSE; + } g_free (full_path); - return namespace; + return TRUE; } diff --git a/girepository.h b/girepository.h index 4c6801697..f3b1f4844 100644 --- a/girepository.h +++ b/girepository.h @@ -72,8 +72,10 @@ struct _GIRepositoryClass GType g_irepository_get_type (void) G_GNUC_CONST; GIRepository *g_irepository_get_default (void); -const gchar * g_irepository_register (GIRepository *repository, - GTypelib *typelib); +void g_irepository_prepend_search_path (const char *directory); +const char * g_irepository_load_typelib (GIRepository *repository, + GTypelib *typelib, + GError **error); void g_irepository_unregister (GIRepository *repository, const gchar *namespace); gboolean g_irepository_is_registered (GIRepository *repository, @@ -81,9 +83,11 @@ gboolean g_irepository_is_registered (GIRepository *repository, GIBaseInfo * g_irepository_find_by_name (GIRepository *repository, const gchar *namespace, const gchar *name); -const char * g_irepository_require (GIRepository *repository, +gboolean g_irepository_require (GIRepository *repository, const char *namespace, GError **error); +gchar ** g_irepository_get_dependencies (GIRepository *repository, + const char *namespace); gchar ** g_irepository_get_namespaces (GIRepository *repository); GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository, GType gtype); @@ -142,8 +146,7 @@ typedef enum GI_INFO_TYPE_PROPERTY, GI_INFO_TYPE_FIELD, GI_INFO_TYPE_ARG, - GI_INFO_TYPE_TYPE, - GI_INFO_TYPE_UNRESOLVED + GI_INFO_TYPE_TYPE } GIInfoType; diff --git a/girmodule.c b/girmodule.c index 1077a487f..65ee392d9 100644 --- a/girmodule.c +++ b/girmodule.c @@ -33,13 +33,14 @@ g_ir_module_new (const gchar *name, const gchar *shared_library) { GIrModule *module; - module = g_new (GIrModule, 1); + module = g_new0 (GIrModule, 1); module->name = g_strdup (name); if (shared_library) module->shared_library = g_strdup (shared_library); else module->shared_library = NULL; + module->dependencies = NULL; module->entries = NULL; return module; @@ -56,6 +57,7 @@ g_ir_module_free (GIrModule *module) g_ir_node_free ((GIrNode *)e->data); g_list_free (module->entries); + /* Don't free dependencies, we inherit that from the parser */ g_free (module); } @@ -77,18 +79,42 @@ g_ir_module_build_typelib (GIrModule *module, guint32 size, offset, offset2, old_offset; GHashTable *strings; GHashTable *types; + char *dependencies; guchar *data; header_size = ALIGN_VALUE (sizeof (Header), 4); n_local_entries = g_list_length (module->entries); + /* Serialize dependencies into one string; this is convenient + * and not a major change to the typelib format. */ + { + GString *dependencies_str = g_string_new (""); + GList *link; + for (link = module->dependencies; link; link = link->next) + { + const char *dependency = link->data; + if (!strcmp (dependency, module->name)) + continue; + g_string_append (dependencies_str, dependency); + if (link->next) + g_string_append_c (dependencies_str, '|'); + } + dependencies = g_string_free (dependencies_str, FALSE); + if (!dependencies[0]) + { + g_free (dependencies); + dependencies = NULL; + } + } + restart: init_stats (); strings = g_hash_table_new (g_str_hash, g_str_equal); types = g_hash_table_new (g_str_hash, g_str_equal); n_entries = g_list_length (module->entries); - g_message ("%d entries (%d local)\n", n_entries, n_local_entries); + g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries, + g_list_length (module->dependencies)); dir_size = n_entries * 12; size = header_size + dir_size; @@ -106,6 +132,8 @@ g_ir_module_build_typelib (GIrModule *module, size += strlen (module->name); if (module->shared_library) size += strlen (module->shared_library); + if (dependencies != NULL) + size += strlen (dependencies); g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n", size, header_size, dir_size, size - header_size - dir_size); @@ -122,6 +150,10 @@ g_ir_module_build_typelib (GIrModule *module, header->n_local_entries = n_local_entries; header->n_annotations = 0; header->annotations = 0; /* filled in later */ + if (dependencies != NULL) + header->dependencies = write_string (dependencies, strings, data, &header_size); + else + header->dependencies = 0; header->size = 0; /* filled in later */ header->namespace = write_string (module->name, strings, data, &header_size); header->shared_library = (module->shared_library? @@ -180,9 +212,11 @@ g_ir_module_build_typelib (GIrModule *module, if (node->type == G_IR_NODE_XREF) { + const char *namespace = ((GIrNodeXRef*)node)->namespace; + entry->blob_type = 0; entry->local = FALSE; - entry->offset = write_string (((GIrNodeXRef*)node)->namespace, strings, data, &offset2); + entry->offset = write_string (namespace, strings, data, &offset2); entry->name = write_string (node->name, strings, data, &offset2); } else diff --git a/girmodule.h b/girmodule.h index 67c6ef7a0..a4511e3b7 100644 --- a/girmodule.h +++ b/girmodule.h @@ -33,6 +33,7 @@ struct _GIrModule { gchar *name; gchar *shared_library; + GList *dependencies; GList *entries; }; diff --git a/girparser.c b/girparser.c index 77a2b60d7..267092c33 100644 --- a/girparser.c +++ b/girparser.c @@ -72,6 +72,7 @@ struct _ParseContext GList *modules; gboolean prefix_aliases; + GList *dependencies; GHashTable *aliases; const char *namespace; @@ -2188,6 +2189,9 @@ start_element_handler (GMarkupParseContext *context, if (!parse_include (context, ctx, name, error)) break; + ctx->dependencies = g_list_prepend (ctx->dependencies, g_strdup (name)); + + state_switch (ctx, STATE_INCLUDE); goto out; } @@ -2226,6 +2230,7 @@ start_element_handler (GMarkupParseContext *context, { ctx->current_module = g_ir_module_new (name, shared_library); ctx->modules = g_list_append (ctx->modules, ctx->current_module); + ctx->current_module->dependencies = ctx->dependencies; state_switch (ctx, STATE_NAMESPACE); goto out; @@ -2704,6 +2709,7 @@ g_ir_parse_string (const gchar *namespace, ctx.namespace = namespace; ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); ctx.type_depth = 0; + ctx.dependencies = NULL; ctx.current_module = NULL; context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL); diff --git a/gtypelib.c b/gtypelib.c index e889d6998..3940a329d 100644 --- a/gtypelib.c +++ b/gtypelib.c @@ -152,7 +152,7 @@ g_typelib_check_sanity (void) size_check_ok = FALSE; \ } - CHECK_SIZE (Header, 100); + CHECK_SIZE (Header, 104); CHECK_SIZE (DirEntry, 12); CHECK_SIZE (SimpleTypeBlob, 4); CHECK_SIZE (ArgBlob, 12); diff --git a/gtypelib.h b/gtypelib.h index 9213bbbb0..31c484db4 100644 --- a/gtypelib.h +++ b/gtypelib.h @@ -57,6 +57,8 @@ typedef struct guint32 n_annotations; guint32 annotations; + guint32 dependencies; + guint32 size; guint32 namespace; guint32 shared_library;