Commit message: None
CVE: CVE-2019-13310
CWE: CWE-399
Vulnerability description: ImageMagick 7.0.8-50 Q16 has memory leaks at AcquireMagickMemory because of an error in MagickWand/mogrify.c.

Project: ImageMagick6

WandExport MagickBooleanType MogrifyImageList(ImageInfo *image_info,
  const int argc,const char **argv,Image **images,ExceptionInfo *exception)
{
  const char
    *option;

  ImageInfo
    *mogrify_info;

  MagickStatusType
    status;

  PixelInterpolateMethod
   interpolate_method;

  QuantizeInfo
    *quantize_info;

  register ssize_t
    i;

  ssize_t
    count,
    index;

  /*
    Apply options to the image list.
  */
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(images != (Image **) NULL);
  assert((*images)->previous == (Image *) NULL);
  assert((*images)->signature == MagickCoreSignature);
  if ((*images)->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      (*images)->filename);
  if ((argc <= 0) || (*argv == (char *) NULL))
    return(MagickTrue);
  interpolate_method=UndefinedInterpolatePixel;
  mogrify_info=CloneImageInfo(image_info);
  quantize_info=AcquireQuantizeInfo(mogrify_info);
  status=MagickTrue;
  for (i=0; i < (ssize_t) argc; i++)
  {
    if (*images == (Image *) NULL)
      break;
    option=argv[i];
    if (IsCommandOption(option) == MagickFalse)
      continue;
    count=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
    count=MagickMax(count,0L);
    if ((i+count) >= (ssize_t) argc)
      break;
    status=MogrifyImageInfo(mogrify_info,(int) count+1,argv+i,exception);
    switch (*(option+1))
    {
      case 'a':
      {
        if (LocaleCompare("affinity",option+1) == 0)
          {
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            if (*option == '+')
              {
                (void) RemapImages(quantize_info,*images,(Image *) NULL,
                  exception);
                break;
              }
            i++;
            break;
          }
        if (LocaleCompare("append",option+1) == 0)
          {
            Image
              *append_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            append_image=AppendImages(*images,*option == '-' ? MagickTrue :
              MagickFalse,exception);
            if (append_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=append_image;
            break;
          }
        if (LocaleCompare("average",option+1) == 0)
          {
            Image
              *average_image;

            /*
              Average an image sequence (deprecated).
            */
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            average_image=EvaluateImages(*images,MeanEvaluateOperator,
              exception);
            if (average_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=average_image;
            break;
          }
        break;
      }
      case 'c':
      {
        if (LocaleCompare("channel-fx",option+1) == 0)
          {
            Image
              *channel_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            channel_image=ChannelFxImage(*images,argv[i+1],exception);
            if (channel_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=channel_image;
            break;
          }
        if (LocaleCompare("clut",option+1) == 0)
          {
            Image
              *clut_image,
              *image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            image=RemoveFirstImageFromList(images);
            clut_image=RemoveFirstImageFromList(images);
            if (clut_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            (void) ClutImage(image,clut_image,interpolate_method,exception);
            clut_image=DestroyImage(clut_image);
            *images=DestroyImageList(*images);
            *images=image;
            break;
          }
        if (LocaleCompare("coalesce",option+1) == 0)
          {
            Image
              *coalesce_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            coalesce_image=CoalesceImages(*images,exception);
            if (coalesce_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=coalesce_image;
            break;
          }
        if (LocaleCompare("combine",option+1) == 0)
          {
            ColorspaceType
              colorspace;

            Image
              *combine_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            colorspace=(*images)->colorspace;
            if ((*images)->number_channels < GetImageListLength(*images))
              colorspace=sRGBColorspace;
            if (*option == '+')
              colorspace=(ColorspaceType) ParseCommandOption(
                MagickColorspaceOptions,MagickFalse,argv[i+1]);
            combine_image=CombineImages(*images,colorspace,exception);
            if (combine_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=combine_image;
            break;
          }
        if (LocaleCompare("compare",option+1) == 0)
          {
            double
              distortion;

            Image
              *difference_image,
              *image,
              *reconstruct_image;

            MetricType
              metric;

            /*
              Mathematically and visually annotate the difference between an
              image and its reconstruction.
            */
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            image=RemoveFirstImageFromList(images);
            reconstruct_image=RemoveFirstImageFromList(images);
            if (reconstruct_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            metric=UndefinedErrorMetric;
            option=GetImageOption(mogrify_info,"metric");
            if (option != (const char *) NULL)
              metric=(MetricType) ParseCommandOption(MagickMetricOptions,
                MagickFalse,option);
            difference_image=CompareImages(image,reconstruct_image,metric,
               &distortion,exception);
             if (difference_image == (Image *) NULL)
               break;
             if (*images != (Image *) NULL)
               *images=DestroyImageList(*images);
             *images=difference_image;
            break;
          }
        if (LocaleCompare("complex",option+1) == 0)
          {
            ComplexOperator
              op;

            Image
              *complex_images;

            (void) SyncImageSettings(mogrify_info,*images,exception);
            op=(ComplexOperator) ParseCommandOption(MagickComplexOptions,
              MagickFalse,argv[i+1]);
            complex_images=ComplexImages(*images,op,exception);
            if (complex_images == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=complex_images;
            break;
          }
        if (LocaleCompare("composite",option+1) == 0)
          {
            CompositeOperator
              compose;

            const char*
              value;

            MagickBooleanType
              clip_to_self;

            Image
              *mask_image,
              *new_images,
              *source_image;

            RectangleInfo
              geometry;

            /* Compose value from "-compose" option only */
            (void) SyncImageSettings(mogrify_info,*images,exception);
            value=GetImageOption(mogrify_info,"compose");
            if (value == (const char *) NULL)
              compose=OverCompositeOp;  /* use Over not source_image->compose */
            else
              compose=(CompositeOperator) ParseCommandOption(
                MagickComposeOptions,MagickFalse,value);

            /* Get "clip-to-self" expert setting (false is normal) */
            clip_to_self=GetCompositeClipToSelf(compose);
            value=GetImageOption(mogrify_info,"compose:clip-to-self");
            if (value != (const char *) NULL)
              clip_to_self=IsStringTrue(value);
            value=GetImageOption(mogrify_info,"compose:outside-overlay");
            if (value != (const char *) NULL)
              clip_to_self=IsStringFalse(value);  /* deprecated */

            new_images=RemoveFirstImageFromList(images);
            source_image=RemoveFirstImageFromList(images);
            if (source_image == (Image *) NULL)
              break; /* FUTURE - produce Exception, rather than silent fail */

            /* FUTURE: this should not be here! - should be part of -geometry */
            if (source_image->geometry != (char *) NULL)
              {
                RectangleInfo
                  resize_geometry;

                (void) ParseRegionGeometry(source_image,source_image->geometry,
                  &resize_geometry,exception);
                if ((source_image->columns != resize_geometry.width) ||
                    (source_image->rows != resize_geometry.height))
                  {
                    Image
                      *resize_image;

                    resize_image=ResizeImage(source_image,resize_geometry.width,
                      resize_geometry.height,source_image->filter,exception);
                    if (resize_image != (Image *) NULL)
                      {
                        source_image=DestroyImage(source_image);
                        source_image=resize_image;
                      }
                  }
              }
            SetGeometry(source_image,&geometry);
            (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
            GravityAdjustGeometry(new_images->columns,new_images->rows,
              new_images->gravity,&geometry);
            mask_image=RemoveFirstImageFromList(images);
            if (mask_image == (Image *) NULL)
              status&=CompositeImage(new_images,source_image,compose,
                clip_to_self,geometry.x,geometry.y,exception);
            else
              {
                if ((compose == DisplaceCompositeOp) ||
                    (compose == DistortCompositeOp))
                  {
                    status&=CompositeImage(source_image,mask_image,
                      CopyGreenCompositeOp,MagickTrue,0,0,exception);
                    status&=CompositeImage(new_images,source_image,compose,
                      clip_to_self,geometry.x,geometry.y,exception);
                  }
                else
                  {
                    Image
                      *clone_image;

                    clone_image=CloneImage(new_images,0,0,MagickTrue,exception);
                    if (clone_image == (Image *) NULL)
                      break;
                    status&=CompositeImage(new_images,source_image,compose,
                      clip_to_self,geometry.x,geometry.y,exception);
                    status&=CompositeImage(new_images,mask_image,
                      CopyAlphaCompositeOp,MagickTrue,0,0,exception);
                    status&=CompositeImage(clone_image,new_images,
                      OverCompositeOp,clip_to_self,0,0,exception);
                    new_images=DestroyImageList(new_images);
                    new_images=clone_image;
                  }
                mask_image=DestroyImage(mask_image);
              }
            source_image=DestroyImage(source_image);
            *images=DestroyImageList(*images);
            *images=new_images;
            break;
          }
        if (LocaleCompare("copy",option+1) == 0)
          {
            Image
              *source_image;

            OffsetInfo
              offset;

            RectangleInfo
              geometry;

            /*
              Copy image pixels.
            */
            (void) SyncImageSettings(mogrify_info,*images,exception);
            (void) ParsePageGeometry(*images,argv[i+2],&geometry,exception);
            offset.x=geometry.x;
            offset.y=geometry.y;
            source_image=(*images);
            if (source_image->next != (Image *) NULL)
              source_image=source_image->next;
            (void) ParsePageGeometry(source_image,argv[i+1],&geometry,
              exception);
            status=CopyImagePixels(*images,source_image,&geometry,&offset,
              exception);
            break;
          }
        break;
      }
      case 'd':
      {
        if (LocaleCompare("deconstruct",option+1) == 0)
          {
            Image
              *deconstruct_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            deconstruct_image=CompareImagesLayers(*images,CompareAnyLayer,
              exception);
            if (deconstruct_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=deconstruct_image;
            break;
          }
        if (LocaleCompare("delete",option+1) == 0)
          {
            if (*option == '+')
              DeleteImages(images,"-1",exception);
            else
              DeleteImages(images,argv[i+1],exception);
            break;
          }
        if (LocaleCompare("dither",option+1) == 0)
          {
            if (*option == '+')
              {
                quantize_info->dither_method=NoDitherMethod;
                break;
              }
            quantize_info->dither_method=(DitherMethod) ParseCommandOption(
              MagickDitherOptions,MagickFalse,argv[i+1]);
            break;
          }
        if (LocaleCompare("duplicate",option+1) == 0)
          {
            Image
              *duplicate_images;

            if (*option == '+')
              duplicate_images=DuplicateImages(*images,1,"-1",exception);
            else
              {
                const char
                  *p;

                size_t
                  number_duplicates;

                number_duplicates=(size_t) StringToLong(argv[i+1]);
                p=strchr(argv[i+1],',');
                if (p == (const char *) NULL)
                  duplicate_images=DuplicateImages(*images,number_duplicates,
                    "-1",exception);
                else
                  duplicate_images=DuplicateImages(*images,number_duplicates,p,
                    exception);
              }
            AppendImageToList(images, duplicate_images);
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            break;
          }
        break;
      }
      case 'e':
      {
        if (LocaleCompare("evaluate-sequence",option+1) == 0)
          {
            Image
              *evaluate_image;

            MagickEvaluateOperator
              op;

            (void) SyncImageSettings(mogrify_info,*images,exception);
            op=(MagickEvaluateOperator) ParseCommandOption(
              MagickEvaluateOptions,MagickFalse,argv[i+1]);
            evaluate_image=EvaluateImages(*images,op,exception);
            if (evaluate_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=evaluate_image;
            break;
          }
        break;
      }
      case 'f':
      {
        if (LocaleCompare("fft",option+1) == 0)
          {
            Image
              *fourier_image;

            /*
              Implements the discrete Fourier transform (DFT).
            */
            (void) SyncImageSettings(mogrify_info,*images,exception);
            fourier_image=ForwardFourierTransformImage(*images,*option == '-' ?
              MagickTrue : MagickFalse,exception);
            if (fourier_image == (Image *) NULL)
              break;
            *images=DestroyImageList(*images);
            *images=fourier_image;
            break;
          }
        if (LocaleCompare("flatten",option+1) == 0)
          {
            Image
              *flatten_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            flatten_image=MergeImageLayers(*images,FlattenLayer,exception);
            if (flatten_image == (Image *) NULL)
              break;
            *images=DestroyImageList(*images);
            *images=flatten_image;
            break;
          }
        if (LocaleCompare("fx",option+1) == 0)
          {
            Image
              *fx_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            fx_image=FxImage(*images,argv[i+1],exception);
            if (fx_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=fx_image;
            break;
          }
        break;
      }
      case 'h':
      {
        if (LocaleCompare("hald-clut",option+1) == 0)
          {
            Image
              *hald_image,
              *image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            image=RemoveFirstImageFromList(images);
            hald_image=RemoveFirstImageFromList(images);
            if (hald_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            (void) HaldClutImage(image,hald_image,exception);
            hald_image=DestroyImage(hald_image);
            if (*images != (Image *) NULL)
              *images=DestroyImageList(*images);
            *images=image;
            break;
          }
        break;
      }
      case 'i':
      {
        if (LocaleCompare("ift",option+1) == 0)
          {
            Image
              *fourier_image,
              *magnitude_image,
              *phase_image;

            /*
              Implements the inverse fourier discrete Fourier transform (DFT).
            */
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            magnitude_image=RemoveFirstImageFromList(images);
            phase_image=RemoveFirstImageFromList(images);
            if (phase_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            fourier_image=InverseFourierTransformImage(magnitude_image,
              phase_image,*option == '-' ? MagickTrue : MagickFalse,exception);
            if (fourier_image == (Image *) NULL)
              break;
            if (*images != (Image *) NULL)
              *images=DestroyImageList(*images);
            *images=fourier_image;
            break;
          }
        if (LocaleCompare("insert",option+1) == 0)
          {
            Image
              *p,
              *q;

            index=0;
            if (*option != '+')
              index=(ssize_t) StringToLong(argv[i+1]);
            p=RemoveLastImageFromList(images);
            if (p == (Image *) NULL)
              {
                (void) ThrowMagickException(exception,GetMagickModule(),
                  OptionError,"NoSuchImage","`%s'",argv[i+1]);
                status=MagickFalse;
                break;
              }
            q=p;
            if (index == 0)
              PrependImageToList(images,q);
            else
              if (index == (ssize_t) GetImageListLength(*images))
                AppendImageToList(images,q);
              else
                {
                    q=GetImageFromList(*images,index-1);
                    if (q == (Image *) NULL)
                      {
                        (void) ThrowMagickException(exception,GetMagickModule(),
                          OptionError,"NoSuchImage","`%s'",argv[i+1]);
                        status=MagickFalse;
                       break;
                     }
                  InsertImageInList(&q,p);
                }
            *images=GetFirstImageInList(q);
            break;
          }
        if (LocaleCompare("interpolate",option+1) == 0)
          {
            interpolate_method=(PixelInterpolateMethod) ParseCommandOption(
              MagickInterpolateOptions,MagickFalse,argv[i+1]);
            break;
          }
        break;
      }
      case 'l':
      {
        if (LocaleCompare("layers",option+1) == 0)
          {
            Image
              *layers;

            LayerMethod
              method;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            layers=(Image *) NULL;
            method=(LayerMethod) ParseCommandOption(MagickLayerOptions,
              MagickFalse,argv[i+1]);
            switch (method)
            {
              case CoalesceLayer:
              {
                layers=CoalesceImages(*images,exception);
                break;
              }
              case CompareAnyLayer:
              case CompareClearLayer:
              case CompareOverlayLayer:
              default:
              {
                layers=CompareImagesLayers(*images,method,exception);
                break;
              }
              case MergeLayer:
              case FlattenLayer:
              case MosaicLayer:
              case TrimBoundsLayer:
              {
                layers=MergeImageLayers(*images,method,exception);
                break;
              }
              case DisposeLayer:
              {
                layers=DisposeImages(*images,exception);
                break;
              }
              case OptimizeImageLayer:
              {
                layers=OptimizeImageLayers(*images,exception);
                break;
              }
              case OptimizePlusLayer:
              {
                layers=OptimizePlusImageLayers(*images,exception);
                break;
              }
              case OptimizeTransLayer:
              {
                OptimizeImageTransparency(*images,exception);
                break;
              }
              case RemoveDupsLayer:
              {
                RemoveDuplicateLayers(images,exception);
                break;
              }
              case RemoveZeroLayer:
              {
                RemoveZeroDelayLayers(images,exception);
                break;
              }
              case OptimizeLayer:
              {
                /*
                  General Purpose, GIF Animation Optimizer.
                */
                layers=CoalesceImages(*images,exception);
                if (layers == (Image *) NULL)
                  {
                    status=MagickFalse;
                    break;
                  }
                *images=DestroyImageList(*images);
                *images=layers;
                layers=OptimizeImageLayers(*images,exception);
                if (layers == (Image *) NULL)
                  {
                    status=MagickFalse;
                    break;
                  }
                *images=DestroyImageList(*images);
                *images=layers;
                layers=(Image *) NULL;
                OptimizeImageTransparency(*images,exception);
                (void) RemapImages(quantize_info,*images,(Image *) NULL,
                  exception);
                break;
              }
              case CompositeLayer:
              {
                CompositeOperator
                  compose;

                Image
                  *source;

                RectangleInfo
                  geometry;

                /*
                  Split image sequence at the first 'NULL:' image.
                */
                source=(*images);
                while (source != (Image *) NULL)
                {
                  source=GetNextImageInList(source);
                  if ((source != (Image *) NULL) &&
                      (LocaleCompare(source->magick,"NULL") == 0))
                    break;
                }
                if (source != (Image *) NULL)
                  {
                    if ((GetPreviousImageInList(source) == (Image *) NULL) ||
                        (GetNextImageInList(source) == (Image *) NULL))
                      source=(Image *) NULL;
                    else
                      {
                        /*
                          Separate the two lists, junk the null: image.
                        */
                        source=SplitImageList(source->previous);
                        DeleteImageFromList(&source);
                      }
                  }
                if (source == (Image *) NULL)
                  {
                    (void) ThrowMagickException(exception,GetMagickModule(),
                      OptionError,"MissingNullSeparator","layers Composite");
                    status=MagickFalse;
                    break;
                  }
                /*
                  Adjust offset with gravity and virtual canvas.
                */
                SetGeometry(*images,&geometry);
                (void) ParseAbsoluteGeometry((*images)->geometry,&geometry);
                geometry.width=source->page.width != 0 ?
                  source->page.width : source->columns;
                geometry.height=source->page.height != 0 ?
                 source->page.height : source->rows;
                GravityAdjustGeometry((*images)->page.width != 0 ?
                  (*images)->page.width : (*images)->columns,
                  (*images)->page.height != 0 ? (*images)->page.height :
                  (*images)->rows,(*images)->gravity,&geometry);
                compose=OverCompositeOp;
                option=GetImageOption(mogrify_info,"compose");
                if (option != (const char *) NULL)
                  compose=(CompositeOperator) ParseCommandOption(
                    MagickComposeOptions,MagickFalse,option);
                CompositeLayers(*images,compose,source,geometry.x,geometry.y,
                  exception);
                source=DestroyImageList(source);
                break;
              }
            }
            if (layers == (Image *) NULL)
              break;
            *images=DestroyImageList(*images);
            *images=layers;
            break;
          }
        break;
      }
      case 'm':
      {
        if (LocaleCompare("map",option+1) == 0)
          {
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            if (*option == '+')
              {
                (void) RemapImages(quantize_info,*images,(Image *) NULL,
                  exception);
                break;
              }
            i++;
            break;
          }
        if (LocaleCompare("maximum",option+1) == 0)
          {
            Image
              *maximum_image;

            /*
              Maximum image sequence (deprecated).
            */
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            maximum_image=EvaluateImages(*images,MaxEvaluateOperator,exception);
            if (maximum_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=maximum_image;
            break;
          }
        if (LocaleCompare("minimum",option+1) == 0)
          {
            Image
              *minimum_image;

            /*
              Minimum image sequence (deprecated).
            */
            (void) SyncImagesSettings(mogrify_info,*images,exception);
            minimum_image=EvaluateImages(*images,MinEvaluateOperator,exception);
            if (minimum_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=minimum_image;
            break;
          }
        if (LocaleCompare("morph",option+1) == 0)
          {
            Image
              *morph_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            morph_image=MorphImages(*images,StringToUnsignedLong(argv[i+1]),
              exception);
            if (morph_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=morph_image;
            break;
          }
        if (LocaleCompare("mosaic",option+1) == 0)
          {
            Image
              *mosaic_image;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            mosaic_image=MergeImageLayers(*images,MosaicLayer,exception);
            if (mosaic_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=mosaic_image;
            break;
          }
        break;
      }
      case 'p':
      {
        if (LocaleCompare("poly",option+1) == 0)
          {
            char
              *args,
              token[MagickPathExtent];

            const char
              *p;

            double
              *arguments;

            Image
              *polynomial_image;

            register ssize_t
              x;

            size_t
              number_arguments;

            /*
              Polynomial image.
            */
            (void) SyncImageSettings(mogrify_info,*images,exception);
            args=InterpretImageProperties(mogrify_info,*images,argv[i+1],
              exception);
            if (args == (char *) NULL)
              break;
            p=(char *) args;
            for (x=0; *p != '\0'; x++)
            {
              GetNextToken(p,&p,MagickPathExtent,token);
              if (*token == ',')
                GetNextToken(p,&p,MagickPathExtent,token);
            }
            number_arguments=(size_t) x;
            arguments=(double *) AcquireQuantumMemory(number_arguments,
              sizeof(*arguments));
            if (arguments == (double *) NULL)
              ThrowWandFatalException(ResourceLimitFatalError,
                "MemoryAllocationFailed",(*images)->filename);
            (void) memset(arguments,0,number_arguments*
              sizeof(*arguments));
            p=(char *) args;
            for (x=0; (x < (ssize_t) number_arguments) && (*p != '\0'); x++)
            {
              GetNextToken(p,&p,MagickPathExtent,token);
              if (*token == ',')
                GetNextToken(p,&p,MagickPathExtent,token);
              arguments[x]=StringToDouble(token,(char **) NULL);
            }
            args=DestroyString(args);
            polynomial_image=PolynomialImage(*images,number_arguments >> 1,
              arguments,exception);
            arguments=(double *) RelinquishMagickMemory(arguments);
            if (polynomial_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=polynomial_image;
          }
        if (LocaleCompare("print",option+1) == 0)
          {
            char
              *string;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            string=InterpretImageProperties(mogrify_info,*images,argv[i+1],
              exception);
            if (string == (char *) NULL)
              break;
            (void) FormatLocaleFile(stdout,"%s",string);
            string=DestroyString(string);
          }
        if (LocaleCompare("process",option+1) == 0)
          {
            char
              **arguments;

            int
              j,
              number_arguments;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            arguments=StringToArgv(argv[i+1],&number_arguments);
            if (arguments == (char **) NULL)
              break;
            if ((argc > 1) && (strchr(arguments[1],'=') != (char *) NULL))
              {
                char
                  breaker,
                  quote,
                  *token;

                const char
                  *argument;

                int
                  next,
                  token_status;

                size_t
                  length;

                TokenInfo
                  *token_info;

                /*
                  Support old style syntax, filter="-option arg".
                */
                length=strlen(argv[i+1]);
                token=(char *) NULL;
                if (~length >= (MagickPathExtent-1))
                  token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
                    sizeof(*token));
                if (token == (char *) NULL)
                  break;
                next=0;
                argument=argv[i+1];
                token_info=AcquireTokenInfo();
                token_status=Tokenizer(token_info,0,token,length,argument,"",
                  "=","\"",'\0',&breaker,&next,&quote);
                token_info=DestroyTokenInfo(token_info);
                if (token_status == 0)
                  {
                    const char
                      *arg;

                    arg=(&(argument[next]));
                    (void) InvokeDynamicImageFilter(token,&(*images),1,&arg,
                      exception);
                  }
                token=DestroyString(token);
                break;
              }
            (void) SubstituteString(&arguments[1],"-","");
            (void) InvokeDynamicImageFilter(arguments[1],&(*images),
              number_arguments-2,(const char **) arguments+2,exception);
            for (j=0; j < number_arguments; j++)
              arguments[j]=DestroyString(arguments[j]);
            arguments=(char **) RelinquishMagickMemory(arguments);
            break;
          }
        break;
      }
      case 'r':
      {
        if (LocaleCompare("reverse",option+1) == 0)
          {
            ReverseImageList(images);
            break;
          }
        break;
      }
      case 's':
      {
        if (LocaleCompare("smush",option+1) == 0)
          {
            Image
              *smush_image;

            ssize_t
              offset;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            offset=(ssize_t) StringToLong(argv[i+1]);
            smush_image=SmushImages(*images,*option == '-' ? MagickTrue :
              MagickFalse,offset,exception);
            if (smush_image == (Image *) NULL)
              {
                status=MagickFalse;
                break;
              }
            *images=DestroyImageList(*images);
            *images=smush_image;
            break;
          }
        if (LocaleCompare("swap",option+1) == 0)
          {
            Image
              *p,
              *q,
              *u,
              *v;

            ssize_t
              swap_index;

            index=(-1);
            swap_index=(-2);
            if (*option != '+')
              {
                GeometryInfo
                  geometry_info;

                MagickStatusType
                  flags;

                swap_index=(-1);
                flags=ParseGeometry(argv[i+1],&geometry_info);
                index=(ssize_t) geometry_info.rho;
                if ((flags & SigmaValue) != 0)
                  swap_index=(ssize_t) geometry_info.sigma;
              }
            p=GetImageFromList(*images,index);
            q=GetImageFromList(*images,swap_index);
            if ((p == (Image *) NULL) || (q == (Image *) NULL))
              {
                (void) ThrowMagickException(exception,GetMagickModule(),
                  OptionError,"NoSuchImage","`%s'",(*images)->filename);
                status=MagickFalse;
                break;
              }
            if (p == q)
              break;
            u=CloneImage(p,0,0,MagickTrue,exception);
            if (u == (Image *) NULL)
              break;
            v=CloneImage(q,0,0,MagickTrue,exception);
            if (v == (Image *) NULL)
              {
                u=DestroyImage(u);
                break;
              }
            ReplaceImageInList(&p,v);
            ReplaceImageInList(&q,u);
            *images=GetFirstImageInList(q);
            break;
          }
        break;
      }
      case 'w':
      {
        if (LocaleCompare("write",option+1) == 0)
          {
            char
              key[MagickPathExtent];

            Image
              *write_images;

            ImageInfo
              *write_info;

            (void) SyncImagesSettings(mogrify_info,*images,exception);
            (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",
              argv[i+1]);
            (void) DeleteImageRegistry(key);
            write_images=(*images);
            if (*option == '+')
              write_images=CloneImageList(*images,exception);
            write_info=CloneImageInfo(mogrify_info);
            status&=WriteImages(write_info,write_images,argv[i+1],exception);
            write_info=DestroyImageInfo(write_info);
            if (*option == '+')
              write_images=DestroyImageList(write_images);
            break;
          }
        break;
      }
      default:
        break;
    }
    i+=count;
  }
  quantize_info=DestroyQuantizeInfo(quantize_info);
  mogrify_info=DestroyImageInfo(mogrify_info);
  status&=MogrifyImageInfo(image_info,argc,argv,exception);
  return(status != 0 ? MagickTrue : MagickFalse);
}

Project: ImageMagick6

WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
  const char *option,const char *arg1n,const char *arg2n)
{
  const char    /* percent escaped versions of the args */
    *arg1,
    *arg2;

  Image
    *new_images;

  MagickStatusType
    status;

  ssize_t
    parse;

#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 _process_flags  (cli_wand->process_flags)
#define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
#define IfNormalOp      (*option=='-')
#define IfPlusOp        (*option!='-')
#define IsNormalOp      IfNormalOp ? MagickTrue : MagickFalse

  assert(cli_wand != (MagickCLI *) NULL);
  assert(cli_wand->signature == MagickWandSignature);
  assert(cli_wand->wand.signature == MagickWandSignature);
  assert(_images != (Image *) NULL);             /* _images must be present */

  if (cli_wand->wand.debug != MagickFalse)
    (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
       "- List Operator: %s \"%s\" \"%s\"", option,
       arg1n == (const char *) NULL ? "null" : arg1n,
       arg2n == (const char *) NULL ? "null" : arg2n);

  arg1 = arg1n;
  arg2 = arg2n;

  /* Interpret Percent Escapes in Arguments - using first image */
  if ( (((_process_flags & ProcessInterpretProperities) != 0 )
        || ((_option_type & AlwaysInterpretArgsFlag) != 0)
       )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
    /* Interpret Percent escapes in argument 1 */
    if (arg1n != (char *) NULL) {
      arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
      if (arg1 == (char *) NULL) {
        CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
        arg1=arg1n;  /* use the given argument as is */
      }
    }
    if (arg2n != (char *) NULL) {
      arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
      if (arg2 == (char *) NULL) {
        CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
        arg2=arg2n;  /* use the given argument as is */
      }
    }
  }
#undef _process_flags
#undef _option_type

  status=MagickTrue;
  new_images=NewImageList();

  switch (*(option+1))
  {
    case 'a':
    {
      if (LocaleCompare("append",option+1) == 0)
        {
          new_images=AppendImages(_images,IsNormalOp,_exception);
          break;
        }
      if (LocaleCompare("average",option+1) == 0)
        {
          CLIWandWarnReplaced("-evaluate-sequence Mean");
          (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",
            NULL);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'c':
    {
      if (LocaleCompare("channel-fx",option+1) == 0)
        {
          new_images=ChannelFxImage(_images,arg1,_exception);
          break;
        }
      if (LocaleCompare("clut",option+1) == 0)
        {
          Image
            *clut_image;

          /* FUTURE - make this a compose option, and thus can be used
             with layers compose or even compose last image over all other
             _images.
          */
          new_images=RemoveFirstImageFromList(&_images);
          clut_image=RemoveLastImageFromList(&_images);
          /* FUTURE - produce Exception, rather than silent fail */
          if (clut_image == (Image *) NULL)
            break;
          (void) ClutImage(new_images,clut_image,new_images->interpolate,
            _exception);
          clut_image=DestroyImage(clut_image);
          break;
        }
      if (LocaleCompare("coalesce",option+1) == 0)
        {
          new_images=CoalesceImages(_images,_exception);
          break;
        }
      if (LocaleCompare("combine",option+1) == 0)
        {
          parse=(ssize_t) _images->colorspace;
          if (_images->number_channels < GetImageListLength(_images))
            parse=sRGBColorspace;
          if ( IfPlusOp )
            parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
          if (parse < 0)
            CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
              arg1);
          new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
          break;
        }
      if (LocaleCompare("compare",option+1) == 0)
        {
          double
            distortion;

          Image
            *image,
            *reconstruct_image;

          MetricType
            metric;

          /*
            Mathematically and visually annotate the difference between an
            image and its reconstruction.
          */
          image=RemoveFirstImageFromList(&_images);
          reconstruct_image=RemoveFirstImageFromList(&_images);
          /* FUTURE - produce Exception, rather than silent fail */
          if (reconstruct_image == (Image *) NULL)
            { 
              image=DestroyImage(image);
              break;
            }
          metric=UndefinedErrorMetric;
          option=GetImageOption(_image_info,"metric");
          if (option != (const char *) NULL)
            metric=(MetricType) ParseCommandOption(MagickMetricOptions,
              MagickFalse,option);
          new_images=CompareImages(image,reconstruct_image,metric,&distortion,
            _exception);
          (void) distortion;
          reconstruct_image=DestroyImage(reconstruct_image);
          image=DestroyImage(image);
          break;
        }
      if (LocaleCompare("complex",option+1) == 0)
        {
          parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
          if (parse < 0)
            CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
              option,arg1);
          new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
          break;
        }
      if (LocaleCompare("composite",option+1) == 0)
        {
          CompositeOperator
            compose;

          const char*
            value;

          MagickBooleanType
            clip_to_self;

          Image
            *mask_image,
            *source_image;

          RectangleInfo
            geometry;

          /* Compose value from "-compose" option only */
          value=GetImageOption(_image_info,"compose");
          if (value == (const char *) NULL)
            compose=OverCompositeOp;  /* use Over not source_image->compose */
          else
            compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
              MagickFalse,value);

          /* Get "clip-to-self" expert setting (false is normal) */
          clip_to_self=GetCompositeClipToSelf(compose);
          value=GetImageOption(_image_info,"compose:clip-to-self");
          if (value != (const char *) NULL)
            clip_to_self=IsStringTrue(value);
          value=GetImageOption(_image_info,"compose:outside-overlay");
          if (value != (const char *) NULL)
            clip_to_self=IsStringFalse(value);  /* deprecated */

          new_images=RemoveFirstImageFromList(&_images);
          source_image=RemoveFirstImageFromList(&_images);
          if (source_image == (Image *) NULL)
            break; /* FUTURE - produce Exception, rather than silent fail */

          /* FUTURE - this should not be here! - should be part of -geometry */
          if (source_image->geometry != (char *) NULL)
            {
              RectangleInfo
                resize_geometry;

              (void) ParseRegionGeometry(source_image,source_image->geometry,
                &resize_geometry,_exception);
              if ((source_image->columns != resize_geometry.width) ||
                  (source_image->rows != resize_geometry.height))
                {
                  Image
                    *resize_image;

                  resize_image=ResizeImage(source_image,resize_geometry.width,
                    resize_geometry.height,source_image->filter,_exception);
                  if (resize_image != (Image *) NULL)
                    {
                      source_image=DestroyImage(source_image);
                      source_image=resize_image;
                    }
                }
            }
          SetGeometry(source_image,&geometry);
          (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
          GravityAdjustGeometry(new_images->columns,new_images->rows,
            new_images->gravity, &geometry);
          mask_image=RemoveFirstImageFromList(&_images);
          if (mask_image == (Image *) NULL)
            status&=CompositeImage(new_images,source_image,compose,clip_to_self,
              geometry.x,geometry.y,_exception);
          else
            {
              if ((compose == DisplaceCompositeOp) ||
                  (compose == DistortCompositeOp))
                {
                  status&=CompositeImage(source_image,mask_image,
                    CopyGreenCompositeOp,MagickTrue,0,0,_exception);
                  status&=CompositeImage(new_images,source_image,compose,
                    clip_to_self,geometry.x,geometry.y,_exception);
                }
              else
                {
                  Image
                    *clone_image;

                  clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
                  if (clone_image == (Image *) NULL)
                    break;
                  status&=CompositeImage(new_images,source_image,compose,
                    clip_to_self,geometry.x,geometry.y,_exception);
                  status&=CompositeImage(new_images,mask_image,
                    CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
                  status&=CompositeImage(clone_image,new_images,OverCompositeOp,
                    clip_to_self,0,0,_exception);
                  new_images=DestroyImageList(new_images);
                  new_images=clone_image;
                }
              mask_image=DestroyImage(mask_image);
            }
          source_image=DestroyImage(source_image);
          break;
        }
        if (LocaleCompare("copy",option+1) == 0)
          {
            Image
              *source_image;

            OffsetInfo
              offset;

            RectangleInfo
              geometry;

            /*
              Copy image pixels.
            */
            if (IsGeometry(arg1) == MagickFalse)
              CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
            if (IsGeometry(arg2) == MagickFalse)
              CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
            (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
            offset.x=geometry.x;
            offset.y=geometry.y;
            source_image=_images;
            if (source_image->next != (Image *) NULL)
              source_image=source_image->next;
            (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
            (void) CopyImagePixels(_images,source_image,&geometry,&offset,
              _exception);
            break;
          }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'd':
    {
      if (LocaleCompare("deconstruct",option+1) == 0)
        {
          CLIWandWarnReplaced("-layer CompareAny");
          (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
          break;
        }
      if (LocaleCompare("delete",option+1) == 0)
        {
          if (IfNormalOp)
            DeleteImages(&_images,arg1,_exception);
          else
            DeleteImages(&_images,"-1",_exception);
          break;
        }
      if (LocaleCompare("duplicate",option+1) == 0)
        {
          if (IfNormalOp)
            {
              const char
                *p;

              size_t
                number_duplicates;

              if (IsGeometry(arg1) == MagickFalse)
                CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
                      arg1);
              number_duplicates=(size_t) StringToLong(arg1);
              p=strchr(arg1,',');
              if (p == (const char *) NULL)
                new_images=DuplicateImages(_images,number_duplicates,"-1",
                  _exception);
              else
                new_images=DuplicateImages(_images,number_duplicates,p,
                  _exception);
            }
          else
            new_images=DuplicateImages(_images,1,"-1",_exception);
          AppendImageToList(&_images, new_images);
          new_images=(Image *) NULL;
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'e':
    {
      if (LocaleCompare("evaluate-sequence",option+1) == 0)
        {
          parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
          if (parse < 0)
            CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
              option,arg1);
          new_images=EvaluateImages(_images,(MagickEvaluateOperator) parse,
            _exception);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'f':
    {
      if (LocaleCompare("fft",option+1) == 0)
        {
          new_images=ForwardFourierTransformImage(_images,IsNormalOp,
           _exception);
          break;
        }
      if (LocaleCompare("flatten",option+1) == 0)
        {
          /* REDIRECTED to use -layers flatten instead */
          (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
          break;
        }
      if (LocaleCompare("fx",option+1) == 0)
        {
          new_images=FxImage(_images,arg1,_exception);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'h':
    {
      if (LocaleCompare("hald-clut",option+1) == 0)
        {
          /* FUTURE - make this a compose option (and thus layers compose )
             or perhaps compose last image over all other _images.
          */
          Image
            *hald_image;

          new_images=RemoveFirstImageFromList(&_images);
          hald_image=RemoveLastImageFromList(&_images);
          if (hald_image == (Image *) NULL)
            break;
          (void) HaldClutImage(new_images,hald_image,_exception);
          hald_image=DestroyImage(hald_image);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'i':
    {
      if (LocaleCompare("ift",option+1) == 0)
        {
          Image
            *magnitude_image,
            *phase_image;

           magnitude_image=RemoveFirstImageFromList(&_images);
           phase_image=RemoveFirstImageFromList(&_images);
          /* FUTURE - produce Exception, rather than silent fail */
           if (phase_image == (Image *) NULL)
             break;
           new_images=InverseFourierTransformImage(magnitude_image,phase_image,
             IsNormalOp,_exception);
           magnitude_image=DestroyImage(magnitude_image);
           phase_image=DestroyImage(phase_image);
          break;
        }
      if (LocaleCompare("insert",option+1) == 0)
        {
          Image
            *insert_image,
            *index_image;

          ssize_t
            index;

          if (IfNormalOp && (IsGeometry(arg1) == MagickFalse))
            CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
          index=0;
          insert_image=RemoveLastImageFromList(&_images);
          if (IfNormalOp)
            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
             {
                index_image=GetImageFromList(_images,index-1);
                if (index_image == (Image *) NULL)
                 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
               InsertImageInList(&index_image,insert_image);
             }
           _images=GetFirstImageInList(index_image);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'l':
    {
      if (LocaleCompare("layers",option+1) == 0)
        {
          parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
          if ( parse < 0 )
            CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
                 option,arg1);
          switch ((LayerMethod) parse)
          {
            case CoalesceLayer:
            {
              new_images=CoalesceImages(_images,_exception);
              break;
            }
            case CompareAnyLayer:
            case CompareClearLayer:
            case CompareOverlayLayer:
            default:
            {
              new_images=CompareImagesLayers(_images,(LayerMethod) parse,
                   _exception);
              break;
            }
            case MergeLayer:
            case FlattenLayer:
            case MosaicLayer:
            case TrimBoundsLayer:
            {
              new_images=MergeImageLayers(_images,(LayerMethod) parse,
                _exception);
              break;
            }
            case DisposeLayer:
            {
              new_images=DisposeImages(_images,_exception);
              break;
            }
            case OptimizeImageLayer:
            {
              new_images=OptimizeImageLayers(_images,_exception);
              break;
            }
            case OptimizePlusLayer:
            {
              new_images=OptimizePlusImageLayers(_images,_exception);
              break;
            }
            case OptimizeTransLayer:
            {
              OptimizeImageTransparency(_images,_exception);
              break;
            }
            case RemoveDupsLayer:
            {
              RemoveDuplicateLayers(&_images,_exception);
              break;
            }
            case RemoveZeroLayer:
            {
              RemoveZeroDelayLayers(&_images,_exception);
              break;
            }
            case OptimizeLayer:
            { /* General Purpose, GIF Animation Optimizer.  */
              new_images=CoalesceImages(_images,_exception);
              if (new_images == (Image *) NULL)
                break;
              _images=DestroyImageList(_images);
              _images=OptimizeImageLayers(new_images,_exception);
              if (_images == (Image *) NULL)
                break;
              new_images=DestroyImageList(new_images);
              OptimizeImageTransparency(_images,_exception);
              (void) RemapImages(_quantize_info,_images,(Image *) NULL,
                _exception);
              break;
            }
            case CompositeLayer:
            {
              Image
                *source;

              RectangleInfo
                geometry;

              CompositeOperator
                compose;

              const char*
                value;

              value=GetImageOption(_image_info,"compose");
              compose=OverCompositeOp;  /* Default to Over */
              if (value != (const char *) NULL)
                compose=(CompositeOperator) ParseCommandOption(
                      MagickComposeOptions,MagickFalse,value);

              /* Split image sequence at the first 'NULL:' image. */
              source=_images;
              while (source != (Image *) NULL)
              {
                source=GetNextImageInList(source);
                if ((source != (Image *) NULL) &&
                    (LocaleCompare(source->magick,"NULL") == 0))
                  break;
              }
              if (source != (Image *) NULL)
                {
                  if ((GetPreviousImageInList(source) == (Image *) NULL) ||
                      (GetNextImageInList(source) == (Image *) NULL))
                    source=(Image *) NULL;
                  else
                    { /* Separate the two lists, junk the null: image.  */
                      source=SplitImageList(source->previous);
                      DeleteImageFromList(&source);
                    }
                }
              if (source == (Image *) NULL)
                {
                  (void) ThrowMagickException(_exception,GetMagickModule(),
                    OptionError,"MissingNullSeparator","layers Composite");
                  break;
                }
              /* Adjust offset with gravity and virtual canvas.  */
              SetGeometry(_images,&geometry);
              (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
              geometry.width=source->page.width != 0 ?
                source->page.width : source->columns;
              geometry.height=source->page.height != 0 ?
               source->page.height : source->rows;
              GravityAdjustGeometry(_images->page.width != 0 ?
                _images->page.width : _images->columns,
                _images->page.height != 0 ? _images->page.height :
                _images->rows,_images->gravity,&geometry);

              /* Compose the two image sequences together */
              CompositeLayers(_images,compose,source,geometry.x,geometry.y,
                _exception);
              source=DestroyImageList(source);
              break;
            }
          }
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'm':
    {
      if (LocaleCompare("map",option+1) == 0)
        {
          CLIWandWarnReplaced("+remap");
          (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
          break;
        }
      if (LocaleCompare("metric",option+1) == 0)
        {
          (void) SetImageOption(_image_info,option+1,arg1);
          break;
        }
      if (LocaleCompare("morph",option+1) == 0)
        {
          Image
            *morph_image;

          if (IsGeometry(arg1) == MagickFalse)
            CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
          morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
            _exception);
          if (morph_image == (Image *) NULL)
            break;
          _images=DestroyImageList(_images);
          _images=morph_image;
          break;
        }
      if (LocaleCompare("mosaic",option+1) == 0)
        {
          /* REDIRECTED to use -layers mosaic instead */
          (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'p':
    {
      if (LocaleCompare("poly",option+1) == 0)
        {
          double
            *args;

          ssize_t
            count;

          /* convert argument string into an array of doubles */
          args = StringToArrayOfDoubles(arg1,&count,_exception);
          if (args == (double *) NULL )
            CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
          new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
           _exception);
          args=(double *) RelinquishMagickMemory(args);
          break;
        }
      if (LocaleCompare("process",option+1) == 0)
        {
          /* FUTURE: better parsing using ScriptToken() from string ??? */
          char
            **arguments;

          int
            j,
            number_arguments;

          arguments=StringToArgv(arg1,&number_arguments);
          if (arguments == (char **) NULL)
            break;
          if (strchr(arguments[1],'=') != (char *) NULL)
            {
              char
                breaker,
                quote,
                *token;

              const char
                *arguments;

              int
                next,
                status;

              size_t
                length;

              TokenInfo
                *token_info;

              /*
                Support old style syntax, filter="-option arg1".
              */
              assert(arg1 != (const char *) NULL);
              length=strlen(arg1);
              token=(char *) NULL;
              if (~length >= (MagickPathExtent-1))
                token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
                  sizeof(*token));
              if (token == (char *) NULL)
                break;
              next=0;
              arguments=arg1;
              token_info=AcquireTokenInfo();
              status=Tokenizer(token_info,0,token,length,arguments,"","=",
                "\"",'\0',&breaker,&next,&quote);
              token_info=DestroyTokenInfo(token_info);
              if (status == 0)
                {
                  const char
                    *argv;

                  argv=(&(arguments[next]));
                  (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
                    _exception);
                }
              token=DestroyString(token);
              break;
            }
          (void) SubstituteString(&arguments[1],"-","");
          (void) InvokeDynamicImageFilter(arguments[1],&_images,
            number_arguments-2,(const char **) arguments+2,_exception);
          for (j=0; j < number_arguments; j++)
            arguments[j]=DestroyString(arguments[j]);
          arguments=(char **) RelinquishMagickMemory(arguments);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 'r':
    {
      if (LocaleCompare("remap",option+1) == 0)
        {
          (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
          break;
        }
      if (LocaleCompare("reverse",option+1) == 0)
        {
          ReverseImageList(&_images);
          break;
        }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    case 's':
    {
      if (LocaleCompare("smush",option+1) == 0)
        {
          /* FUTURE: this option needs more work to make better */
          ssize_t
            offset;

          if (IsGeometry(arg1) == MagickFalse)
            CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
          offset=(ssize_t) StringToLong(arg1);
          new_images=SmushImages(_images,IsNormalOp,offset,_exception);
          break;
        }
      if (LocaleCompare("subimage",option+1) == 0)
        {
          Image
            *base_image,
            *compare_image;

          const char
            *value;

          MetricType
            metric;

          double
            similarity;

          RectangleInfo
            offset;

          base_image=GetImageFromList(_images,0);
          compare_image=GetImageFromList(_images,1);

          /* Comparision Metric */
          metric=UndefinedErrorMetric;
          value=GetImageOption(_image_info,"metric");
          if (value != (const char *) NULL)
            metric=(MetricType) ParseCommandOption(MagickMetricOptions,
              MagickFalse,value);

          new_images=SimilarityImage(base_image,compare_image,metric,0.0,
            &offset,&similarity,_exception);

          if (new_images != (Image *) NULL)
            {
              char
                result[MagickPathExtent];

              (void) FormatLocaleString(result,MagickPathExtent,"%lf",
                similarity);
              (void) SetImageProperty(new_images,"subimage:similarity",result,
                _exception);
              (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
                offset.x);
              (void) SetImageProperty(new_images,"subimage:x",result,
                _exception);
              (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
                offset.y);
              (void) SetImageProperty(new_images,"subimage:y",result,
                _exception);
              (void) FormatLocaleString(result,MagickPathExtent,
                "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
                offset.height,(long) offset.x,(long) offset.y);
              (void) SetImageProperty(new_images,"subimage:offset",result,
                _exception);
            }
          break;
        }
      if (LocaleCompare("swap",option+1) == 0)
        {
        Image
          *p,
          *q,
          *swap;

        ssize_t
          index,
          swap_index;

        index=(-1);
        swap_index=(-2);
        if (IfNormalOp) {
          GeometryInfo
            geometry_info;

          MagickStatusType
            flags;

          swap_index=(-1);
          flags=ParseGeometry(arg1,&geometry_info);
          if ((flags & RhoValue) == 0)
            CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
          index=(ssize_t) geometry_info.rho;
          if ((flags & SigmaValue) != 0)
            swap_index=(ssize_t) geometry_info.sigma;
        }
        p=GetImageFromList(_images,index);
        q=GetImageFromList(_images,swap_index);
        if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
          if (IfNormalOp)
            CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
          else
            CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
        }
        if (p == q)
          CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
        swap=CloneImage(p,0,0,MagickTrue,_exception);
        if (swap == (Image *) NULL)
          CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
            option,GetExceptionMessage(errno));
        ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
        ReplaceImageInList(&q,swap);
        _images=GetFirstImageInList(q);
        break;
      }
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
    }
    default:
      CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
  }

  /* clean up percent escape interpreted strings */
  if (arg1 != arg1n )
    arg1=DestroyString((char *)arg1);
  if (arg2 != arg2n )
    arg2=DestroyString((char *)arg2);

  /* if new image list generated, replace existing image list */
  if (new_images == (Image *) NULL)
    return(status == 0 ? MagickFalse : MagickTrue);
  _images=DestroyImageList(_images);
  _images=GetFirstImageInList(new_images);
  return(status == 0 ? MagickFalse : MagickTrue);

#undef _image_info
#undef _images
#undef _exception
#undef _draw_info
#undef _quantize_info
#undef IfNormalOp
#undef IfPlusOp
#undef IsNormalOp
}