diff options
Diffstat (limited to 'girepository/gitypelib.c')
-rw-r--r-- | girepository/gitypelib.c | 241 |
1 files changed, 175 insertions, 66 deletions
diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c index 2af17e96..d88924a6 100644 --- a/girepository/gitypelib.c +++ b/girepository/gitypelib.c @@ -198,55 +198,17 @@ g_typelib_get_dir_entry_by_name (GITypelib *typelib, } DirEntry * -g_typelib_get_dir_entry_by_gtype (GITypelib *typelib, - gboolean fastpass, - GType gtype) +g_typelib_get_dir_entry_by_gtype_name (GITypelib *typelib, + const gchar *gtype_name) { Header *header = (Header *)typelib->data; - guint n_entries = header->n_local_entries; - const char *gtype_name = g_type_name (gtype); - DirEntry *entry; guint i; - const char *c_prefix; - - /* There is a corner case regarding GdkRectangle. GdkRectangle is a - boxed type, but it is just an alias to boxed struct - CairoRectangleInt. Scanner automatically converts all references - to GdkRectangle to CairoRectangleInt, so GdkRectangle does not - appear in the typelibs at all, although user code might query it. - So if we get such query, we also change it to lookup of - CairoRectangleInt. - https://bugzilla.gnome.org/show_bug.cgi?id=655423 */ - if (!fastpass && !strcmp (gtype_name, "GdkRectangle")) - gtype_name = "CairoRectangleInt"; - - /* Inside each typelib, we include the "C prefix" which acts as - * a namespace mechanism. For GtkTreeView, the C prefix is Gtk. - * Given the assumption that GTypes for a library also use the - * C prefix, we know we can skip examining a typelib if our - * target type does not have this typelib's C prefix. - * - * However, not every class library necessarily conforms to this, - * e.g. Clutter has Cogl inside it. So, we split this into two - * passes. First we try a lookup, skipping things which don't - * have the prefix. If that fails then we try a global lookup, - * ignoring the prefix. - * - * See http://bugzilla.gnome.org/show_bug.cgi?id=564016 - */ - c_prefix = g_typelib_get_string (typelib, header->c_prefix); - if (fastpass && c_prefix != NULL) - { - if (g_ascii_strncasecmp (c_prefix, gtype_name, strlen (c_prefix)) != 0) - return NULL; - } - for (i = 1; i <= n_entries; i++) + for (i = 1; i <= header->n_local_entries; i++) { RegisteredTypeBlob *blob; const char *type; - - entry = g_typelib_get_dir_entry (typelib, i); + DirEntry *entry = g_typelib_get_dir_entry (typelib, i); if (!BLOB_IS_REGISTERED_TYPE (entry)) continue; @@ -261,6 +223,110 @@ g_typelib_get_dir_entry_by_gtype (GITypelib *typelib, return NULL; } +typedef struct { + const char *s; + const char *separator; + gsize sep_len; + GString buf; +} StrSplitIter; + +static void +strsplit_iter_init (StrSplitIter *iter, + const char *s, + const char *separator) +{ + iter->s = s; + iter->separator = separator; + iter->sep_len = strlen (separator); + iter->buf.str = NULL; + iter->buf.len = 0; + iter->buf.allocated_len = 0; +} + +static gboolean +strsplit_iter_next (StrSplitIter *iter, + char **out_val) +{ + const char *s = iter->s; + const char *next; + gsize len; + + if (!s) + return FALSE; + next = strstr (s, iter->separator); + if (next) + { + iter->s = next + iter->sep_len; + len = next - s; + } + else + { + iter->s = NULL; + len = strlen (s); + } + if (len == 0) + { + *out_val = ""; + } + else + { + g_string_overwrite_len (&iter->buf, 0, s, (gssize)len); + *out_val = iter->buf.str; + } + return TRUE; +} + +static void +strsplit_iter_clear (StrSplitIter *iter) +{ + g_free (iter->buf.str); +} + +gboolean +g_typelib_matches_gtype_name_prefix (GITypelib *typelib, + const gchar *gtype_name) +{ + Header *header = (Header *)typelib->data; + const char *c_prefix; + gchar *prefix; + gboolean ret = FALSE; + StrSplitIter split_iter; + gsize gtype_name_len; + + c_prefix = g_typelib_get_string (typelib, header->c_prefix); + if (c_prefix == NULL || strlen (c_prefix) == 0) + return FALSE; + + gtype_name_len = strlen (gtype_name); + + /* c_prefix is a comma separated string of supported prefixes + * in the typelib. + * We match the specified gtype_name if the gtype_name starts + * with the prefix, and is followed by a capital letter. + * For example, a typelib offering the 'Gdk' prefix does match + * GdkX11Cursor, however a typelib offering the 'G' prefix does not. + */ + strsplit_iter_init (&split_iter, c_prefix, ","); + while (strsplit_iter_next (&split_iter, &prefix)) + { + size_t len = strlen (prefix); + + if (gtype_name_len < len) + continue; + + if (strncmp (prefix, gtype_name, len) != 0) + continue; + + if (g_ascii_isupper (gtype_name[len])) + { + ret = TRUE; + break; + } + } + strsplit_iter_clear (&split_iter); + return ret; +} + DirEntry * g_typelib_get_dir_entry_by_error_domain (GITypelib *typelib, GQuark error_domain) @@ -2062,6 +2128,72 @@ g_typelib_error_quark (void) return quark; } +static GSList *library_paths; + +/** + * g_irepository_prepend_library_path: + * @directory: (type filename): a single directory to scan for shared libraries + * + * Prepends @directory to the search path that is used to + * search shared libraries referenced by imported namespaces. + * Multiple calls to this function all contribute to the final + * list of paths. + * The list of paths is unique and shared for all #GIRepository + * instances across the process, but it doesn't affect namespaces + * imported before the call. + * + * If the library is not found in the directories configured + * in this way, loading will fall back to the system library + * path (ie. LD_LIBRARY_PATH and DT_RPATH in ELF systems). + * See the documentation of your dynamic linker for full details. + * + * Since: 1.35.8 + */ +void +g_irepository_prepend_library_path (const char *directory) +{ + library_paths = g_slist_prepend (library_paths, + g_strdup (directory)); +} + +/* Note on the GModule flags used by this function: + + * Glade's autoconnect feature and OpenGL's extension mechanism + * as used by Clutter rely on g_module_open(NULL) to work as a means of + * accessing the app's symbols. This keeps us from using + * G_MODULE_BIND_LOCAL. BIND_LOCAL may have other issues as well; + * in general libraries are not expecting multiple copies of + * themselves and are not expecting to be unloaded. So we just + * load modules globally for now. + */ +static GModule * +load_one_shared_library (const char *shlib) +{ + GSList *p; + GModule *m; + + if (!g_path_is_absolute (shlib)) + { + /* First try in configured library paths */ + for (p = library_paths; p; p = p->next) + { + char *path = g_build_filename (p->data, shlib, NULL); + + m = g_module_open (path, G_MODULE_BIND_LAZY); + + g_free (path); + if (m != NULL) + return m; + } + } + + /* Then try loading from standard paths */ + /* Do not attempt to fix up shlib to replace .la with .so: + it's done by GModule anyway. + */ + return g_module_open (shlib, G_MODULE_BIND_LAZY); +} + static void _g_typelib_do_dlopen (GITypelib *typelib) { @@ -2091,30 +2223,7 @@ _g_typelib_do_dlopen (GITypelib *typelib) { GModule *module; - /* Glade's autoconnect feature and OpenGL's extension mechanism - * as used by Clutter rely on g_module_open(NULL) to work as a means of - * accessing the app's symbols. This keeps us from using - * G_MODULE_BIND_LOCAL. BIND_LOCAL may have other issues as well; - * in general libraries are not expecting multiple copies of - * themselves and are not expecting to be unloaded. So we just - * load modules globally for now. - */ - - module = g_module_open (shlibs[i], G_MODULE_BIND_LAZY); - - if (module == NULL) - { - GString *shlib_full = g_string_new (shlibs[i]); - - module = g_module_open (shlib_full->str, G_MODULE_BIND_LAZY); - if (module == NULL) - { - g_string_overwrite (shlib_full, strlen (shlib_full->str)-2, SHLIB_SUFFIX); - module = g_module_open (shlib_full->str, G_MODULE_BIND_LAZY); - } - - g_string_free (shlib_full, TRUE); - } + module = load_one_shared_library (shlibs[i]); if (module == NULL) { |