* modules.c : Built-in and plugin modules management functions
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: modules.c,v 1.45 2001/12/10 04:53:11 sam Exp $
+ * $Id: modules.c,v 1.46 2001/12/30 07:09:56 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Ethan C. Baldridge <BaldridgeE@cadmus.com>
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
-#include "defs.h"
/* Some faulty libcs have a broken struct dirent when _FILE_OFFSET_BITS
* is set to 64. Don't try to be cleverer. */
#include <stdio.h> /* sprintf() */
#include <string.h> /* strdup() */
+#include <videolan/vlc.h>
+
#if !defined( _MSC_VER )
#include <dirent.h>
#endif
# undef HAVE_DYNAMIC_PLUGINS
#endif
-#ifdef SYS_BEOS
-# include "beos_specific.h"
-#endif
-
-#ifdef SYS_DARWIN
-# include "darwin_specific.h"
-#endif
-
-#include "common.h"
-#include "intf_msg.h"
-#include "threads.h"
-#include "mtime.h"
-#include "tests.h"
#include "netutils.h"
-#include "modules.h"
#include "interface.h"
#include "intf_playlist.h"
#include "iso_lang.h"
#ifdef HAVE_DYNAMIC_PLUGINS
-# include "modules_core.h"
+# include "modules_plugin.h"
#endif
#include "modules_builtin.h"
-#include "modules_export.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
#ifdef HAVE_DYNAMIC_PLUGINS
-static int AllocatePluginModule ( char * );
-#endif
-#ifdef ALLOCATE_ALL_BUILTINS
-static int AllocateBuiltinModule( int ( * ) ( module_t * ),
- int ( * ) ( module_t * ),
- int ( * ) ( module_t * ) );
+static void AllocateAllPlugins ( void );
+static int AllocatePluginModule ( char * );
#endif
-static int DeleteModule ( module_t * );
-static int LockModule ( module_t * );
-static int UnlockModule ( module_t * );
+static void AllocateAllBuiltins ( void );
+static int AllocateBuiltinModule( int ( * ) ( module_t * ),
+ int ( * ) ( module_t * ),
+ int ( * ) ( module_t * ) );
+static int DeleteModule ( module_t * );
+static int LockModule ( module_t * );
+static int UnlockModule ( module_t * );
#ifdef HAVE_DYNAMIC_PLUGINS
-static int HideModule ( module_t * );
-static int CallSymbol ( module_t *, char * );
+static int HideModule ( module_t * );
+static int CallSymbol ( module_t *, char * );
#endif
static module_symbols_t symbols;
*****************************************************************************/
void module_InitBank( void )
{
-#ifdef HAVE_DYNAMIC_PLUGINS
- static char * path[] = { ".", "plugins", PLUGIN_PATH, NULL, NULL };
-
- char ** ppsz_path = path;
- char * psz_fullpath;
- char * psz_file;
-#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
- char * psz_vlcpath = system_GetProgramPath();
- int i_vlclen = strlen( psz_vlcpath );
- boolean_t b_notinroot;
-#endif
- DIR * dir;
- struct dirent * file;
-#endif /* HAVE_DYNAMIC_PLUGINS */
-
p_module_bank->first = NULL;
+ p_module_bank->i_count = 0;
vlc_mutex_init( &p_module_bank->lock );
/*
* Store the symbols to be exported
*/
STORE_SYMBOLS( &symbols );
-#ifdef TRACE
- STORE_TRACE_SYMBOLS( &symbols );
-#endif
/*
* Check all the built-in modules
*/
-#ifdef ALLOCATE_ALL_BUILTINS
intf_WarnMsg( 2, "module: checking built-in modules" );
-
- ALLOCATE_ALL_BUILTINS();
-#endif
+ AllocateAllBuiltins();
/*
* Check all the plugin modules we can find
*/
#ifdef HAVE_DYNAMIC_PLUGINS
intf_WarnMsg( 2, "module: checking plugin modules" );
-
- for( ; *ppsz_path != NULL ; ppsz_path++ )
- {
- /* Store strlen(*ppsz_path) for later use. */
- int i_dirlen = strlen( *ppsz_path );
-
-#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
- b_notinroot = 0;
- /* Under BeOS, we need to add beos_GetProgramPath() to access
- * files under the current directory */
- if( ( i_dirlen > 1 ) && strncmp( *ppsz_path, "/", 1 ) )
- {
- i_dirlen += i_vlclen + 2;
- b_notinroot = 1;
-
- psz_fullpath = malloc( i_dirlen );
- if( psz_fullpath == NULL )
- {
- continue;
- }
- sprintf( psz_fullpath, "%s/%s", psz_vlcpath, *ppsz_path );
- }
- else
-#endif
- {
- psz_fullpath = *ppsz_path;
- }
-
- intf_WarnMsgImm( 1, "module: browsing `%s'", psz_fullpath );
-
- if( (dir = opendir( psz_fullpath )) )
- {
- /* Parse the directory and try to load all files it contains. */
- while( (file = readdir( dir )) )
- {
- int i_filelen = strlen( file->d_name );
-
- /* We only load files ending with ".so" */
- if( i_filelen > 3
- && !strncmp( file->d_name + i_filelen - 3, ".so", 3 ) )
- {
- psz_file = malloc( i_dirlen + i_filelen + 2 );
- if( psz_file == NULL )
- {
- continue;
- }
- sprintf( psz_file, "%s/%s", psz_fullpath, file->d_name );
-
- /* We created a nice filename -- now we just try to load
- * it as a plugin module. */
- AllocatePluginModule( psz_file );
-
- /* We don't care if the allocation succeeded */
- free( psz_file );
- }
- }
-
- /* Close the directory if successfully opened */
- closedir( dir );
- }
-
-#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
- if( b_notinroot )
- {
- free( psz_fullpath );
- }
+ AllocateAllPlugins();
#endif
- }
-#endif /* HAVE_DYNAMIC_PLUGINS */
- intf_WarnMsg( 3, "module: module bank initialized" );
+ intf_WarnMsg( 2, "module: module bank initialized, found %i modules",
+ p_module_bank->i_count );
return;
}
if( DeleteModule( p_module_bank->first ) )
{
/* Module deletion failed */
- intf_ErrMsg( "module error: `%s' can't be removed. trying harder.",
+ intf_ErrMsg( "module error: `%s' can't be removed, trying harder",
p_module_bank->first->psz_name );
/* We just free the module by hand. Niahahahahaha. */
return;
}
+int module_NeedMemcpy( memcpy_module_t *p_memcpy )
+{
+ p_memcpy->p_module = module_Need( MODULE_CAPABILITY_MEMCPY, NULL, NULL );
+
+ if( p_memcpy->p_module == NULL )
+ {
+ return -1;
+ }
+
+ p_memcpy->pf_memcpy = p_memcpy->p_module->p_functions->memcpy.functions.memcpy.fast_memcpy;
+
+ return 0;
+}
+
+void module_UnneedMemcpy( memcpy_module_t *p_memcpy )
+{
+ module_Unneed( p_memcpy->p_module );
+}
+
+#if 0
+int module_NeedIntf( intf_module_t *p_intf )
+{
+ p_intf->p_module = module_Need( MODULE_CAPABILITY_INTF, NULL );
+
+ if( p_intf->p_module == NULL )
+ {
+ return -1;
+ }
+
+ p_intf->pf_open = p_intf->p_module->p_functions->intf.functions.intf.pf_open;
+ p_intf->pf_run = p_intf->p_module->p_functions->intf.functions.intf.pf_run;
+ p_intf->pf_close = p_intf->p_module->p_functions->intf.functions.intf.pf_close;
+
+ return 0;
+}
+#endif
+
/*****************************************************************************
* module_Need: return the best module function, given a capability list.
*****************************************************************************
* This function returns the module that best fits the asked capabilities.
*****************************************************************************/
-module_t * module_Need( int i_capabilities, void *p_data )
+module_t * module_Need( int i_capability, char *psz_name, probedata_t *p_data )
{
module_t * p_module;
- module_t * p_bestmodule = NULL;
- int i_score, i_totalscore, i_bestscore = 0;
- int i_index;
/* We take the global lock */
vlc_mutex_lock( &p_module_bank->lock );
- /* Parse the module list for capabilities and probe each of them */
- for( p_module = p_module_bank->first ;
- p_module != NULL ;
- p_module = p_module->next )
+ if( psz_name != NULL && *psz_name )
{
- /* Test that this module can do everything we need */
- if( ( p_module->i_capabilities & i_capabilities ) == i_capabilities )
+ /* A module name was requested. Use the first matching one. */
+ int i_index;
+ boolean_t b_ok = 0;
+
+ for( p_module = p_module_bank->first;
+ p_module != NULL;
+ p_module = p_module->next )
{
- i_totalscore = 0;
+ /* Test that this module can do everything we need */
+ if( !(p_module->i_capabilities & ( 1 << i_capability )) )
+ {
+ continue;
+ }
+ /* Test if we have the required CPU */
+ if( (p_module->i_cpu_capabilities & p_main->i_cpu_capabilities)
+ != p_module->i_cpu_capabilities )
+ {
+ continue;
+ }
+
+ /* Test if this plugin exports the required shortcut */
+ for( i_index = 0;
+ !b_ok && p_module->pp_shortcuts[i_index];
+ i_index++ )
+ {
+ b_ok = !strcmp( psz_name, p_module->pp_shortcuts[i_index] );
+ }
+
+ if( b_ok )
+ {
+ break;
+ }
+ }
+
+ if( b_ok )
+ {
+ /* Open it ! */
LockModule( p_module );
+ }
+ else
+ {
+ intf_ErrMsg( "module error: requested %s module `%s' not found",
+ GetCapabilityName( i_capability ), psz_name );
+ }
+ }
+ else
+ {
+ /* No module name was requested. Sort the modules and test them */
+ typedef struct module_list_s
+ {
+ struct module_s *p_module;
+ struct module_list_s* p_next;
+ } module_list_t;
+
+ int i_score = 0;
+ int i_index = 0;
+ struct module_list_s *p_list = malloc( p_module_bank->i_count
+ * sizeof( module_list_t ) );
+ struct module_list_s *p_first = NULL;
+
+ /* Parse the module list for capabilities and probe each of them */
+ for( p_module = p_module_bank->first ;
+ p_module != NULL ;
+ p_module = p_module->next )
+ {
+ /* Test that this module can do everything we need */
+ if( !(p_module->i_capabilities & ( 1 << i_capability )) )
+ {
+ continue;
+ }
- /* Parse all the requested capabilities and test them */
- for( i_index = 0 ; (1 << i_index) <= i_capabilities ; i_index++ )
+ /* Test if we have the required CPU */
+ if( (p_module->i_cpu_capabilities & p_main->i_cpu_capabilities)
+ != p_module->i_cpu_capabilities )
{
- if( ( (1 << i_index) & i_capabilities ) )
- {
- i_score = ( (function_list_t *)p_module->p_functions)
- [i_index].pf_probe( p_data );
+ continue;
+ }
- if( i_score )
- {
- i_totalscore += i_score;
- }
- else
- {
- break;
- }
- }
+ /* Test if we requested a particular intf plugin */
+#if 0
+ if( i_capability == MODULE_CAPABILITY_INTF
+ && p_module->psz_program != NULL
+ && strcmp( p_module->psz_program, p_main->psz_arg0 ) )
+ {
+ continue;
}
- intf_WarnMsg( 3, "module: %s has score %d",
- p_module->psz_name, i_totalscore );
+#endif
- /* If the high score was broken, we have a new champion */
- if( i_totalscore > i_bestscore )
+ /* Store this new module */
+ p_list[ i_index ].p_module = p_module;
+
+ if( i_index == 0 )
+ {
+ p_list[ i_index ].p_next = NULL;
+ p_first = p_list;
+ }
+ else
{
- /* Keep the current module locked, but release the previous */
- if( p_bestmodule != NULL )
+ /* Ok, so at school you learned that quicksort is quick, and
+ * bubble sort sucks raw eggs. But that's when dealing with
+ * thousands of items. Here we have barely 50. */
+ struct module_list_s *p_newlist = p_first;
+
+ if( p_first->p_module->pi_score[i_capability]
+ < p_module->pi_score[i_capability] )
{
- UnlockModule( p_bestmodule );
+ p_list[ i_index ].p_next = p_first;
+ p_first = &p_list[ i_index ];
}
+ else
+ {
+ while( p_newlist->p_next != NULL
+ && p_newlist->p_next
+ ->p_module->pi_score[i_capability]
+ >= p_module->pi_score[i_capability] )
+ {
+ p_newlist = p_newlist->p_next;
+ }
- /* This is the new best module */
- i_bestscore = i_totalscore;
- p_bestmodule = p_module;
+ p_list[ i_index ].p_next = p_newlist->p_next;
+ p_newlist->p_next = &p_list[ i_index ];
+ }
}
- else
+
+ i_index++;
+ }
+
+ /* Parse the linked list and use the first successful module */
+ while( p_first != NULL )
+ {
+ LockModule( p_first->p_module );
+
+ /* Test the requested capability */
+ i_score += ((function_list_t *)p_first->p_module->p_functions)
+ [i_capability].pf_probe( p_data );
+
+ /* If the high score was broken, we have a new champion */
+ if( i_score )
{
- /* This module wasn't interesting, unlock it and forget it */
- UnlockModule( p_module );
+ break;
}
+
+ UnlockModule( p_first->p_module );
+
+ p_first = p_first->p_next;
}
+
+ p_module = (p_first == NULL) ? NULL : p_first->p_module;
+ free( p_list );
}
/* We can release the global lock, module refcount was incremented */
vlc_mutex_unlock( &p_module_bank->lock );
- if( p_bestmodule != NULL )
+ if( p_module != NULL )
{
- intf_WarnMsg( 1, "module: locking module `%s'",
- p_bestmodule->psz_name );
+ intf_WarnMsg( 1, "module: locking %s module `%s'",
+ GetCapabilityName( i_capability ),
+ p_module->psz_name );
}
/* Don't forget that the module is still locked if bestmodule != NULL */
- return( p_bestmodule );
+ return( p_module );
}
/*****************************************************************************
* Following functions are local.
*****************************************************************************/
+/*****************************************************************************
+ * AllocateAllPlugins: load all plugin modules we can find.
+ *****************************************************************************/
#ifdef HAVE_DYNAMIC_PLUGINS
+static void AllocateAllPlugins( void )
+{
+ static char * path[] = { ".", "plugins", PLUGIN_PATH, NULL, NULL };
+
+ char ** ppsz_path = path;
+ char * psz_fullpath;
+ char * psz_file;
+#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
+ char * psz_vlcpath = system_GetProgramPath();
+ int i_vlclen = strlen( psz_vlcpath );
+ boolean_t b_notinroot;
+#endif
+ DIR * dir;
+ struct dirent * file;
+
+ for( ; *ppsz_path != NULL ; ppsz_path++ )
+ {
+ /* Store strlen(*ppsz_path) for later use. */
+ int i_dirlen = strlen( *ppsz_path );
+
+#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
+ b_notinroot = 0;
+ /* Under BeOS, we need to add beos_GetProgramPath() to access
+ * files under the current directory */
+ if( ( i_dirlen > 1 ) && strncmp( *ppsz_path, "/", 1 ) )
+ {
+ i_dirlen += i_vlclen + 2;
+ b_notinroot = 1;
+
+ psz_fullpath = malloc( i_dirlen );
+ if( psz_fullpath == NULL )
+ {
+ continue;
+ }
+ sprintf( psz_fullpath, "%s/%s", psz_vlcpath, *ppsz_path );
+ }
+ else
+#endif
+ {
+ psz_fullpath = *ppsz_path;
+ }
+
+ intf_WarnMsgImm( 1, "module: browsing `%s'", psz_fullpath );
+
+ if( (dir = opendir( psz_fullpath )) )
+ {
+ /* Parse the directory and try to load all files it contains. */
+ while( (file = readdir( dir )) )
+ {
+ int i_filelen = strlen( file->d_name );
+
+ /* We only load files ending with ".so" */
+ if( i_filelen > 3
+ && !strncmp( file->d_name + i_filelen - 3, ".so", 3 ) )
+ {
+ psz_file = malloc( i_dirlen + i_filelen + 2 );
+ if( psz_file == NULL )
+ {
+ continue;
+ }
+ sprintf( psz_file, "%s/%s", psz_fullpath, file->d_name );
+
+ /* We created a nice filename -- now we just try to load
+ * it as a plugin module. */
+ AllocatePluginModule( psz_file );
+
+ /* We don't care if the allocation succeeded */
+ free( psz_file );
+ }
+ }
+
+ /* Close the directory if successfully opened */
+ closedir( dir );
+ }
+
+#if defined( SYS_BEOS ) || defined( SYS_DARWIN )
+ if( b_notinroot )
+ {
+ free( psz_fullpath );
+ }
+#endif
+ }
+}
+
/*****************************************************************************
* AllocatePluginModule: load a module into memory and initialize it.
*****************************************************************************
*****************************************************************************/
static int AllocatePluginModule( char * psz_filename )
{
+ char **pp_shortcut;
module_t * p_module, * p_othermodule;
module_handle_t handle;
p_module->p_symbols = &symbols;
/* Initialize the module : fill p_module->psz_name, etc. */
- if( CallSymbol( p_module, "InitModule" ) != 0 )
+ if( CallSymbol( p_module, "InitModule" MODULE_SUFFIX ) != 0 )
{
/* We couldn't call InitModule() */
free( p_module );
return( -1 );
}
- /* Check that version numbers match */
- if( strcmp( VLC_VERSION, p_module->psz_version ) )
- {
- free( p_module );
- module_unload( handle );
- return( -1 );
- }
-
/* Check that we don't already have a module with this name */
for( p_othermodule = p_module_bank->first ;
p_othermodule != NULL ;
{
if( !strcmp( p_othermodule->psz_name, p_module->psz_name ) )
{
+ intf_WarnMsg( 5, "module warning: cannot load %s, a module named "
+ "`%s' already exists",
+ psz_filename, p_module->psz_name );
free( p_module );
module_unload( handle );
return( -1 );
}
/* Activate the module : fill the capability structure, etc. */
- if( CallSymbol( p_module, "ActivateModule" ) != 0 )
+ if( CallSymbol( p_module, "ActivateModule" MODULE_SUFFIX ) != 0 )
{
/* We couldn't call ActivateModule() */
free( p_module );
return( -1 );
}
+ for( pp_shortcut = p_module->pp_shortcuts ; *pp_shortcut ; pp_shortcut++ )
+ {
+ *pp_shortcut = strdup( *pp_shortcut );
+ }
+
/* We strdup() these entries so that they are still valid when the
* module is unloaded. */
p_module->is.plugin.psz_filename =
strdup( p_module->is.plugin.psz_filename );
p_module->psz_name = strdup( p_module->psz_name );
p_module->psz_longname = strdup( p_module->psz_longname );
- p_module->psz_version = strdup( p_module->psz_version );
+
if( p_module->is.plugin.psz_filename == NULL
|| p_module->psz_name == NULL
- || p_module->psz_longname == NULL
- || p_module->psz_version == NULL )
+ || p_module->psz_longname == NULL )
{
intf_ErrMsg( "module error: can't duplicate strings" );
- if( p_module->is.plugin.psz_filename != NULL )
- {
- free( p_module->is.plugin.psz_filename );
- }
-
- if( p_module->psz_name != NULL )
- {
- free( p_module->psz_name );
- }
-
- if( p_module->psz_longname != NULL )
- {
- free( p_module->psz_longname );
- }
-
- if( p_module->psz_version != NULL )
- {
- free( p_module->psz_version );
- }
+ free( p_module->is.plugin.psz_filename );
+ free( p_module->psz_name );
+ free( p_module->psz_longname );
+ free( p_module->psz_program );
free( p_module );
module_unload( handle );
return( -1 );
}
+ if( p_module->psz_program != NULL )
+ {
+ p_module->psz_program = strdup( p_module->psz_program );
+ }
+
/* Everything worked fine ! The module is ready to be added to the list. */
p_module->i_usage = 0;
p_module->i_unused_delay = 0;
p_module->next = p_module_bank->first;
p_module->prev = NULL;
p_module_bank->first = p_module;
+ p_module_bank->i_count++;
/* Immediate message so that a slow module doesn't make the user wait */
intf_WarnMsgImm( 2, "module: new plugin module `%s', %s",
}
#endif /* HAVE_DYNAMIC_PLUGINS */
-#ifdef ALLOCATE_ALL_BUILTINS
+/*****************************************************************************
+ * AllocateAllBuiltins: load all modules we were built with.
+ *****************************************************************************/
+static void AllocateAllBuiltins( void )
+{
+ ALLOCATE_ALL_BUILTINS();
+}
+
/*****************************************************************************
* AllocateBuiltinModule: initialize a built-in module.
*****************************************************************************
return( -1 );
}
- /* Check that version numbers match */
- if( strcmp( VLC_VERSION, p_module->psz_version ) )
- {
- free( p_module );
- return( -1 );
- }
-
/* Check that we don't already have a module with this name */
for( p_othermodule = p_module_bank->first ;
p_othermodule != NULL ;
{
if( !strcmp( p_othermodule->psz_name, p_module->psz_name ) )
{
+ intf_WarnMsg( 5, "module warning: cannot load builtin `%s', a "
+ "module named `%s' already exists",
+ p_module->psz_name, p_module->psz_name );
free( p_module );
return( -1 );
}
return( -1 );
}
- /* We strdup() these entries so that they are still valid when the
- * module is unloaded. */
- p_module->psz_name = strdup( p_module->psz_name );
- p_module->psz_longname = strdup( p_module->psz_longname );
- p_module->psz_version = strdup( p_module->psz_version );
- if( p_module->psz_name == NULL
- || p_module->psz_longname == NULL
- || p_module->psz_version == NULL )
- {
- intf_ErrMsg( "module error: can't duplicate strings" );
-
- if( p_module->psz_name != NULL )
- {
- free( p_module->psz_name );
- }
-
- if( p_module->psz_longname != NULL )
- {
- free( p_module->psz_longname );
- }
-
- if( p_module->psz_version != NULL )
- {
- free( p_module->psz_version );
- }
-
- free( p_module );
- return( -1 );
- }
-
/* Everything worked fine ! The module is ready to be added to the list. */
p_module->i_usage = 0;
p_module->i_unused_delay = 0;
p_module->next = p_module_bank->first;
p_module->prev = NULL;
p_module_bank->first = p_module;
+ p_module_bank->i_count++;
/* Immediate message so that a slow module doesn't make the user wait */
intf_WarnMsgImm( 2, "module: new builtin module `%s', %s",
return( 0 );
}
-#endif /* ALLOCATE_ALL_BUILTINS */
/*****************************************************************************
* DeleteModule: delete a module and its structure.
#endif
/* Unlink the module from the linked list. */
- if( p_module == p_module_bank->first )
- {
- p_module_bank->first = p_module->next;
- }
-
if( p_module->prev != NULL )
{
p_module->prev->next = p_module->next;
}
+ else
+ {
+ p_module_bank->first = p_module->next;
+ }
if( p_module->next != NULL )
{
p_module->next->prev = p_module->prev;
}
+ p_module_bank->i_count--;
+
/* We free the structures that we strdup()ed in Allocate*Module(). */
#ifdef HAVE_DYNAMIC_PLUGINS
if( !p_module->b_builtin )
{
+ char **pp_shortcut = p_module->pp_shortcuts;
+
+ for( ; *pp_shortcut ; pp_shortcut++ )
+ {
+ free( *pp_shortcut );
+ }
+
free( p_module->is.plugin.psz_filename );
+ free( p_module->psz_name );
+ free( p_module->psz_longname );
+ free( p_module->psz_program );
}
#endif
- free( p_module->psz_name );
- free( p_module->psz_longname );
- free( p_module->psz_version );
free( p_module );
* to be a bit more clever here. */
/* Activate the module : fill the capability structure, etc. */
- if( CallSymbol( p_module, "ActivateModule" ) != 0 )
+ if( CallSymbol( p_module, "ActivateModule" MODULE_SUFFIX ) != 0 )
{
/* We couldn't call ActivateModule() -- looks nasty, but
* we can't do much about it. Just try to unload module. */
}
/* Deactivate the module : free the capability structure, etc. */
- if( CallSymbol( p_module, "DeactivateModule" ) != 0 )
+ if( CallSymbol( p_module, "DeactivateModule" MODULE_SUFFIX ) != 0 )
{
/* We couldn't call DeactivateModule() -- looks nasty, but
* we can't do much about it. Just try to unload module anyway. */