MagickWand  6.7.7
magick-cli.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                 M   M   AAA    GGGG  IIIII   CCCC  K   K                    %
00007 %                 MM MM  A   A  G        I    C      K  K                     %
00008 %                 M M M  AAAAA  G GGG    I    C      KKK                      %
00009 %                 M   M  A   A  G   G    I    C      K  K                     %
00010 %                 M   M  A   A   GGGG  IIIII   CCCC  K   K                    %
00011 %                                                                             %
00012 %                            CCCC  L      IIIII                               %
00013 %                           C      L        I                                 %
00014 %                           C      L        I                                 %
00015 %                           C      L        I                                 %
00016 %                            CCCC  LLLLL  IIIII                               %
00017 %                                                                             %
00018 %       Perform "Magick" on Images via the Command Line Interface             %
00019 %                                                                             %
00020 %                             Dragon Computing                                %
00021 %                             Anthony Thyssen                                 %
00022 %                               January 2012                                  %
00023 %                                                                             %
00024 %                                                                             %
00025 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00026 %  dedicated to making software imaging solutions freely available.           %
00027 %                                                                             %
00028 %  You may not use this file except in compliance with the License.  You may  %
00029 %  obtain a copy of the License at                                            %
00030 %                                                                             %
00031 %    http://www.imagemagick.org/script/license.php                            %
00032 %                                                                             %
00033 %  Unless required by applicable law or agreed to in writing, software        %
00034 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00035 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00036 %  See the License for the specific language governing permissions and        %
00037 %  limitations under the License.                                             %
00038 %                                                                             %
00039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00040 %
00041 %  Read CLI arguments, script files, and pipelines, to provide options that
00042 %  manipulate images from many different formats.
00043 %
00044 */
00045 
00046 /*
00047   Include declarations.
00048 */
00049 #include "MagickWand/studio.h"
00050 #include "MagickWand/MagickWand.h"
00051 #include "MagickWand/magick-wand-private.h"
00052 #include "MagickWand/wandcli.h"
00053 #include "MagickWand/wandcli-private.h"
00054 #include "MagickWand/operation.h"
00055 #include "MagickWand/magick-cli.h"
00056 #include "MagickWand/script-token.h"
00057 #include "MagickCore/utility-private.h"
00058 #include "MagickCore/exception-private.h"
00059 #include "MagickCore/version.h"
00060 
00061 /* verbose debugging,
00062       3 - option type details
00063       9 - output options/artifacts/propertys
00064 */
00065 #define MagickCommandDebug 0
00066 
00067 #if MagickCommandDebug >= 9
00068 /*
00069   Temporary Debugging Information
00070   FUTURE: these should be able to be printed out using 'percent escapes'
00071   Actually 'Properities' can already be output with  "%[*]"
00072 */
00073 static void OutputOptions(ImageInfo *image_info)
00074 {
00075   const char
00076     *option,
00077     *value;
00078 
00079   (void) FormatLocaleFile(stderr,"  Global Options:\n");
00080   ResetImageOptionIterator(image_info);
00081   while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) {
00082     (void) FormatLocaleFile(stderr,"    %s: ",option);
00083     value=GetImageOption(image_info,option);
00084     if (value != (const char *) NULL)
00085       (void) FormatLocaleFile(stderr,"%s\n",value);
00086   }
00087   ResetImageOptionIterator(image_info);
00088 }
00089 
00090 static void OutputArtifacts(Image *image)
00091 {
00092   const char
00093     *artifact,
00094     *value;
00095 
00096   (void) FormatLocaleFile(stderr,"  Image Artifacts:\n");
00097   ResetImageArtifactIterator(image);
00098   while ((artifact=GetNextImageArtifact(image)) != (const char *) NULL ) {
00099     (void) FormatLocaleFile(stderr,"    %s: ",artifact);
00100     value=GetImageArtifact(image,artifact);
00101     if (value != (const char *) NULL)
00102       (void) FormatLocaleFile(stderr,"%s\n",value);
00103   }
00104   ResetImageArtifactIterator(image);
00105 }
00106 
00107 static void OutputProperties(Image *image,ExceptionInfo *exception)
00108 {
00109   const char
00110     *property,
00111     *value;
00112 
00113   (void) FormatLocaleFile(stderr,"  Image Properity:\n");
00114   ResetImagePropertyIterator(image);
00115   while ((property=GetNextImageProperty(image)) != (const char *) NULL ) {
00116     (void) FormatLocaleFile(stderr,"    %s: ",property);
00117     value=GetImageProperty(image,property,exception);
00118     if (value != (const char *) NULL)
00119       (void) FormatLocaleFile(stderr,"%s\n",value);
00120   }
00121   ResetImagePropertyIterator(image);
00122 }
00123 #endif
00124 
00125 
00126 /*
00127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00128 %                                                                             %
00129 %                                                                             %
00130 %                                                                             %
00131 +   P r o c e s s S c r i p t O p t i o n s                                   %
00132 %                                                                             %
00133 %                                                                             %
00134 %                                                                             %
00135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00136 %
00137 %  ProcessScriptOptions() reads options and processes options as they are
00138 %  found in the given file, or pipeline.  The filename to open and read
00139 %  options is given as the 'index' argument of the argument array given.
00140 %
00141 %  Other arguments following index may be read by special script options
00142 %  as settings (strings), images, or as operations to be processed in various
00143 %  ways.   How they are treated is up to the script being processed.
00144 %
00145 %  Note that a script not 'return' to the command line processing, nor can
00146 %  they call (and return from) other scripts. At least not at this time.
00147 %
00148 %  There are no 'ProcessOptionFlags' control flags at this time.
00149 %
00150 %  The format of the ProcessScriptOptions method is:
00151 %
00152 %    void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
00153 %               int index)
00154 %
00155 %  A description of each parameter follows:
00156 %
00157 %    o cli_wand: the main CLI Wand to use.
00158 %
00159 %    o argc: the number of elements in the argument vector.
00160 %
00161 %    o argv: A text array containing the command line arguments.
00162 %
00163 %    o index: offset for argc to CLI argumnet count
00164 %
00165 */
00166 WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
00167      int index)
00168 {
00169   ScriptTokenInfo
00170     *token_info;
00171 
00172   CommandOptionFlags
00173     option_type;
00174 
00175   int
00176     count;
00177 
00178   char
00179     *option,
00180     *arg1,
00181     *arg2;
00182 
00183   assert(argc>index); /* at least one argument - script name */
00184   assert(argv != (char **)NULL);
00185   assert(argv[index] != (char *)NULL);
00186   assert(argv[argc-1] != (char *)NULL);
00187   assert(cli_wand != (MagickCLI *) NULL);
00188   assert(cli_wand->signature == WandSignature);
00189   if (cli_wand->wand.debug != MagickFalse)
00190     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
00191 
00192   /* open file script or stream, and set up tokenizer */
00193   token_info = AcquireScriptTokenInfo(argv[index]);
00194   if (token_info == (ScriptTokenInfo *) NULL) {
00195     CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",argv[index]);
00196     return;
00197   }
00198 
00199   /* define the error location string for use in exceptions
00200      order of localtion format escapes: filename, line, column */
00201   cli_wand->location="in \"%s\" at line %u,column %u";
00202   if ( LocaleCompare("-", argv[index]) == 0 )
00203     cli_wand->filename="stdin";
00204   else
00205     cli_wand->filename=argv[index];
00206 
00207   /* Process Options from Script */
00208   option = arg1 = arg2 = (char*)NULL;
00209   while (1) {
00210 
00211     { MagickBooleanType status = GetScriptToken(token_info);
00212       cli_wand->line=token_info->token_line;
00213       cli_wand->column=token_info->token_column;
00214       if( IfMagickFalse(status) )
00215         break; /* error or end of options */
00216     }
00217 
00218     do { /* use break to loop to exception handler and loop */
00219 
00220       /* save option details */
00221       CloneString(&option,token_info->token);
00222 
00223       /* get option, its argument count, and option type */
00224       cli_wand->command = GetCommandOptionInfo(option);
00225       count=cli_wand->command->type;
00226       option_type=(CommandOptionFlags) cli_wand->command->flags;
00227 #if 0
00228       (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
00229           cli_wand->line, cli_wand->line, option, cli_wand->command->mnemonic );
00230 #endif
00231 
00232       /* handle a undefined option - image read - always for "magick-script" */
00233       if ( option_type == UndefinedOptionFlag ||
00234            (option_type & NonMagickOptionFlag) != 0 ) {
00235 #if MagickCommandDebug >= 3
00236         (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
00237                     cli_wand->line, cli_wand->line, option);
00238 #endif
00239         if ( IfMagickFalse(IsCommandOption(option))) {
00240           /* non-option -- treat as a image read */
00241           cli_wand->command=(const OptionInfo *)NULL;
00242           CLIOption(cli_wand,"-read",option);
00243           break; /* next option */
00244         }
00245         CLIWandException(OptionFatalError,"UnrecognizedOption",option);
00246         break; /* next option */
00247       }
00248 
00249       if ( count >= 1 ) {
00250         if( IfMagickFalse(GetScriptToken(token_info)) )
00251           CLIWandException(OptionFatalError,"MissingArgument",option);
00252         CloneString(&arg1,token_info->token);
00253       }
00254       else
00255         CloneString(&arg1,(char *)NULL);
00256 
00257       if ( count >= 2 ) {
00258         if( IfMagickFalse(GetScriptToken(token_info)) )
00259           CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
00260         CloneString(&arg2,token_info->token);
00261       }
00262       else
00263         CloneString(&arg2,(char *)NULL);
00264 
00265       /*
00266         Process Options
00267       */
00268 #if MagickCommandDebug >= 3
00269       (void) FormatLocaleFile(stderr,
00270         "Script %u,%u Option: \"%s\"  Count: %d  Flags: %04x  Args: \"%s\" \"%s\"\n",
00271             cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
00272 #endif
00273       /* Hard Depreciated Options, no code to execute - error */
00274       if ( (option_type & DeprecateOptionFlag) != 0 ) {
00275         CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
00276         break; /* next option */
00277       }
00278 
00279       /* MagickCommandGenesis() options have no place in a magick script */
00280       if ( (option_type & GenesisOptionFlag) != 0 ) {
00281         CLIWandException(OptionError,"InvalidUseOfOption",option);
00282         break; /* next option */
00283       }
00284 
00285       /* handle any special 'script' options */
00286       if ( (option_type & SpecialOptionFlag) != 0 ) {
00287         if ( LocaleCompare(option,"-exit") == 0 ) {
00288           break; /* forced end of script */
00289         }
00290         if ( LocaleCompare(option,"-script") == 0 ) {
00291           /* FUTURE: call new script from this script - error for now */
00292           CLIWandException(OptionError,"InvalidUseOfOption",option);
00293           break; /* next option */
00294         }
00295         /* FUTURE: handle special script-argument options here */
00296         /* handle any other special operators now */
00297         CLIWandException(OptionError,"InvalidUseOfOption",option);
00298         break; /* next option */
00299       }
00300 
00301       /* Process non-specific Option */
00302       CLIOption(cli_wand, option, arg1, arg2);
00303 
00304     } while (0); /* break block to next option */
00305 
00306 #if MagickCommandDebug >= 9
00307     OutputOptions(cli_wand->wand.image_info);
00308     if ( cli_wand->wand.images != (Image *)NULL ) {
00309       OutputArtifacts(cli_wand->wand.images);
00310       OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
00311     }
00312 #endif
00313     if ( IfMagickTrue(CLICatchException(cli_wand, MagickFalse)) )
00314       break;  /* exit loop */
00315   }
00316 
00317   /*
00318      Loop exit - check for some tokenization error
00319   */
00320 #if MagickCommandDebug >= 3
00321   (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
00322 #endif
00323   switch( token_info->status ) {
00324     case TokenStatusOK:
00325     case TokenStatusEOF:
00326       if (cli_wand->image_list_stack != (Stack *)NULL)
00327         CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
00328       else if (cli_wand->image_info_stack != (Stack *)NULL)
00329         CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
00330       break;
00331     case TokenStatusBadQuotes:
00332       /* Ensure last token has a sane length for error report */
00333       if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
00334         token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
00335         token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
00336         token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
00337         token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
00338       }
00339       CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
00340            token_info->token);
00341       break;
00342     case TokenStatusMemoryFailed:
00343       CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
00344       break;
00345     case TokenStatusBinary:
00346       CLIWandException(OptionFatalError,"ScriptIsBinary","");
00347       break;
00348   }
00349 
00350   /* Clean up */
00351   token_info = DestroyScriptTokenInfo(token_info);
00352 
00353   CloneString(&option,(char *)NULL);
00354   CloneString(&arg1,(char *)NULL);
00355   CloneString(&arg2,(char *)NULL);
00356 
00357   return;
00358 }
00359 
00360 /*
00361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00362 %                                                                             %
00363 %                                                                             %
00364 %                                                                             %
00365 +  P r o c e s s C o m m a n d O p t i o n s                                  %
00366 %                                                                             %
00367 %                                                                             %
00368 %                                                                             %
00369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00370 %
00371 %  ProcessCommandOptions() reads and processes arguments in the given
00372 %  command line argument array. The array does not contain the command
00373 %  being processed, only the options.
00374 %
00375 %  The 'process_flags' can be used to control and limit option processing.
00376 %  For example, to only process one option, or how unknown and special options
00377 %  are to be handled, and if the last argument in array is to be regarded as a
00378 %  final image write argument (filename or special coder).
00379 %
00380 %  The format of the ProcessCommandOptions method is:
00381 %
00382 %    int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
00383 %           int index, ProcessOptionFlags process_flags )
00384 %
00385 %  A description of each parameter follows:
00386 %
00387 %    o cli_wand: the main CLI Wand to use.
00388 %
00389 %    o argc: the number of elements in the argument vector.
00390 %
00391 %    o argv: A text array containing the command line arguments.
00392 %
00393 %    o process_flags: What type of arguments will be processed, ignored
00394 %                     or return errors.
00395 %
00396 %    o index: index in the argv array to start processing from
00397 %
00398 % The function returns the index ot the next option to be processed. This
00399 % is really only releven if process_flags contains a ProcessOneOptionOnly
00400 % flag.
00401 %
00402 */
00403 WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc,
00404      char **argv, int index )
00405 {
00406   const char
00407     *option,
00408     *arg1,
00409     *arg2;
00410 
00411   int
00412     i,
00413     end,
00414     count;
00415 
00416   CommandOptionFlags
00417     option_type;
00418 
00419   assert(argc>=index); /* you may have no arguments left! */
00420   assert(argv != (char **)NULL);
00421   assert(argv[index] != (char *)NULL);
00422   assert(argv[argc-1] != (char *)NULL);
00423   assert(cli_wand != (MagickCLI *) NULL);
00424   assert(cli_wand->signature == WandSignature);
00425   if (cli_wand->wand.debug != MagickFalse)
00426     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
00427 
00428   /* define the error location string for use in exceptions
00429      order of localtion format escapes: filename, line, column */
00430   cli_wand->location="at %s argument %u";
00431   cli_wand->filename="CLI";
00432 
00433   end = argc;
00434   if ( (cli_wand->process_flags & ProcessImplictWrite) != 0 )
00435     end--; /* the last arument is an implied write, do not process directly */
00436 
00437   for (i=index; i < end; i += count +1) {
00438     /* Finished processing one option? */
00439     if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index )
00440       return(i);
00441 
00442     do { /* use break to loop to exception handler and loop */
00443 
00444       option=argv[i];
00445       cli_wand->line=i;  /* note the argument for this option */
00446 
00447       /* get option, its argument count, and option type */
00448       cli_wand->command = GetCommandOptionInfo(argv[i]);
00449       count=cli_wand->command->type;
00450       option_type=(CommandOptionFlags) cli_wand->command->flags;
00451 #if 0
00452       (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
00453             i, argv[i], cli_wand->command->mnemonic );
00454 #endif
00455 
00456       if ( option_type == UndefinedOptionFlag ||
00457            (option_type & NonMagickOptionFlag) != 0 ) {
00458 #if MagickCommandDebug >= 3
00459         (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option);
00460 #endif
00461         if ( IfMagickFalse(IsCommandOption(option)) ) {
00462           if ( (cli_wand->process_flags & ProcessImplictRead) != 0 ) {
00463             /* non-option -- treat as a image read */
00464             cli_wand->command=(const OptionInfo *)NULL;
00465             CLIOption(cli_wand,"-read",option);
00466             break; /* next option */
00467           }
00468         }
00469         CLIWandException(OptionFatalError,"UnrecognizedOption",option);
00470         break; /* next option */
00471       }
00472 
00473       if ( ((option_type & SpecialOptionFlag) != 0 ) &&
00474            ((cli_wand->process_flags & ProcessScriptOption) != 0) &&
00475            (LocaleCompare(option,"-script") == 0) ) {
00476         /* Call Script from CLI, with a filename as a zeroth argument.
00477            NOTE: -script may need to use the 'implict write filename' argument
00478            so it must be handled specially to prevent a 'missing argument' error.
00479         */
00480         if ( (i+count) >= argc )
00481           CLIWandException(OptionFatalError,"MissingArgument",option);
00482         ProcessScriptOptions(cli_wand,argc,argv,i+1);
00483         return(argc);  /* Script does not return to CLI -- Yet */
00484                        /* FUTURE: when it does, their may be no write arg! */
00485       }
00486 
00487       if ((i+count) >= end ) {
00488         CLIWandException(OptionFatalError,"MissingArgument",option);
00489         if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
00490           return(end);
00491         break; /* next option - not that their is any! */
00492       }
00493 
00494       arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL;
00495       arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL;
00496 
00497       /*
00498         Process Known Options
00499       */
00500 #if MagickCommandDebug >= 3
00501       (void) FormatLocaleFile(stderr,
00502         "CLI %u Option: \"%s\"  Count: %d  Flags: %04x  Args: \"%s\" \"%s\"\n",
00503             i,option,count,option_type,arg1,arg2);
00504 #endif
00505 
00506       /* ignore 'genesis options' in command line args */
00507       if ( (option_type & GenesisOptionFlag) != 0 )
00508         break; /* next option */
00509 
00510       /* Handle any special options for CLI (-script handled above) */
00511       if ( (option_type & SpecialOptionFlag) != 0 ) {
00512         if ( (cli_wand->process_flags & ProcessExitOption) != 0
00513              && LocaleCompare(option,"-exit") == 0 )
00514           return(i+count);
00515         break; /* next option */
00516       }
00517 
00518       /* Process standard image option */
00519       CLIOption(cli_wand, option, arg1, arg2);
00520 
00521     } while (0); /* break block to next option */
00522 
00523 #if MagickCommandDebug >= 9
00524     OutputOptions(cli_wand->wand.image_info);
00525     if ( cli_wand->wand.images != (Image *)NULL ) {
00526       OutputArtifacts(cli_wand->wand.images);
00527       OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
00528     }
00529 #endif
00530     if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
00531       return(i+count);
00532   }
00533   assert(i==end);
00534 
00535   if ( (cli_wand->process_flags & ProcessImplictWrite) == 0 )
00536     return(end); /* no implied write -- just return to caller */
00537 
00538   assert(end==argc-1); /* end should not include last argument */
00539 
00540   /*
00541      Implicit Write of images to final CLI argument
00542   */
00543   option=argv[i];
00544   cli_wand->line=i;
00545 
00546   /* check that stacks are empty - or cause exception */
00547   if (cli_wand->image_list_stack != (Stack *)NULL)
00548     CLIWandException(OptionError,"UnbalancedParenthesis", "(end of cli)");
00549   else if (cli_wand->image_info_stack != (Stack *)NULL)
00550     CLIWandException(OptionError,"UnbalancedBraces", "(end of cli)");
00551   if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
00552     return(argc);
00553 
00554 #if MagickCommandDebug >= 3
00555   (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option );
00556 #endif
00557 
00558   /* Valid 'do no write' replacement option (instead of "null:") */
00559   if (LocaleCompare(option,"-exit") == 0 )
00560     return(argc);  /* just exit, no image write */
00561 
00562   /* If filename looks like an option,
00563      Or the common 'end of line' error of a single space.
00564      -- produce an error */
00565   if (IfMagickTrue(IsCommandOption(option)) ||
00566       (option[0] == ' ' && option[1] == '\0') ) {
00567     CLIWandException(OptionError,"MissingOutputFilename",option);
00568     return(argc);
00569   }
00570 
00571   cli_wand->command=(const OptionInfo *)NULL;
00572   CLIOption(cli_wand,"-write",option);
00573   return(argc);
00574 }
00575 
00576 /*
00577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00578 %                                                                             %
00579 %                                                                             %
00580 %                                                                             %
00581 +   M a g i c k I m a g e C o m m a n d                                       %
00582 %                                                                             %
00583 %                                                                             %
00584 %                                                                             %
00585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00586 %
00587 %  MagickImageCommand() Handle special use CLI arguments and prepare a
00588 %  CLI MagickCLI to process the command line or directly specified script.
00589 %
00590 %  This is essentualy interface function between the MagickCore library
00591 %  initialization function MagickCommandGenesis(), and the option MagickCLI
00592 %  processing functions  ProcessCommandOptions()  or  ProcessScriptOptions()
00593 %
00594 %  The format of the MagickImageCommand method is:
00595 %
00596 %      MagickBooleanType MagickImageCommand(ImageInfo *image_info,
00597 %           int argc, char **argv, char **metadata, ExceptionInfo *exception)
00598 %
00599 %  A description of each parameter follows:
00600 %
00601 %    o image_info: the starting image_info structure
00602 %         (for compatibilty with MagickCommandGenisis())
00603 %
00604 %    o argc: the number of elements in the argument vector.
00605 %
00606 %    o argv: A text array containing the command line arguments.
00607 %
00608 %    o metadata: any metadata (for VBS) is returned here.
00609 %         (for compatibilty with MagickCommandGenisis())
00610 %
00611 %    o exception: return any errors or warnings in this structure.
00612 %
00613 */
00614 
00615 static void MagickUsage(MagickBooleanType verbose)
00616 {
00617   const char
00618     *name;
00619 
00620   size_t
00621     len;
00622 
00623   name=GetClientName();
00624   len=strlen(name);
00625 
00626   if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
00627     /* convert usage */
00628     (void) FormatLocaleFile(stdout,
00629        "Usage: %s [{option}|{image}...] {output_image}\n",name);
00630     (void) FormatLocaleFile(stdout,
00631        "       %s -help|-version|-usage|-list {option}\n\n",name);
00632     return;
00633   }
00634   else if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
00635     /* magick-script usage */
00636     (void) FormatLocaleFile(stdout,
00637        "Usage: %s {filename} [{script_args}...]\n",name);
00638   }
00639   else {
00640     /* magick usage */
00641     (void) FormatLocaleFile(stdout,
00642        "Usage: %s [{option}|{image}...] {output_image}\n",name);
00643     (void) FormatLocaleFile(stdout,
00644        "       %s [{option}|{image}...] -script {filename} [{script_args}...]\n",
00645        name);
00646   }
00647   (void) FormatLocaleFile(stdout,
00648        "       %s -help|-version|-usage|-list {option}\n\n",name);
00649 
00650   if (IfMagickFalse(verbose))
00651     return;
00652 
00653   (void) FormatLocaleFile(stdout,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
00654     "All options are performed in a strict 'as you see them' order\n",
00655     "You must read-in images before you can operate on them.\n",
00656     "\n",
00657     "Magick Script files can use any of the following forms...\n",
00658     "     #!/path/to/magick -script\n",
00659     "or\n",
00660     "     #!/bin/sh\n",
00661     "     :; exec magick -script \"$0\" \"$@\"; exit 10\n",
00662     "     # Magick script from here...\n",
00663     "or\n",
00664     "     #!/usr/bin/env  magick-script\n",
00665     "The latter two forms do not require the path to the command hard coded.\n",
00666     "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
00667     "\n",
00668     "For more information on usage, options, examples, and techniques\n",
00669     "see the ImageMagick website at    ", MagickAuthoritativeURL);
00670 
00671   return;
00672 }
00673 
00674 /*
00675    Concatanate given file arguments to the given output argument.
00676    Used for a special -concatenate option used for specific 'delegates'.
00677    The option is not formally documented.
00678 
00679       magick -concatenate files... output
00680 
00681    This is much like the UNIX "cat" command, but for both UNIX and Windows,
00682    however the last argument provides the output filename.
00683 */
00684 static MagickBooleanType ConcatenateImages(int argc,char **argv,
00685      ExceptionInfo *exception )
00686 {
00687   FILE
00688     *input,
00689     *output;
00690 
00691   int
00692     c;
00693 
00694   register ssize_t
00695     i;
00696 
00697   if (IfMagickFalse(  ExpandFilenames(&argc,&argv)  ))
00698     ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
00699          GetExceptionMessage(errno));
00700 
00701   output=fopen_utf8(argv[argc-1],"wb");
00702   if (output == (FILE *) NULL) {
00703     ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[argc-1]);
00704     return(MagickFalse);
00705   }
00706   for (i=2; i < (ssize_t) (argc-1); i++) {
00707 #if 0
00708     fprintf(stderr, "DEBUG: Concatenate Image: \"%s\"\n", argv[i]);
00709 #endif
00710     input=fopen_utf8(argv[i],"rb");
00711     if (input == (FILE *) NULL) {
00712         ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
00713         continue;
00714       }
00715     for (c=fgetc(input); c != EOF; c=fgetc(input))
00716       (void) fputc((char) c,output);
00717     (void) fclose(input);
00718     (void) remove_utf8(argv[i]);
00719   }
00720   (void) fclose(output);
00721   return(MagickTrue);
00722 }
00723 
00724 WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
00725   int argc,char **argv,char **metadata,ExceptionInfo *exception)
00726 {
00727   MagickCLI
00728     *cli_wand;
00729 
00730   size_t
00731     len;
00732 
00733   /* For specific OS command line requirements */
00734   ReadCommandlLine(argc,&argv);
00735 
00736   /* Initialize special "CLI Wand" to hold images and settings (empty) */
00737   cli_wand=AcquireMagickCLI(image_info,exception);
00738   cli_wand->line=1;
00739 
00740   GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
00741   SetClientName(cli_wand->wand.name);
00742   ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent);
00743 
00744   len=strlen(argv[0]);  /* precaution */
00745 
00746   /* "convert" command - give a "depreciation" warning" */
00747   if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
00748     cli_wand->process_flags = ConvertCommandOptionFlags;
00749     /*(void) FormatLocaleFile(stderr,"WARNING: %s\n",
00750              "The convert is depreciated in IMv7, use \"magick\"\n");*/
00751   }
00752 
00753   /* Special Case:  If command name ends with "script" implied "-script" */
00754   if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
00755     if (argc >= 2 && (  (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) {
00756       GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
00757       ProcessScriptOptions(cli_wand,argc,argv,1);
00758       goto Magick_Command_Cleanup;
00759     }
00760   }
00761 
00762   /* Special Case: Version Information and Abort */
00763   if (argc == 2) {
00764     if (LocaleCompare("-version",argv[1]) == 0) { /* just version */
00765       CLIOption(cli_wand, "-version");
00766       goto Magick_Command_Exit;
00767     }
00768     if ((LocaleCompare("-help",argv[1]) == 0)   || /* GNU standard option */
00769         (LocaleCompare("--help",argv[1]) == 0) ) { /* just a brief summary */
00770       MagickUsage(MagickFalse);
00771       goto Magick_Command_Exit;
00772     }
00773     if (LocaleCompare("-usage",argv[1]) == 0) {   /* both version & usage */
00774       CLIOption(cli_wand, "-version" );
00775       MagickUsage(MagickTrue);
00776       goto Magick_Command_Exit;
00777     }
00778   }
00779 
00780   /* not enough arguments -- including -help */
00781   if (argc < 3) {
00782     (void) FormatLocaleFile(stderr,
00783        "Error: Invalid argument or not enough arguments\n\n");
00784     MagickUsage(MagickFalse);
00785     goto Magick_Command_Exit;
00786   }
00787 
00788   /* Special "concatenate option (hidden) for delegate usage */
00789   if (LocaleCompare("-concatenate",argv[1]) == 0) {
00790     ConcatenateImages(argc,argv,exception);
00791     goto Magick_Command_Exit;
00792   }
00793 
00794   /* List Information and Abort */
00795   if (argc == 3 && LocaleCompare("-list",argv[1]) == 0) {
00796     CLIOption(cli_wand, argv[1], argv[2]);
00797     goto Magick_Command_Exit;
00798   }
00799 
00800   /* ------------- */
00801   /* The Main Call */
00802 
00803   if (LocaleCompare("-script",argv[1]) == 0) {
00804     /* Start processing directly from script, no pre-script options
00805        Replace wand command name with script name
00806        First argument in the argv array is the script name to read.
00807     */
00808     GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
00809     ProcessScriptOptions(cli_wand,argc,argv,2);
00810   }
00811   else {
00812     /* Normal Command Line, assumes output file as last option */
00813     ProcessCommandOptions(cli_wand,argc,argv,1);
00814   }
00815   /* ------------- */
00816 
00817 Magick_Command_Cleanup:
00818   /* recover original image_info and clean up stacks
00819      FUTURE: "-reset stacks" option  */
00820   while (cli_wand->image_list_stack != (Stack *)NULL)
00821     CLIOption(cli_wand,")");
00822   while (cli_wand->image_info_stack != (Stack *)NULL)
00823     CLIOption(cli_wand,"}");
00824 
00825   /* assert we have recovered the original structures */
00826   assert(cli_wand->wand.image_info == image_info);
00827   assert(cli_wand->wand.exception == exception);
00828 
00829   /* Handle metadata for ImageMagickObject COM object for Windows VBS */
00830   if (metadata != (char **) NULL) {
00831     const char
00832       *format;
00833 
00834     char
00835       *text;
00836 
00837     format="%w,%h,%m";   // Get this from image_info Option splaytree
00838 
00839     text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
00840          exception);
00841     if (text == (char *) NULL)
00842       ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
00843            "MemoryAllocationFailed","'%s'", GetExceptionMessage(errno));
00844     else {
00845       (void) ConcatenateString(&(*metadata),text);
00846       text=DestroyString(text);
00847     }
00848   }
00849 
00850 Magick_Command_Exit:
00851   /* Destroy the special CLI Wand */
00852   cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
00853   cli_wand->wand.exception = (ExceptionInfo *)NULL;
00854   cli_wand=DestroyMagickCLI(cli_wand);
00855 
00856   return(IsMagickTrue(exception->severity > ErrorException));
00857 }