1 /* VIPS package handling.
2 *
3 * J. Cupitt, 8/4/93.
4 *
5 * 18/2/04 JC
6 * - now uses g_module_*() instead of dlopen()
7 * 9/8/04
8 * - uses glib dir scanning stuff instead of dirent.h
9 * 20/5/08
10 * - note_dependencies() does IMAGEVEC as well as IMAGE
11 * 5/8/08
12 * - silent success in loading plugins if the dir isn't there
13 */
14
15 /*
16
17 This file is part of VIPS.
18
19 VIPS is free software; you can redistribute it and/or modify
20 it under the terms of the GNU Lesser General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU Lesser General Public License for more details.
28
29 You should have received a copy of the GNU Lesser General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 02110-1301 USA
33
34 */
35
36 /*
37
38 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
39
40 */
41
42 /*
43 #define DEBUG
44 */
45
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif /*HAVE_CONFIG_H*/
49 #include <vips/intl.h>
50
51 #include <stdio.h>
52 #include <stdlib.h>
53 #ifdef HAVE_SYS_PARAM_H
54 #include <sys/param.h>
55 #endif /*HAVE_SYS_PARAM_H*/
56 #include <string.h>
57 #include <stdarg.h>
58 #include <limits.h>
59
60 #include <vips/vips.h>
61 #include <vips/vips7compat.h>
62 #include <vips/internal.h>
63 #include <vips/debug.h>
64
65 /* Standard VIPS packages.
66 */
67 extern im_package im__arithmetic;
68 extern im_package im__cimg;
69 extern im_package im__colour;
70 extern im_package im__conversion;
71 extern im_package im__convolution;
72 extern im_package im__deprecated;
73 extern im_package im__format;
74 extern im_package im__freq_filt;
75 extern im_package im__histograms_lut;
76 extern im_package im__inplace;
77 extern im_package im__mask;
78 extern im_package im__morphology;
79 extern im_package im__mosaicing;
80 extern im_package im__other;
81 extern im_package im__resample;
82 extern im_package im__video;
83
84 /* im_guess_prefix() args.
85 */
86 static im_arg_desc guess_prefix_args[] = {
87 IM_INPUT_STRING( "argv0" ),
88 IM_INPUT_STRING( "env_name" ),
89 IM_OUTPUT_STRING( "PREFIX" )
90 };
91
92 /* Call im_guess_prefix() via arg vector.
93 */
94 static int
guess_prefix_vec(im_object * argv)95 guess_prefix_vec( im_object *argv )
96 {
97 const char *prefix = vips_guess_prefix( argv[0], argv[1] );
98
99 if( !prefix ) {
100 argv[2] = NULL;
101 return( -1 );
102 }
103
104 argv[2] = im_strdup( NULL, prefix );
105
106 return( 0 );
107 }
108
109 /* Description of im_guess_prefix.
110 */
111 static im_function guess_prefix_desc = {
112 "im_guess_prefix", /* Name */
113 "guess install area", /* Description */
114 0, /* Flags */
115 guess_prefix_vec, /* Dispatch function */
116 VIPS_NUMBER( guess_prefix_args ), /* Size of arg list */
117 guess_prefix_args /* Arg list */
118 };
119
120 /* im_guess_libdir() args.
121 */
122 static im_arg_desc guess_libdir_args[] = {
123 IM_INPUT_STRING( "argv0" ),
124 IM_INPUT_STRING( "env_name" ),
125 IM_OUTPUT_STRING( "LIBDIR" )
126 };
127
128 /* Call im_guess_libdir() via arg vector.
129 */
130 static int
guess_libdir_vec(im_object * argv)131 guess_libdir_vec( im_object *argv )
132 {
133 const char *libdir = vips_guess_libdir( argv[0], argv[1] );
134
135 if( !libdir ) {
136 argv[2] = NULL;
137 return( -1 );
138 }
139
140 argv[2] = im_strdup( NULL, libdir );
141
142 return( 0 );
143 }
144
145 /* Description of im_guess_libdir.
146 */
147 static im_function guess_libdir_desc = {
148 "im_guess_libdir", /* Name */
149 "guess library area", /* Description */
150 0, /* Flags */
151 guess_libdir_vec, /* Dispatch function */
152 VIPS_NUMBER( guess_libdir_args ),/* Size of arg list */
153 guess_libdir_args /* Arg list */
154 };
155
156 /* im_header_int() args.
157 */
158 static im_arg_desc header_int_args[] = {
159 IM_INPUT_STRING( "field" ),
160 IM_INPUT_IMAGE( "image" ),
161 IM_OUTPUT_INT( "value" )
162 };
163
164 /* Call im_header_int() via arg vector.
165 */
166 static int
header_int_vec(im_object * argv)167 header_int_vec( im_object *argv )
168 {
169 return( im_header_int( (IMAGE *) argv[1], (const char *) argv[0],
170 (int *) argv[2] ) );
171 }
172
173 /* Description of im_header_int().
174 */
175 static im_function header_int_desc = {
176 "im_header_int", /* Name */
177 "extract int fields from header", /* Description */
178 0, /* Flags */
179 header_int_vec, /* Dispatch function */
180 VIPS_NUMBER( header_int_args ), /* Size of arg list */
181 header_int_args /* Arg list */
182 };
183
184 /* im_header_get_typeof() args.
185 */
186 static im_arg_desc header_get_typeof_args[] = {
187 IM_INPUT_STRING( "field" ),
188 IM_INPUT_IMAGE( "image" ),
189 IM_OUTPUT_INT( "gtype" )
190 };
191
192 /* Call im_header_get_typeof() via arg vector.
193 */
194 static int
header_get_typeof_vec(im_object * argv)195 header_get_typeof_vec( im_object *argv )
196 {
197 int *out = (int *) argv[2];
198
199 *out = im_header_get_typeof( (IMAGE *) argv[1],
200 (const char *) argv[0] );
201
202 return( 0 );
203 }
204
205 /* Description of im_header_get_typeof().
206 */
207 static im_function header_get_typeof_desc = {
208 "im_header_get_typeof", /* Name */
209 "return field type", /* Description */
210 0, /* Flags */
211 header_get_typeof_vec, /* Dispatch function */
212 VIPS_NUMBER( header_get_typeof_args ),/* Size of arg list */
213 header_get_typeof_args /* Arg list */
214 };
215
216 /* im_header_double() args.
217 */
218 static im_arg_desc header_double_args[] = {
219 IM_INPUT_STRING( "field" ),
220 IM_INPUT_IMAGE( "image" ),
221 IM_OUTPUT_DOUBLE( "value" )
222 };
223
224 /* Call im_header_double() via arg vector.
225 */
226 static int
header_double_vec(im_object * argv)227 header_double_vec( im_object *argv )
228 {
229 return( im_header_double( (IMAGE *) argv[1], (const char *) argv[0],
230 (double *) argv[2] ) );
231 }
232
233 /* Description of im_header_double().
234 */
235 static im_function header_double_desc = {
236 "im_header_double", /* Name */
237 "extract double fields from header", /* Description */
238 0, /* Flags */
239 header_double_vec, /* Dispatch function */
240 VIPS_NUMBER( header_double_args ), /* Size of arg list */
241 header_double_args /* Arg list */
242 };
243
244 /* im_header_string() args.
245 */
246 static im_arg_desc header_string_args[] = {
247 IM_INPUT_STRING( "field" ),
248 IM_INPUT_IMAGE( "image" ),
249 IM_OUTPUT_STRING( "value" )
250 };
251
252 /* Call im_header_string() via arg vector.
253 */
254 static int
header_string_vec(im_object * argv)255 header_string_vec( im_object *argv )
256 {
257 char **out = (char **) &argv[2];
258
259 /* Actually, we call im_header_as_string(), so we can do any field and
260 * not just the string-valued ones.
261 */
262 if( im_header_as_string( (IMAGE *) argv[1],
263 (const char *) argv[0], out ) )
264 return( -1 );
265
266 return( 0 );
267 }
268
269 /* Description of im_header_string().
270 */
271 static im_function header_string_desc = {
272 "im_header_string", /* Name */
273 "extract fields from headers as strings", /* Description */
274 0, /* Flags */
275 header_string_vec, /* Dispatch function */
276 VIPS_NUMBER( header_string_args ),/* Size of arg list */
277 header_string_args /* Arg list */
278 };
279
280 /* im_history_get() args.
281 */
282 static im_arg_desc history_get_args[] = {
283 IM_INPUT_IMAGE( "image" ),
284 IM_OUTPUT_STRING( "history" )
285 };
286
287 /* Call im_history_get() via arg vector.
288 */
289 static int
history_get_vec(im_object * argv)290 history_get_vec( im_object *argv )
291 {
292 char **out = (char **) &argv[1];
293 const char *str;
294
295 if( !(str = im_history_get( (IMAGE *) argv[0] )) ||
296 !(*out = im_strdup( NULL, str )) )
297 return( -1 );
298
299 return( 0 );
300 }
301
302 /* Description of im_history_get().
303 */
304 static im_function history_get_desc = {
305 "im_history_get", /* Name */
306 "return the image history as a string", /* Description */
307 0, /* Flags */
308 history_get_vec, /* Dispatch function */
309 VIPS_NUMBER( history_get_args ),/* Size of arg list */
310 history_get_args /* Arg list */
311 };
312
313 /* im_getext() args.
314 */
315 static im_arg_desc getext_args[] = {
316 IM_INPUT_IMAGE( "image" ),
317 IM_OUTPUT_STRING( "history" )
318 };
319
320 /* Call im_getext() via arg vector.
321 */
322 static int
getext_vec(im_object * argv)323 getext_vec( im_object *argv )
324 {
325 void **out = (void **) &argv[1];
326 int size;
327
328 /* void/char confusion is fine.
329 */
330 if( !(*out = im__read_extension_block( (IMAGE *) argv[0], &size )) )
331 return( -1 );
332
333 return( 0 );
334 }
335
336 /* Description of im_getext().
337 */
338 static im_function getext_desc = {
339 "im_getext", /* Name */
340 "return the image metadata XML as a string", /* Description */
341 0, /* Flags */
342 getext_vec, /* Dispatch function */
343 VIPS_NUMBER( getext_args ), /* Size of arg list */
344 getext_args /* Arg list */
345 };
346
347 /* im_printdesc() args.
348 */
349 static im_arg_desc printdesc_args[] = {
350 IM_INPUT_IMAGE( "image" ),
351 };
352
353 /* Call im_printdesc() via arg vector.
354 */
355 static int
printdesc_vec(im_object * argv)356 printdesc_vec( im_object *argv )
357 {
358 vips_object_print_dump( VIPS_OBJECT( argv[0] ) );
359
360 return( 0 );
361 }
362
363 /* Description of im_printdesc().
364 */
365 static im_function printdesc_desc = {
366 "im_printdesc", /* Name */
367 "print an image header to stdout", /* Description */
368 0, /* Flags */
369 printdesc_vec, /* Dispatch function */
370 VIPS_NUMBER( printdesc_args ), /* Size of arg list */
371 printdesc_args /* Arg list */
372 };
373
374 /* im_version_string() args.
375 */
376 static im_arg_desc version_string_args[] = {
377 IM_OUTPUT_STRING( "version" )
378 };
379
380 /* Call im_version_string() via arg vector.
381 */
382 static int
version_string_vec(im_object * argv)383 version_string_vec( im_object *argv )
384 {
385 if( !(argv[0] = im_strdup( NULL, vips_version_string() )) )
386 return( -1 );
387
388 return( 0 );
389 }
390
391 /* Description of im_version_string.
392 */
393 static im_function version_string_desc = {
394 "im_version_string", /* Name */
395 "VIPS version string", /* Description */
396 0, /* Flags */
397 version_string_vec, /* Dispatch function */
398 VIPS_NUMBER( version_string_args ),/* Size of arg list */
399 version_string_args /* Arg list */
400 };
401
402 /* im_version() args.
403 */
404 static im_arg_desc version_args[] = {
405 IM_INPUT_INT( "flag" ),
406 IM_OUTPUT_INT( "version" )
407 };
408
409 /* Call im_version() via arg vector.
410 */
411 static int
version_vec(im_object * argv)412 version_vec( im_object *argv )
413 {
414 int flag = *((int *) argv[0]);
415 int *out = ((int *) argv[1]);
416
417 int version = vips_version( flag );
418
419 if( version < 0 )
420 return( -1 );
421
422 *out = version;
423
424 return( 0 );
425 }
426
427 /* Description of im_version.
428 */
429 static im_function version_desc = {
430 "im_version", /* Name */
431 "VIPS version number", /* Description */
432 0, /* Flags */
433 version_vec, /* Dispatch function */
434 VIPS_NUMBER( version_args ), /* Size of arg list */
435 version_args /* Arg list */
436 };
437
438 /* im_concurrency_get() args.
439 */
440 static im_arg_desc concurrency_get_args[] = {
441 IM_OUTPUT_INT( "concurrency" )
442 };
443
444 /* Call im_concurrency_get() via arg vector.
445 */
446 static int
concurrency_get_vec(im_object * argv)447 concurrency_get_vec( im_object *argv )
448 {
449 int *out = ((int *) argv[0]);
450
451 *out = vips_concurrency_get();
452
453 return( 0 );
454 }
455
456 /* Description of im_concurrency_get.
457 */
458 static im_function concurrency_get_desc = {
459 "im_concurrency_get", /* Name */
460 "get concurrency level", /* Description */
461 0, /* Flags */
462 concurrency_get_vec, /* Dispatch function */
463 VIPS_NUMBER( concurrency_get_args ), /* Size of arg list */
464 concurrency_get_args /* Arg list */
465 };
466
467 /* im_cache() args.
468 */
469 static im_arg_desc cache_args[] = {
470 IM_INPUT_IMAGE( "in" ),
471 IM_OUTPUT_IMAGE( "out" ),
472 IM_INPUT_INT( "tile_width" ),
473 IM_INPUT_INT( "tile_height" ),
474 IM_INPUT_INT( "max_tiles" )
475 };
476
477 /* Call im_cache() via arg vector.
478 */
479 static int
cache_vec(im_object * argv)480 cache_vec( im_object *argv )
481 {
482 int tile_width = *((int *) argv[2]);
483 int tile_height = *((int *) argv[3]);
484 int max_tiles = *((int *) argv[4]);
485
486 return( im_cache( argv[0], argv[1],
487 tile_width, tile_height, max_tiles ) );
488 }
489
490 /* Description of im_cache.
491 */
492 static im_function cache_desc = {
493 "im_cache", /* Name */
494 "cache results of an operation",/* Description */
495 0, /* Flags */
496 cache_vec, /* Dispatch function */
497 VIPS_NUMBER( cache_args ), /* Size of arg list */
498 cache_args /* Arg list */
499 };
500
501 static int
tile_cache_random_vec(im_object * argv)502 tile_cache_random_vec( im_object *argv )
503 {
504 int tile_width = *((int *) argv[2]);
505 int tile_height = *((int *) argv[3]);
506 int max_tiles = *((int *) argv[4]);
507
508 return( im_tile_cache_random( argv[0], argv[1],
509 tile_width, tile_height, max_tiles ) );
510 }
511
512 /* Description of im_cache.
513 */
514 static im_function tile_cache_random_desc = {
515 "im_tile_cache_random", /* Name */
516 "cache results of an operation",/* Description */
517 0, /* Flags */
518 tile_cache_random_vec, /* Dispatch function */
519 VIPS_NUMBER( cache_args ), /* Size of arg list */
520 cache_args /* Arg list */
521 };
522
523 /* im_binfile() args.
524 */
525 static im_arg_desc binfile_args[] = {
526 IM_INPUT_STRING( "filename" ),
527 IM_OUTPUT_IMAGE( "out" ),
528 IM_INPUT_INT( "width" ),
529 IM_INPUT_INT( "height" ),
530 IM_INPUT_INT( "bands" ),
531 IM_INPUT_INT( "offset" )
532 };
533
534 /* Call im_binfile() via arg vector.
535 */
536 static int
binfile_vec(im_object * argv)537 binfile_vec( im_object *argv )
538 {
539 int width = *((int *) argv[2]);
540 int height = *((int *) argv[3]);
541 int bands = *((int *) argv[4]);
542 int offset = *((int *) argv[5]);
543 VipsImage *im;
544
545 if( !(im = vips_image_new_from_file_raw( argv[0],
546 width, height, bands, offset )) )
547 return( -1 );
548 vips_object_local( argv[1], im );
549
550 if( im_copy( im, argv[1] ) )
551 return( -1 );
552
553 return( 0 );
554 }
555
556 /* Description of im_binfile.
557 */
558 static im_function binfile_desc = {
559 "im_binfile", /* Name */
560 "open a headerless binary file",/* Description */
561 0, /* Flags */
562 binfile_vec, /* Dispatch function */
563 VIPS_NUMBER( binfile_args ), /* Size of arg list */
564 binfile_args /* Arg list */
565 };
566
567 /* Package up iofuncs functions.
568 */
569 static im_function *iofuncs_list[] = {
570 &binfile_desc,
571 &cache_desc,
572 &tile_cache_random_desc,
573 &concurrency_get_desc,
574 &getext_desc,
575 &guess_prefix_desc,
576 &guess_libdir_desc,
577 &header_get_typeof_desc,
578 &header_int_desc,
579 &header_double_desc,
580 &header_string_desc,
581 &history_get_desc,
582 &printdesc_desc,
583 &version_desc,
584 &version_string_desc
585 };
586
587 /* Package of io functions.
588 */
589 static im_package im__iofuncs = {
590 "iofuncs",
591 VIPS_NUMBER( iofuncs_list ),
592 iofuncs_list
593 };
594
595 /* List of built-in VIPS packages.
596 */
597 static im_package *built_in[] = {
598 &im__arithmetic,
599 &im__cimg,
600 &im__colour,
601 &im__conversion,
602 &im__convolution,
603 &im__deprecated,
604 &im__format,
605 &im__freq_filt,
606 &im__histograms_lut,
607 &im__inplace,
608 &im__iofuncs,
609 &im__mask,
610 &im__morphology,
611 &im__mosaicing,
612 &im__other,
613 &im__resample,
614 &im__video
615 };
616 /* How we represent a loaded plugin.
617 */
618 typedef struct _Plugin {
619 GModule *module; /* As loaded by g_module_open() */
620 char *name; /* Name we loaded */
621 im_package *pack; /* Package table */
622 } Plugin;
623
624 /* List of loaded plugins.
625 */
626 static GSList *plugin_list = NULL;
627
628 /* Free a plugin.
629 */
630 static int
plugin_free(Plugin * plug)631 plugin_free( Plugin *plug )
632 {
633 char *name = plug->name ? plug->name : "<unknown>";
634
635 if( plug->module ) {
636 if( !g_module_close( plug->module ) ) {
637 vips_error( "plugin",
638 _( "unable to close plugin \"%s\"" ), name );
639 vips_error( "plugin", "%s", g_module_error() );
640 return( -1 );
641 }
642
643 plug->module = NULL;
644 }
645 VIPS_FREE( plug->name );
646 plug->pack = NULL;
647 g_free( plug );
648
649 plugin_list = g_slist_remove( plugin_list, plug );
650
651 return( 0 );
652 }
653
654 /* Load a plugin.
655 */
656 im_package *
im_load_plugin(const char * name)657 im_load_plugin( const char *name )
658 {
659 Plugin *plug;
660
661 #ifdef DEBUG
662 printf( "im_load_plugin: \"%s\"\n", name );
663 #endif /*DEBUG*/
664
665 if( !g_module_supported() ) {
666 vips_error( "plugin",
667 "%s", _( "plugins not supported on this platform" ) );
668 return( NULL );
669 }
670
671 /* Build a new plugin.
672 */
673 plug = VIPS_NEW( NULL, Plugin );
674 plug->module = NULL;
675 plug->name = g_strdup( name );
676 plug->pack = NULL;
677 plugin_list = g_slist_prepend( plugin_list, plug );
678
679 /* Open library.
680 */
681 if( !(plug->module = g_module_open( name, 0 )) ) {
682 vips_error( "plugin",
683 _( "unable to open plugin \"%s\"" ), name );
684 vips_error( "plugin", "%s", g_module_error() );
685 plugin_free( plug );
686
687 return( NULL );
688 }
689
690 /* Find package.
691 */
692 /* Bizarre double-cast stops a bogus gcc 4.1 compiler warning.
693 */
694 if( !g_module_symbol( plug->module,
695 "package_table", (gpointer *) ((void *) &plug->pack) ) ) {
696 vips_error( "plugin",
697 _( "unable to find symbol \"package_table\" "
698 "in plugin \"%s\"" ), name );
699 vips_error( "plugin", "%s", g_module_error() );
700 plugin_free( plug );
701
702 return( NULL );
703 }
704
705 /* Sanity check.
706 */
707 if( !plug->pack->name || plug->pack->nfuncs < 0 ||
708 plug->pack->nfuncs > 10000 ) {
709 vips_error( "plugin",
710 _( "corrupted package table in plugin \"%s\"" ), name );
711 plugin_free( plug );
712
713 return( NULL );
714 }
715
716 #ifdef DEBUG
717 printf( "added package \"%s\"\n", plug->pack->name );
718 #endif /*DEBUG*/
719
720 return( plug->pack );
721 }
722
723 /* Load all plugins in a directory ... look for '.plg' suffix. Error if we had
724 * any probs.
725 */
726 int
im_load_plugins(const char * fmt,...)727 im_load_plugins( const char *fmt, ... )
728 {
729 va_list ap;
730 char dir_name[VIPS_PATH_MAX];
731 GDir *dir;
732 const char *name;
733 int result;
734
735 /* Silently succeed if we can't do modules.
736 */
737 if( !g_module_supported() )
738 return( 0 );
739
740 va_start( ap, fmt );
741 (void) im_vsnprintf( dir_name, VIPS_PATH_MAX - 1, fmt, ap );
742 va_end( ap );
743
744 #ifdef DEBUG
745 printf( "im_load_plugins: searching \"%s\"\n", dir_name );
746 #endif /*DEBUG*/
747
748 if( !(dir = g_dir_open( dir_name, 0, NULL )) )
749 /* Silent success for dir not there.
750 */
751 return( 0 );
752
753 result = 0;
754 while( (name = g_dir_read_name( dir )) )
755 if( im_ispostfix( name, ".plg" ) ) {
756 char path[VIPS_PATH_MAX];
757
758 im_snprintf( path, VIPS_PATH_MAX - 1,
759 "%s" G_DIR_SEPARATOR_S "%s", dir_name, name );
760 if( !im_load_plugin( path ) )
761 result = -1;
762 }
763 g_dir_close( dir );
764
765 return( result );
766 }
767
768 /* Close all loaded plugins.
769 */
770 int
im_close_plugins(void)771 im_close_plugins( void )
772 {
773 while( plugin_list )
774 if( plugin_free( (Plugin *) plugin_list->data ) )
775 return( -1 );
776
777 return( 0 );
778 }
779
780 /* Apply a user-function to a plugin package.
781 */
782 static void *
apply_plugin(Plugin * plug,VSListMap2Fn fn,void * a)783 apply_plugin( Plugin *plug, VSListMap2Fn fn, void *a )
784 {
785 if( !plug->pack )
786 return( NULL );
787 else
788 return( fn( plug->pack, a, NULL ) );
789 }
790
791 /* Map a function over all packages. Map over plugins first, to allow
792 * overriding of VIPS functions.
793 */
794 void *
im_map_packages(VSListMap2Fn fn,void * a)795 im_map_packages( VSListMap2Fn fn, void *a )
796 {
797 void *r = im_slist_map2( plugin_list,
798 (VSListMap2Fn) apply_plugin, (void *) fn, a );
799
800 /* If not there, try main VIPS package list.
801 */
802 if( !r ) {
803 int i;
804
805 for( i = 0; i < VIPS_NUMBER( built_in ); i++ )
806 if( (r = fn( built_in[i], a, NULL )) )
807 return( r );
808 }
809
810 return( r );
811 }
812
813 /* Search a package for a function.
814 */
815 static im_function *
search_package(im_package * pack,const char * name)816 search_package( im_package *pack, const char *name )
817 {
818 int i;
819
820 for( i = 0; i < pack->nfuncs; i++ )
821 if( strcmp( pack->table[i]->name, name ) == 0 )
822 return( pack->table[i] );
823
824 return( NULL );
825 }
826
827 /* Search all packages for a function.
828 */
829 im_function *
im_find_function(const char * name)830 im_find_function( const char *name )
831 {
832 im_function *fn = im_map_packages(
833 (VSListMap2Fn) search_package, (void *) name );
834
835 if( !fn ) {
836 vips_error( "im_find_function", _( "\"%s\" not found" ), name );
837 return( NULL );
838 }
839
840 return( fn );
841 }
842
843 /* Test for package is of name.
844 */
845 static im_package *
package_name(im_package * pack,const char * name)846 package_name( im_package *pack, const char *name )
847 {
848 if( strcmp( pack->name, name ) == 0 )
849 return( pack );
850
851 return( NULL );
852 }
853
854 /* Find a package.
855 */
856 im_package *
im_find_package(const char * name)857 im_find_package( const char *name )
858 {
859 im_package *pack = im_map_packages(
860 (VSListMap2Fn) package_name, (void *) name );
861
862 if( !pack ) {
863 vips_error( "im_find_package", _( "\"%s\" not found" ), name );
864 return( NULL );
865 }
866
867 return( pack );
868 }
869
870 /* Test for package contains a function.
871 */
872 static im_package *
package_function(im_package * pack,const char * name)873 package_function( im_package *pack, const char *name )
874 {
875 if( search_package( pack, name ) )
876 return( pack );
877 else
878 return( NULL );
879 }
880
881 /* Find a function's package by name.
882 */
883 im_package *
im_package_of_function(const char * name)884 im_package_of_function( const char *name )
885 {
886 im_package *pack = im_map_packages(
887 (VSListMap2Fn) package_function, (void *) name );
888
889 if( !pack ) {
890 vips_error( "im_package_of_function",
891 _( "\"%s\" not found" ), name );
892 return( NULL );
893 }
894
895 return( pack );
896 }
897
898 /* Free any store we allocated for the argument list.
899 */
900 int
im_free_vargv(im_function * fn,im_object * vargv)901 im_free_vargv( im_function *fn, im_object *vargv )
902 {
903 int i;
904 int vargc = fn->argc;
905
906 /* Free all elements.
907 */
908 for( i = 0; i < vargc; i++ )
909 if( vargv[i] ) {
910 /* If there is local storage, free it.
911 */
912 if( fn->argv[i].desc->size != 0 )
913 g_free( vargv[i] );
914
915 /* NULL out pointer.
916 */
917 vargv[i] = NULL;
918 }
919
920 return( 0 );
921 }
922
923 /* Allocate any local store the args will need; NULL out all others.
924 */
925 int
im_allocate_vargv(im_function * fn,im_object * vargv)926 im_allocate_vargv( im_function *fn, im_object *vargv )
927 {
928 int i;
929 int vargc = fn->argc;
930
931 /* NULL out all pointers.
932 */
933 for( i = 0; i < vargc; i++ )
934 vargv[i] = NULL;
935
936 /* Allocate any space we will need.
937 */
938 for( i = 0; i < vargc; i++ ) {
939 int sz = fn->argv[i].desc->size;
940
941 if( sz != 0 )
942 if( !(vargv[i] = vips_malloc( NULL, sz )) ) {
943 /* Free anything we did allocate.
944 */
945 (void) im_free_vargv( fn, vargv );
946 return( -1 );
947 }
948
949 /* Zero memory.
950 */
951 memset( vargv[i], 0, sz );
952 }
953
954 return( 0 );
955 }
956
957 /* Destroy the objects in the arg list.
958 */
959 static int
destroy_args(im_function * fn,im_object * vargv)960 destroy_args( im_function *fn, im_object *vargv )
961 {
962 int i;
963 int vargc = fn->argc;
964
965 /* Destroy all elements with destroy functions.
966 */
967 for( i = 0; i < vargc; i++ )
968 if( vargv[i] )
969 /* If there's a destroy function for this type,
970 * trigger it.
971 */
972 if( fn->argv[i].desc->dest &&
973 fn->argv[i].desc->dest( vargv[i] ) )
974 return( -1 );
975
976 return( 0 );
977 }
978
979 /* Init an im_object array from a set of command-line arguments.
980 */
981 static int
build_args(im_function * fn,im_object * vargv,int argc,char ** argv)982 build_args( im_function *fn, im_object *vargv, int argc, char **argv )
983 {
984 im_arg_desc *arg = fn->argv;
985 int vargc = fn->argc;
986 char *str;
987 int i, j;
988
989 /* Loop, constructing each im_arg.
990 */
991 for( i = 0, j = 0; i < vargc; i++ ) {
992 /* Find type for this arg.
993 */
994 im_type_desc *type = arg[i].desc;
995
996 /* Do we need to use up a command line argument?
997 */
998 if( type->flags & IM_TYPE_ARG ) {
999 if( !argv[j] ) {
1000 vips_error( "im_run_command",
1001 "%s", _( "too few arguments" ) );
1002 return( -1 );
1003 }
1004 str = argv[j++];
1005
1006 /* Init object.
1007 */
1008 if( type->init && type->init( &vargv[i], str ) )
1009 return( -1 );
1010 }
1011 else {
1012 /* Init object with no arg.
1013 */
1014 if( type->init && type->init( &vargv[i], "no arg" ) )
1015 return( -1 );
1016 }
1017 }
1018
1019 /* Have we used up all the command-line args?
1020 */
1021 if( argv[j] ) {
1022 vips_error( "im_run_command", "%s", _( "too many arguments" ) );
1023 return( -1 );
1024 }
1025
1026 return( 0 );
1027 }
1028
1029 /* Make a region on sub, closed by callback on main.
1030 */
1031 static int
region_local_image(IMAGE * main,IMAGE * sub)1032 region_local_image( IMAGE *main, IMAGE *sub )
1033 {
1034 VipsRegion *reg;
1035
1036 if( !(reg = vips_region_new( sub )) )
1037 return( -1 );
1038 vips_object_local( main, reg );
1039
1040 return( 0 );
1041 }
1042
1043 /* vargv[i] is an output image on a PIO function ... make all input images
1044 * depend on it.
1045 */
1046 static int
note_dependencies(im_function * fn,im_object * vargv,int i)1047 note_dependencies( im_function *fn, im_object *vargv, int i )
1048 {
1049 int j;
1050
1051 for( j = 0; j < fn->argc; j++ ) {
1052 im_type_desc *type = fn->argv[j].desc;
1053
1054 if( !(type->flags & IM_TYPE_OUTPUT) ) {
1055 if( strcmp( type->type, IM_TYPE_IMAGE ) == 0 ) {
1056 if( region_local_image( vargv[i], vargv[j] ) )
1057 return( -1 );
1058 }
1059 else if( strcmp( type->type, IM_TYPE_IMAGEVEC ) == 0 ) {
1060 im_imagevec_object *iv = vargv[j];
1061 int k;
1062
1063 for( k = 0; k < iv->n; k++ )
1064 if( region_local_image( vargv[i],
1065 iv->vec[k] ) )
1066 return( -1 );
1067 }
1068 }
1069 }
1070
1071 return( 0 );
1072 }
1073
1074 /* Call all defined print functions.
1075 */
1076 static int
print_args(im_function * fn,im_object * vargv)1077 print_args( im_function *fn, im_object *vargv )
1078 {
1079 int i;
1080 int vargc = fn->argc;
1081
1082 /* Print all elements.
1083 */
1084 for( i = 0; i < vargc; i++ )
1085 if( fn->argv[i].print && vargv[i] )
1086 if( fn->argv[i].print( vargv[i] ) )
1087 return( -1 );
1088
1089 return( 0 );
1090 }
1091
1092 /* Add to the hist of all output images.
1093 */
1094 static int
add_hist(im_function * fn,im_object * vargv,int argc,char ** argv)1095 add_hist( im_function *fn, im_object *vargv, int argc, char **argv )
1096 {
1097 int i;
1098 int vargc = fn->argc;
1099
1100 /* Search for output images.
1101 */
1102 for( i = 0; i < vargc; i++ )
1103 if( strcmp( fn->argv[i].desc->type, IM_TYPE_IMAGE ) == 0 &&
1104 (fn->argv[i].desc->flags & IM_TYPE_OUTPUT) )
1105 if( im_updatehist( vargv[i], fn->name, argc, argv ) )
1106 return( -1 );
1107
1108 return( 0 );
1109 }
1110
1111 /* Call a VIPS function.
1112 */
1113 static int
dispatch_function(im_function * fn,im_object * vargv,int argc,char ** argv)1114 dispatch_function( im_function *fn, im_object *vargv, int argc, char **argv )
1115 {
1116 /* Init memory from command line arguments.
1117 */
1118 if( build_args( fn, vargv, argc, argv ) )
1119 return( -1 );
1120
1121 /* If this is a PIO function, we need to make sure that we close
1122 * the input images after the output images, since the output image
1123 * may include delayed image conversion filters which will not run
1124 * until the output is closed.
1125 *
1126 * Do this by:
1127 * - for each output image
1128 * - for each input image
1129 * - create a region on the input, closed by a
1130 * close callback on the output image
1131 */
1132 if( fn->flags & IM_FN_PIO ) {
1133 int i;
1134
1135 for( i = 0; i < fn->argc; i++ ) {
1136 im_type_desc *type = fn->argv[i].desc;
1137
1138 if( type->flags & IM_TYPE_OUTPUT &&
1139 strcmp( type->type, IM_TYPE_IMAGE ) == 0 )
1140 if( note_dependencies( fn, vargv, i ) )
1141 return( -1 );
1142 }
1143 }
1144
1145 /* Call function.
1146 */
1147 if( fn->disp( vargv ) )
1148 return( -1 );
1149
1150 /* Print output.
1151 */
1152 if( print_args( fn, vargv ) )
1153 return( -1 );
1154
1155 /* Add to history of all output images.
1156 */
1157 if( add_hist( fn, vargv, argc, argv ) )
1158 return( -1 );
1159
1160 /* All ok!
1161 */
1162 return( 0 );
1163 }
1164
1165 /* Run a command.
1166 */
1167 int
im_run_command(char * name,int argc,char ** argv)1168 im_run_command( char *name, int argc, char **argv )
1169 {
1170 static im_object object_array[IM_MAX_ARGS];
1171 im_object *vargv = object_array;
1172 im_function *fn;
1173
1174 /* Search packages for a matching function.
1175 */
1176 if( !(fn = im_find_function( name )) )
1177 return( -1 );
1178
1179 /* Allocate space for arguments.
1180 */
1181 if( im_allocate_vargv( fn, vargv ) )
1182 return( -1 );
1183
1184 /* Call it.
1185 */
1186 if( dispatch_function( fn, vargv, argc, argv ) ) {
1187 destroy_args( fn, vargv );
1188 im_free_vargv( fn, vargv );
1189 return( -1 );
1190 }
1191
1192 /* Clean up and exit.
1193 */
1194 if( destroy_args( fn, vargv ) )
1195 return( -1 );
1196 im_free_vargv( fn, vargv );
1197
1198 return( 0 );
1199 }
1200