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