stuff
This commit is contained in:
parent
4e159c8f54
commit
755f5bff9e
5
TODO
5
TODO
@ -1,3 +1,8 @@
|
|||||||
|
- read_vips() in im_open.c:179 needs moving to format and breaking into is_a,
|
||||||
|
header, load and save, as tiff etc.
|
||||||
|
|
||||||
|
make im_file2vips, im_vips2file?
|
||||||
|
|
||||||
- pluggable formats
|
- pluggable formats
|
||||||
|
|
||||||
for each format, store:
|
for each format, store:
|
||||||
|
@ -300,6 +300,12 @@ im_function *im_find_function( const char *name );
|
|||||||
im_package *im_find_package( const char *name );
|
im_package *im_find_package( const char *name );
|
||||||
im_package *im_package_of_function( const char *name );
|
im_package *im_package_of_function( const char *name );
|
||||||
|
|
||||||
|
/* Map over and find formats.
|
||||||
|
*/
|
||||||
|
void *im_map_formats( VSListMap2Fn fn, void *a, void *b );
|
||||||
|
im_format *im_format_for_file( const char *filename );
|
||||||
|
im_format *im_format_for_name( const char *filename );
|
||||||
|
|
||||||
/* Allocate space for, and free im_object argument lists.
|
/* Allocate space for, and free im_object argument lists.
|
||||||
*/
|
*/
|
||||||
int im_free_vargv( im_function *fn, im_object *vargv );
|
int im_free_vargv( im_function *fn, im_object *vargv );
|
||||||
|
@ -418,5 +418,124 @@ im_package im__format = {
|
|||||||
list
|
list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Suffix sets.
|
||||||
|
*/
|
||||||
|
static const char *tiff_suffs[] = { ".tif", ".tiff", NULL };
|
||||||
|
static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL };
|
||||||
|
static const char *png_suffs[] = { ".png", NULL };
|
||||||
|
static const char *csv_suffs[] = { ".csv", NULL };
|
||||||
|
static const char *ppm_suffs[] = { ".ppm", ".pgm", ".pbm", NULL };
|
||||||
|
static const char *exr_suffs[] = { ".exr", NULL };
|
||||||
|
static const char *analyze_suffs[] = { ".img", ".hdr", NULL };
|
||||||
|
static const char *magick_suffs[] = { NULL };
|
||||||
|
|
||||||
|
/* VIPS image formats.
|
||||||
|
*/
|
||||||
|
static im_format jpeg_desc = {
|
||||||
|
"jpeg", /* internal name */
|
||||||
|
N_( "JPEG" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
jpeg_suffs, /* Allowed suffixes */
|
||||||
|
im_isjpeg, /* is_a */
|
||||||
|
im_jpeg2vips_header, /* Load header only */
|
||||||
|
im_jpeg2vips, /* Load */
|
||||||
|
im_vips2jpeg /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format tiff_desc = {
|
||||||
|
"tiff", /* internal name */
|
||||||
|
N_( "TIFF" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
tiff_suffs, /* Allowed suffixes */
|
||||||
|
im_istiff, /* is_a */
|
||||||
|
im_tiff2vips_header, /* Load header only */
|
||||||
|
im_tiff2vips, /* Load */
|
||||||
|
im_vips2tiff /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format png_desc = {
|
||||||
|
"png", /* internal name */
|
||||||
|
N_( "PNG" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
png_suffs, /* Allowed suffixes */
|
||||||
|
im_ispng, /* is_a */
|
||||||
|
im_png2vips_header, /* Load header only */
|
||||||
|
im_png2vips, /* Load */
|
||||||
|
im_vips2png /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format csv_desc = {
|
||||||
|
"csv", /* internal name */
|
||||||
|
N_( "CSV" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
csv_suffs, /* Allowed suffixes */
|
||||||
|
NULL, /* is_a */
|
||||||
|
im_csv2vips_header, /* Load header only */
|
||||||
|
im_csv2vips, /* Load */
|
||||||
|
im_vips2csv /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format ppm_desc = {
|
||||||
|
"ppm", /* internal name */
|
||||||
|
N_( "PPM/PBM/PNM" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
ppm_suffs, /* Allowed suffixes */
|
||||||
|
im_isppm, /* is_a */
|
||||||
|
im_ppm2vips_header, /* Load header only */
|
||||||
|
im_ppm2vips, /* Load */
|
||||||
|
im_vips2ppm /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format analyze_desc = {
|
||||||
|
"analyze", /* internal name */
|
||||||
|
N_( "Analyze 6.0" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
analyze_suffs, /* Allowed suffixes */
|
||||||
|
im_isanalyze, /* is_a */
|
||||||
|
im_analyze2vips_header, /* Load header only */
|
||||||
|
im_analyze2vips, /* Load */
|
||||||
|
NULL /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format exr_desc = {
|
||||||
|
"exr", /* internal name */
|
||||||
|
N_( "OpenEXR" ), /* i18n'd visible name */
|
||||||
|
0, /* Priority */
|
||||||
|
exr_suffs, /* Allowed suffixes */
|
||||||
|
im_isexr, /* is_a */
|
||||||
|
im_exr2vips_header, /* Load header only */
|
||||||
|
im_exr2vips, /* Load */
|
||||||
|
NULL /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
static im_format magick_desc = {
|
||||||
|
"magick", /* internal name */
|
||||||
|
N_( "ImageMagick-supported format" ), /* i18n'd visible name */
|
||||||
|
-1000, /* Priority */
|
||||||
|
magick_suffs, /* Allowed suffixes */
|
||||||
|
im_ismagick, /* is_a */
|
||||||
|
im_magick2vips_header, /* Load header only */
|
||||||
|
im_magick2vips, /* Load */
|
||||||
|
NULL /* Save */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Package up all these formats.
|
||||||
|
*/
|
||||||
|
static im_format *format_list[] = {
|
||||||
|
&csv_desc,
|
||||||
|
&jpeg_desc,
|
||||||
|
&magick_desc,
|
||||||
|
&png_desc,
|
||||||
|
&exr_desc,
|
||||||
|
&ppm_desc,
|
||||||
|
&analyze_desc,
|
||||||
|
&tiff_desc
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Package of format.
|
||||||
|
*/
|
||||||
|
im_format_package im__format_format = {
|
||||||
|
"format",
|
||||||
|
IM_NUMBER( format_list ),
|
||||||
|
format_list
|
||||||
|
};
|
||||||
|
@ -225,6 +225,30 @@ read_vips( const char *filename )
|
|||||||
return( im2 );
|
return( im2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
else if( im_isvips( name ) ) {
|
||||||
|
if( mode[1] == 'w' ) {
|
||||||
|
if( !(im = im_init( filename )) )
|
||||||
|
return( NULL );
|
||||||
|
if( im_openinrw( im ) ) {
|
||||||
|
im_close( im );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
if( im->Bbits != IM_BBITS_BYTE &&
|
||||||
|
im_isMSBfirst( im ) !=
|
||||||
|
im_amiMSBfirst() ) {
|
||||||
|
im_close( im );
|
||||||
|
im_error( "im_open", _( "open for read-"
|
||||||
|
"write for native format "
|
||||||
|
"images only" ) );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
im = read_vips( filename );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/* Delayed save: if we write to TIFF or to JPEG format, actually do the write
|
/* Delayed save: if we write to TIFF or to JPEG format, actually do the write
|
||||||
* to a "p" and on preclose do im_vips2tiff() or whatever. Track save
|
* to a "p" and on preclose do im_vips2tiff() or whatever. Track save
|
||||||
* parameters here.
|
* parameters here.
|
||||||
@ -416,6 +440,7 @@ IMAGE *
|
|||||||
im_open( const char *filename, const char *mode )
|
im_open( const char *filename, const char *mode )
|
||||||
{
|
{
|
||||||
IMAGE *im;
|
IMAGE *im;
|
||||||
|
im_format *format;
|
||||||
|
|
||||||
/* Pass in a nonsense name for argv0 ... this init world is only here
|
/* Pass in a nonsense name for argv0 ... this init world is only here
|
||||||
* for old programs which are missing an im_init_world() call. We must
|
* for old programs which are missing an im_init_world() call. We must
|
||||||
@ -431,107 +456,11 @@ im_open( const char *filename, const char *mode )
|
|||||||
|
|
||||||
switch( mode[0] ) {
|
switch( mode[0] ) {
|
||||||
case 'r':
|
case 'r':
|
||||||
{
|
if( !(format = im_format_for_file( filename )) )
|
||||||
char name[FILENAME_MAX];
|
|
||||||
char options[FILENAME_MAX];
|
|
||||||
|
|
||||||
/* Break any options off the name ... eg. "fred.tif:jpeg,tile"
|
|
||||||
* etc.
|
|
||||||
*/
|
|
||||||
im_filename_split( filename, name, options );
|
|
||||||
|
|
||||||
/* Check for other formats.
|
|
||||||
|
|
||||||
FIXME ... should have a table to avoid all this
|
|
||||||
repetition
|
|
||||||
|
|
||||||
*/
|
|
||||||
if( !im_existsf( "%s", name ) ) {
|
|
||||||
im_error( "im_open",
|
|
||||||
_( "\"%s\" is not readable" ), name );
|
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
|
||||||
else if( im_istiff( name ) ) {
|
|
||||||
/* If TIFF open fails, try going through libmagick.
|
|
||||||
*/
|
|
||||||
if( !(im = open_sub(
|
if( !(im = open_sub(
|
||||||
im_tiff2vips_header, im_tiff2vips,
|
format->header, format->load, filename )) )
|
||||||
filename )) &&
|
|
||||||
!(im = open_sub(
|
|
||||||
im_magick2vips_header, im_magick2vips,
|
|
||||||
filename )) )
|
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
|
||||||
else if( im_isjpeg( name ) ) {
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_jpeg2vips_header, im_jpeg2vips, filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else if( im_isexr( name ) ) {
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_exr2vips_header, im_exr2vips, filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else if( im_isppm( name ) ) {
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_ppm2vips_header, im_ppm2vips, filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else if( im_ispng( name ) ) {
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_png2vips_header, im_png2vips, filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else if( im_filename_suffix_match( name, im_suffix_csv ) ) {
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_csv2vips_header, im_csv2vips, filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else if( im_isvips( name ) ) {
|
|
||||||
if( mode[1] == 'w' ) {
|
|
||||||
/* Has to be native format for >8 bits.
|
|
||||||
*/
|
|
||||||
if( !(im = im_init( filename )) )
|
|
||||||
return( NULL );
|
|
||||||
if( im_openinrw( im ) ) {
|
|
||||||
im_close( im );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
if( im->Bbits != IM_BBITS_BYTE &&
|
|
||||||
im_isMSBfirst( im ) !=
|
|
||||||
im_amiMSBfirst() ) {
|
|
||||||
im_close( im );
|
|
||||||
im_error( "im_open", _( "open for read-"
|
|
||||||
"write for native format "
|
|
||||||
"images only" ) );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
im = read_vips( filename );
|
|
||||||
}
|
|
||||||
else if( im_isanalyze( name ) ) {
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_analyze2vips_header, im_analyze2vips,
|
|
||||||
filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else if( im_ismagick( name ) ) {
|
|
||||||
/* Have this last as it can be very slow to detect
|
|
||||||
* failure.
|
|
||||||
*/
|
|
||||||
if( !(im = open_sub(
|
|
||||||
im_magick2vips_header, im_magick2vips,
|
|
||||||
filename )) )
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
im_error( "im_open", _( "\"%s\" is not "
|
|
||||||
"a supported format" ), filename );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
|
@ -72,6 +72,8 @@ extern im_package im__other;
|
|||||||
extern im_package im__relational;
|
extern im_package im__relational;
|
||||||
extern im_package im__video;
|
extern im_package im__video;
|
||||||
|
|
||||||
|
extern im_format_package im__format_format;
|
||||||
|
|
||||||
/* im_guess_prefix() args.
|
/* im_guess_prefix() args.
|
||||||
*/
|
*/
|
||||||
static im_arg_desc guess_prefix_args[] = {
|
static im_arg_desc guess_prefix_args[] = {
|
||||||
@ -419,12 +421,56 @@ static im_package *built_in[] = {
|
|||||||
&im__video
|
&im__video
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* List of loaded formats.
|
||||||
|
*/
|
||||||
|
static GSList *format_list = NULL;
|
||||||
|
|
||||||
|
static gint
|
||||||
|
format_compare( im_format *a, im_format *b )
|
||||||
|
{
|
||||||
|
return( a->priority - b->priority );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort the format list after a change.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
format_sort( void )
|
||||||
|
{
|
||||||
|
format_list = g_slist_sort( format_list,
|
||||||
|
(GCompareFunc) format_compare );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove a package of formats.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
format_remove( im_format_package *format )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < format->nfuncs; i++ )
|
||||||
|
format_list = g_slist_remove( format_list, format->table[i] );
|
||||||
|
format_sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a package of formats.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
format_add( im_format_package *format )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < format->nfuncs; i++ )
|
||||||
|
format_list = g_slist_prepend( format_list, format->table[i] );
|
||||||
|
format_sort();
|
||||||
|
}
|
||||||
|
|
||||||
/* How we represent a loaded plugin.
|
/* How we represent a loaded plugin.
|
||||||
*/
|
*/
|
||||||
typedef struct _Plugin {
|
typedef struct _Plugin {
|
||||||
GModule *module; /* As loaded by g_module_open() */
|
GModule *module; /* As loaded by g_module_open() */
|
||||||
char *name; /* Name we loaded */
|
char *name; /* Name we loaded */
|
||||||
im_package *pack; /* Package table */
|
im_package *pack; /* Package table */
|
||||||
|
im_format_package *format; /* Package format table */
|
||||||
} Plugin;
|
} Plugin;
|
||||||
|
|
||||||
/* List of loaded plugins.
|
/* List of loaded plugins.
|
||||||
@ -438,6 +484,8 @@ plugin_free( Plugin *plug )
|
|||||||
{
|
{
|
||||||
char *name = plug->name ? plug->name : "<unknown>";
|
char *name = plug->name ? plug->name : "<unknown>";
|
||||||
|
|
||||||
|
if( plug->format )
|
||||||
|
format_remove( plug->format );
|
||||||
if( plug->module ) {
|
if( plug->module ) {
|
||||||
if( !g_module_close( plug->module ) ) {
|
if( !g_module_close( plug->module ) ) {
|
||||||
im_error( "plugin",
|
im_error( "plugin",
|
||||||
@ -477,6 +525,7 @@ im_load_plugin( const char *name )
|
|||||||
plug->module = NULL;
|
plug->module = NULL;
|
||||||
plug->name = NULL;
|
plug->name = NULL;
|
||||||
plug->pack = NULL;
|
plug->pack = NULL;
|
||||||
|
plug->format = NULL;
|
||||||
plugin_list = g_slist_prepend( plugin_list, plug );
|
plugin_list = g_slist_prepend( plugin_list, plug );
|
||||||
|
|
||||||
/* Attach name.
|
/* Attach name.
|
||||||
@ -511,22 +560,44 @@ im_load_plugin( const char *name )
|
|||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The format table is optional.
|
||||||
|
*/
|
||||||
|
if( !g_module_symbol( plug->module,
|
||||||
|
"format_table", (gpointer *) ((void *) &plug->format) ) )
|
||||||
|
plug->format = NULL;
|
||||||
|
|
||||||
/* Sanity check.
|
/* Sanity check.
|
||||||
*/
|
*/
|
||||||
if( !plug->pack->name || plug->pack->nfuncs < 0 ||
|
if( !plug->pack->name || plug->pack->nfuncs < 0 ||
|
||||||
plug->pack->nfuncs > 10000 ) {
|
plug->pack->nfuncs > 10000 ) {
|
||||||
im_error( "plugin",
|
im_error( "plugin",
|
||||||
_( "corrupted package table in plugin \"%s\"" ),
|
_( "corrupted package table in plugin \"%s\"" ), name );
|
||||||
|
plugin_free( plug );
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
if( plug->format ) {
|
||||||
|
if( !plug->format->name || plug->format->nfuncs < 0 ||
|
||||||
|
plug->format->nfuncs > 10000 ) {
|
||||||
|
|
||||||
|
im_error( "plugin",
|
||||||
|
_( "corrupted format table in plugin \"%s\"" ),
|
||||||
name );
|
name );
|
||||||
plugin_free( plug );
|
plugin_free( plug );
|
||||||
|
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "added package \"%s\" ...\n", plug->pack->name );
|
printf( "added package \"%s\" ...\n", plug->pack->name );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
|
/* Add any formats to our format list and sort again.
|
||||||
|
*/
|
||||||
|
if( plug->format )
|
||||||
|
format_add( plug->format );
|
||||||
|
|
||||||
return( plug->pack );
|
return( plug->pack );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,6 +771,89 @@ im_package_of_function( const char *name )
|
|||||||
return( pack );
|
return( pack );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map a function over all formats.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
im_map_formats( VSListMap2Fn fn, void *a, void *b )
|
||||||
|
{
|
||||||
|
return( im_slist_map2( format_list, fn, a, b ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can this format open this file?
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
format_for_file_sub( im_format *format,
|
||||||
|
const char *filename, const char *name )
|
||||||
|
{
|
||||||
|
if( format->is_a ) {
|
||||||
|
if( format->is_a( name ) )
|
||||||
|
return( format );
|
||||||
|
}
|
||||||
|
else if( im_filename_suffix_match( name, format->suffs ) )
|
||||||
|
return( format );
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
im_format *
|
||||||
|
im_format_for_file( const char *filename )
|
||||||
|
{
|
||||||
|
char name[FILENAME_MAX];
|
||||||
|
char options[FILENAME_MAX];
|
||||||
|
im_format *format;
|
||||||
|
|
||||||
|
/* Break any options off the name ... eg. "fred.tif:jpeg,tile"
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
im_filename_split( filename, name, options );
|
||||||
|
|
||||||
|
if( !im_existsf( "%s", name ) ) {
|
||||||
|
im_error( "im_format_for_file",
|
||||||
|
_( "\"%s\" is not readable" ), name );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
format = (im_format *) im_map_formats(
|
||||||
|
(VSListMap2Fn) format_for_file_sub,
|
||||||
|
(void *) filename, (void *) name );
|
||||||
|
|
||||||
|
if( !format ) {
|
||||||
|
im_error( "im_format_for_file",
|
||||||
|
_( "\"%s\" is not in a supported format" ), name );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( format );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can we write this filename with this format?
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
format_for_name_sub( im_format *format,
|
||||||
|
const char *filename, const char *name )
|
||||||
|
{
|
||||||
|
if( im_filename_suffix_match( name, format->suffs ) )
|
||||||
|
return( format );
|
||||||
|
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
im_format *
|
||||||
|
im_format_for_name( const char *filename )
|
||||||
|
{
|
||||||
|
char name[FILENAME_MAX];
|
||||||
|
char options[FILENAME_MAX];
|
||||||
|
|
||||||
|
/* Break any options off the name ... eg. "fred.tif:jpeg,tile"
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
im_filename_split( filename, name, options );
|
||||||
|
|
||||||
|
return( (im_format *) im_map_formats(
|
||||||
|
(VSListMap2Fn) format_for_name_sub,
|
||||||
|
(void *) filename, (void *) name ) );
|
||||||
|
}
|
||||||
|
|
||||||
/* Free any store we allocated for the argument list.
|
/* Free any store we allocated for the argument list.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
Loading…
Reference in New Issue
Block a user