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 - added VIPS_ARGUMENT_APPEND to help control arg ordering
- generate has a 'stop' param to signal successful early termination - generate has a 'stop' param to signal successful early termination
- added optional output args, eg. x/y for min - added optional output args, eg. x/y for min
- CLI supports optional output args
10/8/11 started 7.26.3 10/8/11 started 7.26.3
- don't use G_VALUE_COLLECT_INIT(), many platforms do not have a glib this - 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. - C interface needs to look for optional output args in final psss, eg.
vips_min( im, &min, vips_min( im, &min,

View File

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

View File

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

View File

@ -504,7 +504,7 @@ vips_call_split( const char *operation_name, va_list optional, ... )
} }
static void * static void *
vips_call_find_pspec_char( VipsObject *object, vips_call_find_pspec( VipsObject *object,
GParamSpec *pspec, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
@ -512,31 +512,42 @@ vips_call_find_pspec_char( VipsObject *object,
{ {
const char *name = (const char *) a; 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) && if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
!argument_instance->assigned && !argument_instance->assigned )
g_param_spec_get_name( pspec )[0] == name[0] ) if( (strlen( name ) == 1 &&
return( pspec ); g_param_spec_get_name( pspec )[0] == name[0]) ||
strcmp( g_param_spec_get_name( pspec ), name ) == 0 )
return( argument_instance );
return( NULL ); return( NULL );
} }
static void * /* Keep this stuff around for output args.
vips_call_find_pspec_name( VipsObject *object, */
GParamSpec *pspec, typedef struct _VipsCallOptionOutput {
VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance;
VipsArgumentInstance *argument_instance, const char *value;
void *a, void *b ) } 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) && if( vips_object_get_argument_to_string( object,
(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && g_param_spec_get_name( pspec ), output->value ) ) {
!argument_instance->assigned && /* FIXME .. Hmm what can we do here? If an arg is image
strcmp( g_param_spec_get_name( pspec ), name ) == 0 ) * output, for example, we will lose the error.
return( pspec ); */
}
return( NULL ); g_free( output );
} }
static gboolean static gboolean
@ -545,6 +556,8 @@ vips_call_options_set( const gchar *option_name, const gchar *value,
{ {
VipsOperation *operation = (VipsOperation *) data; VipsOperation *operation = (VipsOperation *) data;
const char *name; const char *name;
VipsArgumentInstance *argument_instance;
VipsArgumentClass *argument_class;
GParamSpec *pspec; GParamSpec *pspec;
VIPS_DEBUG_MSG( "vips_call_options_set: %s = %s\n", 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++ ) for( name = option_name; *name == '-'; name++ )
; ;
/* If this is a single-character name, find the first unset pspec with if( !(argument_instance = (VipsArgumentInstance *)
* that initial. Otherwise, search for a spec of that name. vips_argument_map(
*/
if( strlen( name ) == 1 )
pspec = (GParamSpec *) vips_argument_map(
VIPS_OBJECT( operation ), VIPS_OBJECT( operation ),
vips_call_find_pspec_char, vips_call_find_pspec, (void *) name, NULL )) ) {
(void *) name, NULL );
else
pspec = (GParamSpec *) vips_argument_map(
VIPS_OBJECT( operation ),
vips_call_find_pspec_name,
(void *) name, NULL );
if( !pspec ) {
vips_error( VIPS_OBJECT( operation )->nickname, vips_error( VIPS_OBJECT( operation )->nickname,
_( "unknown argument '%s'" ), name ); _( "unknown argument '%s'" ), name );
return( FALSE ); return( FALSE );
} }
argument_class = argument_instance->argument_class;
pspec = ((VipsArgument *) argument_instance)->pspec;
/* if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) {
* if( vips_object_set_argument_from_string(
* FIXME ... for output args, need to attach a close callback to VIPS_OBJECT( operation ),
* operation to write the value g_param_spec_get_name( pspec ), value ) )
* return( FALSE );
*/ }
if( vips_object_set_argument_from_string( VIPS_OBJECT( operation ), else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) {
name, value ) ) VipsCallOptionOutput *output;
return( FALSE );
/* 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 ); return( TRUE );
} }