magick-cli.c revision 0ea037a49d6f7f926e2cabb90c1ebcbf6b1c39bf
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, (arg), filename, line, column */ 191 cli_wand->location="'%s' in \"%s\" line %u column %u"; 192 cli_wand->location2="'%s' '%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( IfMagickFalse(status) ) 207 break; /* error or end of options */ 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=(CommandOptionFlags) 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 ( IfMagickFalse(IsCommandOption(option))) 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( IfMagickFalse(GetScriptToken(token_info)) ) 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( IfMagickFalse(GetScriptToken(token_info)) ) 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 if ( cli_wand->wand.images != (Image *)NULL ) 284 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 285 cli_wand->wand.exception); 286 287 if ( (option_type & SimpleOperatorOptionFlag) != 0) 288 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 289 290 if ( (option_type & ListOperatorOptionFlag) != 0 ) 291 CLIListOperatorImages(cli_wand, option, arg1, arg2); 292 293next_token: 294#if MagickCommandDebug >= 4 295 OutputOptions(cli_wand->wand.image_info); 296 if ( cli_wand->wand.images != (Image *)NULL ) 297 OutputArtifacts(cli_wand->wand.images); 298#endif 299 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 300 break; 301 } 302 303#if MagickCommandDebug 304 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status); 305#endif 306 switch( token_info->status ) { 307 case TokenStatusOK: 308 case TokenStatusEOF: 309 break; 310 case TokenStatusBadQuotes: 311 /* Ensure last token has a sane length for error report */ 312 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) { 313 token_info->token[INITAL_TOKEN_LENGTH-4] = '.'; 314 token_info->token[INITAL_TOKEN_LENGTH-3] = '.'; 315 token_info->token[INITAL_TOKEN_LENGTH-2] = '.'; 316 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0'; 317 } 318 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes", 319 token_info->token); 320 break; 321 case TokenStatusMemoryFailed: 322 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed",""); 323 break; 324 case TokenStatusBinary: 325 CLIWandException(OptionFatalError,"ScriptIsBinary",""); 326 break; 327 } 328 329 /* Clean up */ 330 token_info = DestroyScriptTokenInfo(token_info); 331 332 CloneString(&option,(char *)NULL); 333 CloneString(&arg1,(char *)NULL); 334 CloneString(&arg2,(char *)NULL); 335 336 return; 337} 338 339/* 340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 341% % 342% % 343% % 344+ P r o c e s s C o m m a n d O p t i o n s % 345% % 346% % 347% % 348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 349% 350% ProcessCommandOptions() reads and processes arguments in the given 351% command line argument array. The array does not contain the command 352% being processed, only the options. 353% 354% The 'process_flags' can be used to control and limit option processing. 355% For example, to only process one option, or how unknown and special options 356% are to be handled, and if the last argument in array is to be regarded as a 357% final image write argument (filename or special coder). 358% 359% The format of the ProcessCommandOptions method is: 360% 361% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv, 362% int index, ProcessOptionFlags process_flags ) 363% 364% A description of each parameter follows: 365% 366% o cli_wand: the main CLI Wand to use. 367% 368% o argc: the number of elements in the argument vector. 369% 370% o argv: A text array containing the command line arguments. 371% 372% o process_flags: What type of arguments will be processed, ignored 373% or return errors. 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 /* define the error location string for use in exceptions 408 order of input escapes: option, (arg), filename, line, column */ 409 cli_wand->location="'%s' %s arg %u"; 410 cli_wand->location2="'%s' '%s' %s arg %u"; 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=(CommandOptionFlags) 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 ( IfMagickFalse(IsCommandOption(option) ) && 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 if ( cli_wand->wand.images != (Image *)NULL ) 489 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 490 cli_wand->wand.exception); 491 492 if ( (option_type & SimpleOperatorOptionFlag) != 0) 493 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 494 495 if ( (option_type & ListOperatorOptionFlag) != 0 ) 496 CLIListOperatorImages(cli_wand, option, arg1, arg2); 497 498next_argument: 499#if MagickCommandDebug >= 4 500 OutputOptions(cli_wand->wand.image_info); 501 if ( cli_wand->wand.images != (Image *)NULL ) 502 OutputArtifacts(cli_wand->wand.images); 503#endif 504 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 505 return(i+count); 506 } 507 assert(i==end); 508 509 if ( ( process_flags & ProcessOutputFile ) == 0 ) 510 return(end); 511 512 assert(end==argc-1); 513 514 /* 515 Implicit Write of images to final CLI argument 516 */ 517 option=argv[i]; 518 cli_wand->line=i; 519 520#if MagickCommandDebug 521 (void) FormatLocaleFile(stderr, "CLI Write File: \"%s\"\n", option ); 522#endif 523 524 // if stacks are not empty 525 // ThrowConvertException(OptionError,"UnbalancedParenthesis",option,i); 526 527 /* This is a valid 'do no write' option for a CLI */ 528 if (LocaleCompare(option,"-exit") == 0 ) 529 return(argc); /* just exit, no image write */ 530 531 /* If there is an option -- produce an error */ 532 if (IsCommandOption(option) != MagickFalse) { 533 CLIWandException(OptionError,"MissingOutputFilename",option); 534 return(argc); 535 } 536 537 /* If no images in MagickCLI */ 538 if ( cli_wand->wand.images == (Image *) NULL ) { 539 /* a "null:" output coder with no images is not an error! */ 540 if ( LocaleCompare(option,"null:") == 0 ) 541 return(argc); 542 CLIWandException(OptionError,"NoImagesForFinalWrite",option); 543 return(argc); 544 } 545 546#if 0 547 WandListOperatorImages(cli_wand,"-write",option,(const char *)NULL); 548#else 549 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 550 cli_wand->wand.exception); 551 (void) WriteImages(cli_wand->wand.image_info,cli_wand->wand.images,option, 552 cli_wand->wand.exception); 553#endif 554 return(argc); 555} 556 557/* 558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 559% % 560% % 561% % 562+ M a g i c k I m a g e C o m m a n d % 563% % 564% % 565% % 566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 567% 568% MagickImageCommand() Handle special use CLI arguments and prepare a 569% CLI MagickCLI to process the command line or directly specified script. 570% 571% This is essentualy interface function between the MagickCore library 572% initialization function MagickCommandGenesis(), and the option MagickCLI 573% processing functions ProcessCommandOptions() or ProcessScriptOptions() 574% 575% The format of the MagickImageCommand method is: 576% 577% MagickBooleanType MagickImageCommand(ImageInfo *image_info, 578% int argc, char **argv, char **metadata, ExceptionInfo *exception) 579% 580% A description of each parameter follows: 581% 582% o image_info: the starting image_info structure 583% (for compatibilty with MagickCommandGenisis()) 584% 585% o argc: the number of elements in the argument vector. 586% 587% o argv: A text array containing the command line arguments. 588% 589% o metadata: any metadata (for VBS) is returned here. 590% (for compatibilty with MagickCommandGenisis()) 591% 592% o exception: return any errors or warnings in this structure. 593% 594*/ 595 596static MagickBooleanType MagickUsage(void) 597{ 598 printf("Usage: %s [(options|images) ...] output_image\n", GetClientName()); 599 printf(" %s -script filename [script args...]\n", GetClientName()); 600 printf("\n"); 601 printf(" For more information on usage, options, examples, and technqiues\n"); 602 printf(" see the ImageMagick website at\n %s\n", MagickAuthoritativeURL); 603 return(MagickFalse); 604} 605 606/* 607 Concatanate given file arguments to the given output argument. 608 Used for a special -concatenate option used for specific 'delegates'. 609 The option is not formally documented. 610 611 magick -concatenate files... output 612 613 This is much like the UNIX "cat" command, but for both UNIX and Windows, 614 however the last argument provides the output filename. 615*/ 616static MagickBooleanType ConcatenateImages(int argc,char **argv, 617 ExceptionInfo *exception) 618{ 619 FILE 620 *input, 621 *output; 622 623 int 624 c; 625 626 register ssize_t 627 i; 628 629 output=fopen_utf8(argv[argc-1],"wb"); 630 if (output == (FILE *) NULL) { 631 ThrowFileException(exception,FileOpenError,"UnableToOpenFile", 632 argv[argc-1]); 633 return(MagickFalse); 634 } 635 for (i=2; i < (ssize_t) (argc-1); i++) { 636 input=fopen_utf8(argv[i],"rb"); 637 if (input == (FILE *) NULL) 638 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]); 639 for (c=fgetc(input); c != EOF; c=fgetc(input)) 640 (void) fputc((char) c,output); 641 (void) fclose(input); 642 (void) remove_utf8(argv[i]); 643 } 644 (void) fclose(output); 645 return(MagickTrue); 646} 647 648WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info, 649 int argc,char **argv,char **metadata,ExceptionInfo *exception) 650{ 651 MagickCLI 652 *cli_wand; 653 654 const char 655 *option; 656 657 ProcessOptionFlags 658 process_flags = MagickCommandOptionFlags; 659 660 /* For specific OS command line requirements */ 661 ReadCommandlLine(argc,&argv); 662 663#if 0 664 status=ExpandFilenames(&argc,&argv); 665 if ( IfMagickFalse(status) ) 666 ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed", 667 GetExceptionMessage(errno)); 668#endif 669 670 /* Initialize special "CLI Wand" to hold images and settings (empty) */ 671 cli_wand=AcquireMagickCLI(image_info,exception); 672 673 GetPathComponent(argv[0],TailPath,cli_wand->wand.name); 674 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent); 675 676 /* "convert" command - give a "depreciation" warning" */ 677 if ( (LocaleCompare("convert",argv[0]+strlen((argv[0])-7)) == 0) || 678 (LocaleNCompare("convert",argv[0],7) == 0) || 679 (LocaleNCompare("lt-convert",argv[0],10) == 0) ) { 680 process_flags = ConvertCommandOptionFlags; 681 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n", 682 "The convert is depreciated in IMv7, use \"magick\"\n");*/ 683 } 684 685 /* Special Case: If command name ends with "script" then run it as is 686 a "-script" option is implied. This allows you to name the "magick" 687 command "magick-script", and create scripts of the form... 688 #!/usr/bin/env magick-script 689 */ 690 if (LocaleCompare("script",argv[0]+strlen(argv[0])-6) == 0) { 691 GetPathComponent(argv[1],TailPath,cli_wand->wand.name); 692 ProcessScriptOptions(cli_wand,argc,argv,1); 693 goto Magick_Command_Cleanup; 694 } 695 696 /* Special Case: Version Information and Abort */ 697 if (argc == 2) { 698 option=argv[1]; 699 if ((LocaleCompare("-version",option) == 0) || 700 (LocaleCompare("--version",option) == 0) ) { 701 CLISpecialOperator(cli_wand, "-version", (char *)NULL); 702 goto Magick_Command_Exit; 703 } 704 } 705 706 /* not enough arguments -- including -help */ 707 if (argc < 3) { 708 CLISpecialOperator(cli_wand, "-version", (char *)NULL); 709 MagickUsage(); 710 goto Magick_Command_Exit; 711 } 712 713 /* List Information and Abort */ 714 if (LocaleCompare("-list",argv[1]) == 0) { 715 CLISpecialOperator(cli_wand, argv[1], argv[2]); 716 goto Magick_Command_Exit; 717 } 718 719 /* Special "concatenate option (hidden) for delegate usage */ 720 if (LocaleCompare("-concatenate",argv[1]) == 0) { 721 ConcatenateImages(argc,argv,exception); 722 goto Magick_Command_Exit; 723 } 724 725 /* ------------- */ 726 /* The Main Call */ 727 728 if (LocaleCompare("-script",argv[1]) == 0) { 729 /* Start processing directly from script, no pre-script options 730 Replace wand command name with script name 731 First argument in the argv array is the script name to read. 732 */ 733 GetPathComponent(argv[2],TailPath,cli_wand->wand.name); 734 ProcessScriptOptions(cli_wand,argc,argv,2); 735 } 736 else { 737 /* Normal Command Line, assumes output file as last option */ 738 ProcessCommandOptions(cli_wand,argc,argv,1, process_flags); 739 } 740 /* ------------- */ 741 742Magick_Command_Cleanup: 743 /* recover original image_info from bottom of stack */ 744 while (cli_wand->image_info_stack != (Stack *)NULL) 745 CLISpecialOperator(cli_wand,"}",(const char *)NULL); 746 747 /* assert we have recovered the original structures */ 748 assert(cli_wand->wand.image_info == image_info); 749 assert(cli_wand->wand.exception == exception); 750 751 /* Handle metadata for ImageMagickObject COM object for Windows VBS */ 752 if (metadata != (char **) NULL) { 753 const char 754 *format; 755 756 char 757 *text; 758 759 format="%w,%h,%m"; // Get this from image_info Option splaytree 760 761 text=InterpretImageProperties(image_info,cli_wand->wand.images,format, 762 exception); 763 if (text == (char *) NULL) 764 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, 765 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno)); 766 else { 767 (void) ConcatenateString(&(*metadata),text); 768 text=DestroyString(text); 769 } 770 } 771 772Magick_Command_Exit: 773 /* Destroy the special CLI Wand */ 774 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */ 775 cli_wand->wand.exception = (ExceptionInfo *)NULL; 776 cli_wand=DestroyMagickCLI(cli_wand); 777 778 return(IsMagickTrue(exception->severity > ErrorException)); 779} 780