Imported Upstream version 1.49.1
[platform/upstream/gobject-introspection.git] / girepository / girepository.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  * GObject introspection: Repository implementation
3  *
4  * Copyright (C) 2005 Matthias Clasen
5  * Copyright (C) 2008 Colin Walters <walters@verbum.org>
6  * Copyright (C) 2008 Red Hat, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include <glib.h>
31 #include <glib/gprintf.h>
32 #include <gmodule.h>
33 #include "girepository.h"
34 #include "gitypelib-internal.h"
35 #include "girepository-private.h"
36
37 /**
38  * SECTION:girepository
39  * @short_description: GObject Introspection repository manager
40  * @include: girepository.h
41  *
42  * #GIRepository is used to manage repositories of namespaces. Namespaces
43  * are represented on disk by type libraries (.typelib files).
44  */
45
46
47 static GIRepository *default_repository = NULL;
48 static GSList *search_path = NULL;
49
50 struct _GIRepositoryPrivate
51 {
52   GHashTable *typelibs; /* (string) namespace -> GITypelib */
53   GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */
54   GHashTable *info_by_gtype; /* GType -> GIBaseInfo */
55   GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */
56 };
57
58 G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT);
59
60 #ifdef G_PLATFORM_WIN32
61
62 #include <windows.h>
63
64 static HMODULE girepository_dll = NULL;
65
66 #ifdef DLL_EXPORT
67
68 BOOL WINAPI
69 DllMain (HINSTANCE hinstDLL,
70          DWORD     fdwReason,
71          LPVOID    lpvReserved)
72 {
73   if (fdwReason == DLL_PROCESS_ATTACH)
74       girepository_dll = hinstDLL;
75
76   return TRUE;
77 }
78
79 #endif
80
81 #undef GOBJECT_INTROSPECTION_LIBDIR
82
83 /* GOBJECT_INTROSPECTION_LIBDIR is used only in code called just once,
84  * so no problem leaking this
85  */
86 #define GOBJECT_INTROSPECTION_LIBDIR \
87   g_build_filename (g_win32_get_package_installation_directory_of_module (girepository_dll), \
88                     "lib", \
89                     NULL)
90
91 #endif
92
93 static void
94 g_irepository_init (GIRepository *repository)
95 {
96   repository->priv = G_TYPE_INSTANCE_GET_PRIVATE (repository, G_TYPE_IREPOSITORY,
97                                                   GIRepositoryPrivate);
98   repository->priv->typelibs
99     = g_hash_table_new_full (g_str_hash, g_str_equal,
100                              (GDestroyNotify) NULL,
101                              (GDestroyNotify) g_typelib_free);
102   repository->priv->lazy_typelibs
103     = g_hash_table_new_full (g_str_hash, g_str_equal,
104                              (GDestroyNotify) g_free,
105                              (GDestroyNotify) NULL);
106   repository->priv->info_by_gtype
107     = g_hash_table_new_full (g_direct_hash, g_direct_equal,
108                              (GDestroyNotify) NULL,
109                              (GDestroyNotify) g_base_info_unref);
110   repository->priv->info_by_error_domain
111     = g_hash_table_new_full (g_direct_hash, g_direct_equal,
112                              (GDestroyNotify) NULL,
113                              (GDestroyNotify) g_base_info_unref);
114 }
115
116 static void
117 g_irepository_finalize (GObject *object)
118 {
119   GIRepository *repository = G_IREPOSITORY (object);
120
121   g_hash_table_destroy (repository->priv->typelibs);
122   g_hash_table_destroy (repository->priv->lazy_typelibs);
123   g_hash_table_destroy (repository->priv->info_by_gtype);
124   g_hash_table_destroy (repository->priv->info_by_error_domain);
125
126   (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
127 }
128
129 static void
130 g_irepository_class_init (GIRepositoryClass *class)
131 {
132   GObjectClass *gobject_class;
133
134   gobject_class = G_OBJECT_CLASS (class);
135
136   gobject_class->finalize = g_irepository_finalize;
137
138   g_type_class_add_private (class, sizeof (GIRepositoryPrivate));
139 }
140
141 static void
142 init_globals (void)
143 {
144   static gsize initialized = 0;
145
146   if (!g_once_init_enter (&initialized))
147     return;
148
149   if (default_repository == NULL)
150     default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL);
151
152   if (search_path == NULL)
153     {
154       const char *libdir;
155       char *typelib_dir;
156       const gchar *type_lib_path_env;
157
158       /* This variable is intended to take precedence over both:
159        *   - the default search path;
160        *   - all g_irepository_prepend_search_path() calls.
161        */
162       type_lib_path_env = g_getenv ("GI_TYPELIB_PATH");
163
164       search_path = NULL;
165       if (type_lib_path_env)
166         {
167           gchar **custom_dirs;
168           gchar **d;
169
170           custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0);
171
172           d = custom_dirs;
173           while (*d)
174             {
175               search_path = g_slist_prepend (search_path, *d);
176               d++;
177             }
178
179           /* ownership of the array content was passed to the list */
180           g_free (custom_dirs);
181         }
182
183       libdir = GOBJECT_INTROSPECTION_LIBDIR;
184
185       typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL);
186
187       search_path = g_slist_prepend (search_path, typelib_dir);
188
189       search_path = g_slist_reverse (search_path);
190     }
191
192   g_once_init_leave (&initialized, 1);
193 }
194
195 /**
196  * g_irepository_prepend_search_path:
197  * @directory: (type filename): directory name to prepend to the typelib
198  *   search path
199  *
200  * Prepends @directory to the typelib search path.
201  * See g_irepository_get_search_path().
202  */
203 void
204 g_irepository_prepend_search_path (const char *directory)
205 {
206   init_globals ();
207   search_path = g_slist_prepend (search_path, g_strdup (directory));
208 }
209
210 /**
211  * g_irepository_get_search_path:
212  *
213  * Returns the current search path #GIRepository will use when loading
214  * typelib files. The list is internal to #GIRespository and should not
215  * be freed, nor should its string elements.
216  *
217  * Returns: (element-type filename) (transfer none): #GSList of strings
218  */
219 GSList *
220 g_irepository_get_search_path (void)
221 {
222   return search_path;
223 }
224
225 static char *
226 build_typelib_key (const char *name, const char *source)
227 {
228   GString *str = g_string_new (name);
229   g_string_append_c (str, '\0');
230   g_string_append (str, source);
231   return g_string_free (str, FALSE);
232 }
233
234 /* Note: Returns %NULL (not an empty %NULL-terminated array) if there are no
235  * dependencies. */
236 static char **
237 get_typelib_dependencies (GITypelib *typelib)
238 {
239   Header *header;
240   const char *dependencies_glob;
241
242   header = (Header *)typelib->data;
243
244   if (header->dependencies == 0)
245     return NULL;
246
247   dependencies_glob = g_typelib_get_string (typelib, header->dependencies);
248   return g_strsplit (dependencies_glob, "|", 0);
249 }
250
251 static GIRepository *
252 get_repository (GIRepository *repository)
253 {
254   init_globals ();
255
256   if (repository != NULL)
257     return repository;
258   else
259     return default_repository;
260 }
261
262 static GITypelib *
263 check_version_conflict (GITypelib *typelib,
264                         const gchar *namespace,
265                         const gchar *expected_version,
266                         char       **version_conflict)
267 {
268   Header *header;
269   const char *loaded_version;
270
271   if (expected_version == NULL)
272     {
273       if (version_conflict)
274         *version_conflict = NULL;
275       return typelib;
276     }
277
278   header = (Header*)typelib->data;
279   loaded_version = g_typelib_get_string (typelib, header->nsversion);
280   g_assert (loaded_version != NULL);
281
282   if (strcmp (expected_version, loaded_version) != 0)
283     {
284       if (version_conflict)
285         *version_conflict = (char*)loaded_version;
286       return NULL;
287     }
288   if (version_conflict)
289     *version_conflict = NULL;
290   return typelib;
291 }
292
293 static GITypelib *
294 get_registered_status (GIRepository *repository,
295                        const char   *namespace,
296                        const char   *version,
297                        gboolean      allow_lazy,
298                        gboolean     *lazy_status,
299                        char        **version_conflict)
300 {
301   GITypelib *typelib;
302   repository = get_repository (repository);
303   if (lazy_status)
304     *lazy_status = FALSE;
305   typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
306   if (typelib)
307     return check_version_conflict (typelib, namespace, version, version_conflict);
308   typelib = g_hash_table_lookup (repository->priv->lazy_typelibs, namespace);
309   if (!typelib)
310     return NULL;
311   if (lazy_status)
312     *lazy_status = TRUE;
313   if (!allow_lazy)
314     return NULL;
315   return check_version_conflict (typelib, namespace, version, version_conflict);
316 }
317
318 static GITypelib *
319 get_registered (GIRepository *repository,
320                 const char   *namespace,
321                 const char   *version)
322 {
323   return get_registered_status (repository, namespace, version, TRUE, NULL, NULL);
324 }
325
326 static gboolean
327 load_dependencies_recurse (GIRepository *repository,
328                            GITypelib     *typelib,
329                            GError      **error)
330 {
331   char **dependencies;
332
333   dependencies = get_typelib_dependencies (typelib);
334
335   if (dependencies != NULL)
336     {
337       int i;
338
339       for (i = 0; dependencies[i]; i++)
340         {
341           char *dependency = dependencies[i];
342           const char *last_dash;
343           char *dependency_namespace;
344           const char *dependency_version;
345
346           last_dash = strrchr (dependency, '-');
347           dependency_namespace = g_strndup (dependency, last_dash - dependency);
348           dependency_version = last_dash+1;
349
350           if (!g_irepository_require (repository, dependency_namespace, dependency_version,
351                                       0, error))
352             {
353               g_free (dependency_namespace);
354               g_strfreev (dependencies);
355               return FALSE;
356             }
357           g_free (dependency_namespace);
358         }
359       g_strfreev (dependencies);
360     }
361   return TRUE;
362 }
363
364 static const char *
365 register_internal (GIRepository *repository,
366                    const char   *source,
367                    gboolean      lazy,
368                    GITypelib     *typelib,
369                    GError      **error)
370 {
371   Header *header;
372   const gchar *namespace;
373
374   g_return_val_if_fail (typelib != NULL, FALSE);
375
376   header = (Header *)typelib->data;
377
378   g_return_val_if_fail (header != NULL, FALSE);
379
380   namespace = g_typelib_get_string (typelib, header->namespace);
381
382   if (lazy)
383     {
384       g_assert (!g_hash_table_lookup (repository->priv->lazy_typelibs,
385                                       namespace));
386       g_hash_table_insert (repository->priv->lazy_typelibs,
387                            build_typelib_key (namespace, source), (void *)typelib);
388     }
389   else
390     {
391       gpointer value;
392       char *key;
393
394       /* First, try loading all the dependencies */
395       if (!load_dependencies_recurse (repository, typelib, error))
396         return NULL;
397
398       /* Check if we are transitioning from lazily loaded state */
399       if (g_hash_table_lookup_extended (repository->priv->lazy_typelibs,
400                                         namespace,
401                                         (gpointer)&key, &value))
402         g_hash_table_remove (repository->priv->lazy_typelibs, key);
403       else
404         key = build_typelib_key (namespace, source);
405
406       g_hash_table_insert (repository->priv->typelibs, key, (void *)typelib);
407     }
408
409   return namespace;
410 }
411
412 /**
413  * g_irepository_get_immediate_dependencies:
414  * @repository: (nullable): A #GIRepository or %NULL for the singleton
415  *   process-global default #GIRepository
416  * @namespace_: Namespace of interest
417  *
418  * Return an array of the immediate versioned dependencies for @namespace_.
419  * Returned strings are of the form <code>namespace-version</code>.
420  *
421  * Note: @namespace_ must have already been loaded using a function
422  * such as g_irepository_require() before calling this function.
423  *
424  * To get the transitive closure of dependencies for @namespace_, use
425  * g_irepository_get_dependencies().
426  *
427  * Returns: (transfer full): Zero-terminated string array of immediate versioned
428  *   dependencies
429  *
430  * Since: 1.44
431  */
432 char **
433 g_irepository_get_immediate_dependencies (GIRepository *repository,
434                                           const char   *namespace)
435 {
436   GITypelib *typelib;
437   gchar **deps;
438
439   g_return_val_if_fail (namespace != NULL, NULL);
440
441   repository = get_repository (repository);
442
443   typelib = get_registered (repository, namespace, NULL);
444   g_return_val_if_fail (typelib != NULL, NULL);
445
446   /* Ensure we always return a non-%NULL vector. */
447   deps = get_typelib_dependencies (typelib);
448   if (deps == NULL)
449       deps = g_strsplit ("", "|", 0);
450
451   return deps;
452 }
453
454 /* Load the transitive closure of dependency namespace-version strings for the
455  * given @typelib. @repository must be non-%NULL. @transitive_dependencies must
456  * be a pre-existing GHashTable<owned utf8, owned utf8> set for storing the
457  * dependencies. */
458 static void
459 get_typelib_dependencies_transitive (GIRepository *repository,
460                                      GITypelib    *typelib,
461                                      GHashTable   *transitive_dependencies)
462 {
463   gchar **immediate_dependencies;
464   guint i;
465
466   immediate_dependencies = get_typelib_dependencies (typelib);
467
468   for (i = 0; immediate_dependencies != NULL && immediate_dependencies[i]; i++)
469     {
470       gchar *dependency;
471       const gchar *last_dash;
472       gchar *dependency_namespace;
473
474       dependency = immediate_dependencies[i];
475
476       /* Steal from the strv. */
477       g_hash_table_add (transitive_dependencies, dependency);
478       immediate_dependencies[i] = NULL;
479
480       /* Recurse for this namespace. */
481       last_dash = strrchr (dependency, '-');
482       dependency_namespace = g_strndup (dependency, last_dash - dependency);
483
484       typelib = get_registered (repository, dependency_namespace, NULL);
485       g_return_if_fail (typelib != NULL);
486       get_typelib_dependencies_transitive (repository, typelib,
487                                            transitive_dependencies);
488
489       g_free (dependency_namespace);
490     }
491
492   g_free (immediate_dependencies);
493 }
494
495 /**
496  * g_irepository_get_dependencies:
497  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
498  *   process-global default #GIRepository
499  * @namespace_: Namespace of interest
500  *
501  * Return an array of all (transitive) versioned dependencies for
502  * @namespace_. Returned strings are of the form
503  * <code>namespace-version</code>.
504  *
505  * Note: @namespace_ must have already been loaded using a function
506  * such as g_irepository_require() before calling this function.
507  *
508  * To get only the immediate dependencies for @namespace_, use
509  * g_irepository_get_immediate_dependencies().
510  *
511  * Returns: (transfer full): Zero-terminated string array of all versioned
512  *   dependencies
513  */
514 char **
515 g_irepository_get_dependencies (GIRepository *repository,
516                                 const char *namespace)
517 {
518   GITypelib *typelib;
519   GHashTable *transitive_dependencies;  /* set of owned utf8 */
520   GHashTableIter iter;
521   gchar *dependency;
522   GPtrArray *out;  /* owned utf8 elements */
523
524   g_return_val_if_fail (namespace != NULL, NULL);
525
526   repository = get_repository (repository);
527
528   typelib = get_registered (repository, namespace, NULL);
529   g_return_val_if_fail (typelib != NULL, NULL);
530
531   /* Load the dependencies. */
532   transitive_dependencies = g_hash_table_new (g_str_hash, g_str_equal);
533   get_typelib_dependencies_transitive (repository, typelib,
534                                        transitive_dependencies);
535
536   /* Convert to a string array. */
537   out = g_ptr_array_new_full (g_hash_table_size (transitive_dependencies),
538                               g_free);
539   g_hash_table_iter_init (&iter, transitive_dependencies);
540
541   while (g_hash_table_iter_next (&iter, (gpointer) &dependency, NULL))
542     {
543       g_ptr_array_add (out, dependency);
544       g_hash_table_iter_steal (&iter);
545     }
546
547   g_hash_table_unref (transitive_dependencies);
548
549   /* Add a NULL terminator. */
550   g_ptr_array_add (out, NULL);
551
552   return (gchar **) g_ptr_array_free (out, FALSE);
553 }
554
555 /**
556  * g_irepository_load_typelib:
557  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
558  *   process-global default #GIRepository
559  * @typelib: TODO
560  * @flags: TODO
561  * @error: TODO
562  *
563  * TODO
564  */
565 const char *
566 g_irepository_load_typelib (GIRepository *repository,
567                             GITypelib     *typelib,
568                             GIRepositoryLoadFlags flags,
569                             GError      **error)
570 {
571   Header *header;
572   const char *namespace;
573   const char *nsversion;
574   gboolean allow_lazy = flags & G_IREPOSITORY_LOAD_FLAG_LAZY;
575   gboolean is_lazy;
576   char *version_conflict;
577
578   repository = get_repository (repository);
579
580   header = (Header *) typelib->data;
581   namespace = g_typelib_get_string (typelib, header->namespace);
582   nsversion = g_typelib_get_string (typelib, header->nsversion);
583
584   if (get_registered_status (repository, namespace, nsversion, allow_lazy,
585                              &is_lazy, &version_conflict))
586     {
587       if (version_conflict != NULL)
588         {
589           g_set_error (error, G_IREPOSITORY_ERROR,
590                        G_IREPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
591                        "Attempting to load namespace '%s', version '%s', but '%s' is already loaded",
592                        namespace, nsversion, version_conflict);
593           return NULL;
594         }
595       return namespace;
596     }
597   return register_internal (repository, "<builtin>",
598                             allow_lazy, typelib, error);
599 }
600
601 /**
602  * g_irepository_is_registered:
603  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
604  *   process-global default #GIRepository
605  * @namespace_: Namespace of interest
606  * @version: (allow-none): Required version, may be %NULL for latest
607  *
608  * Check whether a particular namespace (and optionally, a specific
609  * version thereof) is currently loaded.  This function is likely to
610  * only be useful in unusual circumstances; in order to act upon
611  * metadata in the namespace, you should call g_irepository_require()
612  * instead which will ensure the namespace is loaded, and return as
613  * quickly as this function will if it has already been loaded.
614  *
615  * Returns: %TRUE if namespace-version is loaded, %FALSE otherwise
616  */
617 gboolean
618 g_irepository_is_registered (GIRepository *repository,
619                              const gchar *namespace,
620                              const gchar *version)
621 {
622   repository = get_repository (repository);
623   return get_registered (repository, namespace, version) != NULL;
624 }
625
626 /**
627  * g_irepository_get_default:
628  *
629  * Returns the singleton process-global default #GIRepository. It is
630  * not currently supported to have multiple repositories in a
631  * particular process, but this function is provided in the unlikely
632  * eventuality that it would become possible, and as a convenience for
633  * higher level language bindings to conform to the GObject method
634  * call conventions.
635  *
636  * All methods on #GIRepository also accept %NULL as an instance
637  * parameter to mean this default repository, which is usually more
638  * convenient for C.
639  *
640  * Returns: (transfer none): The global singleton #GIRepository
641  */
642 GIRepository *
643 g_irepository_get_default (void)
644 {
645   return get_repository (NULL);
646 }
647
648 /**
649  * g_irepository_get_n_infos:
650  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
651  *   process-global default #GIRepository
652  * @namespace_: Namespace to inspect
653  *
654  * This function returns the number of metadata entries in
655  * given namespace @namespace_.  The namespace must have
656  * already been loaded before calling this function.
657  *
658  * Returns: number of metadata entries
659  */
660 gint
661 g_irepository_get_n_infos (GIRepository *repository,
662                            const gchar  *namespace)
663 {
664   GITypelib *typelib;
665   gint n_interfaces = 0;
666
667   g_return_val_if_fail (namespace != NULL, -1);
668
669   repository = get_repository (repository);
670
671   typelib = get_registered (repository, namespace, NULL);
672
673   g_return_val_if_fail (typelib != NULL, -1);
674
675   n_interfaces = ((Header *)typelib->data)->n_local_entries;
676
677   return n_interfaces;
678 }
679
680 /**
681  * g_irepository_get_info:
682  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
683  *   process-global default #GIRepository
684  * @namespace_: Namespace to inspect
685  * @index: 0-based offset into namespace metadata for entry
686  *
687  * This function returns a particular metadata entry in the
688  * given namespace @namespace_.  The namespace must have
689  * already been loaded before calling this function.
690  * See g_irepository_get_n_infos() to find the maximum number of
691  * entries.
692  *
693  * Returns: (transfer full): #GIBaseInfo containing metadata
694  */
695 GIBaseInfo *
696 g_irepository_get_info (GIRepository *repository,
697                         const gchar  *namespace,
698                         gint          index)
699 {
700   GITypelib *typelib;
701   DirEntry *entry;
702
703   g_return_val_if_fail (namespace != NULL, NULL);
704
705   repository = get_repository (repository);
706
707   typelib = get_registered (repository, namespace, NULL);
708
709   g_return_val_if_fail (typelib != NULL, NULL);
710
711   entry = g_typelib_get_dir_entry (typelib, index + 1);
712   if (entry == NULL)
713     return NULL;
714   return _g_info_new_full (entry->blob_type,
715                            repository,
716                            NULL, typelib, entry->offset);
717 }
718
719 typedef struct {
720   const gchar *gtype_name;
721   GITypelib *result_typelib;
722 } FindByGTypeData;
723
724 static DirEntry *
725 find_by_gtype (GHashTable *table, FindByGTypeData *data, gboolean check_prefix)
726 {
727   GHashTableIter iter;
728   gpointer key, value;
729   DirEntry *ret;
730
731   g_hash_table_iter_init (&iter, table);
732   while (g_hash_table_iter_next (&iter, &key, &value))
733     {
734       GITypelib *typelib = (GITypelib*)value;
735       if (check_prefix)
736         {
737           if (!g_typelib_matches_gtype_name_prefix (typelib, data->gtype_name))
738             continue;
739         }
740
741       ret = g_typelib_get_dir_entry_by_gtype_name (typelib, data->gtype_name);
742       if (ret)
743         {
744           data->result_typelib = typelib;
745           return ret;
746         }
747     }
748
749   return NULL;
750 }
751
752 /**
753  * g_irepository_find_by_gtype:
754  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
755  *   process-global default #GIRepository
756  * @gtype: GType to search for
757  *
758  * Searches all loaded namespaces for a particular #GType.  Note that
759  * in order to locate the metadata, the namespace corresponding to
760  * the type must first have been loaded.  There is currently no
761  * mechanism for determining the namespace which corresponds to an
762  * arbitrary GType - thus, this function will operate most reliably
763  * when you know the GType to originate from be from a loaded namespace.
764  *
765  * Returns: (transfer full): #GIBaseInfo representing metadata about @type, or %NULL
766  */
767 GIBaseInfo *
768 g_irepository_find_by_gtype (GIRepository *repository,
769                              GType         gtype)
770 {
771   FindByGTypeData data;
772   GIBaseInfo *cached;
773   DirEntry *entry;
774
775   repository = get_repository (repository);
776
777   cached = g_hash_table_lookup (repository->priv->info_by_gtype,
778                                 (gpointer)gtype);
779
780   if (cached != NULL)
781     return g_base_info_ref (cached);
782
783   data.gtype_name = g_type_name (gtype);
784   data.result_typelib = NULL;
785
786   /* Inside each typelib, we include the "C prefix" which acts as
787    * a namespace mechanism.  For GtkTreeView, the C prefix is Gtk.
788    * Given the assumption that GTypes for a library also use the
789    * C prefix, we know we can skip examining a typelib if our
790    * target type does not have this typelib's C prefix. Use this
791    * assumption as our first attempt at locating the DirEntry.
792    */
793   entry = find_by_gtype (repository->priv->typelibs, &data, TRUE);
794   if (entry == NULL)
795     entry = find_by_gtype (repository->priv->lazy_typelibs, &data, TRUE);
796
797   /* Not ever class library necessarily specifies a correct c_prefix,
798    * so take a second pass. This time we will try a global lookup,
799    * ignoring prefixes.
800    * See http://bugzilla.gnome.org/show_bug.cgi?id=564016
801    */
802   if (entry == NULL)
803     entry = find_by_gtype (repository->priv->typelibs, &data, FALSE);
804   if (entry == NULL)
805     entry = find_by_gtype (repository->priv->lazy_typelibs, &data, FALSE);
806
807   if (entry != NULL)
808     {
809       cached = _g_info_new_full (entry->blob_type,
810                                  repository,
811                                  NULL, data.result_typelib, entry->offset);
812
813       g_hash_table_insert (repository->priv->info_by_gtype,
814                            (gpointer) gtype,
815                            g_base_info_ref (cached));
816       return cached;
817     }
818   return NULL;
819 }
820
821 /**
822  * g_irepository_find_by_name:
823  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
824  *   process-global default #GIRepository
825  * @namespace_: Namespace which will be searched
826  * @name: Entry name to find
827  *
828  * Searches for a particular entry in a namespace.  Before calling
829  * this function for a particular namespace, you must call
830  * g_irepository_require() once to load the namespace, or otherwise
831  * ensure the namespace has already been loaded.
832  *
833  * Returns: (transfer full): #GIBaseInfo representing metadata about @name, or %NULL
834  */
835 GIBaseInfo *
836 g_irepository_find_by_name (GIRepository *repository,
837                             const gchar  *namespace,
838                             const gchar  *name)
839 {
840   GITypelib *typelib;
841   DirEntry *entry;
842
843   g_return_val_if_fail (namespace != NULL, NULL);
844
845   repository = get_repository (repository);
846   typelib = get_registered (repository, namespace, NULL);
847   g_return_val_if_fail (typelib != NULL, NULL);
848
849   entry = g_typelib_get_dir_entry_by_name (typelib, name);
850   if (entry == NULL)
851     return NULL;
852   return _g_info_new_full (entry->blob_type,
853                            repository,
854                            NULL, typelib, entry->offset);
855 }
856
857 typedef struct {
858   GIRepository *repository;
859   GQuark domain;
860
861   GITypelib *result_typelib;
862   DirEntry *result;
863 } FindByErrorDomainData;
864
865 static void
866 find_by_error_domain_foreach (gpointer key,
867                               gpointer value,
868                               gpointer datap)
869 {
870   GITypelib *typelib = (GITypelib*)value;
871   FindByErrorDomainData *data = datap;
872
873   if (data->result != NULL)
874     return;
875
876   data->result = g_typelib_get_dir_entry_by_error_domain (typelib, data->domain);
877   if (data->result)
878     data->result_typelib = typelib;
879 }
880
881 /**
882  * g_irepository_find_by_error_domain:
883  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
884  *   process-global default #GIRepository
885  * @domain: a #GError domain
886  *
887  * Searches for the enum type corresponding to the given #GError
888  * domain. Before calling this function for a particular namespace,
889  * you must call g_irepository_require() once to load the namespace, or
890  * otherwise ensure the namespace has already been loaded.
891  *
892  * Returns: (transfer full): #GIEnumInfo representing metadata about @domain's
893  * enum type, or %NULL
894  * Since: 1.29.17
895  */
896 GIEnumInfo *
897 g_irepository_find_by_error_domain (GIRepository *repository,
898                                     GQuark        domain)
899 {
900   FindByErrorDomainData data;
901   GIEnumInfo *cached;
902
903   repository = get_repository (repository);
904
905   cached = g_hash_table_lookup (repository->priv->info_by_error_domain,
906                                 GUINT_TO_POINTER (domain));
907
908   if (cached != NULL)
909     return g_base_info_ref ((GIBaseInfo *)cached);
910
911   data.repository = repository;
912   data.domain = domain;
913   data.result_typelib = NULL;
914   data.result = NULL;
915
916   g_hash_table_foreach (repository->priv->typelibs, find_by_error_domain_foreach, &data);
917   if (data.result == NULL)
918     g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_error_domain_foreach, &data);
919
920   if (data.result != NULL)
921     {
922       cached = _g_info_new_full (data.result->blob_type,
923                                  repository,
924                                  NULL, data.result_typelib, data.result->offset);
925
926       g_hash_table_insert (repository->priv->info_by_error_domain,
927                            GUINT_TO_POINTER (domain),
928                            g_base_info_ref (cached));
929       return cached;
930     }
931   return NULL;
932 }
933
934 static void
935 collect_namespaces (gpointer key,
936                     gpointer value,
937                     gpointer data)
938 {
939   GList **list = data;
940
941   *list = g_list_append (*list, key);
942 }
943
944 /**
945  * g_irepository_get_loaded_namespaces:
946  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
947  *   process-global default #GIRepository
948  *
949  * Return the list of currently loaded namespaces.
950  *
951  * Returns: (element-type utf8) (transfer full): List of namespaces
952  */
953 gchar **
954 g_irepository_get_loaded_namespaces (GIRepository *repository)
955 {
956   GList *l, *list = NULL;
957   gchar **names;
958   gint i;
959
960   repository = get_repository (repository);
961
962   g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list);
963   g_hash_table_foreach (repository->priv->lazy_typelibs, collect_namespaces, &list);
964
965   names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
966   i = 0;
967   for (l = list; l; l = l->next)
968     names[i++] = g_strdup (l->data);
969   g_list_free (list);
970
971   return names;
972 }
973
974 /**
975  * g_irepository_get_version:
976  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
977  *   process-global default #GIRepository
978  * @namespace_: Namespace to inspect
979  *
980  * This function returns the loaded version associated with the given
981  * namespace @namespace_.
982  *
983  * Note: The namespace must have already been loaded using a function
984  * such as g_irepository_require() before calling this function.
985  *
986  * Returns: Loaded version
987  */
988 const gchar *
989 g_irepository_get_version (GIRepository *repository,
990                            const gchar  *namespace)
991 {
992   GITypelib *typelib;
993   Header *header;
994
995   g_return_val_if_fail (namespace != NULL, NULL);
996
997   repository = get_repository (repository);
998
999   typelib = get_registered (repository, namespace, NULL);
1000
1001   g_return_val_if_fail (typelib != NULL, NULL);
1002
1003   header = (Header *) typelib->data;
1004   return g_typelib_get_string (typelib, header->nsversion);
1005 }
1006
1007 /**
1008  * g_irepository_get_shared_library:
1009  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
1010  *   process-global default #GIRepository
1011  * @namespace_: Namespace to inspect
1012  *
1013  * This function returns a comma-separated list of paths to the
1014  * shared C libraries associated with the given namespace @namespace_.
1015  * There may be no shared library path associated, in which case this
1016  * function will return %NULL.
1017  *
1018  * Note: The namespace must have already been loaded using a function
1019  * such as g_irepository_require() before calling this function.
1020  *
1021  * Returns: Comma-separated list of paths to shared libraries,
1022  *   or %NULL if none are associated
1023  */
1024 const gchar *
1025 g_irepository_get_shared_library (GIRepository *repository,
1026                                   const gchar  *namespace)
1027 {
1028   GITypelib *typelib;
1029   Header *header;
1030
1031   g_return_val_if_fail (namespace != NULL, NULL);
1032
1033   repository = get_repository (repository);
1034
1035   typelib = get_registered (repository, namespace, NULL);
1036
1037   g_return_val_if_fail (typelib != NULL, NULL);
1038
1039   header = (Header *) typelib->data;
1040   if (header->shared_library)
1041     return g_typelib_get_string (typelib, header->shared_library);
1042   else
1043     return NULL;
1044 }
1045
1046 /**
1047  * g_irepository_get_c_prefix:
1048  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
1049  *   process-global default #GIRepository
1050  * @namespace_: Namespace to inspect
1051  *
1052  * This function returns the "C prefix", or the C level namespace
1053  * associated with the given introspection namespace.  Each C symbol
1054  * starts with this prefix, as well each #GType in the library.
1055  *
1056  * Note: The namespace must have already been loaded using a function
1057  * such as g_irepository_require() before calling this function.
1058  *
1059  * Returns: C namespace prefix, or %NULL if none associated
1060  */
1061 const gchar *
1062 g_irepository_get_c_prefix (GIRepository *repository,
1063                             const gchar  *namespace_)
1064 {
1065   GITypelib *typelib;
1066   Header *header;
1067
1068   g_return_val_if_fail (namespace_ != NULL, NULL);
1069
1070   repository = get_repository (repository);
1071
1072   typelib = get_registered (repository, namespace_, NULL);
1073
1074   g_return_val_if_fail (typelib != NULL, NULL);
1075
1076   header = (Header *) typelib->data;
1077   if (header->c_prefix)
1078     return g_typelib_get_string (typelib, header->c_prefix);
1079   else
1080     return NULL;
1081 }
1082
1083 /**
1084  * g_irepository_get_typelib_path:
1085  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
1086  *   process-global default #GIRepository
1087  * @namespace_: GI namespace to use, e.g. "Gtk"
1088  *
1089  * If namespace @namespace_ is loaded, return the full path to the
1090  * .typelib file it was loaded from.  If the typelib for
1091  * namespace @namespace_ was included in a shared library, return
1092  * the special string "&lt;builtin&gt;".
1093  *
1094  * Returns: Filesystem path (or $lt;builtin$gt;) if successful, %NULL if namespace is not loaded
1095  */
1096
1097 const gchar *
1098 g_irepository_get_typelib_path (GIRepository *repository,
1099                                 const gchar  *namespace)
1100 {
1101   gpointer orig_key, value;
1102
1103   repository = get_repository (repository);
1104
1105   if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace,
1106                                      &orig_key, &value))
1107     {
1108       if (!g_hash_table_lookup_extended (repository->priv->lazy_typelibs, namespace,
1109                                          &orig_key, &value))
1110
1111         return NULL;
1112     }
1113   return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
1114 }
1115
1116 /* This simple search function looks for a specified namespace-version;
1117    it's faster than the full directory listing required for latest version. */
1118 static GMappedFile *
1119 find_namespace_version (const gchar  *namespace,
1120                         const gchar  *version,
1121                         GSList       *search_path,
1122                         gchar       **path_ret)
1123 {
1124   GSList *ldir;
1125   GError *error = NULL;
1126   GMappedFile *mfile = NULL;
1127   char *fname;
1128
1129   fname = g_strdup_printf ("%s-%s.typelib", namespace, version);
1130
1131   for (ldir = search_path; ldir; ldir = ldir->next)
1132     {
1133       char *path = g_build_filename (ldir->data, fname, NULL);
1134
1135       mfile = g_mapped_file_new (path, FALSE, &error);
1136       if (error)
1137         {
1138           g_free (path);
1139           g_clear_error (&error);
1140           continue;
1141         }
1142       *path_ret = path;
1143       break;
1144     }
1145   g_free (fname);
1146   return mfile;
1147 }
1148
1149 static gboolean
1150 parse_version (const char *version,
1151                int *major,
1152                int *minor)
1153 {
1154   const char *dot;
1155   char *end;
1156
1157   *major = strtol (version, &end, 10);
1158   dot = strchr (version, '.');
1159   if (dot == NULL)
1160     {
1161       *minor = 0;
1162       return TRUE;
1163     }
1164   if (dot != end)
1165     return FALSE;
1166   *minor = strtol (dot+1, &end, 10);
1167   if (end != (version + strlen (version)))
1168     return FALSE;
1169   return TRUE;
1170 }
1171
1172 static int
1173 compare_version (const char *v1,
1174                  const char *v2)
1175 {
1176   gboolean success;
1177   int v1_major, v1_minor;
1178   int v2_major, v2_minor;
1179
1180   success = parse_version (v1, &v1_major, &v1_minor);
1181   g_assert (success);
1182
1183   success = parse_version (v2, &v2_major, &v2_minor);
1184   g_assert (success);
1185
1186   if (v1_major > v2_major)
1187     return 1;
1188   else if (v2_major > v1_major)
1189     return -1;
1190   else if (v1_minor > v2_minor)
1191     return 1;
1192   else if (v2_minor > v1_minor)
1193     return -1;
1194   return 0;
1195 }
1196
1197 struct NamespaceVersionCandidadate
1198 {
1199   GMappedFile *mfile;
1200   int path_index;
1201   char *path;
1202   char *version;
1203 };
1204
1205 static int
1206 compare_candidate_reverse (struct NamespaceVersionCandidadate *c1,
1207                            struct NamespaceVersionCandidadate *c2)
1208 {
1209   int result = compare_version (c1->version, c2->version);
1210   /* First, check the version */
1211   if (result > 0)
1212     return -1;
1213   else if (result < 0)
1214     return 1;
1215   else
1216     {
1217       /* Now check the path index, which says how early in the search path
1218        * we found it.  This ensures that of equal version targets, we
1219        * pick the earlier one.
1220        */
1221       if (c1->path_index == c2->path_index)
1222         return 0;
1223       else if (c1->path_index > c2->path_index)
1224         return 1;
1225       else
1226         return -1;
1227     }
1228 }
1229
1230 static void
1231 free_candidate (struct NamespaceVersionCandidadate *candidate)
1232 {
1233   g_mapped_file_unref (candidate->mfile);
1234   g_free (candidate->path);
1235   g_free (candidate->version);
1236   g_slice_free (struct NamespaceVersionCandidadate, candidate);
1237 }
1238
1239 static GSList *
1240 enumerate_namespace_versions (const gchar *namespace,
1241                               GSList      *search_path)
1242 {
1243   GSList *candidates = NULL;
1244   GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal);
1245   char *namespace_dash;
1246   char *namespace_typelib;
1247   GSList *ldir;
1248   GError *error = NULL;
1249   int index;
1250
1251   namespace_dash = g_strdup_printf ("%s-", namespace);
1252   namespace_typelib = g_strdup_printf ("%s.typelib", namespace);
1253
1254   index = 0;
1255   for (ldir = search_path; ldir; ldir = ldir->next)
1256     {
1257       GDir *dir;
1258       const char *dirname;
1259       const char *entry;
1260
1261       dirname = (const char*)ldir->data;
1262       dir = g_dir_open (dirname, 0, NULL);
1263       if (dir == NULL)
1264         continue;
1265       while ((entry = g_dir_read_name (dir)) != NULL)
1266         {
1267           GMappedFile *mfile;
1268           char *path, *version;
1269           struct NamespaceVersionCandidadate *candidate;
1270
1271           if (!g_str_has_suffix (entry, ".typelib"))
1272             continue;
1273
1274           if (g_str_has_prefix (entry, namespace_dash))
1275             {
1276               const char *last_dash;
1277               const char *name_end;
1278               int major, minor;
1279
1280               name_end = strrchr (entry, '.');
1281               last_dash = strrchr (entry, '-');
1282               version = g_strndup (last_dash+1, name_end-(last_dash+1));
1283               if (!parse_version (version, &major, &minor))
1284                 {
1285                   g_free (version);
1286                   continue;
1287                 }
1288             }
1289           else
1290             continue;
1291
1292           if (g_hash_table_lookup (found_versions, version) != NULL)
1293             {
1294               g_free (version);
1295               continue;
1296             }
1297           g_hash_table_insert (found_versions, version, version);
1298
1299           path = g_build_filename (dirname, entry, NULL);
1300           mfile = g_mapped_file_new (path, FALSE, &error);
1301           if (mfile == NULL)
1302             {
1303               g_free (path);
1304               g_free (version);
1305               g_clear_error (&error);
1306               continue;
1307             }
1308           candidate = g_slice_new0 (struct NamespaceVersionCandidadate);
1309           candidate->mfile = mfile;
1310           candidate->path_index = index;
1311           candidate->path = path;
1312           candidate->version = version;
1313           candidates = g_slist_prepend (candidates, candidate);
1314         }
1315       g_dir_close (dir);
1316       index++;
1317     }
1318
1319   g_free (namespace_dash);
1320   g_free (namespace_typelib);
1321   g_hash_table_destroy (found_versions);
1322
1323   return candidates;
1324 }
1325
1326 static GMappedFile *
1327 find_namespace_latest (const gchar  *namespace,
1328                        GSList       *search_path,
1329                        gchar       **version_ret,
1330                        gchar       **path_ret)
1331 {
1332   GSList *candidates;
1333   GMappedFile *result = NULL;
1334
1335   *version_ret = NULL;
1336   *path_ret = NULL;
1337
1338   candidates = enumerate_namespace_versions (namespace, search_path);
1339
1340   if (candidates != NULL)
1341     {
1342       struct NamespaceVersionCandidadate *elected;
1343       candidates = g_slist_sort (candidates, (GCompareFunc) compare_candidate_reverse);
1344
1345       elected = (struct NamespaceVersionCandidadate *) candidates->data;
1346       /* Remove the elected one so we don't try to free its contents */
1347       candidates = g_slist_delete_link (candidates, candidates);
1348
1349       result = elected->mfile;
1350       *path_ret = elected->path;
1351       *version_ret = elected->version;
1352       g_slice_free (struct NamespaceVersionCandidadate, elected); /* just free the container */
1353       g_slist_foreach (candidates, (GFunc) free_candidate, NULL);
1354       g_slist_free (candidates);
1355     }
1356   return result;
1357 }
1358
1359 /**
1360  * g_irepository_enumerate_versions:
1361  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
1362  *   process-global default #GIRepository
1363  * @namespace_: GI namespace, e.g. "Gtk"
1364  *
1365  * Obtain an unordered list of versions (either currently loaded or
1366  * available) for @namespace_ in this @repository.
1367  *
1368  * Returns: (element-type utf8) (transfer full): the array of versions.
1369  */
1370 GList *
1371 g_irepository_enumerate_versions (GIRepository *repository,
1372                          const gchar  *namespace_)
1373 {
1374   GList *ret = NULL;
1375   GSList *candidates, *link;
1376   const gchar *loaded_version;
1377
1378   init_globals ();
1379   candidates = enumerate_namespace_versions (namespace_, search_path);
1380
1381   for (link = candidates; link; link = link->next)
1382     {
1383       struct NamespaceVersionCandidadate *candidate = link->data;
1384       ret = g_list_prepend (ret, g_strdup (candidate->version));
1385       free_candidate (candidate);
1386     }
1387   g_slist_free (candidates);
1388
1389   /* The currently loaded version of a namespace is also part of the
1390    * available versions, as it could have been loaded using
1391    * require_private().
1392    */
1393   if (g_irepository_is_registered (repository, namespace_, NULL))
1394     {
1395       loaded_version = g_irepository_get_version (repository, namespace_);
1396       if (loaded_version && !g_list_find_custom (ret, loaded_version, g_str_equal))
1397         ret = g_list_prepend (ret, g_strdup (loaded_version));
1398     }
1399
1400   return ret;
1401 }
1402
1403 static GITypelib *
1404 require_internal (GIRepository  *repository,
1405                   const gchar   *namespace,
1406                   const gchar   *version,
1407                   GIRepositoryLoadFlags flags,
1408                   GSList        *search_path,
1409                   GError       **error)
1410 {
1411   GMappedFile *mfile;
1412   GITypelib *ret = NULL;
1413   Header *header;
1414   GITypelib *typelib = NULL;
1415   const gchar *typelib_namespace, *typelib_version;
1416   gboolean allow_lazy = (flags & G_IREPOSITORY_LOAD_FLAG_LAZY) > 0;
1417   gboolean is_lazy;
1418   char *version_conflict = NULL;
1419   char *path = NULL;
1420   char *tmp_version = NULL;
1421
1422   g_return_val_if_fail (namespace != NULL, FALSE);
1423
1424   repository = get_repository (repository);
1425
1426   typelib = get_registered_status (repository, namespace, version, allow_lazy,
1427                                    &is_lazy, &version_conflict);
1428   if (typelib)
1429     return typelib;
1430
1431   if (version_conflict != NULL)
1432     {
1433       g_set_error (error, G_IREPOSITORY_ERROR,
1434                    G_IREPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
1435                    "Requiring namespace '%s' version '%s', but '%s' is already loaded",
1436                    namespace, version, version_conflict);
1437       return NULL;
1438     }
1439
1440   if (version != NULL)
1441     {
1442       mfile = find_namespace_version (namespace, version,
1443                                       search_path, &path);
1444       tmp_version = g_strdup (version);
1445     }
1446   else
1447     {
1448       mfile = find_namespace_latest (namespace, search_path,
1449                                      &tmp_version, &path);
1450     }
1451
1452   if (mfile == NULL)
1453     {
1454       if (version != NULL)
1455         g_set_error (error, G_IREPOSITORY_ERROR,
1456                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1457                      "Typelib file for namespace '%s', version '%s' not found",
1458                      namespace, version);
1459       else
1460         g_set_error (error, G_IREPOSITORY_ERROR,
1461                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1462                      "Typelib file for namespace '%s' (any version) not found",
1463                      namespace);
1464       goto out;
1465     }
1466
1467   {
1468     GError *temp_error = NULL;
1469     typelib = g_typelib_new_from_mapped_file (mfile, &temp_error);
1470     if (!typelib)
1471       {
1472         g_set_error (error, G_IREPOSITORY_ERROR,
1473                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1474                      "Failed to load typelib file '%s' for namespace '%s': %s",
1475                      path, namespace, temp_error->message);
1476         g_clear_error (&temp_error);
1477         goto out;
1478       }
1479   }
1480   header = (Header *) typelib->data;
1481   typelib_namespace = g_typelib_get_string (typelib, header->namespace);
1482   typelib_version = g_typelib_get_string (typelib, header->nsversion);
1483
1484   if (strcmp (typelib_namespace, namespace) != 0)
1485     {
1486       g_set_error (error, G_IREPOSITORY_ERROR,
1487                    G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
1488                    "Typelib file %s for namespace '%s' contains "
1489                    "namespace '%s' which doesn't match the file name",
1490                    path, namespace, typelib_namespace);
1491       g_typelib_free (typelib);
1492       goto out;
1493     }
1494   if (version != NULL && strcmp (typelib_version, version) != 0)
1495     {
1496       g_set_error (error, G_IREPOSITORY_ERROR,
1497                    G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
1498                    "Typelib file %s for namespace '%s' contains "
1499                    "version '%s' which doesn't match the expected version '%s'",
1500                    path, namespace, typelib_version, version);
1501       g_typelib_free (typelib);
1502       goto out;
1503     }
1504
1505   if (!register_internal (repository, path, allow_lazy,
1506                           typelib, error))
1507     {
1508       g_typelib_free (typelib);
1509       goto out;
1510     }
1511   ret = typelib;
1512  out:
1513   g_free (tmp_version);
1514   g_free (path);
1515   return ret;
1516 }
1517
1518 /**
1519  * g_irepository_require:
1520  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
1521  *   process-global default #GIRepository
1522  * @namespace_: GI namespace to use, e.g. "Gtk"
1523  * @version: (allow-none): Version of namespace, may be %NULL for latest
1524  * @flags: Set of %GIRepositoryLoadFlags, may be 0
1525  * @error: a #GError.
1526  *
1527  * Force the namespace @namespace_ to be loaded if it isn't already.
1528  * If @namespace_ is not loaded, this function will search for a
1529  * ".typelib" file using the repository search path.  In addition, a
1530  * version @version of namespace may be specified.  If @version is
1531  * not specified, the latest will be used.
1532  *
1533  * Returns: (transfer none): a pointer to the #GITypelib if successful, %NULL otherwise
1534  */
1535 GITypelib *
1536 g_irepository_require (GIRepository  *repository,
1537                        const gchar   *namespace,
1538                        const gchar   *version,
1539                        GIRepositoryLoadFlags flags,
1540                        GError       **error)
1541 {
1542   GITypelib *typelib;
1543
1544   init_globals ();
1545   typelib = require_internal (repository, namespace, version, flags,
1546                               search_path, error);
1547
1548   return typelib;
1549 }
1550
1551 /**
1552  * g_irepository_require_private:
1553  * @repository: (allow-none): A #GIRepository or %NULL for the singleton
1554  *   process-global default #GIRepository
1555  * @typelib_dir: Private directory where to find the requested typelib
1556  * @namespace_: GI namespace to use, e.g. "Gtk"
1557  * @version: (allow-none): Version of namespace, may be %NULL for latest
1558  * @flags: Set of %GIRepositoryLoadFlags, may be 0
1559  * @error: a #GError.
1560  *
1561  * Force the namespace @namespace_ to be loaded if it isn't already.
1562  * If @namespace_ is not loaded, this function will search for a
1563  * ".typelib" file within the private directory only. In addition, a
1564  * version @version of namespace should be specified.  If @version is
1565  * not specified, the latest will be used.
1566  *
1567  * Returns: (transfer none): a pointer to the #GITypelib if successful, %NULL otherwise
1568  */
1569 GITypelib *
1570 g_irepository_require_private (GIRepository  *repository,
1571                                const gchar   *typelib_dir,
1572                                const gchar   *namespace,
1573                                const gchar   *version,
1574                                GIRepositoryLoadFlags flags,
1575                                GError       **error)
1576 {
1577   GSList search_path = { (gpointer) typelib_dir, NULL };
1578
1579   return require_internal (repository, namespace, version, flags,
1580                            &search_path, error);
1581 }
1582
1583 static gboolean
1584 g_irepository_introspect_cb (const char *option_name,
1585                              const char *value,
1586                              gpointer data,
1587                              GError **error)
1588 {
1589   GError *tmp_error = NULL;
1590   gboolean ret = g_irepository_dump (value, &tmp_error);
1591   if (!ret)
1592     {
1593       g_error ("Failed to extract GType data: %s",
1594                tmp_error->message);
1595       exit (1);
1596     }
1597   exit (0);
1598 }
1599
1600 static const GOptionEntry introspection_args[] = {
1601   { "introspect-dump", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK,
1602     g_irepository_introspect_cb, "Dump introspection information",
1603     "infile.txt,outfile.xml" },
1604   { NULL }
1605 };
1606
1607 /**
1608  * g_irepository_get_option_group: (skip)
1609  *
1610  * Obtain the option group for girepository, it's used
1611  * by the dumper and for programs that wants to provide
1612  * introspection information
1613  *
1614  * Returns: (transfer full): the option group
1615  */
1616 GOptionGroup *
1617 g_irepository_get_option_group (void)
1618 {
1619   GOptionGroup *group;
1620   group = g_option_group_new ("girepository", "Introspection Options", "Show Introspection Options", NULL, NULL);
1621
1622   g_option_group_add_entries (group, introspection_args);
1623   return group;
1624 }
1625
1626 GQuark
1627 g_irepository_error_quark (void)
1628 {
1629   static GQuark quark = 0;
1630   if (quark == 0)
1631     quark = g_quark_from_static_string ("g-irepository-error-quark");
1632   return quark;
1633 }
1634
1635 /**
1636  * g_type_tag_to_string:
1637  * @type: the type_tag
1638  *
1639  * Obtain a string representation of @type
1640  *
1641  * Returns: the string
1642  */
1643 const gchar*
1644 g_type_tag_to_string (GITypeTag type)
1645 {
1646   switch (type)
1647     {
1648     case GI_TYPE_TAG_VOID:
1649       return "void";
1650     case GI_TYPE_TAG_BOOLEAN:
1651       return "gboolean";
1652     case GI_TYPE_TAG_INT8:
1653       return "gint8";
1654     case GI_TYPE_TAG_UINT8:
1655       return "guint8";
1656     case GI_TYPE_TAG_INT16:
1657       return "gint16";
1658     case GI_TYPE_TAG_UINT16:
1659       return "guint16";
1660     case GI_TYPE_TAG_INT32:
1661       return "gint32";
1662     case GI_TYPE_TAG_UINT32:
1663       return "guint32";
1664     case GI_TYPE_TAG_INT64:
1665       return "gint64";
1666     case GI_TYPE_TAG_UINT64:
1667       return "guint64";
1668     case GI_TYPE_TAG_FLOAT:
1669       return "gfloat";
1670     case GI_TYPE_TAG_DOUBLE:
1671       return "gdouble";
1672     case GI_TYPE_TAG_UNICHAR:
1673       return "gunichar";
1674     case GI_TYPE_TAG_GTYPE:
1675       return "GType";
1676     case GI_TYPE_TAG_UTF8:
1677       return "utf8";
1678     case GI_TYPE_TAG_FILENAME:
1679       return "filename";
1680     case GI_TYPE_TAG_ARRAY:
1681       return "array";
1682     case GI_TYPE_TAG_INTERFACE:
1683       return "interface";
1684     case GI_TYPE_TAG_GLIST:
1685       return "glist";
1686     case GI_TYPE_TAG_GSLIST:
1687       return "gslist";
1688     case GI_TYPE_TAG_GHASH:
1689       return "ghash";
1690     case GI_TYPE_TAG_ERROR:
1691       return "error";
1692     default:
1693       return "unknown";
1694     }
1695 }
1696
1697 /**
1698  * g_info_type_to_string:
1699  * @type: the info type
1700  *
1701  * Obtain a string representation of @type
1702  *
1703  * Returns: the string
1704  */
1705 const gchar*
1706 g_info_type_to_string (GIInfoType type)
1707 {
1708   switch (type)
1709     {
1710     case GI_INFO_TYPE_INVALID:
1711       return "invalid";
1712     case GI_INFO_TYPE_FUNCTION:
1713       return "function";
1714     case GI_INFO_TYPE_CALLBACK:
1715       return "callback";
1716     case GI_INFO_TYPE_STRUCT:
1717       return "struct";
1718     case GI_INFO_TYPE_BOXED:
1719       return "boxed";
1720     case GI_INFO_TYPE_ENUM:
1721       return "enum";
1722     case GI_INFO_TYPE_FLAGS:
1723       return "flags";
1724     case GI_INFO_TYPE_OBJECT:
1725       return "object";
1726     case GI_INFO_TYPE_INTERFACE:
1727       return "interface";
1728     case GI_INFO_TYPE_CONSTANT:
1729       return "constant";
1730     case GI_INFO_TYPE_UNION:
1731       return "union";
1732     case GI_INFO_TYPE_VALUE:
1733       return "value";
1734     case GI_INFO_TYPE_SIGNAL:
1735       return "signal";
1736     case GI_INFO_TYPE_VFUNC:
1737       return "vfunc";
1738     case GI_INFO_TYPE_PROPERTY:
1739       return "property";
1740     case GI_INFO_TYPE_FIELD:
1741       return "field";
1742     case GI_INFO_TYPE_ARG:
1743       return "arg";
1744     case GI_INFO_TYPE_TYPE:
1745       return "type";
1746     case GI_INFO_TYPE_UNRESOLVED:
1747       return "unresolved";
1748     default:
1749       return "unknown";
1750   }
1751 }