Commit fd1220a2 authored by Sam Hocevar's avatar Sam Hocevar

 . removed a few useless malloc() and unused variables in the audio SDL stuff
 . prepared the work for built-in modules (not yet finished)
parent 627633ae
...@@ -38,31 +38,25 @@ ...@@ -38,31 +38,25 @@
* #define MODULE_VAR(blah) "VLC_MODULE_foo_blah" * #define MODULE_VAR(blah) "VLC_MODULE_foo_blah"
* *
* and, if BUILTIN is set, we will also need: * and, if BUILTIN is set, we will also need:
* #define InitModule foo_InitModule * #define MODULE_FUNC( zog ) module_foo_zog
* #define ActivateModule foo_ActivateModule
* #define DeactivateModule foo_DeactivateModule
* *
* this can't easily be done with the C preprocessor, thus a few ugly hacks. * this can't easily be done with the C preprocessor, thus a few ugly hacks.
*/ */
/* I can't believe I need to do this to change foo to "foo" */ /* I can't believe I need to do this to change foo to "foo" */
#define UGLY_KLUDGE(z) NASTY_CROCK(z) #define UGLY_KLUDGE( z ) NASTY_CROCK( z )
#define NASTY_CROCK(z) #z #define NASTY_CROCK( z ) #z
/* And I need to do _this_ to change foo bar to foo_bar ! */ /* And I need to do _this_ to change foo bar to foo_inner_bar ! */
#define AWFUL_BRITTLE(y,z) CRUDE_HACK(y,z) #define AWFUL_BRITTLE( y, z ) CRUDE_HACK( y, z )
#define CRUDE_HACK(y,z) y##_##z #define CRUDE_HACK( y, z ) module_##y##_##z
/* Also, I need to do this to change blah to "VLC_MODULE_foo_blah" */ /* Also, I need to do this to change blah to "VLC_MODULE_foo_blah" */
#define MODULE_STRING UGLY_KLUDGE(MODULE_NAME) #define MODULE_STRING UGLY_KLUDGE( MODULE_NAME )
#define MODULE_VAR(z) "VLC_MODULE_" UGLY_KLUDGE(MODULE_NAME) "_" #z #define MODULE_VAR( z ) "VLC_MODULE_" UGLY_KLUDGE( MODULE_NAME ) "_" #z
/* If the module is built-in, then we need to define foo_InitModule instead /* If the module is built-in, then we need to define foo_InitModule instead
* of InitModule. Same for Activate- and DeactivateModule. */ * of InitModule. Same for Activate- and DeactivateModule. */
#ifdef BUILTIN #define MODULE_FUNC( function ) AWFUL_BRITTLE( MODULE_NAME, function )
# define InitModule AWFUL_BRITTLE(MODULE_NAME,InitModule)
# define ActivateModule AWFUL_BRITTLE(MODULE_NAME,ActivateModule)
# define DeactivateModule AWFUL_BRITTLE(MODULE_NAME,DeactivateModule)
#endif
/***************************************************************************** /*****************************************************************************
* Macros used to build the configuration structure. * Macros used to build the configuration structure.
......
...@@ -35,8 +35,7 @@ ...@@ -35,8 +35,7 @@
#include <stdio.h> /* "intf_msg.h" */ #include <stdio.h> /* "intf_msg.h" */
#include <stdlib.h> /* calloc(), malloc(), free() */ #include <stdlib.h> /* calloc(), malloc(), free() */
#include <SDL/SDL.h> /* SDL base include */
#include "SDL/SDL.h" /* SDL base include */
#include "config.h" #include "config.h"
#include "common.h" /* boolean_t, byte_t */ #include "common.h" /* boolean_t, byte_t */
...@@ -51,7 +50,6 @@ ...@@ -51,7 +50,6 @@
#include "modules.h" #include "modules.h"
/***************************************************************************** /*****************************************************************************
* aout_sys_t: dsp audio output method descriptor * aout_sys_t: dsp audio output method descriptor
***************************************************************************** *****************************************************************************
...@@ -66,9 +64,10 @@ typedef struct aout_sys_s ...@@ -66,9 +64,10 @@ typedef struct aout_sys_s
{ {
byte_t * audio_buf; byte_t * audio_buf;
int i_audio_end; int i_audio_end;
boolean_t b_active; boolean_t b_active;
} aout_sys_t;
} aout_sys_t;
/***************************************************************************** /*****************************************************************************
* Local prototypes. * Local prototypes.
...@@ -80,7 +79,8 @@ static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info ); ...@@ -80,7 +79,8 @@ static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info );
static void aout_Play ( aout_thread_t *p_aout, static void aout_Play ( aout_thread_t *p_aout,
byte_t *buffer, int i_size ); byte_t *buffer, int i_size );
static void aout_Close ( aout_thread_t *p_aout ); static void aout_Close ( aout_thread_t *p_aout );
static void SDL_aout_callback(void *userdata, Uint8 *stream, int len);
static void aout_SDLCallback ( void *userdata, Uint8 *stream, int len );
/***************************************************************************** /*****************************************************************************
* Functions exported as capabilities. They are declared as static so that * Functions exported as capabilities. They are declared as static so that
...@@ -97,45 +97,36 @@ void aout_getfunctions( function_list_t * p_function_list ) ...@@ -97,45 +97,36 @@ void aout_getfunctions( function_list_t * p_function_list )
} }
/***************************************************************************** /*****************************************************************************
* aout_Probe: probes the audio device and return a score * aout_Probe: probe the audio device and return a score
***************************************************************************** *****************************************************************************
* This function tries to open the dps and returns a score to the plugin * This function tries to initialize SDL audio and returns a score to the
* manager so that it can select the best plugin. * plugin manager so that it can select the best plugin.
*****************************************************************************/ *****************************************************************************/
static int aout_Probe( probedata_t *p_data ) static int aout_Probe( probedata_t *p_data )
{ {
SDL_AudioSpec *desired, *obtained; SDL_AudioSpec desired, obtained;
/* Start AudioSDL */ /* Start AudioSDL */
if( SDL_Init(SDL_INIT_AUDIO) != 0) if( SDL_Init(SDL_INIT_AUDIO) != 0 )
{ {
intf_DbgMsg( "aout_Probe: SDL init error: %s", SDL_GetError() ); intf_DbgMsg( "aout: SDL_Init failed (%s)", SDL_GetError() );
return( 0 ); return( 0 );
} }
/* asks for a minimum audio spec so that we are sure the dsp exists */ desired.freq = 11025; /* frequency */
desired = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) ); desired.format = AUDIO_U8; /* unsigned 8 bits */
obtained = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) ); desired.channels = 2; /* mono */
desired.callback = aout_SDLCallback; /* no callback function yet */
desired->freq = 11025; /* frequency */ desired.userdata = NULL; /* null parm for callback */
desired->format = AUDIO_U8; /* unsigned 8 bits */ desired.samples = 4096;
desired->channels = 2; /* mono */
desired->callback = SDL_aout_callback; /* no callback function yet */
desired->userdata = NULL; /* null parm for callback */
desired->samples = 4096;
/* If we were unable to open the device, there is no way we can use /* If we were unable to open the device, there is no way we can use
* the plugin. Return a score of 0. */ * the plugin. Return a score of 0. */
if(SDL_OpenAudio( desired, obtained ) < 0) if( SDL_OpenAudio( &desired, &obtained ) < 0 )
{ {
free( desired ); intf_DbgMsg( "aout: SDL_OpenAudio failed (%s)", SDL_GetError() );
free( obtained );
intf_DbgMsg( "aout_Probe: aout sdl error : %s", SDL_GetError() );
return( 0 ); return( 0 );
} }
free( desired );
free( obtained );
/* Otherwise, there are good chances we can use this plugin, return 100. */ /* Otherwise, there are good chances we can use this plugin, return 100. */
SDL_CloseAudio(); SDL_CloseAudio();
...@@ -149,29 +140,25 @@ static int aout_Probe( probedata_t *p_data ) ...@@ -149,29 +140,25 @@ static int aout_Probe( probedata_t *p_data )
} }
/***************************************************************************** /*****************************************************************************
* aout_Open: opens the audio device (the digital sound processor) * aout_Open: open the audio device
***************************************************************************** *****************************************************************************
* This function opens the dsp as a usual non-blocking write-only file, and * This function opens the dsp as a usual non-blocking write-only file, and
* modifies the p_aout->i_fd with the file's descriptor. * modifies the p_aout->i_fd with the file's descriptor.
*****************************************************************************/ *****************************************************************************/
static int aout_Open( aout_thread_t *p_aout ) static int aout_Open( aout_thread_t *p_aout )
{ {
SDL_AudioSpec *desired; SDL_AudioSpec desired;
int i_channels = p_aout->b_stereo?2:1; int i_channels = p_aout->b_stereo ? 2 : 1;
/* asks for a minimum audio spec so that we are sure the dsp exists */
desired = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) );
/* Allocate structure */ /* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) ); p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL ) if( p_aout->p_sys == NULL )
{ {
intf_ErrMsg("aout_Open error: %s", strerror(ENOMEM) ); intf_ErrMsg( "aout error: %s", strerror(ENOMEM) );
return( 1 ); return( 1 );
} }
p_aout->p_sys->i_audio_end = 0; p_aout->p_sys->i_audio_end = 0;
p_aout->p_sys->audio_buf = malloc( OVERFLOWLIMIT ); p_aout->p_sys->audio_buf = malloc( OVERFLOWLIMIT );
...@@ -183,40 +170,37 @@ static int aout_Open( aout_thread_t *p_aout ) ...@@ -183,40 +170,37 @@ static int aout_Open( aout_thread_t *p_aout )
p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR, p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR,
AOUT_RATE_DEFAULT ); AOUT_RATE_DEFAULT );
desired.freq = p_aout->l_rate;
desired->freq = p_aout->l_rate;
/* TODO: write conversion beetween AOUT_FORMAT_DEFAULT /* TODO: write conversion beetween AOUT_FORMAT_DEFAULT
* AND AUDIO* from SDL. */ * AND AUDIO* from SDL. */
desired->format = AUDIO_S16LSB; /* stereo 16 bits */ desired.format = AUDIO_S16LSB; /* stereo 16 bits */
desired->channels = i_channels; desired.channels = i_channels;
desired->callback = SDL_aout_callback; desired.callback = aout_SDLCallback;
desired->userdata = p_aout->p_sys; desired.userdata = p_aout->p_sys;
desired->samples = 2048; desired.samples = 1024;
/* Open the sound device /* Open the sound device
* we just ask the SDL to wrap at the good frequency if the one we * we just ask the SDL to wrap at the good frequency if the one we
* ask for is unavailable. This is done by setting the second parar * ask for is unavailable. This is done by setting the second parar
* to NULL * to NULL
*/ */
if( SDL_OpenAudio(desired,NULL) < 0 ) if( SDL_OpenAudio( &desired, NULL ) < 0 )
{ {
free( desired ); intf_ErrMsg( "aout error: SDL_OpenAudio failed (%s)", SDL_GetError() );
intf_ErrMsg( "aout_Open error: can't open audio device: %s",
SDL_GetError() );
return( -1 ); return( -1 );
} }
p_aout->p_sys->b_active = 1; p_aout->p_sys->b_active = 1;
free( desired ); SDL_PauseAudio( 0 );
SDL_PauseAudio(0);
return( 0 );
return( 0 );
} }
/***************************************************************************** /*****************************************************************************
* aout_SetFormat: resets the dsp and sets its format * aout_SetFormat: reset the audio device and sets its format
***************************************************************************** *****************************************************************************
* This functions resets the DSP device, tries to initialize the output * This functions resets the audio device, tries to initialize the output
* format with the value contained in the dsp structure, and if this value * format with the value contained in the dsp structure, and if this value
* could not be set, the default value returned by ioctl is set. It then * could not be set, the default value returned by ioctl is set. It then
* does the same for the stereo mode, and for the output rate. * does the same for the stereo mode, and for the output rate.
...@@ -224,32 +208,31 @@ static int aout_Open( aout_thread_t *p_aout ) ...@@ -224,32 +208,31 @@ static int aout_Open( aout_thread_t *p_aout )
static int aout_SetFormat( aout_thread_t *p_aout ) static int aout_SetFormat( aout_thread_t *p_aout )
{ {
/* TODO: finish and clean this */ /* TODO: finish and clean this */
SDL_AudioSpec *desired; SDL_AudioSpec desired;
int i_stereo = p_aout->b_stereo?2:1; int i_stereo = p_aout->b_stereo ? 2 : 1;
desired = (SDL_AudioSpec *)malloc( sizeof(SDL_AudioSpec) );
/*i_format = p_aout->i_format;*/
/* i_format = p_aout->i_format; desired.freq = p_aout->l_rate; /* Set the output rate */
*/ desired.format = AUDIO_S16LSB; /* stereo 16 bits */
desired->freq = p_aout->l_rate; /* Set the output rate */ desired.channels = i_stereo;
desired->format = AUDIO_S16LSB; /* stereo 16 bits */ desired.callback = aout_SDLCallback;
desired->channels = i_stereo; desired.userdata = p_aout->p_sys;
desired->callback = SDL_aout_callback; desired.samples = 2048;
desired->userdata = p_aout->p_sys;
desired->samples = 2048;
/* Open the sound device */ /* Open the sound device */
SDL_PauseAudio(1); SDL_PauseAudio( 1 );
SDL_CloseAudio(); SDL_CloseAudio();
if( SDL_OpenAudio(desired,NULL) < 0 )
if( SDL_OpenAudio( &desired, NULL ) < 0 )
{ {
free( desired );
p_aout->p_sys->b_active = 0; p_aout->p_sys->b_active = 0;
return( -1 ); return( -1 );
} }
p_aout->p_sys->b_active = 1; p_aout->p_sys->b_active = 1;
free( desired ); SDL_PauseAudio( 0 );
SDL_PauseAudio(0);
return(0); return( 0 );
} }
/***************************************************************************** /*****************************************************************************
...@@ -265,36 +248,11 @@ static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit ) ...@@ -265,36 +248,11 @@ static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
/* returning 0 here juste gives awful sound in the speakers :/ */ /* returning 0 here juste gives awful sound in the speakers :/ */
return( l_buffer_limit ); return( l_buffer_limit );
} }
return( p_aout->p_sys->i_audio_end-l_buffer_limit); return( p_aout->p_sys->i_audio_end - l_buffer_limit);
}
static void SDL_aout_callback(void *userdata, byte_t *stream, int len)
{
struct aout_sys_s * p_sys = userdata;
int end = p_sys->i_audio_end;
if(end > OVERFLOWLIMIT)
{
intf_ErrMsg("aout SDL_aout_callback: Overflow.");
free(p_sys->audio_buf);
p_sys->audio_buf = NULL;
p_sys->i_audio_end = 0;
end = 0;
// we've gone to slow, increase output freq
}
/* if we are not in underrun */
if(end>len)
{
memcpy(stream, p_sys->audio_buf, len);
memmove(p_sys->audio_buf, &(p_sys->audio_buf[len]), end-len);
p_sys->i_audio_end -= len;
}
} }
/***************************************************************************** /*****************************************************************************
* aout_Play: plays a sound samples buffer * aout_Play: play a sound samples buffer
***************************************************************************** *****************************************************************************
* This function writes a buffer of i_length bytes in the dsp * This function writes a buffer of i_length bytes in the dsp
*****************************************************************************/ *****************************************************************************/
...@@ -304,30 +262,60 @@ static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) ...@@ -304,30 +262,60 @@ static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
SDL_LockAudio(); /* Stop callbacking */ SDL_LockAudio(); /* Stop callbacking */
audio_buf = realloc(audio_buf, p_aout->p_sys->i_audio_end + i_size); p_aout->p_sys->audio_buf = realloc( audio_buf,
memcpy(&(audio_buf[p_aout->p_sys->i_audio_end]), buffer, i_size); p_aout->p_sys->i_audio_end + i_size);
memcpy( p_aout->p_sys->audio_buf + p_aout->p_sys->i_audio_end,
buffer, i_size);
p_aout->p_sys->i_audio_end += i_size; p_aout->p_sys->i_audio_end += i_size;
p_aout->p_sys->audio_buf = audio_buf;
SDL_UnlockAudio(); /* go on callbacking */ SDL_UnlockAudio(); /* go on callbacking */
} }
/***************************************************************************** /*****************************************************************************
* aout_Close: closes the dsp audio device * aout_Close: close the audio device
*****************************************************************************/ *****************************************************************************/
static void aout_Close( aout_thread_t *p_aout ) static void aout_Close( aout_thread_t *p_aout )
{ {
if( p_aout->p_sys->b_active ) if( p_aout->p_sys->b_active )
{ {
SDL_PauseAudio(1); /* pause audio */ SDL_PauseAudio( 1 ); /* pause audio */
if(p_aout->p_sys->audio_buf != NULL) /* do we have a buffer now ? */ if( p_aout->p_sys->audio_buf != NULL ) /* do we have a buffer now ? */
{ {
free(p_aout->p_sys->audio_buf); free( p_aout->p_sys->audio_buf );
} }
p_aout->p_sys->b_active = 0; /* just for sam */
} }
free(p_aout->p_sys); /* Close the Output. */
SDL_CloseAudio(); SDL_CloseAudio();
free( p_aout->p_sys ); /* Close the Output. */
}
/*****************************************************************************
* aout_SDLCallback: what to do once SDL has played sound samples
*****************************************************************************/
static void aout_SDLCallback( void *userdata, byte_t *stream, int len )
{
struct aout_sys_s * p_sys = userdata;
if( p_sys->i_audio_end > OVERFLOWLIMIT )
{
intf_ErrMsg( "aout error: aout_SDLCallback overflowed" );
free( p_sys->audio_buf );
p_sys->audio_buf = NULL;
p_sys->i_audio_end = 0;
/* we've gone to slow, increase output freq */
}
/* if we are not in underrun */
if( p_sys->i_audio_end > len )
{
p_sys->i_audio_end -= len;
memcpy( stream, p_sys->audio_buf, len );
memmove( p_sys->audio_buf, p_sys->audio_buf + len, p_sys->i_audio_end );
}
} }
...@@ -50,13 +50,74 @@ ...@@ -50,13 +50,74 @@
/***************************************************************************** /*****************************************************************************
* Building configuration tree * Building configuration tree
*****************************************************************************/ *****************************************************************************/
MODULE_CONFIG_START MODULE_CONFIG_START
ADD_WINDOW( "Configuration for sdl module" ) ADD_WINDOW( "Configuration for SDL module" )
ADD_COMMENT( "For now, the sdl module cannot be configured" ) ADD_COMMENT( "For now, the SDL module cannot be configured" )
MODULE_CONFIG_END MODULE_CONFIG_END
/*****************************************************************************
* Capabilities defined in the other files.
******************************************************************************/
extern void aout_getfunctions( function_list_t * p_function_list );
/*****************************************************************************
* InitModule: get the module structure and configuration.
*****************************************************************************
* We have to fill psz_name, psz_longname and psz_version. These variables
* will be strdup()ed later by the main application because the module can
* be unloaded later to save memory, and we want to be able to access this
* data even after the module has been unloaded.
*****************************************************************************/
int InitModule( module_t * p_module )
{
p_module->psz_name = MODULE_STRING;
p_module->psz_longname = "Simple DirectMedia Layer module";
p_module->psz_version = VERSION;
p_module->i_capabilities = MODULE_CAPABILITY_NULL
| MODULE_CAPABILITY_AOUT;
return( 0 );
}
/*****************************************************************************
* ActivateModule: set the module to an usable state.
*****************************************************************************
* This function fills the capability functions and the configuration
* structure. Once ActivateModule() has been called, the i_usage can
* be set to 0 and calls to NeedModule() be made to increment it. To unload
* the module, one has to wait until i_usage == 0 and call DeactivateModule().
*****************************************************************************/
int ActivateModule( module_t * p_module )
{
p_module->p_functions = malloc( sizeof( module_functions_t ) );
if( p_module->p_functions == NULL )
{
return( -1 );
}
aout_getfunctions( &p_module->p_functions->aout );
p_module->p_config = p_config;
return( 0 );
}
/*****************************************************************************
* DeactivateModule: make sure the module can be unloaded.
*****************************************************************************
* This function must only be called when i_usage == 0. If it successfully
* returns, i_usage can be set to -1 and the module unloaded. Be careful to
* lock usage_lock during the whole process.
*****************************************************************************/
int DeactivateModule( module_t * p_module )
{
free( p_module->p_functions );
return( 0 );
}
/* old plugin API */
/***************************************************************************** /*****************************************************************************
* Exported prototypes * Exported prototypes
...@@ -64,7 +125,6 @@ MODULE_CONFIG_END ...@@ -64,7 +125,6 @@ MODULE_CONFIG_END
static void vout_GetPlugin( p_vout_thread_t p_vout ); static void vout_GetPlugin( p_vout_thread_t p_vout );
static void intf_GetPlugin( p_intf_thread_t p_intf ); static void intf_GetPlugin( p_intf_thread_t p_intf );
/* Video output */ /* Video output */
int vout_SDLCreate ( vout_thread_t *p_vout, char *psz_display, int vout_SDLCreate ( vout_thread_t *p_vout, char *psz_display,
int i_root_window, void *p_data ); int i_root_window, void *p_data );
...@@ -81,11 +141,6 @@ void intf_SDLDestroy ( p_intf_thread_t p_intf ); ...@@ -81,11 +141,6 @@ void intf_SDLDestroy ( p_intf_thread_t p_intf );
void intf_SDLManage ( p_intf_thread_t p_intf ); void intf_SDLManage ( p_intf_thread_t p_intf );
/*****************************************************************************
* * Capabilities defined in the other files.
******************************************************************************/
extern void aout_getfunctions( function_list_t * p_function_list );
/***************************************************************************** /*****************************************************************************
* GetConfig: get the plugin structure and configuration * GetConfig: get the plugin structure and configuration
*****************************************************************************/ *****************************************************************************/
...@@ -140,64 +195,4 @@ static void intf_GetPlugin( p_intf_thread_t p_intf ) ...@@ -140,64 +195,4 @@ static void intf_GetPlugin( p_intf_thread_t p_intf )
p_intf->p_sys_manage = intf_SDLManage; p_intf->p_sys_manage = intf_SDLManage;
} }
/*****************************************************************************
* Audio stuff: All the new modules things
*****************************************************************************/
/*****************************************************************************
* InitModule: get the module structure and configuration.
*****************************************************************************
* We have to fill psz_name, psz_longname and psz_version. These variables
* will be strdup()ed later by the main application because the module can
* be unloaded later to save memory, and we want to be able to access this
* data even after the module has been unloaded.
*****************************************************************************/
int InitModule( module_t * p_module )
{
p_module->psz_name = MODULE_STRING;
p_module->psz_longname = "Linux SDL audio module";
p_module->psz_version = VERSION;
p_module->i_capabilities = MODULE_CAPABILITY_NULL
| MODULE_CAPABILITY_AOUT;
return( 0 );
}
/*****************************************************************************
* ActivateModule: set the module to an usable state.
*****************************************************************************
* This function fills the capability functions and the configuration
* structure. Once ActivateModule() has been called, the i_usage can
* be set to 0 and calls to NeedModule() be made to increment it. To unload
* the module, one has to wait until i_usage == 0 and call DeactivateModule().
*****************************************************************************/
int ActivateModule( module_t * p_module )
{
p_module->p_functions = malloc( sizeof( module_functions_t ) );
if( p_module->p_functions == NULL )
{
return( -1 );
}
aout_getfunctions( &p_module->p_functions->aout );
p_module->p_config = p_config;
return( 0 );
}
/*****************************************************************************
* DeactivateModule: make sure the module can be unloaded.
*****************************************************************************
* This function must only be called when i_usage == 0. If it successfully
* returns, i_usage can be set to -1 and the module unloaded. Be careful to
* lock usage_lock during the whole process.
*****************************************************************************/
int DeactivateModule( module_t * p_module )
{
free( p_module->p_functions );
return( 0 );
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment