diff options
Diffstat (limited to 'src/rc-plugin.c')
-rw-r--r-- | src/rc-plugin.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/rc-plugin.c b/src/rc-plugin.c new file mode 100644 index 00000000..c02b6a81 --- /dev/null +++ b/src/rc-plugin.c @@ -0,0 +1,119 @@ +/* + librc-plugin.c + Simple plugin handler + Copyright 2007 Gentoo Foundation + Released under the GPLv2 + */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" +#include "rc-plugin.h" +#include "strlist.h" + +typedef struct plugin +{ + char *name; + void *handle; + int (*hook) (rc_hook_t hook, const char *name); + struct plugin *next; +} plugin_t; + +static plugin_t *plugins = NULL; + +void rc_plugin_load (void) +{ + char **files; + char *file; + int i; + plugin_t *plugin = plugins; + + /* Ensure some sanity here */ + rc_plugin_unload (); + + if (! rc_exists (RC_PLUGINDIR)) + return; + + files = rc_ls_dir (NULL, RC_PLUGINDIR, 0); + STRLIST_FOREACH (files, file, i) + { + char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL); + void *h = dlopen (p, RTLD_LAZY); + char *func; + void *f; + + if (! h) + { + eerror ("dlopen `%s': %s", p, dlerror ()); + free (p); + continue; + } + + func = file; + file = strsep (&func, "."); + func = rc_xmalloc (strlen (file) + strlen ("__hook") + 1); + sprintf (func, "_%s_hook", file); + + f = dlsym (h, func); + if (! f) + { + eerror ("`%s' does not expose the symbol `%s'", p, func); + dlclose (h); + } + else + { + if (plugin) + { + plugin->next = rc_xmalloc (sizeof (plugin_t)); + plugin = plugin->next; + } + else + plugin = plugins = rc_xmalloc (sizeof (plugin_t)); + + memset (plugin, 0, sizeof (plugin_t)); + plugin->name = strdup (file); + plugin->handle = h; + plugin->hook = f; + } + + free (func); + free (p); + } + + rc_strlist_free (files); +} + +void rc_plugin_run (rc_hook_t hook, const char *value) +{ + plugin_t *plugin = plugins; + + while (plugin) + { + if (plugin->hook) + plugin->hook (hook, value); + + plugin = plugin->next; + } +} + +void rc_plugin_unload (void) +{ + plugin_t *plugin = plugins; + plugin_t *next; + + while (plugin) + { + next = plugin->next; + dlclose (plugin->handle); + free (plugin->name); + free (plugin); + plugin = next; + } + plugins = NULL; +} |