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