1 /* -*- Mode: C; c-file-style: "gnu"; -*- */
2 /* GObject introspection: Repository implementation
4 * Copyright (C) 2005 Matthias Clasen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
26 #include <glib/gprintf.h>
28 #include "girepository.h"
31 static GStaticMutex globals_lock = G_STATIC_MUTEX_INIT;
32 static GIRepository *default_repository = NULL;
33 static GHashTable *default_typelib = NULL;
34 static GSList *search_path = NULL;
36 struct _GIRepositoryPrivate
38 GHashTable *typelib; /* (string) namespace -> GTypelib */
41 G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT);
44 g_irepository_init (GIRepository *repository)
46 repository->priv = G_TYPE_INSTANCE_GET_PRIVATE (repository, G_TYPE_IREPOSITORY,
51 g_irepository_finalize (GObject *object)
53 GIRepository *repository = G_IREPOSITORY (object);
55 g_hash_table_destroy (repository->priv->typelib);
57 (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
61 g_irepository_class_init (GIRepositoryClass *class)
63 GObjectClass *gobject_class;
65 gobject_class = G_OBJECT_CLASS (class);
67 gobject_class->finalize = g_irepository_finalize;
69 g_type_class_add_private (class, sizeof (GIRepositoryPrivate));
75 g_static_mutex_lock (&globals_lock);
77 if (default_repository == NULL)
79 default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL);
80 if (default_typelib == NULL)
81 default_typelib = g_hash_table_new_full (g_str_hash, g_str_equal,
82 (GDestroyNotify) NULL,
83 (GDestroyNotify) g_typelib_free);
84 default_repository->priv->typelib = default_typelib;
87 if (search_path == NULL)
89 const gchar *const *datadirs;
90 const gchar *const *dir;
92 datadirs = g_get_system_data_dirs ();
95 for (dir = datadirs; *dir; dir++) {
96 char *path = g_build_filename (*dir, "gitypelibs", NULL);
97 search_path = g_slist_prepend (search_path, path);
99 search_path = g_slist_reverse (search_path);
102 g_static_mutex_unlock (&globals_lock);
106 build_typelib_key (const char *name, const char *source)
108 GString *str = g_string_new (name);
109 g_string_append_c (str, '\0');
110 g_string_append (str, source);
111 return g_string_free (str, FALSE);
115 register_internal (GIRepository *repository,
122 GError *error = NULL;
124 g_return_val_if_fail (typelib != NULL, NULL);
126 header = (Header *)typelib->data;
128 g_return_val_if_fail (header != NULL, NULL);
130 if (repository != NULL)
132 if (repository->priv->typelib == NULL)
133 repository->priv->typelib = g_hash_table_new_full (g_str_hash, g_str_equal,
134 (GDestroyNotify) NULL,
135 (GDestroyNotify) g_typelib_free);
136 table = repository->priv->typelib;
141 table = default_typelib;
144 name = g_typelib_get_string (typelib, header->namespace);
146 if (g_hash_table_lookup (table, name))
148 g_printerr ("typelib (%p) for '%s' already registered\n",
153 g_hash_table_insert (table, build_typelib_key (name, source), (void *)typelib);
155 if (typelib->module == NULL)
156 typelib->module = g_module_open (NULL, 0);
162 g_irepository_register (GIRepository *repository,
165 return register_internal (repository, "<builtin>", typelib);
169 g_irepository_unregister (GIRepository *repository,
170 const gchar *namespace)
174 if (repository != NULL)
175 table = repository->priv->typelib;
179 table = default_typelib;
182 if (!g_hash_table_remove (table, namespace))
184 g_printerr ("namespace '%s' not registered\n", namespace);
189 g_irepository_is_registered (GIRepository *repository,
190 const gchar *namespace)
194 if (repository != NULL)
195 table = repository->priv->typelib;
199 table = default_typelib;
202 return g_hash_table_lookup (table, namespace) != NULL;
206 g_irepository_get_default (void)
209 return default_repository;
213 count_interfaces (gpointer key,
217 guchar *typelib = ((GTypelib *) value)->data;
218 gint *n_interfaces = (gint *)data;
220 *n_interfaces += ((Header *)typelib)->n_local_entries;
224 g_irepository_get_n_infos (GIRepository *repository,
225 const gchar *namespace)
227 gint n_interfaces = 0;
233 typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
236 n_interfaces = ((Header *)typelib->data)->n_local_entries;
240 g_hash_table_foreach (repository->priv->typelib,
241 count_interfaces, &n_interfaces);
256 find_interface (gpointer key,
261 GTypelib *typelib = (GTypelib *)value;
262 IfaceData *iface_data = (IfaceData *)data;
271 n_entries = ((Header *)typelib->data)->n_local_entries;
273 if (iface_data->name)
275 for (i = 1; i <= n_entries; i++)
277 entry = g_typelib_get_dir_entry (typelib, i);
278 name = g_typelib_get_string (typelib, entry->name);
279 if (strcmp (name, iface_data->name) == 0)
286 else if (iface_data->type)
288 for (i = 1; i <= n_entries; i++)
290 entry = g_typelib_get_dir_entry (typelib, i);
291 if (entry->blob_type < 4)
294 offset = *(guint32*)&typelib->data[entry->offset + 8];
295 type = g_typelib_get_string (typelib, offset);
296 if (strcmp (type, iface_data->type) == 0)
303 else if (iface_data->index > n_entries)
304 iface_data->index -= n_entries;
305 else if (iface_data->index > 0)
307 index = iface_data->index;
308 iface_data->index = 0;
313 entry = g_typelib_get_dir_entry (typelib, index);
314 iface_data->iface = g_info_new (entry->blob_type, NULL,
315 typelib, entry->offset);
320 g_irepository_get_info (GIRepository *repository,
321 const gchar *namespace,
328 data.index = index + 1;
335 typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
338 find_interface ((void *)namespace, typelib, &data);
341 g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
347 g_irepository_find_by_gtype (GIRepository *repository,
353 data.type = g_type_name (type);
357 g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
363 * g_irepository_find_by_name
364 * @repository: A #GIRepository, may be %NULL for the default
365 * @namespace: Namespace to search in, may be %NULL for all
366 * @name: Name to find
368 * Searches for a particular name in one or all namespaces.
369 * See #g_irepository_require to load metadata for namespaces.
371 * Returns: #GIBaseInfo representing metadata about @name, or %NULL
374 g_irepository_find_by_name (GIRepository *repository,
375 const gchar *namespace,
389 typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
392 find_interface ((void *)namespace, typelib, &data);
395 g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
401 collect_namespaces (gpointer key,
407 *list = g_list_append (*list, key);
411 * g_irepository_get_namespaces
412 * @repository: A #GIRepository, may be %NULL for the default
414 * Return the list of currently known namespaces. Normally
415 * if you want a particular namespace, you should call
416 * #g_irepository_require to load it in.
418 * Returns: List of namespaces
421 g_irepository_get_namespaces (GIRepository *repository)
423 GList *l, *list = NULL;
427 g_hash_table_foreach (repository->priv->typelib, collect_namespaces, &list);
429 names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
431 for (l = list; l; l = l->next)
432 names[i++] = g_strdup (l->data);
439 g_irepository_get_shared_library (GIRepository *repository,
440 const gchar *namespace)
445 typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
448 header = (Header *) typelib->data;
449 if (header->shared_library)
450 return g_typelib_get_string (typelib, header->shared_library);
456 * g_irepository_get_typelib_path
457 * @repository: Repository, may be %NULL for the default
458 * @namespace: GI namespace to use, e.g. "Gtk"
460 * If namespace @namespace is loaded, return the full path to the
461 * .typelib file it was loaded from. If the typelib for
462 * namespace @namespace was included in a shared library, return
463 * the special string "<builtin>".
465 * Returns: Filesystem path (or <builtin>) if successful, %NULL otherwise
469 g_irepository_get_typelib_path (GIRepository *repository,
470 const gchar *namespace)
472 gpointer orig_key, value;
474 if (!g_hash_table_lookup_extended (repository->priv->typelib, namespace,
477 return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
481 * g_irepository_require
482 * @repository: Repository, may be %NULL for the default
483 * @namespace: GI namespace to use, e.g. "Gtk"
486 * Force the namespace @namespace to be loaded if it isn't
487 * already. If @namespace is not loaded, this function will
488 * search for a ".typelib" file using the repository search
491 * Returns: Namespace if successful, NULL otherwise
494 g_irepository_require (GIRepository *repository,
495 const gchar *namespace,
500 gchar *fname, *full_path;
502 GError *error1 = NULL;
503 GTypelib *typelib = NULL;
504 const gchar *typelib_namespace, *shlib_fname;
509 if (repository != NULL)
510 table = repository->priv->typelib;
514 table = default_typelib;
517 /* don't bother loading a namespace if already registered */
518 if (g_hash_table_lookup (table, namespace))
521 fname = g_strconcat (namespace, ".typelib", NULL);
523 for (ldir = search_path; ldir; ldir = ldir->next)
527 full_path = g_build_filename (ldir->data, fname, NULL);
528 mfile = g_mapped_file_new (full_path, FALSE, &error1);
531 g_clear_error (&error1);
535 typelib = g_typelib_new_from_mapped_file (mfile);
536 header = (Header *) typelib->data;
537 typelib_namespace = g_typelib_get_string (typelib, header->namespace);
539 if (strcmp (typelib_namespace, namespace) != 0)
541 g_set_error (error, G_IREPOSITORY_ERROR,
542 G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
543 "Typelib file %s for namespace '%s' contains "
544 "namespace '%s' which doesn't match the file name",
545 full_path, namespace, typelib_namespace);
554 g_set_error (error, G_IREPOSITORY_ERROR,
555 G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
556 "Typelib file for namespace '%s' was not found in search"
557 " path or could not be openened", namespace);
564 /* optionally load shared library and attach it to the typelib */
565 shlib = ((Header *) typelib->data)->shared_library;
568 gchar *resolved_shlib;
570 shlib_fname = g_typelib_get_string (typelib, shlib);
571 resolved_shlib = g_module_build_path (NULL, shlib_fname);
573 module = g_module_open (resolved_shlib,
574 G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL);
577 g_set_error (error, G_IREPOSITORY_ERROR,
578 G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
579 "Typelib for namespace '%s' references shared library "
580 "%s, but it could not be openened (%s)",
581 namespace, resolved_shlib, g_module_error ());
583 g_free (resolved_shlib);
586 g_free (resolved_shlib);
589 g_hash_table_remove (table, namespace);
590 register_internal (repository, full_path, typelib);
597 g_irepository_error_quark (void)
599 static GQuark quark = 0;
601 quark = g_quark_from_static_string ("g-irepository-error-quark");
606 g_type_tag_to_string (GITypeTag type)
610 case GI_TYPE_TAG_VOID:
612 case GI_TYPE_TAG_BOOLEAN:
614 case GI_TYPE_TAG_INT8:
616 case GI_TYPE_TAG_UINT8:
618 case GI_TYPE_TAG_INT16:
620 case GI_TYPE_TAG_UINT16:
622 case GI_TYPE_TAG_INT32:
624 case GI_TYPE_TAG_UINT32:
626 case GI_TYPE_TAG_INT64:
628 case GI_TYPE_TAG_UINT64:
630 case GI_TYPE_TAG_INT:
632 case GI_TYPE_TAG_UINT:
634 case GI_TYPE_TAG_LONG:
636 case GI_TYPE_TAG_ULONG:
638 case GI_TYPE_TAG_SSIZE:
640 case GI_TYPE_TAG_SIZE:
642 case GI_TYPE_TAG_FLOAT:
644 case GI_TYPE_TAG_DOUBLE:
646 case GI_TYPE_TAG_UTF8:
648 case GI_TYPE_TAG_FILENAME:
650 case GI_TYPE_TAG_ARRAY:
652 case GI_TYPE_TAG_INTERFACE:
654 case GI_TYPE_TAG_GLIST:
656 case GI_TYPE_TAG_GSLIST:
658 case GI_TYPE_TAG_GHASH:
660 case GI_TYPE_TAG_ERROR: