diff --git a/include/QF/plugin.h b/include/QF/plugin.h index b4215ff08..c1ead3be4 100644 --- a/include/QF/plugin.h +++ b/include/QF/plugin.h @@ -91,6 +91,7 @@ typedef struct plugin_s { const char *copyright; plugin_funcs_t *functions; plugin_data_t *data; + const char *full_name; } plugin_t; /* diff --git a/libs/util/plugin.c b/libs/util/plugin.c index 78505ae4a..b06b84c66 100644 --- a/libs/util/plugin.c +++ b/libs/util/plugin.c @@ -59,12 +59,21 @@ static __attribute__ ((unused)) const char rcsid[] = #include "QF/hash.h" #include "QF/plugin.h" #include "QF/sys.h" +#include "QF/cmd.h" #include "compat.h" +// loaded_plugins is for plugins loaded from scripts only - not system +// plugins + +typedef struct loaded_plugin_s { + char *name; + plugin_t *plugin; +} loaded_plugin_t; + cvar_t *fs_pluginpath; -hashtab_t *registered_plugins; +hashtab_t *registered_plugins, *loaded_plugins; static const char *pi_error = ""; @@ -74,6 +83,19 @@ plugin_get_key (void *pl, void *unused) return ((plugin_list_t *) pl)->name; } +static const char * +loaded_plugin_get_key (void *lp, void *unusued) +{ + return ((loaded_plugin_t *) lp)->name; +} + +static void +loaded_plugin_delete (void *lp, void *unused) +{ + free (((loaded_plugin_t *) lp)->name); + free ((loaded_plugin_t *) lp); +} + static int pi_close_lib (void *handle) { @@ -146,6 +168,51 @@ PI_InitCvars (void) "Location of your plugin directory"); } +static void +PI_Plugin_Load_f (void) +{ + plugin_t *pi; + const char *type, *name; + + if (Cmd_Argc() != 3) { + Sys_Printf ("Usage: plugin_load \n"); + return; + } + + type = Cmd_Argv(1); + name = Cmd_Argv(2); + + pi = PI_LoadPlugin (type, name); + if (!pi) + Sys_Printf ("Error loading plugin %s %s\n", type, name); +} + +static void +PI_Plugin_Unload_f (void) +{ + char plugin_name[1024]; + loaded_plugin_t *lp; + plugin_t *pi; + + if (Cmd_Argc() != 3) { + Sys_Printf ("Usage: plugin_unload \n"); + return; + } + + // try to locate the plugin + snprintf (plugin_name, sizeof (plugin_name), "%s_%s", Cmd_Argv(1), + Cmd_Argv(2)); + lp = Hash_Find (loaded_plugins, plugin_name); + if (lp) { + pi = lp->plugin; + } else { + Sys_Printf ("Plugin %s not loaded\n", plugin_name); + return; + } + + PI_UnloadPlugin (pi); +} + /* PI_Init @@ -157,11 +224,27 @@ PI_Init (void) { PI_InitCvars (); registered_plugins = Hash_NewTable (253, plugin_get_key, 0, 0); + loaded_plugins = Hash_NewTable(253, loaded_plugin_get_key, + loaded_plugin_delete, 0); + Cmd_AddCommand("plugin_load", PI_Plugin_Load_f, + "load the plugin of the given type name and name"); + Cmd_AddCommand("plugin_unload", PI_Plugin_Unload_f, + "unload the plugin of the given type name and name"); } void PI_Shutdown (void) { + void **elems, **cur; + + // unload all "loaded" plugins and free the hash + elems = Hash_GetList (loaded_plugins); + for (cur = elems; *cur; ++cur) + PI_UnloadPlugin (((loaded_plugin_t *) *cur)->plugin); + free (elems); + + Hash_DelTable (loaded_plugins); + } plugin_t * @@ -175,6 +258,7 @@ PI_LoadPlugin (const char *type, const char *name) plugin_t *plugin = NULL; P_PluginInfo plugin_info = NULL; plugin_list_t *pl; + loaded_plugin_t *lp; if (!name) return NULL; @@ -183,6 +267,14 @@ PI_LoadPlugin (const char *type, const char *name) // Build the plugin name snprintf (plugin_name, sizeof (plugin_name), "%s_%s", type, name); + + // make sure we're not already loaded + lp = Hash_Find (loaded_plugins, plugin_name); + if (lp) { + Sys_Printf ("Plugin %s already loaded\n", plugin_name); + return NULL; + } + pl = Hash_Find (registered_plugins, plugin_name); if (pl) { plugin_info = pl->info; @@ -225,6 +317,13 @@ PI_LoadPlugin (const char *type, const char *name) return NULL; } + // add the plugin to the loaded_plugins hashtable + lp = malloc (sizeof (loaded_plugin_t)); + lp->name = strcpy (malloc (strlen (plugin_name)), plugin_name); + lp->plugin = plugin; + Hash_Add (loaded_plugins, lp); + + plugin->full_name = lp->name; plugin->handle = dlhand; return plugin; } @@ -241,6 +340,10 @@ PI_UnloadPlugin (plugin_t *plugin) Sys_DPrintf ("Warning: No shutdown function for type %d plugin!\n", plugin->type); } + + // remove from the table of loaded plugins + Hash_Free (loaded_plugins, Hash_Del (loaded_plugins, plugin->full_name)); + if (!plugin->handle) // we didn't load it return true; return pi_close_lib (plugin->handle);