X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Fmodules.c;h=15feab162a7f0218125c9fea26adff7dee695acf;hb=d6aa3d36b8570833583b763b187979399b8c6b2a;hp=5e4a0bf30c17788b8adc2941df202e75a4f1e53f;hpb=df85fc8b8befb1a0cc8b8007d99d82bfac26b249;p=vlc diff --git a/src/modules/modules.c b/src/modules/modules.c index 5e4a0bf30c..15feab162a 100644 --- a/src/modules/modules.c +++ b/src/modules/modules.c @@ -30,6 +30,8 @@ #include #include +#include +#include #include "libvlc.h" #include /* free(), strtol() */ @@ -41,44 +43,20 @@ # include #endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif +#include #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif - -#if !defined(HAVE_DYNAMIC_PLUGINS) - /* no support for plugins */ -#elif defined(HAVE_DL_DYLD) -# if defined(HAVE_MACH_O_DYLD_H) -# include -# endif -#elif defined(HAVE_DL_BEOS) -# if defined(HAVE_IMAGE_H) -# include -# endif -#elif defined(HAVE_DL_WINDOWS) -# include -#elif defined(HAVE_DL_DLOPEN) -# if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */ -# include -# endif -# if defined(HAVE_SYS_DL_H) -# include -# endif -#elif defined(HAVE_DL_SHL_LOAD) -# if defined(HAVE_DL_H) -# include -# endif +#ifdef ENABLE_NLS +# include #endif #include "config/configuration.h" -#include "vlc_charset.h" +#include #include "vlc_arrays.h" #include "modules/modules.h" @@ -106,6 +84,7 @@ static void DupModule ( module_t * ); static void UndupModule ( module_t * ); #endif +#undef module_InitBank /** * Init bank * @@ -114,7 +93,7 @@ static void UndupModule ( module_t * ); * \param p_this vlc object structure * \return nothing */ -void __module_InitBank( vlc_object_t *p_this ) +void module_InitBank( vlc_object_t *p_this ) { module_bank_t *p_bank = NULL; @@ -138,6 +117,8 @@ void __module_InitBank( vlc_object_t *p_this ) * options of main will be available in the module bank structure just * as for every other module. */ AllocateBuiltinModule( p_this, vlc_entry__main ); + vlc_rwlock_init (&config_lock); + config_SortConfig (); } else p_module_bank->i_usage++; @@ -166,7 +147,7 @@ void module_EndBank( vlc_object_t *p_this, bool b_plugins ) assert (p_bank != NULL); /* Save the configuration */ - if( !config_GetInt( p_this, "ignore-config" ) ) + if( !var_InheritBool( p_this, "ignore-config" ) ) config_AutoSaveConfigFile( p_this ); /* If plugins were _not_ loaded, then the caller still has the bank lock @@ -181,12 +162,13 @@ void module_EndBank( vlc_object_t *p_this, bool b_plugins ) vlc_mutex_unlock( &module_lock ); return; } + + config_UnsortConfig (); + vlc_rwlock_destroy (&config_lock); p_module_bank = NULL; vlc_mutex_unlock( &module_lock ); #ifdef HAVE_DYNAMIC_PLUGINS - if( p_bank->b_cache ) - CacheSave( p_this, p_bank ); while( p_bank->i_loaded_cache-- ) { if( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] ) @@ -195,25 +177,15 @@ void module_EndBank( vlc_object_t *p_this, bool b_plugins ) p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->p_module ); free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->psz_file ); free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] ); - p_bank->pp_loaded_cache[p_bank->i_loaded_cache] = NULL; } } - if( p_bank->pp_loaded_cache ) - { - free( p_bank->pp_loaded_cache ); - p_bank->pp_loaded_cache = NULL; - } + free( p_bank->pp_loaded_cache ); while( p_bank->i_cache-- ) { free( p_bank->pp_cache[p_bank->i_cache]->psz_file ); free( p_bank->pp_cache[p_bank->i_cache] ); - p_bank->pp_cache[p_bank->i_cache] = NULL; - } - if( p_bank->pp_cache ) - { - free( p_bank->pp_cache ); - p_bank->pp_cache = NULL; } + free( p_bank->pp_cache ); #endif while( p_bank->head != NULL ) @@ -230,7 +202,7 @@ void module_EndBank( vlc_object_t *p_this, bool b_plugins ) * \param p_this vlc object structure * \return nothing */ -void module_LoadPlugins( vlc_object_t * p_this, bool b_cache_delete ) +void module_LoadPlugins( vlc_object_t * p_this ) { module_bank_t *p_bank = p_module_bank; @@ -241,14 +213,13 @@ void module_LoadPlugins( vlc_object_t * p_this, bool b_cache_delete ) if( p_bank->i_usage == 1 ) { msg_Dbg( p_this, "checking plugin modules" ); - p_module_bank->b_cache = config_GetInt( p_this, "plugins-cache" ) > 0; + p_module_bank->b_cache = var_InheritBool( p_this, "plugins-cache" ); - if( p_module_bank->b_cache || b_cache_delete ) - CacheLoad( p_this, p_module_bank, b_cache_delete ); AllocateAllPlugins( p_this, p_module_bank ); + config_UnsortConfig (); + config_SortConfig (); } #endif - p_module_bank->b_plugins = true; vlc_mutex_unlock( &module_lock ); } @@ -323,6 +294,24 @@ int module_get_score( const module_t *m ) return m->i_score; } +/** + * Translate a string using the module's text domain + * + * \param m the module + * \param str the American English ASCII string to localize + * \return the gettext-translated string + */ +const char *module_gettext (const module_t *m, const char *str) +{ +#ifdef ENABLE_NLS + const char *domain = m->domain ? m->domain : PACKAGE_NAME; + return dgettext (domain, str); +#else + (void)m; + return str; +#endif +} + module_t *module_hold (module_t *m) { vlc_hold (&m->vlc_gc_data); @@ -334,6 +323,19 @@ void module_release (module_t *m) vlc_release (&m->vlc_gc_data); } +#undef module_start +int module_start (vlc_object_t *obj, module_t *m) +{ + return m->pf_activate ? (m->pf_activate (obj)) : VLC_SUCCESS; +} + +#undef module_stop +void module_stop (vlc_object_t *obj, module_t *m) +{ + if (m->pf_deactivate) + m->pf_deactivate (obj); +} + /** * Frees the flat list of VLC modules. * @param list list obtained by module_list_get() @@ -400,24 +402,21 @@ static int modulecmp (const void *a, const void *b) return lb->i_score - la->i_score; } +#undef module_need /** * module Need * * Return the best module function, given a capability list. * - * If the p_this object doesn't have it's psz_object_name set, then - * psz_object_name will be set to the module's name, unless the user - * provided an alias using the "module name@alias" syntax in which case - * psz_object_name will be set to the alias. - * * \param p_this the vlc object * \param psz_capability list of capabilities needed * \param psz_name name of the module asked - * \param b_strict TRUE yto use the strict mode + * \param b_strict if true, do not fallback to plugin with a different name + * but the same capability * \return the module or NULL in case of a failure */ -module_t * __module_need( vlc_object_t *p_this, const char *psz_capability, - const char *psz_name, bool b_strict ) +module_t * module_need( vlc_object_t *p_this, const char *psz_capability, + const char *psz_name, bool b_strict ) { stats_TimerStart( p_this, "module_need()", STATS_TIMER_MODULE_NEED ); @@ -449,16 +448,13 @@ module_t * __module_need( vlc_object_t *p_this, const char *psz_capability, } i_shortcuts++; - psz_shortcuts = psz_last_shortcut = strdup( psz_name ); + psz_parser = psz_shortcuts = psz_last_shortcut = strdup( psz_name ); - for( psz_parser = psz_shortcuts; *psz_parser; psz_parser++ ) + while( ( psz_parser = strchr( psz_parser, ',' ) ) ) { - if( *psz_parser == ',' ) - { - *psz_parser = '\0'; - i_shortcuts++; - psz_last_shortcut = psz_parser + 1; - } + *psz_parser = '\0'; + i_shortcuts++; + psz_last_shortcut = ++psz_parser; } /* Check if the user wants to override the "strict" mode */ @@ -481,20 +477,16 @@ module_t * __module_need( vlc_object_t *p_this, const char *psz_capability, size_t count; module_t **p_all = module_list_get (&count); p_list = malloc( count * sizeof( module_list_t ) ); - unsigned i_cpu = vlc_CPU(); /* Parse the module list for capabilities and probe each of them */ count = 0; for (size_t i = 0; (p_module = p_all[i]) != NULL; i++) { - bool b_shortcut_bonus = false; + int i_shortcut_bonus = 0; /* Test that this module can do what we need */ if( !module_provides( p_module, psz_capability ) ) continue; - /* Test if we have the required CPU */ - if( (p_module->i_cpu & i_cpu) != p_module->i_cpu ) - continue; /* If we required a shortcut, check this plugin provides it. */ if( i_shortcuts > 0 ) @@ -503,7 +495,7 @@ module_t * __module_need( vlc_object_t *p_this, const char *psz_capability, for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- ) { - for( unsigned i = 0; p_module->pp_shortcuts[i]; i++ ) + for( unsigned i = 0; i < p_module->i_shortcuts; i++ ) { char *c; if( ( c = strchr( name, '@' ) ) @@ -514,7 +506,7 @@ module_t * __module_need( vlc_object_t *p_this, const char *psz_capability, /* Found it */ if( c && c[1] ) psz_alias = c+1; - b_shortcut_bonus = true; + i_shortcut_bonus = i_short * 10000; goto found_shortcut; } } @@ -537,10 +529,8 @@ module_t * __module_need( vlc_object_t *p_this, const char *psz_capability, found_shortcut: /* Store this new module */ p_list[count].p_module = module_hold (p_module); - p_list[count].i_score = p_module->i_score; - if( b_shortcut_bonus ) - p_list[count].i_score += 10000; - p_list[count].b_force = b_shortcut_bonus && b_strict; + p_list[count].i_score = p_module->i_score + i_shortcut_bonus; + p_list[count].b_force = i_shortcut_bonus && b_strict; count++; } @@ -565,20 +555,20 @@ found_shortcut: { module_t *p_new_module = AllocatePlugin( p_this, p_real->psz_filename ); - if( p_new_module ) - { - CacheMerge( p_this, p_real, p_new_module ); - DeleteModule( p_module_bank, p_new_module ); + if( p_new_module == NULL ) + { /* Corrupted module */ + msg_Err( p_this, "possibly corrupt module cache" ); + module_release( p_cand ); + continue; } + CacheMerge( p_this, p_real, p_new_module ); + DeleteModule( p_module_bank, p_new_module ); } #endif p_this->b_force = p_list[i].b_force; - int ret = VLC_SUCCESS; - if( p_cand->pf_activate ) - ret = p_cand->pf_activate( p_this ); - switch( ret ) + switch( module_start( p_this, p_cand ) ) { case VLC_SUCCESS: /* good module! */ @@ -607,32 +597,15 @@ found_shortcut: { msg_Dbg( p_this, "using %s module \"%s\"", psz_capability, p_module->psz_object_name ); + vlc_object_set_name( p_this, psz_alias ? psz_alias + : p_module->psz_object_name ); } else if( count == 0 ) - { - if( !strcmp( psz_capability, "access_demux" ) - || !strcmp( psz_capability, "stream_filter" ) - || !strcmp( psz_capability, "vout_window" ) ) - { - msg_Dbg( p_this, "no %s module matched \"%s\"", - psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); - } - else - { - msg_Err( p_this, "no %s module matched \"%s\"", + msg_Dbg( p_this, "no %s module matched \"%s\"", psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); - - msg_StackSet( VLC_EGENERIC, "no %s module matched \"%s\"", - psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); - } - } - else if( psz_name != NULL && *psz_name ) - { - msg_Warn( p_this, "no %s module matching \"%s\" could be loaded", - psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); - } else - msg_StackSet( VLC_EGENERIC, "no suitable %s module", psz_capability ); + msg_Dbg( p_this, "no %s module matching \"%s\" could be loaded", + psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); free( psz_shortcuts ); free( psz_var ); @@ -645,6 +618,7 @@ found_shortcut: return p_module; } +#undef module_unneed /** * Module unneed * @@ -654,16 +628,10 @@ found_shortcut: * \param p_module the module structure * \return nothing */ -void __module_unneed( vlc_object_t * p_this, module_t * p_module ) +void module_unneed( vlc_object_t * p_this, module_t * p_module ) { - /* Use the close method */ - if( p_module->pf_deactivate ) - { - p_module->pf_deactivate( p_this ); - } - msg_Dbg( p_this, "removing module \"%s\"", p_module->psz_object_name ); - + module_stop( p_this, p_module ); module_release( p_module ); } @@ -728,9 +696,7 @@ module_t *module_find_by_shortcut (const char *psz_shortcut) for (size_t i = 0; (module = list[i]) != NULL; i++) { - for (size_t j = 0; - (module->pp_shortcuts[j] != NULL) && (j < MODULE_SHORTCUT_MAX); - j++) + for (size_t j = 0; j < module->i_shortcuts; j++) { if (!strcmp (module->pp_shortcuts[j], psz_shortcut)) { @@ -744,80 +710,6 @@ out: return module; } -/** - * GetModuleNamesForCapability - * - * Return a NULL terminated array with the names of the modules - * that have a certain capability. - * Free after uses both the string and the table. - * \param psz_capability the capability asked - * \param pppsz_longname an pointer to an array of string to contain - the long names of the modules. If set to NULL the function don't use it. - * \return the NULL terminated array - */ -char ** module_GetModulesNamesForCapability( const char *psz_capability, - char ***pppsz_longname ) -{ - size_t count = 0; - char **psz_ret; - - module_t **list = module_list_get (NULL); - - /* Proceed in two passes: count the number of modules first */ - for (size_t i = 0; list[i]; i++) - { - module_t *p_module = list[i]; - const char *psz_module_capability = p_module->psz_capability; - - if( psz_module_capability - && !strcmp( psz_module_capability, psz_capability ) ) - count++; - } - - /* Then get the names */ - psz_ret = malloc( sizeof(char*) * (count+1) ); - if( pppsz_longname ) - *pppsz_longname = malloc( sizeof(char*) * (count+1) ); - if( !psz_ret || ( pppsz_longname && *pppsz_longname == NULL ) ) - { - free( psz_ret ); - if( pppsz_longname ) - { - free( *pppsz_longname ); - *pppsz_longname = NULL; - } - module_list_free (list); - return NULL; - } - - for (size_t i = 0, j = 0; list[i]; i++) - { - module_t *p_module = list[i]; - const char *psz_module_capability = p_module->psz_capability; - - if( psz_module_capability - && !strcmp( psz_module_capability, psz_capability ) ) - { - /* Explicit hack: Use the last shortcut. It _should_ be - * different from the object name, at least if the object - * contains multiple submodules with the same capability. */ - unsigned k = 0; - while( p_module->pp_shortcuts[k] != NULL ) - k++; - assert( k > 0); /* pp_shortcuts[0] is always set */ - psz_ret[j] = strdup( p_module->pp_shortcuts[k - 1] ); - if( pppsz_longname ) - (*pppsz_longname)[j] = strdup( module_get_name( p_module, true ) ); - j++; - } - } - psz_ret[count] = NULL; - - module_list_free (list); - - return psz_ret; -} - /** * Get the configuration of a module * @@ -841,7 +733,6 @@ module_config_t *module_config_get( const module_t *module, unsigned *restrict p { const module_config_t *item = module->p_config + i; if( item->b_internal /* internal option */ - || item->b_unsaveable /* non-modifiable option */ || item->b_removed /* removed option */ ) continue; @@ -927,20 +818,17 @@ static void AllocateAllPlugins( vlc_object_t *p_this, module_bank_t *p_bank ) int count,i; char * path; vlc_array_t *arraypaths = vlc_array_new(); + const bool b_reset = var_InheritBool( p_this, "reset-plugins-cache" ); /* Contruct the special search path for system that have a relocatable - * executable. Set it to /modules and /plugins. */ + * executable. Set it to /plugins. */ + assert( vlcpath ); - if( vlcpath && asprintf( &path, "%s" DIR_SEP "modules", vlcpath ) != -1 ) - vlc_array_append( arraypaths, path ); - if( vlcpath && asprintf( &path, "%s" DIR_SEP "plugins", vlcpath ) != -1 ) + if( asprintf( &path, "%s" DIR_SEP "plugins", vlcpath ) != -1 ) vlc_array_append( arraypaths, path ); -#ifndef WIN32 - vlc_array_append( arraypaths, strdup( PLUGIN_PATH ) ); -#endif /* If the user provided a plugin path, we add it to the list */ - char *userpaths = config_GetPsz( p_this, "plugin-path" ); + char *userpaths = var_InheritString( p_this, "plugin-path" ); char *paths_iter; for( paths_iter = userpaths; paths_iter; ) @@ -957,11 +845,20 @@ static void AllocateAllPlugins( vlc_object_t *p_this, module_bank_t *p_bank ) if( !path ) continue; + size_t offset = p_module_bank->i_cache; + if( b_reset ) + CacheDelete( p_this, path ); + else + CacheLoad( p_this, p_module_bank, path ); + msg_Dbg( p_this, "recursively browsing `%s'", path ); /* Don't go deeper than 5 subdirectories */ AllocatePluginDir( p_this, p_bank, path, 5 ); + + CacheSave( p_this, path, p_module_bank->pp_cache + offset, + p_module_bank->i_cache - offset ); free( path ); } @@ -978,21 +875,23 @@ static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank, if( i_maxdepth == 0 ) return; - DIR *dh = utf8_opendir (psz_dir); + DIR *dh = vlc_opendir (psz_dir); if (dh == NULL) return; /* Parse the directory and try to load all files it contains. */ for (;;) { - char *file = utf8_readdir (dh), *path; + char *file = vlc_readdir (dh), *path; struct stat st; if (file == NULL) break; /* Skip ".", ".." */ - if (!strcmp (file, ".") || !strcmp (file, "..")) + if (!strcmp (file, ".") || !strcmp (file, "..") + /* Skip directories for unsupported optimizations */ + || !vlc_CPU_CheckPluginDir (file)) { free (file); continue; @@ -1000,7 +899,7 @@ static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank, const int pathlen = asprintf (&path, "%s"DIR_SEP"%s", psz_dir, file); free (file); - if (pathlen == -1 || utf8_stat (path, &st)) + if (pathlen == -1 || vlc_stat (path, &st)) continue; if (S_ISDIR (st.st_mode)) @@ -1008,10 +907,11 @@ static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank, AllocatePluginDir (p_this, p_bank, path, i_maxdepth - 1); else if (S_ISREG (st.st_mode) - && ((size_t)pathlen >= strlen (LIBEXT)) - && !strncasecmp (path + pathlen - strlen (LIBEXT), LIBEXT, - strlen (LIBEXT))) - /* ^^ We only load files ending with LIBEXT */ + && strncmp (path, "lib", 3) + && ((size_t)pathlen >= sizeof ("_plugin"LIBEXT)) + && !strncasecmp (path + pathlen - strlen ("_plugin"LIBEXT), + "_plugin"LIBEXT, strlen ("_plugni"LIBEXT))) + /* ^^ We only load files matching "lib*_plugin"LIBEXT */ AllocatePluginFile (p_this, p_bank, path, st.st_mtime, st.st_size); free (path); @@ -1042,16 +942,16 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, p_module = AllocatePlugin( p_this, psz_file ); } else - /* If junk dll, don't try to load it */ - if( p_cache_entry->b_junk ) - return -1; - else { module_config_t *p_item = NULL, *p_end = NULL; p_module = p_cache_entry->p_module; p_module->b_loaded = false; + /* If plugin-path contains duplicate entries... */ + if( p_module->next != NULL ) + return 0; /* already taken care of that one */ + /* For now we force loading if the module's config contains * callbacks or actions. * Could be optimized by adding an API call.*/ @@ -1064,13 +964,14 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, break; } } - if( p_module == p_cache_entry->p_module ) - p_cache_entry->b_used = true; } if( p_module == NULL ) return -1; + /* We have not already scanned and inserted this module */ + assert( p_module->next == NULL ); + /* Everything worked fine ! * The module is ready to be added to the list. */ p_module->b_builtin = false; @@ -1079,6 +980,7 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, p_module->psz_object_name, p_module->psz_longname ); */ p_module->next = p_bank->head; p_bank->head = p_module; + assert( p_module->next != NULL ); /* Insertion done */ if( !p_module_bank->b_cache ) return 0; @@ -1086,7 +988,7 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, /* Add entry to cache */ module_cache_t **pp_cache = p_bank->pp_cache; - pp_cache = realloc( pp_cache, (p_bank->i_cache + 1) * sizeof(void *) ); + pp_cache = realloc_or_free( pp_cache, (p_bank->i_cache + 1) * sizeof(void *) ); if( pp_cache == NULL ) return -1; pp_cache[p_bank->i_cache] = malloc( sizeof(module_cache_t) ); @@ -1095,8 +997,6 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, pp_cache[p_bank->i_cache]->psz_file = strdup( psz_file ); pp_cache[p_bank->i_cache]->i_time = i_file_time; pp_cache[p_bank->i_cache]->i_size = i_file_size; - pp_cache[p_bank->i_cache]->b_junk = p_module ? 0 : 1; - pp_cache[p_bank->i_cache]->b_used = true; pp_cache[p_bank->i_cache]->p_module = p_module; p_bank->pp_cache = pp_cache; p_bank->i_cache++; @@ -1157,12 +1057,9 @@ static module_t * AllocatePlugin( vlc_object_t * p_this, const char *psz_file ) *****************************************************************************/ static void DupModule( module_t *p_module ) { - char **pp_shortcut; - - for( pp_shortcut = p_module->pp_shortcuts ; *pp_shortcut ; pp_shortcut++ ) - { - *pp_shortcut = strdup( *pp_shortcut ); - } + char **pp_shortcuts = p_module->pp_shortcuts; + for( unsigned i = 0; i < p_module->i_shortcuts; i++ ) + pp_shortcuts[i] = strdup( p_module->pp_shortcuts[i] ); /* We strdup() these entries so that they are still valid when the * module is unloaded. */ @@ -1172,6 +1069,7 @@ static void DupModule( module_t *p_module ) p_module->psz_longname = strdup( p_module->psz_longname ); p_module->psz_help = p_module->psz_help ? strdup( p_module->psz_help ) : NULL; + p_module->domain = p_module->domain ? strdup( p_module->domain ) : NULL; for (module_t *subm = p_module->submodule; subm; subm = subm->next) DupModule (subm); @@ -1184,20 +1082,19 @@ static void DupModule( module_t *p_module ) *****************************************************************************/ static void UndupModule( module_t *p_module ) { - char **pp_shortcut; + char **pp_shortcuts = p_module->pp_shortcuts; for (module_t *subm = p_module->submodule; subm; subm = subm->next) UndupModule (subm); - for( pp_shortcut = p_module->pp_shortcuts ; *pp_shortcut ; pp_shortcut++ ) - { - free( *pp_shortcut ); - } + for( unsigned i = 0; i < p_module->i_shortcuts; i++ ) + free( pp_shortcuts[i] ); free( p_module->psz_capability ); FREENULL( p_module->psz_shortname ); free( p_module->psz_longname ); FREENULL( p_module->psz_help ); + free( p_module->domain ); } #endif /* HAVE_DYNAMIC_PLUGINS */