support optional output args in the cli

the cli interface now supports optional output args ... C API next
This commit is contained in:
John Cupitt 2011-09-04 10:10:39 +01:00
parent bbaef3dad1
commit 7fe104fee6
5 changed files with 65 additions and 72 deletions

View File

@ -4,6 +4,7 @@
- added VIPS_ARGUMENT_APPEND to help control arg ordering
- generate has a 'stop' param to signal successful early termination
- added optional output args, eg. x/y for min
- CLI supports optional output args
10/8/11 started 7.26.3
- don't use G_VALUE_COLLECT_INIT(), many platforms do not have a glib this

31
TODO
View File

@ -1,34 +1,3 @@
- see TODO comment on vips_call_options_set()
- cmd line interface needs to print optional output args, if requested
eg.
$ vips min fred.v
12
$ vips min -x fred.v
12
300
the switch is there, but breaks an assert:
$ vips min -x babe.jpg
VIPS:ERROR:object.c:1178:vips_object_set_argument_from_string: assertion
failed: (argument_class->flags & VIPS_ARGUMENT_INPUT)
Aborted
options are being made incorrectly:
$ vips min --help
-y, --y=gint Vertical position of minimum
--y should not have an arg
- C interface needs to look for optional output args in final psss, eg.
vips_min( im, &min,

View File

@ -134,6 +134,10 @@ typedef struct _VipsArgumentClass {
typedef struct _VipsArgumentInstance {
VipsArgument parent;
/* The class we are part of.
*/
VipsArgumentClass *argument_class;
/* The object we are attached to.
*/
VipsObject *object;
@ -154,9 +158,9 @@ typedef struct _VipsArgumentInstance {
typedef GHashTable VipsArgumentTable;
VipsArgumentInstance *vips__argument_get_instance( VipsArgumentClass *,
VipsObject *);
VipsObject * );
VipsArgument *vips__argument_table_lookup( VipsArgumentTable *,
GParamSpec *);
GParamSpec * );
void vips__object_set_member( VipsObject *object, GParamSpec *pspec,
GObject **member, GObject *argument );
typedef void *(*VipsArgumentMapFn)( VipsObject *, GParamSpec *,

View File

@ -366,6 +366,7 @@ vips_argument_init( VipsObject *object )
argument_instance = g_new( VipsArgumentInstance, 1 );
((VipsArgument *) argument_instance)->pspec = pspec;
argument_instance->argument_class = argument_class;
argument_instance->object = object;
argument_instance->assigned = FALSE;
argument_instance->close_id = 0;

View File

@ -504,7 +504,7 @@ vips_call_split( const char *operation_name, va_list optional, ... )
}
static void *
vips_call_find_pspec_char( VipsObject *object,
vips_call_find_pspec( VipsObject *object,
GParamSpec *pspec,
VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance,
@ -512,31 +512,42 @@ vips_call_find_pspec_char( VipsObject *object,
{
const char *name = (const char *) a;
/* One char names we assume are "-x" style abbreviations, longer names
* we match the whole string.
*/
if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
!argument_instance->assigned &&
g_param_spec_get_name( pspec )[0] == name[0] )
return( pspec );
!argument_instance->assigned )
if( (strlen( name ) == 1 &&
g_param_spec_get_name( pspec )[0] == name[0]) ||
strcmp( g_param_spec_get_name( pspec ), name ) == 0 )
return( argument_instance );
return( NULL );
}
static void *
vips_call_find_pspec_name( VipsObject *object,
GParamSpec *pspec,
VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance,
void *a, void *b )
/* Keep this stuff around for output args.
*/
typedef struct _VipsCallOptionOutput {
VipsArgumentInstance *argument_instance;
const char *value;
} VipsCallOptionOutput;
static void
vips_call_option_output( VipsObject *object,
VipsCallOptionOutput *output )
{
const char *name = (const char *) a;
VipsArgumentInstance *argument_instance = output->argument_instance;
GParamSpec *pspec = ((VipsArgument *) argument_instance)->pspec;
if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
!argument_instance->assigned &&
strcmp( g_param_spec_get_name( pspec ), name ) == 0 )
return( pspec );
if( vips_object_get_argument_to_string( object,
g_param_spec_get_name( pspec ), output->value ) ) {
/* FIXME .. Hmm what can we do here? If an arg is image
* output, for example, we will lose the error.
*/
}
return( NULL );
g_free( output );
}
static gboolean
@ -545,6 +556,8 @@ vips_call_options_set( const gchar *option_name, const gchar *value,
{
VipsOperation *operation = (VipsOperation *) data;
const char *name;
VipsArgumentInstance *argument_instance;
VipsArgumentClass *argument_class;
GParamSpec *pspec;
VIPS_DEBUG_MSG( "vips_call_options_set: %s = %s\n",
@ -555,34 +568,39 @@ vips_call_options_set( const gchar *option_name, const gchar *value,
for( name = option_name; *name == '-'; name++ )
;
/* If this is a single-character name, find the first unset pspec with
* that initial. Otherwise, search for a spec of that name.
*/
if( strlen( name ) == 1 )
pspec = (GParamSpec *) vips_argument_map(
if( !(argument_instance = (VipsArgumentInstance *)
vips_argument_map(
VIPS_OBJECT( operation ),
vips_call_find_pspec_char,
(void *) name, NULL );
else
pspec = (GParamSpec *) vips_argument_map(
VIPS_OBJECT( operation ),
vips_call_find_pspec_name,
(void *) name, NULL );
if( !pspec ) {
vips_call_find_pspec, (void *) name, NULL )) ) {
vips_error( VIPS_OBJECT( operation )->nickname,
_( "unknown argument '%s'" ), name );
return( FALSE );
}
argument_class = argument_instance->argument_class;
pspec = ((VipsArgument *) argument_instance)->pspec;
/*
*
* FIXME ... for output args, need to attach a close callback to
* operation to write the value
*
*/
if( vips_object_set_argument_from_string( VIPS_OBJECT( operation ),
name, value ) )
return( FALSE );
if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) {
if( vips_object_set_argument_from_string(
VIPS_OBJECT( operation ),
g_param_spec_get_name( pspec ), value ) )
return( FALSE );
}
else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) {
VipsCallOptionOutput *output;
/* We can't do output now, we have to attach a callback to do
* the processing after the operation has run.
*
* FIXME ... something like posteval or postbuild might be
* better for this?
*/
output = g_new( VipsCallOptionOutput, 1 );
output->argument_instance = argument_instance;
output->value = value;
g_signal_connect( operation, "preclose",
G_CALLBACK( vips_call_option_output ),
output );
}
return( TRUE );
}