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-2018 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 % https://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"
63 3 - show option details (better to use -debug Command now)
64 5 - image counts (after option runs)
66 #define MagickCommandDebug 0
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 + P r o c e s s S c r i p t O p t i o n s %
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 % ProcessScriptOptions() reads options and processes options as they are
81 % found in the given file, or pipeline. The filename to open and read
82 % options is given as the 'index' argument of the argument array given.
84 % Other arguments following index may be read by special script options
85 % as settings (strings), images, or as operations to be processed in various
86 % ways. How they are treated is up to the script being processed.
88 % Note that a script not 'return' to the command line processing, nor can
89 % they call (and return from) other scripts. At least not at this time.
91 % There are no 'ProcessOptionFlags' control flags at this time.
93 % The format of the ProcessScriptOptions method is:
95 % void ProcessScriptOptions(MagickCLI *cli_wand,const char *filename,
96 % int argc,char **argv,int index)
98 % A description of each parameter follows:
100 % o cli_wand: the main CLI Wand to use.
102 % o filename: the filename of script to process
104 % o argc: the number of elements in the argument vector. (optional)
106 % o argv: A text array containing the command line arguments. (optional)
108 % o index: offset of next argment in argv (script arguments) (optional)
111 WandExport void ProcessScriptOptions(MagickCLI *cli_wand,const char *filename,
112 int magick_unused(argc),char **magick_unused(argv),int magick_unused(index))
128 magick_unreferenced(argc);
129 magick_unreferenced(argv);
130 magick_unreferenced(index);
131 assert(filename != (char *) NULL ); /* at least one argument - script name */
132 assert(cli_wand != (MagickCLI *) NULL);
133 assert(cli_wand->signature == MagickWandSignature);
134 if (cli_wand->wand.debug != MagickFalse)
135 (void) LogMagickEvent(CommandEvent,GetMagickModule(),
136 "Processing script \"%s\"", filename);
138 /* open file script or stream, and set up tokenizer */
139 token_info = AcquireScriptTokenInfo(filename);
140 if (token_info == (ScriptTokenInfo *) NULL) {
141 CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",filename);
145 /* define the error location string for use in exceptions
146 order of localtion format escapes: filename, line, column */
147 cli_wand->location="in \"%s\" at line %u,column %u";
148 if ( LocaleCompare("-", filename) == 0 )
149 cli_wand->filename="stdin";
151 cli_wand->filename=filename;
153 /* Process Options from Script */
154 option = arg1 = arg2 = (char*) NULL;
155 DisableMSCWarning(4127)
159 { MagickBooleanType status = GetScriptToken(token_info);
160 cli_wand->line=token_info->token_line;
161 cli_wand->column=token_info->token_column;
162 if (status == MagickFalse)
163 break; /* error or end of options */
166 do { /* use break to loop to exception handler and loop */
168 /* save option details */
169 CloneString(&option,token_info->token);
171 /* get option, its argument count, and option type */
172 cli_wand->command = GetCommandOptionInfo(option);
173 count=cli_wand->command->type;
174 option_type=(CommandOptionFlags) cli_wand->command->flags;
176 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
177 cli_wand->line, cli_wand->line, option, cli_wand->command->mnemonic );
180 /* handle a undefined option - image read - always for "magick-script" */
181 if ( option_type == UndefinedOptionFlag ||
182 (option_type & NonMagickOptionFlag) != 0 ) {
183 #if MagickCommandDebug >= 3
184 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
185 cli_wand->line, cli_wand->line, option);
187 if (IsCommandOption(option) == MagickFalse) {
188 /* non-option -- treat as a image read */
189 cli_wand->command=(const OptionInfo *) NULL;
190 CLIOption(cli_wand,"-read",option);
191 break; /* next option */
193 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
194 break; /* next option */
198 if (GetScriptToken(token_info) == MagickFalse)
199 CLIWandException(OptionFatalError,"MissingArgument",option);
200 CloneString(&arg1,token_info->token);
203 CloneString(&arg1,(char *) NULL);
206 if (GetScriptToken(token_info) == MagickFalse)
207 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
208 CloneString(&arg2,token_info->token);
211 CloneString(&arg2,(char *) NULL);
216 #if MagickCommandDebug >= 3
217 (void) FormatLocaleFile(stderr,
218 "Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
219 cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
221 /* Hard Deprecated Options, no code to execute - error */
222 if ( (option_type & DeprecateOptionFlag) != 0 ) {
223 CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
224 break; /* next option */
227 /* MagickCommandGenesis() options have no place in a magick script */
228 if ( (option_type & GenesisOptionFlag) != 0 ) {
229 CLIWandException(OptionError,"InvalidUseOfOption",option);
230 break; /* next option */
233 /* handle any special 'script' options */
234 if ( (option_type & SpecialOptionFlag) != 0 ) {
235 if ( LocaleCompare(option,"-exit") == 0 ) {
236 goto loop_exit; /* break out of loop - return from script */
238 if ( LocaleCompare(option,"-script") == 0 ) {
239 /* FUTURE: call new script from this script - error for now */
240 CLIWandException(OptionError,"InvalidUseOfOption",option);
241 break; /* next option */
243 /* FUTURE: handle special script-argument options here */
244 /* handle any other special operators now */
245 CLIWandException(OptionError,"InvalidUseOfOption",option);
246 break; /* next option */
249 /* Process non-specific Option */
250 CLIOption(cli_wand, option, arg1, arg2);
251 (void) fflush(stdout);
252 (void) fflush(stderr);
254 DisableMSCWarning(4127)
255 } while (0); /* break block to next option */
258 #if MagickCommandDebug >= 5
259 fprintf(stderr, "Script Image Count = %ld\n",
260 GetImageListLength(cli_wand->wand.images) );
262 if (CLICatchException(cli_wand, MagickFalse) != MagickFalse)
263 break; /* exit loop */
267 Loop exit - check for some tokenization error
270 #if MagickCommandDebug >= 3
271 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
273 switch( token_info->status ) {
276 if (cli_wand->image_list_stack != (Stack *) NULL)
277 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
278 else if (cli_wand->image_info_stack != (Stack *) NULL)
279 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
281 case TokenStatusBadQuotes:
282 /* Ensure last token has a sane length for error report */
283 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
284 token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
285 token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
286 token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
287 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
289 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
292 case TokenStatusMemoryFailed:
293 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
295 case TokenStatusBinary:
296 CLIWandException(OptionFatalError,"ScriptIsBinary","");
299 (void) fflush(stdout);
300 (void) fflush(stderr);
301 if (cli_wand->wand.debug != MagickFalse)
302 (void) LogMagickEvent(CommandEvent,GetMagickModule(),
303 "Script End \"%s\"", filename);
306 token_info = DestroyScriptTokenInfo(token_info);
308 CloneString(&option,(char *) NULL);
309 CloneString(&arg1,(char *) NULL);
310 CloneString(&arg2,(char *) NULL);
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320 + P r o c e s s C o m m a n d O p t i o n s %
324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 % ProcessCommandOptions() reads and processes arguments in the given
327 % command line argument array. The 'index' defines where in the array we
328 % should begin processing
330 % The 'process_flags' can be used to control and limit option processing.
331 % For example, to only process one option, or how unknown and special options
332 % are to be handled, and if the last argument in array is to be regarded as a
333 % final image write argument (filename or special coder).
335 % The format of the ProcessCommandOptions method is:
337 % int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
340 % A description of each parameter follows:
342 % o cli_wand: the main CLI Wand to use.
344 % o argc: the number of elements in the argument vector.
346 % o argv: A text array containing the command line arguments.
348 % o process_flags: What type of arguments will be processed, ignored
351 % o index: index in the argv array to start processing from
353 % The function returns the index ot the next option to be processed. This
354 % is really only releven if process_flags contains a ProcessOneOptionOnly
358 WandExport int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
374 assert(argc>=index); /* you may have no arguments left! */
375 assert(argv != (char **) NULL);
376 assert(argv[index] != (char *) NULL);
377 assert(argv[argc-1] != (char *) NULL);
378 assert(cli_wand != (MagickCLI *) NULL);
379 assert(cli_wand->signature == MagickWandSignature);
381 /* define the error location string for use in exceptions
382 order of localtion format escapes: filename, line, column */
383 cli_wand->location="at %s arg %u";
384 cli_wand->filename="CLI";
385 cli_wand->line=index; /* note first argument we will process */
387 if (cli_wand->wand.debug != MagickFalse)
388 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
389 "- Starting (\"%s\")", argv[index]);
392 if ( (cli_wand->process_flags & ProcessImplictWrite) != 0 )
393 end--; /* the last arument is an implied write, do not process directly */
395 for (i=index; i < end; i += count +1) {
396 /* Finished processing one option? */
397 if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index )
400 do { /* use break to loop to exception handler and loop */
403 cli_wand->line=i; /* note the argument for this option */
405 /* get option, its argument count, and option type */
406 cli_wand->command = GetCommandOptionInfo(argv[i]);
407 count=cli_wand->command->type;
408 option_type=(CommandOptionFlags) cli_wand->command->flags;
410 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
411 i, argv[i], cli_wand->command->mnemonic );
414 if ( option_type == UndefinedOptionFlag ||
415 (option_type & NonMagickOptionFlag) != 0 ) {
416 #if MagickCommandDebug >= 3
417 (void) FormatLocaleFile(stderr, "CLI arg %d Non-Option: \"%s\"\n",
420 if (IsCommandOption(option) == MagickFalse) {
421 if ( (cli_wand->process_flags & ProcessImplictRead) != 0 ) {
422 /* non-option -- treat as a image read */
423 cli_wand->command=(const OptionInfo *) NULL;
424 CLIOption(cli_wand,"-read",option);
425 break; /* next option */
428 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
429 break; /* next option */
432 if ( ((option_type & SpecialOptionFlag) != 0 ) &&
433 ((cli_wand->process_flags & ProcessScriptOption) != 0) &&
434 (LocaleCompare(option,"-script") == 0) ) {
435 /* Call Script from CLI, with a filename as a zeroth argument.
436 NOTE: -script may need to use the 'implict write filename' argument
437 so it must be handled specially to prevent a 'missing argument' error.
439 if ( (i+count) >= argc )
440 CLIWandException(OptionFatalError,"MissingArgument",option);
441 ProcessScriptOptions(cli_wand,argv[i+1],argc,argv,i+count);
442 return(argc); /* Script does not return to CLI -- Yet */
443 /* FUTURE: when it does, their may be no write arg! */
446 if ((i+count) >= end ) {
447 CLIWandException(OptionFatalError,"MissingArgument",option);
448 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
450 break; /* next option - not that their is any! */
453 arg1 = ( count >= 1 ) ? argv[i+1] : (char *) NULL;
454 arg2 = ( count >= 2 ) ? argv[i+2] : (char *) NULL;
457 Process Known Options
459 #if MagickCommandDebug >= 3
460 (void) FormatLocaleFile(stderr,
461 "CLI arg %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
462 i,option,count,option_type,arg1,arg2);
464 /* ignore 'genesis options' in command line args */
465 if ( (option_type & GenesisOptionFlag) != 0 )
466 break; /* next option */
468 /* Handle any special options for CLI (-script handled above) */
469 if ( (option_type & SpecialOptionFlag) != 0 ) {
470 if ( (cli_wand->process_flags & ProcessExitOption) != 0
471 && LocaleCompare(option,"-exit") == 0 )
473 break; /* next option */
476 /* Process standard image option */
477 CLIOption(cli_wand, option, arg1, arg2);
479 DisableMSCWarning(4127)
480 } while (0); /* break block to next option */
483 #if MagickCommandDebug >= 5
484 (void) FormatLocaleFile(stderr, "CLI-post Image Count = %ld\n",
485 (long) GetImageListLength(cli_wand->wand.images) );
487 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
492 if ( (cli_wand->process_flags & ProcessImplictWrite) == 0 )
493 return(end); /* no implied write -- just return to caller */
495 assert(end==argc-1); /* end should not include last argument */
498 Implicit Write of images to final CLI argument
503 /* check that stacks are empty - or cause exception */
504 if (cli_wand->image_list_stack != (Stack *) NULL)
505 CLIWandException(OptionError,"UnbalancedParenthesis", "(end of cli)");
506 else if (cli_wand->image_info_stack != (Stack *) NULL)
507 CLIWandException(OptionError,"UnbalancedBraces", "(end of cli)");
508 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
511 #if MagickCommandDebug >= 3
512 (void) FormatLocaleFile(stderr,"CLI arg %d Write File: \"%s\"\n",i,option);
515 /* Valid 'do no write' replacement option (instead of "null:") */
516 if (LocaleCompare(option,"-exit") == 0 )
517 return(argc); /* just exit, no image write */
519 /* If filename looks like an option,
520 Or the common 'end of line' error of a single space.
521 -- produce an error */
522 if (IsCommandOption(option) != MagickFalse ||
523 (option[0] == ' ' && option[1] == '\0') ) {
524 CLIWandException(OptionError,"MissingOutputFilename",option);
528 cli_wand->command=(const OptionInfo *) NULL;
529 CLIOption(cli_wand,"-write",option);
534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538 + M a g i c k I m a g e C o m m a n d %
542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
544 % MagickImageCommand() Handle special use CLI arguments and prepare a
545 % CLI MagickCLI to process the command line or directly specified script.
547 % This is essentualy interface function between the MagickCore library
548 % initialization function MagickCommandGenesis(), and the option MagickCLI
549 % processing functions ProcessCommandOptions() or ProcessScriptOptions()
551 % The format of the MagickImageCommand method is:
553 % MagickBooleanType MagickImageCommand(ImageInfo *image_info,int argc,
554 % char **argv,char **metadata,ExceptionInfo *exception)
556 % A description of each parameter follows:
558 % o image_info: the starting image_info structure
559 % (for compatibilty with MagickCommandGenisis())
561 % o argc: the number of elements in the argument vector.
563 % o argv: A text array containing the command line arguments.
565 % o metadata: any metadata (for VBS) is returned here.
566 % (for compatibilty with MagickCommandGenisis())
568 % o exception: return any errors or warnings in this structure.
572 static void MagickUsage(MagickBooleanType verbose)
580 name=GetClientName();
583 if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
585 (void) FormatLocaleFile(stdout,
586 "Usage: %s [ {option} | {image} ... ] {output_image}\n",name);
587 (void) FormatLocaleFile(stdout,
588 " %s -help | -version | -usage | -list {option}\n\n",name);
591 else if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
592 /* magick-script usage */
593 (void) FormatLocaleFile(stdout,
594 "Usage: %s {filename} [ {script_args} ... ]\n",name);
598 (void) FormatLocaleFile(stdout,
599 "Usage: %s tool [ {option} | {image} ... ] {output_image}\n",name);
600 (void) FormatLocaleFile(stdout,
601 "Usage: %s [ {option} | {image} ... ] {output_image}\n",name);
602 (void) FormatLocaleFile(stdout,
603 " %s [ {option} | {image} ... ] -script {filename} [ {script_args} ...]\n",
606 (void) FormatLocaleFile(stdout,
607 " %s -help | -version | -usage | -list {option}\n\n",name);
609 if (verbose == MagickFalse)
612 (void) FormatLocaleFile(stdout,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
613 "All options are performed in a strict 'as you see them' order\n",
614 "You must read-in images before you can operate on them.\n",
616 "Magick Script files can use any of the following forms...\n",
617 " #!/path/to/magick -script\n",
620 " :; exec magick -script \"$0\" \"$@\"; exit 10\n",
621 " # Magick script from here...\n",
623 " #!/usr/bin/env magick-script\n",
624 "The latter two forms do not require the path to the command hard coded.\n",
625 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
627 "For more information on usage, options, examples, and techniques\n",
628 "see the ImageMagick website at ", MagickAuthoritativeURL);
634 Concatanate given file arguments to the given output argument.
635 Used for a special -concatenate option used for specific 'delegates'.
636 The option is not formally documented.
638 magick -concatenate files... output
640 This is much like the UNIX "cat" command, but for both UNIX and Windows,
641 however the last argument provides the output filename.
643 static MagickBooleanType ConcatenateImages(int argc,char **argv,
644 ExceptionInfo *exception )
659 if (ExpandFilenames(&argc,&argv) == MagickFalse)
660 ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
661 GetExceptionMessage(errno));
662 output=fopen_utf8(argv[argc-1],"wb");
663 if (output == (FILE *) NULL)
665 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
670 for (i=2; i < (ssize_t) (argc-1); i++)
672 input=fopen_utf8(argv[i],"rb");
673 if (input == (FILE *) NULL)
675 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
678 for (c=fgetc(input); c != EOF; c=fgetc(input))
679 if (fputc((char) c,output) != c)
681 (void) fclose(input);
682 (void) remove_utf8(argv[i]);
684 (void) fclose(output);
688 WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,int argc,
689 char **argv,char **metadata,ExceptionInfo *exception)
697 assert(image_info != (ImageInfo *) NULL);
699 /* For specific OS command line requirements */
700 ReadCommandlLine(argc,&argv);
702 /* Initialize special "CLI Wand" to hold images and settings (empty) */
703 cli_wand=AcquireMagickCLI(image_info,exception);
704 cli_wand->location="Initializing";
705 cli_wand->filename=argv[0];
708 if (cli_wand->wand.debug != MagickFalse)
709 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
713 GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
714 SetClientName(cli_wand->wand.name);
715 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MagickPathExtent);
717 len=strlen(argv[0]); /* precaution */
719 /* "convert" command - give a "deprecated" warning" */
720 if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
721 cli_wand->process_flags = ConvertCommandOptionFlags;
722 (void) FormatLocaleFile(stderr,"WARNING: %s\n",
723 "The convert command is deprecated in IMv7, use \"magick\"\n");
726 /* Special Case: If command name ends with "script" implied "-script" */
727 if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
728 if (argc >= 2 && ( (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) {
729 GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
730 ProcessScriptOptions(cli_wand,argv[1],argc,argv,2);
731 goto Magick_Command_Cleanup;
735 /* Special Case: Version Information and Abort */
737 if ((LocaleCompare("-version",argv[1]) == 0) || /* GNU standard option */
738 (LocaleCompare("--version",argv[1]) == 0) ) { /* just version */
739 CLIOption(cli_wand, "-version");
740 goto Magick_Command_Exit;
742 if ((LocaleCompare("-help",argv[1]) == 0) || /* GNU standard option */
743 (LocaleCompare("--help",argv[1]) == 0) ) { /* just a brief summary */
744 if (cli_wand->wand.debug != MagickFalse)
745 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
746 "- Special Option \"%s\"", argv[1]);
747 MagickUsage(MagickFalse);
748 goto Magick_Command_Exit;
750 if (LocaleCompare("-usage",argv[1]) == 0) { /* both version & usage */
751 if (cli_wand->wand.debug != MagickFalse)
752 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
753 "- Special Option \"%s\"", argv[1]);
754 CLIOption(cli_wand, "-version" );
755 MagickUsage(MagickTrue);
756 goto Magick_Command_Exit;
760 /* not enough arguments -- including -help */
762 (void) FormatLocaleFile(stderr,
763 "Error: Invalid argument or not enough arguments\n\n");
764 MagickUsage(MagickFalse);
765 goto Magick_Command_Exit;
768 /* Special "concatenate option (hidden) for delegate usage */
769 if (LocaleCompare("-concatenate",argv[1]) == 0) {
770 if (cli_wand->wand.debug != MagickFalse)
771 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
772 "- Special Option \"%s\"", argv[1]);
773 ConcatenateImages(argc,argv,exception);
774 goto Magick_Command_Exit;
777 /* List Information and Abort */
778 if (argc == 3 && LocaleCompare("-list",argv[1]) == 0) {
779 CLIOption(cli_wand, argv[1], argv[2]);
780 goto Magick_Command_Exit;
786 if (LocaleCompare("-script",argv[1]) == 0) {
787 /* Start processing directly from script, no pre-script options
788 Replace wand command name with script name
789 First argument in the argv array is the script name to read.
791 GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
792 ProcessScriptOptions(cli_wand,argv[2],argc,argv,3);
795 /* Normal Command Line, assumes output file as last option */
796 ProcessCommandOptions(cli_wand,argc,argv,1);
800 Magick_Command_Cleanup:
801 cli_wand->location="Cleanup";
802 cli_wand->filename=argv[0];
803 if (cli_wand->wand.debug != MagickFalse)
804 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
807 /* recover original image_info and clean up stacks
808 FUTURE: "-reset stacks" option */
809 while ((cli_wand->image_list_stack != (Stack *) NULL) &&
810 (cli_wand->image_list_stack->next != (Stack *) NULL))
811 CLIOption(cli_wand,")");
812 while ((cli_wand->image_info_stack != (Stack *) NULL) &&
813 (cli_wand->image_info_stack->next != (Stack *) NULL))
814 CLIOption(cli_wand,"}");
816 /* assert we have recovered the original structures */
817 assert(cli_wand->wand.image_info == image_info);
818 assert(cli_wand->wand.exception == exception);
820 /* Handle metadata for ImageMagickObject COM object for Windows VBS */
821 if ((cli_wand->wand.images != (Image *) NULL) &&
822 (metadata != (char **) NULL))
830 format="%w,%h,%m"; /* Get this from image_info Option splaytree */
831 text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
833 if (text == (char *) NULL)
834 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
835 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
838 (void) ConcatenateString(&(*metadata),text);
839 text=DestroyString(text);
844 cli_wand->location="Exiting";
845 cli_wand->filename=argv[0];
846 if (cli_wand->wand.debug != MagickFalse)
847 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
850 /* Destroy the special CLI Wand */
851 cli_wand->wand.image_info = (ImageInfo *) NULL; /* not these */
852 cli_wand->wand.exception = (ExceptionInfo *) NULL;
853 cli_wand=DestroyMagickCLI(cli_wand);
855 return(exception->severity < ErrorException ? MagickTrue : MagickFalse);