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-2013 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/exception-private.h"
59 #include "MagickCore/version.h"
62 3 - option type details
63 5 - include image counts
65 #define MagickCommandDebug 0
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 + P r o c e s s S c r i p t O p t i o n s %
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 % ProcessScriptOptions() reads options and processes options as they are
80 % found in the given file, or pipeline. The filename to open and read
81 % options is given as the 'index' argument of the argument array given.
83 % Other arguments following index may be read by special script options
84 % as settings (strings), images, or as operations to be processed in various
85 % ways. How they are treated is up to the script being processed.
87 % Note that a script not 'return' to the command line processing, nor can
88 % they call (and return from) other scripts. At least not at this time.
90 % There are no 'ProcessOptionFlags' control flags at this time.
92 % The format of the ProcessScriptOptions method is:
94 % void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
97 % A description of each parameter follows:
99 % o cli_wand: the main CLI Wand to use.
101 % o argc: the number of elements in the argument vector.
103 % o argv: A text array containing the command line arguments.
105 % o index: offset for argc to CLI argumnet count
108 WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
125 assert(argc>index); /* at least one argument - script name */
126 assert(argv != (char **)NULL);
127 assert(argv[index] != (char *)NULL);
128 assert(argv[argc-1] != (char *)NULL);
129 assert(cli_wand != (MagickCLI *) NULL);
130 assert(cli_wand->signature == WandSignature);
131 if (cli_wand->wand.debug != MagickFalse)
132 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
134 /* open file script or stream, and set up tokenizer */
135 token_info = AcquireScriptTokenInfo(argv[index]);
136 if (token_info == (ScriptTokenInfo *) NULL) {
137 CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",argv[index]);
141 /* define the error location string for use in exceptions
142 order of localtion format escapes: filename, line, column */
143 cli_wand->location="in \"%s\" at line %u,column %u";
144 if ( LocaleCompare("-", argv[index]) == 0 )
145 cli_wand->filename="stdin";
147 cli_wand->filename=argv[index];
149 /* Process Options from Script */
150 option = arg1 = arg2 = (char*)NULL;
153 { MagickBooleanType status = GetScriptToken(token_info);
154 cli_wand->line=token_info->token_line;
155 cli_wand->column=token_info->token_column;
156 if( IfMagickFalse(status) )
157 break; /* error or end of options */
160 do { /* use break to loop to exception handler and loop */
162 /* save option details */
163 CloneString(&option,token_info->token);
165 /* get option, its argument count, and option type */
166 cli_wand->command = GetCommandOptionInfo(option);
167 count=cli_wand->command->type;
168 option_type=(CommandOptionFlags) cli_wand->command->flags;
170 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
171 cli_wand->line, cli_wand->line, option, cli_wand->command->mnemonic );
174 /* handle a undefined option - image read - always for "magick-script" */
175 if ( option_type == UndefinedOptionFlag ||
176 (option_type & NonMagickOptionFlag) != 0 ) {
177 #if MagickCommandDebug >= 3
178 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
179 cli_wand->line, cli_wand->line, option);
181 if ( IfMagickFalse(IsCommandOption(option))) {
182 /* non-option -- treat as a image read */
183 cli_wand->command=(const OptionInfo *)NULL;
184 CLIOption(cli_wand,"-read",option);
185 break; /* next option */
187 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
188 break; /* next option */
192 if( IfMagickFalse(GetScriptToken(token_info)) )
193 CLIWandException(OptionFatalError,"MissingArgument",option);
194 CloneString(&arg1,token_info->token);
197 CloneString(&arg1,(char *)NULL);
200 if( IfMagickFalse(GetScriptToken(token_info)) )
201 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
202 CloneString(&arg2,token_info->token);
205 CloneString(&arg2,(char *)NULL);
210 #if MagickCommandDebug >= 3
211 (void) FormatLocaleFile(stderr,
212 "Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
213 cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
215 /* Hard Depreciated Options, no code to execute - error */
216 if ( (option_type & DeprecateOptionFlag) != 0 ) {
217 CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
218 break; /* next option */
221 /* MagickCommandGenesis() options have no place in a magick script */
222 if ( (option_type & GenesisOptionFlag) != 0 ) {
223 CLIWandException(OptionError,"InvalidUseOfOption",option);
224 break; /* next option */
227 /* handle any special 'script' options */
228 if ( (option_type & SpecialOptionFlag) != 0 ) {
229 if ( LocaleCompare(option,"-exit") == 0 ) {
230 goto loop_exit; /* break out of loop - return from script */
232 if ( LocaleCompare(option,"-script") == 0 ) {
233 /* FUTURE: call new script from this script - error for now */
234 CLIWandException(OptionError,"InvalidUseOfOption",option);
235 break; /* next option */
237 /* FUTURE: handle special script-argument options here */
238 /* handle any other special operators now */
239 CLIWandException(OptionError,"InvalidUseOfOption",option);
240 break; /* next option */
243 /* Process non-specific Option */
244 CLIOption(cli_wand, option, arg1, arg2);
246 } while (0); /* break block to next option */
248 #if MagickCommandDebug >= 5
249 fprintf(stderr, "Script Image Count = %ld\n",
250 GetImageListLength(cli_wand->wand.images) );
252 if ( IfMagickTrue(CLICatchException(cli_wand, MagickFalse)) )
253 break; /* exit loop */
257 Loop exit - check for some tokenization error
260 #if MagickCommandDebug >= 3
261 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
263 switch( token_info->status ) {
266 if (cli_wand->image_list_stack != (Stack *)NULL)
267 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
268 else if (cli_wand->image_info_stack != (Stack *)NULL)
269 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
271 case TokenStatusBadQuotes:
272 /* Ensure last token has a sane length for error report */
273 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
274 token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
275 token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
276 token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
277 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
279 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
282 case TokenStatusMemoryFailed:
283 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
285 case TokenStatusBinary:
286 CLIWandException(OptionFatalError,"ScriptIsBinary","");
291 token_info = DestroyScriptTokenInfo(token_info);
293 CloneString(&option,(char *)NULL);
294 CloneString(&arg1,(char *)NULL);
295 CloneString(&arg2,(char *)NULL);
301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305 + P r o c e s s C o m m a n d O p t i o n s %
309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311 % ProcessCommandOptions() reads and processes arguments in the given
312 % command line argument array. The array does not contain the command
313 % being processed, only the options.
315 % The 'process_flags' can be used to control and limit option processing.
316 % For example, to only process one option, or how unknown and special options
317 % are to be handled, and if the last argument in array is to be regarded as a
318 % final image write argument (filename or special coder).
320 % The format of the ProcessCommandOptions method is:
322 % int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
323 % int index, ProcessOptionFlags process_flags )
325 % A description of each parameter follows:
327 % o cli_wand: the main CLI Wand to use.
329 % o argc: the number of elements in the argument vector.
331 % o argv: A text array containing the command line arguments.
333 % o process_flags: What type of arguments will be processed, ignored
336 % o index: index in the argv array to start processing from
338 % The function returns the index ot the next option to be processed. This
339 % is really only releven if process_flags contains a ProcessOneOptionOnly
343 WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc,
344 char **argv, int index )
359 assert(argc>=index); /* you may have no arguments left! */
360 assert(argv != (char **)NULL);
361 assert(argv[index] != (char *)NULL);
362 assert(argv[argc-1] != (char *)NULL);
363 assert(cli_wand != (MagickCLI *) NULL);
364 assert(cli_wand->signature == WandSignature);
365 if (cli_wand->wand.debug != MagickFalse)
366 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
368 /* define the error location string for use in exceptions
369 order of localtion format escapes: filename, line, column */
370 cli_wand->location="at %s argument %u";
371 cli_wand->filename="CLI";
374 if ( (cli_wand->process_flags & ProcessImplictWrite) != 0 )
375 end--; /* the last arument is an implied write, do not process directly */
377 for (i=index; i < end; i += count +1) {
378 /* Finished processing one option? */
379 if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index )
382 do { /* use break to loop to exception handler and loop */
385 cli_wand->line=i; /* note the argument for this option */
387 /* get option, its argument count, and option type */
388 cli_wand->command = GetCommandOptionInfo(argv[i]);
389 count=cli_wand->command->type;
390 option_type=(CommandOptionFlags) cli_wand->command->flags;
392 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
393 i, argv[i], cli_wand->command->mnemonic );
396 if ( option_type == UndefinedOptionFlag ||
397 (option_type & NonMagickOptionFlag) != 0 ) {
398 #if MagickCommandDebug >= 3
399 (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option);
401 if ( IfMagickFalse(IsCommandOption(option)) ) {
402 if ( (cli_wand->process_flags & ProcessImplictRead) != 0 ) {
403 /* non-option -- treat as a image read */
404 cli_wand->command=(const OptionInfo *)NULL;
405 CLIOption(cli_wand,"-read",option);
406 break; /* next option */
409 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
410 break; /* next option */
413 if ( ((option_type & SpecialOptionFlag) != 0 ) &&
414 ((cli_wand->process_flags & ProcessScriptOption) != 0) &&
415 (LocaleCompare(option,"-script") == 0) ) {
416 /* Call Script from CLI, with a filename as a zeroth argument.
417 NOTE: -script may need to use the 'implict write filename' argument
418 so it must be handled specially to prevent a 'missing argument' error.
420 if ( (i+count) >= argc )
421 CLIWandException(OptionFatalError,"MissingArgument",option);
422 ProcessScriptOptions(cli_wand,argc,argv,i+1);
423 return(argc); /* Script does not return to CLI -- Yet */
424 /* FUTURE: when it does, their may be no write arg! */
427 if ((i+count) >= end ) {
428 CLIWandException(OptionFatalError,"MissingArgument",option);
429 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
431 break; /* next option - not that their is any! */
434 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL;
435 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL;
438 Process Known Options
440 #if MagickCommandDebug >= 3
441 (void) FormatLocaleFile(stderr,
442 "CLI %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
443 i,option,count,option_type,arg1,arg2);
446 /* ignore 'genesis options' in command line args */
447 if ( (option_type & GenesisOptionFlag) != 0 )
448 break; /* next option */
450 /* Handle any special options for CLI (-script handled above) */
451 if ( (option_type & SpecialOptionFlag) != 0 ) {
452 if ( (cli_wand->process_flags & ProcessExitOption) != 0
453 && LocaleCompare(option,"-exit") == 0 )
455 break; /* next option */
458 /* Process standard image option */
459 CLIOption(cli_wand, option, arg1, arg2);
461 } while (0); /* break block to next option */
463 #if MagickCommandDebug >= 5
464 fprintf(stderr, "CLI Image Count = %ld\n",
465 GetImageListLength(cli_wand->wand.images) );
467 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
472 if ( (cli_wand->process_flags & ProcessImplictWrite) == 0 )
473 return(end); /* no implied write -- just return to caller */
475 assert(end==argc-1); /* end should not include last argument */
478 Implicit Write of images to final CLI argument
483 /* check that stacks are empty - or cause exception */
484 if (cli_wand->image_list_stack != (Stack *)NULL)
485 CLIWandException(OptionError,"UnbalancedParenthesis", "(end of cli)");
486 else if (cli_wand->image_info_stack != (Stack *)NULL)
487 CLIWandException(OptionError,"UnbalancedBraces", "(end of cli)");
488 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
491 #if MagickCommandDebug >= 3
492 (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option );
495 /* Valid 'do no write' replacement option (instead of "null:") */
496 if (LocaleCompare(option,"-exit") == 0 )
497 return(argc); /* just exit, no image write */
499 /* If filename looks like an option,
500 Or the common 'end of line' error of a single space.
501 -- produce an error */
502 if (IfMagickTrue(IsCommandOption(option)) ||
503 (option[0] == ' ' && option[1] == '\0') ) {
504 CLIWandException(OptionError,"MissingOutputFilename",option);
508 cli_wand->command=(const OptionInfo *)NULL;
509 CLIOption(cli_wand,"-write",option);
514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 + M a g i c k I m a g e C o m m a n d %
522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524 % MagickImageCommand() Handle special use CLI arguments and prepare a
525 % CLI MagickCLI to process the command line or directly specified script.
527 % This is essentualy interface function between the MagickCore library
528 % initialization function MagickCommandGenesis(), and the option MagickCLI
529 % processing functions ProcessCommandOptions() or ProcessScriptOptions()
531 % The format of the MagickImageCommand method is:
533 % MagickBooleanType MagickImageCommand(ImageInfo *image_info,
534 % int argc, char **argv, char **metadata, ExceptionInfo *exception)
536 % A description of each parameter follows:
538 % o image_info: the starting image_info structure
539 % (for compatibilty with MagickCommandGenisis())
541 % o argc: the number of elements in the argument vector.
543 % o argv: A text array containing the command line arguments.
545 % o metadata: any metadata (for VBS) is returned here.
546 % (for compatibilty with MagickCommandGenisis())
548 % o exception: return any errors or warnings in this structure.
552 static void MagickUsage(MagickBooleanType verbose)
560 name=GetClientName();
563 if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
565 (void) FormatLocaleFile(stdout,
566 "Usage: %s [{option}|{image}...] {output_image}\n",name);
567 (void) FormatLocaleFile(stdout,
568 " %s -help|-version|-usage|-list {option}\n\n",name);
571 else if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
572 /* magick-script usage */
573 (void) FormatLocaleFile(stdout,
574 "Usage: %s {filename} [{script_args}...]\n",name);
578 (void) FormatLocaleFile(stdout,
579 "Usage: %s [{option}|{image}...] {output_image}\n",name);
580 (void) FormatLocaleFile(stdout,
581 " %s [{option}|{image}...] -script {filename} [{script_args}...]\n",
584 (void) FormatLocaleFile(stdout,
585 " %s -help|-version|-usage|-list {option}\n\n",name);
587 if (IfMagickFalse(verbose))
590 (void) FormatLocaleFile(stdout,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
591 "All options are performed in a strict 'as you see them' order\n",
592 "You must read-in images before you can operate on them.\n",
594 "Magick Script files can use any of the following forms...\n",
595 " #!/path/to/magick -script\n",
598 " :; exec magick -script \"$0\" \"$@\"; exit 10\n",
599 " # Magick script from here...\n",
601 " #!/usr/bin/env magick-script\n",
602 "The latter two forms do not require the path to the command hard coded.\n",
603 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
605 "For more information on usage, options, examples, and techniques\n",
606 "see the ImageMagick website at ", MagickAuthoritativeURL);
612 Concatanate given file arguments to the given output argument.
613 Used for a special -concatenate option used for specific 'delegates'.
614 The option is not formally documented.
616 magick -concatenate files... output
618 This is much like the UNIX "cat" command, but for both UNIX and Windows,
619 however the last argument provides the output filename.
621 static MagickBooleanType ConcatenateImages(int argc,char **argv,
622 ExceptionInfo *exception )
634 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
635 ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
636 GetExceptionMessage(errno));
638 output=fopen_utf8(argv[argc-1],"wb");
639 if (output == (FILE *) NULL) {
640 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[argc-1]);
643 for (i=2; i < (ssize_t) (argc-1); i++) {
645 fprintf(stderr, "DEBUG: Concatenate Image: \"%s\"\n", argv[i]);
647 input=fopen_utf8(argv[i],"rb");
648 if (input == (FILE *) NULL) {
649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
652 for (c=fgetc(input); c != EOF; c=fgetc(input))
653 (void) fputc((char) c,output);
654 (void) fclose(input);
655 (void) remove_utf8(argv[i]);
657 (void) fclose(output);
661 WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
662 int argc,char **argv,char **metadata,ExceptionInfo *exception)
670 /* For specific OS command line requirements */
671 ReadCommandlLine(argc,&argv);
673 /* Initialize special "CLI Wand" to hold images and settings (empty) */
674 cli_wand=AcquireMagickCLI(image_info,exception);
677 GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
678 SetClientName(cli_wand->wand.name);
679 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent);
681 len=strlen(argv[0]); /* precaution */
683 /* "convert" command - give a "depreciation" warning" */
684 if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
685 cli_wand->process_flags = ConvertCommandOptionFlags;
686 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n",
687 "The convert is depreciated in IMv7, use \"magick\"\n");*/
690 /* Special Case: If command name ends with "script" implied "-script" */
691 if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
692 if (argc >= 2 && ( (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) {
693 GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
694 ProcessScriptOptions(cli_wand,argc,argv,1);
695 goto Magick_Command_Cleanup;
699 /* Special Case: Version Information and Abort */
701 if (LocaleCompare("-version",argv[1]) == 0) { /* just version */
702 CLIOption(cli_wand, "-version");
703 goto Magick_Command_Exit;
705 if ((LocaleCompare("-help",argv[1]) == 0) || /* GNU standard option */
706 (LocaleCompare("--help",argv[1]) == 0) ) { /* just a brief summary */
707 MagickUsage(MagickFalse);
708 goto Magick_Command_Exit;
710 if (LocaleCompare("-usage",argv[1]) == 0) { /* both version & usage */
711 CLIOption(cli_wand, "-version" );
712 MagickUsage(MagickTrue);
713 goto Magick_Command_Exit;
717 /* not enough arguments -- including -help */
719 (void) FormatLocaleFile(stderr,
720 "Error: Invalid argument or not enough arguments\n\n");
721 MagickUsage(MagickFalse);
722 goto Magick_Command_Exit;
725 /* Special "concatenate option (hidden) for delegate usage */
726 if (LocaleCompare("-concatenate",argv[1]) == 0) {
727 ConcatenateImages(argc,argv,exception);
728 goto Magick_Command_Exit;
731 /* List Information and Abort */
732 if (argc == 3 && LocaleCompare("-list",argv[1]) == 0) {
733 CLIOption(cli_wand, argv[1], argv[2]);
734 goto Magick_Command_Exit;
740 if (LocaleCompare("-script",argv[1]) == 0) {
741 /* Start processing directly from script, no pre-script options
742 Replace wand command name with script name
743 First argument in the argv array is the script name to read.
745 GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
746 ProcessScriptOptions(cli_wand,argc,argv,2);
749 /* Normal Command Line, assumes output file as last option */
750 ProcessCommandOptions(cli_wand,argc,argv,1);
754 Magick_Command_Cleanup:
755 /* recover original image_info and clean up stacks
756 FUTURE: "-reset stacks" option */
757 while (cli_wand->image_list_stack != (Stack *)NULL)
758 CLIOption(cli_wand,")");
759 while (cli_wand->image_info_stack != (Stack *)NULL)
760 CLIOption(cli_wand,"}");
762 /* assert we have recovered the original structures */
763 assert(cli_wand->wand.image_info == image_info);
764 assert(cli_wand->wand.exception == exception);
766 /* Handle metadata for ImageMagickObject COM object for Windows VBS */
767 if (metadata != (char **) NULL) {
774 format="%w,%h,%m"; // Get this from image_info Option splaytree
776 text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
778 if (text == (char *) NULL)
779 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
780 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
782 (void) ConcatenateString(&(*metadata),text);
783 text=DestroyString(text);
788 /* Destroy the special CLI Wand */
789 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
790 cli_wand->wand.exception = (ExceptionInfo *)NULL;
791 cli_wand=DestroyMagickCLI(cli_wand);
793 return(IsMagickTrue(exception->severity > ErrorException));