magick-cli.c revision 7e822e51decafc0b225255d2bfb1aba4e491d556
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 == (ScriptTokenInfo *) 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 /* save option details */ 211 CloneString(&option,token_info->token); 212 213 { /* get option type and argument count */ 214 const OptionInfo *option_info = GetCommandOptionInfo(option); 215 count=option_info->type; 216 option_type=option_info->flags; 217#if MagickCommandDebug >= 2 218 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n", 219 cli_wand->line, cli_wand->line, option, option_info->mnemonic ); 220#endif 221 } 222 223 /* handle a undefined option - image read? */ 224 if ( option_type == UndefinedOptionFlag || 225 (option_type & NonMagickOptionFlag) != 0 ) { 226#if MagickCommandDebug 227 (void) FormatLocaleFile(stderr, "Script Non-Option: \"%s\"\n", option); 228#endif 229 if ( IsCommandOption(option) == MagickFalse) 230 /* non-option -- treat as a image read */ 231 CLISpecialOperator(cli_wand,"-read",option); 232 else 233 CLIWandExceptionBreak(OptionFatalError,"UnrecognizedOption",option); 234 count = 0; 235 goto next_token; 236 } 237 238 if ( count >= 1 ) { 239 if( GetScriptToken(token_info) == MagickFalse ) 240 CLIWandException(OptionFatalError,"MissingArgument",option); 241 CloneString(&arg1,token_info->token); 242 } 243 else 244 CloneString(&arg1,(char *)NULL); 245 246 if ( count >= 2 ) { 247 if( GetScriptToken(token_info) == MagickFalse ) 248 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option); 249 CloneString(&arg2,token_info->token); 250 } 251 else 252 CloneString(&arg2,(char *)NULL); 253 254#if MagickCommandDebug 255 (void) FormatLocaleFile(stderr, 256 "Script Option: \"%s\" \tCount: %d Flags: %04x Args: \"%s\" \"%s\"\n", 257 option,(int) count,option_type,arg1,arg2); 258#endif 259 260 if ( (option_type & DeprecateOptionFlag) != 0 ) { 261 CLIWandException(OptionWarning,"DeprecatedOption",option); 262 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 263 break; 264 } 265 266 /* handle special script-argument options here */ 267 //either continue processing command line 268 // or making use of the command line options. 269 //CLICommandOptions(cli_wand,count+1,argv, MagickScriptArgsFlags); 270 271 /* Process Option from file */ 272 if ( (option_type & SpecialOptionFlag) != 0 ) { 273 if ( LocaleCompare(option,"-exit") == 0 ) 274 break; 275 /* No "-script" option from script at this time - though posible */ 276 CLISpecialOperator(cli_wand,option,arg1); 277 } 278 279 if ( (option_type & SettingOptionFlags) != 0 ) { 280 CLISettingOptionInfo(cli_wand, option, arg1); 281 // FUTURE: Sync Specific Settings into Image Properities (not global) 282 } 283 284 if ( (option_type & SimpleOperatorOptionFlag) != 0) 285 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 286 287 if ( (option_type & ListOperatorOptionFlag) != 0 ) 288 CLIListOperatorImages(cli_wand, option, arg1, arg2); 289 290next_token: 291#if MagickCommandDebug >= 4 292 OutputOptions(cli_wand->wand.image_info); 293 if ( cli_wand->wand.images != (Image *)NULL ) 294 OutputArtifacts(cli_wand->wand.images); 295#endif 296 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 297 break; 298 } 299 300#if MagickCommandDebug 301 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status); 302#endif 303 switch( token_info->status ) { 304 case TokenStatusOK: 305 case TokenStatusEOF: 306 break; 307 case TokenStatusBadQuotes: 308 /* Ensure last token has a sane length for error report */ 309 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) { 310 token_info->token[INITAL_TOKEN_LENGTH-4] = '.'; 311 token_info->token[INITAL_TOKEN_LENGTH-3] = '.'; 312 token_info->token[INITAL_TOKEN_LENGTH-2] = '.'; 313 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0'; 314 } 315 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes", 316 token_info->token); 317 break; 318 case TokenStatusMemoryFailed: 319 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed",""); 320 break; 321 case TokenStatusBinary: 322 CLIWandException(OptionFatalError,"ScriptIsBinary",""); 323 break; 324 } 325 326 /* Clean up */ 327 token_info = DestroyScriptTokenInfo(token_info); 328 329 CloneString(&option,(char *)NULL); 330 CloneString(&arg1,(char *)NULL); 331 CloneString(&arg2,(char *)NULL); 332 333 return; 334} 335 336/* 337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 338% % 339% % 340% % 341+ P r o c e s s C o m m a n d O p t i o n s % 342% % 343% % 344% % 345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 346% 347% ProcessCommandOptions() reads and processes arguments in the given 348% command line argument array. The array does not contain the command 349% being processed, only the options. 350% 351% The 'process_flags' can be used to control and limit option processing. 352% For example, to only process one option, or how unknown and special options 353% are to be handled, and if the last argument in array is to be regarded as a 354% final image write argument (filename or special coder). 355% 356% The format of the ProcessCommandOptions method is: 357% 358% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv, 359% int index, ProcessOptionFlags process_flags ) 360% 361% A description of each parameter follows: 362% 363% o cli_wand: the main CLI Wand to use. 364% 365% o argc: the number of elements in the argument vector. 366% 367% o argv: A text array containing the command line arguments. 368% 369% o process_flags: What type of arguments we are allowed to process 370% 371% o index: index in the argv array to start processing from 372% 373% The function returns the index ot the next option to be processed. This 374% is really only releven if process_flags contains a ProcessOneOptionOnly 375% flag. 376% 377*/ 378WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc, 379 char **argv, int index, ProcessOptionFlags process_flags ) 380{ 381 const char 382 *option, 383 *arg1, 384 *arg2; 385 386 int 387 i, 388 end, 389 count; 390 391 CommandOptionFlags 392 option_type; 393 394 assert(argc>=index); /* you may have no arguments left! */ 395 assert(argv != (char **)NULL); 396 assert(argv[index] != (char *)NULL); 397 assert(argv[argc-1] != (char *)NULL); 398 assert(cli_wand != (MagickCLI *) NULL); 399 assert(cli_wand->signature == WandSignature); 400 if (cli_wand->wand.debug != MagickFalse) 401 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 402 403 /* 404 Parse command-line options. 405 */ 406 cli_wand->location="'%s' %s arg %d"; 407 cli_wand->filename="CLI"; 408 409 end = argc; 410 if ( ( process_flags & ProcessOutputFile ) != 0 ) 411 end--; 412 413 for (i=index; i < end; i += count +1) { 414 /* Finished processing one option? */ 415 if ( ( process_flags & ProcessOneOptionOnly ) != 0 && i != index ) 416 return(i); 417 418 option=argv[i]; 419 cli_wand->line=i; 420 421 { const OptionInfo *option_info = GetCommandOptionInfo(argv[i]); 422 count=option_info->type; 423 option_type=option_info->flags; 424#if MagickCommandDebug >= 2 425 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n", 426 i, argv[i], option_info->mnemonic ); 427#endif 428 } 429 430 if ( option_type == UndefinedOptionFlag || 431 (option_type & NonMagickOptionFlag) != 0 ) { 432#if MagickCommandDebug 433 (void) FormatLocaleFile(stderr, "CLI Non-Option: \"%s\"\n", option); 434#endif 435 if ( ( IsCommandOption(option) == MagickFalse ) && 436 ( (process_flags & ProcessNonOptionImageRead) != 0 ) ) 437 /* non-option -- treat as a image read */ 438 CLISpecialOperator(cli_wand,"-read",option); 439 else if ( (process_flags & ProcessUnknownOptionError) != 0 ) 440 CLIWandException(OptionFatalError,"UnrecognizedOption",option); 441 count = 0; 442 goto next_argument; 443 } 444 445 if ( (option_type & DeprecateOptionFlag) != 0 ) { 446 CLIWandException(OptionWarning,"DeprecatedOption",option); 447 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 448 return(i+count+1); 449 } 450 if ((i+count) >= end ) { 451 CLIWandException(OptionFatalError,"MissingArgument",option); 452 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 453 return(end); 454 goto next_argument; /* no more arguments unable to proceed */ 455 } 456 457 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL; 458 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL; 459 460#if MagickCommandDebug 461 (void) FormatLocaleFile(stderr, 462 "CLI Option: \"%s\" \tCount: %d Flags: %04x Args: \"%s\" \"%s\"\n", 463 option,(int) count,option_type,arg1,arg2); 464#endif 465 466 if ( (option_type & SpecialOptionFlag) != 0 ) { 467 if ( ( process_flags & ProcessExitOption ) != 0 468 && LocaleCompare(option,"-exit") == 0 ) 469 return(i+count); 470 if ( ( process_flags & ProcessScriptOption ) != 0 471 && LocaleCompare(option,"-script") == 0) { 472 // Unbalanced Parenthesis if stack not empty 473 // Call Script, with a filename as a zeroth argument 474 ProcessScriptOptions(cli_wand,argc,argv,i+1); 475 return(argc); /* no more options after script process! */ 476 } 477 CLISpecialOperator(cli_wand,option,arg1); 478 } 479 480 if ( (option_type & SettingOptionFlags) != 0 ) { 481 CLISettingOptionInfo(cli_wand, option, arg1); 482 // FUTURE: Sync Specific Settings into Image Properities (not global) 483 } 484 485 if ( (option_type & SimpleOperatorOptionFlag) != 0) 486 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 487 488 if ( (option_type & ListOperatorOptionFlag) != 0 ) 489 CLIListOperatorImages(cli_wand, option, arg1, arg2); 490 491next_argument: 492#if MagickCommandDebug >= 4 493 OutputOptions(cli_wand->wand.image_info); 494 if ( cli_wand->wand.images != (Image *)NULL ) 495 OutputArtifacts(cli_wand->wand.images); 496#endif 497 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 498 return(i+count); 499 } 500 assert(i==end); 501 502 if ( ( process_flags & ProcessOutputFile ) == 0 ) 503 return(end); 504 505 assert(end==argc-1); 506 507 /* 508 Implicit Write of images to final CLI argument 509 */ 510 option=argv[i]; 511 cli_wand->line=i; 512 513#if MagickCommandDebug 514 (void) FormatLocaleFile(stderr, "CLI Write File: \"%s\"\n", option ); 515#endif 516 517 // if stacks are not empty 518 // ThrowConvertException(OptionError,"UnbalancedParenthesis",option,i); 519 520 /* This is a valid 'do no write' option for a CLI */ 521 if (LocaleCompare(option,"-exit") == 0 ) 522 return(argc); /* just exit, no image write */ 523 524 /* If there is an option -- produce an error */ 525 if (IsCommandOption(option) != MagickFalse) { 526 CLIWandException(OptionError,"MissingOutputFilename",option); 527 return(argc); 528 } 529 530 /* If no images in MagickCLI */ 531 if ( cli_wand->wand.images == (Image *) NULL ) { 532 /* a "null:" output coder with no images is not an error! */ 533 if ( LocaleCompare(option,"null:") == 0 ) 534 return(argc); 535 CLIWandException(OptionError,"NoImagesForFinalWrite",option); 536 return(argc); 537 } 538 539#if 0 540 WandListOperatorImages(cli_wand,"-write",option,(const char *)NULL); 541#else 542 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 543 cli_wand->wand.exception); 544 (void) WriteImages(cli_wand->wand.image_info,cli_wand->wand.images,option, 545 cli_wand->wand.exception); 546#endif 547 return(argc); 548} 549 550/* 551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 552% % 553% % 554% % 555+ M a g i c k I m a g e C o m m a n d % 556% % 557% % 558% % 559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 560% 561% MagickImageCommand() Handle special use CLI arguments and prepare a 562% CLI MagickCLI to process the command line or directly specified script. 563% 564% This is essentualy interface function between the MagickCore library 565% initialization function MagickCommandGenesis(), and the option MagickCLI 566% processing functions ProcessCommandOptions() or ProcessScriptOptions() 567% 568% The format of the MagickImageCommand method is: 569% 570% MagickBooleanType MagickImageCommand(ImageInfo *image_info, 571% int argc, char **argv, char **metadata, ExceptionInfo *exception) 572% 573% A description of each parameter follows: 574% 575% o image_info: the starting image_info structure 576% (for compatibilty with MagickCommandGenisis()) 577% 578% o argc: the number of elements in the argument vector. 579% 580% o argv: A text array containing the command line arguments. 581% 582% o metadata: any metadata is returned here. 583% (for compatibilty with MagickCommandGenisis()) 584% 585% o exception: return any errors or warnings in this structure. 586% 587*/ 588 589static MagickBooleanType MagickUsage(void) 590{ 591 printf("Version: %s\n",GetMagickVersion((size_t *) NULL)); 592 printf("Copyright: %s\n",GetMagickCopyright()); 593 printf("Features: %s\n\n",GetMagickFeatures()); 594 printf("\n"); 595 596 printf("Usage: %s [(options|images) ...] output_image\n", GetClientName()); 597 printf(" %s -script filename [script args...]\n", GetClientName()); 598 printf(" ... | %s -script - | ...\n", GetClientName()); 599 printf("\n"); 600 601 printf(" For more information on usage, options, examples, and technqiues\n"); 602 printf(" see the ImageMagick website at\n %s\n", MagickAuthoritativeURL); 603 printf(" Or the web pages in ImageMagick Sources\n"); 604 return(MagickFalse); 605} 606 607/* 608 Concatanate given file arguments to the given output argument. 609 Used for a special -concatenate option used for specific 'delegates'. 610 The option is not formally documented. 611 612 magick -concatenate files... output 613 614 This is much like the UNIX "cat" command, but for both UNIX and Windows, 615 however the last argument provides the output filename. 616*/ 617static MagickBooleanType ConcatenateImages(int argc,char **argv, 618 ExceptionInfo *exception) 619{ 620 FILE 621 *input, 622 *output; 623 624 int 625 c; 626 627 register ssize_t 628 i; 629 630 output=fopen_utf8(argv[argc-1],"wb"); 631 if (output == (FILE *) NULL) { 632 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 633 argv[argc-1]); 634 return(MagickFalse); 635 } 636 for (i=2; i < (ssize_t) (argc-1); i++) { 637 input=fopen_utf8(argv[i],"rb"); 638 if (input == (FILE *) NULL) 639 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]); 640 for (c=fgetc(input); c != EOF; c=fgetc(input)) 641 (void) fputc((char) c,output); 642 (void) fclose(input); 643 (void) remove_utf8(argv[i]); 644 } 645 (void) fclose(output); 646 return(MagickTrue); 647} 648 649WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info, 650 int argc,char **argv,char **metadata,ExceptionInfo *exception) 651{ 652 MagickCLI 653 *cli_wand; 654 655 const char 656 *option; 657 658 /* For specific OS command line requirements */ 659 ReadCommandlLine(argc,&argv); 660 661#if 0 662 /* FUTURE: This does not make sense! Remove it. 663 Only a 'image read' needs to expand file name glob patterns 664 */ 665 status=ExpandFilenames(&argc,&argv); 666 if (status == MagickFalse) 667 ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed", 668 GetExceptionMessage(errno)); 669#endif 670 671 /* Handle special single use options */ 672 if (argc == 2) { 673 option=argv[1]; 674 if ((LocaleCompare("-version",option+1) == 0) || 675 (LocaleCompare("--version",option+1) == 0) ) { 676 (void) FormatLocaleFile(stdout,"Version: %s\n", 677 GetMagickVersion((size_t *) NULL)); 678 (void) FormatLocaleFile(stdout,"Copyright: %s\n", 679 GetMagickCopyright()); 680 (void) FormatLocaleFile(stdout,"Features: %s\n\n", 681 GetMagickFeatures()); 682 return(MagickFalse); 683 } 684 } 685 686 if (argc >= 2) { 687 /* Special "concatenate option (hidden) for delegate usage */ 688 if (LocaleCompare("-concatenate",argv[1]) == 0) 689 return(ConcatenateImages(argc,argv,exception)); 690 691 /* Special Handling for a "#!/usr/bin/env magick-script" script */ 692 if (LocaleCompare("magick-script",argv[0]+strlen(argv[0])-13) == 0) { 693 cli_wand=AcquireMagickCLI(image_info,exception); 694 GetPathComponent(argv[1],TailPath,cli_wand->wand.name); 695 ProcessScriptOptions(cli_wand,argc,argv,1); 696 goto Magick_Command_Cleanup; 697 } 698 } 699 700 if (argc < 3) 701 return(MagickUsage()); 702 703 /* Initialize special "CLI Wand" to hold images and settings (empty) */ 704 cli_wand=AcquireMagickCLI(image_info,exception); 705 706 if (LocaleCompare("-list",argv[1]) == 0) 707 /* Special option, list information and exit 708 FUTURE: this should be a MagickCore option, 709 especially as no wand is actually needed! 710 */ 711 CLISpecialOperator(cli_wand, argv[1], argv[2]); 712 else if (LocaleCompare("-script",argv[1]) == 0) { 713 /* Start processing directly from script, no pre-script options 714 Replace wand command name with script name 715 First argument in the argv array is the script name to read. 716 */ 717 GetPathComponent(argv[2],TailPath,cli_wand->wand.name); 718 ProcessScriptOptions(cli_wand,argc,argv,2); 719 } 720 else { 721 /* Noraml Command Line, Assumes output file as last option */ 722 GetPathComponent(argv[0],TailPath,cli_wand->wand.name); 723 ProcessCommandOptions(cli_wand,argc,argv,1, 724 (LocaleCompare("magick",argv[0]+strlen(argv[0])-6) == 0)? 725 MagickCommandOptionFlags : ConvertCommandOptionFlags); 726 } 727 728Magick_Command_Cleanup: 729 /* recover original image_info from bottom of stack */ 730 while (cli_wand->image_info_stack != (Stack *)NULL) 731 CLISpecialOperator(cli_wand,"}",(const char *)NULL); 732 733 /* assert we have recovered the original structures */ 734 assert(cli_wand->wand.image_info == image_info); 735 assert(cli_wand->wand.exception == exception); 736 737 /* Handle metadata for ImageMagickObject COM object for Windows VBS */ 738 if (metadata != (char **) NULL) { 739 const char 740 *format; 741 742 char 743 *text; 744 745 format="%w,%h,%m"; // Get this from image_info Option splaytree 746 747 text=InterpretImageProperties(image_info,cli_wand->wand.images,format, 748 exception); 749 if (text == (char *) NULL) 750 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, 751 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno)); 752 else { 753 (void) ConcatenateString(&(*metadata),text); 754 text=DestroyString(text); 755 } 756 } 757 758 /* Destroy the special CLI Wand */ 759 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */ 760 cli_wand->wand.exception = (ExceptionInfo *)NULL; 761 cli_wand=DestroyMagickCLI(cli_wand); 762 763 return((exception->severity > ErrorException) ? MagickFalse : MagickTrue); 764} 765