]> granicus.if.org Git - imagemagick/commitdiff
Adding Special 'Stacking' Operators
authoranthony <anthony@git.imagemagick.org>
Sun, 26 Feb 2012 12:58:58 +0000 (12:58 +0000)
committeranthony <anthony@git.imagemagick.org>
Sun, 26 Feb 2012 12:58:58 +0000 (12:58 +0000)
MagickWand/ChangeLog
MagickWand/magick-cli.c
MagickWand/magick-cli.h
MagickWand/magick-image.c
MagickWand/magick-wand-private.h
MagickWand/magick-wand.c
MagickWand/operation.c
MagickWand/operation.h

index 3cc0b9a9f5cb97f1d43a4c23e75c49257d47698a..cc2987dadcdaf17bd81b715b72b23339042a715f 100644 (file)
@@ -1,3 +1,10 @@
+2012-02-26 7.0.0-0 Anthony  <anthony@griffith...>
+  * A super-struct MagickCLI which includes a MagicWand is used to add the
+    extra requirements needed for Command Land and Script handling of CLI
+    options.  This structure allows CLI options to use either MagickWand or
+    MagickCore API's to implement the CLI options.
+  * Adding stacking options to "magick"
+
 2012-02-12  7.0.0-0 Anthony  <anthony@griffith...>
   * new module "magick-cli" providing base for new "magick" command
 
index 6ec30063a6e23396efc7f5a68cd0606f4cfe20c7..b59bc8b3724c9952fe89ac48cd0828c81e35b74e 100644 (file)
 #include "MagickWand/studio.h"
 #include "MagickWand/MagickWand.h"
 #include "MagickWand/magick-wand-private.h"
+#include "MagickWand/magick-cli-private.h"
+#include "MagickWand/magick-cli.h"
+#include "MagickWand/operation.h"
 #include "MagickCore/memory_.h"
 #include "MagickCore/string-private.h"
-#include "MagickWand/operation.h"
 #include "MagickCore/utility-private.h"
 #include "MagickCore/version.h"
 \f
+/* verbose debugging,
+      1 - option type
+      2 - source of option
+      3 - mnemonic lookup  */
 #define MagickCommandDebug 0
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  GetScriptToken() is fairly general, finite state token parser. That will
-%  divide a input file stream into tokens, in a way that is almost identical
-%  to a UNIX shell.
-%
-%  It returns 'MagickTrue' if a token was found. Even in the special case of
-%  a empty token followed immediatally by a EOF. For example:  ''{EOF}
-%
-%  A token is returned immediatally the end of token is found.  That is
-%  parsing is purely character by character, and not line-by-line. This
-%  should allow for mixed stream of tokens (options), and other data (images)
-%  without problems.  Assuming the other data has a well defined End-Of-Data
-%  handling (see complex example below).
+%  divide a input file stream into tokens, in a way that is as close to a
+%  UNIX shell, as is feasable.  Only shell variable, and command
+%  substitutions will not be performed.
 %
 %  Tokens are white space separated, and may be quoted, or even partially
 %  quoted by either single or double quotes, or the use of backslashes,
 %
 %  For example:    This\ is' a 'single" token"
 %
+%  A token is returned immediatally the end of token is found. That is as soon
+%  as a ending white-space or EOF condition was determined.  That is to say
+%  the file stream is parsed purely character-by-character, regardless any
+%  buffering constraints set by the system.
+%
+%  The function will return 'MagickTrue' if a valid token was found, while
+%  the token status will be set accordingally to 'OK' or 'EOF', according to
+%  the cause of the end of token.  The token may be an empty string if the
+%  input was a quoted empty string.  Other error conditions return a value of
+%  MagickFalse, indicating any token found was incomplete due to the error
+%  condition.
+%
 %  Single quotes will preserve all characters including backslashes. Double
 %  quotes will also preserve backslashes unless escaping a double quote,
 %  or another backslashes.  Other shell meta-characters are not treated as
 %  For example Quoting the quote chars:
 %              \'  "'"       \"  '"'  "\""      \\  '\'  "\\"
 %
-%  Comments start with a '#' character at the start of a new token (generally
-%  at start of a line, or after a unquoted white space charcater) and continue
-%  to the end of line.  The are simply ignored.  You can escape a comment '#'
-%  character to return a token that starts with such a character.
-%
-%  More complex example...
-%  Sending a PGM image in the middle of a standard input script.
+%  Outside quotes, backslash characters will make spaces, tabs and quotes part
+%  of a token returned. However a backslash at the end of a line (and outside
+%  quotes) will cause the newline to be completely ignored (as per the shell
+%  line continuation).
 %
-%  magick -script - <<END
-%    # read a stdin in-line image...
-%    "pgm:-[0]" P2 2 2 3   0 1 1 2
-%    # continue processing that image
-%    -resize 100x100
-%    -write enlarged.png
-%  END
-%
-%  Only a single space character separates the 'image read' from the
-%  'image data' after which the next operation is read.  This only works
-%  for image data formats with a well defined length or End-of-Data marker
-%  such as MIFF, and PbmPlus file formats.
+%  Comments start with a '#' character at the start of a new token, will be
+%  completely ignored upto the end of line, regardless of any backslash at the
+%  end of the line.  You can escape a comment '#', using quotes or backlsashes
+%  just as you can in a shell.
 %
 %  The format of the MagickImageCommand method is:
 %
@@ -267,6 +266,15 @@ static MagickBooleanType GetScriptToken(ScriptTokenInfo *token_info)
             SaveChar('\\');
             break;
           }
+        if (c == '\n')
+          switch (state)
+          {
+            case IN_COMMENT:
+              state=IN_WHITE;  /* end comment */
+            case IN_WHITE:
+            case IN_TOKEN:
+              continue;   /* line continuation (outside quotes and comment) */
+          }
         switch (state)
         {
           case IN_WHITE:
@@ -314,78 +322,6 @@ static MagickBooleanType GetScriptToken(ScriptTokenInfo *token_info)
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   P r o c e s s S p e c i a l O p t i o n                                   %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  ProcessSpecialOption() Apply certian options that are specific to Shell
-%  API interface.  Specifically reading images and handling image and
-%  image_info (settings) stacks.
-%
-%  The format of the ProcessSpecialOption method is:
-%
-%      void ProcessSpecialOption(MagickWand *wand,const char *option,
-%           const char *arg, ProcessOptionFlags process_flags )
-%
-%  A description of each parameter follows:
-%
-%    o wand: the main CLI Wand to use.
-%
-%    o option: The special option (with any switch char) to process
-%
-%    o arg: Argument for option, if required
-%
-%    o process_flags: Wether to process specific options or not.
-%
-*/
-WandExport void ProcessSpecialOption(MagickWand *wand,
-     const char *option, const char *arg, ProcessOptionFlags process_flags)
-{
-  if ( LocaleCompare("-read",option) == 0 )
-    {
-      Image *
-        new_images;
-
-      CopyMagickString(wand->image_info->filename,arg,MaxTextExtent);
-      if (wand->image_info->ping != MagickFalse)
-        new_images=PingImages(wand->image_info,wand->exception);
-      else
-        new_images=ReadImages(wand->image_info,wand->exception);
-      AppendImageToList(&wand->images, new_images);
-      return;
-    }
-  if (LocaleCompare("-sans",option) == 0)
-    return;
-  if (LocaleCompare("-sans0",option) == 0)
-    return;
-  if (LocaleCompare("-sans2",option) == 0)
-    return;
-  if (LocaleCompare("-noop",option) == 0)
-    return;
-
-#if 0
-  if (LocaleCompare(option,"(") == 0)
-    // push images/settings
-  if (LocaleCompare(option,")") == 0)
-    // pop images/settings
-  if (LocaleCompare(option,"respect_parenthesis") == 0)
-    // adjust stack handling
-  // Other 'special' options this should handle
-  //    "region" "clone"  "list" "version"
-  // It does not do "exit" however as due to its side-effect requirements
-
-  if ( ( process_flags & ProcessUnknownOptionError ) != 0 )
-    MagickExceptionReturn(OptionError,"InvalidUseOfOption",option);
-#endif
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 +   P r o c e s s S c r i p t O p t i o n s                                   %
 %                                                                             %
 %                                                                             %
@@ -407,11 +343,11 @@ WandExport void ProcessSpecialOption(MagickWand *wand,
 %
 %  The format of the ProcessScriptOptions method is:
 %
-%    void ProcessScriptOptions(MagickWand *wand,int argc,char **argv)
+%    void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv)
 %
 %  A description of each parameter follows:
 %
-%    o wand: the main CLI Wand to use.
+%    o cli_wand: the main CLI Wand to use.
 %
 %    o argc: the number of elements in the argument vector.
 %
@@ -419,11 +355,11 @@ WandExport void ProcessSpecialOption(MagickWand *wand,
 %
 */
 #define MagickExceptionScript(severity,tag,arg,line,col) \
-  (void) ThrowMagickException(wand->exception,GetMagickModule(),severity,tag, \
-       "'%s' : Line %u Column %u of script \"%s\"", arg, line, col, wand->name);
+  (void) ThrowMagickException(cli_wand->wand.exception,GetMagickModule(), \
+       severity,tag, "'%s' : Line %u Column %u of script \"%s\"", \
+       arg, line, col, cli_wand->wand.name);
 
-WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
-     char **argv)
+WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv)
 {
   char
     *option,
@@ -448,24 +384,23 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
     file_opened;
 
   assert(argc>0 && argv[argc-1] != (char *)NULL);
-  assert(wand != (MagickWand *) NULL);
-  assert(wand->signature == WandSignature);
-  assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
-  if (wand->debug != MagickFalse)
-    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
 
   /* Initialize variables */
   /* FUTURE handle file opening for '-' 'fd:N' or script filename */
   file_opened=MagickFalse;
   if ( LocaleCompare(argv[0],"-") == 0 )
     {
-      CopyMagickString(wand->name,"stdin",MaxTextExtent);
+      CopyMagickString(cli_wand->wand.name,"stdin",MaxTextExtent);
       token_info.stream=stdin;
       file_opened=MagickFalse;
     }
   else
     {
-      GetPathComponent(argv[0],TailPath,wand->name);
+      GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
       token_info.stream=fopen(argv[0], "r");
       file_opened=MagickTrue;
     }
@@ -481,7 +416,7 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
       if ( file_opened != MagickFalse )
         fclose(token_info.stream);
       MagickExceptionScript(ResourceLimitError,"MemoryAllocationFailed","",0,0);
-      (void) ThrowMagickException(wand->exception,GetMagickModule(),
+      (void) ThrowMagickException(cli_wand->wand.exception,GetMagickModule(),
            ResourceLimitError,"MemoryAllocationFailed","script token buffer");
       return;
     }
@@ -509,7 +444,7 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
       option_line=token_info.token_line;
       option_column=token_info.token_column;
 
-#if MagickCommandDebug
+#if MagickCommandDebug >=2
       (void) FormatLocaleFile(stderr, "Script Option Token: %u,%u: \"%s\"\n",
                option_line, option_column, option );
 #endif
@@ -517,7 +452,7 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
       { const OptionInfo *option_info = GetCommandOptionInfo(option);
         count=option_info->type;
         option_type=option_info->flags;
-#if MagickCommandDebug >= 2
+#if MagickCommandDebug >= 3
         (void) FormatLocaleFile(stderr, "option \"%s\" matched \"%s\"\n",
              option, option_info->mnemonic );
 #endif
@@ -533,13 +468,23 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
           if ( IsCommandOption(option) == MagickFalse)
             {
               /* non-option -- treat as a image read */
-              ProcessSpecialOption(wand,"-read",option,MagickScriptReadFlags);
+              CLISpecialOperator(cli_wand,"-read",option);
               count = 0;
-              continue;
             }
-          MagickExceptionScript(OptionFatalError,"UnrecognizedOption",
-               option,option_line,option_column);
-          break;
+          else
+            MagickExceptionScript(OptionFatalError,"UnrecognizedOption",
+                 option,option_line,option_column);
+
+          // FUTURE: '-regard_warning' causes IM to exit more prematurely!
+          // Note pipelined options may like more control over this level
+          if (cli_wand->wand.exception->severity > ErrorException)
+            {
+              if (cli_wand->wand.exception->severity > ErrorException)
+                  //(regard_warnings != MagickFalse))
+                break;                     /* FATAL - caller handles exception */
+              CatchException(cli_wand->wand.exception); /* output warnings and clear!!! */
+            }
+          continue;
         }
 
       plus_alt_op = MagickFalse;
@@ -574,7 +519,7 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
       /* handle script special options */
       //either continue processing command line
       // or making use of the command line options.
-      //ProcessCommandOptions(wand,count+1,argv, MagickScriptArgsFlags);
+      //CLICommandOptions(cli_wand,count+1,argv, MagickScriptArgsFlags);
 
 #if MagickCommandDebug
       (void) FormatLocaleFile(stderr,
@@ -588,29 +533,29 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
           if ( LocaleCompare(option,"-exit") == 0 )
             break;
           /* No "-script" from script at this time */
-          ProcessSpecialOption(wand,option,arg1,MagickScriptReadFlags);
+          CLISpecialOperator(cli_wand,option,arg1);
         }
 
       if ( (option_type & SettingOptionFlags) != 0 )
         {
-          WandSettingOptionInfo(wand, option+1, arg1);
+          CLISettingOptionInfo(cli_wand, option+1, arg1);
           // FUTURE: Sync Specific Settings into Images
         }
 
       if ( (option_type & SimpleOperatorOptionFlag) != 0)
-        WandSimpleOperatorImages(wand, plus_alt_op, option+1, arg1, arg2);
+        CLISimpleOperatorImages(cli_wand, plus_alt_op, option+1, arg1, arg2);
 
       if ( (option_type & ListOperatorOptionFlag) != 0 )
-        WandListOperatorImages(wand, plus_alt_op, option+1, arg1, arg2);
+        CLIListOperatorImages(cli_wand, plus_alt_op, option+1, arg1, arg2);
 
       // FUTURE: '-regard_warning' causes IM to exit more prematurely!
       // Note pipelined options may like more control over this level
-      if (wand->exception->severity > ErrorException)
+      if (cli_wand->wand.exception->severity > ErrorException)
         {
-          if (wand->exception->severity > ErrorException)
+          if (cli_wand->wand.exception->severity > ErrorException)
               //(regard_warnings != MagickFalse))
             break;                     /* FATAL - caller handles exception */
-          CatchException(wand->exception); /* output warnings and clear!!! */
+          CatchException(cli_wand->wand.exception); /* output warnings and clear!!! */
         }
     }
 #if MagickCommandDebug
@@ -676,12 +621,12 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
 %
 %  The format of the ProcessCommandOptions method is:
 %
-%    int ProcessCommandOptions(MagickWand *wand,int argc,char **argv,
+%    int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
 %           int *index, ProcessOptionFlags process_flags )
 %
 %  A description of each parameter follows:
 %
-%    o wand: the main CLI Wand to use.
+%    o cli_wand: the main CLI Wand to use.
 %
 %    o argc: the number of elements in the argument vector.
 %
@@ -692,7 +637,7 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
 */
 /* FUTURE: correctly identify option... CLI arg,  Script line,column  */
 #define MagickExceptionContinue(severity,tag,arg,index) \
-  (void) ThrowMagickException(wand->exception,GetMagickModule(),severity,tag, \
+  (void) ThrowMagickException(cli_wand->wand.exception,GetMagickModule(),severity,tag, \
        "'%s' : CLI Arg #%d", arg, (int) index); \
 
 #define MagickExceptionReturn(severity,tag,option,arg) \
@@ -701,7 +646,7 @@ WandExport void ProcessScriptOptions(MagickWand *wand,int argc,
   return; \
 }
 
-WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
+WandExport void ProcessCommandOptions(MagickCLI *cli_wand,int argc,
      char **argv, ProcessOptionFlags process_flags )
 {
   const char
@@ -721,11 +666,10 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
     option_type;
 
   assert(argc>0 && argv[argc-1] != (char *)NULL);
-  assert(wand != (MagickWand *) NULL);
-  assert(wand->signature == WandSignature);
-  assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
-  if (wand->debug != MagickFalse)
-    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
 
   /*
     Parse command-line options.
@@ -736,7 +680,7 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
   for (i=0; i < end; i += count +1)
     {
 #if MagickCommandDebug >= 2
-      (void) FormatLocaleFile(stderr, "index= %d\n", i );
+      (void) FormatLocaleFile(stderr, "index= %d  option="%s\"\n", i, argv[i]);
 #endif
       /* Finished processing one option? */
       if ( ( process_flags & ProcessOneOptionOnly ) != 0 && i != 0 )
@@ -751,7 +695,7 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
       { const OptionInfo *option_info = GetCommandOptionInfo(argv[i]);
         count=option_info->type;
         option_type=option_info->flags;
-#if MagickCommandDebug >= 2
+#if MagickCommandDebug >= 3
         (void) FormatLocaleFile(stderr, "option \"%s\" matched \"%s\"\n",
              argv[i], option_info->mnemonic );
 #endif
@@ -763,24 +707,30 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
 #if MagickCommandDebug
           (void) FormatLocaleFile(stderr, "CLI Non-Option: \"%s\"\n", option);
 #endif
-          if ( IsCommandOption(option) != MagickFalse )
+          if ( ( IsCommandOption(option) == MagickFalse ) &&
+               ( (process_flags & ProcessNonOptionImageRead) != 0 ) )
             {
-              if ( ( process_flags & ProcessNonOptionImageRead ) != 0 )
-               {
-                /* non-option -- treat as a image read */
-                ProcessSpecialOption(wand,"-read",option,process_flags);
-                count = 0;
-              }
+              /* non-option -- treat as a image read */
+              CLISpecialOperator(cli_wand,"-read",option);
+              count = 0;
             }
-          else if ( ( process_flags & ProcessUnknownOptionError ) != 0 )
+          else if ( (process_flags & ProcessUnknownOptionError) != 0 )
+            MagickExceptionReturn(OptionFatalError,"UnrecognizedOption",
+                 option,i);
+
+          // FUTURE: '-regard_warning' causes IM to exit more prematurely!
+          // Note pipelined options may like more control over this level
+          if (cli_wand->wand.exception->severity > ErrorException)
             {
-              MagickExceptionReturn(OptionFatalError,"UnrecognizedOption",
-                   option,i);
-              return;
+              if (cli_wand->wand.exception->severity > ErrorException)
+                  //(regard_warnings != MagickFalse))
+                break;                     /* FATAL - caller handles exception */
+              CatchException(cli_wand->wand.exception); /* output warnings and clear!!! */
             }
           continue;
         }
 
+
       if ( (option_type & DeprecateOptionFlag) != 0 )
         MagickExceptionContinue(OptionWarning,"DeprecatedOption",option,i);
         /* continue processing option anyway */
@@ -809,32 +759,32 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
             {
               // Unbalanced Parenthesis if stack not empty
               // Call Script, with a filename as a zeroth argument
-              ProcessScriptOptions(wand,argc-(i+1),argv+(i+1));
+              ProcessScriptOptions(cli_wand,argc-(i+1),argv+(i+1));
               return;
             }
-          ProcessSpecialOption(wand,option,arg1,process_flags);
+          CLISpecialOperator(cli_wand,option,arg1);
         }
 
       if ( (option_type & SettingOptionFlags) != 0 )
         {
-          WandSettingOptionInfo(wand, option+1, arg1);
+          CLISettingOptionInfo(cli_wand, option+1, arg1);
           // FUTURE: Sync Specific Settings into Images
         }
 
       if ( (option_type & SimpleOperatorOptionFlag) != 0)
-        WandSimpleOperatorImages(wand, plus_alt_op, option+1, arg1, arg2);
+        CLISimpleOperatorImages(cli_wand, plus_alt_op, option+1, arg1, arg2);
 
       if ( (option_type & ListOperatorOptionFlag) != 0 )
-        WandListOperatorImages(wand, plus_alt_op, option+1, arg1, arg2);
+        CLIListOperatorImages(cli_wand, plus_alt_op, option+1, arg1, arg2);
 
       // FUTURE: '-regard_warning' causes IM to exit more prematurely!
       // Note pipelined options may like more control over this level
-      if (wand->exception->severity > ErrorException)
+      if (cli_wand->wand.exception->severity > ErrorException)
         {
-          if (wand->exception->severity > ErrorException)
+          if (cli_wand->wand.exception->severity > ErrorException)
               //(regard_warnings != MagickFalse))
             return;                    /* FATAL - caller handles exception */
-          CatchException(wand->exception); /* output warnings and clear!!! */
+          CatchException(cli_wand->wand.exception); /* output warnings and clear!!! */
         }
     }
 
@@ -843,7 +793,7 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
   assert(end==argc-1);
 
   /*
-     Write out final image!
+     Implicit Write of images to final CLI argument
   */
   option=argv[i];
 
@@ -863,8 +813,8 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
     /* FUTURE: Better Error - Output Filename not Found */
     MagickExceptionReturn(OptionError,"MissingOutputFilename",option,i);
 
-  /* If no images in MagickWand */
-  if ( wand->images == (Image *) NULL )
+  /* If no images in MagickCLI */
+  if ( cli_wand->wand.images == (Image *) NULL )
     {
       /* a "null:" output coder with no images is not an error! */
       if ( LocaleCompare(option,"null:") == 0 )
@@ -872,10 +822,14 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
       MagickExceptionReturn(OptionError,"NoImagesForFinalWrite",option,i);
     }
 
-  //WandListOperatorImages(wand,MagickFalse,"write",option,(const char *)NULL);
-  (void) SyncImagesSettings(wand->image_info,wand->images,wand->exception);
-  (void) WriteImages(wand->image_info,wand->images,option,wand->exception);
-
+#if 0
+  WandListOperatorImages(cli_wand,MagickFalse,"write",option,(const char *)NULL);
+#else
+  (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
+       cli_wand->wand.exception);
+  (void) WriteImages(cli_wand->wand.image_info,cli_wand->wand.images,option,
+       cli_wand->wand.exception);
+#endif
   return;
 }
 \f
@@ -891,10 +845,10 @@ WandExport void ProcessCommandOptions(MagickWand *wand,int argc,
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  MagickImageCommand() Handle special use CLI arguments and prepare a
-%  CLI MagickWand to process the command line or directly specified script.
+%  CLI MagickCLI to process the command line or directly specified script.
 %
 %  This is essentualy interface function between the MagickCore library
-%  initialization function MagickCommandGenesis(), and the option MagickWand
+%  initialization function MagickCommandGenesis(), and the option MagickCLI
 %  processing functions  ProcessCommandOptions()  or  ProcessScriptOptions()
 %
 %  The format of the MagickImageCommand method is:
@@ -994,8 +948,8 @@ static MagickBooleanType ConcatenateImages(int argc,char **argv,
 WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
   int argc,char **argv,char **metadata,ExceptionInfo *exception)
 {
-  MagickWand
-    *wand;
+  MagickCLI
+    *cli_wand;
 
   const char
     *option;
@@ -1023,7 +977,7 @@ WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
 
 #if 0
   /* FUTURE: This does not make sense!  Remove it.
-     Only implied 'image read' needs to expand file name glob patterns
+     Only a 'image read' needs to expand file name glob patterns
   */
   status=ExpandFilenames(&argc,&argv);
   if (status == MagickFalse)
@@ -1031,38 +985,38 @@ WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
       GetExceptionMessage(errno));
 #endif
 
-  /* Special hidden option for 'delegates' - no wand needed */
+  /* Special option (hidden) for delegate usage - no wand needed */
   if (LocaleCompare("-concatenate",argv[1]) == 0)
     return(ConcatenateImages(argc,argv,exception));
 
   /* Initialize special "CLI Wand" to hold images and settings (empty) */
   /* FUTURE: add this to 'operations.c' */
-  wand=NewMagickWand();
-  wand->image_info=DestroyImageInfo(wand->image_info);
-  wand->image_info=image_info;
-  wand->exception=DestroyExceptionInfo(wand->exception);
-  wand->exception=exception;
-  wand->draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
-  wand->quantize_info=AcquireQuantizeInfo(image_info);
-
-  if (LocaleCompare("-list",argv[1]) == 0)
-    /* Special option - list argument constants and other information */
-    /* FUTURE - this really should be a direct MagickCore Function */
-    WandSettingOptionInfo(wand, argv[1]+1, argv[2]);
-  else if (LocaleCompare("-script",argv[1]) == 0)
+  cli_wand=AcquireMagickCLI(image_info,exception);
+
+  if (LocaleCompare("-script",argv[1]) == 0)
     {
-      /* Start processing from script, no pre-script options */
-      GetPathComponent(argv[2],TailPath,wand->name);
-      ProcessScriptOptions(wand,argc-2,argv+2);
+      /* Start processing directly from script, no pre-script options
+        Replace wand command name with script name
+      */
+      GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
+      ProcessScriptOptions(cli_wand,argc-2,argv+2);
     }
+  else if (LocaleCompare("-list",argv[1]) == 0)
+    /* Special option, list information and exit
+       FUTURE: this should be a MagickCore option, no wand is actually needed
+    */
+
+    CLISpecialOperator(cli_wand, argv[1]+1, argv[2]);
   else
-    {
-      /* Processing Command line, assuming output file as last option */
-      ProcessCommandOptions(wand,argc-1,argv+1,MagickCommandOptionFlags);
-    }
+    /* Processing Command line, assuming output file as last option */
+    ProcessCommandOptions(cli_wand,argc-1,argv+1,MagickCommandOptionFlags);
 
-  assert(wand->exception == exception);
-  assert(wand->image_info == image_info);
+
+  /* recover original image_info - check we get the right image_info */
+  while (cli_wand->image_info_stack != (Stack *)NULL)
+    CLISpecialOperator(cli_wand,"}",(const char *)NULL);
+  assert(cli_wand->wand.image_info == image_info);
+  assert(cli_wand->wand.exception == exception);
 
   /* Handle metadata for ImageMagickObject COM object for Windows VBS */
   if (metadata != (char **) NULL)
@@ -1075,7 +1029,8 @@ WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
 
       format="%w,%h,%m";   // Get this from image_info Option splaytree
 
-      text=InterpretImageProperties(image_info,wand->images,format,exception);
+      text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
+           exception);
       if (text == (char *) NULL)
         ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
              "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
@@ -1085,11 +1040,10 @@ WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
           text=DestroyString(text);
         }
     }
-
   /* Destroy the special CLI Wand */
-  wand->exception = (ExceptionInfo *)NULL;
-  wand->image_info = (ImageInfo *)NULL;
-  wand=DestroyMagickWand(wand);
+  cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
+  cli_wand->wand.exception = (ExceptionInfo *)NULL;
+  cli_wand=DestroyMagickCLI(cli_wand);
 
   return((exception->severity > ErrorException) ? MagickFalse : MagickTrue);
 }
index 9b862a0fb3a48f287dc67da77bb01735ecac6fb1..b72154099fd2037507fb2247a995a24b66b7bb5b 100644 (file)
@@ -22,6 +22,9 @@
 extern "C" {
 #endif
 
+typedef struct _MagickCLI
+  MagickCLI;
+
 typedef enum
 {
   /* What options should be processed */
@@ -32,12 +35,14 @@ typedef enum
   /* Special Option Handling */
   ProcessExitOption           = 0x0100,  /* allow '-exit' use */
   ProcessScriptOption         = 0x0200,  /* allow '-script' use */
+  ProcessReadOption           = 0x0400,  /* allow '-read' use */
 
   /* Option Processing Flags */
   ProcessOneOptionOnly        = 0x4000,  /* Process One Option Only */
   ProcessOutputFile           = 0x8000,  /* Process the output file */
 
   /* Flag Groups for specific Situations */
+  CommandCommandOptionFlags   = 0x80FF,  /* Convert Command Flags */
   MagickCommandOptionFlags    = 0x8FFF,  /* Magick Command Flags */
   MagickScriptArgsFlags       = 0x00FF,  /* Script Args Flags */
   MagickScriptReadFlags       = 0x01FF   /* Script Read Flags */
@@ -45,10 +50,8 @@ typedef enum
 } ProcessOptionFlags;
 
 extern WandExport void
-  ProcessSpecialOption(MagickWand *,const char *,const char *,
-       ProcessOptionFlags),
-  ProcessScriptOptions(MagickWand *,int,char **),
-  ProcessCommandOptions(MagickWand *,int,char **,ProcessOptionFlags);
+  ProcessScriptOptions(MagickCLI *,int,char **),
+  ProcessCommandOptions(MagickCLI *,int,char **,ProcessOptionFlags);
 
 extern WandExport MagickBooleanType
   MagickImageCommand(ImageInfo *,int,char **,char **,ExceptionInfo *);
index ea77fb818e6ac53dd8a39a0dc9f590afe66a0bcb..3b9c5921475b77c9c8b8390ddfae72809f1bae5a 100644 (file)
@@ -107,10 +107,8 @@ static MagickWand *CloneMagickWandFromImages(const MagickWand *wand,
   clone_wand->id=AcquireWandId();
   (void) FormatLocaleString(clone_wand->name,MaxTextExtent,"%s-%.20g",
     MagickWandId,(double) clone_wand->id);
-  clone_wand->exception=AcquireExceptionInfo();
   InheritException(clone_wand->exception,wand->exception);
   clone_wand->image_info=CloneImageInfo(wand->image_info);
-  clone_wand->quantize_info=CloneQuantizeInfo(wand->quantize_info);
   clone_wand->images=images;
   clone_wand->debug=IsEventLogging();
   if (clone_wand->debug != MagickFalse)
index 18496c50adbf98e08c268ef34e5f1936ad50c7d1..96d38ad5ab070f6333aea3e5f009e38d250e7630 100644 (file)
@@ -43,20 +43,14 @@ struct _MagickWand
   ImageInfo
     *image_info;      /* Global settings used for images in Wand */
 
-  QuantizeInfo
-    *quantize_info;   /* for CLI API usage, not used by MagickWand API */
-
-  DrawInfo
-    *draw_info;       /* for CLI API usage, not used by MagickWand API */
+  ExceptionInfo
+    *exception;
 
   MagickBooleanType
     set_first,        /* wand set to first image, prepend new images */
     image_pending,    /* this image is pending Next Iteration */
     debug;            /* Log calls to MagickWand library */
 
-  ExceptionInfo
-    *exception;
-
   size_t
     signature;
 };
index a50013f6b1d2fa83ba4f9e3c7f491799b8a91d97..eac8fe1412d85759a2125fa6251e8b0bdd3c3d88 100644 (file)
@@ -91,10 +91,6 @@ WandExport void ClearMagickWand(MagickWand *wand)
   if (wand->debug != MagickFalse)
     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
   wand->images=DestroyImageList(wand->images);
-  if (wand->quantize_info != (QuantizeInfo *) NULL )
-    wand->quantize_info=DestroyQuantizeInfo(wand->quantize_info);
-  if (wand->draw_info != (DrawInfo *) NULL )
-    wand->draw_info=DestroyDrawInfo(wand->draw_info);
   wand->image_info=AcquireImageInfo();
   ClearMagickException(wand->exception);
   wand->debug=IsEventLogging();
@@ -142,14 +138,6 @@ WandExport MagickWand *CloneMagickWand(const MagickWand *wand)
   clone_wand->exception=AcquireExceptionInfo();
   InheritException(clone_wand->exception,wand->exception);
   clone_wand->image_info=CloneImageInfo(wand->image_info);
-  if ( wand->quantize_info == (QuantizeInfo *) NULL )
-    clone_wand->quantize_info=(QuantizeInfo *) NULL;
-  else
-    clone_wand->quantize_info=CloneQuantizeInfo(wand->quantize_info);
-  if ( wand->draw_info == (DrawInfo *) NULL )
-    clone_wand->draw_info=(DrawInfo *) NULL;
-  else
-    clone_wand->draw_info=CloneDrawInfo(wand->image_info,wand->draw_info);
   clone_wand->images=CloneImageList(wand->images,clone_wand->exception);
   clone_wand->debug=IsEventLogging();
   if (clone_wand->debug != MagickFalse)
@@ -187,10 +175,6 @@ WandExport MagickWand *DestroyMagickWand(MagickWand *wand)
   if (wand->debug != MagickFalse)
     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
   wand->images=DestroyImageList(wand->images);
-  if (wand->quantize_info != (QuantizeInfo *) NULL )
-    wand->quantize_info=DestroyQuantizeInfo(wand->quantize_info);
-  if (wand->draw_info != (DrawInfo *) NULL )
-    wand->draw_info=DestroyDrawInfo(wand->draw_info);
   if (wand->image_info != (ImageInfo *) NULL )
     wand->image_info=DestroyImageInfo(wand->image_info);
   if (wand->exception != (ExceptionInfo *) NULL )
@@ -1063,8 +1047,6 @@ WandExport MagickWand *NewMagickWand(void)
     (double) wand->id);
   wand->images=NewImageList();
   wand->image_info=AcquireImageInfo();
-  wand->quantize_info=(QuantizeInfo *) NULL; /* not used in MagickWand API */
-  wand->draw_info=(DrawInfo *) NULL;         /* not used in MagickWand API */
   wand->exception=AcquireExceptionInfo();
   wand->debug=IsEventLogging();
   if (wand->debug != MagickFalse)
index 34b33aa430333444447a35d089ef18aea4bf4df7..80ea2125fab13c1f6718eec8b4d93ee6f667b4d1 100644 (file)
@@ -50,7 +50,9 @@
 #include "MagickWand/studio.h"
 #include "MagickWand/MagickWand.h"
 #include "MagickWand/magick-wand-private.h"
+#include "MagickWand/magick-cli-private.h"
 #include "MagickWand/operation.h"
+#include "MagickWand/wand.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/thread-private.h"
 #include "MagickCore/string-private.h"
@@ -72,7 +74,7 @@ static const char
 */
 static MagickBooleanType MonitorProgress(const char *text,
   const MagickOffsetType offset,const MagickSizeType extent,
-  void *wand_unused(client_data))
+  void *wand_unused(cli_wandent_data))
 {
   char
     message[MaxTextExtent],
@@ -149,6 +151,8 @@ static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
   specifications (or direct floating point numbers).  The number of floats
   needed to represent a color varies depending on teh current channel
   setting.
+
+  This really should be in MagickCore, so that other API's can make use of it.
 */
 static Image *SparseColorOption(const Image *image,
   const SparseColorMethod method,const char *arguments,
@@ -223,7 +227,7 @@ static Image *SparseColorOption(const Image *image,
   number_arguments=x;
   if ( error ) {
     (void) ThrowMagickException(exception,GetMagickModule(),
-               OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
+               OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
                "Invalid number of Arguments");
     return( (Image *)NULL);
   }
@@ -246,7 +250,7 @@ static Image *SparseColorOption(const Image *image,
     if ( token[0] == '\0' ) break;
     if ( isalpha((int) token[0]) || token[0] == '#' ) {
       (void) ThrowMagickException(exception,GetMagickModule(),
-            OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
+            OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
             "Color found, instead of X-coord");
       error = MagickTrue;
       break;
@@ -257,7 +261,7 @@ static Image *SparseColorOption(const Image *image,
     if ( token[0] == '\0' ) break;
     if ( isalpha((int) token[0]) || token[0] == '#' ) {
       (void) ThrowMagickException(exception,GetMagickModule(),
-            OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
+            OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
             "Color found, instead of Y-coord");
       error = MagickTrue;
       break;
@@ -332,7 +336,7 @@ static Image *SparseColorOption(const Image *image,
   }
   if ( number_arguments != x && !error ) {
     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-      "InvalidArgument","`%s': %s","sparse-color","Argument Parsing Error");
+      "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
     sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
     return( (Image *)NULL);
   }
@@ -351,30 +355,172 @@ static Image *SparseColorOption(const Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   W a n d S e t t i n g O p t i o n I n f o                                 %
++   A c q u i r e W a n d C L I                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireMagickCLI() creates a new CLI wand (an expanded form of Magick
+%  Wand). The given image_info and exception is included as is if provided.
+%
+%  Use DestroyMagickCLI() to dispose of the CLI wand when it is no longer
+%  needed.
+%
+%  The format of the NewMagickWand method is:
+% 
+%      MagickCLI *AcquireMagickCLI(ImageInfo *image_info,
+%           ExceptionInfo *exception)
+%
+*/
+WandExport MagickCLI *AcquireMagickCLI(ImageInfo *image_info,
+    ExceptionInfo *exception)
+{
+  MagickCLI
+    *cli_wand;
+
+  /* precaution - as per NewMagickWand() */
+  {
+     size_t depth = MAGICKCORE_QUANTUM_DEPTH;
+     const char *quantum = GetMagickQuantumDepth(&depth);
+     if (depth != MAGICKCORE_QUANTUM_DEPTH)
+       ThrowWandFatalException(WandError,"QuantumDepthMismatch",quantum);
+  }
+
+  /* allocate memory for MgaickCLI */
+  cli_wand=(MagickCLI *) AcquireMagickMemory(sizeof(*cli_wand));
+  if (cli_wand == (MagickCLI *) NULL)
+    {
+      ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
+        GetExceptionMessage(errno));
+      return((MagickCLI *)NULL);
+    }
+
+  /* Initialize Wand Part of MagickCLI
+     FUTURE: this is a repeat of code from NewMagickWand()
+     However some parts may be given fro man external source!
+  */
+  cli_wand->wand.id=AcquireWandId();
+  (void) FormatLocaleString(cli_wand->wand.name,MaxTextExtent,
+           "%s-%.20g","MagickWandCLI", (double) cli_wand->wand.id);
+  cli_wand->wand.images=NewImageList();
+  if ( image_info == (ImageInfo *)NULL)
+    cli_wand->wand.image_info=AcquireImageInfo();
+  else
+    cli_wand->wand.image_info=image_info;
+  if ( exception == (ExceptionInfo *)NULL)
+    cli_wand->wand.exception=AcquireExceptionInfo();
+  else
+    cli_wand->wand.exception=exception;
+  cli_wand->wand.debug=IsEventLogging();
+  cli_wand->wand.signature=WandSignature;
+
+  /* Initialize CLI Part of MagickCLI */
+  cli_wand->draw_info=CloneDrawInfo(cli_wand->wand.image_info,(DrawInfo *) NULL);
+  cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
+  cli_wand->image_list_stack=(Stack *)NULL;
+  cli_wand->image_info_stack=(Stack *)NULL;
+  cli_wand->signature=WandSignature;
+
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
+  return(cli_wand);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y W a n d C L I                                               %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  WandSettingOptionInfo() applies a single settings option into a CLI wand
+%  DestroyMagickCLI() destorys everything in a CLI wand, including image_info
+%  and any exceptions, if still present in the wand.
+%
+%  The format of the NewMagickWand method is:
+% 
+%    MagickWand *DestroyMagickCLI()
+%            Exception *exception)
+%
+*/
+WandExport MagickCLI *DestroyMagickCLI(MagickCLI *cli_wand)
+{
+  Stack
+    *node;
+
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  assert(cli_wand->wand.signature == WandSignature);
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
+
+  /* Destroy CLI part of MagickCLI */
+  if (cli_wand->draw_info != (DrawInfo *) NULL )
+    cli_wand->draw_info=DestroyDrawInfo(cli_wand->draw_info);
+  if (cli_wand->quantize_info != (QuantizeInfo *) NULL )
+    cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
+  while(cli_wand->image_list_stack != (Stack *)NULL)
+    {
+      node=cli_wand->image_list_stack;
+      cli_wand->image_list_stack=node->next;
+      (void) DestroyImageList((Image *)node->data);
+      (void) RelinquishMagickMemory(node);
+    }
+  while(cli_wand->image_info_stack != (Stack *)NULL)
+    {
+      node=cli_wand->image_info_stack;
+      cli_wand->image_info_stack=node->next;
+      (void) DestroyImageInfo((ImageInfo *)node->data);
+      (void) RelinquishMagickMemory(node);
+    }
+  cli_wand->signature=(~WandSignature);
+
+  /* Destroy Wand part MagickCLI */
+  cli_wand->wand.images=DestroyImageList(cli_wand->wand.images);
+  if (cli_wand->wand.image_info != (ImageInfo *) NULL )
+    cli_wand->wand.image_info=DestroyImageInfo(cli_wand->wand.image_info);
+  if (cli_wand->wand.exception != (ExceptionInfo *) NULL )
+    cli_wand->wand.exception=DestroyExceptionInfo(cli_wand->wand.exception);
+  RelinquishWandId(cli_wand->wand.id);
+  cli_wand->wand.signature=(~WandSignature);
+
+  return((MagickCLI *)NULL);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C L I S e t t i n g O p t i o n I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CLISettingOptionInfo() applies a single settings option into a CLI wand
 %  holding the image_info, draw_info, quantize_info structures that will be
-%  used when processing the images also found within the wand.
+%  used when processing the images.
 %
-%  These options do no require images to be present in the wand for them to be
-%  able to be set, in which case they will be applied to
+%  These options do no require images to be present in the CLI wand for them
+%  to be able to be set, in which case they will generally be applied to image
+%  that are read in later
 %
 %  Options handled by this function are listed in CommandOptions[] of
 %  "option.c" that is one of "SettingOptionFlags" option flags.
 %
 %  The format of the WandSettingOptionInfo method is:
 %
-%    void WandSettingOptionInfo(MagickWand *wand,const char *option,
+%    void CLISettingOptionInfo(MagickCLI *cli_wand,const char *option,
 %               const char *arg)
 %
 %  A description of each parameter follows:
 %
-%    o wand: structure holding settings to be applied
+%    o cli_wand: structure holding settings to be applied
 %
 %    o option: The option string to be set
 %
@@ -384,9 +530,9 @@ static Image *SparseColorOption(const Image *image,
 %
 % Example usage...
 %
-%    WandSettingOptionInfo(wand, "background", MagickTrue, "Red");
-%    WandSettingOptionInfo(wand, "adjoin", "true");
-%    WandSettingOptionInfo(wand, "adjoin", NULL);
+%    CLISettingOptionInfo(cli_wand, "background", MagickTrue, "Red");
+%    CLISettingOptionInfo(cli_wand, "adjoin", "true");
+%    CLISettingOptionInfo(cli_wand, "adjoin", NULL);
 %
 % Or for handling command line arguments EG: +/-option ["arg"]
 %
@@ -396,25 +542,25 @@ static Image *SparseColorOption(const Image *image,
 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
 %    if ( (flags & SettingOptionFlags) != 0 )
-%      WandSettingOptionInfo(wand, argv[i]+1,
+%      CLISettingOptionInfo(cli_wand, argv[i]+1,
 %            (((*argv[i])!='-') ? (char *)NULL
 %                   : (count>0) ? argv[i+1] : "true") );
 %    i += count+1;
 %
 */
-WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
+WandExport void CLISettingOptionInfo(MagickCLI *cli_wand,const char *option,
      const char *arg)
 {
-  assert(wand != (MagickWand *) NULL);
-  assert(wand->signature == WandSignature);
-  assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
-  if (wand->debug != MagickFalse)
-    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
-
-#define image_info      (wand->image_info)
-#define draw_info       (wand->draw_info)
-#define quantize_info   (wand->quantize_info)
-#define exception       (wand->exception)
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  assert(cli_wand->wand.signature == WandSignature);
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
+
+#define image_info      (cli_wand->wand.image_info)
+#define exception       (cli_wand->wand.exception)
+#define draw_info       (cli_wand->draw_info)
+#define quantize_info   (cli_wand->quantize_info)
 #define IfSetOption     (arg!=(char *)NULL)
 #define ArgOption(def)  (IfSetOption?arg:(const char *)(def))
 #define ArgBoolean      (IfSetOption?MagickTrue:MagickFalse)
@@ -527,7 +673,7 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
       if (LocaleCompare("box",option) == 0)
         {
           /* DEPRECIATED - now "undercolor" */
-          WandSettingOptionInfo(wand,"undercolor",arg);
+          CLISettingOptionInfo(cli_wand,"undercolor",arg);
           break;
         }
       break;
@@ -553,8 +699,9 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
         }
       if (LocaleCompare("channel",option) == 0)
         {
-          /* This is applied to images in SimpleImageOperator!!!
-             FUTURE: move it to SyncImageSettings() - or alternative
+          /* FUTURE:  -channel mask {vaules}
+             This is applied to images in SimpleImageOperator!!!
+             Move it to SyncImageSettings() - or alternative
           */
           image_info->channel=(ChannelType) (
                IfSetOption ? ParseChannelOption(arg) : DefaultChannels );
@@ -615,7 +762,7 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
           /* SyncImageSettings() used to set per-image attribute. */
           (void) SetLogEventMask(ArgOption("none"));
           image_info->debug=IsEventLogging(); /* extract logging*/
-          wand->debug=IsEventLogging();
+          cli_wand->wand.debug=IsEventLogging();
           break;
         }
       if (LocaleCompare("define",option) == 0)
@@ -898,97 +1045,6 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
           (void) SetImageOption(image_info,option,ArgOption(NULL));
           break;
         }
-      if (LocaleCompare("list",option) == 0)
-        {
-          ssize_t
-            list;
-
-          /* FUTURE: This is not really a Setting Option, but a Special
-           * The bulk of this should be turned into a MagickCore function
-           */
-          list=ParseCommandOption(MagickListOptions,MagickFalse,
-               ArgOption("list"));
-          switch (list)
-          {
-            case MagickCoderOptions:
-            {
-              (void) ListCoderInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickColorOptions:
-            {
-              (void) ListColorInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickConfigureOptions:
-            {
-              (void) ListConfigureInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickDelegateOptions:
-            {
-              (void) ListDelegateInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickFontOptions:
-            {
-              (void) ListTypeInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickFormatOptions:
-            {
-              (void) ListMagickInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickLocaleOptions:
-            {
-              (void) ListLocaleInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickLogOptions:
-            {
-              (void) ListLogInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickMagicOptions:
-            {
-              (void) ListMagicInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickMimeOptions:
-            {
-              (void) ListMimeInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickModuleOptions:
-            {
-              (void) ListModuleInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickPolicyOptions:
-            {
-              (void) ListPolicyInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickResourceOptions:
-            {
-              (void) ListMagickResourceInfo((FILE *) NULL,exception);
-              break;
-            }
-            case MagickThresholdOptions:
-            {
-              (void) ListThresholdMaps((FILE *) NULL,exception);
-              break;
-            }
-            default:
-            {
-              (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
-                exception);
-              break;
-            }
-          }
-          break;
-        }
       if (LocaleCompare("log",option) == 0)
         {
           if (IfSetOption)
@@ -1170,6 +1226,11 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
           draw_info->render= IfSetOption ? MagickFalse : MagickTrue;
           break;
         }
+      if (LocaleCompare("respect-parenthesis",option) == 0)
+        {
+          (void) SetImageOption(image_info,option,ArgOption(NULL));
+          break;
+        }
       break;
     }
     case 's':
@@ -1412,9 +1473,9 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
       break;
   }
 #undef image_info
+#undef exception
 #undef draw_info
 #undef quantize_info
-#undef exception
 #undef IfSetOption
 #undef ArgOption
 #undef ArgBoolean
@@ -1427,28 +1488,28 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+     W a n d S i m p l e O p e r a t o r I m a g e s                         %
++     C L I S i m p l e O p e r a t o r I m a g e s                           %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  WandSimpleOperatorImages() applys one simple image operation given to all
-%  the images in the current wand,  with the settings that are saved in the
-%  CLI wand.
+%  the images in the CLI wand,  with the settings that was previously saved in
+%  the CLI wand.
 %
 %  It is assumed that any per-image settings are up-to-date with respect to
-%  extra settings that have been saved in the wand.
+%  extra settings that were already saved in the wand.
 %
 %  The format of the WandSimpleOperatorImage method is:
 %
-%    void WandSimpleOperatorImages(MagickWand *wand,
+%    void CLISimpleOperatorImages(MagickCLI *cli_wand,
 %        const MagickBooleanType plus_alt_op, const char *option,
 %        const char *arg1, const char *arg2)
 %
 %  A description of each parameter follows:
 %
-%    o wand: structure holding settings to be applied
+%    o cli_wand: structure holding settings and images to be operated on
 %
 %    o plus_alt_op:  request the 'plus' or alturnative form of the operation
 %
@@ -1460,23 +1521,24 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
 %
 % Example usage...
 %
-%  WandSimpleOperatorImages(wand, MagickFalse,"crop","100x100+20+30",NULL);
-%  WandSimpleOperatorImages(wand, MagickTrue, "repage",NULL,NULL);
-%  WandSimpleOperatorImages(wand, MagickTrue, "distort","SRT","45");
-%  if ( wand->exception->severity != UndefinedException ) {
+%  CLISimpleOperatorImages(cli_wand, MagickFalse,"crop","100x100+20+30",NULL);
+%  CLISimpleOperatorImages(cli_wand, MagickTrue, "repage",NULL,NULL);
+%  CLISimpleOperatorImages(cli_wand, MagickTrue, "distort","SRT","45");
+%  if ( cli_wand->wand.exception->severity != UndefinedException ) {
 %    CatchException(exception);
 %    exit(1);
 %  }
 %
 % Or for handling command line arguments EG: +/-option ["arg"]
 %
+%    cli_wand
 %    argc,argv
 %    i=index in argv
 %
 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
 %    if ( (flags & SimpleOperatorOptionFlag) != 0 )
-%      WandSimpleOperatorImages(wand,
+%      CLISimpleOperatorImages(cli_wand,
 %          ((*argv[i])=='+')?MagickTrue:MagickFalse,argv[i]+1,
 %          count>=1 ? argv[i+1] : (char *)NULL,
 %          count>=2 ? argv[i+2] : (char *)NULL );
@@ -1486,7 +1548,7 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
 
 /*
   Internal subrountine to apply one simple image operation to the current
-  image pointed to by the wand.
+  image pointed to by the CLI wand.
 
   The image in the list may be modified in three different ways...
     * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
@@ -1501,7 +1563,7 @@ WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
   also change.  GetFirstImageInList() should be used by caller if they wish
   return the Image pointer to the first image in list.
 */
-static void WandSimpleOperatorImage(MagickWand *wand,
+static void CLISimpleOperatorImage(MagickCLI *cli_wand,
   const MagickBooleanType plus_alt_op, const char *option,
   const char *arg1, const char *arg2)
 {
@@ -1517,21 +1579,19 @@ static void WandSimpleOperatorImage(MagickWand *wand,
   MagickStatusType
     flags;
 
-#define image_info      (wand->image_info)
-#define draw_info       (wand->draw_info)
-#define quantize_info   (wand->quantize_info)
-#define image           (wand->images)
-#define exception       (wand->exception)
+#define image_info      (cli_wand->wand.image_info)
+#define image           (cli_wand->wand.images)
+#define exception       (cli_wand->wand.exception)
+#define draw_info       (cli_wand->draw_info)
+#define quantize_info   (cli_wand->quantize_info)
 #define normal_op       (plus_alt_op?MagickFalse:MagickTrue)
 
-  assert(image_info != (const ImageInfo *) NULL);
-  assert(image_info->signature == MagickSignature);
-  assert(draw_info != (DrawInfo *) NULL);      /* ensure it is a CLI wand */
-  assert(image != (Image *) NULL);             /* there is an image */
-  assert(image->signature == MagickSignature); /* and is a valid image */
-
-  if (wand->debug != MagickFalse)
-    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  assert(cli_wand->wand.signature == WandSignature);
+  assert(image != (Image *) NULL);             /* an image must be present */
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
 
   SetGeometryInfo(&geometry_info);
 
@@ -1803,15 +1863,15 @@ static void WandSimpleOperatorImage(MagickWand *wand,
           (void) ClampImage(image,exception);
           break;
         }
-      if (LocaleCompare("clip",option) == 0)
+      if (LocaleCompare("cli_wandp",option) == 0)
         {
           if (plus_alt_op == MagickFalse)
             (void) ClipImage(image,exception);
-          else /* "+clip" remove the write mask */
+          else /* "+mask" remove the write mask */
             (void) SetImageMask(image,(Image *) NULL,exception);
           break;
         }
-      if (LocaleCompare("clip-mask",option) == 0)
+      if (LocaleCompare("cli_wandp-mask",option) == 0)
         {
           CacheView
             *mask_view;
@@ -1829,7 +1889,7 @@ static void WandSimpleOperatorImage(MagickWand *wand,
             y;
 
           if (plus_alt_op != MagickFalse)
-          { /* "+clip-mask" Remove the write mask */
+          { /* "+cli_wandp-mask" Remove the write mask */
               (void) SetImageMask(image,(Image *) NULL,exception);
               break;
             }
@@ -1839,7 +1899,7 @@ static void WandSimpleOperatorImage(MagickWand *wand,
           if (SetImageStorageClass(mask_image,DirectClass,exception)
                == MagickFalse)
             break;
-          /* Create a write mask from clip-mask image */
+          /* Create a write mask from cli_wandp-mask image */
           /* FUTURE: use Alpha operations instead and create a Grey Image */
           mask_view=AcquireCacheView(mask_image);
           for (y=0; y < (ssize_t) mask_image->rows; y++)
@@ -1867,7 +1927,7 @@ static void WandSimpleOperatorImage(MagickWand *wand,
           mask_image=DestroyImage(mask_image);
           break;
         }
-      if (LocaleCompare("clip-path",option) == 0)
+      if (LocaleCompare("cli_wandp-path",option) == 0)
         {
           (void) ClipImagePath(image,arg1,
                (MagickBooleanType)(!(int)plus_alt_op),exception);
@@ -2940,6 +3000,7 @@ static void WandSimpleOperatorImage(MagickWand *wand,
       if (LocaleCompare("separate",option) == 0)
         {
           /* WARNING: This can generate multiple images! */
+          /* FUTURE - this may be replaced by a "-channel" method */
           new_image=SeparateImages(image,exception);
           break;
         }
@@ -3298,34 +3359,34 @@ static void WandSimpleOperatorImage(MagickWand *wand,
 #undef normal_op
 }
 
-WandExport void WandSimpleOperatorImages(MagickWand *wand,
+WandExport void CLISimpleOperatorImages(MagickCLI *cli_wand,
   const MagickBooleanType plus_alt_op, const char *option,
   const char *arg1, const char *arg2)
 {
   size_t
-    n;
-
-  register ssize_t
+    n,
     i;
 
-  assert(wand->image_info != (const ImageInfo *) NULL);
-  assert(wand->image_info->signature == MagickSignature);
-  assert(wand->draw_info != (DrawInfo *) NULL);   /* ensure it is a CLI wand */
-  assert(wand->images != (Image *) NULL);         /* there is one image */
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  assert(cli_wand->wand.signature == WandSignature);
+  assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
 
   i=0;
-  n=GetImageListLength(wand->images);
-  (void) n;
-  wand->images=GetFirstImageInList(wand->images);
-  for ( ; ; )
+  n=GetImageListLength(cli_wand->wand.images);
+  cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
+  while (1)
   {
-    WandSimpleOperatorImage(wand, plus_alt_op, option, arg1, arg2);
-    if ( wand->images->next == (Image *) NULL )
-      break;
-    wand->images=wand->images->next;
     i++;
+    CLISimpleOperatorImage(cli_wand, plus_alt_op, option, arg1, arg2);
+    if ( cli_wand->wand.images->next == (Image *) NULL )
+      break;
+    cli_wand->wand.images=cli_wand->wand.images->next;
   }
-  wand->images=GetFirstImageInList(wand->images);
+  assert( i == n );
+  cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
   return;
 }
 \f
@@ -3334,25 +3395,25 @@ WandExport void WandSimpleOperatorImages(MagickWand *wand,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+     W a n d L i s t O p e r a t o r I m a g e s                             %
++     C L I L i s t O p e r a t o r I m a g e s                               %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  WandListOperatorImages() applies a single operation that is apply to the
+%  CLIListOperatorImages() applies a single operation that is apply to the
 %  entire image list as a whole. The result is often a complete replacment
 %  of the image list with a completely new list, or just a single image.
 %
 %  The format of the MogrifyImage method is:
 %
-%    void WandListOperatorImages(MagickWand *wand,
+%    void CLIListOperatorImages(MagickCLI *cli_wand,
 %        const MagickBooleanType plus_alt_op,const char *option,
 %        const char *arg1, const char *arg2)
 %
 %  A description of each parameter follows:
 %
-%    o wand: structure holding settings to be applied
+%    o cli_wand: structure holding settings to be applied
 %
 %    o plus_alt_op:  request the 'plus' or alturnative form of the operation
 %
@@ -3364,50 +3425,49 @@ WandExport void WandSimpleOperatorImages(MagickWand *wand,
 %
 % Example usage...
 %
-%  WandListOperatorImages(wand,MagickFalse,"duplicate", "3",  NULL);
-%  WandListOperatorImages(wand,MagickTrue, "append",    NULL, NULL);
-%  if ( wand->exception->severity != UndefinedException ) {
+%  CLIListOperatorImages(cli_wand,MagickFalse,"duplicate", "3",  NULL);
+%  CLIListOperatorImages(cli_wand,MagickTrue, "append",    NULL, NULL);
+%  if ( cli_wand->wand.exception->severity != UndefinedException ) {
 %    CatchException(exception);
 %    exit(1);
 %  }
 %
 % Or for handling command line arguments EG: +/-option ["arg"]
 %
+%    cli_wand
 %    argc,argv
 %    i=index in argv
 %
 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
 %    if ( (flags & ListOperatorOptionFlag) != 0 )
-%      WandListOperatorImages(wand,
+%      CLIListOperatorImages(cli_wand,
 %          ((*argv[i])=='+')?MagickTrue:MagickFalse,argv[i]+1,
 %          count>=1 ? argv[i+1] : (char *)NULL,
 %          count>=2 ? argv[i+2] : (char *)NULL );
 %    i += count+1;
 %
 */
-WandExport void WandListOperatorImages(MagickWand *wand,
+WandExport void CLIListOperatorImages(MagickCLI *cli_wand,
      const MagickBooleanType plus_alt_op,const char *option,
      const char *arg1, const char *arg2)
 {
   Image
     *new_images;
 
-#define image_info      (wand->image_info)
-#define draw_info       (wand->draw_info)
-#define quantize_info   (wand->quantize_info)
-#define images          (wand->images)
-#define exception       (wand->exception)
+#define image_info      (cli_wand->wand.image_info)
+#define images          (cli_wand->wand.images)
+#define exception       (cli_wand->wand.exception)
+#define draw_info       (cli_wand->draw_info)
+#define quantize_info   (cli_wand->quantize_info)
 #define normal_op       (plus_alt_op?MagickFalse:MagickTrue)
 
-  assert(image_info != (const ImageInfo *) NULL);
-  assert(image_info->signature == MagickSignature);
-  assert(draw_info != (DrawInfo *) NULL);       /* ensure it is a CLI wand */
-  assert(images != (Image *) NULL);             /* there is an image */
-  assert(images->signature == MagickSignature); /* and is a valid image */
-
-  if (wand->debug != MagickFalse)
-    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  assert(cli_wand->wand.signature == WandSignature);
+  assert(images != (Image *) NULL);             /* images must be present */
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
 
   (void) SyncImagesSettings(image_info,images,exception);
 
@@ -3425,7 +3485,7 @@ WandExport void WandListOperatorImages(MagickWand *wand,
       if (LocaleCompare("average",option) == 0)
         {
           /* DEPRECIATED - use -evaluate-sequence Mean */
-          WandListOperatorImages(wand,plus_alt_op,"evaluate-sequence","Mean",
+          CLIListOperatorImages(cli_wand,plus_alt_op,"evaluate-sequence","Mean",
                NULL);
           break;
         }
@@ -3462,6 +3522,7 @@ WandExport void WandListOperatorImages(MagickWand *wand,
         }
       if (LocaleCompare("combine",option) == 0)
         {
+          /* FUTURE - this may be replaced by a 'channel' method */
           new_images=CombineImages(images,exception);
           break;
         }
@@ -3535,7 +3596,7 @@ WandExport void WandListOperatorImages(MagickWand *wand,
       if (LocaleCompare("deconstruct",option) == 0)
         {
           /* DEPRECIATED - use -layers CompareAny */
-          WandListOperatorImages(wand,plus_alt_op,"layer","CompareAny",NULL);
+          CLIListOperatorImages(cli_wand,plus_alt_op,"layer","CompareAny",NULL);
           break;
         }
       if (LocaleCompare("delete",option) == 0)
@@ -3597,7 +3658,7 @@ WandExport void WandListOperatorImages(MagickWand *wand,
       if (LocaleCompare("flatten",option) == 0)
         {
           /* DEPRECIATED use -layers mosaic instead */
-          WandListOperatorImages(wand,plus_alt_op,"layer",option,NULL);
+          CLIListOperatorImages(cli_wand,plus_alt_op,"layer",option,NULL);
           break;
         }
       if (LocaleCompare("fx",option) == 0)
@@ -3659,22 +3720,22 @@ WandExport void WandListOperatorImages(MagickWand *wand,
           insert_image=RemoveLastImageFromList(&images);
           if (plus_alt_op == MagickFalse)
             index=(ssize_t) StringToLong(arg1);
+          index_image=insert_image;
           if (index == 0)
             PrependImageToList(&images,insert_image);
+          else if (index == (ssize_t) GetImageListLength(images))
+            AppendImageToList(&images,insert_image);
           else
-            if (index == (ssize_t) GetImageListLength(images))
-              AppendImageToList(&images,insert_image);
-            else
-              {
-                 index_image=GetImageFromList(images,index-1);
-                 if (index_image == (Image *) NULL)
-                   {
-                     (void) ThrowMagickException(exception,GetMagickModule(),
-                       OptionError,"NoSuchImage","`%s'",arg1);
-                     break;
-                   }
-                InsertImageInList(&index_image,insert_image);
-              }
+            {
+               index_image=GetImageFromList(images,index-1);
+               if (index_image == (Image *) NULL)
+                 {
+                   (void) ThrowMagickException(exception,GetMagickModule(),
+                     OptionError,"NoSuchImage","'%s'",arg1);
+                   break;
+                 }
+              InsertImageInList(&index_image,insert_image);
+            }
           images=GetFirstImageInList(index_image);
           break;
         }
@@ -3866,7 +3927,7 @@ WandExport void WandListOperatorImages(MagickWand *wand,
       if (LocaleCompare("mosaic",option) == 0)
         {
           /* DEPRECIATED use -layers mosaic instead */
-          WandListOperatorImages(wand,plus_alt_op,"layer",option,NULL);
+          CLIListOperatorImages(cli_wand,plus_alt_op,"layer",option,NULL);
           break;
         }
       break;
@@ -4020,7 +4081,7 @@ WandExport void WandListOperatorImages(MagickWand *wand,
           if ((p == (Image *) NULL) || (q == (Image *) NULL))
             {
               (void) ThrowMagickException(exception,GetMagickModule(),
-                OptionError,"NoSuchImage","`%s'",images->filename);
+                OptionError,"NoSuchImage","'%s'",images->filename);
               break;
             }
           if (p == q)
@@ -4068,13 +4129,355 @@ WandExport void WandListOperatorImages(MagickWand *wand,
 
   if (images != (Image *) NULL)
     images=DestroyImageList(images);
-  images=new_images;
+  images=GetFirstImageInList(new_images);
   return;
 
 #undef image_info
+#undef images
+#undef exception
 #undef draw_info
 #undef quantize_info
+#undef normal_op
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C L I S p e c i a l O p e r a t i o n s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CLISpecialOption() Applies operations that may involve empty image lists
+%  and or stacks of image lists or image_info settings.
+%
+%  Note: inlike other Operators, these may involve other special 'option'
+%  character prefixes, other than simply '-' or '+' and as such the full
+%  original otpion must be passed.
+%
+%  The format of the CLISpecialOption method is:
+%
+%      void CLISpecialOption(MagickCLI *cli_wand,const char *option,
+%           const char *arg)
+%
+%  A description of each parameter follows:
+%
+%    o cli_wand: the main CLI Wand to use.
+%
+%    o option: The special option (with any switch char) to process
+%
+%    o arg: Argument for option, if required
+%
+*/
+
+#define MaxImageStackDepth  32
+
+WandExport void CLISpecialOperator(MagickCLI *cli_wand,
+  const char *option, const char *arg)
+{
+#define exception       (cli_wand->wand.exception)
+
+  assert(cli_wand != (MagickCLI *) NULL);
+  assert(cli_wand->signature == WandSignature);
+  assert(cli_wand->wand.signature == WandSignature);
+  if (cli_wand->wand.debug != MagickFalse)
+    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
+
+  if (LocaleCompare(option,"(") == 0)
+    {
+      /* stack 'push' images */
+      Stack
+        *node;
+
+      size_t
+        size;
+
+      const char*
+        value;
+
+      size=0;
+      node=cli_wand->image_list_stack;
+      for ( ; node != (Stack *)NULL; node=node->next)
+        size++;
+      if ( size >= MaxImageStackDepth )
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"ParenthesisNestedTooDeeply", option);
+          return;
+        }
+      node=(Stack *) AcquireMagickMemory(sizeof(*node));
+      if (node == (Stack *) NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+              ResourceLimitFatalError,"MemoryAllocationFailed", "PushImages");
+          return;
+        }
+      node->data = (void *)cli_wand->wand.images;
+      cli_wand->wand.images = NewImageList();
+      node->next = cli_wand->image_list_stack;
+      cli_wand->image_list_stack = node;
+
+      /* handle respect-parenthesis */
+      value=GetImageOption(cli_wand->wand.image_info,"respect-parenthesis");
+      if (value != (const char *) NULL)
+        option="{";
+      else
+        return;
+    }
+  if (LocaleCompare(option,"{") == 0)
+    {
+      /* stack 'push' of image_info settings */
+      Stack
+        *node;
+
+      size_t
+        size;
+
+      size=0;
+      node=cli_wand->image_info_stack;
+      for ( ; node != (Stack *)NULL; node=node->next)
+        size++;
+      if ( size >= MaxImageStackDepth )
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"ParenthesisNestedTooDeeply", option);
+          return;
+        }
+      node=(Stack *) AcquireMagickMemory(sizeof(*node));
+      if (node == (Stack *) NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+              ResourceLimitFatalError,"MemoryAllocationFailed", "PushSettings");
+          return;
+        }
+
+      node->data = (void *)cli_wand->wand.image_info;
+      cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
+      if (cli_wand->wand.image_info == (ImageInfo *)NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+              ResourceLimitFatalError,"MemoryAllocationFailed", "PushSettings");
+          cli_wand->wand.image_info = (ImageInfo *)node->data;
+          node = (Stack *)RelinquishMagickMemory(node);
+          return;
+        }
+
+      node->next = cli_wand->image_info_stack;
+      cli_wand->image_info_stack = node;
+
+      return;
+    }
+  if (LocaleCompare(option,")") == 0)
+    {
+      /* pop images from stack */
+      Stack
+        *node;
+
+      const char*
+        value;
+
+      node = (void *)cli_wand->image_list_stack;
+      if ( node == (Stack *)NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"UnbalancedParenthesis", option);
+          return;
+        }
+      cli_wand->image_list_stack = node->next;
+
+      AppendImageToList((Image **)&node->data,cli_wand->wand.images);
+      cli_wand->wand.images= (Image *)node->data;
+      node = (Stack *)RelinquishMagickMemory(node);
+
+      /* handle respect-parenthesis - of the previous 'push' settings */
+      node = cli_wand->image_info_stack;
+      if ( node != (Stack *)NULL)
+        {
+          value=GetImageOption((ImageInfo *)node->data,"respect-parenthesis");
+          if (value != (const char *) NULL)
+            option="}";
+          else
+            return;
+        }
+      else
+        return;
+    }
+  if (LocaleCompare(option,"}") == 0)
+    {
+      /* pop image_info settings from stack */
+      Stack
+        *node;
+
+      node = (void *)cli_wand->image_info_stack;
+      if ( node == (Stack *)NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"UnbalancedParenthesis", option);
+          return;
+        }
+      cli_wand->image_info_stack = node->next;
+
+      (void) DestroyImageInfo(cli_wand->wand.image_info);
+      cli_wand->wand.image_info = (ImageInfo *)node->data;
+      node = (Stack *)RelinquishMagickMemory(node);
+
+      GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
+      cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
+      cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
+
+      return;
+    }
+  if (LocaleCompare(option+1,"clone") == 0)
+    {
+      Image
+        *new_images;
+
+      if (*option == '+')
+        arg="-1";
+      if (IsSceneGeometry(arg,MagickFalse) == MagickFalse)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"InvalidArgument", "'%s': %s", option, arg);
+          return;
+        }
+      if ( cli_wand->image_list_stack == (Stack *)NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"UnableToCloneImage", option);
+          return;
+        }
+      new_images = (Image *)cli_wand->image_list_stack->data;
+      if (new_images == (Image *) NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+               OptionError,"UnableToCloneImage", option);
+          return;
+        }
+      new_images=CloneImages(new_images,arg,exception);
+      if (new_images == (Image *) NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"NoSuchImage",option);
+          return;
+        }
+      AppendImageToList(&cli_wand->wand.images,new_images);
+      return;
+    }
+  if ( LocaleCompare("-read",option) == 0 )
+    {
+#if 1
+      Image *
+        new_images;
+
+      CopyMagickString(cli_wand->wand.image_info->filename,arg,MaxTextExtent);
+      if (cli_wand->wand.image_info->ping != MagickFalse)
+        new_images=PingImages(cli_wand->wand.image_info,exception);
+      else
+        new_images=ReadImages(cli_wand->wand.image_info,exception);
+      AppendImageToList(&cli_wand->wand.images, new_images);
+#else
+      /* read images using MagickWand method - no ping */
+      /* This is not working! - it locks up in a CPU loop! */
+      MagickSetLastIterator(&cli_wand->wand);
+      MagickReadImage(&cli_wand->wand,arg);
+      MagickSetFirstIterator(&cli_wand->wand);
+#endif
+      return;
+    }
+  if (LocaleCompare("-noop",option) == 0)
+    return;
+  if (LocaleCompare("-sans",option) == 0)
+    return;
+  if (LocaleCompare("-sans0",option) == 0)
+    return;
+  if (LocaleCompare("-sans2",option) == 0)
+    return;
+  if (LocaleCompare("-list",option) == 0)
+    {
+      /* FUTURE: This should really be built into the MagickCore
+         It does not actually require any wand or images at all!
+       */
+      ssize_t
+        list;
+
+      list=ParseCommandOption(MagickListOptions,MagickFalse, arg);
+      switch (list)
+      {
+        case MagickCoderOptions:
+        {
+          (void) ListCoderInfo((FILE *) NULL,exception);
+          break;
+        }
+        case MagickColorOptions:
+        {
+          (void) ListColorInfo((FILE *) NULL,exception);
+          break;
+        }
+        case MagickConfigureOptions:
+        {
+          (void) ListConfigureInfo((FILE *) NULL,exception);
+          break;
+        }
+        case MagickDelegateOptions:
+        {
+          (void) ListDelegateInfo((FILE *) NULL,exception);
+          break;
+        }
+        case MagickFontOptions:
+        {
+          (void) ListTypeInfo((FILE *) NULL,exception);
+          break;
+        }
+        case MagickFormatOptions:
+          (void) ListMagickInfo((FILE *) NULL,exception);
+          break;
+        case MagickLocaleOptions:
+          (void) ListLocaleInfo((FILE *) NULL,exception);
+          break;
+        case MagickLogOptions:
+          (void) ListLogInfo((FILE *) NULL,exception);
+          break;
+        case MagickMagicOptions:
+          (void) ListMagicInfo((FILE *) NULL,exception);
+          break;
+        case MagickMimeOptions:
+          (void) ListMimeInfo((FILE *) NULL,exception);
+          break;
+        case MagickModuleOptions:
+          (void) ListModuleInfo((FILE *) NULL,exception);
+          break;
+        case MagickPolicyOptions:
+          (void) ListPolicyInfo((FILE *) NULL,exception);
+          break;
+        case MagickResourceOptions:
+          (void) ListMagickResourceInfo((FILE *) NULL,exception);
+          break;
+        case MagickThresholdOptions:
+          (void) ListThresholdMaps((FILE *) NULL,exception);
+          break;
+        default:
+          (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
+            exception);
+          break;
+      }
+      return;
+    }
+
+#if 0
+    // adjust stack handling
+  // Other 'special' options this should handle
+  //    "region" "list" "version"
+  // It does not do "exit" however as due to its side-effect requirements
+#endif
+#if 0
+  if ( ( process_flags & ProcessUnknownOptionError ) != 0 )
+    MagickExceptionReturn(OptionError,"InvalidUseOfOption",option);
+#endif
+
+#undef image_info
 #undef images
 #undef exception
-#undef normal_op
 }
index 6ab6369489c7c6d681c6a3241a6ed330ae6deffb..d586a14b05dbb1fd1af2b44f9d3b2f7f25e39332 100644 (file)
@@ -23,12 +23,17 @@ extern "C" {
 #endif
 
 
+extern WandExport MagickCLI
+  *AcquireMagickCLI(ImageInfo *,ExceptionInfo *),
+  *DestroyMagickCLI(MagickCLI *);
+
 extern WandExport void
-  WandSettingOptionInfo(MagickWand *,const char *,const char *),
-  WandSimpleOperatorImages(MagickWand *,const MagickBooleanType,
+  CLISettingOptionInfo(MagickCLI *,const char *,const char *),
+  CLISimpleOperatorImages(MagickCLI *,const MagickBooleanType,
+       const char *,const char *,const char *),
+  CLIListOperatorImages(MagickCLI *,const MagickBooleanType,
        const char *,const char *,const char *),
-  WandListOperatorImages(MagickWand *,const MagickBooleanType,
-       const char *,const char *,const char *);
+  CLISpecialOperator(MagickCLI *,const char *,const char *);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }