2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M AAA GGGG IIIII CCCC K K %
7 % MM MM A A G I C K K %
8 % M M M AAAAA G GGG I C KKK %
9 % M M A A G G I C K K %
10 % M M A A GGGG IIIII CCCC K K %
18 % Perform "Magick" on Images via the Command Line Interface %
25 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
26 % dedicated to making software imaging solutions freely available. %
28 % You may not use this file except in compliance with the License. You may %
29 % obtain a copy of the License at %
31 % http://www.imagemagick.org/script/license.php %
33 % Unless required by applicable law or agreed to in writing, software %
34 % distributed under the License is distributed on an "AS IS" BASIS, %
35 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36 % See the License for the specific language governing permissions and %
37 % limitations under the License. %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 % Read CLI arguments, script files, and pipelines, to provide options that
42 % manipulate images from many different formats.
49 #include "MagickWand/studio.h"
50 #include "MagickWand/MagickWand.h"
51 #include "MagickWand/magick-wand-private.h"
52 #include "MagickWand/wandcli.h"
53 #include "MagickWand/wandcli-private.h"
54 #include "MagickWand/operation.h"
55 #include "MagickWand/magick-cli.h"
56 #include "MagickWand/script-token.h"
57 #include "MagickCore/utility-private.h"
58 #include "MagickCore/version.h"
61 3 - option type details
62 9 - output options/artifacts/propertys
64 #define MagickCommandDebug 0
66 #define ThrowFileException(exception,severity,tag,context) \
71 message=GetExceptionMessage(errno); \
72 (void) ThrowMagickException(exception,GetMagickModule(),severity, \
73 tag == (const char *) NULL ? "unknown" : tag,"'%s': %s",context,message); \
74 message=DestroyString(message); \
77 #if MagickCommandDebug >= 9
79 Temporary Debugging Information
80 FUTURE: these should be able to be printed out using 'percent escapes'
81 Actually 'Properities' can already be output with "%[*]"
83 static void OutputOptions(ImageInfo *image_info)
89 (void) FormatLocaleFile(stdout," Global Options:\n");
90 ResetImageOptionIterator(image_info);
91 while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) {
92 (void) FormatLocaleFile(stdout," %s: ",option);
93 value=GetImageOption(image_info,option);
94 if (value != (const char *) NULL)
95 (void) FormatLocaleFile(stdout,"%s\n",value);
97 ResetImageOptionIterator(image_info);
100 static void OutputArtifacts(Image *image)
106 (void) FormatLocaleFile(stdout," Image Artifacts:\n");
107 ResetImageArtifactIterator(image);
108 while ((artifact=GetNextImageArtifact(image)) != (const char *) NULL ) {
109 (void) FormatLocaleFile(stdout," %s: ",artifact);
110 value=GetImageArtifact(image,artifact);
111 if (value != (const char *) NULL)
112 (void) FormatLocaleFile(stdout,"%s\n",value);
114 ResetImageArtifactIterator(image);
117 static void OutputProperties(Image *image,ExceptionInfo *exception)
123 (void) FormatLocaleFile(stdout," Image Properity:\n");
124 ResetImagePropertyIterator(image);
125 while ((property=GetNextImageProperty(image)) != (const char *) NULL ) {
126 (void) FormatLocaleFile(stdout," %s: ",property);
127 value=GetImageProperty(image,property,exception);
128 if (value != (const char *) NULL)
129 (void) FormatLocaleFile(stdout,"%s\n",value);
131 ResetImagePropertyIterator(image);
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 + P r o c e s s S c r i p t O p t i o n s %
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 % ProcessScriptOptions() reads options and processes options as they are
148 % found in the given file, or pipeline. The filename to open and read
149 % options is given as the 'index' argument of the argument array given.
151 % Other arguments following index may be read by special script options
152 % as settings (strings), images, or as operations to be processed in various
153 % ways. How they are treated is up to the script being processed.
155 % Note that a script not 'return' to the command line processing, nor can
156 % they call (and return from) other scripts. At least not at this time.
158 % There are no 'ProcessOptionFlags' control flags at this time.
160 % The format of the ProcessScriptOptions method is:
162 % void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
165 % A description of each parameter follows:
167 % o cli_wand: the main CLI Wand to use.
169 % o argc: the number of elements in the argument vector.
171 % o argv: A text array containing the command line arguments.
173 % o index: offset for argc to CLI argumnet count
176 WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
193 assert(argc>index); /* at least one argument - script name */
194 assert(argv != (char **)NULL);
195 assert(argv[index] != (char *)NULL);
196 assert(argv[argc-1] != (char *)NULL);
197 assert(cli_wand != (MagickCLI *) NULL);
198 assert(cli_wand->signature == WandSignature);
199 if (cli_wand->wand.debug != MagickFalse)
200 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
202 /* open file script or stream, and set up tokenizer */
203 token_info = AcquireScriptTokenInfo(argv[index]);
204 if (token_info == (ScriptTokenInfo *) NULL) {
205 ThrowFileException(cli_wand->wand.exception,OptionFatalError,
206 "UnableToOpenScript",argv[index]);
210 /* define the error location string for use in exceptions
211 order of input escapes: option, (arg), filename, line, column */
212 cli_wand->location="'%s' in \"%s\" line %u column %u";
213 cli_wand->location2="'%s' '%s' in \"%s\" line %u column %u";
214 if ( LocaleCompare("-", argv[index]) == 0 )
215 cli_wand->filename="stdin";
217 cli_wand->filename=argv[index];
219 /* Process Options from Script */
220 option = arg1 = arg2 = (char*)NULL;
224 { MagickBooleanType status = GetScriptToken(token_info);
225 cli_wand->line=token_info->token_line;
226 cli_wand->column=token_info->token_column;
227 if( IfMagickFalse(status) )
228 break; /* error or end of options */
231 /* save option details */
232 CloneString(&option,token_info->token);
234 { /* get option type and argument count */
235 const OptionInfo *option_info = GetCommandOptionInfo(option);
236 count=option_info->type;
237 option_type=(CommandOptionFlags) option_info->flags;
239 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
240 cli_wand->line, cli_wand->line, option, option_info->mnemonic );
244 /* handle a undefined option - image read? */
245 if ( option_type == UndefinedOptionFlag ||
246 (option_type & NonMagickOptionFlag) != 0 ) {
247 #if MagickCommandDebug >= 3
248 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
249 cli_wand->line, cli_wand->line, option);
251 if ( IfMagickFalse(IsCommandOption(option))) {
252 /* non-option -- treat as a image read */
253 CLISpecialOperator(cli_wand,"-read",option);
256 if ( LocaleCompare(option,"-script") == 0 ) {
257 option_type=SpecialOptionFlag;
259 /* fall thru - collect one argument */
262 CLIWandExceptionBreak(OptionFatalError,"UnrecognizedOption",option);
268 if( IfMagickFalse(GetScriptToken(token_info)) )
269 CLIWandException(OptionFatalError,"MissingArgument",option);
270 CloneString(&arg1,token_info->token);
273 CloneString(&arg1,(char *)NULL);
276 if( IfMagickFalse(GetScriptToken(token_info)) )
277 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
278 CloneString(&arg2,token_info->token);
281 CloneString(&arg2,(char *)NULL);
283 #if MagickCommandDebug >= 3
284 (void) FormatLocaleFile(stderr,
285 "Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
286 cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
289 if ( (option_type & GenesisOptionFlag) != 0 ) {
290 /* Genesis Options have no place in a magick script */
291 CLIWandExceptionBreak(OptionError,"InvalidUseOfOption",option);
294 if ( (option_type & DeprecateOptionFlag) != 0 ) {
295 CLIWandException(OptionWarning,"DeprecatedOption",option);
296 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
298 /* fall through - do the depreciated option */
300 if (((option_type & ImageRequiredFlags) != 0 ) &&
301 ( cli_wand->wand.images == (Image *)NULL ) ) {
302 CLIWandException(OptionError,"NoImagesFound",option);
306 /* handle special script-argument options here */
307 //either continue processing command line
308 // or making use of the command line options.
309 //CLICommandOptions(cli_wand,count+1,argv, MagickScriptArgsFlags);
312 Process Option from file
314 if ( (option_type & SpecialOptionFlag) != 0 ) {
315 if ( LocaleCompare(option,"-exit") == 0 ) {
316 break; /* forced end of script */
318 else if ( LocaleCompare(option,"-script") == 0 ) {
319 /* FUTURE: call new script from this script */
320 CLIWandExceptionBreak(OptionError,"InvalidUseOfOption",option);
323 /* handle any other special operators now */
324 CLISpecialOperator(cli_wand,option,arg1);
327 if ( (option_type & SettingOptionFlags) != 0 ) {
328 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
329 // FUTURE: Sync Specific Settings into Image Properities (not global)
331 if ( cli_wand->wand.images != (Image *)NULL )
332 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
333 cli_wand->wand.exception);
335 if ( (option_type & SimpleOperatorOptionFlag) != 0)
336 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
338 if ( (option_type & ListOperatorOptionFlag) != 0 )
339 CLIListOperatorImages(cli_wand, option, arg1, arg2);
342 #if MagickCommandDebug >= 9
343 OutputOptions(cli_wand->wand.image_info);
344 if ( cli_wand->wand.images != (Image *)NULL ) {
345 OutputArtifacts(cli_wand->wand.images);
346 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
349 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
353 #if MagickCommandDebug >= 3
354 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
356 switch( token_info->status ) {
359 if (cli_wand->image_list_stack != (Stack *)NULL)
360 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
361 else if (cli_wand->image_info_stack != (Stack *)NULL)
362 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
364 case TokenStatusBadQuotes:
365 /* Ensure last token has a sane length for error report */
366 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
367 token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
368 token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
369 token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
370 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
372 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
375 case TokenStatusMemoryFailed:
376 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
378 case TokenStatusBinary:
379 CLIWandException(OptionFatalError,"ScriptIsBinary","");
384 token_info = DestroyScriptTokenInfo(token_info);
386 CloneString(&option,(char *)NULL);
387 CloneString(&arg1,(char *)NULL);
388 CloneString(&arg2,(char *)NULL);
394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 + P r o c e s s C o m m a n d O p t i o n s %
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 % ProcessCommandOptions() reads and processes arguments in the given
405 % command line argument array. The array does not contain the command
406 % being processed, only the options.
408 % The 'process_flags' can be used to control and limit option processing.
409 % For example, to only process one option, or how unknown and special options
410 % are to be handled, and if the last argument in array is to be regarded as a
411 % final image write argument (filename or special coder).
413 % The format of the ProcessCommandOptions method is:
415 % int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
416 % int index, ProcessOptionFlags process_flags )
418 % A description of each parameter follows:
420 % o cli_wand: the main CLI Wand to use.
422 % o argc: the number of elements in the argument vector.
424 % o argv: A text array containing the command line arguments.
426 % o process_flags: What type of arguments will be processed, ignored
429 % o index: index in the argv array to start processing from
431 % The function returns the index ot the next option to be processed. This
432 % is really only releven if process_flags contains a ProcessOneOptionOnly
436 WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc,
437 char **argv, int index, ProcessOptionFlags process_flags )
452 assert(argc>=index); /* you may have no arguments left! */
453 assert(argv != (char **)NULL);
454 assert(argv[index] != (char *)NULL);
455 assert(argv[argc-1] != (char *)NULL);
456 assert(cli_wand != (MagickCLI *) NULL);
457 assert(cli_wand->signature == WandSignature);
458 if (cli_wand->wand.debug != MagickFalse)
459 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
461 /* define the error location string for use in exceptions
462 order of input escapes: option, (arg), filename, line, column */
463 cli_wand->location="'%s' %s arg %u";
464 cli_wand->location2="'%s' '%s' %s arg %u";
465 cli_wand->filename="CLI";
468 if ( ( process_flags & ProcessOutputFile ) != 0 )
471 for (i=index; i < end; i += count +1) {
472 /* Finished processing one option? */
473 if ( ( process_flags & ProcessOneOptionOnly ) != 0 && i != index )
479 { const OptionInfo *option_info = GetCommandOptionInfo(argv[i]);
480 count=option_info->type;
481 option_type=(CommandOptionFlags) option_info->flags;
483 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
484 i, argv[i], option_info->mnemonic );
488 if ( option_type == UndefinedOptionFlag ||
489 (option_type & NonMagickOptionFlag) != 0 ) {
490 #if MagickCommandDebug >= 3
491 (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option);
493 if ( IfMagickFalse(IsCommandOption(option)) ) {
494 if ( (process_flags & ProcessNonOptionImageRead) != 0 )
495 /* non-option -- treat as a image read */
496 CLISpecialOperator(cli_wand,"-read",option);
498 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
501 if ( ((process_flags & ProcessScriptOption) != 0) &&
502 (LocaleCompare(option,"-script") == 0) ) {
503 /* Call Script from CLI, with a filename as a zeroth argument.
504 NOTE: -script may need to use 'implict write filename' so it
505 must be handled here to prevent 'missing argument' error.
507 ProcessScriptOptions(cli_wand,argc,argv,i+1);
508 return(argc); /* Script does not return to CLI -- Yet -- FUTURE */
510 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
514 if ((i+count) >= end ) {
515 CLIWandException(OptionFatalError,"MissingArgument",option);
516 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
518 goto next_argument; /* no more arguments unable to proceed */
521 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL;
522 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL;
524 #if MagickCommandDebug >= 3
525 (void) FormatLocaleFile(stderr,
526 "CLI %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
527 i,option,count,option_type,arg1,arg2);
530 if ( (option_type & DeprecateOptionFlag) != 0 ) {
531 CLIWandException(OptionWarning,"DeprecatedOption",option);
532 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
534 /* fall through - do the depreciated option */
536 if ( (option_type & GenesisOptionFlag) != 0 ) {
537 goto next_argument; /* ignore genesis options */
539 if (((option_type & ImageRequiredFlags) != 0 ) &&
540 ( cli_wand->wand.images == (Image *)NULL ) ) {
541 CLIWandException(OptionError,"NoImagesFound",option);
545 if ( (option_type & SpecialOptionFlag) != 0 ) {
546 if ( ( process_flags & ProcessExitOption ) != 0
547 && LocaleCompare(option,"-exit") == 0 )
549 /* handle any other special operators now */
550 CLISpecialOperator(cli_wand,option,arg1);
553 if ( (option_type & SettingOptionFlags) != 0 ) {
554 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
555 // FUTURE: Sync individual Settings into images (no SyncImageSettings())
557 if ( cli_wand->wand.images != (Image *)NULL )
558 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
559 cli_wand->wand.exception);
561 if ( (option_type & SimpleOperatorOptionFlag) != 0)
562 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
564 if ( (option_type & ListOperatorOptionFlag) != 0 )
565 CLIListOperatorImages(cli_wand, option, arg1, arg2);
568 #if MagickCommandDebug >= 9
569 OutputOptions(cli_wand->wand.image_info);
570 if ( cli_wand->wand.images != (Image *)NULL ) {
571 OutputArtifacts(cli_wand->wand.images);
572 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
575 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
580 if ( ( process_flags & ProcessOutputFile ) == 0 )
586 Implicit Write of images to final CLI argument
591 #if MagickCommandDebug >= 3
592 (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option );
595 /* check that stacks are empty */
596 if (cli_wand->image_list_stack != (Stack *)NULL)
597 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
598 else if (cli_wand->image_info_stack != (Stack *)NULL)
599 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
600 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
603 /* This is a valid 'do no write' option - no images needed */
604 if (LocaleCompare(option,"-exit") == 0 )
605 return(argc); /* just exit, no image write */
607 /* If filename looks like an option -- produce an error */
608 if (IsCommandOption(option) != MagickFalse) {
609 CLIWandException(OptionError,"MissingOutputFilename",option);
613 CLISpecialOperator(cli_wand,"-write",option);
618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 + M a g i c k I m a g e C o m m a n d %
626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 % MagickImageCommand() Handle special use CLI arguments and prepare a
629 % CLI MagickCLI to process the command line or directly specified script.
631 % This is essentualy interface function between the MagickCore library
632 % initialization function MagickCommandGenesis(), and the option MagickCLI
633 % processing functions ProcessCommandOptions() or ProcessScriptOptions()
635 % The format of the MagickImageCommand method is:
637 % MagickBooleanType MagickImageCommand(ImageInfo *image_info,
638 % int argc, char **argv, char **metadata, ExceptionInfo *exception)
640 % A description of each parameter follows:
642 % o image_info: the starting image_info structure
643 % (for compatibilty with MagickCommandGenisis())
645 % o argc: the number of elements in the argument vector.
647 % o argv: A text array containing the command line arguments.
649 % o metadata: any metadata (for VBS) is returned here.
650 % (for compatibilty with MagickCommandGenisis())
652 % o exception: return any errors or warnings in this structure.
656 static void MagickUsage(MagickBooleanType verbose)
664 name=GetClientName();
667 if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
668 /* magick-script usage */
669 (void) FormatLocaleFile(stdout,
670 "Usage: %s {filename} [{script_args}...]\n",name);
672 else if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
674 (void) FormatLocaleFile(stdout,
675 "Usage: %s [{option}|{image}...] {output_image}\n",name);
676 (void) FormatLocaleFile(stdout,
677 " %s -help|-version|-usage|-list {option}\n",name);
681 (void) FormatLocaleFile(stdout,
682 "Usage: %s [{option}|{image}...] {output_image}\n",name);
683 (void) FormatLocaleFile(stdout,
684 " %s [{option}|{image}...] -script {filename} [{script_args}...]\n",
686 (void) FormatLocaleFile(stdout,
687 " %s -help|-version|-usage|-list {option}\n",name);
690 if (IfMagickFalse(verbose))
693 (void) FormatLocaleFile(stdout,"\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
694 "All options are performed in a strict 'as you see them' order\n",
695 "You must read-in images before you can operate on them.\n",
697 "Magick Script files can use any of the following forms...\n",
698 " #!/path/to/magick -script\n",
701 " :; exec magick -script \"$0\" \"$@\"; exit 10\n",
702 " # Magick script from here...\n",
704 " #!/usr/bin/env magick-script\n",
705 "The latter two forms do not require the path to the command hard coded.\n",
706 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
708 "For more information on usage, options, examples, and techniques\n",
709 "see the ImageMagick website at ", MagickAuthoritativeURL);
715 Concatanate given file arguments to the given output argument.
716 Used for a special -concatenate option used for specific 'delegates'.
717 The option is not formally documented.
719 magick -concatenate files... output
721 This is much like the UNIX "cat" command, but for both UNIX and Windows,
722 however the last argument provides the output filename.
724 static MagickBooleanType ConcatenateImages(int argc,char **argv,
725 ExceptionInfo *exception)
737 output=fopen_utf8(argv[argc-1],"wb");
738 if (output == (FILE *) NULL) {
739 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
743 for (i=2; i < (ssize_t) (argc-1); i++) {
744 input=fopen_utf8(argv[i],"rb");
745 if (input == (FILE *) NULL)
746 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
747 for (c=fgetc(input); c != EOF; c=fgetc(input))
748 (void) fputc((char) c,output);
749 (void) fclose(input);
750 (void) remove_utf8(argv[i]);
752 (void) fclose(output);
756 WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
757 int argc,char **argv,char **metadata,ExceptionInfo *exception)
769 process_flags = MagickCommandOptionFlags;
771 /* For specific OS command line requirements */
772 ReadCommandlLine(argc,&argv);
775 status=ExpandFilenames(&argc,&argv);
776 if ( IfMagickFalse(status) )
777 ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed",
778 GetExceptionMessage(errno));
781 /* Initialize special "CLI Wand" to hold images and settings (empty) */
782 cli_wand=AcquireMagickCLI(image_info,exception);
785 GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
786 SetClientName(cli_wand->wand.name);
787 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent);
789 len=strlen(argv[0]); /* precaution */
791 /* "convert" command - give a "depreciation" warning" */
792 if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
793 process_flags = ConvertCommandOptionFlags;
794 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n",
795 "The convert is depreciated in IMv7, use \"magick\"\n");*/
798 /* Special Case: If command name ends with "script" implied "-script" */
799 if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
800 if (argc >= 2 && *(argv[1]) != '-') {
801 GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
802 ProcessScriptOptions(cli_wand,argc,argv,1);
803 goto Magick_Command_Cleanup;
807 /* Special Case: Version Information and Abort */
810 if (LocaleCompare("-version",option) == 0) {
811 CLISpecialOperator(cli_wand, "-version", (char *)NULL);
812 goto Magick_Command_Exit;
814 if ((LocaleCompare("-help",option) == 0) || /* GNU standard option */
815 (LocaleCompare("--help",option) == 0) ) {
816 MagickUsage(MagickFalse);
817 goto Magick_Command_Exit;
819 if (LocaleCompare("-usage",option) == 0) {
820 CLISpecialOperator(cli_wand, "-version", (char *)NULL);
821 MagickUsage(MagickTrue);
822 goto Magick_Command_Exit;
826 /* not enough arguments -- including -help */
828 (void) FormatLocaleFile(stderr,
829 "Error: Invalid argument or not enough arguments\n\n");
830 MagickUsage(MagickFalse);
831 goto Magick_Command_Exit;
834 /* List Information and Abort */
835 if (LocaleCompare("-list",argv[1]) == 0) {
836 CLISpecialOperator(cli_wand, argv[1], argv[2]);
837 goto Magick_Command_Exit;
840 /* Special "concatenate option (hidden) for delegate usage */
841 if (LocaleCompare("-concatenate",argv[1]) == 0) {
842 ConcatenateImages(argc,argv,exception);
843 goto Magick_Command_Exit;
849 if (LocaleCompare("-script",argv[1]) == 0) {
850 /* Start processing directly from script, no pre-script options
851 Replace wand command name with script name
852 First argument in the argv array is the script name to read.
854 GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
855 ProcessScriptOptions(cli_wand,argc,argv,2);
858 /* Normal Command Line, assumes output file as last option */
859 ProcessCommandOptions(cli_wand,argc,argv,1, process_flags);
863 Magick_Command_Cleanup:
864 /* recover original image_info and clean up stacks */
865 while (cli_wand->image_list_stack != (Stack *)NULL)
866 CLISpecialOperator(cli_wand,")",(const char *)NULL);
867 while (cli_wand->image_info_stack != (Stack *)NULL)
868 CLISpecialOperator(cli_wand,"}",(const char *)NULL);
870 /* assert we have recovered the original structures */
871 assert(cli_wand->wand.image_info == image_info);
872 assert(cli_wand->wand.exception == exception);
874 /* Handle metadata for ImageMagickObject COM object for Windows VBS */
875 if (metadata != (char **) NULL) {
882 format="%w,%h,%m"; // Get this from image_info Option splaytree
884 text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
886 if (text == (char *) NULL)
887 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
888 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
890 (void) ConcatenateString(&(*metadata),text);
891 text=DestroyString(text);
896 /* Destroy the special CLI Wand */
897 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
898 cli_wand->wand.exception = (ExceptionInfo *)NULL;
899 cli_wand=DestroyMagickCLI(cli_wand);
901 return(IsMagickTrue(exception->severity > ErrorException));