magick-cli.c revision 45ef08fd6a09813e4a8f5ddadf85ba9e0ec2cdc7
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-2013 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/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" 60 61/* verbose debugging, 62 3 - option type details 63 5 - include image counts 64*/ 65#define MagickCommandDebug 0 66 67 68/* 69%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 70% % 71% % 72% % 73+ P r o c e s s S c r i p t O p t i o n s % 74% % 75% % 76% % 77%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 78% 79% ProcessScriptOptions() reads options and processes options as they are 80% found in the given file, or pipeline. The filename to open and read 81% options is given as the 'index' argument of the argument array given. 82% 83% Other arguments following index may be read by special script options 84% as settings (strings), images, or as operations to be processed in various 85% ways. How they are treated is up to the script being processed. 86% 87% Note that a script not 'return' to the command line processing, nor can 88% they call (and return from) other scripts. At least not at this time. 89% 90% There are no 'ProcessOptionFlags' control flags at this time. 91% 92% The format of the ProcessScriptOptions method is: 93% 94% void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv, 95% int index) 96% 97% A description of each parameter follows: 98% 99% o cli_wand: the main CLI Wand to use. 100% 101% o argc: the number of elements in the argument vector. 102% 103% o argv: A text array containing the command line arguments. 104% 105% o index: offset for argc to CLI argumnet count 106% 107*/ 108WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv, 109 int index) 110{ 111 ScriptTokenInfo 112 *token_info; 113 114 CommandOptionFlags 115 option_type; 116 117 int 118 count; 119 120 char 121 *option, 122 *arg1, 123 *arg2; 124 125 assert(argc>index); /* at least one argument - script name */ 126 assert(argv != (char **)NULL); 127 assert(argv[index] != (char *)NULL); 128 assert(argv[argc-1] != (char *)NULL); 129 assert(cli_wand != (MagickCLI *) NULL); 130 assert(cli_wand->signature == WandSignature); 131 if (cli_wand->wand.debug != MagickFalse) 132 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 133 134 /* open file script or stream, and set up tokenizer */ 135 token_info = AcquireScriptTokenInfo(argv[index]); 136 if (token_info == (ScriptTokenInfo *) NULL) { 137 CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",argv[index]); 138 return; 139 } 140 141 /* define the error location string for use in exceptions 142 order of localtion format escapes: filename, line, column */ 143 cli_wand->location="in \"%s\" at line %u,column %u"; 144 if ( LocaleCompare("-", argv[index]) == 0 ) 145 cli_wand->filename="stdin"; 146 else 147 cli_wand->filename=argv[index]; 148 149 /* Process Options from Script */ 150 option = arg1 = arg2 = (char*)NULL; 151 while (1) { 152 153 { MagickBooleanType status = GetScriptToken(token_info); 154 cli_wand->line=token_info->token_line; 155 cli_wand->column=token_info->token_column; 156 if( IfMagickFalse(status) ) 157 break; /* error or end of options */ 158 } 159 160 do { /* use break to loop to exception handler and loop */ 161 162 /* save option details */ 163 CloneString(&option,token_info->token); 164 165 /* get option, its argument count, and option type */ 166 cli_wand->command = GetCommandOptionInfo(option); 167 count=cli_wand->command->type; 168 option_type=(CommandOptionFlags) cli_wand->command->flags; 169#if 0 170 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n", 171 cli_wand->line, cli_wand->line, option, cli_wand->command->mnemonic ); 172#endif 173 174 /* handle a undefined option - image read - always for "magick-script" */ 175 if ( option_type == UndefinedOptionFlag || 176 (option_type & NonMagickOptionFlag) != 0 ) { 177#if MagickCommandDebug >= 3 178 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n", 179 cli_wand->line, cli_wand->line, option); 180#endif 181 if ( IfMagickFalse(IsCommandOption(option))) { 182 /* non-option -- treat as a image read */ 183 cli_wand->command=(const OptionInfo *)NULL; 184 CLIOption(cli_wand,"-read",option); 185 break; /* next option */ 186 } 187 CLIWandException(OptionFatalError,"UnrecognizedOption",option); 188 break; /* next option */ 189 } 190 191 if ( count >= 1 ) { 192 if( IfMagickFalse(GetScriptToken(token_info)) ) 193 CLIWandException(OptionFatalError,"MissingArgument",option); 194 CloneString(&arg1,token_info->token); 195 } 196 else 197 CloneString(&arg1,(char *)NULL); 198 199 if ( count >= 2 ) { 200 if( IfMagickFalse(GetScriptToken(token_info)) ) 201 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option); 202 CloneString(&arg2,token_info->token); 203 } 204 else 205 CloneString(&arg2,(char *)NULL); 206 207 /* 208 Process Options 209 */ 210#if MagickCommandDebug >= 3 211 (void) FormatLocaleFile(stderr, 212 "Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n", 213 cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2); 214#endif 215 /* Hard Depreciated Options, no code to execute - error */ 216 if ( (option_type & DeprecateOptionFlag) != 0 ) { 217 CLIWandException(OptionError,"DeprecatedOptionNoCode",option); 218 break; /* next option */ 219 } 220 221 /* MagickCommandGenesis() options have no place in a magick script */ 222 if ( (option_type & GenesisOptionFlag) != 0 ) { 223 CLIWandException(OptionError,"InvalidUseOfOption",option); 224 break; /* next option */ 225 } 226 227 /* handle any special 'script' options */ 228 if ( (option_type & SpecialOptionFlag) != 0 ) { 229 if ( LocaleCompare(option,"-exit") == 0 ) { 230 goto loop_exit; /* break out of loop - return from script */ 231 } 232 if ( LocaleCompare(option,"-script") == 0 ) { 233 /* FUTURE: call new script from this script - error for now */ 234 CLIWandException(OptionError,"InvalidUseOfOption",option); 235 break; /* next option */ 236 } 237 /* FUTURE: handle special script-argument options here */ 238 /* handle any other special operators now */ 239 CLIWandException(OptionError,"InvalidUseOfOption",option); 240 break; /* next option */ 241 } 242 243 /* Process non-specific Option */ 244 CLIOption(cli_wand, option, arg1, arg2); 245 246 } while (0); /* break block to next option */ 247 248#if MagickCommandDebug >= 5 249 fprintf(stderr, "Script Image Count = %ld\n", 250 GetImageListLength(cli_wand->wand.images) ); 251#endif 252 if ( IfMagickTrue(CLICatchException(cli_wand, MagickFalse)) ) 253 break; /* exit loop */ 254 } 255 256 /* 257 Loop exit - check for some tokenization error 258 */ 259loop_exit: 260#if MagickCommandDebug >= 3 261 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status); 262#endif 263 switch( token_info->status ) { 264 case TokenStatusOK: 265 case TokenStatusEOF: 266 if (cli_wand->image_list_stack != (Stack *)NULL) 267 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)"); 268 else if (cli_wand->image_info_stack != (Stack *)NULL) 269 CLIWandException(OptionError,"UnbalancedBraces", "(eof)"); 270 break; 271 case TokenStatusBadQuotes: 272 /* Ensure last token has a sane length for error report */ 273 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) { 274 token_info->token[INITAL_TOKEN_LENGTH-4] = '.'; 275 token_info->token[INITAL_TOKEN_LENGTH-3] = '.'; 276 token_info->token[INITAL_TOKEN_LENGTH-2] = '.'; 277 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0'; 278 } 279 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes", 280 token_info->token); 281 break; 282 case TokenStatusMemoryFailed: 283 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed",""); 284 break; 285 case TokenStatusBinary: 286 CLIWandException(OptionFatalError,"ScriptIsBinary",""); 287 break; 288 } 289 290 /* Clean up */ 291 token_info = DestroyScriptTokenInfo(token_info); 292 293 CloneString(&option,(char *)NULL); 294 CloneString(&arg1,(char *)NULL); 295 CloneString(&arg2,(char *)NULL); 296 297 return; 298} 299 300/* 301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 302% % 303% % 304% % 305+ P r o c e s s C o m m a n d O p t i o n s % 306% % 307% % 308% % 309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 310% 311% ProcessCommandOptions() reads and processes arguments in the given 312% command line argument array. The array does not contain the command 313% being processed, only the options. 314% 315% The 'process_flags' can be used to control and limit option processing. 316% For example, to only process one option, or how unknown and special options 317% are to be handled, and if the last argument in array is to be regarded as a 318% final image write argument (filename or special coder). 319% 320% The format of the ProcessCommandOptions method is: 321% 322% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv, 323% int index, ProcessOptionFlags process_flags ) 324% 325% A description of each parameter follows: 326% 327% o cli_wand: the main CLI Wand to use. 328% 329% o argc: the number of elements in the argument vector. 330% 331% o argv: A text array containing the command line arguments. 332% 333% o process_flags: What type of arguments will be processed, ignored 334% or return errors. 335% 336% o index: index in the argv array to start processing from 337% 338% The function returns the index ot the next option to be processed. This 339% is really only releven if process_flags contains a ProcessOneOptionOnly 340% flag. 341% 342*/ 343WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc, 344 char **argv, int index ) 345{ 346 const char 347 *option, 348 *arg1, 349 *arg2; 350 351 int 352 i, 353 end, 354 count; 355 356 CommandOptionFlags 357 option_type; 358 359 assert(argc>=index); /* you may have no arguments left! */ 360 assert(argv != (char **)NULL); 361 assert(argv[index] != (char *)NULL); 362 assert(argv[argc-1] != (char *)NULL); 363 assert(cli_wand != (MagickCLI *) NULL); 364 assert(cli_wand->signature == WandSignature); 365 if (cli_wand->wand.debug != MagickFalse) 366 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 367 368 /* define the error location string for use in exceptions 369 order of localtion format escapes: filename, line, column */ 370 cli_wand->location="at %s argument %u"; 371 cli_wand->filename="CLI"; 372 373 end = argc; 374 if ( (cli_wand->process_flags & ProcessImplictWrite) != 0 ) 375 end--; /* the last arument is an implied write, do not process directly */ 376 377 for (i=index; i < end; i += count +1) { 378 /* Finished processing one option? */ 379 if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index ) 380 return(i); 381 382 do { /* use break to loop to exception handler and loop */ 383 384 option=argv[i]; 385 cli_wand->line=i; /* note the argument for this option */ 386 387 /* get option, its argument count, and option type */ 388 cli_wand->command = GetCommandOptionInfo(argv[i]); 389 count=cli_wand->command->type; 390 option_type=(CommandOptionFlags) cli_wand->command->flags; 391#if 0 392 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n", 393 i, argv[i], cli_wand->command->mnemonic ); 394#endif 395 396 if ( option_type == UndefinedOptionFlag || 397 (option_type & NonMagickOptionFlag) != 0 ) { 398#if MagickCommandDebug >= 3 399 (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option); 400#endif 401 if ( IfMagickFalse(IsCommandOption(option)) ) { 402 if ( (cli_wand->process_flags & ProcessImplictRead) != 0 ) { 403 /* non-option -- treat as a image read */ 404 cli_wand->command=(const OptionInfo *)NULL; 405 CLIOption(cli_wand,"-read",option); 406 break; /* next option */ 407 } 408 } 409 CLIWandException(OptionFatalError,"UnrecognizedOption",option); 410 break; /* next option */ 411 } 412 413 if ( ((option_type & SpecialOptionFlag) != 0 ) && 414 ((cli_wand->process_flags & ProcessScriptOption) != 0) && 415 (LocaleCompare(option,"-script") == 0) ) { 416 /* Call Script from CLI, with a filename as a zeroth argument. 417 NOTE: -script may need to use the 'implict write filename' argument 418 so it must be handled specially to prevent a 'missing argument' error. 419 */ 420 if ( (i+count) >= argc ) 421 CLIWandException(OptionFatalError,"MissingArgument",option); 422 ProcessScriptOptions(cli_wand,argc,argv,i+1); 423 return(argc); /* Script does not return to CLI -- Yet */ 424 /* FUTURE: when it does, their may be no write arg! */ 425 } 426 427 if ((i+count) >= end ) { 428 CLIWandException(OptionFatalError,"MissingArgument",option); 429 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 430 return(end); 431 break; /* next option - not that their is any! */ 432 } 433 434 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL; 435 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL; 436 437 /* 438 Process Known Options 439 */ 440#if MagickCommandDebug >= 3 441 (void) FormatLocaleFile(stderr, 442 "CLI %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n", 443 i,option,count,option_type,arg1,arg2); 444#endif 445 446 /* ignore 'genesis options' in command line args */ 447 if ( (option_type & GenesisOptionFlag) != 0 ) 448 break; /* next option */ 449 450 /* Handle any special options for CLI (-script handled above) */ 451 if ( (option_type & SpecialOptionFlag) != 0 ) { 452 if ( (cli_wand->process_flags & ProcessExitOption) != 0 453 && LocaleCompare(option,"-exit") == 0 ) 454 return(i+count); 455 break; /* next option */ 456 } 457 458 /* Process standard image option */ 459 CLIOption(cli_wand, option, arg1, arg2); 460 461 } while (0); /* break block to next option */ 462 463#if MagickCommandDebug >= 5 464 fprintf(stderr, "CLI Image Count = %ld\n", 465 GetImageListLength(cli_wand->wand.images) ); 466#endif 467 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 468 return(i+count); 469 } 470 assert(i==end); 471 472 if ( (cli_wand->process_flags & ProcessImplictWrite) == 0 ) 473 return(end); /* no implied write -- just return to caller */ 474 475 assert(end==argc-1); /* end should not include last argument */ 476 477 /* 478 Implicit Write of images to final CLI argument 479 */ 480 option=argv[i]; 481 cli_wand->line=i; 482 483 /* check that stacks are empty - or cause exception */ 484 if (cli_wand->image_list_stack != (Stack *)NULL) 485 CLIWandException(OptionError,"UnbalancedParenthesis", "(end of cli)"); 486 else if (cli_wand->image_info_stack != (Stack *)NULL) 487 CLIWandException(OptionError,"UnbalancedBraces", "(end of cli)"); 488 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse ) 489 return(argc); 490 491#if MagickCommandDebug >= 3 492 (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option ); 493#endif 494 495 /* Valid 'do no write' replacement option (instead of "null:") */ 496 if (LocaleCompare(option,"-exit") == 0 ) 497 return(argc); /* just exit, no image write */ 498 499 /* If filename looks like an option, 500 Or the common 'end of line' error of a single space. 501 -- produce an error */ 502 if (IfMagickTrue(IsCommandOption(option)) || 503 (option[0] == ' ' && option[1] == '\0') ) { 504 CLIWandException(OptionError,"MissingOutputFilename",option); 505 return(argc); 506 } 507 508 cli_wand->command=(const OptionInfo *)NULL; 509 CLIOption(cli_wand,"-write",option); 510 return(argc); 511} 512 513/* 514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 515% % 516% % 517% % 518+ M a g i c k I m a g e C o m m a n d % 519% % 520% % 521% % 522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 523% 524% MagickImageCommand() Handle special use CLI arguments and prepare a 525% CLI MagickCLI to process the command line or directly specified script. 526% 527% This is essentualy interface function between the MagickCore library 528% initialization function MagickCommandGenesis(), and the option MagickCLI 529% processing functions ProcessCommandOptions() or ProcessScriptOptions() 530% 531% The format of the MagickImageCommand method is: 532% 533% MagickBooleanType MagickImageCommand(ImageInfo *image_info, 534% int argc, char **argv, char **metadata, ExceptionInfo *exception) 535% 536% A description of each parameter follows: 537% 538% o image_info: the starting image_info structure 539% (for compatibilty with MagickCommandGenisis()) 540% 541% o argc: the number of elements in the argument vector. 542% 543% o argv: A text array containing the command line arguments. 544% 545% o metadata: any metadata (for VBS) is returned here. 546% (for compatibilty with MagickCommandGenisis()) 547% 548% o exception: return any errors or warnings in this structure. 549% 550*/ 551 552static void MagickUsage(MagickBooleanType verbose) 553{ 554 const char 555 *name; 556 557 size_t 558 len; 559 560 name=GetClientName(); 561 len=strlen(name); 562 563 if (len>=7 && LocaleCompare("convert",name+len-7) == 0) { 564 /* convert usage */ 565 (void) FormatLocaleFile(stdout, 566 "Usage: %s [{option}|{image}...] {output_image}\n",name); 567 (void) FormatLocaleFile(stdout, 568 " %s -help|-version|-usage|-list {option}\n\n",name); 569 return; 570 } 571 else if (len>=6 && LocaleCompare("script",name+len-6) == 0) { 572 /* magick-script usage */ 573 (void) FormatLocaleFile(stdout, 574 "Usage: %s {filename} [{script_args}...]\n",name); 575 } 576 else { 577 /* magick usage */ 578 (void) FormatLocaleFile(stdout, 579 "Usage: %s [{option}|{image}...] {output_image}\n",name); 580 (void) FormatLocaleFile(stdout, 581 " %s [{option}|{image}...] -script {filename} [{script_args}...]\n", 582 name); 583 } 584 (void) FormatLocaleFile(stdout, 585 " %s -help|-version|-usage|-list {option}\n\n",name); 586 587 if (IfMagickFalse(verbose)) 588 return; 589 590 (void) FormatLocaleFile(stdout,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", 591 "All options are performed in a strict 'as you see them' order\n", 592 "You must read-in images before you can operate on them.\n", 593 "\n", 594 "Magick Script files can use any of the following forms...\n", 595 " #!/path/to/magick -script\n", 596 "or\n", 597 " #!/bin/sh\n", 598 " :; exec magick -script \"$0\" \"$@\"; exit 10\n", 599 " # Magick script from here...\n", 600 "or\n", 601 " #!/usr/bin/env magick-script\n", 602 "The latter two forms do not require the path to the command hard coded.\n", 603 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n", 604 "\n", 605 "For more information on usage, options, examples, and techniques\n", 606 "see the ImageMagick website at ", MagickAuthoritativeURL); 607 608 return; 609} 610 611/* 612 Concatanate given file arguments to the given output argument. 613 Used for a special -concatenate option used for specific 'delegates'. 614 The option is not formally documented. 615 616 magick -concatenate files... output 617 618 This is much like the UNIX "cat" command, but for both UNIX and Windows, 619 however the last argument provides the output filename. 620*/ 621static MagickBooleanType ConcatenateImages(int argc,char **argv, 622 ExceptionInfo *exception ) 623{ 624 FILE 625 *input, 626 *output; 627 628 int 629 c; 630 631 register ssize_t 632 i; 633 634 if (IfMagickFalse( ExpandFilenames(&argc,&argv) )) 635 ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed", 636 GetExceptionMessage(errno)); 637 638 output=fopen_utf8(argv[argc-1],"wb"); 639 if (output == (FILE *) NULL) { 640 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[argc-1]); 641 return(MagickFalse); 642 } 643 for (i=2; i < (ssize_t) (argc-1); i++) { 644#if 0 645 fprintf(stderr, "DEBUG: Concatenate Image: \"%s\"\n", argv[i]); 646#endif 647 input=fopen_utf8(argv[i],"rb"); 648 if (input == (FILE *) NULL) { 649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]); 650 continue; 651 } 652 for (c=fgetc(input); c != EOF; c=fgetc(input)) 653 (void) fputc((char) c,output); 654 (void) fclose(input); 655 (void) remove_utf8(argv[i]); 656 } 657 (void) fclose(output); 658 return(MagickTrue); 659} 660 661WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info, 662 int argc,char **argv,char **metadata,ExceptionInfo *exception) 663{ 664 MagickCLI 665 *cli_wand; 666 667 size_t 668 len; 669 670 /* For specific OS command line requirements */ 671 ReadCommandlLine(argc,&argv); 672 673 /* Initialize special "CLI Wand" to hold images and settings (empty) */ 674 cli_wand=AcquireMagickCLI(image_info,exception); 675 cli_wand->line=1; 676 677 GetPathComponent(argv[0],TailPath,cli_wand->wand.name); 678 SetClientName(cli_wand->wand.name); 679 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent); 680 681 len=strlen(argv[0]); /* precaution */ 682 683 /* "convert" command - give a "depreciation" warning" */ 684 if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) { 685 cli_wand->process_flags = ConvertCommandOptionFlags; 686 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n", 687 "The convert is depreciated in IMv7, use \"magick\"\n");*/ 688 } 689 690 /* Special Case: If command name ends with "script" implied "-script" */ 691 if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) { 692 if (argc >= 2 && ( (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) { 693 GetPathComponent(argv[1],TailPath,cli_wand->wand.name); 694 ProcessScriptOptions(cli_wand,argc,argv,1); 695 goto Magick_Command_Cleanup; 696 } 697 } 698 699 /* Special Case: Version Information and Abort */ 700 if (argc == 2) { 701 if (LocaleCompare("-version",argv[1]) == 0) { /* just version */ 702 CLIOption(cli_wand, "-version"); 703 goto Magick_Command_Exit; 704 } 705 if ((LocaleCompare("-help",argv[1]) == 0) || /* GNU standard option */ 706 (LocaleCompare("--help",argv[1]) == 0) ) { /* just a brief summary */ 707 MagickUsage(MagickFalse); 708 goto Magick_Command_Exit; 709 } 710 if (LocaleCompare("-usage",argv[1]) == 0) { /* both version & usage */ 711 CLIOption(cli_wand, "-version" ); 712 MagickUsage(MagickTrue); 713 goto Magick_Command_Exit; 714 } 715 } 716 717 /* not enough arguments -- including -help */ 718 if (argc < 3) { 719 (void) FormatLocaleFile(stderr, 720 "Error: Invalid argument or not enough arguments\n\n"); 721 MagickUsage(MagickFalse); 722 goto Magick_Command_Exit; 723 } 724 725 /* Special "concatenate option (hidden) for delegate usage */ 726 if (LocaleCompare("-concatenate",argv[1]) == 0) { 727 ConcatenateImages(argc,argv,exception); 728 goto Magick_Command_Exit; 729 } 730 731 /* List Information and Abort */ 732 if (argc == 3 && LocaleCompare("-list",argv[1]) == 0) { 733 CLIOption(cli_wand, argv[1], argv[2]); 734 goto Magick_Command_Exit; 735 } 736 737 /* ------------- */ 738 /* The Main Call */ 739 740 if (LocaleCompare("-script",argv[1]) == 0) { 741 /* Start processing directly from script, no pre-script options 742 Replace wand command name with script name 743 First argument in the argv array is the script name to read. 744 */ 745 GetPathComponent(argv[2],TailPath,cli_wand->wand.name); 746 ProcessScriptOptions(cli_wand,argc,argv,2); 747 } 748 else { 749 /* Normal Command Line, assumes output file as last option */ 750 ProcessCommandOptions(cli_wand,argc,argv,1); 751 } 752 /* ------------- */ 753 754Magick_Command_Cleanup: 755 /* recover original image_info and clean up stacks 756 FUTURE: "-reset stacks" option */ 757 while (cli_wand->image_list_stack != (Stack *)NULL) 758 CLIOption(cli_wand,")"); 759 while (cli_wand->image_info_stack != (Stack *)NULL) 760 CLIOption(cli_wand,"}"); 761 762 /* assert we have recovered the original structures */ 763 assert(cli_wand->wand.image_info == image_info); 764 assert(cli_wand->wand.exception == exception); 765 766 /* Handle metadata for ImageMagickObject COM object for Windows VBS */ 767 if (metadata != (char **) NULL) { 768 const char 769 *format; 770 771 char 772 *text; 773 774 format="%w,%h,%m"; // Get this from image_info Option splaytree 775 776 text=InterpretImageProperties(image_info,cli_wand->wand.images,format, 777 exception); 778 if (text == (char *) NULL) 779 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, 780 "MemoryAllocationFailed","'%s'", GetExceptionMessage(errno)); 781 else { 782 (void) ConcatenateString(&(*metadata),text); 783 text=DestroyString(text); 784 } 785 } 786 787Magick_Command_Exit: 788 /* Destroy the special CLI Wand */ 789 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */ 790 cli_wand->wand.exception = (ExceptionInfo *)NULL; 791 cli_wand=DestroyMagickCLI(cli_wand); 792 793 return(IsMagickTrue(exception->severity > ErrorException)); 794} 795