/* Libvisual - The audio visualisation framework. * * Copyright (C) 2004, 2005, 2006 Dennis Smit * * Authors: Dennis Smit * * $Id: lv_plugin.c,v 1.80.2.1 2006/03/04 12:32:47 descender Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "lvconfig.h" #if defined(VISUAL_OS_WIN32) #include #else #include #endif #include #include "lv_libvisual.h" #include "lv_plugin.h" #include "lv_log.h" #include "lv_mem.h" extern VisList *__lv_plugins; static int plugin_info_dtor (VisObject *object); static int plugin_ref_dtor (VisObject *object); static int plugin_environ_dtor (VisObject *object); static int plugin_dtor (VisObject *object); static int plugin_add_dir_to_list (VisList *list, const char *dir); static char *get_delim_node (const char *str, char delim, int index); static int plugin_info_dtor (VisObject *object) { VisPluginInfo *pluginfo = VISUAL_PLUGININFO (object); if (pluginfo->plugname != NULL) visual_mem_free (pluginfo->plugname); if (pluginfo->type != NULL) visual_mem_free (pluginfo->type); if (pluginfo->name != NULL) visual_mem_free (pluginfo->name); if (pluginfo->author != NULL) visual_mem_free (pluginfo->author); if (pluginfo->version != NULL) visual_mem_free (pluginfo->version); if (pluginfo->about != NULL) visual_mem_free (pluginfo->about); if (pluginfo->help != NULL) visual_mem_free (pluginfo->help); pluginfo->plugname = NULL; pluginfo->type = NULL; pluginfo->name = NULL; pluginfo->author = NULL; pluginfo->version = NULL; pluginfo->about = NULL; pluginfo->help = NULL; return VISUAL_OK; } static int plugin_ref_dtor (VisObject *object) { VisPluginRef *ref = VISUAL_PLUGINREF (object); if (ref->file != NULL) visual_mem_free (ref->file); if (ref->usecount > 0) visual_log (VISUAL_LOG_CRITICAL, _("A plugin reference with %d instances has been destroyed."), ref->usecount); if (ref->info != NULL) visual_object_unref (VISUAL_OBJECT (ref->info)); ref->file = NULL; ref->info = NULL; return VISUAL_OK; } static int plugin_environ_dtor (VisObject *object) { VisPluginEnviron *enve = VISUAL_PLUGINENVIRON (object); if (enve->environment != NULL) visual_object_unref (enve->environment); enve->environment = NULL; return VISUAL_OK; } static int plugin_dtor (VisObject *object) { VisPluginData *plugin = VISUAL_PLUGINDATA (object); if (plugin->ref != NULL) visual_object_unref (VISUAL_OBJECT (plugin->ref)); if (plugin->params != NULL) visual_object_unref (VISUAL_OBJECT (plugin->params)); visual_collection_destroy (VISUAL_COLLECTION (&plugin->environment)); plugin->ref = NULL; plugin->params = NULL; return VISUAL_OK; } static char *get_delim_node (const char *str, char delim, int index) { char *buf; const char *start; const char *end = str; int i = 0; do { start = end; end = strchr (start + 1, delim); if (i == index) { /* Last section doesn't contain a delim */ if (end == NULL) end = str + strlen (str); /* Cut off the delim that is in front */ if (i > 0) start++; break; } i++; } while (end != NULL); if (end == NULL) return NULL; buf = visual_mem_malloc0 ((end - start) + 1); strncpy (buf, start, end - start); return buf; } /** * @defgroup VisPlugin VisPlugin * @{ */ /** * Creates a new VisPluginInfo structure. * * @return A newly allocated VisPluginInfo */ VisPluginInfo *visual_plugin_info_new () { VisPluginInfo *pluginfo; pluginfo = visual_mem_new0 (VisPluginInfo, 1); /* Do the VisObject initialization */ visual_object_initialize (VISUAL_OBJECT (pluginfo), TRUE, plugin_info_dtor); return pluginfo; } /** * Copies data from one VisPluginInfo to another, this does not copy everything * but only things that are needed in the local copy for the plugin registry. * * @param dest Pointer to the destination VisPluginInfo in which some data is copied. * @param src Pointer to the source VisPluginInfo from which some data is copied. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_INFO_NULL on failure. */ int visual_plugin_info_copy (VisPluginInfo *dest, VisPluginInfo *src) { visual_log_return_val_if_fail (dest != NULL, -VISUAL_ERROR_PLUGIN_INFO_NULL); visual_log_return_val_if_fail (src != NULL, -VISUAL_ERROR_PLUGIN_INFO_NULL); visual_mem_copy (dest, src, sizeof (VisPluginInfo)); dest->plugname = strdup (src->plugname); dest->type = strdup (src->type); dest->name = strdup (src->name); dest->author = strdup (src->author); dest->version = strdup (src->version); dest->about = strdup (src->about); dest->help = strdup (src->help); return VISUAL_OK; } /** * Pumps the queued events into the plugin it's event handler if it has one. * * @param plugin Pointer to a VisPluginData of which the events need to be pumped into * the handler. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_NULL or -VISUAL_ERROR_PLUGIN_NO_EVENT_HANDLER on failure. */ int visual_plugin_events_pump (VisPluginData *plugin) { visual_log_return_val_if_fail (plugin != NULL, -VISUAL_ERROR_PLUGIN_NULL); if (plugin->info->events != NULL) { plugin->info->events (plugin, &plugin->eventqueue); return VISUAL_OK; } return -VISUAL_ERROR_PLUGIN_NO_EVENT_HANDLER; } /** * Gives the event queue from a VisPluginData. This queue needs to be used * when you want to send events to the plugin. * * @see visual_plugin_events_pump * * @param plugin Pointer to the VisPluginData from which we want the queue. * * @return A pointer to the requested VisEventQueue or NULL on failure. */ VisEventQueue *visual_plugin_get_eventqueue (VisPluginData *plugin) { visual_log_return_val_if_fail (plugin != NULL, NULL); return &plugin->eventqueue; } /** * Sets a VisUIWidget as top user interface widget for the plugin. When a VisUI * tree is requested by a client, to render a configuration userinterface, this * VisUIWidget is used as top widget. * * @param plugin Pointer to the VisPluginData to which we set the VisUIWidget as top widget. * @param widget Pointer to the VisUIWidget that we use as top widget for the user interface. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_NULL on failure. */ int visual_plugin_set_userinterface (VisPluginData *plugin, VisUIWidget *widget) { visual_log_return_val_if_fail (plugin != NULL, -VISUAL_ERROR_PLUGIN_NULL); plugin->userinterface = widget; return VISUAL_OK; } /** * Retrieves the VisUI top widget for the plugin. * * @param plugin Pointer to the VisPluginData of which we request the VisUIWidget that serves as top widget. * * @return Pointer to the VisUIWidget that serves as top widget, possibly NULL. */ VisUIWidget *visual_plugin_get_userinterface (VisPluginData *plugin) { visual_log_return_val_if_fail (plugin != NULL, NULL); return plugin->userinterface; } /** * Gives the VisPluginInfo related to a VisPluginData. * * @param plugin The VisPluginData of which the VisPluginInfo is requested. * * @return The VisPluginInfo within the VisPluginData, or NULL on failure. */ VisPluginInfo *visual_plugin_get_info (VisPluginData *plugin) { visual_log_return_val_if_fail (plugin != NULL, NULL); return plugin->info; } /** * Gives the VisParamContainer related to a VisPluginData. * * @param plugin The VisPluginData of which the VisParamContainer is requested. * * @return The VisParamContainer within the VisPluginData, or NULL on failure. */ VisParamContainer *visual_plugin_get_params (VisPluginData *plugin) { visual_log_return_val_if_fail (plugin != NULL, NULL); return plugin->params; } /** * Gives the VisRandomContext related to a VisPluginData. * * @param plugin The VisPluginData of which the VisRandomContext is requested. * * @return The VisRandomContext within the VisPluginDAta, or NULL on failure. */ VisRandomContext *visual_plugin_get_random_context (VisPluginData *plugin) { visual_log_return_val_if_fail (plugin != NULL, NULL); return &plugin->random; } /** * Retrieves the plugin specific part of a plugin. * * @param plugin The pointer to the VisPluginData from which we want the plugin specific part. * * @return Void * pointing to the plugin specific part which can be cast. */ void *visual_plugin_get_specific (VisPluginData *plugin) { VisPluginInfo *pluginfo; visual_log_return_val_if_fail (plugin != NULL, NULL); pluginfo = visual_plugin_get_info (plugin); visual_log_return_val_if_fail (pluginfo != NULL, NULL); return pluginfo->plugin; } /** * Creates a new VisPluginRef structure. * * The VisPluginRef contains data for the plugin loader. * * @return Newly allocated VisPluginRef. */ VisPluginRef *visual_plugin_ref_new () { VisPluginRef *ref; ref = visual_mem_new0 (VisPluginRef, 1); /* Do the VisObject initialization */ visual_object_initialize (VISUAL_OBJECT (ref), TRUE, plugin_ref_dtor); return ref; } /** * Creates a new VisPluginData structure. * * @return A newly allocated VisPluginData. */ VisPluginData *visual_plugin_new () { VisPluginData *plugin; plugin = visual_mem_new0 (VisPluginData, 1); /* Do the VisObject initialization */ visual_object_initialize (VISUAL_OBJECT (plugin), TRUE, plugin_dtor); plugin->params = visual_param_container_new (); return plugin; } /** * Gives a VisList that contains references to all the plugins in the registry. * * @see VisPluginRef * * @return VisList of references to all the libvisual plugins. */ VisList *visual_plugin_get_registry () { return __lv_plugins; } /** * Gives a newly allocated VisList with references for one plugin type. * * @see VisPluginRef * * @param pluglist Pointer to the VisList that contains the plugin registry. * @param domain The plugin type that is filtered for. * * @return Newly allocated VisList that is a filtered version of the plugin registry. */ VisList *visual_plugin_registry_filter (VisList *pluglist, const char *domain) { VisList *list; VisListEntry *entry = NULL; VisPluginRef *ref; int ret; visual_log_return_val_if_fail (pluglist != NULL, NULL); list = visual_list_new (visual_object_collection_destroyer); if (list == NULL) { visual_log (VISUAL_LOG_CRITICAL, _("Cannot create a new list")); return NULL; } while ((ref = visual_list_next (pluglist, &entry)) != NULL) { if ((ret = visual_plugin_type_member_of (ref->info->type, domain))) { if (ret == TRUE) { visual_object_ref (VISUAL_OBJECT (ref)); visual_list_add (list, ref); } else if (ret != FALSE) { visual_log (VISUAL_LOG_WARNING, visual_error_to_string (ret)); } } else if (ret != FALSE) { /* FIXME XXX TODO, patch frmo duilio check how this works */ visual_log (VISUAL_LOG_WARNING, visual_error_to_string (ret)); } } return list; } /** * Get the next plugin based on it's name. * * @see visual_plugin_registry_filter * * @param list Pointer to the VisList containing the plugins. Adviced is to filter * this list first using visual_plugin_registry_filter. * @param name Name of a plugin entry of which we want the next entry or NULL to get * the first entry. * * @return The name of the next plugin or NULL on failure. */ const char *visual_plugin_get_next_by_name (VisList *list, const char *name) { VisListEntry *entry = NULL; VisPluginRef *ref; int tagged = FALSE; visual_log_return_val_if_fail (list != NULL, NULL); while ((ref = visual_list_next (list, &entry)) != NULL) { if (name == NULL) return ref->info->plugname; if (tagged == TRUE) return ref->info->plugname; if (strcmp (name, ref->info->plugname) == 0) tagged = TRUE; } return NULL; } /** * Get the previous plugin based on it's name. * * @see visual_plugin_registry_filter * * @param list Pointer to the VisList containing the plugins. Adviced is to filter * this list first using visual_plugin_registry_filter. * @param name Name of a plugin entry of which we want the previous entry or NULL to get * the last entry. * * @return The name of the next plugin or NULL on failure. */ const char *visual_plugin_get_prev_by_name (VisList *list, const char *name) { VisListEntry *entry = NULL; VisPluginRef *ref, *pref = NULL; visual_log_return_val_if_fail (list != NULL, NULL); if (name == NULL) { ref = visual_list_get (list, visual_collection_size (VISUAL_COLLECTION (list)) - 1); if (ref == NULL) return NULL; return ref->info->plugname; } while ((ref = visual_list_next (list, &entry)) != NULL) { if (strcmp (name, ref->info->plugname) == 0) { if (pref != NULL) return pref->info->plugname; else return NULL; } pref = ref; } return NULL; } static int plugin_add_dir_to_list (VisList *list, const char *dir) { VisPluginRef **ref; char temp[FILENAME_MAX]; int i, j, n; size_t len; int cnt = 0; #if defined(VISUAL_OS_WIN32) BOOL fFinished; HANDLE hList; TCHAR szDir[MAX_PATH+1]; TCHAR szSubDir[MAX_PATH+1]; WIN32_FIND_DATA FileData; snprintf (szDir, MAX_PATH, "%s\\*", dir); hList = FindFirstFile (szDir, &FileData); if (hList == INVALID_HANDLE_VALUE) { FindClose (hList); return 0; } visual_mem_set (temp, 0, sizeof (temp)); fFinished = FALSE; while (!fFinished) { ref = NULL; if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { snprintf (temp, 1023, "%s\\%s", dir, FileData.cFileName); len = strlen (temp); if (len > 5 && (strncmp (&temp[len - 5], ".dll", 5) == 0)) ref = visual_plugin_get_references (temp, &cnt); if (ref != NULL) { for (j = 0; j < cnt; j++) visual_list_add (list, ref[j]); /* This is the pointer pointer pointer, not a ref itself */ visual_mem_free (ref); } if (!FindNextFile (hList, &FileData)) { if (GetLastError () == ERROR_NO_MORE_FILES) { fFinished = TRUE; } } } } FindClose (hList); #else struct dirent **namelist; n = scandir (dir, &namelist, NULL, alphasort); if (n < 0) return -1; /* Free the . and .. entries */ visual_mem_free (namelist[0]); visual_mem_free (namelist[1]); visual_mem_set (temp, 0, sizeof (temp)); for (i = 2; i < n; i++) { ref = NULL; snprintf (temp, 1023, "%s/%s", dir, namelist[i]->d_name); len = strlen (temp); if (len > 3 && (strncmp (&temp[len - 3], ".so", 3) == 0)) ref = visual_plugin_get_references (temp, &cnt); if (ref != NULL) { for (j = 0; j < cnt; j++) visual_list_add (list, ref[j]); /* This is the pointer pointer pointer, not a ref itself */ visual_mem_free (ref); } visual_mem_free (namelist[i]); } visual_mem_free (namelist); #endif return 0; } /** * Private function to unload a plugin. After calling this function the * given argument is no longer usable. * * @param plugin Pointer to the VisPluginData that needs to be unloaded. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_NULL, -VISUAL_ERROR_PLUGIN_HANDLE_NULL or * -VISUAL_ERROR_PLUGIN_REF_NULL on failure. */ int visual_plugin_unload (VisPluginData *plugin) { VisPluginRef *ref; visual_log_return_val_if_fail (plugin != NULL, -VISUAL_ERROR_PLUGIN_NULL); ref = plugin->ref; /* Not loaded */ if (plugin->handle == NULL) { visual_object_unref (VISUAL_OBJECT (plugin)); visual_log (VISUAL_LOG_CRITICAL, _("Tried unloading a plugin that never has been loaded.")); return -VISUAL_ERROR_PLUGIN_HANDLE_NULL; } if (plugin->realized == TRUE) plugin->info->cleanup (plugin); if (plugin->info->plugin != NULL) visual_object_unref (VISUAL_OBJECT (plugin->info->plugin)); if (plugin->info != NULL) visual_object_unref (VISUAL_OBJECT (plugin->info)); #if defined(VISUAL_OS_WIN32) FreeLibrary (plugin->handle); #else dlclose (plugin->handle); #endif plugin->info = NULL; if (ref != NULL) { if (ref->usecount > 0) ref->usecount--; } visual_param_container_set_eventqueue (plugin->params, NULL); visual_object_unref (VISUAL_OBJECT (plugin)); return VISUAL_OK; } /** * Private function to load a plugin. * * @param ref Pointer to the VisPluginRef containing information about * the plugin that needs to be loaded. * * @return A newly created and loaded VisPluginData. */ VisPluginData *visual_plugin_load (VisPluginRef *ref) { VisPluginData *plugin; VisTime time_; VisPluginInfo *pluginfo; VisPluginGetInfoFunc get_plugin_info; #if defined(VISUAL_OS_WIN32) HMODULE handle; #else /* !VISUAL_OS_WIN32 */ void *handle; #endif int cnt; visual_log_return_val_if_fail (ref != NULL, NULL); visual_log_return_val_if_fail (ref->info != NULL, NULL); /* Check if this plugin is reentrant */ if (ref->usecount > 0 && (ref->info->flags & VISUAL_PLUGIN_FLAG_NOT_REENTRANT)) { visual_log (VISUAL_LOG_CRITICAL, _("Cannot load plugin %s, the plugin is already loaded and is not reentrant."), ref->info->plugname); return NULL; } #if defined(VISUAL_OS_WIN32) handle = LoadLibrary (ref->file); #else handle = dlopen (ref->file, RTLD_LAZY); #endif if (handle == NULL) { #if defined(VISUAL_OS_WIN32) visual_log (VISUAL_LOG_CRITICAL, "Cannot load plugin: win32 error code: %d", GetLastError ()); #else visual_log (VISUAL_LOG_CRITICAL, _("Cannot load plugin: %s"), dlerror ()); #endif return NULL; } #if defined(VISUAL_OS_WIN32) get_plugin_info = (VisPluginGetInfoFunc) GetProcAddress (handle, "get_plugin_info"); #else get_plugin_info = (VisPluginGetInfoFunc) dlsym (handle, "get_plugin_info"); #endif if (get_plugin_info == NULL) { #if defined(VISUAL_OS_WIN32) visual_log (VISUAL_LOG_CRITICAL, "Cannot initialize plugin: win32 error code: %d", GetLastError ()); FreeLibrary (handle); #else visual_log (VISUAL_LOG_CRITICAL, _("Cannot initialize plugin: %s"), dlerror ()); dlclose (handle); #endif return NULL; } pluginfo = VISUAL_PLUGININFO (get_plugin_info (&cnt)); if (pluginfo == NULL) { visual_log (VISUAL_LOG_CRITICAL, _("Cannot get plugin info while loading.")); #if defined(VISUAL_OS_WIN32) FreeLibrary (handle); #else dlclose (handle); #endif return NULL; } plugin = visual_plugin_new (); plugin->ref = ref; plugin->info = &pluginfo[ref->index]; visual_object_ref (VISUAL_OBJECT (ref)); ref->usecount++; plugin->realized = FALSE; plugin->handle = handle; /* Now the plugin is set up and ready to be realized, also random seed its random context */ visual_time_get (&time_); visual_random_context_set_seed (&plugin->random, time_.tv_usec); return plugin; } /** * Private function to realize the plugin. This initializes the plugin. * * @param plugin Pointer to the VisPluginData that needs to be realized. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_NULL or -VISUAL_ERROR_PLUGIN_ALREADY_REALIZED on failure. */ int visual_plugin_realize (VisPluginData *plugin) { VisParamContainer *paramcontainer; visual_log_return_val_if_fail (plugin != NULL, -VISUAL_ERROR_PLUGIN_NULL); if (plugin->realized == TRUE) return -VISUAL_ERROR_PLUGIN_ALREADY_REALIZED; paramcontainer = visual_plugin_get_params (plugin); visual_param_container_set_eventqueue (paramcontainer, &plugin->eventqueue); plugin->info->init (plugin); plugin->realized = TRUE; return VISUAL_OK; } /** * Private function to create VisPluginRefs from plugins. * * @param pluginpath The full path and filename to the plugin of which a reference * needs to be obtained. * @param count Int pointer that will contain the number of VisPluginRefs returned. * * @return The optionally newly allocated VisPluginRefs for the plugin. */ VisPluginRef **visual_plugin_get_references (const char *pluginpath, int *count) { VisPluginRef **ref; VisPluginInfo *plug_info; VisPluginInfo *dup_info; const char *plug_name; VisPluginGetInfoFunc get_plugin_info; int *plugin_version; #if defined(VISUAL_OS_WIN32) HMODULE handle; #else /* !VISUAL_OS_WIN32 */ void *handle; #endif int cnt = 1, i; visual_log_return_val_if_fail (pluginpath != NULL, NULL); #if defined(VISUAL_OS_WIN32) handle = LoadLibrary (pluginpath); #else handle = dlopen (pluginpath, RTLD_LAZY); #endif if (handle == NULL) { #if defined(VISUAL_OS_WIN32) visual_log (VISUAL_LOG_CRITICAL, "Cannot load plugin: win32 error code: %d", GetLastError()); #else visual_log (VISUAL_LOG_CRITICAL, _("Cannot load plugin: %s"), dlerror ()); #endif return NULL; } #if defined(VISUAL_OS_WIN32) plugin_version = (int *) GetProcAddress (handle, VISUAL_PLUGIN_VERSION_TAG); #else plugin_version = (int *) dlsym (handle, VISUAL_PLUGIN_VERSION_TAG); #endif if (plugin_version == NULL || *plugin_version != VISUAL_PLUGIN_API_VERSION) { visual_log (VISUAL_LOG_CRITICAL, _("Plugin %s is not compatible with version %s of libvisual"), pluginpath, visual_get_version ()); #if defined(VISUAL_OS_WIN32) FreeLibrary (handle); #else dlclose (handle); #endif return NULL; } #if defined(VISUAL_OS_WIN32) get_plugin_info = (VisPluginGetInfoFunc) GetProcAddress (handle, "get_plugin_info"); #else get_plugin_info = (VisPluginGetInfoFunc) dlsym (handle, "get_plugin_info"); #endif if (get_plugin_info == NULL) { #if defined(VISUAL_OS_WIN32) visual_log (VISUAL_LOG_CRITICAL, "Cannot initialize plugin: win32 error code: %d", GetLastError ()); FreeLibrary (handle); #else visual_log (VISUAL_LOG_CRITICAL, _("Cannot initialize plugin: %s"), dlerror ()); dlclose (handle); #endif return NULL; } plug_info = VISUAL_PLUGININFO (get_plugin_info (&cnt)); if (plug_info == NULL) { visual_log (VISUAL_LOG_CRITICAL, _("Cannot get plugin info")); #if defined(VISUAL_OS_WIN32) FreeLibrary (handle); #else dlclose (handle); #endif return NULL; } ref = visual_mem_new0 (VisPluginRef *, cnt); for (i = 0; i < cnt; i++) { ref[i] = visual_plugin_ref_new (); dup_info = visual_plugin_info_new (); visual_plugin_info_copy (dup_info, &plug_info[i]); ref[i]->index = i; ref[i]->info = dup_info; ref[i]->file = strdup (pluginpath); visual_object_unref (plug_info[i].plugin); visual_object_unref (VISUAL_OBJECT (&plug_info[i])); } #if defined(VISUAL_OS_WIN32) FreeLibrary (handle); #else dlclose (handle); #endif *count = cnt; return ref; } /** * Private function to create the complete plugin registry from a set of paths. * * @param paths A pointer list to a set of paths. * @param ignore_non_existing A flag that can be set with TRUE or FALSE to ignore non existing dirs. * * @return A newly allocated VisList containing the plugin registry for the set of paths. */ VisList *visual_plugin_get_list (const char **paths, int ignore_non_existing) { VisList *list; int i = 0; list = visual_list_new (visual_object_collection_destroyer); while (paths[i] != NULL) { if (plugin_add_dir_to_list (list, paths[i]) < 0) { if (ignore_non_existing == FALSE) visual_log (VISUAL_LOG_WARNING, _("Failed to add the %s directory to the plugin registry"), paths[i]); } i++; } return list; } /** * Private function to find a plugin in a plugin registry. * * @param list Pointer to a VisList containing VisPluginRefs in which * the search is done. * @param name The name of the plugin we're looking for. * * @return The VisPluginRef for the plugin if found, or NULL when not found. */ VisPluginRef *visual_plugin_find (VisList *list, const char *name) { VisListEntry *entry = NULL; VisPluginRef *ref; while ((ref = visual_list_next (list, &entry)) != NULL) { if (ref->info->plugname == NULL) continue; if (strcmp (name, ref->info->plugname) == 0) return ref; } return NULL; } /** * Gives the VISUAL_PLUGIN_API_VERSION value for which the library is compiled. * This can be used to check against for API/ABI compatibility check. * * @return The VISUAL_PLUGIN_API_VERSION define value. */ int visual_plugin_get_api_version () { return VISUAL_PLUGIN_API_VERSION; } /** * Get the domain part from a plugin type string. * * @param type The type string. * * @return A newly allocated string containing the domain part of this plugin type, or NULL on failure. */ const char *visual_plugin_type_get_domain (const char *type) { visual_log_return_val_if_fail (type != NULL, NULL); return get_delim_node (type, ':', 0); } /** * Get the package part from a plugin type string. * * @param type The type string. * * @return A newly allocated string containing the package part of this plugin type, or NULL on failure. */ const char *visual_plugin_type_get_package (const char *type) { visual_log_return_val_if_fail (type != NULL, NULL); return get_delim_node (type, ':', 1); } /** * Get the type part from a plugin type string. * * @param type The type string. * * @return A newly allocated string containing the type part of this plugin type, or NULL on failure. */ const char *visual_plugin_type_get_type (const char *type) { char *str; char *flags; char *typestr; visual_log_return_val_if_fail (type != NULL, NULL); str = get_delim_node (type, ':', 2); flags = strchr (str, '.'); if (flags != NULL) { typestr = visual_mem_malloc0 (flags - str); strncpy (typestr, str, flags - str); visual_mem_free (str); return typestr; } return str; } /** * Get the depth of a plugin type string. * * @param type The type string. * * @return A VisPluginTypeDepth enum value that describes out of how many parts this plugin * type string consists, -VISUAL_ERROR_NULL on failure. */ VisPluginTypeDepth visual_plugin_type_get_depth (const char *type) { int i = 0; visual_log_return_val_if_fail (type != NULL, -VISUAL_ERROR_NULL); while (i < VISUAL_PLUGIN_TYPE_DEPTH_TYPE) { char *part; part = get_delim_node (type, ':', i); if (part == NULL) break; i++; visual_mem_free (part); } return i; } /** * Check if a certain plugin type string falls within the domain of the other. * * @param domain The domain in which the type string should fall. * @param type The type string that is checked against the given domain. * * @return TRUE if it falls within the domain, FALSE when not, -VISUAL_ERROR_NULL on failure */ int visual_plugin_type_member_of (const char *domain, const char *type) { char *ndomain; char *tmp; char *comp1; char *comp2; int diff = 0; int i = 0; visual_log_return_val_if_fail (domain != NULL, -VISUAL_ERROR_NULL); visual_log_return_val_if_fail (type != NULL, -VISUAL_ERROR_NULL); ndomain = visual_mem_malloc0 (strlen (domain) + 1); tmp = strchr (domain, '.'); if (tmp != NULL) strncpy (ndomain, domain, tmp - domain); else strcpy (ndomain, domain); while (i < visual_plugin_type_get_depth (ndomain)) { comp1 = get_delim_node (ndomain, ':', i); comp2 = get_delim_node (type, ':', i); if (comp1 == NULL || comp2 == NULL) { if (comp1 != NULL) visual_mem_free (comp1); if (comp2 != NULL) visual_mem_free (comp2); visual_mem_free (ndomain); return FALSE; } if (strcmp (comp1, comp2) != 0) diff++; visual_mem_free (comp1); visual_mem_free (comp2); i++; } visual_mem_free (ndomain); if (diff > 0) return FALSE; return TRUE; } /** * Retrieves the flags section from the plugin type string. * * @param type The type string, containing the plugin type and optional flags. * * return NULL if no flags are found, the flags between the '[' and ']' braces on succes. * for example when the plugin type string is "Libvisual:core:actor.[special|something]" * the returned flag string would be "special|something". Keep in mind that the string is * allocated and should be freed after it's not being used anylonger. */ const char *visual_plugin_type_get_flags (const char *type) { char *flagsret; char *flagstr; visual_log_return_val_if_fail (type != NULL, NULL); flagstr = strstr (type, ".["); if (flagstr == NULL) return NULL; flagstr += 2; /* Skip the ".[" */ flagsret = visual_mem_malloc0 (strlen (flagstr) - 1); strncpy (flagsret, flagstr, strlen (flagstr) - 1); flagsret[strlen (flagstr) - 1] = '\0'; return flagsret; } /** * Checks if a certain flag is found within a plugin type string. * * @param type The type string, containing the plugin type and optional flags. * @param flag The flag string to check for within the type string. * * @return TRUE in found, FALSE if not found, -VISUAL_ERROR_NULL on failure. */ int visual_plugin_type_has_flag (const char *type, const char *flag) { char *flags; char *nflag, *s; visual_log_return_val_if_fail (type != NULL, -VISUAL_ERROR_NULL); visual_log_return_val_if_fail (flag != NULL, -VISUAL_ERROR_NULL); nflag = flags = (char *) visual_plugin_type_get_flags (type); if (flags == NULL) return FALSE; do { s = strchr (nflag, '|'); if (s != NULL) { if (strncmp (nflag, flag, s - nflag - 1) == 0) { visual_mem_free (flags); return TRUE; } } else { if (strcmp (nflag, flag) == 0) { visual_mem_free (flags); return TRUE; } } } while ((nflag = strchr (nflag, '|') + 1)); visual_mem_free (flags); return FALSE; } /** * Creates a VisPluginEnviron structure. * * @param type The Environ type that is requested. * @param envobj The VisObject connected to this Environ type. * * @return A newly allocated VisPluginEnviron, or NULL on failure. */ VisPluginEnviron *visual_plugin_environ_new (const char *type, VisObject *envobj) { VisPluginEnviron *enve; enve = visual_mem_new0 (VisPluginEnviron, 1); /* Do the VisObject initialization */ visual_object_initialize (VISUAL_OBJECT (enve), TRUE, plugin_environ_dtor); enve->type = type; enve->environment = envobj; return enve; } /** * Adds a VisPluginEnviron to the plugin it's environment list. * * @param plugin Pointer to the VisPluginData to which the VisPluginEnviron is added. * @param enve Pointer to the VisPluginEnviron that is added to the VisPluginData. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_NULL, -VISUAL_ERROR_PLUGIN_ENVIRON_NULL, * -VISUAL_ERROR_NULL or error values returned by visual_list_add() on failure. */ int visual_plugin_environ_add (VisPluginData *plugin, VisPluginEnviron *enve) { visual_log_return_val_if_fail (plugin != NULL, -VISUAL_ERROR_PLUGIN_NULL); visual_log_return_val_if_fail (enve != NULL, -VISUAL_ERROR_PLUGIN_ENVIRON_NULL); visual_log_return_val_if_fail (enve->type != NULL, -VISUAL_ERROR_NULL); visual_plugin_environ_remove (plugin, enve->type); return visual_list_add (&plugin->environment, enve); } /** * Removes a VisPluginEnviron from the plugin it's environment list. * * @param plugin Pointer to the VisPluginData from which the VisPluginEnviron is removed. * @param type The Environ type that is removed. * * @return VISUAL_OK on succes, -VISUAL_ERROR_PLUGIN_NULL or -VISUAL_ERROR_NULL on failure. */ int visual_plugin_environ_remove (VisPluginData *plugin, const char *type) { VisPluginEnviron *enve; VisListEntry *le = NULL; visual_log_return_val_if_fail (plugin != NULL, -VISUAL_ERROR_PLUGIN_NULL); visual_log_return_val_if_fail (type != NULL, -VISUAL_ERROR_NULL); while ((enve = visual_list_next (&plugin->environment, &le)) != NULL) { /* Remove from list */ if (strcmp (enve->type, type) == 0) { visual_list_delete (&plugin->environment, &le); visual_object_unref (VISUAL_OBJECT (enve)); return VISUAL_OK; } } return VISUAL_OK; } /** * Retrieves a VisPluginEnviron from the plugin it's environment list. * * @param plugin Pointer to the VisPluginData from which the VisPluginEnviron is requested. * @param type The Environ type that is requested. * * @return The requested VisPluginEnviron it's environ specific VisObject, or NULL on failure */ VisObject *visual_plugin_environ_get (VisPluginData *plugin, const char *type) { VisPluginEnviron *enve; VisListEntry *le = NULL; visual_log_return_val_if_fail (plugin != NULL, NULL); visual_log_return_val_if_fail (type != NULL, NULL); while ((enve = visual_list_next (&plugin->environment, &le)) != NULL) { if (strcmp (enve->type, type) == 0) return enve->environment; } return NULL; } /** * @} */