03226f6f67
"vips list clases" now works, not tested actually supplying any args
1142 lines
24 KiB
C
1142 lines
24 KiB
C
/* VIPS universal main program.
|
|
*
|
|
* J. Cupitt, 8/4/93.
|
|
* 12/5/06
|
|
* - use GOption. g_*_prgname()
|
|
* 16/7/06
|
|
* - hmm, was broken for function name as argv1 case
|
|
* 11/7/06
|
|
* - add "all" option to -l
|
|
* 14/7/06
|
|
* - ignore "--" arguments.
|
|
* 2/9/06
|
|
* - do less init ... im_init_world() does more now
|
|
* 18/8/06
|
|
* - use IM_EXEEXT
|
|
* 16/10/06
|
|
* - add --version
|
|
* 17/10/06
|
|
* - add --swig
|
|
* - cleanups
|
|
* - remove --swig again, sigh
|
|
* - add throw() decls to C++ to help SWIG
|
|
* 14/1/07
|
|
* - add --list packages
|
|
* 26/2/07
|
|
* - add input *VEC arg types to C++ binding
|
|
* 17/8/08
|
|
* - add --list formats
|
|
* 29/11/08
|
|
* - add --list interpolators
|
|
* 9/2/09
|
|
* - and now we just have --list packages/classes/package-name
|
|
* 13/11/09
|
|
* - drop _f postfixes, drop many postfixes
|
|
* 24/6/10
|
|
* - less chatty error messages
|
|
* - oops, don't rename "copy_set" as "copy_"
|
|
*/
|
|
|
|
/*
|
|
|
|
This file is part of VIPS.
|
|
|
|
VIPS 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 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
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
|
|
|
*/
|
|
|
|
/*
|
|
#define DEBUG_FATAL
|
|
#define DEBUG_LEAK
|
|
#define DEBUG
|
|
*/
|
|
|
|
/* Need to disable these sometimes.
|
|
#undef DEBUG_FATAL
|
|
#undef DEBUG_LEAK
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif /*HAVE_CONFIG_H*/
|
|
#include <vips/intl.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <locale.h>
|
|
|
|
#include <vips/vips.h>
|
|
#include <vips/internal.h>
|
|
|
|
#ifdef OS_WIN32
|
|
#define strcasecmp(a,b) _stricmp(a,b)
|
|
#endif
|
|
|
|
static char *main_option_plugin = NULL;
|
|
static gboolean *main_option_version;
|
|
|
|
static GOptionEntry main_option[] = {
|
|
{ "plugin", 'p', 0, G_OPTION_ARG_FILENAME, &main_option_plugin,
|
|
N_( "load PLUGIN" ),
|
|
N_( "PLUGIN" ) },
|
|
{ "version", 'v', 0, G_OPTION_ARG_NONE, &main_option_version,
|
|
N_( "print version" ), NULL },
|
|
{ NULL }
|
|
};
|
|
|
|
typedef void *(*map_name_fn)( im_function * );
|
|
|
|
/* Loop over a package.
|
|
*/
|
|
static void *
|
|
map_package( im_package *pack, map_name_fn fn )
|
|
{
|
|
int i;
|
|
void *result;
|
|
|
|
for( i = 0; i < pack->nfuncs; i++ )
|
|
if( (result = fn( pack->table[i] )) )
|
|
return( result );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
/* Apply a function to a vips operation, or map over a package of operations.
|
|
*/
|
|
static void *
|
|
map_name( const char *name, map_name_fn fn )
|
|
{
|
|
im_package *pack;
|
|
im_function *func;
|
|
|
|
if( !name || strcmp( name, "all" ) == 0 )
|
|
/* Do all packages.
|
|
*/
|
|
im_map_packages( (VSListMap2Fn) map_package, fn );
|
|
else if( (pack = im_find_package( name )) )
|
|
/* Do one package.
|
|
*/
|
|
map_package( pack, fn );
|
|
else if( (func = im_find_function( name )) )
|
|
/* Do a single function.
|
|
*/
|
|
fn( func );
|
|
else {
|
|
im_error( "map_name",
|
|
_( "no package or function \"%s\"" ), name );
|
|
return( fn );
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
static void *
|
|
list_package( im_package *pack )
|
|
{
|
|
printf( "%-20s - %d operations\n", pack->name, pack->nfuncs );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
static void *
|
|
list_function( im_function *func )
|
|
{
|
|
printf( "%-20s - %s\n", func->name, _( func->desc ) );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
static void *
|
|
list_class( VipsObjectClass *class )
|
|
{
|
|
/* Ignore abstract classes.
|
|
*/
|
|
if( !G_TYPE_IS_ABSTRACT( G_OBJECT_CLASS_TYPE( class ) ) )
|
|
vips_object_print_class( class );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
static int
|
|
print_list( int argc, char **argv )
|
|
{
|
|
if( !argv[0] || strcmp( argv[0], "packages" ) == 0 )
|
|
im_map_packages( (VSListMap2Fn) list_package, NULL );
|
|
else if( strcmp( argv[0], "classes" ) == 0 )
|
|
vips_class_map_all( g_type_from_name( "VipsObject" ),
|
|
(VipsClassMap) list_class, NULL );
|
|
else {
|
|
if( map_name( argv[0], list_function ) )
|
|
error_exit( "unknown package \"%s\"", argv[0] );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* Is s1 a prefix of s2?
|
|
*/
|
|
static int
|
|
isprefix( const char *s1, const char *s2 )
|
|
{
|
|
while( *s1 && *s1 == *s2 ) {
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return( *s1 == '\0' );
|
|
}
|
|
|
|
/* Is s1 a postfix of s2?
|
|
*/
|
|
static int
|
|
ispostfix( const char *s1, const char *s2 )
|
|
{
|
|
int l1 = strlen( s1 );
|
|
int l2 = strlen( s2 );
|
|
|
|
if( l2 < l1 )
|
|
return( 0 );
|
|
|
|
return( strcasecmp( s1, s2 + l2 - l1 ) == 0 );
|
|
}
|
|
|
|
/* Print "ln -s" lines for this package.
|
|
*/
|
|
static void *
|
|
print_links_package( im_package *pack )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < pack->nfuncs; i++ )
|
|
printf( "rm -f %s" IM_EXEEXT "; "
|
|
"ln -s vips" IM_EXEEXT " %s" IM_EXEEXT "\n",
|
|
pack->table[i]->name, pack->table[i]->name );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
/* Print "ln -s" lines for this package.
|
|
*/
|
|
static int
|
|
print_links( int argc, char **argv )
|
|
{
|
|
im_map_packages( (VSListMap2Fn) print_links_package, NULL );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* Does a function have any printing output?
|
|
*/
|
|
static int
|
|
has_print( im_function *fn )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < fn->argc; i++ )
|
|
if( fn->argv[i].print )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* Print a usage string from an im_function descriptor.
|
|
*/
|
|
static void
|
|
usage( im_function *fn )
|
|
{
|
|
int i;
|
|
im_package *pack = im_package_of_function( fn->name );
|
|
|
|
/* Don't print the prgname if we're being run as a symlink.
|
|
*/
|
|
fprintf( stderr, "usage: " );
|
|
if( im_isprefix( "vips", g_get_prgname() ) )
|
|
fprintf( stderr, "%s ", g_get_prgname() );
|
|
fprintf( stderr, "%s ", fn->name );
|
|
|
|
/* Print args requiring command-line input.
|
|
*/
|
|
for( i = 0; i < fn->argc; i++ )
|
|
if( fn->argv[i].desc->flags & IM_TYPE_ARG )
|
|
fprintf( stderr, "%s ", fn->argv[i].name );
|
|
|
|
/* Print types of command line args.
|
|
*/
|
|
fprintf( stderr, "\nwhere:\n" );
|
|
for( i = 0; i < fn->argc; i++ )
|
|
if( fn->argv[i].desc->flags & IM_TYPE_ARG )
|
|
fprintf( stderr, "\t%s is of type \"%s\"\n",
|
|
fn->argv[i].name, fn->argv[i].desc->type );
|
|
|
|
/* Print output print args.
|
|
*/
|
|
if( has_print( fn ) ) {
|
|
fprintf( stderr, "prints:\n" );
|
|
for( i = 0; i < fn->argc; i++ )
|
|
if( fn->argv[i].print )
|
|
fprintf( stderr, "\t%s of type \"%s\"\n",
|
|
fn->argv[i].name,
|
|
fn->argv[i].desc->type );
|
|
}
|
|
|
|
/* Print description of this function, and package it comes from.
|
|
*/
|
|
fprintf( stderr, "%s", _( fn->desc ) );
|
|
if( pack )
|
|
fprintf( stderr, ", from package \"%s\"", pack->name );
|
|
fprintf( stderr, "\n" );
|
|
|
|
/* Print any flags this function has.
|
|
*/
|
|
fprintf( stderr, "flags: " );
|
|
if( fn->flags & IM_FN_PIO )
|
|
fprintf( stderr, "(PIO function) " );
|
|
else
|
|
fprintf( stderr, "(WIO function) " );
|
|
if( fn->flags & IM_FN_TRANSFORM )
|
|
fprintf( stderr, "(coordinate transformer) " );
|
|
else
|
|
fprintf( stderr, "(no coordinate transformation) " );
|
|
if( fn->flags & IM_FN_PTOP )
|
|
fprintf( stderr, "(point-to-point operation) " );
|
|
else
|
|
fprintf( stderr, "(area operation) " );
|
|
if( fn->flags & IM_FN_NOCACHE )
|
|
fprintf( stderr, "(nocache operation) " );
|
|
else
|
|
fprintf( stderr, "(result can be cached) " );
|
|
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
|
|
/* Convert VIPS type name to C++ type name. NULL for type unsupported by C++
|
|
* layer.
|
|
*/
|
|
static char *
|
|
vips2cpp( im_type_desc *ty )
|
|
{
|
|
int k;
|
|
|
|
/* VIPS types.
|
|
*/
|
|
static char *vtypes[] = {
|
|
IM_TYPE_DOUBLE,
|
|
IM_TYPE_INT,
|
|
IM_TYPE_COMPLEX,
|
|
IM_TYPE_STRING,
|
|
IM_TYPE_IMAGE,
|
|
IM_TYPE_IMASK,
|
|
IM_TYPE_DMASK,
|
|
IM_TYPE_DISPLAY,
|
|
IM_TYPE_IMAGEVEC,
|
|
IM_TYPE_DOUBLEVEC,
|
|
IM_TYPE_INTVEC
|
|
};
|
|
|
|
/* Corresponding C++ types.
|
|
*/
|
|
static char *ctypes[] = {
|
|
"double",
|
|
"int",
|
|
"std::complex<double>",
|
|
"char*",
|
|
"VImage",
|
|
"VIMask",
|
|
"VDMask",
|
|
"VDisplay",
|
|
"std::vector<VImage>",
|
|
"std::vector<double>",
|
|
"std::vector<int>"
|
|
};
|
|
|
|
for( k = 0; k < IM_NUMBER( vtypes ); k++ )
|
|
if( strcmp( ty->type, vtypes[k] ) == 0 )
|
|
return( ctypes[k] );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
/* Test a function definition for C++ suitability.
|
|
*/
|
|
static int
|
|
is_cppable( im_function *fn )
|
|
{
|
|
int j;
|
|
|
|
/* Check we know all the types.
|
|
*/
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
if( !vips2cpp( ty ) )
|
|
return( 0 );
|
|
}
|
|
|
|
/* We dont wrap output IMAGEVEC/DOUBLEVEC/INTVEC.
|
|
*/
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
if( ty->flags & IM_TYPE_OUTPUT )
|
|
if( strcmp( ty->type, IM_TYPE_IMAGEVEC ) == 0 ||
|
|
strcmp( ty->type, IM_TYPE_DOUBLEVEC ) == 0 ||
|
|
strcmp( ty->type, IM_TYPE_INTVEC ) == 0 )
|
|
return( 0 );
|
|
}
|
|
|
|
/* Must be at least one image argument (input or output) ... since we
|
|
* get inserted in the VImage class. Other funcs get wrapped by hand.
|
|
*/
|
|
for( j = 0; j < fn->argc; j++ )
|
|
if( strcmp( fn->argv[j].desc->type, IM_TYPE_IMAGE ) == 0 )
|
|
break;
|
|
if( j == fn->argc )
|
|
return( 0 );
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
/* Search for the first output arg, and the first IMAGE input arg.
|
|
*/
|
|
static void
|
|
find_ioargs( im_function *fn, int *ia, int *oa )
|
|
{
|
|
int j;
|
|
|
|
/* Look for first output arg - this will be the result of the
|
|
* function.
|
|
*/
|
|
*oa = -1;
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
if( ty->flags & IM_TYPE_OUTPUT ) {
|
|
*oa = j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Look for first input IMAGE arg. This will become the implicit
|
|
* "this" arg.
|
|
*/
|
|
*ia = -1;
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
if( !(ty->flags & IM_TYPE_OUTPUT) &&
|
|
strcmp( ty->type, IM_TYPE_IMAGE ) == 0 ) {
|
|
*ia = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
drop_postfix( char *str, const char *postfix )
|
|
{
|
|
if( ispostfix( postfix, str ) ) {
|
|
str[strlen( str ) - strlen( postfix )] = '\0';
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
/* Turn a VIPS name into a C++ name. Eg. im_lintra_vec becomes lin.
|
|
*/
|
|
static void
|
|
c2cpp_name( const char *in, char *out )
|
|
{
|
|
static const char *dont_drop[] = {
|
|
"_set",
|
|
};
|
|
static const char *drop[] = {
|
|
"_vec",
|
|
"const",
|
|
"tra",
|
|
"set",
|
|
"_f"
|
|
};
|
|
|
|
int i;
|
|
gboolean changed;
|
|
|
|
/* Copy, chopping off "im_" prefix.
|
|
*/
|
|
if( isprefix( "im_", in ) )
|
|
strcpy( out, in + 3 );
|
|
else
|
|
strcpy( out, in );
|
|
|
|
/* Repeatedly drop postfixes while we can. Stop if we see a dont_drop
|
|
* postfix.
|
|
*/
|
|
do {
|
|
gboolean found;
|
|
|
|
found = FALSE;
|
|
for( i = 0; i < IM_NUMBER( dont_drop ); i++ )
|
|
if( ispostfix( dont_drop[i], out ) ) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
if( found )
|
|
break;
|
|
|
|
changed = FALSE;
|
|
for( i = 0; i < IM_NUMBER( drop ); i++ )
|
|
changed |= drop_postfix( out, drop[i] );
|
|
} while( changed );
|
|
}
|
|
|
|
/* Print prototype for a function (ie. will be followed by code).
|
|
*
|
|
* Eg.:
|
|
* VImage VImage::lin( double a, double b ) throw( VError )
|
|
*/
|
|
static void *
|
|
print_cppproto( im_function *fn )
|
|
{
|
|
int j;
|
|
char name[4096];
|
|
int oa, ia;
|
|
int flg;
|
|
|
|
/* If it's not cppable, do nothing.
|
|
*/
|
|
if( !is_cppable( fn ) )
|
|
return( NULL );
|
|
|
|
/* Make C++ name.
|
|
*/
|
|
c2cpp_name( fn->name, name );
|
|
|
|
/* Find input and output args.
|
|
*/
|
|
find_ioargs( fn, &ia, &oa );
|
|
|
|
/* Print output type.
|
|
*/
|
|
if( oa == -1 )
|
|
printf( "void " );
|
|
else
|
|
printf( "%s ", vips2cpp( fn->argv[oa].desc ) );
|
|
|
|
printf( "VImage::%s(", name );
|
|
|
|
/* Print arg list.
|
|
*/
|
|
flg = 0;
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
/* Skip ia and oa.
|
|
*/
|
|
if( j == ia || j == oa )
|
|
continue;
|
|
|
|
/* Print arg type.
|
|
*/
|
|
if( flg )
|
|
printf( ", %s", vips2cpp( ty ) );
|
|
else {
|
|
printf( " %s", vips2cpp( ty ) );
|
|
flg = 1;
|
|
}
|
|
|
|
/* If it's an putput arg, print a "&" to make a reference
|
|
* argument.
|
|
*/
|
|
if( ty->flags & IM_TYPE_OUTPUT )
|
|
printf( "&" );
|
|
|
|
/* Print arg name.
|
|
*/
|
|
printf( " %s", fn->argv[j].name );
|
|
}
|
|
|
|
/* End of arg list!
|
|
*/
|
|
if( flg )
|
|
printf( " " );
|
|
printf( ") throw( VError )\n" );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
/* Print cpp decl for a function.
|
|
*
|
|
* Eg.
|
|
* VImage lin( double, double ) throw( VError );
|
|
*/
|
|
static void *
|
|
print_cppdecl( im_function *fn )
|
|
{
|
|
int j;
|
|
char name[4096];
|
|
int oa, ia;
|
|
int flg;
|
|
|
|
/* If it's not cppable, do nothing.
|
|
*/
|
|
if( !is_cppable( fn ) )
|
|
return( NULL );
|
|
|
|
/* Make C++ name.
|
|
*/
|
|
c2cpp_name( fn->name, name );
|
|
|
|
/* Find input and output args.
|
|
*/
|
|
find_ioargs( fn, &ia, &oa );
|
|
if( ia == -1 )
|
|
/* No input image, so make it a static in the class
|
|
* declaration.
|
|
*/
|
|
printf( "static " );
|
|
|
|
/* Print output type.
|
|
*/
|
|
if( oa == -1 )
|
|
printf( "void " );
|
|
else
|
|
printf( "%s ", vips2cpp( fn->argv[oa].desc ) );
|
|
|
|
/* Print function name and start arg list.
|
|
*/
|
|
printf( "%s(", name );
|
|
|
|
/* Print arg list.
|
|
*/
|
|
flg = 0;
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
/* Skip ia and oa.
|
|
*/
|
|
if( j == ia || j == oa )
|
|
continue;
|
|
|
|
/* Print arg type.
|
|
*/
|
|
if( flg )
|
|
printf( ", %s", vips2cpp( ty ) );
|
|
else {
|
|
printf( " %s", vips2cpp( ty ) );
|
|
flg = 1;
|
|
}
|
|
|
|
/* If it's an putput arg, print a "&" to make a reference
|
|
* argument.
|
|
*/
|
|
if( ty->flags & IM_TYPE_OUTPUT )
|
|
printf( "&" );
|
|
}
|
|
|
|
/* End of arg list!
|
|
*/
|
|
if( flg )
|
|
printf( " " );
|
|
|
|
printf( ") throw( VError );\n" );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
static void
|
|
print_invec( int j, const char *arg,
|
|
const char *vips_name, const char *c_name, const char *extract )
|
|
{
|
|
printf( "\t((%s*) _vec.data(%d))->n = %s.size();\n",
|
|
vips_name, j, arg );
|
|
printf( "\t((%s*) _vec.data(%d))->vec = new %s[%s.size()];\n",
|
|
vips_name, j, c_name, arg );
|
|
printf( "\tfor( unsigned int i = 0; i < %s.size(); i++ )\n",
|
|
arg );
|
|
printf( "\t\t((%s*) _vec.data(%d))->vec[i] = %s[i]%s;\n",
|
|
vips_name, j, arg, extract );
|
|
}
|
|
|
|
/* Print the definition for a function.
|
|
*/
|
|
static void *
|
|
print_cppdef( im_function *fn )
|
|
{
|
|
int j;
|
|
int ia, oa;
|
|
|
|
/* If it's not cppable, do nothing.
|
|
*/
|
|
if( !is_cppable( fn ) )
|
|
return( NULL );
|
|
|
|
find_ioargs( fn, &ia, &oa );
|
|
|
|
printf( "// %s: %s\n", fn->name, _( fn->desc ) );
|
|
print_cppproto( fn );
|
|
printf( "{\n" );
|
|
|
|
/* Declare the implicit input image.
|
|
*/
|
|
if( ia != -1 )
|
|
printf( "\tVImage %s = *this;\n", fn->argv[ia].name );
|
|
|
|
/* Declare return value, if any.
|
|
*/
|
|
if( oa != -1 )
|
|
printf( "\t%s %s;\n\n",
|
|
vips2cpp( fn->argv[oa].desc ),
|
|
fn->argv[oa].name );
|
|
|
|
/* Declare the arg vector.
|
|
*/
|
|
printf( "\tVargv _vec( \"%s\" );\n\n", fn->name );
|
|
|
|
/* Create the input args.
|
|
*/
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
/* Images are special - have to init the vector, even
|
|
* for output args. Have to translate VImage.
|
|
*/
|
|
if( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 ) {
|
|
printf( "\t_vec.data(%d) = %s.image();\n",
|
|
j, fn->argv[j].name );
|
|
continue;
|
|
}
|
|
|
|
/* For output masks, we have to set an input filename. Not
|
|
* freed, so constant string is OK.
|
|
*/
|
|
if( (ty->flags & IM_TYPE_OUTPUT) &&
|
|
(strcmp( ty->type, IM_TYPE_IMASK ) == 0 ||
|
|
strcmp( ty->type, IM_TYPE_DMASK ) == 0) ) {
|
|
printf( "\t((im_mask_object*) _vec.data(%d))->name = "
|
|
"(char*)\"noname\";\n", j );
|
|
continue;
|
|
}
|
|
|
|
/* Skip other output args.
|
|
*/
|
|
if( ty->flags & IM_TYPE_OUTPUT )
|
|
continue;
|
|
|
|
if( strcmp( ty->type, IM_TYPE_IMASK ) == 0 )
|
|
/* Mask types are different - have to use
|
|
* im_mask_object.
|
|
*/
|
|
printf( "\t((im_mask_object*) "
|
|
"_vec.data(%d))->mask = %s.mask().iptr;\n",
|
|
j, fn->argv[j].name );
|
|
else if( strcmp( ty->type, IM_TYPE_DMASK ) == 0 )
|
|
printf( "\t((im_mask_object*) "
|
|
"_vec.data(%d))->mask = %s.mask().dptr;\n",
|
|
j, fn->argv[j].name );
|
|
else if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 )
|
|
/* Display have to use VDisplay.
|
|
*/
|
|
printf( "\t_vec.data(%d) = %s.disp();\n",
|
|
j, fn->argv[j].name );
|
|
else if( strcmp( ty->type, IM_TYPE_STRING ) == 0 )
|
|
/* Zap input strings directly into _vec.
|
|
*/
|
|
printf( "\t_vec.data(%d) = (im_object) %s;\n",
|
|
j, fn->argv[j].name );
|
|
else if( strcmp( ty->type, IM_TYPE_IMAGEVEC ) == 0 )
|
|
print_invec( j, fn->argv[j].name,
|
|
"im_imagevec_object", "IMAGE *", ".image()" );
|
|
else if( strcmp( ty->type, IM_TYPE_DOUBLEVEC ) == 0 )
|
|
print_invec( j, fn->argv[j].name,
|
|
"im_doublevec_object", "double", "" );
|
|
else if( strcmp( ty->type, IM_TYPE_INTVEC ) == 0 )
|
|
print_invec( j, fn->argv[j].name,
|
|
"im_intvec_object", "int", "" );
|
|
else
|
|
/* Just use vips2cpp().
|
|
*/
|
|
printf( "\t*((%s*) _vec.data(%d)) = %s;\n",
|
|
vips2cpp( ty ), j, fn->argv[j].name );
|
|
}
|
|
|
|
/* Call function.
|
|
*/
|
|
printf( "\t_vec.call();\n" );
|
|
|
|
/* Extract output args.
|
|
*/
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty = fn->argv[j].desc;
|
|
|
|
/* Skip input args.
|
|
*/
|
|
if( !(ty->flags & IM_TYPE_OUTPUT) )
|
|
continue;
|
|
|
|
/* Skip images (done on input side, really).
|
|
*/
|
|
if( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 )
|
|
continue;
|
|
|
|
if( strcmp( ty->type, IM_TYPE_IMASK ) == 0 ||
|
|
strcmp( ty->type, IM_TYPE_DMASK ) == 0 )
|
|
/* Mask types are different - have to use
|
|
* im_mask_object.
|
|
*/
|
|
printf( "\t%s.embed( (DOUBLEMASK *)((im_mask_object*)"
|
|
"_vec.data(%d))->mask );\n",
|
|
fn->argv[j].name, j );
|
|
else if( strcmp( ty->type, IM_TYPE_STRING ) == 0 )
|
|
/* Strings are grabbed out of the vec.
|
|
*/
|
|
printf( "\t%s = (char*) _vec.data(%d);\n",
|
|
fn->argv[j].name, j );
|
|
else
|
|
/* Just use vips2cpp().
|
|
*/
|
|
printf( "\t%s = *((%s*)_vec.data(%d));\n",
|
|
fn->argv[j].name, vips2cpp( ty ), j );
|
|
}
|
|
|
|
/* Note dependancies if out is an image and this function uses
|
|
* PIO.
|
|
*/
|
|
if( oa != -1 ) {
|
|
im_type_desc *ty = fn->argv[oa].desc;
|
|
|
|
if( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 &&
|
|
(fn->flags & IM_FN_PIO) ) {
|
|
/* Loop for all input args again ..
|
|
*/
|
|
for( j = 0; j < fn->argc; j++ ) {
|
|
im_type_desc *ty2 = fn->argv[j].desc;
|
|
|
|
/* Skip output args.
|
|
*/
|
|
if( ty2->flags & IM_TYPE_OUTPUT )
|
|
continue;
|
|
|
|
/* Input image.
|
|
*/
|
|
if( strcmp( ty2->type, IM_TYPE_IMAGE ) == 0 )
|
|
printf( "\t%s._ref->addref( "
|
|
"%s._ref );\n",
|
|
fn->argv[oa].name,
|
|
fn->argv[j].name );
|
|
else if( strcmp( ty2->type, IM_TYPE_IMAGEVEC )
|
|
== 0 ) {
|
|
/* The out depends on every image in
|
|
* the input vector.
|
|
*/
|
|
printf( "\tfor( unsigned int i = 0; "
|
|
"i < %s.size(); i++ )\n",
|
|
fn->argv[j].name );
|
|
printf( "\t\t%s._ref->addref( "
|
|
"%s[i]._ref );\n",
|
|
fn->argv[oa].name,
|
|
fn->argv[j].name );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return result.
|
|
*/
|
|
if( oa != -1 )
|
|
printf( "\n\treturn( %s );\n", fn->argv[oa].name );
|
|
|
|
printf( "}\n\n" );
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
/* Print C++ decls for function, package or all.
|
|
*/
|
|
static int
|
|
print_cppdecls( int argc, char **argv )
|
|
{
|
|
printf( "// this file automatically generated from\n"
|
|
"// VIPS library %s\n", im_version_string() );
|
|
|
|
if( map_name( argv[0], print_cppdecl ) )
|
|
error_exit( NULL );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* Print C++ bindings for function, package or all.
|
|
*/
|
|
static int
|
|
print_cppdefs( int argc, char **argv )
|
|
{
|
|
printf( "// this file automatically generated from\n"
|
|
"// VIPS library %s\n", im_version_string() );
|
|
|
|
if( map_name( argv[0], print_cppdef ) )
|
|
error_exit( NULL );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* All our built-in actions.
|
|
*/
|
|
|
|
typedef int (*Action)( int argc, char **argv );
|
|
|
|
typedef struct _ActionEntry {
|
|
char *name;
|
|
char *description;
|
|
GOptionEntry *group;
|
|
Action action;
|
|
} ActionEntry;
|
|
|
|
static GOptionEntry empty_options[] = {
|
|
{ NULL }
|
|
};
|
|
|
|
static ActionEntry actions[] = {
|
|
{ "list", N_( "list classes|packages|all|package-name|operation-name" ),
|
|
&empty_options[0], print_list },
|
|
{ "cpph", N_( "generate headers for C++ binding" ),
|
|
&empty_options[0], print_cppdecls },
|
|
{ "cppc", N_( "generate bodies for C++ binding" ),
|
|
&empty_options[0], print_cppdefs },
|
|
{ "links", N_( "generate links for vips/bin" ),
|
|
&empty_options[0], print_links },
|
|
};
|
|
|
|
static void
|
|
parse_options( GOptionContext *context, int *argc, char **argv )
|
|
{
|
|
GError *error = NULL;
|
|
int i, j;
|
|
|
|
#ifdef DEBUG
|
|
printf( "parse_options:\n" );
|
|
for( i = 0; i < *argc; i++ )
|
|
printf( "%d) %s\n", i, argv[i] );
|
|
#endif /*DEBUG*/
|
|
|
|
if( !g_option_context_parse( context, argc, &argv, &error ) ) {
|
|
if( error ) {
|
|
fprintf( stderr, "%s\n", error->message );
|
|
g_error_free( error );
|
|
}
|
|
|
|
error_exit( "%s", g_get_prgname() );
|
|
}
|
|
|
|
/* We support --plugin and --version for all cases.
|
|
*/
|
|
if( main_option_plugin ) {
|
|
if( !im_load_plugin( main_option_plugin ) )
|
|
error_exit( NULL );
|
|
}
|
|
|
|
if( main_option_version )
|
|
printf( "vips-%s\n", im_version_string() );
|
|
|
|
/* Remove any "--" argument. If one of our arguments is a negative
|
|
* number, the user will need to have added the "--" flag to stop
|
|
* GOption parsing. But "--" is still passed down to us and we need to
|
|
* ignore it.
|
|
*/
|
|
for( i = 1; i < *argc - 1; i++ )
|
|
if( strcmp( argv[i], "--" ) == 0 ) {
|
|
for( j = i; j < *argc; j++ )
|
|
argv[j] = argv[j + 1];
|
|
|
|
*argc -= 1;
|
|
}
|
|
}
|
|
|
|
static GOptionGroup *
|
|
add_main_group( GOptionContext *context, VipsOperation *user_data )
|
|
{
|
|
GOptionGroup *main_group;
|
|
|
|
main_group = g_option_group_new( NULL, NULL, NULL, user_data, NULL );
|
|
g_option_group_add_entries( main_group, main_option );
|
|
g_option_group_set_translation_domain( main_group, GETTEXT_PACKAGE );
|
|
g_option_context_set_main_group( context, main_group );
|
|
g_option_context_add_group( context, im_get_option_group() );
|
|
|
|
return( main_group );
|
|
}
|
|
|
|
/* VIPS universal main program.
|
|
*/
|
|
int
|
|
main( int argc, char **argv )
|
|
{
|
|
char *action;
|
|
GOptionContext *context;
|
|
GOptionGroup *main_group;
|
|
VipsOperation *operation;
|
|
im_function *fn;
|
|
int i, j;
|
|
gboolean handled;
|
|
|
|
if( im_init_world( argv[0] ) )
|
|
error_exit( NULL );
|
|
textdomain( GETTEXT_PACKAGE );
|
|
setlocale( LC_ALL, "" );
|
|
|
|
#ifdef DEBUG_FATAL
|
|
/* Set masks for debugging ... stop on any problem.
|
|
*/
|
|
g_log_set_always_fatal(
|
|
G_LOG_FLAG_RECURSION |
|
|
G_LOG_FLAG_FATAL |
|
|
G_LOG_LEVEL_ERROR |
|
|
G_LOG_LEVEL_CRITICAL |
|
|
G_LOG_LEVEL_WARNING );
|
|
|
|
fprintf( stderr, "*** DEBUG_FATAL: will abort() on first warning\n" );
|
|
#endif /*!DEBUG_FATAL*/
|
|
|
|
#ifdef DEBUG_LEAK
|
|
fprintf( stderr, "*** DEBUG_LEAK: will leak test on exit\n" );
|
|
#endif /*!DEBUG_LEAK*/
|
|
|
|
/* Try to find our action.
|
|
*/
|
|
action = NULL;
|
|
|
|
/* Should we try to run the thing we are named as?
|
|
*/
|
|
if( !im_isprefix( "vips", g_get_prgname() ) )
|
|
action = argv[0];
|
|
|
|
if( !action ) {
|
|
/* Look for the first non-option argument, if any, and make
|
|
* that our action.
|
|
*/
|
|
for( i = 1; i < argc; i++ )
|
|
if( argv[i][0] != '-' ) {
|
|
action = argv[i];
|
|
|
|
/* Remove the action from argv.
|
|
*/
|
|
for( j = i; j < argc; j++ )
|
|
argv[j] = argv[j + 1];
|
|
argc -= 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
context = g_option_context_new( _( "[ACTION] [OPTIONS] [PARAMETERS] - "
|
|
"VIPS driver program" ) );
|
|
handled = FALSE;
|
|
|
|
/* Could be one of our built-in actions.
|
|
*/
|
|
if( action )
|
|
for( i = 0; i < VIPS_NUMBER( actions ); i++ )
|
|
if( strcmp( action, actions[i].name ) == 0 ) {
|
|
main_group = add_main_group( context, NULL );
|
|
g_option_group_add_entries( main_group,
|
|
actions[i].group );
|
|
parse_options( context, &argc, argv );
|
|
|
|
if( actions[i].action( argc - 1, argv + 1 ) )
|
|
error_exit( "%s", action );
|
|
|
|
handled = TRUE;
|
|
break;
|
|
}
|
|
|
|
/* Could be a vips7 im_function.
|
|
*/
|
|
if( action && !handled &&
|
|
(fn = im_find_function( action )) ) {
|
|
(void) add_main_group( context, NULL );
|
|
parse_options( context, &argc, argv );
|
|
|
|
if( im_run_command( action, argc - 1, argv + 1 ) ) {
|
|
if( argc == 1 )
|
|
usage( fn );
|
|
else
|
|
error_exit( NULL );
|
|
}
|
|
|
|
handled = TRUE;
|
|
}
|
|
im_error_clear();
|
|
|
|
/* Could be a vips8 VipsOperation.
|
|
*/
|
|
if( action && !handled &&
|
|
(operation = vips_operation_new( action )) ) {
|
|
main_group = add_main_group( context, operation );
|
|
vips_call_options( main_group, operation );
|
|
parse_options( context, &argc, argv );
|
|
|
|
if( vips_call_argv( operation, argc - 1, argv + 1 ) ) {
|
|
if( argc == 1 ) {
|
|
char *help;
|
|
|
|
help = g_option_context_get_help( context,
|
|
FALSE, NULL );
|
|
printf( "%s", help );
|
|
vips_object_print( VIPS_OBJECT( operation ) );
|
|
error_exit( NULL );
|
|
}
|
|
|
|
error_exit( NULL );
|
|
}
|
|
|
|
g_object_unref( operation );
|
|
|
|
handled = TRUE;
|
|
}
|
|
im_error_clear();
|
|
|
|
if( action && !handled ) {
|
|
printf( "%s", _( "possible actions:\n" ) );
|
|
for( i = 0; i < VIPS_NUMBER( actions ); i++ )
|
|
printf( "%10s - %s\n",
|
|
actions[i].name, actions[i].description );
|
|
|
|
error_exit( "unknown action \"%s\"", action );
|
|
}
|
|
|
|
if( !handled ) {
|
|
(void) add_main_group( context, NULL );
|
|
parse_options( context, &argc, argv );
|
|
}
|
|
|
|
g_option_context_free( context );
|
|
|
|
im_close_plugins();
|
|
|
|
#ifdef DEBUG_LEAK
|
|
printf( "** leak test on exit:\n" );
|
|
im__print_all();
|
|
printf( "** leak test done\n" );
|
|
#endif /*DEBUG_LEAK*/
|
|
|
|
return( 0 );
|
|
}
|