ecdaab4da32ed603c7f2a3ca044ef808bf23494d
[platform/upstream/glib.git] / gio / giomodule.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "giomodule.h"
28 #include "giomodule-priv.h"
29 #include "gmemorysettingsbackend.h"
30 #include "glocalfilemonitor.h"
31 #include "glocaldirectorymonitor.h"
32 #include "gnativevolumemonitor.h"
33 #include "gproxyresolver.h"
34 #include "gproxy.h"
35 #include "gsocks4proxy.h"
36 #include "gsocks4aproxy.h"
37 #include "gsocks5proxy.h"
38 #include "gtlsbackend.h"
39 #include "gvfs.h"
40 #ifdef G_OS_WIN32
41 #include "gregistrysettingsbackend.h"
42 #endif
43 #include <glib/gstdio.h>
44
45 #undef G_DISABLE_DEPRECATED
46
47 #ifdef G_OS_UNIX
48 #include "gdesktopappinfo.h"
49 #endif
50
51 /**
52  * SECTION:giomodule
53  * @short_description: Loadable GIO Modules
54  * @include: gio/gio.h
55  *
56  * Provides an interface and default functions for loading and unloading 
57  * modules. This is used internally to make GIO extensible, but can also
58  * be used by others to implement module loading.
59  * 
60  **/
61
62 /**
63  * SECTION:extensionpoints
64  * @short_description: Extension Points
65  * @include: gio.h
66  * @see_also: <link linkend="extending-gio">Extending GIO</link>
67  *
68  * #GIOExtensionPoint provides a mechanism for modules to extend the
69  * functionality of the library or application that loaded it in an 
70  * organized fashion.  
71  *
72  * An extension point is identified by a name, and it may optionally
73  * require that any implementation must by of a certain type (or derived
74  * thereof). Use g_io_extension_point_register() to register an
75  * extension point, and g_io_extension_point_set_required_type() to
76  * set a required type.
77  *
78  * A module can implement an extension point by specifying the #GType 
79  * that implements the functionality. Additionally, each implementation
80  * of an extension point has a name, and a priority. Use
81  * g_io_extension_point_implement() to implement an extension point.
82  * 
83  *  |[
84  *  GIOExtensionPoint *ep;
85  *
86  *  /&ast; Register an extension point &ast;/
87  *  ep = g_io_extension_point_register ("my-extension-point");
88  *  g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE);
89  *  ]|
90  *
91  *  |[
92  *  /&ast; Implement an extension point &ast;/
93  *  G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE);
94  *  g_io_extension_point_implement ("my-extension-point",
95  *                                  my_example_impl_get_type (),
96  *                                  "my-example",
97  *                                  10);
98  *  ]|
99  *
100  *  It is up to the code that registered the extension point how
101  *  it uses the implementations that have been associated with it.
102  *  Depending on the use case, it may use all implementations, or
103  *  only the one with the highest priority, or pick a specific
104  *  one by name.
105  *
106  *  To avoid opening all modules just to find out what extension
107  *  points they implement, GIO makes use of a caching mechanism,
108  *  see <link linkend="gio-querymodules">gio-querymodules</link>.
109  *  You are expected to run this command after installing a
110  *  GIO module.
111  */
112 struct _GIOModule {
113   GTypeModule parent_instance;
114
115   gchar       *filename;
116   GModule     *library;
117   gboolean     initialized; /* The module was loaded at least once */
118
119   void (* load)   (GIOModule *module);
120   void (* unload) (GIOModule *module);
121 };
122
123 struct _GIOModuleClass
124 {
125   GTypeModuleClass parent_class;
126
127 };
128
129 static void      g_io_module_finalize      (GObject      *object);
130 static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
131 static void      g_io_module_unload_module (GTypeModule  *gmodule);
132
133 struct _GIOExtension {
134   char *name;
135   GType type;
136   gint priority;
137 };
138
139 struct _GIOExtensionPoint {
140   GType required_type;
141   char *name;
142   GList *extensions;
143   GList *lazy_load_modules;
144 };
145
146 static GHashTable *extension_points = NULL;
147 G_LOCK_DEFINE_STATIC(extension_points);
148
149 G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE);
150
151 static void
152 g_io_module_class_init (GIOModuleClass *class)
153 {
154   GObjectClass     *object_class      = G_OBJECT_CLASS (class);
155   GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
156
157   object_class->finalize     = g_io_module_finalize;
158
159   type_module_class->load    = g_io_module_load_module;
160   type_module_class->unload  = g_io_module_unload_module;
161 }
162
163 static void
164 g_io_module_init (GIOModule *module)
165 {
166 }
167
168 static void
169 g_io_module_finalize (GObject *object)
170 {
171   GIOModule *module = G_IO_MODULE (object);
172
173   g_free (module->filename);
174
175   G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
176 }
177
178 static gboolean
179 g_io_module_load_module (GTypeModule *gmodule)
180 {
181   GIOModule *module = G_IO_MODULE (gmodule);
182
183   if (!module->filename)
184     {
185       g_warning ("GIOModule path not set");
186       return FALSE;
187     }
188
189   module->library = g_module_open (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
190
191   if (!module->library)
192     {
193       g_printerr ("%s\n", g_module_error ());
194       return FALSE;
195     }
196
197   /* Make sure that the loaded library contains the required methods */
198   if (! g_module_symbol (module->library,
199                          "g_io_module_load",
200                          (gpointer) &module->load) ||
201       ! g_module_symbol (module->library,
202                          "g_io_module_unload",
203                          (gpointer) &module->unload))
204     {
205       g_printerr ("%s\n", g_module_error ());
206       g_module_close (module->library);
207
208       return FALSE;
209     }
210
211   /* Initialize the loaded module */
212   module->load (module);
213   module->initialized = TRUE;
214
215   return TRUE;
216 }
217
218 static void
219 g_io_module_unload_module (GTypeModule *gmodule)
220 {
221   GIOModule *module = G_IO_MODULE (gmodule);
222
223   module->unload (module);
224
225   g_module_close (module->library);
226   module->library = NULL;
227
228   module->load   = NULL;
229   module->unload = NULL;
230 }
231
232 /**
233  * g_io_module_new:
234  * @filename: filename of the shared library module.
235  * 
236  * Creates a new GIOModule that will load the specific
237  * shared library when in use.
238  * 
239  * Returns: a #GIOModule from given @filename, 
240  * or %NULL on error.
241  **/
242 GIOModule *
243 g_io_module_new (const gchar *filename)
244 {
245   GIOModule *module;
246
247   g_return_val_if_fail (filename != NULL, NULL);
248
249   module = g_object_new (G_IO_TYPE_MODULE, NULL);
250   module->filename = g_strdup (filename);
251
252   return module;
253 }
254
255 static gboolean
256 is_valid_module_name (const gchar *basename)
257 {
258 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
259   return
260     g_str_has_prefix (basename, "lib") &&
261     g_str_has_suffix (basename, ".so");
262 #else
263   return g_str_has_suffix (basename, ".dll");
264 #endif
265 }
266
267 /**
268  * g_io_modules_scan_all_in_directory:
269  * @dirname: pathname for a directory containing modules to scan.
270  *
271  * Scans all the modules in the specified directory, ensuring that
272  * any extension point implemented by a module is registered.
273  *
274  * This may not actually load and initialize all the types in each
275  * module, some modules may be lazily loaded and initialized when
276  * an extension point it implementes is used with e.g.
277  * g_io_extension_point_get_extensions() or
278  * g_io_extension_point_get_extension_by_name().
279  *
280  * If you need to guarantee that all types are loaded in all the modules,
281  * use g_io_modules_scan_all_in_directory().
282  *
283  * Since: 2.24
284  **/
285 void
286 g_io_modules_scan_all_in_directory (const char *dirname)
287 {
288   const gchar *name;
289   char *filename;
290   GDir *dir;
291   GStatBuf statbuf;
292   char *data;
293   time_t cache_mtime;
294   GHashTable *cache;
295
296   if (!g_module_supported ())
297     return;
298
299   dir = g_dir_open (dirname, 0, NULL);
300   if (!dir)
301     return;
302
303   filename = g_build_filename (dirname, "giomodule.cache", NULL);
304
305   cache = g_hash_table_new_full (g_str_hash, g_str_equal,
306                                  g_free, (GDestroyNotify)g_strfreev);
307
308   cache_mtime = 0;
309   if (g_stat (filename, &statbuf) == 0 &&
310       g_file_get_contents (filename, &data, NULL, NULL))
311     {
312       char **lines;
313       int i;
314
315       /* Cache mtime is the time the cache file was created, any file
316        * that has a ctime before this was created then and not modified
317        * since then (userspace can't change ctime). Its possible to change
318        * the ctime forward without changing the file content, by e.g.
319        * chmoding the file, but this is uncommon and will only cause us
320        * to not use the cache so will not cause bugs.
321        */
322       cache_mtime = statbuf.st_mtime;
323
324       lines = g_strsplit (data, "\n", -1);
325       g_free (data);
326
327       for (i = 0;  lines[i] != NULL; i++)
328         {
329           char *line = lines[i];
330           char *file;
331           char *colon;
332           char **extension_points;
333
334           if (line[0] == '#')
335             continue;
336
337           colon = strchr (line, ':');
338           if (colon == NULL || line == colon)
339             continue; /* Invalid line, ignore */
340
341           *colon = 0; /* terminate filename */
342           file = g_strdup (line);
343           colon++; /* after colon */
344
345           while (g_ascii_isspace (*colon))
346             colon++;
347
348           extension_points = g_strsplit (colon, ",", -1);
349           g_hash_table_insert (cache, file, extension_points);
350         }
351       g_strfreev (lines);
352     }
353
354   while ((name = g_dir_read_name (dir)))
355     {
356       if (is_valid_module_name (name))
357         {
358           GIOExtensionPoint *extension_point;
359           GIOModule *module;
360           gchar *path;
361           char **extension_points;
362           int i;
363
364           path = g_build_filename (dirname, name, NULL);
365           module = g_io_module_new (path);
366
367           extension_points = g_hash_table_lookup (cache, name);
368           if (extension_points != NULL &&
369               g_stat (path, &statbuf) == 0 &&
370               statbuf.st_ctime <= cache_mtime)
371             {
372               /* Lazy load/init the library when first required */
373               for (i = 0; extension_points[i] != NULL; i++)
374                 {
375                   extension_point =
376                     g_io_extension_point_register (extension_points[i]);
377                   extension_point->lazy_load_modules =
378                     g_list_prepend (extension_point->lazy_load_modules,
379                                     module);
380                 }
381             }
382           else
383             {
384               /* Try to load and init types */
385               if (g_type_module_use (G_TYPE_MODULE (module)))
386                 g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
387               else
388                 { /* Failure to load */
389                   g_printerr ("Failed to load module: %s\n", path);
390                   g_object_unref (module);
391                   g_free (path);
392                   continue;
393                 }
394             }
395
396           g_free (path);
397         }
398     }
399
400   g_dir_close (dir);
401
402   g_hash_table_destroy (cache);
403
404   g_free (filename);
405 }
406
407
408 /**
409  * g_io_modules_load_all_in_directory:
410  * @dirname: pathname for a directory containing modules to load.
411  *
412  * Loads all the modules in the specified directory.
413  *
414  * If don't require all modules to be initialized (and thus registering
415  * all gtypes) then you can use g_io_modules_scan_all_in_directory()
416  * which allows delayed/lazy loading of modules.
417  *
418  * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
419  *      from the directory,
420  *      All the modules are loaded into memory, if you want to
421  *      unload them (enabling on-demand loading) you must call
422  *      g_type_module_unuse() on all the modules. Free the list
423  *      with g_list_free().
424  **/
425 GList *
426 g_io_modules_load_all_in_directory (const char *dirname)
427 {
428   const gchar *name;
429   GDir        *dir;
430   GList *modules;
431
432   if (!g_module_supported ())
433     return NULL;
434
435   dir = g_dir_open (dirname, 0, NULL);
436   if (!dir)
437     return NULL;
438
439   modules = NULL;
440   while ((name = g_dir_read_name (dir)))
441     {
442       if (is_valid_module_name (name))
443         {
444           GIOModule *module;
445           gchar     *path;
446
447           path = g_build_filename (dirname, name, NULL);
448           module = g_io_module_new (path);
449
450           if (!g_type_module_use (G_TYPE_MODULE (module)))
451             {
452               g_printerr ("Failed to load module: %s\n", path);
453               g_object_unref (module);
454               g_free (path);
455               continue;
456             }
457           
458           g_free (path);
459
460           modules = g_list_prepend (modules, module);
461         }
462     }
463   
464   g_dir_close (dir);
465
466   return modules;
467 }
468
469 G_LOCK_DEFINE_STATIC (registered_extensions);
470 G_LOCK_DEFINE_STATIC (loaded_dirs);
471
472 extern GType _g_fen_directory_monitor_get_type (void);
473 extern GType _g_fen_file_monitor_get_type (void);
474 extern GType _g_inotify_directory_monitor_get_type (void);
475 extern GType _g_inotify_file_monitor_get_type (void);
476 extern GType _g_unix_volume_monitor_get_type (void);
477 extern GType _g_local_vfs_get_type (void);
478
479 extern GType _g_win32_volume_monitor_get_type (void);
480 extern GType g_win32_directory_monitor_get_type (void);
481 extern GType _g_winhttp_vfs_get_type (void);
482
483 extern GType _g_dummy_proxy_resolver_get_type (void);
484 extern GType _g_dummy_tls_backend_get_type (void);
485
486 #ifdef G_PLATFORM_WIN32
487
488 #include <windows.h>
489
490 static HMODULE gio_dll = NULL;
491
492 #ifdef DLL_EXPORT
493
494 BOOL WINAPI
495 DllMain (HINSTANCE hinstDLL,
496          DWORD     fdwReason,
497          LPVOID    lpvReserved)
498 {
499   if (fdwReason == DLL_PROCESS_ATTACH)
500       gio_dll = hinstDLL;
501
502   return TRUE;
503 }
504
505 #endif
506
507 #undef GIO_MODULE_DIR
508
509 /* GIO_MODULE_DIR is used only in code called just once,
510  * so no problem leaking this
511  */
512 #define GIO_MODULE_DIR \
513   g_build_filename (g_win32_get_package_installation_directory_of_module (gio_dll), \
514                     "lib/gio/modules", \
515                     NULL)
516
517 #endif
518
519 void
520 _g_io_modules_ensure_extension_points_registered (void)
521 {
522   static gboolean registered_extensions = FALSE;
523   GIOExtensionPoint *ep;
524
525   G_LOCK (registered_extensions);
526   
527   if (!registered_extensions)
528     {
529       registered_extensions = TRUE;
530       
531 #ifdef G_OS_UNIX
532 #if !GLIB_CHECK_VERSION (3, 0, 0)
533       ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
534       g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
535 #endif
536 #endif
537       
538       ep = g_io_extension_point_register (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME);
539       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_DIRECTORY_MONITOR);
540       
541       ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
542       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
543       
544       ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
545       g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
546       
547       ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
548       g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
549       
550       ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
551       g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
552
553       ep = g_io_extension_point_register ("gsettings-backend");
554       g_io_extension_point_set_required_type (ep, G_TYPE_OBJECT);
555
556       ep = g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
557       g_io_extension_point_set_required_type (ep, G_TYPE_PROXY_RESOLVER);
558
559       ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME);
560       g_io_extension_point_set_required_type (ep, G_TYPE_PROXY);
561
562       ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
563       g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND);
564     }
565   
566   G_UNLOCK (registered_extensions);
567  }
568
569 void
570 _g_io_modules_ensure_loaded (void)
571 {
572   static gboolean loaded_dirs = FALSE;
573   const char *module_path;
574
575   _g_io_modules_ensure_extension_points_registered ();
576   
577   G_LOCK (loaded_dirs);
578
579   if (!loaded_dirs)
580     {
581       loaded_dirs = TRUE;
582
583       g_io_modules_scan_all_in_directory (GIO_MODULE_DIR);
584
585       module_path = g_getenv ("GIO_EXTRA_MODULES");
586
587       if (module_path)
588         {
589           gchar **paths;
590           int i;
591
592           paths = g_strsplit (module_path, ":", 0);
593
594           for (i = 0; paths[i] != NULL; i++)
595             g_io_modules_scan_all_in_directory (paths[i]);
596
597           g_strfreev (paths);
598         }
599
600       /* Initialize types from built-in "modules" */
601       g_memory_settings_backend_get_type ();
602 #if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H)
603       _g_inotify_directory_monitor_get_type ();
604       _g_inotify_file_monitor_get_type ();
605 #endif
606 #if defined(HAVE_FEN)
607       _g_fen_directory_monitor_get_type ();
608       _g_fen_file_monitor_get_type ();
609 #endif
610 #ifdef G_OS_WIN32
611       _g_win32_volume_monitor_get_type ();
612       g_win32_directory_monitor_get_type ();
613       g_registry_backend_get_type ();
614 #endif
615 #ifdef G_OS_UNIX
616       _g_unix_volume_monitor_get_type ();
617 #endif
618 #ifdef G_OS_WIN32
619       _g_winhttp_vfs_get_type ();
620 #endif
621       _g_local_vfs_get_type ();
622       _g_dummy_proxy_resolver_get_type ();
623       _g_socks4a_proxy_get_type ();
624       _g_socks4_proxy_get_type ();
625       _g_socks5_proxy_get_type ();
626       _g_dummy_tls_backend_get_type ();
627     }
628
629   G_UNLOCK (loaded_dirs);
630 }
631
632 static void
633 g_io_extension_point_free (GIOExtensionPoint *ep)
634 {
635   g_free (ep->name);
636   g_free (ep);
637 }
638
639 /**
640  * g_io_extension_point_register:
641  * @name: The name of the extension point
642  *
643  * Registers an extension point.
644  *
645  * Returns: the new #GIOExtensionPoint. This object is owned by GIO
646  *    and should not be freed
647  */
648 GIOExtensionPoint *
649 g_io_extension_point_register (const char *name)
650 {
651   GIOExtensionPoint *ep;
652   
653   G_LOCK (extension_points);
654   if (extension_points == NULL)
655     extension_points = g_hash_table_new_full (g_str_hash,
656                                               g_str_equal,
657                                               NULL,
658                                               (GDestroyNotify)g_io_extension_point_free);
659
660   ep = g_hash_table_lookup (extension_points, name);
661   if (ep != NULL)
662     {
663       G_UNLOCK (extension_points);
664       return ep;
665     }
666
667   ep = g_new0 (GIOExtensionPoint, 1);
668   ep->name = g_strdup (name);
669   
670   g_hash_table_insert (extension_points, ep->name, ep);
671   
672   G_UNLOCK (extension_points);
673
674   return ep;
675 }
676
677 /**
678  * g_io_extension_point_lookup:
679  * @name: the name of the extension point
680  *
681  * Looks up an existing extension point.
682  *
683  * Returns: the #GIOExtensionPoint, or %NULL if there is no
684  *    registered extension point with the given name
685  */
686 GIOExtensionPoint *
687 g_io_extension_point_lookup (const char *name)
688 {
689   GIOExtensionPoint *ep;
690
691   G_LOCK (extension_points);
692   ep = NULL;
693   if (extension_points != NULL)
694     ep = g_hash_table_lookup (extension_points, name);
695   
696   G_UNLOCK (extension_points);
697
698   return ep;
699   
700 }
701
702 /**
703  * g_io_extension_point_set_required_type:
704  * @extension_point: a #GIOExtensionPoint
705  * @type: the #GType to require
706  *
707  * Sets the required type for @extension_point to @type. 
708  * All implementations must henceforth have this type.
709  */
710 void
711 g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
712                                         GType              type)
713 {
714   extension_point->required_type = type;
715 }
716
717 /**
718  * g_io_extension_point_get_required_type:
719  * @extension_point: a #GIOExtensionPoint
720  *
721  * Gets the required type for @extension_point.
722  *
723  * Returns: the #GType that all implementations must have, 
724  *     or #G_TYPE_INVALID if the extension point has no required type
725  */
726 GType
727 g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
728 {
729   return extension_point->required_type;
730 }
731
732 void
733 lazy_load_modules (GIOExtensionPoint *extension_point)
734 {
735   GIOModule *module;
736   GList *l;
737
738   for (l = extension_point->lazy_load_modules; l != NULL; l = l->next)
739     {
740       module = l->data;
741
742       if (!module->initialized)
743         {
744           if (g_type_module_use (G_TYPE_MODULE (module)))
745             g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
746           else
747             g_printerr ("Failed to load module: %s\n",
748                         module->filename);
749         }
750     }
751 }
752
753 /**
754  * g_io_extension_point_get_extensions:
755  * @extension_point: a #GIOExtensionPoint
756  *
757  * Gets a list of all extensions that implement this extension point.
758  * The list is sorted by priority, beginning with the highest priority.
759  *
760  * Returns: (element-type GIOExtension) (transfer none): a #GList of
761  * #GIOExtension<!-- -->s. The list is owned by GIO and should not be
762  * modified.
763  */
764 GList *
765 g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
766 {
767   lazy_load_modules (extension_point);
768   return extension_point->extensions;
769 }
770
771 /**
772  * g_io_extension_point_get_extension_by_name:
773  * @extension_point: a #GIOExtensionPoint
774  * @name: the name of the extension to get
775  *
776  * Finds a #GIOExtension for an extension point by name.
777  *
778  * Returns: (transfer none): the #GIOExtension for @extension_point that has the
779  *    given name, or %NULL if there is no extension with that name
780  */
781 GIOExtension *
782 g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
783                                             const char        *name)
784 {
785   GList *l;
786
787   lazy_load_modules (extension_point);
788   for (l = extension_point->extensions; l != NULL; l = l->next)
789     {
790       GIOExtension *e = l->data;
791
792       if (e->name != NULL &&
793           strcmp (e->name, name) == 0)
794         return e;
795     }
796   
797   return NULL;
798 }
799
800 static gint
801 extension_prio_compare (gconstpointer  a,
802                         gconstpointer  b)
803 {
804   const GIOExtension *extension_a = a, *extension_b = b;
805
806   if (extension_a->priority > extension_b->priority)
807     return -1;
808
809   if (extension_b->priority > extension_a->priority)
810     return 1;
811
812   return 0;
813 }
814
815 /**
816  * g_io_extension_point_implement:
817  * @extension_point_name: the name of the extension point
818  * @type: the #GType to register as extension 
819  * @extension_name: the name for the extension
820  * @priority: the priority for the extension
821  *
822  * Registers @type as extension for the extension point with name
823  * @extension_point_name. 
824  *
825  * If @type has already been registered as an extension for this 
826  * extension point, the existing #GIOExtension object is returned.
827  *
828  * Returns: a #GIOExtension object for #GType
829  */
830 GIOExtension *
831 g_io_extension_point_implement (const char *extension_point_name,
832                                 GType       type,
833                                 const char *extension_name,
834                                 gint        priority)
835 {
836   GIOExtensionPoint *extension_point;
837   GIOExtension *extension;
838   GList *l;
839
840   g_return_val_if_fail (extension_point_name != NULL, NULL);
841
842   extension_point = g_io_extension_point_lookup (extension_point_name);
843   if (extension_point == NULL)
844     {
845       g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
846       return NULL;
847     }
848   
849   if (extension_point->required_type != 0 &&
850       !g_type_is_a (type, extension_point->required_type))
851     {
852       g_warning ("Tried to register an extension of the type %s to extension point %s. "
853                  "Expected type is %s.",
854                  g_type_name (type),
855                  extension_point_name, 
856                  g_type_name (extension_point->required_type));
857       return NULL;
858     }      
859
860   /* It's safe to register the same type multiple times */
861   for (l = extension_point->extensions; l != NULL; l = l->next)
862     {
863       extension = l->data;
864       if (extension->type == type)
865         return extension;
866     }
867   
868   extension = g_slice_new0 (GIOExtension);
869   extension->type = type;
870   extension->name = g_strdup (extension_name);
871   extension->priority = priority;
872   
873   extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
874                                                       extension, extension_prio_compare);
875   
876   return extension;
877 }
878
879 /**
880  * g_io_extension_ref_class:
881  * @extension: a #GIOExtension
882  *
883  * Gets a reference to the class for the type that is 
884  * associated with @extension.
885  *
886  * Returns: (transfer full): the #GTypeClass for the type of @extension
887  */
888 GTypeClass *
889 g_io_extension_ref_class (GIOExtension *extension)
890 {
891   return g_type_class_ref (extension->type);
892 }
893
894 /**
895  * g_io_extension_get_type:
896  * @extension: a #GIOExtension
897  *
898  * Gets the type associated with @extension.
899  *
900  * Returns: the type of @extension
901  */
902 GType
903 g_io_extension_get_type (GIOExtension *extension)
904 {
905   return extension->type;
906 }
907
908 /**
909  * g_io_extension_get_name:
910  * @extension: a #GIOExtension
911  *
912  * Gets the name under which @extension was registered.
913  *
914  * Note that the same type may be registered as extension
915  * for multiple extension points, under different names.
916  *
917  * Returns: the name of @extension.
918  */
919 const char *
920 g_io_extension_get_name (GIOExtension *extension)
921 {
922   return extension->name;
923 }
924
925 /**
926  * g_io_extension_get_priority:
927  * @extension: a #GIOExtension
928  *
929  * Gets the priority with which @extension was registered.
930  *
931  * Returns: the priority of @extension
932  */
933 gint
934 g_io_extension_get_priority (GIOExtension *extension)
935 {
936   return extension->priority;
937 }