magick-cli.c revision 24aa882bb8f0a8555253f77fc9ad8cb12fcb8c05
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 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 % 11% % 12% CCCC L IIIII % 13% C L I % 14% C L I % 15% C L I % 16% CCCC LLLLL IIIII % 17% % 18% Perform "Magick" on Images via the Command Line Interface % 19% % 20% Dragon Computing % 21% Anthony Thyssen % 22% January 2012 % 23% % 24% % 25% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 26% dedicated to making software imaging solutions freely available. % 27% % 28% You may not use this file except in compliance with the License. You may % 29% obtain a copy of the License at % 30% % 31% http://www.imagemagick.org/script/license.php % 32% % 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. % 38% % 39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40% 41% Read CLI arguments, script files, and pipelines, to provide options that 42% manipulate images from many different formats. 43% 44*/ 45 46/* 47 Include declarations. 48*/ 49#include "MagickWand/studio.h" 50#include "MagickWand/MagickWand.h" 51#include "MagickWand/magick-wand-private.h" 52#include "MagickWand/operation.h" 53#include "MagickWand/operation-private.h" 54#include "MagickWand/magick-cli.h" 55#include "MagickWand/script-token.h" 56#include "MagickCore/utility-private.h" 57#include "MagickCore/version.h" 58 59/* verbose debugging, 60 1 - option type 61 2 - source of option 62 3 - mnemonic lookup 63 4 - output options/artifacts 64*/ 65#define MagickCommandDebug 0 66 67#define ThrowFileException(exception,severity,tag,context) \ 68{ \ 69 char \ 70 *message; \ 71 \ 72 message=GetExceptionMessage(errno); \ 73 (void) ThrowMagickException(exception,GetMagickModule(),severity, \ 74 tag == (const char *) NULL ? "unknown" : tag,"`%s': %s",context,message); \ 75 message=DestroyString(message); \ 76} 77 78#if MagickCommandDebug >= 4 79static void OutputOptions(ImageInfo *image_info) 80{ 81 const char 82 *option, 83 *value; 84 85 (void) FormatLocaleFile(stdout," Image_Info Options:\n"); 86 ResetImageOptionIterator(image_info); 87 while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) { 88 (void) FormatLocaleFile(stdout," %s: ",option); 89 value=GetImageOption(image_info,option); 90 if (value != (const char *) NULL) 91 (void) FormatLocaleFile(stdout,"%s\n",value); 92 } 93 ResetImageOptionIterator(image_info); 94} 95 96static void OutputArtifacts(Image *image) 97{ 98 const char 99 *artifact, 100 *value; 101 102 (void) FormatLocaleFile(stdout," Image Artifacts:\n"); 103 ResetImageArtifactIterator(image); 104 while ((artifact=GetNextImageArtifact(image)) != (const char *) NULL ) { 105 (void) FormatLocaleFile(stdout," %s: ",artifact); 106 value=GetImageArtifact(image,artifact); 107 if (value != (const char *) NULL) 108 (void) FormatLocaleFile(stdout,"%s\n",value); 109 } 110 ResetImageArtifactIterator(image); 111} 112#endif 113 114 115/* 116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 117% % 118% % 119% % 120+ P r o c e s s S c r i p t O p t i o n s % 121% % 122% % 123% % 124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 125% 126% ProcessScriptOptions() reads options and processes options as they are 127% found in the given file, or pipeline. The filename to open and read 128% options is given as the 'index' argument of the argument array given. 129% 130% Other arguments following index may be read by special script options 131% as settings (strings), images, or as operations to be processed in various 132% ways. How they are treated is up to the script being processed. 133% 134% Note that a script not 'return' to the command line processing, nor can 135% they call (and return from) other scripts. At least not at this time. 136% 137% There are no 'ProcessOptionFlags' control flags at this time. 138% 139% The format of the ProcessScriptOptions method is: 140% 141% void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv, 142% int index) 143% 144% A description of each parameter follows: 145% 146% o cli_wand: the main CLI Wand to use. 147% 148% o argc: the number of elements in the argument vector. 149% 150% o argv: A text array containing the command line arguments. 151% 152% o index: offset for argc to CLI argumnet count 153% 154*/ 155WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv, 156 int index) 157{ 158 ScriptTokenInfo 159 *token_info; 160 161 CommandOptionFlags 162 option_type; 163 164 int 165 count; 166 167 char 168 *option, 169 *arg1, 170 *arg2; 171 172 assert(argc>index); /* at least one argument - script name */ 173 assert(argv != (char **)NULL); 174 assert(argv[index] != (char *)NULL); 175 assert(argv[argc-1] != (char *)NULL); 176 assert(cli_wand != (MagickCLI *) NULL); 177 assert(cli_wand->signature == WandSignature); 178 if (cli_wand->wand.debug != MagickFalse) 179 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 180 181 /* open file script or stream, and set up tokenizer */ 182 token_info = AcquireScriptTokenInfo(argv[index]); 183 if (token_info->token == (char *) NULL) { 184 ThrowFileException(cli_wand->wand.exception,OptionFatalError, 185 "UnableToOpenScript",argv[index]); 186 return; 187 } 188 189 /* define the error location string for use in exceptions 190 order of input escapes: option, filename, line, column 191 */ 192 cli_wand->location="'%s' in \"%s\" line %u column %u"; 193 if ( LocaleCompare("-", argv[index]) == 0 ) 194 cli_wand->filename="stdin"; 195 else 196 cli_wand->filename=argv[index]; 197 198 /* Process Options from Script */ 199 option = arg1 = arg2 = (char*)NULL; 200 while (1) { 201 202 /* Get a option */ 203 { MagickBooleanType status = GetScriptToken(token_info); 204 cli_wand->line=token_info->token_line; 205 cli_wand->column=token_info->token_column; 206 if( status == MagickFalse ) 207 break; 208 } 209 210 /* Sanity check: option is larger than anything that should be posible */ 211 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) { 212 token_info->token[INITAL_TOKEN_LENGTH-4] = '.'; 213 token_info->token[INITAL_TOKEN_LENGTH-3] = '.'; 214 token_info->token[INITAL_TOKEN_LENGTH-2] = '.'; 215 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0'; 216 CLIWandException(OptionFatalError,"UnrecognizedOption",token_info->token); 217 break; 218 } 219 220 /* save option details */ 221 CloneString(&option,token_info->token); 222 223 { /* get option type and argument count */ 224 const OptionInfo *option_info = GetCommandOptionInfo(option); 225 count=option_info->type; 226 option_type=option_info->flags; 227#if MagickCommandDebug >= 2 228 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n", 229 cli_wand->line, cli_wand->line, option, option_info->mnemonic ); 230#endif 231 } 232 233 /* handle a undefined option - image read? */ 234 if ( option_type == UndefinedOptionFlag || 235 (option_type & NonMagickOptionFlag) != 0 ) { 236#if MagickCommandDebug 237 (void) FormatLocaleFile(stderr, "Script Non-Option: \"%s\"\n", option); 238#endif 239 if ( IsCommandOption(option) == MagickFalse) 240 /* non-option -- treat as a image read */ 241 CLISpecialOperator(cli_wand,"-read",option); 242 else 243 CLIWandExceptionBreak(OptionFatalError,"UnrecognizedOption",option); 244 count = 0; 245 goto next_token; 246 } 247 248 if ( count >= 1 ) { 249 if( GetScriptToken(token_info) == MagickFalse ) 250 CLIWandException(OptionFatalError,"MissingArgument",option); 251 CloneString(&arg1,token_info->token); 252 } 253 else 254 CloneString(&arg1,(char *)NULL); 255 256 if ( count >= 2 ) { 257 if( GetScriptToken(token_info) == MagickFalse ) 258 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option); 259 CloneString(&arg2,token_info->token); 260 } 261 else 262 CloneString(&arg2,(char *)NULL); 263 264 /* handle script special options here */ 265 //either continue processing command line 266 // or making use of the command line options. 267 //CLICommandOptions(cli_wand,count+1,argv, MagickScriptArgsFlags); 268 269#if MagickCommandDebug 270 (void) FormatLocaleFile(stderr, 271 "Script Option: \"%s\" \tCount: %d Flags: %04x Args: \"%s\" \"%s\"\n", 272 option,(int) count,option_type,arg1,arg2); 273#endif 274 275 /* Process non-script specific option from file */ 276 if ( (option_type & SpecialOptionFlag) != 0 ) { 277 if ( LocaleCompare(option,"-exit") == 0 ) 278 break; 279 /* No "-script" option from script at this time */ 280 CLISpecialOperator(cli_wand,option,arg1); 281 } 282 283 if ( (option_type & SettingOptionFlags) != 0 ) { 284 CLISettingOptionInfo(cli_wand, option, arg1); 285 // FUTURE: Sync Specific Settings into Image Properities (not global) 286 } 287 288 if ( (option_type & SimpleOperatorOptionFlag) != 0) 289 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 290 291 if ( (option_type & ListOperatorOptionFlag) != 0 ) 292 CLIListOperatorImages(cli_wand, option, arg1, arg2); 293 294next_token: 295#if MagickCommandDebug >= 4 296 OutputOptions(cli_wand->wand.image_info); 297 if ( cli_wand->wand.images != (Image *)NULL ) 298 OutputArtifacts(cli_wand->wand.images); 299#endif 300 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 301 break; 302 } 303 304#if MagickCommandDebug 305 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status); 306#endif 307 switch( token_info->status ) { 308 case TokenStatusOK: 309 case TokenStatusEOF: 310 break; 311 case TokenStatusBadQuotes: 312 /* Ensure last token has a sane length for error report */ 313 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) { 314 token_info->token[INITAL_TOKEN_LENGTH-4] = '.'; 315 token_info->token[INITAL_TOKEN_LENGTH-3] = '.'; 316 token_info->token[INITAL_TOKEN_LENGTH-2] = '.'; 317 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0'; 318 } 319 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes", 320 token_info->token); 321 break; 322 case TokenStatusMemoryFailed: 323 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed",""); 324 break; 325 case TokenStatusBinary: 326 CLIWandException(OptionFatalError,"ScriptIsBinary",""); 327 break; 328 } 329 330 /* Clean up */ 331 token_info = DestroyScriptTokenInfo(token_info); 332 333 CloneString(&option,(char *)NULL); 334 CloneString(&arg1,(char *)NULL); 335 CloneString(&arg2,(char *)NULL); 336 337 return; 338} 339 340/* 341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 342% % 343% % 344% % 345+ P r o c e s s C o m m a n d O p t i o n s % 346% % 347% % 348% % 349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 350% 351% ProcessCommandOptions() reads and processes arguments in the given 352% command line argument array. The array does not contain the command 353% being processed, only the options. 354% 355% The 'process_flags' can be used to control and limit option processing. 356% For example, to only process one option, or how unknown and special options 357% are to be handled, and if the last argument in array is to be regarded as a 358% final image write argument (filename or special coder). 359% 360% The format of the ProcessCommandOptions method is: 361% 362% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv, 363% int index, ProcessOptionFlags process_flags ) 364% 365% A description of each parameter follows: 366% 367% o cli_wand: the main CLI Wand to use. 368% 369% o argc: the number of elements in the argument vector. 370% 371% o argv: A text array containing the command line arguments. 372% 373% o process_flags: What type of arguments we are allowed to process 374% 375% o index: index in the argv array to start processing from 376% 377% The function returns the index ot the next option to be processed. This 378% is really only releven if process_flags contains a ProcessOneOptionOnly 379% flag. 380% 381*/ 382WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc, 383 char **argv, int index, ProcessOptionFlags process_flags ) 384{ 385 const char 386 *option, 387 *arg1, 388 *arg2; 389 390 int 391 i, 392 end, 393 count; 394 395 CommandOptionFlags 396 option_type; 397 398 assert(argc>=index); /* you may have no arguments left! */ 399 assert(argv != (char **)NULL); 400 assert(argv[index] != (char *)NULL); 401 assert(argv[argc-1] != (char *)NULL); 402 assert(cli_wand != (MagickCLI *) NULL); 403 assert(cli_wand->signature == WandSignature); 404 if (cli_wand->wand.debug != MagickFalse) 405 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 406 407 /* 408 Parse command-line options. 409 */ 410 cli_wand->location="'%s' %s arg %d"; 411 cli_wand->filename="CLI"; 412 413 end = argc; 414 if ( ( process_flags & ProcessOutputFile ) != 0 ) 415 end--; 416 417 for (i=index; i < end; i += count +1) { 418 /* Finished processing one option? */ 419 if ( ( process_flags & ProcessOneOptionOnly ) != 0 && i != index ) 420 return(i); 421 422 option=argv[i]; 423 cli_wand->line=i; 424 425 { const OptionInfo *option_info = GetCommandOptionInfo(argv[i]); 426 count=option_info->type; 427 option_type=option_info->flags; 428#if MagickCommandDebug >= 2 429 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n", 430 i, argv[i], option_info->mnemonic ); 431#endif 432 } 433 434 if ( option_type == UndefinedOptionFlag || 435 (option_type & NonMagickOptionFlag) != 0 ) { 436#if MagickCommandDebug 437 (void) FormatLocaleFile(stderr, "CLI Non-Option: \"%s\"\n", option); 438#endif 439 if ( ( IsCommandOption(option) == MagickFalse ) && 440 ( (process_flags & ProcessNonOptionImageRead) != 0 ) ) 441 /* non-option -- treat as a image read */ 442 CLISpecialOperator(cli_wand,"-read",option); 443 else if ( (process_flags & ProcessUnknownOptionError) != 0 ) 444 CLIWandException(OptionFatalError,"UnrecognizedOption",option); 445 count = 0; 446 goto next_argument; 447 } 448 449 if ( (option_type & DeprecateOptionFlag) != 0 ) { 450 CLIWandException(OptionWarning,"DeprecatedOption",option); 451 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 452 return(i+count+1); 453 } 454 if ((i+count) >= end ) { 455 CLIWandException(OptionFatalError,"MissingArgument",option); 456 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 457 return(end); 458 goto next_argument; /* no more arguments unable to proceed */ 459 } 460 461 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL; 462 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL; 463 464#if MagickCommandDebug 465 (void) FormatLocaleFile(stderr, 466 "CLI Option: \"%s\" \tCount: %d Flags: %04x Args: \"%s\" \"%s\"\n", 467 option,(int) count,option_type,arg1,arg2); 468#endif 469 470 if ( (option_type & SpecialOptionFlag) != 0 ) { 471 if ( ( process_flags & ProcessExitOption ) != 0 472 && LocaleCompare(option,"-exit") == 0 ) 473 return(i+count); 474 if ( ( process_flags & ProcessScriptOption ) != 0 475 && LocaleCompare(option,"-script") == 0) { 476 // Unbalanced Parenthesis if stack not empty 477 // Call Script, with a filename as a zeroth argument 478 ProcessScriptOptions(cli_wand,argc,argv,i+1); 479 return(argc); /* no more options after script process! */ 480 } 481 CLISpecialOperator(cli_wand,option,arg1); 482 } 483 484 if ( (option_type & SettingOptionFlags) != 0 ) { 485 CLISettingOptionInfo(cli_wand, option, arg1); 486 // FUTURE: Sync Specific Settings into Image Properities (not global) 487 } 488 489 if ( (option_type & SimpleOperatorOptionFlag) != 0) 490 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 491 492 if ( (option_type & ListOperatorOptionFlag) != 0 ) 493 CLIListOperatorImages(cli_wand, option, arg1, arg2); 494 495next_argument: 496#if MagickCommandDebug >= 4 497 OutputOptions(cli_wand->wand.image_info); 498 if ( cli_wand->wand.images != (Image *)NULL ) 499 OutputArtifacts(cli_wand->wand.images); 500#endif 501 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 502 return(i+count); 503 } 504 assert(i==end); 505 506 if ( ( process_flags & ProcessOutputFile ) == 0 ) 507 return(end); 508 509 assert(end==argc-1); 510 511 /* 512 Implicit Write of images to final CLI argument 513 */ 514 option=argv[i]; 515 516#if MagickCommandDebug 517 (void) FormatLocaleFile(stderr, "CLI Write File: \"%s\"\n", option ); 518#endif 519 520 // if stacks are not empty 521 // ThrowConvertException(OptionError,"UnbalancedParenthesis",option,i); 522 523 /* This is a valid 'do no write' option for a CLI */ 524 if (LocaleCompare(option,"-exit") == 0 ) 525 return(argc); /* just exit, no image write */ 526 527 /* If there is an option -- produce an error */ 528 if (IsCommandOption(option) != MagickFalse) { 529 CLIWandException(OptionError,"MissingOutputFilename",option); 530 return(argc); 531 } 532 533 /* If no images in MagickCLI */ 534 if ( cli_wand->wand.images == (Image *) NULL ) { 535 /* a "null:" output coder with no images is not an error! */ 536 if ( LocaleCompare(option,"null:") == 0 ) 537 return(argc); 538 CLIWandException(OptionError,"NoImagesForFinalWrite",option); 539 return(argc); 540 } 541 542#if 0 543 WandListOperatorImages(cli_wand,"-write",option,(const char *)NULL); 544#else 545 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 546 cli_wand->wand.exception); 547 (void) WriteImages(cli_wand->wand.image_info,cli_wand->wand.images,option, 548 cli_wand->wand.exception); 549#endif 550 return(argc); 551} 552 553/* 554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 555% % 556% % 557% % 558+ M a g i c k I m a g e C o m m a n d % 559% % 560% % 561% % 562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 563% 564% MagickImageCommand() Handle special use CLI arguments and prepare a 565% CLI MagickCLI to process the command line or directly specified script. 566% 567% This is essentualy interface function between the MagickCore library 568% initialization function MagickCommandGenesis(), and the option MagickCLI 569% processing functions ProcessCommandOptions() or ProcessScriptOptions() 570% 571% The format of the MagickImageCommand method is: 572% 573% MagickBooleanType MagickImageCommand(ImageInfo *image_info, 574% int argc, char **argv, char **metadata, ExceptionInfo *exception) 575% 576% A description of each parameter follows: 577% 578% o image_info: the starting image_info structure 579% (for compatibilty with MagickCommandGenisis()) 580% 581% o argc: the number of elements in the argument vector. 582% 583% o argv: A text array containing the command line arguments. 584% 585% o metadata: any metadata is returned here. 586% (for compatibilty with MagickCommandGenisis()) 587% 588% o exception: return any errors or warnings in this structure. 589% 590*/ 591 592static MagickBooleanType MagickUsage(void) 593{ 594 printf("Version: %s\n",GetMagickVersion((size_t *) NULL)); 595 printf("Copyright: %s\n",GetMagickCopyright()); 596 printf("Features: %s\n\n",GetMagickFeatures()); 597 printf("\n"); 598 599 printf("Usage: %s [(options|images) ...] output_image\n", GetClientName()); 600 printf(" %s -script filename [script args...]\n", GetClientName()); 601 printf(" ... | %s -script - | ...\n", GetClientName()); 602 printf("\n"); 603 604 printf(" For more information on usage, options, examples, and technqiues\n"); 605 printf(" see the ImageMagick website at\n %s\n", MagickAuthoritativeURL); 606 printf(" Or the web pages in ImageMagick Sources\n"); 607 return(MagickFalse); 608} 609 610/* 611 Concatanate given file arguments to the given output argument. 612 Used for a special -concatenate option used for specific 'delegates'. 613 The option is not formally documented. 614 615 magick -concatenate files... output 616 617 This is much like the UNIX "cat" command, but for both UNIX and Windows, 618 however the last argument provides the output filename. 619*/ 620static MagickBooleanType ConcatenateImages(int argc,char **argv, 621 ExceptionInfo *exception) 622{ 623 FILE 624 *input, 625 *output; 626 627 int 628 c; 629 630 register ssize_t 631 i; 632 633 output=fopen_utf8(argv[argc-1],"wb"); 634 if (output == (FILE *) NULL) { 635 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 636 argv[argc-1]); 637 return(MagickFalse); 638 } 639 for (i=2; i < (ssize_t) (argc-1); i++) { 640 input=fopen_utf8(argv[i],"rb"); 641 if (input == (FILE *) NULL) 642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]); 643 for (c=fgetc(input); c != EOF; c=fgetc(input)) 644 (void) fputc((char) c,output); 645 (void) fclose(input); 646 (void) remove_utf8(argv[i]); 647 } 648 (void) fclose(output); 649 return(MagickTrue); 650} 651 652WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info, 653 int argc,char **argv,char **metadata,ExceptionInfo *exception) 654{ 655 MagickCLI 656 *cli_wand; 657 658 const char 659 *option; 660 661 /* Handle special single use options */ 662 if (argc == 2) { 663 option=argv[1]; 664 if ((LocaleCompare("-version",option+1) == 0) || 665 (LocaleCompare("--version",option+1) == 0) ) { 666 (void) FormatLocaleFile(stdout,"Version: %s\n", 667 GetMagickVersion((size_t *) NULL)); 668 (void) FormatLocaleFile(stdout,"Copyright: %s\n", 669 GetMagickCopyright()); 670 (void) FormatLocaleFile(stdout,"Features: %s\n\n", 671 GetMagickFeatures()); 672 return(MagickFalse); 673 } 674 } 675 /* The "magick" command must have at least two arguments */ 676 if (argc < 3) 677 return(MagickUsage()); 678 ReadCommandlLine(argc,&argv); 679 680#if 0 681 /* FUTURE: This does not make sense! Remove it. 682 Only a 'image read' needs to expand file name glob patterns 683 */ 684 status=ExpandFilenames(&argc,&argv); 685 if (status == MagickFalse) 686 ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed", 687 GetExceptionMessage(errno)); 688#endif 689 690 /* Special option (hidden) for delegate usage - no wand needed */ 691 if (LocaleCompare("-concatenate",argv[1]) == 0) 692 return(ConcatenateImages(argc,argv,exception)); 693 694 /* Initialize special "CLI Wand" to hold images and settings (empty) */ 695 /* FUTURE: add this to 'operations.c' */ 696 cli_wand=AcquireMagickCLI(image_info,exception); 697 698 if (LocaleCompare("-list",argv[1]) == 0) 699 /* Special option, list information and exit 700 FUTURE: this should be a MagickCore option, 701 especially as no wand is actually needed! 702 */ 703 CLISpecialOperator(cli_wand, argv[1], argv[2]); 704 else if (LocaleCompare("-script",argv[1]) == 0) { 705 /* Start processing directly from script, no pre-script options 706 Replace wand command name with script name 707 First argument in the argv array is the script name to read. 708 */ 709 GetPathComponent(argv[2],TailPath,cli_wand->wand.name); 710 ProcessScriptOptions(cli_wand,argc,argv,2); 711 } 712 else { 713 /* Processing Command line, assuming output file as last option */ 714 GetPathComponent(argv[0],TailPath,cli_wand->wand.name); 715 ProcessCommandOptions(cli_wand,argc,argv,1,MagickCommandOptionFlags); 716 } 717 718 /* recover original image_info from bottom of stack */ 719 while (cli_wand->image_info_stack != (Stack *)NULL) 720 CLISpecialOperator(cli_wand,"}",(const char *)NULL); 721 722 /* assert we have recovered the original structures */ 723 assert(cli_wand->wand.image_info == image_info); 724 assert(cli_wand->wand.exception == exception); 725 726 /* Handle metadata for ImageMagickObject COM object for Windows VBS */ 727 if (metadata != (char **) NULL) { 728 const char 729 *format; 730 731 char 732 *text; 733 734 format="%w,%h,%m"; // Get this from image_info Option splaytree 735 736 text=InterpretImageProperties(image_info,cli_wand->wand.images,format, 737 exception); 738 if (text == (char *) NULL) 739 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, 740 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno)); 741 else { 742 (void) ConcatenateString(&(*metadata),text); 743 text=DestroyString(text); 744 } 745 } 746 /* Destroy the special CLI Wand */ 747 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */ 748 cli_wand->wand.exception = (ExceptionInfo *)NULL; 749 cli_wand=DestroyMagickCLI(cli_wand); 750 751 return((exception->severity > ErrorException) ? MagickFalse : MagickTrue); 752} 753