Document g_irepository_get_dependencies
[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
27 #include <glib.h>
28 #include <glib/gprintf.h>
29 #include <gmodule.h>
30 #include "girepository.h"
31 #include "gtypelib.h"
32
33 static GStaticMutex globals_lock = G_STATIC_MUTEX_INIT;
34 static GIRepository *default_repository = NULL;
35 static GSList *search_path = NULL;
36
37 struct _GIRepositoryPrivate 
38 {
39   GHashTable *typelibs; /* (string) namespace -> GTypelib */
40   GHashTable *lazy_typelibs; /* (string) namespace-version -> GTypelib */
41 };
42
43 G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT);
44
45 static void 
46 g_irepository_init (GIRepository *repository)
47 {
48   repository->priv = G_TYPE_INSTANCE_GET_PRIVATE (repository, G_TYPE_IREPOSITORY,
49                                                   GIRepositoryPrivate);
50   repository->priv->typelibs 
51     = g_hash_table_new_full (g_str_hash, g_str_equal,
52                              (GDestroyNotify) NULL,
53                              (GDestroyNotify) g_typelib_free);
54   repository->priv->lazy_typelibs 
55     = g_hash_table_new (g_str_hash, g_str_equal);
56 }
57
58 static void
59 g_irepository_finalize (GObject *object)
60 {
61   GIRepository *repository = G_IREPOSITORY (object);
62
63   g_hash_table_destroy (repository->priv->typelibs);
64   g_hash_table_destroy (repository->priv->lazy_typelibs);
65   
66   (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
67 }
68
69 static void
70 g_irepository_class_init (GIRepositoryClass *class)
71 {
72   GObjectClass *gobject_class;
73
74   gobject_class = G_OBJECT_CLASS (class);
75
76   gobject_class->finalize = g_irepository_finalize;
77
78   g_type_class_add_private (class, sizeof (GIRepositoryPrivate)); 
79 }
80
81 static void
82 init_globals ()
83 {
84   g_static_mutex_lock (&globals_lock);
85
86   if (default_repository == NULL) 
87     { 
88       default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL);
89     }
90
91   if (search_path == NULL)
92     {
93       const gchar *const *datadirs;
94       const gchar *const *dir;
95       
96       datadirs = g_get_system_data_dirs ();
97       
98       search_path = NULL;
99       for (dir = datadirs; *dir; dir++) {
100         char *path = g_build_filename (*dir, "girepository", NULL);
101         search_path = g_slist_prepend (search_path, path);
102       }
103       search_path = g_slist_reverse (search_path);
104     }
105
106   g_static_mutex_unlock (&globals_lock);
107 }
108
109 void
110 g_irepository_prepend_search_path (const char *directory)
111 {
112   init_globals ();
113   search_path = g_slist_prepend (search_path, g_strdup (directory));
114 }
115
116 static char *
117 build_typelib_key (const char *name, const char *source)
118 {
119   GString *str = g_string_new (name);
120   g_string_append_c (str, '\0');
121   g_string_append (str, source);
122   return g_string_free (str, FALSE);
123 }
124
125 static char **
126 get_typelib_dependencies (GTypelib *typelib)
127 {
128   Header *header;
129   const char *dependencies_glob;
130
131   header = (Header *)typelib->data;
132
133   if (header->dependencies == 0)
134     return NULL;
135
136   dependencies_glob = g_typelib_get_string (typelib, header->dependencies);
137   return g_strsplit (dependencies_glob, "|", 0);
138 }
139
140 static GIRepository *
141 get_repository (GIRepository *repository)
142 {
143   if (repository != NULL)
144     return repository;
145   else 
146     {
147       init_globals ();
148       return default_repository;
149     }
150 }
151
152 static GTypelib *
153 check_version_conflict (GTypelib *typelib, 
154                         const gchar *namespace,
155                         const gchar *expected_version,
156                         char       **version_conflict)
157 {
158   Header *header;
159   const char *loaded_version;
160
161   if (expected_version == NULL)
162     {
163       if (version_conflict)
164         *version_conflict = NULL;
165       return typelib;
166     }
167   
168   header = (Header*)typelib->data;
169   loaded_version = g_typelib_get_string (typelib, header->nsversion);
170   g_assert (loaded_version != NULL);
171   
172   if (strcmp (expected_version, loaded_version) != 0)
173     {
174       if (version_conflict)
175         *version_conflict = (char*)loaded_version;
176       return NULL;
177     }
178   if (version_conflict)
179     *version_conflict = NULL;
180   return typelib;
181 }
182
183 static GTypelib *
184 get_registered_status (GIRepository *repository,
185                        const char   *namespace,
186                        const char   *version,
187                        gboolean      allow_lazy,
188                        gboolean     *lazy_status,
189                        char        **version_conflict)
190 {
191   GTypelib *typelib;
192   repository = get_repository (repository);
193   if (lazy_status)
194     *lazy_status = FALSE;
195   typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
196   if (typelib) 
197     return check_version_conflict (typelib, namespace, version, version_conflict);
198   typelib = g_hash_table_lookup (repository->priv->lazy_typelibs, namespace);
199   if (!typelib)
200     return NULL;
201   if (lazy_status)
202     *lazy_status = TRUE;
203   if (!allow_lazy)
204     return NULL;
205   return check_version_conflict (typelib, namespace, version, version_conflict);
206 }
207
208 static GTypelib *
209 get_registered (GIRepository *repository,
210                 const char   *namespace,
211                 const char   *version)
212 {
213   return get_registered_status (repository, namespace, version, TRUE, NULL, NULL);
214 }
215
216 static gboolean
217 load_dependencies_recurse (GIRepository *repository,
218                            GTypelib     *typelib,
219                            GError      **error)
220 {
221   char **dependencies;
222
223   dependencies = get_typelib_dependencies (typelib);
224
225   if (dependencies != NULL)
226     {
227       int i;
228           
229       for (i = 0; dependencies[i]; i++)
230         {
231           char *dependency = dependencies[i];
232           const char *last_dash;
233           char *dependency_namespace;
234           const char *dependency_version;
235
236           last_dash = strrchr (dependency, '-');
237           dependency_namespace = g_strndup (dependency, last_dash - dependency);
238           dependency_version = last_dash+1;
239               
240           if (!g_irepository_require (repository, dependency_namespace, dependency_version,
241                                       0, error))
242             {
243               g_free (dependency_namespace);
244               g_strfreev (dependencies);
245               return FALSE;
246             }
247           g_free (dependency_namespace);
248         }
249       g_strfreev (dependencies);
250     }
251   return TRUE;
252 }
253
254 static const char *
255 register_internal (GIRepository *repository,
256                    const char   *source,
257                    gboolean      lazy,
258                    GTypelib     *typelib,
259                    GError      **error)
260 {
261   Header *header;
262   const gchar *namespace;
263   const gchar *version;
264   gboolean was_loaded;
265   gboolean currently_lazy;
266
267   g_return_val_if_fail (typelib != NULL, FALSE);
268   
269   header = (Header *)typelib->data;
270
271   g_return_val_if_fail (header != NULL, FALSE);
272
273   namespace = g_typelib_get_string (typelib, header->namespace);
274   version = g_typelib_get_string (typelib, header->nsversion);
275
276   if (lazy)
277     {
278       g_assert (!g_hash_table_lookup (repository->priv->lazy_typelibs, 
279                                       namespace));
280       g_hash_table_insert (repository->priv->lazy_typelibs, 
281                            build_typelib_key (namespace, source), (void *)typelib);
282     }
283   else
284     {
285       gpointer value;
286       char *key;
287
288       /* First, try loading all the dependencies */
289       if (!load_dependencies_recurse (repository, typelib, error))
290         return NULL;
291       
292       /* Check if we are transitioning from lazily loaded state */
293       if (g_hash_table_lookup_extended (repository->priv->lazy_typelibs, 
294                                         namespace,
295                                         (gpointer)&key, &value))
296         g_hash_table_remove (repository->priv->lazy_typelibs, key);
297       else
298         key = build_typelib_key (namespace, source);
299
300       g_hash_table_insert (repository->priv->typelibs, key, (void *)typelib);
301     }
302
303   if (typelib->modules == NULL)
304     typelib->modules = g_list_append(typelib->modules, g_module_open (NULL, 0));
305
306   return namespace;
307 }
308
309 /**
310  * g_irepository_get_dependencies
311  * @repository: A #GIRepository, may be %NULL for the default
312  * @namespace: Namespace of interest
313  *
314  * Return an array of all (transitive) dependencies for namespace
315  * @namespace, including version.  The returned strings are of the
316  * form <code>namespace-version</code>.
317  *
318  * Note: The namespace must have already been loaded using a function
319  * such as #g_irepository_require before calling this function.
320  *
321  * Returns: Zero-terminated string array of versioned dependencies
322  */
323 char **
324 g_irepository_get_dependencies (GIRepository *repository,
325                                 const char *namespace)
326 {
327   GTypelib *typelib;
328
329   g_return_val_if_fail (namespace != NULL, NULL);
330
331   repository = get_repository (repository);
332
333   typelib = get_registered (repository, namespace, NULL);
334   g_return_val_if_fail (typelib != NULL, NULL);
335
336   return get_typelib_dependencies (typelib);
337 }
338
339 const char *
340 g_irepository_load_typelib (GIRepository *repository,
341                             GTypelib     *typelib,
342                             GIRepositoryLoadFlags flags,
343                             GError      **error)
344 {
345   Header *header;
346   const char *namespace;
347   const char *nsversion;
348   gboolean allow_lazy = flags & G_IREPOSITORY_LOAD_FLAG_LAZY;
349   gboolean is_lazy;
350   char *version_conflict;
351
352   repository = get_repository (repository);
353
354   header = (Header *) typelib->data;
355   namespace = g_typelib_get_string (typelib, header->namespace);
356   nsversion = g_typelib_get_string (typelib, header->nsversion);
357
358   if (get_registered_status (repository, namespace, nsversion, allow_lazy, 
359                              &is_lazy, &version_conflict))
360     {
361       if (version_conflict != NULL)
362         {
363           g_set_error (error, G_IREPOSITORY_ERROR,
364                        G_IREPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
365                        "Attempting to load namespace '%s', version '%s', but '%s' is already loaded",
366                        namespace, nsversion, version_conflict);
367           return NULL;
368         }
369       return namespace;
370     }
371   return register_internal (repository, "<builtin>", 
372                             allow_lazy, typelib, error);
373 }
374
375 /**
376  * g_irepository_is_registered
377  * @repository: A #GIRepository, may be %NULL for the default
378  * @namespace: Namespace of interest
379  * @version: <allow-none>: Required version, may be %NULL for latest
380  *
381  * Check whether a particular namespace (and optionally, a specific
382  * version thereof) is currently loaded.  This function is likely to
383  * only be useful in unusual circumstances; in order to act upon
384  * metadata in the namespace, you should call #g_irepository_require
385  * instead which will ensure the namespace is loaded, and return as
386  * quickly as this function will if it has already been loaded.
387  * 
388  * Returns: %TRUE if namespace-version is loaded, %FALSE otherwise
389  */
390 gboolean
391 g_irepository_is_registered (GIRepository *repository, 
392                              const gchar *namespace,
393                              const gchar *version)
394 {
395   repository = get_repository (repository);
396   return get_registered (repository, namespace, version) != NULL;
397 }
398
399 /**
400  * g_irepository_get_default
401  *
402  * Returns the singleton process-global default #GIRepository.  It is
403  * not currently supported to have multiple repositories in a
404  * particular process, but this function is provided in the unlikely
405  * eventuality that it would become possible, and as a convenience for
406  * higher level language bindings to conform to the GObject method
407  * call conventions.
408
409  * All methods on #GIRepository also accept %NULL as an instance
410  * parameter to mean this default repository, which is usually more
411  * convenient for C.
412  * 
413  * Returns: The global singleton #GIRepository 
414  */
415 GIRepository * 
416 g_irepository_get_default (void)
417 {
418   return get_repository (NULL);
419 }
420
421 static void 
422 count_interfaces (gpointer key,
423                   gpointer value,
424                   gpointer data)
425 {
426   guchar *typelib = ((GTypelib *) value)->data;
427   gint *n_interfaces = (gint *)data;
428   
429   *n_interfaces += ((Header *)typelib)->n_local_entries;
430 }
431
432 /**
433  * g_irepository_get_n_infos
434  * @repository: A #GIRepository, may be %NULL for the default
435  * @namespace: Namespace to inspect
436  *
437  * This function returns the number of metadata entries in
438  * given namespace @namespace.  The namespace must have
439  * already been loaded before calling this function.
440  *
441  * Returns: number of metadata entries
442  */
443 gint                   
444 g_irepository_get_n_infos (GIRepository *repository,
445                            const gchar  *namespace)
446 {
447   GTypelib *typelib;
448   gint n_interfaces = 0;
449
450   g_return_val_if_fail (namespace != NULL, -1);
451
452   repository = get_repository (repository);
453   
454   typelib = get_registered (repository, namespace, NULL);
455
456   g_return_val_if_fail (typelib != NULL, -1);
457
458   n_interfaces = ((Header *)typelib->data)->n_local_entries;
459
460   return n_interfaces;
461 }
462
463 typedef struct
464 {
465   gint index;
466   const gchar *name;
467   const gchar *type;
468   GIBaseInfo *iface;
469 } IfaceData;
470
471 static void
472 find_interface (gpointer key,
473                 gpointer value,
474                 gpointer data)
475 {
476   gint i;
477   GTypelib *typelib = (GTypelib *)value;
478   IfaceData *iface_data = (IfaceData *)data;
479   gint index;
480   gint n_entries;
481   guint32 offset;
482   const gchar *name;
483   const gchar *type;
484   DirEntry *entry;    
485
486   index = 0;
487   n_entries = ((Header *)typelib->data)->n_local_entries;
488
489   if (iface_data->name)
490     {
491       for (i = 1; i <= n_entries; i++)
492         {
493           entry = g_typelib_get_dir_entry (typelib, i);
494           name = g_typelib_get_string (typelib, entry->name);
495           if (strcmp (name, iface_data->name) == 0)
496             {
497               index = i;
498               break;
499             }
500         }
501     }
502   else if (iface_data->type)
503     {
504       for (i = 1; i <= n_entries; i++)
505         {
506           RegisteredTypeBlob *blob;
507
508           entry = g_typelib_get_dir_entry (typelib, i);
509           if (!BLOB_IS_REGISTERED_TYPE (entry))
510             continue;
511
512           blob = (RegisteredTypeBlob *)(&typelib->data[entry->offset]);
513           if (!blob->gtype_name)
514             continue;
515
516           type = g_typelib_get_string (typelib, blob->gtype_name);
517           if (strcmp (type, iface_data->type) == 0)
518             {
519               index = i;
520               break;
521             }
522         }
523     }
524   else if (iface_data->index > n_entries)
525     iface_data->index -= n_entries;
526   else if (iface_data->index > 0)
527     {
528       index = iface_data->index;
529       iface_data->index = 0;
530     }
531
532   if (index != 0)
533     {
534       entry = g_typelib_get_dir_entry (typelib, index);
535       iface_data->iface = g_info_new (entry->blob_type, NULL,
536                                       typelib, entry->offset);
537     }
538 }
539
540 /**
541  * g_irepository_get_info
542  * @repository: A #GIRepository, may be %NULL for the default
543  * @namespace: Namespace to inspect
544  * @index: Offset into namespace metadata for entry
545  *
546  * This function returns a particular metadata entry in the
547  * given namespace @namespace.  The namespace must have
548  * already been loaded before calling this function.
549  *
550  * Returns: #GIBaseInfo containing metadata
551  */
552 GIBaseInfo * 
553 g_irepository_get_info (GIRepository *repository,
554                         const gchar  *namespace,
555                         gint          index)
556 {
557   IfaceData data;
558   GTypelib *typelib;
559
560   g_return_val_if_fail (namespace != NULL, NULL);
561
562   repository = get_repository (repository);
563
564   data.name = NULL;
565   data.type = NULL;
566   data.index = index + 1;
567   data.iface = NULL;
568
569   typelib = get_registered (repository, namespace, NULL);
570   
571   g_return_val_if_fail (typelib != NULL, NULL);
572
573   find_interface ((void *)namespace, typelib, &data);
574
575   return data.iface;  
576 }
577
578 /**
579  * g_irepository_find_by_gtype
580  * @repository: A #GIRepository, may be %NULL for the default
581  * @type: GType to search for
582  *
583  * Searches all loaded namespaces for a particular #GType.  Note that
584  * in order to locate the metadata, the namespace corresponding to
585  * the type must first have been loaded.  There is currently no
586  * mechanism for determining the namespace which corresponds to an
587  * arbitrary GType - thus, this function will function most reliably
588  * when you have expect the GType to be from a known namespace.
589  *
590  * Returns: #GIBaseInfo representing metadata about @type, or %NULL
591  */
592 GIBaseInfo * 
593 g_irepository_find_by_gtype (GIRepository *repository,
594                              GType         type)
595 {
596   IfaceData data;
597
598   repository = get_repository (repository);
599
600   data.name = NULL;
601   data.type = g_type_name (type);
602   data.index = -1;
603   data.iface = NULL;
604
605   g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
606   g_hash_table_foreach (repository->priv->lazy_typelibs, find_interface, &data);
607
608   return data.iface;
609 }
610
611 /**
612  * g_irepository_find_by_name
613  * @repository: A #GIRepository, may be %NULL for the default
614  * @namespace: Namespace which will be searched
615  * @name: Entry name to find
616  *
617  * Searches for a particular entry in a namespace.  Before calling
618  * this function for a particular namespace, you must call
619  * #g_irepository_require once to load the namespace, or otherwise
620  * ensure the namespace has already been loaded.
621  *
622  * Returns: #GIBaseInfo representing metadata about @name, or %NULL
623  */
624 GIBaseInfo * 
625 g_irepository_find_by_name (GIRepository *repository,
626                             const gchar  *namespace,
627                             const gchar  *name)
628 {
629   IfaceData data;
630   GTypelib *typelib;
631
632   g_return_val_if_fail (namespace != NULL, NULL);
633
634   repository = get_repository (repository);
635
636   data.name = name;
637   data.type = NULL;
638   data.index = -1;
639   data.iface = NULL;
640
641   typelib = get_registered (repository, namespace, NULL);
642   
643   g_return_val_if_fail (typelib != NULL, NULL);
644
645   find_interface ((void *)namespace, typelib, &data);
646
647   return data.iface;
648 }
649
650 static void
651 collect_namespaces (gpointer key,
652                     gpointer value,
653                     gpointer data)
654 {
655   GList **list = data;
656
657   *list = g_list_append (*list, key);
658 }
659
660 /**
661  * g_irepository_get_namespaces
662  * @repository: A #GIRepository, may be %NULL for the default
663  *
664  * Return the list of currently loaded namespaces.
665  *
666  * Returns: <utf8,transfer>: List of namespaces
667  */
668 gchar ** 
669 g_irepository_get_loaded_namespaces (GIRepository *repository)
670 {
671   GList *l, *list = NULL;
672   gchar **names;
673   gint i;
674
675   repository = get_repository (repository);
676
677   g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list);
678   g_hash_table_foreach (repository->priv->lazy_typelibs, collect_namespaces, &list);
679
680   names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
681   i = 0;
682   for (l = list; l; l = l->next)
683     names[i++] = g_strdup (l->data); 
684   g_list_free (list);
685
686   return names;
687 }
688
689 /**
690  * g_irepository_get_version
691  * @repository: A #GIRepository, may be %NULL for the default
692  * @namespace: Namespace to inspect
693  *
694  * This function returns the loaded version associated with the given
695  * namespace @namespace.
696  *
697  * Note: The namespace must have already been loaded using a function
698  * such as #g_irepository_require before calling this function.
699  *
700  * Returns: Loaded version
701  */
702 const gchar *
703 g_irepository_get_version (GIRepository *repository,
704                            const gchar  *namespace)
705 {
706   GTypelib *typelib;
707   Header *header;
708
709   g_return_val_if_fail (namespace != NULL, NULL);
710
711   repository = get_repository (repository);
712
713   typelib = get_registered (repository, namespace, NULL);
714
715   g_return_val_if_fail (typelib != NULL, NULL);
716
717   header = (Header *) typelib->data;
718   return g_typelib_get_string (typelib, header->nsversion);
719 }
720
721 /**
722  * g_irepository_get_shared_library
723  * @repository: A #GIRepository, may be %NULL for the default
724  * @namespace: Namespace to inspect
725  *
726  * This function returns the full path to the shared C library
727  * associated with the given namespace @namespace. There may be no
728  * shared library path associated, in which case this function will
729  * return %NULL.
730  *
731  * Note: The namespace must have already been loaded using a function
732  * such as #g_irepository_require before calling this function.
733  *
734  * Returns: Full path to shared library, or %NULL if none associated
735  */
736 const gchar *
737 g_irepository_get_shared_library (GIRepository *repository,
738                                   const gchar  *namespace)
739 {
740   GTypelib *typelib;
741   Header *header;
742
743   g_return_val_if_fail (namespace != NULL, NULL);
744
745   repository = get_repository (repository);
746
747   typelib = get_registered (repository, namespace, NULL);
748
749   g_return_val_if_fail (typelib != NULL, NULL);
750
751   header = (Header *) typelib->data;
752   if (header->shared_library)
753     return g_typelib_get_string (typelib, header->shared_library);
754   else
755     return NULL;
756 }
757
758 /**
759  * g_irepository_get_typelib_path
760  * @repository: Repository, may be %NULL for the default
761  * @namespace: GI namespace to use, e.g. "Gtk"
762  * @version: <allow-none>: Version of namespace to use, e.g. "0.8", may be %NULL
763  *
764  * If namespace @namespace is loaded, return the full path to the
765  * .typelib file it was loaded from.  If the typelib for 
766  * namespace @namespace was included in a shared library, return
767  * the special string "<builtin>".
768  *
769  * Returns: Filesystem path (or <builtin>) if successful, %NULL if namespace is not loaded
770  */
771
772 const gchar * 
773 g_irepository_get_typelib_path (GIRepository *repository,
774                                 const gchar  *namespace)
775 {
776   gpointer orig_key, value;
777
778   repository = get_repository (repository);
779
780   if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace,
781                                      &orig_key, &value))
782     {
783       if (!g_hash_table_lookup_extended (repository->priv->lazy_typelibs, namespace,
784                                          &orig_key, &value))
785         
786         return NULL;
787     }
788   return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
789 }
790
791 /* This simple search function looks for a specified namespace-version;
792    it's faster than the full directory listing required for latest version. */
793 static GMappedFile *
794 find_namespace_version (const gchar  *namespace,
795                         const gchar  *version,
796                         gchar       **path_ret)
797 {
798   GSList *ldir;
799   GError *error = NULL;
800   GMappedFile *mfile = NULL;
801   char *fname;
802  
803   fname = g_strdup_printf ("%s-%s.typelib", namespace, version);
804
805   for (ldir = search_path; ldir; ldir = ldir->next)
806     {
807       Header *header;
808       char *path = g_build_filename (ldir->data, fname, NULL);
809       
810       mfile = g_mapped_file_new (path, FALSE, &error);
811       if (error)
812         {
813           g_free (path);
814           g_clear_error (&error);
815           continue;
816         }
817       *path_ret = path;
818       break;
819     }
820   g_free (fname);
821   return mfile;
822 }
823
824 static gboolean
825 parse_version (const char *version,
826                int *major,
827                int *minor)
828 {
829   const char *dot;
830   const char *end;
831
832   *major = strtol (version, &end, 10);
833   dot = strchr (version, '.');
834   if (dot == NULL)
835     {
836       *minor = 0;
837       return TRUE;
838     }
839   if (dot != end)
840     return FALSE;
841   *minor = strtol (dot+1, &end, 10);
842   if (end != (version + strlen (version)))
843     return FALSE;
844   return TRUE;
845 }
846
847 static int
848 compare_version (const char *v1,
849                  const char *v2)
850 {
851   gboolean success;
852   int v1_major, v1_minor;
853   int v2_major, v2_minor;
854
855   success = parse_version (v1, &v1_major, &v1_minor);
856   g_assert (success);
857
858   success = parse_version (v2, &v2_major, &v2_minor);
859   g_assert (success);
860
861   if (v1_major > v2_major)
862     return 1;
863   else if (v2_major > v1_major)
864     return -1;
865   else if (v1_minor > v2_minor)
866     return 1;
867   else if (v2_minor > v1_minor)
868     return -1;
869   return 0;
870 }
871
872 struct NamespaceVersionCandidadate
873 {
874   GMappedFile *mfile;
875   char *path;
876   char *version;
877 };
878
879 static int
880 compare_candidate_reverse (struct NamespaceVersionCandidadate *c1,
881                            struct NamespaceVersionCandidadate *c2)
882 {
883   int result = compare_version (c1->version, c2->version);
884   if (result > 0)
885     return -1;
886   else if (result < 0)
887     return 1;
888   else
889     return 0;
890 }
891
892 static void
893 free_candidate (struct NamespaceVersionCandidadate *candidate)
894 {
895   g_mapped_file_free (candidate->mfile);
896   g_free (candidate->path);
897   g_free (candidate->version);
898   g_free (candidate);
899 }
900
901 static GMappedFile *
902 find_namespace_latest (const gchar  *namespace,
903                        gchar       **version_ret,
904                        gchar       **path_ret)
905 {
906   GSList *ldir;
907   GError *error = NULL;
908   char *namespace_dash;
909   char *namespace_typelib;
910   GSList *candidates = NULL;
911   GMappedFile *result = NULL;
912
913   *version_ret = NULL;
914   *path_ret = NULL;
915
916   namespace_dash = g_strdup_printf ("%s-", namespace);
917   namespace_typelib = g_strdup_printf ("%s.typelib", namespace);
918  
919   for (ldir = search_path; ldir; ldir = ldir->next)
920     {
921       GDir *dir;
922       const char *dirname;
923       const char *entry;
924
925       dirname = (const char*)ldir->data;
926       dir = g_dir_open (dirname, 0, NULL);
927       if (dir == NULL)
928         continue;
929       while ((entry = g_dir_read_name (dir)) != NULL) 
930         {
931           GMappedFile *mfile;
932           char *path, *version;
933           struct NamespaceVersionCandidadate *candidate;
934
935           if (!g_str_has_suffix (entry, ".typelib"))
936             continue;
937           
938           if (g_str_has_prefix (entry, namespace_dash))
939             {
940               const char *last_dash;
941               const char *name_end;
942               int major, minor;
943
944               name_end = strrchr (entry, '.');
945               last_dash = strrchr (entry, '-');
946               version = g_strndup (last_dash+1, name_end-(last_dash+1));
947               if (!parse_version (version, &major, &minor))
948                 continue;
949             }
950           else
951             continue;
952
953           path = g_build_filename (dirname, entry, NULL);
954           mfile = g_mapped_file_new (path, FALSE, &error);
955           if (mfile == NULL)
956             {
957               g_free (path);
958               g_free (version);
959               g_clear_error (&error);
960               continue;
961             }
962           candidate = g_new0 (struct NamespaceVersionCandidadate, 1);
963           candidate->mfile = mfile;
964           candidate->path = path;
965           candidate->version = version;
966           candidates = g_slist_prepend (candidates, candidate);
967         }
968       g_dir_close (dir);
969     }
970
971   if (candidates != NULL)
972     {
973       struct NamespaceVersionCandidadate *elected;
974       candidates = g_slist_sort (candidates, (GCompareFunc) compare_candidate_reverse);
975       
976       elected = (struct NamespaceVersionCandidadate *) candidates->data;
977       /* Remove the elected one so we don't try to free it */
978       candidates = g_slist_delete_link (candidates, candidates);
979       
980       result = elected->mfile;
981       *path_ret = elected->path;
982       *version_ret = elected->version;
983       g_slist_foreach (candidates, (GFunc) free_candidate, NULL);
984       g_slist_free (candidates);
985     }  
986
987   g_free (namespace_dash);
988   g_free (namespace_typelib);
989   return result;
990 }
991
992 /**
993  * g_irepository_require
994  * @repository: <allow-none>: Repository, may be %NULL for the default
995  * @namespace: GI namespace to use, e.g. "Gtk"
996  * @version: <allow-none>: Version of namespace, may be %NULL for latest
997  * @flags: Set of %GIRepositoryLoadFlags, may be %0
998  * @error: a #GError.
999  *
1000  * Force the namespace @namespace to be loaded if it isn't already.
1001  * If @namespace is not loaded, this function will search for a
1002  * ".typelib" file using the repository search path.  In addition, a
1003  * version @version of namespace may be specified.  If @version is
1004  * not specified, the latest will be used.
1005  *
1006  * Returns: %TRUE if successful, %NULL otherwise
1007  */
1008 gboolean
1009 g_irepository_require (GIRepository  *repository,
1010                        const gchar   *namespace,
1011                        const gchar   *version,
1012                        GIRepositoryLoadFlags flags,
1013                        GError       **error)
1014 {
1015   const char *dir;
1016   GMappedFile *mfile;
1017   gboolean ret = FALSE;
1018   GError *error1 = NULL;
1019   Header *header;
1020   GTypelib *typelib = NULL;
1021   const gchar *typelib_namespace, *typelib_version, *shlib_fname;
1022   GModule *module;
1023   guint32 shlib;
1024   gboolean allow_lazy = (flags & G_IREPOSITORY_LOAD_FLAG_LAZY) > 0;
1025   gboolean is_lazy;
1026   char *version_conflict = NULL;
1027   char *path = NULL;
1028   char *tmp_version = NULL;
1029
1030   g_return_val_if_fail (namespace != NULL, FALSE);
1031
1032   repository = get_repository (repository);
1033
1034   if (get_registered_status (repository, namespace, version, allow_lazy, 
1035                              &is_lazy, &version_conflict))
1036     return TRUE;
1037
1038   if (version_conflict != NULL)
1039     {
1040       g_set_error (error, G_IREPOSITORY_ERROR,
1041                    G_IREPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
1042                    "Requiring namespace '%s' version '%s', but '%s' is already loaded",
1043                    namespace, version, version_conflict);
1044       return FALSE;
1045     }
1046
1047   if (version != NULL)
1048     {
1049       mfile = find_namespace_version (namespace, version, &path);
1050       tmp_version = g_strdup (version);
1051     }
1052   else
1053     {
1054       mfile = find_namespace_latest (namespace, &tmp_version, &path);
1055     }
1056   
1057   if (mfile == NULL)
1058     {
1059       const char *error_fmt;
1060       if (version != NULL)
1061         g_set_error (error, G_IREPOSITORY_ERROR,
1062                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1063                      "Typelib file %s for namespace '%s', version '%s' not found",
1064                      namespace, version);
1065       else
1066         g_set_error (error, G_IREPOSITORY_ERROR,
1067                      G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
1068                      "Typelib file for namespace '%s' (any version) not found",
1069                      namespace);
1070       goto out;
1071     }
1072
1073   typelib = g_typelib_new_from_mapped_file (mfile);
1074   header = (Header *) typelib->data;
1075   typelib_namespace = g_typelib_get_string (typelib, header->namespace);
1076   typelib_version = g_typelib_get_string (typelib, header->nsversion);
1077   
1078   if (strcmp (typelib_namespace, namespace) != 0)
1079     {
1080       g_set_error (error, G_IREPOSITORY_ERROR,
1081                    G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
1082                    "Typelib file %s for namespace '%s' contains "
1083                    "namespace '%s' which doesn't match the file name",
1084                    path, namespace, typelib_namespace);
1085       goto out;
1086     }
1087   if (version != NULL && strcmp (typelib_version, version) != 0)
1088     {
1089       g_set_error (error, G_IREPOSITORY_ERROR,
1090                    G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
1091                    "Typelib file %s for namespace '%s' contains "
1092                    "version '%s' which doesn't match the expected version '%s'",
1093                    path, namespace, typelib_version, version);
1094       goto out;
1095     }
1096
1097   if (!register_internal (repository, path, allow_lazy, 
1098                           typelib, error))
1099     {
1100       g_typelib_free (typelib);
1101       goto out;
1102     }
1103   ret = TRUE;
1104  out:
1105   g_free (tmp_version);
1106   g_free (path);
1107   return ret; 
1108 }
1109
1110
1111 GQuark
1112 g_irepository_error_quark (void)
1113 {
1114   static GQuark quark = 0;
1115   if (quark == 0)
1116     quark = g_quark_from_static_string ("g-irepository-error-quark");
1117   return quark;
1118 }
1119
1120 const gchar*
1121 g_type_tag_to_string (GITypeTag type)
1122 {
1123   switch (type)
1124     {
1125     case GI_TYPE_TAG_VOID:
1126       return "void";
1127     case GI_TYPE_TAG_BOOLEAN:
1128       return "boolean";
1129     case GI_TYPE_TAG_INT8:
1130       return "int8";
1131     case GI_TYPE_TAG_UINT8:
1132       return "uint8";
1133     case GI_TYPE_TAG_INT16:
1134       return "int16";
1135     case GI_TYPE_TAG_UINT16:
1136       return "uint16";
1137     case GI_TYPE_TAG_INT32:
1138       return "int32";
1139     case GI_TYPE_TAG_UINT32:
1140       return "uint32";
1141     case GI_TYPE_TAG_INT64:
1142       return "int64";
1143     case GI_TYPE_TAG_UINT64:
1144       return "uint64";
1145     case GI_TYPE_TAG_INT:
1146       return "int";
1147     case GI_TYPE_TAG_UINT:
1148       return "uint";
1149     case GI_TYPE_TAG_LONG:
1150       return "long";
1151     case GI_TYPE_TAG_ULONG:
1152       return "ulong";
1153     case GI_TYPE_TAG_SSIZE:
1154       return "ssize";
1155     case GI_TYPE_TAG_SIZE:
1156       return "size";
1157     case GI_TYPE_TAG_FLOAT:
1158       return "float";
1159     case GI_TYPE_TAG_DOUBLE:
1160       return "double";
1161     case GI_TYPE_TAG_TIME_T:
1162       return "time_t";
1163     case GI_TYPE_TAG_GTYPE:
1164       return "GType";
1165     case GI_TYPE_TAG_UTF8:
1166       return "utf8";
1167     case GI_TYPE_TAG_FILENAME:
1168       return "filename";
1169     case GI_TYPE_TAG_ARRAY:
1170       return "array";
1171     case GI_TYPE_TAG_INTERFACE:
1172       return "interface";
1173     case GI_TYPE_TAG_GLIST:
1174       return "glist";
1175     case GI_TYPE_TAG_GSLIST:
1176       return "gslist";
1177     case GI_TYPE_TAG_GHASH:
1178       return "ghash";
1179     case GI_TYPE_TAG_ERROR:
1180       return "error";
1181     default:
1182       return "unknown";
1183     }
1184 }