girepository: fix some doc comment syntax
[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 /**
519  * g_irepository_get_info:
520  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
521  * @namespace_: Namespace to inspect
522  * @index: 0-based offset into namespace metadata for entry
523  *
524  * This function returns a particular metadata entry in the
525  * given namespace @namespace_.  The namespace must have
526  * already been loaded before calling this function.
527  * See g_irepository_get_n_infos() to find the maximum number of
528  * entries.
529  *
530  * Returns: (transfer full): #GIBaseInfo containing metadata
531  */
532 GIBaseInfo *
533 g_irepository_get_info (GIRepository *repository,
534                         const gchar  *namespace,
535                         gint          index)
536 {
537   GITypelib *typelib;
538   DirEntry *entry;
539
540   g_return_val_if_fail (namespace != NULL, NULL);
541
542   repository = get_repository (repository);
543
544   typelib = get_registered (repository, namespace, NULL);
545
546   g_return_val_if_fail (typelib != NULL, NULL);
547
548   entry = g_typelib_get_dir_entry (typelib, index + 1);
549   if (entry == NULL)
550     return NULL;
551   return _g_info_new_full (entry->blob_type,
552                            repository,
553                            NULL, typelib, entry->offset);
554 }
555
556 typedef struct {
557   GIRepository *repository;
558   GType type;
559
560   gboolean fastpass;
561   GITypelib *result_typelib;
562   DirEntry *result;
563 } FindByGTypeData;
564
565 static void
566 find_by_gtype_foreach (gpointer key,
567                        gpointer value,
568                        gpointer datap)
569 {
570   GITypelib *typelib = (GITypelib*)value;
571   FindByGTypeData *data = datap;
572
573   if (data->result != NULL)
574     return;
575
576   data->result = g_typelib_get_dir_entry_by_gtype (typelib, data->fastpass, data->type);
577   if (data->result)
578     data->result_typelib = typelib;
579 }
580
581 /**
582  * g_irepository_find_by_gtype:
583  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
584  * @gtype: GType to search for
585  *
586  * Searches all loaded namespaces for a particular #GType.  Note that
587  * in order to locate the metadata, the namespace corresponding to
588  * the type must first have been loaded.  There is currently no
589  * mechanism for determining the namespace which corresponds to an
590  * arbitrary GType - thus, this function will operate most reliably
591  * when you know the GType to originate from be from a loaded namespace.
592  *
593  * Returns: (transfer full): #GIBaseInfo representing metadata about @type, or %NULL
594  */
595 GIBaseInfo *
596 g_irepository_find_by_gtype (GIRepository *repository,
597                              GType         gtype)
598 {
599   FindByGTypeData data;
600   GIBaseInfo *cached;
601
602   repository = get_repository (repository);
603
604   cached = g_hash_table_lookup (repository->priv->info_by_gtype,
605                                 (gpointer)gtype);
606
607   if (cached != NULL)
608     return g_base_info_ref (cached);
609
610   data.repository = repository;
611   data.fastpass = TRUE;
612   data.type = gtype;
613   data.result_typelib = NULL;
614   data.result = NULL;
615
616   g_hash_table_foreach (repository->priv->typelibs, find_by_gtype_foreach, &data);
617   if (data.result == NULL)
618     g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_gtype_foreach, &data);
619
620   /* We do two passes; see comment in find_interface */
621   if (data.result == NULL)
622     {
623       data.fastpass = FALSE;
624       g_hash_table_foreach (repository->priv->typelibs, find_by_gtype_foreach, &data);
625     }
626   if (data.result == NULL)
627     g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_gtype_foreach, &data);
628
629   if (data.result != NULL)
630     {
631       cached = _g_info_new_full (data.result->blob_type,
632                                  repository,
633                                  NULL, data.result_typelib, data.result->offset);
634
635       g_hash_table_insert (repository->priv->info_by_gtype,
636                            (gpointer) gtype,
637                            g_base_info_ref (cached));
638       return cached;
639     }
640   return NULL;
641 }
642
643 /**
644  * g_irepository_find_by_name:
645  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
646  * @namespace_: Namespace which will be searched
647  * @name: Entry name to find
648  *
649  * Searches for a particular entry in a namespace.  Before calling
650  * this function for a particular namespace, you must call
651  * g_irepository_require() once to load the namespace, or otherwise
652  * ensure the namespace has already been loaded.
653  *
654  * Returns: (transfer full): #GIBaseInfo representing metadata about @name, or %NULL
655  */
656 GIBaseInfo *
657 g_irepository_find_by_name (GIRepository *repository,
658                             const gchar  *namespace,
659                             const gchar  *name)
660 {
661   GITypelib *typelib;
662   DirEntry *entry;
663
664   g_return_val_if_fail (namespace != NULL, NULL);
665
666   repository = get_repository (repository);
667   typelib = get_registered (repository, namespace, NULL);
668   g_return_val_if_fail (typelib != NULL, NULL);
669
670   entry = g_typelib_get_dir_entry_by_name (typelib, name);
671   if (entry == NULL)
672     return NULL;
673   return _g_info_new_full (entry->blob_type,
674                            repository,
675                            NULL, typelib, entry->offset);
676 }
677
678 static void
679 collect_namespaces (gpointer key,
680                     gpointer value,
681                     gpointer data)
682 {
683   GList **list = data;
684
685   *list = g_list_append (*list, key);
686 }
687
688 /**
689  * g_irepository_get_loaded_namespaces:
690  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
691  *
692  * Return the list of currently loaded namespaces.
693  *
694  * Returns: (utf8) (transfer full): List of namespaces
695  */
696 gchar **
697 g_irepository_get_loaded_namespaces (GIRepository *repository)
698 {
699   GList *l, *list = NULL;
700   gchar **names;
701   gint i;
702
703   repository = get_repository (repository);
704
705   g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list);
706   g_hash_table_foreach (repository->priv->lazy_typelibs, collect_namespaces, &list);
707
708   names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
709   i = 0;
710   for (l = list; l; l = l->next)
711     names[i++] = g_strdup (l->data);
712   g_list_free (list);
713
714   return names;
715 }
716
717 /**
718  * g_irepository_get_version:
719  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
720  * @namespace_: Namespace to inspect
721  *
722  * This function returns the loaded version associated with the given
723  * namespace @namespace_.
724  *
725  * Note: The namespace must have already been loaded using a function
726  * such as g_irepository_require() before calling this function.
727  *
728  * Returns: Loaded version
729  */
730 const gchar *
731 g_irepository_get_version (GIRepository *repository,
732                            const gchar  *namespace)
733 {
734   GITypelib *typelib;
735   Header *header;
736
737   g_return_val_if_fail (namespace != NULL, NULL);
738
739   repository = get_repository (repository);
740
741   typelib = get_registered (repository, namespace, NULL);
742
743   g_return_val_if_fail (typelib != NULL, NULL);
744
745   header = (Header *) typelib->data;
746   return g_typelib_get_string (typelib, header->nsversion);
747 }
748
749 /**
750  * g_irepository_get_shared_library:
751  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
752  * @namespace_: Namespace to inspect
753  *
754  * This function returns the full path to the shared C library
755  * associated with the given namespace @namespace_. There may be no
756  * shared library path associated, in which case this function will
757  * return %NULL.
758  *
759  * Note: The namespace must have already been loaded using a function
760  * such as g_irepository_require() before calling this function.
761  *
762  * Returns: Full path to shared library, or %NULL if none associated
763  */
764 const gchar *
765 g_irepository_get_shared_library (GIRepository *repository,
766                                   const gchar  *namespace)
767 {
768   GITypelib *typelib;
769   Header *header;
770
771   g_return_val_if_fail (namespace != NULL, NULL);
772
773   repository = get_repository (repository);
774
775   typelib = get_registered (repository, namespace, NULL);
776
777   g_return_val_if_fail (typelib != NULL, NULL);
778
779   header = (Header *) typelib->data;
780   if (header->shared_library)
781     return g_typelib_get_string (typelib, header->shared_library);
782   else
783     return NULL;
784 }
785
786 /**
787  * g_irepository_get_c_prefix
788  * @repository: (allow-none): A #GIRepository, may be %NULL for the default
789  * @namespace_: Namespace to inspect
790  *
791  * This function returns the "C prefix", or the C level namespace
792  * associated with the given introspection namespace.  Each C symbol
793  * starts with this prefix, as well each #GType in the library.
794  *
795  * Note: The namespace must have already been loaded using a function
796  * such as g_irepository_require() before calling this function.
797  *
798  * Returns: C namespace prefix, or %NULL if none associated
799  */
800 const gchar *
801 g_irepository_get_c_prefix (GIRepository *repository,
802                             const gchar  *namespace_)
803 {
804   GITypelib *typelib;
805   Header *header;
806
807   g_return_val_if_fail (namespace_ != NULL, NULL);
808
809   repository = get_repository (repository);
810
811   typelib = get_registered (repository, namespace_, NULL);
812
813   g_return_val_if_fail (typelib != NULL, NULL);
814
815   header = (Header *) typelib->data;
816   if (header->shared_library)
817     return g_typelib_get_string (typelib, header->c_prefix);
818   else
819     return NULL;
820 }
821
822 /**
823  * g_irepository_get_typelib_path
824  * @repository: (allow-none): Repository, may be %NULL for the default
825  * @namespace_: GI namespace to use, e.g. "Gtk"
826  *
827  * If namespace @namespace_ is loaded, return the full path to the
828  * .typelib file it was loaded from.  If the typelib for
829  * namespace @namespace_ was included in a shared library, return
830  * the special string "$lt;builtin$gt;".
831  *
832  * Returns: Filesystem path (or $lt;builtin$gt;) if successful, %NULL if namespace is not loaded
833  */
834
835 const gchar *
836 g_irepository_get_typelib_path (GIRepository *repository,
837                                 const gchar  *namespace)
838 {
839   gpointer orig_key, value;
840
841   repository = get_repository (repository);
842
843   if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace,
844                                      &orig_key, &value))
845     {
846       if (!g_hash_table_lookup_extended (repository->priv->lazy_typelibs, namespace,
847                                          &orig_key, &value))
848
849         return NULL;
850     }
851   return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
852 }
853
854 /* This simple search function looks for a specified namespace-version;
855    it's faster than the full directory listing required for latest version. */
856 static GMappedFile *
857 find_namespace_version (const gchar  *namespace,
858                         const gchar  *version,
859                         GSList       *search_path,
860                         gchar       **path_ret)
861 {
862   GSList *ldir;
863   GError *error = NULL;
864   GMappedFile *mfile = NULL;
865   char *fname;
866
867   fname = g_strdup_printf ("%s-%s.typelib", namespace, version);
868
869   for (ldir = search_path; ldir; ldir = ldir->next)
870     {
871       char *path = g_build_filename (ldir->data, fname, NULL);
872
873       mfile = g_mapped_file_new (path, FALSE, &error);
874       if (error)
875         {
876           g_free (path);
877           g_clear_error (&error);
878           continue;
879         }
880       *path_ret = path;
881       break;
882     }
883   g_free (fname);
884   return mfile;
885 }
886
887 static gboolean
888 parse_version (const char *version,
889                int *major,
890                int *minor)
891 {
892   const char *dot;
893   char *end;
894
895   *major = strtol (version, &end, 10);
896   dot = strchr (version, '.');
897   if (dot == NULL)
898     {
899       *minor = 0;
900       return TRUE;
901     }
902   if (dot != end)
903     return FALSE;
904   *minor = strtol (dot+1, &end, 10);
905   if (end != (version + strlen (version)))
906     return FALSE;
907   return TRUE;
908 }
909
910 static int
911 compare_version (const char *v1,
912                  const char *v2)
913 {
914   gboolean success;
915   int v1_major, v1_minor;
916   int v2_major, v2_minor;
917
918   success = parse_version (v1, &v1_major, &v1_minor);
919   g_assert (success);
920
921   success = parse_version (v2, &v2_major, &v2_minor);
922   g_assert (success);
923
924   if (v1_major > v2_major)
925     return 1;
926   else if (v2_major > v1_major)
927     return -1;
928   else if (v1_minor > v2_minor)
929     return 1;
930   else if (v2_minor > v1_minor)
931     return -1;
932   return 0;
933 }
934
935 struct NamespaceVersionCandidadate
936 {
937   GMappedFile *mfile;
938   int path_index;
939   char *path;
940   char *version;
941 };
942
943 static int
944 compare_candidate_reverse (struct NamespaceVersionCandidadate *c1,
945                            struct NamespaceVersionCandidadate *c2)
946 {
947   int result = compare_version (c1->version, c2->version);
948   /* First, check the version */
949   if (result > 0)
950     return -1;
951   else if (result < 0)
952     return 1;
953   else
954     {
955       /* Now check the path index, which says how early in the search path
956        * we found it.  This ensures that of equal version targets, we
957        * pick the earlier one.
958        */
959       if (c1->path_index == c2->path_index)
960         return 0;
961       else if (c1->path_index > c2->path_index)
962         return 1;
963       else
964         return -1;
965     }
966 }
967
968 static void
969 free_candidate (struct NamespaceVersionCandidadate *candidate)
970 {
971   g_mapped_file_unref (candidate->mfile);
972   g_free (candidate->path);
973   g_free (candidate->version);
974   g_slice_free (struct NamespaceVersionCandidadate, candidate);
975 }
976
977 static GSList *
978 enumerate_namespace_versions (const gchar *namespace,
979                               GSList      *search_path)
980 {
981   GSList *candidates = NULL;
982   GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal);
983   char *namespace_dash;
984   char *namespace_typelib;
985   GSList *ldir;
986   GError *error = NULL;
987   int index;
988
989   namespace_dash = g_strdup_printf ("%s-", namespace);
990   namespace_typelib = g_strdup_printf ("%s.typelib", namespace);
991
992   index = 0;
993   for (ldir = search_path; ldir; ldir = ldir->next)
994     {
995       GDir *dir;
996       const char *dirname;
997       const char *entry;
998
999       dirname = (const char*)ldir->data;
1000       dir = g_dir_open (dirname, 0, NULL);
1001       if (dir == NULL)
1002         continue;
1003       while ((entry = g_dir_read_name (dir)) != NULL)
1004         {
1005           GMappedFile *mfile;
1006           char *path, *version;
1007           struct NamespaceVersionCandidadate *candidate;
1008
1009           if (!g_str_has_suffix (entry, ".typelib"))
1010             continue;
1011
1012           if (g_str_has_prefix (entry, namespace_dash))
1013             {
1014               const char *last_dash;
1015               const char *name_end;
1016               int major, minor;
1017
1018               name_end = strrchr (entry, '.');
1019               last_dash = strrchr (entry, '-');
1020               version = g_strndup (last_dash+1, name_end-(last_dash+1));
1021               if (!parse_version (version, &major, &minor))
1022                 {
1023                   g_free (version);
1024                   continue;
1025                 }
1026             }
1027           else
1028             continue;
1029
1030           if (g_hash_table_lookup (found_versions, version) != NULL)
1031             {
1032               g_free (version);
1033               continue;
1034             }
1035           g_hash_table_insert (found_versions, version, version);
1036
1037           path = g_build_filename (dirname, entry, NULL);
1038           mfile = g_mapped_file_new (path, FALSE, &error);
1039           if (mfile == NULL)
1040             {
1041               g_free (path);
1042               g_free (version);
1043               g_clear_error (&error);
1044               continue;
1045             }
1046           candidate = g_slice_new0 (struct NamespaceVersionCandidadate);
1047           candidate->mfile = mfile;
1048           candidate->path_index = index;
1049           candidate->path = path;
1050           candidate->version = version;
1051           candidates = g_slist_prepend (candidates, candidate);
1052         }
1053       g_dir_close (dir);
1054       index++;
1055     }
1056
1057   g_free (namespace_dash);
1058   g_free (namespace_typelib);
1059   g_hash_table_destroy (found_versions);
1060
1061   return candidates;
1062 }
1063
1064 static GMappedFile *
1065 find_namespace_latest (const gchar  *namespace,
1066                        GSList       *search_path,
1067                        gchar       **version_ret,
1068                        gchar       **path_ret)
1069 {
1070   GSList *candidates;
1071   GMappedFile *result = NULL;
1072
1073   *version_ret = NULL;
1074   *path_ret = NULL;
1075
1076   candidates = enumerate_namespace_versions (namespace, search_path);
1077
1078   if (candidates != NULL)
1079     {
1080       struct NamespaceVersionCandidadate *elected;
1081       candidates = g_slist_sort (candidates, (GCompareFunc) compare_candidate_reverse);
1082
1083       elected = (struct NamespaceVersionCandidadate *) candidates->data;
1084       /* Remove the elected one so we don't try to free its contents */
1085       candidates = g_slist_delete_link (candidates, candidates);
1086
1087       result = elected->mfile;
1088       *path_ret = elected->path;
1089       *version_ret = elected->version;
1090       g_slice_free (struct NamespaceVersionCandidadate, elected); /* just free the container */
1091       g_slist_foreach (candidates, (GFunc) free_candidate, NULL);
1092       g_slist_free (candidates);
1093     }
1094   return result;
1095 }
1096
1097 /**
1098  * g_irepository_enumerate_versions:
1099  * @repository: (allow-none): the repository
1100  * @namespace_: GI namespace, e.g. "Gtk"
1101  *
1102  * Obtain an unordered list of versions (either currently loaded or
1103  * available) for @namespace_ in this @repository.
1104  *
1105  * Returns: (element-type utf8) (transfer full): the array of versions.
1106  */
1107 GList *
1108 g_irepository_enumerate_versions (GIRepository *repository,
1109                          const gchar  *namespace_)
1110 {
1111   GList *ret = NULL;
1112   GSList *search_path;
1113   GSList *candidates, *link;
1114   const gchar *loaded_version;
1115
1116   search_path = build_search_path_with_overrides ();
1117   candidates = enumerate_namespace_versions (namespace_, search_path);
1118   g_slist_free (search_path);
1119
1120   for (link = candidates; link; link = link->next)
1121     {
1122       struct NamespaceVersionCandidadate *candidate = link->data;
1123       ret = g_list_prepend (ret, g_strdup (candidate->version));
1124       free_candidate (candidate);
1125     }
1126   g_slist_free (candidates);
1127
1128   /* The currently loaded version of a namespace is also part of the
1129    * available versions, as it could have been loaded using
1130    * require_private().
1131    */
1132   if (g_irepository_is_registered (repository, namespace_, NULL))
1133     {
1134       loaded_version = g_irepository_get_version (repository, namespace_);
1135       if (loaded_version && !g_list_find_custom (ret, loaded_version, g_str_equal))
1136         ret = g_list_prepend (ret, g_strdup (loaded_version));
1137     }
1138
1139   return ret;
1140 }
1141
1142 static GITypelib *
1143 require_internal (GIRepository  *repository,
1144                   const gchar   *namespace,
1145                   const gchar   *version,
1146                   GIRepositoryLoadFlags flags,
1147                   GSList        *search_path,
1148                   GError       **error)
1149 {
1150   GMappedFile *mfile;
1151   GITypelib *ret = NULL;
1152   Header *header;
1153   GITypelib *typelib = NULL;
1154   const gchar *typelib_namespace, *typelib_version;
1155   gboolean allow_lazy = (flags & G_IREPOSITORY_LOAD_FLAG_LAZY) > 0;
1156   gboolean is_lazy;
1157   char *version_conflict = NULL;
1158   char *path = NULL;
1159   char *tmp_version = NULL;
1160
1161   g_return_val_if_fail (namespace != NULL, FALSE);
1162
1163   repository = get_repository (repository);
1164
1165   typelib = get_registered_status (repository, namespace, version, allow_lazy,
1166                                    &is_lazy, &version_conflict);
1167   if (typelib)
1168     return typelib;
1169
1170   if (version_conflict != NULL)
1171     {
1172       g_set_error (error, G_IREPOSITORY_ERROR,
1173                    G_IREPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
1174                    "Requiring namespace '%s' version '%s', but '%s' is already loaded",
1175                    namespace, version, version_conflict);
1176       return NULL;
1177     }
1178
1179   if (version != NULL)
1180     {
1181       mfile = find_namespace_version (namespace, version,
1182                                       search_path, &path);
1183       tmp_version = g_strdup (version);
1184     }
1185   else
1186     {
1187       mfile = find_namespace_latest (namespace, search_path,
1188                                      &tmp_version, &path);
1189     }
1190
1191   if (mfile == NULL)
1192     {
1193       if (version != NULL)
1194         g_set_error (error, G_IREPOSITORY_ERROR,
1195                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1196                      "Typelib file for namespace '%s', version '%s' not found",
1197                      namespace, version);
1198       else
1199         g_set_error (error, G_IREPOSITORY_ERROR,
1200                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1201                      "Typelib file for namespace '%s' (any version) not found",
1202                      namespace);
1203       goto out;
1204     }
1205
1206   {
1207     GError *temp_error = NULL;
1208     typelib = g_typelib_new_from_mapped_file (mfile, &temp_error);
1209     if (!typelib)
1210       {
1211         g_set_error (error, G_IREPOSITORY_ERROR,
1212                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1213                      "Failed to load typelib file '%s' for namespace '%s': %s",
1214                      path, namespace, temp_error->message);
1215         g_clear_error (&temp_error);
1216         goto out;
1217       }
1218   }
1219   header = (Header *) typelib->data;
1220   typelib_namespace = g_typelib_get_string (typelib, header->namespace);
1221   typelib_version = g_typelib_get_string (typelib, header->nsversion);
1222
1223   if (strcmp (typelib_namespace, namespace) != 0)
1224     {
1225       g_set_error (error, G_IREPOSITORY_ERROR,
1226                    G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
1227                    "Typelib file %s for namespace '%s' contains "
1228                    "namespace '%s' which doesn't match the file name",
1229                    path, namespace, typelib_namespace);
1230       g_typelib_free (typelib);
1231       goto out;
1232     }
1233   if (version != NULL && strcmp (typelib_version, version) != 0)
1234     {
1235       g_set_error (error, G_IREPOSITORY_ERROR,
1236                    G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
1237                    "Typelib file %s for namespace '%s' contains "
1238                    "version '%s' which doesn't match the expected version '%s'",
1239                    path, namespace, typelib_version, version);
1240       g_typelib_free (typelib);
1241       goto out;
1242     }
1243
1244   if (!register_internal (repository, path, allow_lazy,
1245                           typelib, error))
1246     {
1247       g_typelib_free (typelib);
1248       goto out;
1249     }
1250   ret = typelib;
1251  out:
1252   g_free (tmp_version);
1253   g_free (path);
1254   return ret;
1255 }
1256
1257 /**
1258  * g_irepository_require:
1259  * @repository: (allow-none): Repository, may be %NULL for the default
1260  * @namespace_: GI namespace to use, e.g. "Gtk"
1261  * @version: (allow-none): Version of namespace, may be %NULL for latest
1262  * @flags: Set of %GIRepositoryLoadFlags, may be 0
1263  * @error: a #GError.
1264  *
1265  * Force the namespace @namespace_ to be loaded if it isn't already.
1266  * If @namespace_ is not loaded, this function will search for a
1267  * ".typelib" file using the repository search path.  In addition, a
1268  * version @version of namespace may be specified.  If @version is
1269  * not specified, the latest will be used.
1270  *
1271  * Returns: (transfer none): a pointer to the #GITypelib if successful, %NULL otherwise
1272  */
1273 GITypelib *
1274 g_irepository_require (GIRepository  *repository,
1275                        const gchar   *namespace,
1276                        const gchar   *version,
1277                        GIRepositoryLoadFlags flags,
1278                        GError       **error)
1279 {
1280   GSList *search_path;
1281   GITypelib *typelib;
1282
1283   search_path = build_search_path_with_overrides ();
1284   typelib = require_internal (repository, namespace, version, flags,
1285                               search_path, error);
1286   g_slist_free (search_path);
1287
1288   return typelib;
1289 }
1290
1291 /**
1292  * g_irepository_require_private:
1293  * @repository: (allow-none): Repository, may be %NULL for the default
1294  * @typelib_dir: Private directory where to find the requested typelib
1295  * @namespace_: GI namespace to use, e.g. "Gtk"
1296  * @version: (allow-none): Version of namespace, may be %NULL for latest
1297  * @flags: Set of %GIRepositoryLoadFlags, may be 0
1298  * @error: a #GError.
1299  *
1300  * Force the namespace @namespace_ to be loaded if it isn't already.
1301  * If @namespace_ is not loaded, this function will search for a
1302  * ".typelib" file within the private directory only. In addition, a
1303  * version @version of namespace should be specified.  If @version is
1304  * not specified, the latest will be used.
1305  *
1306  * Returns: (transfer none): a pointer to the #GITypelib if successful, %NULL otherwise
1307  */
1308 GITypelib *
1309 g_irepository_require_private (GIRepository  *repository,
1310                                const gchar   *typelib_dir,
1311                                const gchar   *namespace,
1312                                const gchar   *version,
1313                                GIRepositoryLoadFlags flags,
1314                                GError       **error)
1315 {
1316   GSList search_path = { (gpointer) typelib_dir, NULL };
1317
1318   return require_internal (repository, namespace, version, flags,
1319                            &search_path, error);
1320 }
1321
1322 static gboolean
1323 g_irepository_introspect_cb (const char *option_name,
1324                              const char *value,
1325                              gpointer data,
1326                              GError **error)
1327 {
1328   GError *tmp_error = NULL;
1329   gboolean ret = g_irepository_dump (value, &tmp_error);
1330   if (!ret)
1331     {
1332       g_error ("Failed to extract GType data: %s",
1333                tmp_error->message);
1334       exit (1);
1335     }
1336   exit (0);
1337 }
1338
1339 static const GOptionEntry introspection_args[] = {
1340   { "introspect-dump", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK,
1341     g_irepository_introspect_cb, "Dump introspection information",
1342     "infile.txt,outfile.xml" },
1343   { NULL }
1344 };
1345
1346 /**
1347  * g_irepository_get_option_group: (skip)
1348  *
1349  * Obtain the option group for girepository, it's used
1350  * by the dumper and for programs that wants to provide
1351  * introspection information
1352  *
1353  * Returns: (transfer full): the option group
1354  */
1355 GOptionGroup *
1356 g_irepository_get_option_group (void)
1357 {
1358   GOptionGroup *group;
1359   group = g_option_group_new ("girepository", "Introspection Options", "Show Introspection Options", NULL, NULL);
1360
1361   g_option_group_add_entries (group, introspection_args);
1362   return group;
1363 }
1364
1365 GQuark
1366 g_irepository_error_quark (void)
1367 {
1368   static GQuark quark = 0;
1369   if (quark == 0)
1370     quark = g_quark_from_static_string ("g-irepository-error-quark");
1371   return quark;
1372 }
1373
1374 /**
1375  * g_type_tag_to_string:
1376  * @type: the type_tag
1377  *
1378  * Obtain a string representation of @type
1379  *
1380  * Returns: the string
1381  */
1382 const gchar*
1383 g_type_tag_to_string (GITypeTag type)
1384 {
1385   switch (type)
1386     {
1387     case GI_TYPE_TAG_VOID:
1388       return "void";
1389     case GI_TYPE_TAG_BOOLEAN:
1390       return "gboolean";
1391     case GI_TYPE_TAG_INT8:
1392       return "gint8";
1393     case GI_TYPE_TAG_UINT8:
1394       return "guint8";
1395     case GI_TYPE_TAG_INT16:
1396       return "gint16";
1397     case GI_TYPE_TAG_UINT16:
1398       return "guint16";
1399     case GI_TYPE_TAG_INT32:
1400       return "gint32";
1401     case GI_TYPE_TAG_UINT32:
1402       return "guint32";
1403     case GI_TYPE_TAG_INT64:
1404       return "gint64";
1405     case GI_TYPE_TAG_UINT64:
1406       return "guint64";
1407     case GI_TYPE_TAG_FLOAT:
1408       return "gfloat";
1409     case GI_TYPE_TAG_DOUBLE:
1410       return "gdouble";
1411     case GI_TYPE_TAG_UNICHAR:
1412       return "gunichar";
1413     case GI_TYPE_TAG_GTYPE:
1414       return "GType";
1415     case GI_TYPE_TAG_UTF8:
1416       return "utf8";
1417     case GI_TYPE_TAG_FILENAME:
1418       return "filename";
1419     case GI_TYPE_TAG_ARRAY:
1420       return "array";
1421     case GI_TYPE_TAG_INTERFACE:
1422       return "interface";
1423     case GI_TYPE_TAG_GLIST:
1424       return "glist";
1425     case GI_TYPE_TAG_GSLIST:
1426       return "gslist";
1427     case GI_TYPE_TAG_GHASH:
1428       return "ghash";
1429     case GI_TYPE_TAG_ERROR:
1430       return "error";
1431     default:
1432       return "unknown";
1433     }
1434 }
1435
1436 /**
1437  * g_info_type_to_string:
1438  * @type: the info type
1439  *
1440  * Obtain a string representation of @type
1441  *
1442  * Returns: the string
1443  */
1444 const gchar*
1445 g_info_type_to_string (GIInfoType type)
1446 {
1447   switch (type)
1448     {
1449     case GI_INFO_TYPE_INVALID:
1450       return "invalid";
1451     case GI_INFO_TYPE_FUNCTION:
1452       return "function";
1453     case GI_INFO_TYPE_CALLBACK:
1454       return "callback";
1455     case GI_INFO_TYPE_STRUCT:
1456       return "struct";
1457     case GI_INFO_TYPE_BOXED:
1458       return "boxed";
1459     case GI_INFO_TYPE_ENUM:
1460       return "enum";
1461     case GI_INFO_TYPE_FLAGS:
1462       return "flags";
1463     case GI_INFO_TYPE_OBJECT:
1464       return "object";
1465     case GI_INFO_TYPE_INTERFACE:
1466       return "interface";
1467     case GI_INFO_TYPE_CONSTANT:
1468       return "constant";
1469     case GI_INFO_TYPE_ERROR_DOMAIN:
1470       return "error domain";
1471     case GI_INFO_TYPE_UNION:
1472       return "union";
1473     case GI_INFO_TYPE_VALUE:
1474       return "value";
1475     case GI_INFO_TYPE_SIGNAL:
1476       return "signal";
1477     case GI_INFO_TYPE_VFUNC:
1478       return "vfunc";
1479     case GI_INFO_TYPE_PROPERTY:
1480       return "property";
1481     case GI_INFO_TYPE_FIELD:
1482       return "field";
1483     case GI_INFO_TYPE_ARG:
1484       return "arg";
1485     case GI_INFO_TYPE_TYPE:
1486       return "type";
1487     case GI_INFO_TYPE_UNRESOLVED:
1488       return "unresolved";
1489     default:
1490       return "unknown";
1491   }
1492 }