1 /* base class for all vips operations
2 *
3 * 30/12/14
4 * - display default/min/max for pspec in usage
5 */
6
7 /*
8
9 Copyright (C) 1991-2005 The National Gallery
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301 USA
25
26 */
27
28 /*
29
30 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
31
32 */
33
34 /*
35 #define VIPS_DEBUG
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif /*HAVE_CONFIG_H*/
41 #include <vips/intl.h>
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <math.h>
47
48 #include <vips/vips.h>
49 #include <vips/internal.h>
50 #include <vips/debug.h>
51
52 #include <gobject/gvaluecollector.h>
53
54 /**
55 * SECTION: operation
56 * @short_description: the VIPS operation base object class
57 * @stability: Stable
58 * @see_also: <link linkend="VipsObject">object</link>
59 * @include: vips/vips.h
60 *
61 * The #VipsOperation class and associated types and macros.
62 *
63 * #VipsOperation is the base class for all operations in libvips. It builds
64 * on #VipsObject to provide the introspection and command-line interface to
65 * libvips.
66 *
67 * It also maintains a cache of recent operations. See below.
68 *
69 * vips_call(), vips_call_split() and vips_call_split_option_string() are used
70 * by vips to implement the C API. They can execute any #VipsOperation,
71 * passing in a set of required and optional arguments. Normally you would not
72 * use these functions directly: every operation has a tiny wrapper function
73 * which provides type-safety for the required arguments. For example,
74 * vips_embed() is defined as:
75 *
76 * |[
77 * int
78 * vips_embed( VipsImage *in, VipsImage **out,
79 * int x, int y, int width, int height, ... )
80 * {
81 * va_list ap;
82 * int result;
83 *
84 * va_start( ap, height );
85 * result = vips_call_split( "embed", ap, in, out, x, y, width, height );
86 * va_end( ap );
87 *
88 * return( result );
89 * }
90 * ]|
91 *
92 * Use vips_call_argv() to run any vips operation from a command-line style
93 * argc/argv array. This is the thing used by the vips main program to
94 * implement the vips command-line interface.
95 *
96 * ## #VipsOperation and reference counting
97 *
98 * After calling a #VipsOperation you are responsible for unreffing any output
99 * objects. For example, consider:
100 *
101 * |[
102 * VipsImage *im = ...;
103 * VipsImage *t1;
104 *
105 * if (vips_invert (im, &t1, NULL))
106 * error ..
107 * ]|
108 *
109 * This will invert @im and return a new #VipsImage, @t1. As the caller
110 * of vips_invert(), you are responsible for @t1 and must unref it when you no
111 * longer need it. If vips_invert() fails, no @t1 is returned and you don't
112 * need to do anything.
113 *
114 * If you don't need to use @im for another operation,
115 * you can unref @im immediately after the call. If @im is needed to calculate
116 * @t1, vips_invert() will add a ref to @im and automatically drop it when @t1
117 * is unreffed.
118 *
119 * Consider running two operations, one after the other. You could write:
120 *
121 * |[
122 * VipsImage *im = ...;
123 * VipsImage *t1, *t2;
124 *
125 * if (vips_invert (im, &t1, NULL)) {
126 * g_object_unref (im);
127 * return -1;
128 * }
129 * g_object_unref (im);
130 *
131 * if (vips_flip (t1, &t2, VIPS_DIRECTION_HORIZONTAL, NULL)) {
132 * g_object_unref (t1);
133 * return -1;
134 * }
135 * g_object_unref (t1);
136 * ]|
137 *
138 * This is correct, but rather long-winded. libvips provides a handy thing to
139 * make a vector of auto-freeing object references. You can write this as:
140 *
141 * |[
142 * VipsObject *parent = ...;
143 * VipsImage *im = ...;
144 * VipsImage *t = (VipsImage **) vips_object_local_array (parent, 2);
145 *
146 * if (vips_invert (im, &t[0], NULL) ||
147 * vips_flip (t[0], &t[1], VIPS_DIRECTION_HORIZONTAL, NULL))
148 * return -1;
149 * ]|
150 *
151 * where @parent is some enclosing object which will be unreffed when this
152 * task is complete. vips_object_local_array() makes an array of #VipsObject
153 * (or #VipsImage, in this case) where when @parent is freed, all non-NULL
154 * #VipsObject in the array are also unreffed.
155 *
156 * ## The #VipsOperation cache
157 *
158 * Because all #VipsObject are immutable, they can be cached. The cache is
159 * very simple to use: instead of calling vips_object_build(), call
160 * vips_cache_operation_build(). This function calculates a hash from the
161 * operations's input arguments and looks it up in table of all recent
162 * operations. If there's a hit, the new operation is unreffed, the old
163 * operation reffed, and the old operation returned in place of the new one.
164 *
165 * The cache size is controlled with vips_cache_set_max() and friends.
166 */
167
168 /**
169 * VipsOperationFlags:
170 * @VIPS_OPERATION_NONE: no flags
171 * @VIPS_OPERATION_SEQUENTIAL: can work sequentially with a small buffer
172 * @VIPS_OPERATION_NOCACHE: must not be cached
173 * @VIPS_OPERATION_DEPRECATED: a compatibility thing
174 *
175 * Flags we associate with an operation.
176 *
177 * @VIPS_OPERATION_SEQUENTIAL means that the operation works like vips_conv():
178 * it can process images top-to-bottom with only small non-local
179 * references.
180 *
181 * Every scan-line must be requested, you are not allowed to skip
182 * ahead, but as a special case, the very first request can be for a region
183 * not at the top of the image. In this case, the first part of the image will
184 * be read and discarded
185 *
186 * Every scan-line must be requested, you are not allowed to skip
187 * ahead, but as a special case, the very first request can be for a region
188 * not at the top of the image. In this case, the first part of the image will
189 * be read and discarded
190 *
191 * @VIPS_OPERATION_NOCACHE means that the operation must not be cached by
192 * vips.
193 *
194 * @VIPS_OPERATION_DEPRECATED means this is an old operation kept in vips for
195 * compatibility only and should be hidden from users.
196 */
197
198 /* Abstract base class for operations.
199 */
200
201 /* Our signals.
202 */
203 enum {
204 SIG_INVALIDATE,
205 SIG_LAST
206 };
207
208 static guint vips_operation_signals[SIG_LAST] = { 0 };
209
210 G_DEFINE_ABSTRACT_TYPE( VipsOperation, vips_operation, VIPS_TYPE_OBJECT );
211
212 static void
vips_operation_finalize(GObject * gobject)213 vips_operation_finalize( GObject *gobject )
214 {
215 VipsOperation *operation = VIPS_OPERATION( gobject );
216
217 VIPS_DEBUG_MSG( "vips_operation_finalize: %p\n", gobject );
218
219 if( operation->pixels )
220 g_info( _( "%d pixels calculated" ), operation->pixels );
221
222 G_OBJECT_CLASS( vips_operation_parent_class )->finalize( gobject );
223 }
224
225 static void
vips_operation_dispose(GObject * gobject)226 vips_operation_dispose( GObject *gobject )
227 {
228 VIPS_DEBUG_MSG( "vips_operation_dispose: %p\n", gobject );
229
230 G_OBJECT_CLASS( vips_operation_parent_class )->dispose( gobject );
231 }
232
233 /* Three basic types of command-line argument.
234 *
235 * INPUTS: things like an input image, there is a filename argument on the
236 * command-line which is used to construct the operation argument.
237 *
238 * NOARG_OUTPUT: things like the result of VipsMax, there's no correspondiong
239 * command-line argument, we just print the value.
240 *
241 * OPTIONS: optional arguments.
242 *
243 * NONE: hide this thing.
244 */
245
246 typedef enum {
247 USAGE_INPUTS,
248 USAGE_NOARG_OUTPUT,
249 USAGE_OPTIONS,
250 USAGE_NONE
251 } UsageType;
252
253 typedef struct {
254 char *message; /* header message on first print */
255 UsageType type; /* Type of arg to select */
256 gboolean oftype; /* Show as "of type" */
257 int n; /* Arg number */
258 } VipsOperationClassUsage;
259
260 /* Put an arg into one the categories above.
261 */
262 static UsageType
vips_operation_class_usage_classify(VipsArgumentClass * argument_class)263 vips_operation_class_usage_classify( VipsArgumentClass *argument_class )
264 {
265 if( !(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) ||
266 (argument_class->flags & VIPS_ARGUMENT_DEPRECATED) )
267 return( USAGE_NONE );
268
269 if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) )
270 return( USAGE_OPTIONS );
271
272 if( vips_argument_class_needsstring( argument_class ) )
273 return( USAGE_INPUTS );
274
275 if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
276 !vips_argument_class_needsstring( argument_class ) )
277 return( USAGE_NOARG_OUTPUT );
278
279 return( USAGE_NONE );
280 }
281
282 static void
vips_operation_pspec_usage(VipsBuf * buf,GParamSpec * pspec)283 vips_operation_pspec_usage( VipsBuf *buf, GParamSpec *pspec )
284 {
285 GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
286
287 /* These are the pspecs that vips uses that have interesting values.
288 */
289 if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
290 GTypeClass *class = g_type_class_ref( type );
291 GParamSpecEnum *pspec_enum = (GParamSpecEnum *) pspec;
292
293 GEnumClass *genum;
294 int i;
295
296 /* Should be impossible, no need to warn.
297 */
298 if( !class )
299 return;
300
301 genum = G_ENUM_CLASS( class );
302
303 vips_buf_appendf( buf, "\t\t\t" );
304 vips_buf_appendf( buf, "%s", _( "default" ) );
305 vips_buf_appendf( buf, ": %s\n",
306 vips_enum_nick( type, pspec_enum->default_value ) );
307 vips_buf_appendf( buf, "\t\t\t" );
308 vips_buf_appendf( buf, "%s", _( "allowed" ) );
309 vips_buf_appendf( buf, ": " );
310
311 /* -1 since we always have a "last" member.
312 */
313 for( i = 0; i < genum->n_values - 1; i++ ) {
314 if( i > 0 )
315 vips_buf_appends( buf, ", " );
316 vips_buf_appends( buf, genum->values[i].value_nick );
317 }
318
319 vips_buf_appendf( buf, "\n" );
320 }
321 else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
322 GParamSpecBoolean *pspec_boolean = (GParamSpecBoolean *) pspec;
323
324 vips_buf_appendf( buf, "\t\t\t" );
325 vips_buf_appendf( buf, "%s", _( "default" ) );
326 vips_buf_appendf( buf, ": %s\n",
327 pspec_boolean->default_value ? "true" : "false" );
328 }
329 else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
330 GParamSpecDouble *pspec_double = (GParamSpecDouble *) pspec;
331
332 vips_buf_appendf( buf, "\t\t\t" );
333 vips_buf_appendf( buf, "%s", _( "default" ) );
334 vips_buf_appendf( buf, ": %g\n", pspec_double->default_value );
335 vips_buf_appendf( buf, "\t\t\t" );
336 vips_buf_appendf( buf, "%s", _( "min" ) );
337 vips_buf_appendf( buf, ": %g, ", pspec_double->minimum );
338 vips_buf_appendf( buf, "%s", _( "max" ) );
339 vips_buf_appendf( buf, ": %g\n", pspec_double->maximum );
340 }
341 else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
342 GParamSpecInt *pspec_int = (GParamSpecInt *) pspec;
343
344 vips_buf_appendf( buf, "\t\t\t" );
345 vips_buf_appendf( buf, "%s", _( "default" ) );
346 vips_buf_appendf( buf, ": %d\n", pspec_int->default_value );
347 vips_buf_appendf( buf, "\t\t\t" );
348 vips_buf_appendf( buf, "%s", _( "min" ) );
349 vips_buf_appendf( buf, ": %d, ", pspec_int->minimum );
350 vips_buf_appendf( buf, "%s", _( "max" ) );
351 vips_buf_appendf( buf, ": %d\n", pspec_int->maximum );
352 }
353
354 }
355
356 static void *
vips_operation_class_usage_arg(VipsObjectClass * object_class,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsBuf * buf,VipsOperationClassUsage * usage)357 vips_operation_class_usage_arg( VipsObjectClass *object_class,
358 GParamSpec *pspec, VipsArgumentClass *argument_class,
359 VipsBuf *buf, VipsOperationClassUsage *usage )
360 {
361 if( usage->type ==
362 vips_operation_class_usage_classify( argument_class ) ) {
363 if( usage->message &&
364 usage->n == 0 )
365 vips_buf_appendf( buf, "%s\n", usage->message );
366
367 if( usage->oftype ) {
368 vips_buf_appendf( buf, " %-12s - %s, %s %s\n",
369 g_param_spec_get_name( pspec ),
370 g_param_spec_get_blurb( pspec ),
371 (argument_class->flags & VIPS_ARGUMENT_INPUT) ?
372 _( "input" ) : _( "output" ),
373 g_type_name(
374 G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
375 vips_operation_pspec_usage( buf, pspec );
376 }
377 else {
378 if( usage->n > 0 )
379 vips_buf_appends( buf, " " );
380 vips_buf_appends( buf,
381 g_param_spec_get_name( pspec ) );
382 }
383
384 usage->n += 1;
385 }
386
387 return( NULL );
388 }
389
390 static void
vips_operation_usage(VipsOperationClass * class,VipsBuf * buf)391 vips_operation_usage( VipsOperationClass *class, VipsBuf *buf )
392 {
393 VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
394
395 VipsOperationClassUsage usage;
396
397 vips_buf_appendf( buf, "%s\n", object_class->description );
398 vips_buf_appendf( buf, "usage:\n" );
399
400 /* First pass through args: show the required names.
401 */
402 vips_buf_appendf( buf, " %s ", object_class->nickname );
403 usage.message = NULL;
404 usage.type = USAGE_INPUTS;
405 usage.oftype = FALSE;
406 usage.n = 0;
407 vips_argument_class_map( object_class,
408 (VipsArgumentClassMapFn) vips_operation_class_usage_arg,
409 buf, &usage );
410 vips_buf_appends( buf, " [--option-name option-value ...]\n" );
411
412 /* Show required types.
413 */
414 usage.message = "where:";
415 usage.type = USAGE_INPUTS;
416 usage.oftype = TRUE;
417 usage.n = 0;
418 vips_argument_class_map( object_class,
419 (VipsArgumentClassMapFn) vips_operation_class_usage_arg,
420 buf, &usage );
421
422 /* Show outputs with no input arg (eg. output maximum value for
423 * vips_max()).
424 */
425 usage.message = "outputs:";
426 usage.type = USAGE_NOARG_OUTPUT;
427 usage.oftype = TRUE;
428 usage.n = 0;
429 vips_argument_class_map( object_class,
430 (VipsArgumentClassMapFn) vips_operation_class_usage_arg,
431 buf, &usage );
432
433 /* Show optional args.
434 */
435 usage.message = "optional arguments:";
436 usage.type = USAGE_OPTIONS;
437 usage.oftype = TRUE;
438 usage.n = 0;
439 vips_argument_class_map( object_class,
440 (VipsArgumentClassMapFn) vips_operation_class_usage_arg,
441 buf, &usage );
442
443 /* Show flags.
444 */
445 if( class->flags ) {
446 GFlagsValue *value;
447 VipsOperationFlags flags;
448 GFlagsClass *flags_class =
449 g_type_class_ref( VIPS_TYPE_OPERATION_FLAGS );
450
451 vips_buf_appendf( buf, "operation flags: " );
452 flags = class->flags;
453 while( flags && (value =
454 g_flags_get_first_value( flags_class, flags )) ) {
455 vips_buf_appendf( buf, "%s ", value->value_nick );
456 flags &= ~value->value;
457 }
458 vips_buf_appends( buf, "\n" );
459 }
460 }
461
462 static void *
vips_operation_call_argument(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)463 vips_operation_call_argument( VipsObject *object, GParamSpec *pspec,
464 VipsArgumentClass *argument_class,
465 VipsArgumentInstance *argument_instance,
466 void *a, void *b )
467 {
468 VipsArgument *argument = (VipsArgument *) argument_class;
469
470 printf( " %s: offset = %d ",
471 g_param_spec_get_name( argument->pspec ),
472 argument_class->offset );
473 if( argument_class->flags & VIPS_ARGUMENT_REQUIRED )
474 printf ("required " );
475 if( argument_class->flags & VIPS_ARGUMENT_CONSTRUCT )
476 printf ("construct " );
477 if( argument_class->flags & VIPS_ARGUMENT_SET_ONCE )
478 printf ("set-once " );
479 if( argument_instance->assigned )
480 printf ("assigned " );
481 printf( "\n" );
482
483 return( NULL );
484 }
485
486 static void
vips_operation_dump(VipsObject * object,VipsBuf * buf)487 vips_operation_dump( VipsObject *object, VipsBuf *buf )
488 {
489 VipsOperation *operation = VIPS_OPERATION( object );
490 VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
491
492 if( operation->found_hash )
493 printf( "hash = %x\n", operation->hash );
494 printf( "%s args:\n", object_class->nickname );
495 vips_argument_map( VIPS_OBJECT( operation ),
496 vips_operation_call_argument, NULL, NULL );
497
498 VIPS_OBJECT_CLASS( vips_operation_parent_class )->dump( object, buf );
499 }
500
501 static void *
vips_operation_vips_operation_print_summary_arg(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)502 vips_operation_vips_operation_print_summary_arg( VipsObject *object,
503 GParamSpec *pspec,
504 VipsArgumentClass *argument_class,
505 VipsArgumentInstance *argument_instance,
506 void *a, void *b )
507 {
508 VipsBuf *buf = (VipsBuf *) a;
509
510 /* Just assigned input and output construct args. _summary() is used
511 * for things like cache tracing, so it's useful to show output args.
512 */
513 if( ((argument_class->flags & VIPS_ARGUMENT_INPUT) ||
514 (argument_class->flags & VIPS_ARGUMENT_OUTPUT)) &&
515 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
516 argument_instance->assigned ) {
517 const char *name = g_param_spec_get_name( pspec );
518 GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
519
520 GValue gvalue = { 0, };
521 char *str;
522
523 g_value_init( &gvalue, type );
524 g_object_get_property( G_OBJECT( object ), name, &gvalue );
525 str = g_strdup_value_contents( &gvalue );
526 vips_buf_appendf( buf, " %s=%s", name, str );
527 g_free( str );
528 g_value_unset( &gvalue );
529 }
530
531 return( NULL );
532 }
533
534 static void
vips_operation_summary(VipsObject * object,VipsBuf * buf)535 vips_operation_summary( VipsObject *object, VipsBuf *buf )
536 {
537 VipsOperation *operation = VIPS_OPERATION( object );
538 VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS( object );
539
540 vips_buf_appendf( buf, "%s", object_class->nickname );
541 vips_argument_map( VIPS_OBJECT( operation ),
542 vips_operation_vips_operation_print_summary_arg, buf, NULL );
543
544 vips_buf_appends( buf, " -" );
545
546 VIPS_OBJECT_CLASS( vips_operation_parent_class )->
547 summary( object, buf );
548 }
549
550 static VipsOperationFlags
vips_operation_real_get_flags(VipsOperation * operation)551 vips_operation_real_get_flags( VipsOperation *operation )
552 {
553 VipsOperationClass *class = VIPS_OPERATION_GET_CLASS( operation );
554
555 return( class->flags );
556 }
557
558 static void
vips_operation_class_init(VipsOperationClass * class)559 vips_operation_class_init( VipsOperationClass *class )
560 {
561 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
562 VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
563
564 gobject_class->finalize = vips_operation_finalize;
565 gobject_class->dispose = vips_operation_dispose;
566
567 vobject_class->nickname = "operation";
568 vobject_class->description = _( "operations" );
569 vobject_class->summary = vips_operation_summary;
570 vobject_class->dump = vips_operation_dump;
571
572 class->usage = vips_operation_usage;
573 class->get_flags = vips_operation_real_get_flags;
574
575 vips_operation_signals[SIG_INVALIDATE] = g_signal_new( "invalidate",
576 G_TYPE_FROM_CLASS( class ),
577 G_SIGNAL_RUN_LAST,
578 G_STRUCT_OFFSET( VipsOperationClass, invalidate ),
579 NULL, NULL,
580 g_cclosure_marshal_VOID__VOID,
581 G_TYPE_NONE, 0 );
582 }
583
584 static void
vips_operation_init(VipsOperation * operation)585 vips_operation_init( VipsOperation *operation )
586 {
587 }
588
589 /**
590 * vips_operation_get_flags:
591 * @operation: operation to fetch flags from
592 *
593 * Returns the set of flags for this operation.
594 *
595 * Returns: 0 on success, or -1 on error.
596 */
597 VipsOperationFlags
vips_operation_get_flags(VipsOperation * operation)598 vips_operation_get_flags( VipsOperation *operation )
599 {
600 VipsOperationClass *class = VIPS_OPERATION_GET_CLASS( operation );
601
602 return( class->get_flags( operation ) );
603 }
604
605 /**
606 * vips_operation_class_print_usage: (skip)
607 * @operation_class: class to print usage for
608 *
609 * Print a usage message for the operation to stdout.
610 */
611 void
vips_operation_class_print_usage(VipsOperationClass * operation_class)612 vips_operation_class_print_usage( VipsOperationClass *operation_class )
613 {
614 char str[4096];
615 VipsBuf buf = VIPS_BUF_STATIC( str );
616
617 operation_class->usage( operation_class, &buf );
618 printf( "%s", vips_buf_all( &buf ) );
619 }
620
621 void
vips_operation_invalidate(VipsOperation * operation)622 vips_operation_invalidate( VipsOperation *operation )
623 {
624 #ifdef VIPS_DEBUG
625 printf( "vips_operation_invalidate: %p\n", operation );
626 vips_object_print_summary( VIPS_OBJECT( operation ) );
627 #endif /*VIPS_DEBUG*/
628
629 g_signal_emit( operation, vips_operation_signals[SIG_INVALIDATE], 0 );
630 }
631
632 /**
633 * vips_operation_new: (constructor)
634 * @name: nickname of operation to create
635 *
636 * Return a new #VipsOperation with the specified nickname. Useful for
637 * language bindings.
638 *
639 * You'll need to set
640 * any arguments and build the operation before you can use it. See
641 * vips_call() for a higher-level way to make new operations.
642 *
643 * Returns: (transfer full): the new operation.
644 */
645 VipsOperation *
vips_operation_new(const char * name)646 vips_operation_new( const char *name )
647 {
648 GType type;
649 VipsObject *object;
650 VipsOperation *operation;
651
652 vips_check_init();
653
654 if( !(type = vips_type_find( "VipsOperation", name )) ) {
655 vips_error( "VipsOperation",
656 _( "class \"%s\" not found" ), name );
657 return( NULL );
658 }
659
660 if( !(object = g_object_new( type, NULL )) ) {
661 vips_error( "VipsOperation",
662 _( "\"%s\" is not an instantiable class" ), name );
663 return( NULL );
664 }
665
666 operation = VIPS_OPERATION( object );
667
668 VIPS_DEBUG_MSG( "vips_operation_new: %s (%p)\n", name, operation );
669
670 return( operation );
671 }
672
673 /* Some systems do not have va_copy() ... this might work (it does on MSVC,
674 * apparently).
675 *
676 * FIXME ... this should be in configure.in
677 */
678 #ifndef va_copy
679 #define va_copy(d,s) ((d) = (s))
680 #endif
681
682 static int
vips_operation_set_valist_required(VipsOperation * operation,va_list ap)683 vips_operation_set_valist_required( VipsOperation *operation, va_list ap )
684 {
685 VIPS_DEBUG_MSG( "vips_operation_set_valist_required:\n" );
686
687 /* Set required input arguments. Can't use vips_argument_map here
688 * :-( because passing va_list by reference is not portable.
689 */
690 VIPS_ARGUMENT_FOR_ALL( operation,
691 pspec, argument_class, argument_instance ) {
692
693 g_assert( argument_instance );
694
695 /* We skip deprecated required args. There will be a new,
696 * renamed arg in the same place.
697 */
698 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
699 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) ) {
700 VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class, ap );
701
702 #ifdef VIPS_DEBUG
703 {
704 char *str;
705
706 str = g_strdup_value_contents( &value );
707 VIPS_DEBUG_MSG( "\t%s = %s\n",
708 g_param_spec_get_name( pspec ), str );
709 g_free( str );
710 }
711 #endif /*VIPS_DEBUG */
712
713 g_object_set_property( G_OBJECT( operation ),
714 g_param_spec_get_name( pspec ), &value );
715
716 VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class, ap );
717
718 #ifdef VIPS_DEBUG
719 printf( "\tskipping arg %p for %s\n",
720 arg, g_param_spec_get_name( pspec ) );
721 #endif /*VIPS_DEBUG */
722
723 VIPS_ARGUMENT_COLLECT_END
724 }
725 } VIPS_ARGUMENT_FOR_ALL_END
726
727 return( 0 );
728 }
729
730 static int
vips_operation_get_valist_required(VipsOperation * operation,va_list ap)731 vips_operation_get_valist_required( VipsOperation *operation, va_list ap )
732 {
733 VIPS_DEBUG_MSG( "vips_operation_get_valist_required:\n" );
734
735 /* Extract output arguments. Can't use vips_argument_map here
736 * :-( because passing va_list by reference is not portable.
737 */
738 VIPS_ARGUMENT_FOR_ALL( operation,
739 pspec, argument_class, argument_instance ) {
740 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) ) {
741 VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class, ap );
742
743 VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class, ap );
744
745 if( !argument_instance->assigned )
746 continue;
747
748 #ifdef VIPS_DEBUG
749 printf( "\twriting %s to %p\n",
750 g_param_spec_get_name( pspec ), arg );
751 #endif /*VIPS_DEBUG */
752
753 /* It'd be nice to be able to test for arg being a
754 * valid gobject pointer, since passing in a valid
755 * pointer (and having us destroy it) is a common
756 * error and a cause of hard-to-find leaks.
757 *
758 * Unfortunately, G_IS_OBJECT() can't be given an
759 * arbitrary pointer for testing -- you're very likely
760 * to get coredumps.
761 */
762
763 g_object_get( G_OBJECT( operation ),
764 g_param_spec_get_name( pspec ), arg, NULL );
765
766 /* If the pspec is an object, that will up the ref
767 * count. We want to hand over the ref, so we have to
768 * knock it down again.
769 */
770 if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
771 GObject *object;
772
773 object = *((GObject **) arg);
774 g_object_unref( object );
775 }
776
777 VIPS_ARGUMENT_COLLECT_END
778 }
779 } VIPS_ARGUMENT_FOR_ALL_END
780
781 return( 0 );
782 }
783
784 static int
vips_operation_get_valist_optional(VipsOperation * operation,va_list ap)785 vips_operation_get_valist_optional( VipsOperation *operation, va_list ap )
786 {
787 char *name;
788
789 VIPS_DEBUG_MSG( "vips_operation_get_valist_optional:\n" );
790
791 for( name = va_arg( ap, char * ); name; name = va_arg( ap, char * ) ) {
792 GParamSpec *pspec;
793 VipsArgumentClass *argument_class;
794 VipsArgumentInstance *argument_instance;
795
796 VIPS_DEBUG_MSG( "\tname = '%s' (%p)\n", name, name );
797
798 if( vips_object_get_argument( VIPS_OBJECT( operation ), name,
799 &pspec, &argument_class, &argument_instance ) )
800 return( -1 );
801
802 VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class, ap );
803
804 /* We must collect input args as we walk the name/value list,
805 * but we don't do anything with them.
806 */
807
808 VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class, ap );
809
810 /* Here's an output arg.
811 */
812
813 #ifdef VIPS_DEBUG
814 printf( "\twriting %s to %p\n",
815 g_param_spec_get_name( pspec ), arg );
816 #endif /*VIPS_DEBUG */
817
818 /* If the dest pointer is NULL, skip the read.
819 */
820 if( arg ) {
821 g_object_get( G_OBJECT( operation ),
822 g_param_spec_get_name( pspec ), arg,
823 NULL );
824
825 /* If the pspec is an object, that will up
826 * the ref count. We want to hand over the
827 * ref, so we have to knock it down again.
828 */
829 if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
830 GObject *object;
831
832 object = *((GObject **) arg);
833 g_object_unref( object );
834 }
835 }
836
837 VIPS_ARGUMENT_COLLECT_END
838 }
839
840 return( 0 );
841 }
842
843 /**
844 * vips_call_required_optional:
845 * @operation: the operation to execute
846 * @required: %va_list of required arguments
847 * @optional: NULL-terminated %va_list of name / value pairs
848 *
849 * This is the main entry point for the C and C++ varargs APIs. @operation
850 * is executed, supplying @required and @optional arguments.
851 *
852 * Beware, this can change @operation to point at an old, cached one.
853 *
854 * Returns: 0 on success, -1 on error
855 */
856 int
vips_call_required_optional(VipsOperation ** operation,va_list required,va_list optional)857 vips_call_required_optional( VipsOperation **operation,
858 va_list required, va_list optional )
859 {
860 int result;
861 va_list a;
862 va_list b;
863
864 /* We need to be able to walk required and optional twice. On x64 gcc,
865 * vips_operation_set_valist_required() etc. will destructively alter
866 * the passed-in va_list. We make a copy and walk that instead.
867 */
868 va_copy( a, required );
869 va_copy( b, optional );
870 result = vips_operation_set_valist_required( *operation, a ) ||
871 vips_object_set_valist( VIPS_OBJECT( *operation ), b );
872 va_end( a );
873 va_end( b );
874
875 if( result )
876 return( -1 );
877
878 /* Build from cache.
879 */
880 if( vips_cache_operation_buildp( operation ) )
881 return( -1 );
882
883 /* Walk args again, writing output.
884 */
885 va_copy( a, required );
886 va_copy( b, optional );
887 result = vips_operation_get_valist_required( *operation, required ) ||
888 vips_operation_get_valist_optional( *operation, optional );
889 va_end( a );
890 va_end( b );
891
892 return( result );
893 }
894
895 static int
vips_call_by_name(const char * operation_name,const char * option_string,va_list required,va_list optional)896 vips_call_by_name( const char *operation_name,
897 const char *option_string, va_list required, va_list optional )
898 {
899 VipsOperation *operation;
900 int result;
901
902 VIPS_DEBUG_MSG( "vips_call_by_name: starting for %s ...\n",
903 operation_name );
904
905 if( !(operation = vips_operation_new( operation_name )) )
906 return( -1 );
907
908 /* Set str options before vargs options, so the user can't override
909 * things we set deliberately.
910 */
911 if( option_string &&
912 vips_object_set_from_string( VIPS_OBJECT( operation ),
913 option_string ) ) {
914 vips_object_unref_outputs( VIPS_OBJECT( operation ) );
915 g_object_unref( operation );
916
917 return( -1 );
918 }
919
920 result = vips_call_required_optional( &operation, required, optional );
921
922 /* Build failed: junk args and back out.
923 */
924 if( result ) {
925 vips_object_unref_outputs( VIPS_OBJECT( operation ) );
926 g_object_unref( operation );
927
928 return( -1 );
929 }
930
931 /* The operation we have built should now have been reffed by one of
932 * its arguments or have finished its work. Either way, we can unref.
933 */
934 g_object_unref( operation );
935
936 return( result );
937 }
938
939 /**
940 * vips_call:
941 * @operation_name: name of operation to call
942 * @...: required args, then a %NULL-terminated list of argument/value pairs
943 *
944 * vips_call() calls the named operation, passing in required arguments and
945 * then setting any optional ones from the remainder of the arguments as a set
946 * of name/value pairs.
947 *
948 * For example, vips_embed() takes six required arguments, @in, @out, @x, @y,
949 * @width, @height, and has two optional arguments, @extend and @background.
950 * You can run it with vips_call() like this:
951 *
952 * |[
953 * VipsImage *in = ...
954 * VipsImage *out;
955 *
956 * if( vips_call( "embed", in, &out, 10, 10, 100, 100,
957 * "extend", VIPS_EXTEND_COPY,
958 * NULL ) )
959 * ... error
960 * ]|
961 *
962 * Normally of course you'd just use the vips_embed() wrapper function and get
963 * type-safety for the required arguments.
964 *
965 * See also: vips_call_split(), vips_call_options().
966 *
967 * Returns: 0 on success, -1 on error
968 */
969 int
vips_call(const char * operation_name,...)970 vips_call( const char *operation_name, ... )
971 {
972 VipsOperation *operation;
973 int result;
974 va_list required;
975 va_list optional;
976
977 if( !(operation = vips_operation_new( operation_name )) )
978 return( -1 );
979
980 /* We have to break the va_list into separate required and optional
981 * components.
982 *
983 * Note the start, grab the required, then copy and reuse.
984 */
985 va_start( required, operation_name );
986
987 va_copy( optional, required );
988
989 VIPS_ARGUMENT_FOR_ALL( operation,
990 pspec, argument_class, argument_instance ) {
991
992 g_assert( argument_instance );
993
994 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) ) {
995 VIPS_ARGUMENT_COLLECT_SET( pspec, argument_class,
996 optional );
997
998 VIPS_ARGUMENT_COLLECT_GET( pspec, argument_class,
999 optional );
1000
1001 VIPS_ARGUMENT_COLLECT_END
1002 }
1003 } VIPS_ARGUMENT_FOR_ALL_END
1004
1005 /* We just needed this operation for the arg loop.
1006 */
1007 g_object_unref( operation );
1008
1009 result = vips_call_by_name( operation_name, NULL, required, optional );
1010
1011 va_end( required );
1012 va_end( optional );
1013
1014 return( result );
1015 }
1016
1017 int
vips_call_split(const char * operation_name,va_list optional,...)1018 vips_call_split( const char *operation_name, va_list optional, ... )
1019 {
1020 int result;
1021 va_list required;
1022
1023 va_start( required, optional );
1024 result = vips_call_by_name( operation_name, NULL,
1025 required, optional );
1026 va_end( required );
1027
1028 return( result );
1029 }
1030
1031 int
vips_call_split_option_string(const char * operation_name,const char * option_string,va_list optional,...)1032 vips_call_split_option_string( const char *operation_name,
1033 const char *option_string, va_list optional, ... )
1034 {
1035 int result;
1036 va_list required;
1037
1038 va_start( required, optional );
1039 result = vips_call_by_name( operation_name, option_string,
1040 required, optional );
1041 va_end( required );
1042
1043 return( result );
1044 }
1045
1046 static void *
vips_call_find_pspec(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)1047 vips_call_find_pspec( VipsObject *object,
1048 GParamSpec *pspec,
1049 VipsArgumentClass *argument_class,
1050 VipsArgumentInstance *argument_instance,
1051 void *a, void *b )
1052 {
1053 const char *name = (const char *) a;
1054
1055 /* One char names we assume are "-x" style abbreviations, longer names
1056 * we match the whole string.
1057 */
1058 if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
1059 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
1060 !argument_instance->assigned )
1061 if( (strlen( name ) == 1 &&
1062 g_param_spec_get_name( pspec )[0] == name[0]) ||
1063 strcmp( g_param_spec_get_name( pspec ), name ) == 0 )
1064 return( argument_instance );
1065
1066 return( NULL );
1067 }
1068
1069 /* Keep this stuff around for output args.
1070 */
1071 typedef struct _VipsCallOptionOutput {
1072 VipsArgumentInstance *argument_instance;
1073 char *value;
1074 } VipsCallOptionOutput;
1075
1076 static int
vips_call_option_output(VipsObject * object,VipsCallOptionOutput * output)1077 vips_call_option_output( VipsObject *object,
1078 VipsCallOptionOutput *output )
1079 {
1080 VipsArgumentInstance *argument_instance = output->argument_instance;
1081 GParamSpec *pspec = ((VipsArgument *) argument_instance)->pspec;
1082
1083 int result;
1084
1085 /* Don't look at the output arg if _build() hasn't run sucessfully, it
1086 * probably won't have been set.
1087 */
1088 result = 0;
1089 if( object->constructed )
1090 result = vips_object_get_argument_to_string( object,
1091 g_param_spec_get_name( pspec ), output->value );
1092
1093 return( result );
1094 }
1095
1096 static void
vips_call_option_output_free(VipsObject * object,VipsCallOptionOutput * output)1097 vips_call_option_output_free( VipsObject *object, VipsCallOptionOutput *output )
1098 {
1099 VIPS_FREE( output->value );
1100 g_free( output );
1101 }
1102
1103 static gboolean
vips_call_options_set(const gchar * option_name,const gchar * value,gpointer data,GError ** error)1104 vips_call_options_set( const gchar *option_name, const gchar *value,
1105 gpointer data, GError **error )
1106 {
1107 VipsOperation *operation = (VipsOperation *) data;
1108 const char *name;
1109 VipsArgumentInstance *argument_instance;
1110 VipsArgumentClass *argument_class;
1111 GParamSpec *pspec;
1112
1113 VIPS_DEBUG_MSG( "vips_call_options_set: %s = %s\n",
1114 option_name, value );
1115
1116 /* Remove any leading "--" from the option name.
1117 */
1118 for( name = option_name; *name == '-'; name++ )
1119 ;
1120
1121 if( !(argument_instance = (VipsArgumentInstance *)
1122 vips_argument_map(
1123 VIPS_OBJECT( operation ),
1124 vips_call_find_pspec, (void *) name, NULL )) ) {
1125 vips_error( VIPS_OBJECT_GET_CLASS( operation )->nickname,
1126 _( "unknown argument '%s'" ), name );
1127 vips_error_g( error );
1128 return( FALSE );
1129 }
1130 argument_class = argument_instance->argument_class;
1131 pspec = ((VipsArgument *) argument_instance)->pspec;
1132
1133 if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) {
1134 if( vips_object_set_argument_from_string(
1135 VIPS_OBJECT( operation ),
1136 g_param_spec_get_name( pspec ), value ) ) {
1137 vips_error_g( error );
1138 return( FALSE );
1139 }
1140
1141 #ifdef VIPS_DEBUG
1142 {
1143 GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
1144 GValue gvalue = { 0, };
1145 char *str;
1146
1147 g_value_init( &gvalue, type );
1148 g_object_get_property( G_OBJECT( operation ),
1149 g_param_spec_get_name( pspec ), &gvalue );
1150 str = g_strdup_value_contents( &gvalue );
1151 VIPS_DEBUG_MSG( "\tGValue %s = %s\n",
1152 g_param_spec_get_name( pspec ), str );
1153 g_free( str );
1154 g_value_unset( &gvalue );
1155 }
1156 #endif /*VIPS_DEBUG*/
1157 }
1158 else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) {
1159 VipsCallOptionOutput *output;
1160
1161 /* We can't do output now, we have to attach a callback to do
1162 * the processing after the operation has run.
1163 */
1164 output = g_new( VipsCallOptionOutput, 1 );
1165 output->argument_instance = argument_instance;
1166 output->value = g_strdup( value );
1167 g_signal_connect( operation, "postbuild",
1168 G_CALLBACK( vips_call_option_output ),
1169 output );
1170 g_signal_connect( operation, "close",
1171 G_CALLBACK( vips_call_option_output_free ),
1172 output );
1173 }
1174
1175 return( TRUE );
1176 }
1177
1178 static void *
vips_call_options_add(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)1179 vips_call_options_add( VipsObject *object,
1180 GParamSpec *pspec,
1181 VipsArgumentClass *argument_class,
1182 VipsArgumentInstance *argument_instance,
1183 void *a, void *b )
1184 {
1185 GOptionGroup *group = (GOptionGroup *) a;
1186
1187 if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
1188 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
1189 !argument_instance->assigned ) {
1190 const char *name = g_param_spec_get_name( pspec );
1191 gboolean needs_string =
1192 vips_object_argument_needsstring( object, name );
1193 GOptionEntry entry[2];
1194
1195 entry[0].long_name = name;
1196 entry[0].description = g_param_spec_get_blurb( pspec );
1197
1198 /* Don't set short names for deprecated args.
1199 */
1200 if( argument_class->flags & VIPS_ARGUMENT_DEPRECATED )
1201 entry[0].short_name = '\0';
1202 else
1203 entry[0].short_name = name[0];
1204
1205 entry[0].flags = 0;
1206 if( !needs_string )
1207 entry[0].flags |= G_OPTION_FLAG_NO_ARG;
1208 if( argument_class->flags & VIPS_ARGUMENT_DEPRECATED )
1209 entry[0].flags |= G_OPTION_FLAG_HIDDEN;
1210
1211 entry[0].arg = G_OPTION_ARG_CALLBACK;
1212 entry[0].arg_data = (gpointer) vips_call_options_set;
1213 if( needs_string )
1214 entry[0].arg_description =
1215 g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) );
1216 else
1217 entry[0].arg_description = NULL;
1218
1219 entry[1].long_name = NULL;
1220
1221 VIPS_DEBUG_MSG( "vips_call_options_add: adding %s\n", name );
1222
1223 g_option_group_add_entries( group, &entry[0] );
1224 }
1225
1226 return( NULL );
1227 }
1228
1229 void
vips_call_options(GOptionGroup * group,VipsOperation * operation)1230 vips_call_options( GOptionGroup *group, VipsOperation *operation )
1231 {
1232 (void) vips_argument_map( VIPS_OBJECT( operation ),
1233 vips_call_options_add, group, NULL );
1234 }
1235
1236 /* What we track during an argv call.
1237 */
1238 typedef struct _VipsCall {
1239 VipsOperation *operation;
1240 int argc;
1241 char **argv;
1242 int i;
1243 } VipsCall;
1244
1245 static const char *
vips_call_get_arg(VipsCall * call,int i)1246 vips_call_get_arg( VipsCall *call, int i )
1247 {
1248 if( i < 0 ||
1249 i >= call->argc ) {
1250 vips_error( VIPS_OBJECT_GET_CLASS( call->operation )->nickname,
1251 "%s", _( "too few arguments" ) );
1252 return( NULL );
1253 }
1254
1255 return( call->argv[i] );
1256 }
1257
1258 static void *
vips_call_argv_input(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)1259 vips_call_argv_input( VipsObject *object,
1260 GParamSpec *pspec,
1261 VipsArgumentClass *argument_class,
1262 VipsArgumentInstance *argument_instance,
1263 void *a, void *b )
1264 {
1265 VipsCall *call = (VipsCall *) a;
1266
1267 /* Loop over all required construct args.
1268 */
1269 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
1270 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
1271 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) ) {
1272 const char *name = g_param_spec_get_name( pspec );
1273
1274 if( (argument_class->flags & VIPS_ARGUMENT_INPUT) ) {
1275 const char *arg;
1276
1277 if( !(arg = vips_call_get_arg( call, call->i )) ||
1278 vips_object_set_argument_from_string( object,
1279 name, arg ) )
1280 return( pspec );
1281
1282 call->i += 1;
1283 }
1284 else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) {
1285 if( vips_object_argument_needsstring( object, name ) )
1286 call->i += 1;
1287 }
1288 }
1289
1290 return( NULL );
1291 }
1292
1293 static void *
vips_call_argv_output(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)1294 vips_call_argv_output( VipsObject *object,
1295 GParamSpec *pspec,
1296 VipsArgumentClass *argument_class,
1297 VipsArgumentInstance *argument_instance,
1298 void *a, void *b )
1299 {
1300 VipsCall *call = (VipsCall *) a;
1301
1302 /* Loop over all required construct args.
1303 */
1304 if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
1305 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
1306 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) ) {
1307 if( (argument_class->flags & VIPS_ARGUMENT_INPUT) )
1308 call->i += 1;
1309 else if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) ) {
1310 const char *name = g_param_spec_get_name( pspec );
1311 const char *arg;
1312
1313 arg = NULL;
1314 if( vips_object_argument_needsstring( object, name ) ) {
1315 arg = vips_call_get_arg( call, call->i );
1316 if( !arg )
1317 return( pspec );
1318
1319 call->i += 1;
1320 }
1321
1322 if( vips_object_get_argument_to_string( object,
1323 name, arg ) )
1324 return( pspec );
1325 }
1326 }
1327
1328 return( NULL );
1329 }
1330
1331 /* Our main command-line entry point. Optional args should have been set by
1332 * the GOption parser already, see above.
1333 *
1334 * We don't create the operation, so we must not unref it. The caller must
1335 * unref on error too. The caller must also call vips_object_unref_outputs() on
1336 * all code paths.
1337 */
1338 int
vips_call_argv(VipsOperation * operation,int argc,char ** argv)1339 vips_call_argv( VipsOperation *operation, int argc, char **argv )
1340 {
1341 VipsCall call;
1342
1343 g_assert( argc >= 0 );
1344
1345 #ifdef VIPS_DEBUG
1346 printf( "vips_call_argv: " );
1347 vips_object_print_name( VIPS_OBJECT( operation ) );
1348 printf( "\n" );
1349 {
1350 int i;
1351
1352 for( i = 0; i < argc; i++ )
1353 printf( "%d) %s\n", i, argv[i] );
1354 }
1355 #endif /*VIPS_DEBUG*/
1356
1357 call.operation = operation;
1358 call.argc = argc;
1359 call.argv = argv;
1360
1361 call.i = 0;
1362 if( vips_argument_map( VIPS_OBJECT( operation ),
1363 vips_call_argv_input, &call, NULL ) )
1364 return( -1 );
1365
1366 /* Any unused arguments? We must fail. Consider eg. "vips bandjoin a b
1367 * c". This would overwrite b with a and ignore c, potentially
1368 * disastrous.
1369 */
1370 if( argc > call.i ) {
1371 vips_error( VIPS_OBJECT_GET_CLASS( operation )->nickname,
1372 "%s", _( "too many arguments" ) );
1373 return( -1 );
1374 }
1375
1376 /* We can't use the operation cache, we need to be able to change the
1377 * operation pointer. The cache probably wouldn't help anyway.
1378 */
1379 if( vips_object_build( VIPS_OBJECT( operation ) ) )
1380 return( -1 );
1381
1382 /* We're not using the cache, so we need to print the trace line.
1383 */
1384 if( vips__cache_trace ) {
1385 printf( "vips cache : " );
1386 vips_object_print_summary( VIPS_OBJECT( operation ) );
1387 }
1388
1389 call.i = 0;
1390 if( vips_argument_map( VIPS_OBJECT( operation ),
1391 vips_call_argv_output, &call, NULL ) )
1392 return( -1 );
1393
1394 return( 0 );
1395 }
1396