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