diff options
Diffstat (limited to 'magick/command.c')
-rw-r--r-- | magick/command.c | 287 |
1 files changed, 207 insertions, 80 deletions
diff --git a/magick/command.c b/magick/command.c index f51017a..1b51eac 100644 --- a/magick/command.c +++ b/magick/command.c @@ -1,5 +1,5 @@ /* -% Copyright (C) 2003 - 2022 GraphicsMagick Group +% Copyright (C) 2003 - 2023 GraphicsMagick Group % Copyright (C) 2002 ImageMagick Studio % % This program is covered by multiple licenses, which are described in @@ -129,13 +129,19 @@ typedef int (*CommandLineParser)(FILE *in, int acmax, char **av); #define SIZE_OPTION_VALUE 256 typedef struct _BatchOptions { - MagickBool stop_on_error, - is_feedback_enabled, - is_echo_enabled; - char prompt[SIZE_OPTION_VALUE], - pass[SIZE_OPTION_VALUE], - fail[SIZE_OPTION_VALUE]; - CommandLineParser command_line_parser; + MagickBool + stop_on_error, + is_feedback_enabled, + is_echo_enabled, + is_tap_mode; + + char + prompt[SIZE_OPTION_VALUE], + pass[SIZE_OPTION_VALUE], + fail[SIZE_OPTION_VALUE]; + + CommandLineParser + command_line_parser; } BatchOptions; typedef MagickPassFail (*CommandVectorHandler)(ImageInfo *image_info, @@ -1161,7 +1167,11 @@ MagickExport MagickPassFail AnimateImageCommand(ImageInfo *image_info, { if (LocaleCompare("map",option+1) == 0) { - (void) strcpy(argv[i]+1,"sans"); + /* + Indicate that option was already handled so + MogrifyImage() will ignore it. + */ + (void) strlcpy(argv[i]+1,"Z",strlen(argv[i]+1)+1); resource_info.map_type=(char *) NULL; if (*option == '-') { @@ -1470,6 +1480,7 @@ MagickExport MagickPassFail AnimateImageCommand(ImageInfo *image_info, (void) CatchImageException(image); AppendImageToList(&image_list,image); } + image_list=GetFirstImageInList(image_list); if (resource_info.window_id != (char *) NULL) MagickXAnimateBackgroundImage(display,&resource_info,image_list); else @@ -1542,6 +1553,7 @@ static MagickPassFail BatchCommand(int argc, char **argv) MagickBool hasInputFile; int ac; char *av[MAX_PARAM+1]; + unsigned int line_no = 0; #if defined(MSWINDOWS) InitializeMagick((char *) NULL); @@ -1595,9 +1607,15 @@ static MagickPassFail BatchCommand(int argc, char **argv) (void) fflush(stdout); } + while (!(ferror(stdin) || ferror(stdout) || ferror(stderr) || feof(stdin))) { - if (batch_options.prompt[0]) + if (batch_options.is_tap_mode) + { + (void) fputs("# ", stdout); + (void) fflush(stdout); + } + else if (batch_options.prompt[0]) { (void) fputs(batch_options.prompt, stdout); (void) fflush(stdout); @@ -1609,7 +1627,7 @@ static MagickPassFail BatchCommand(int argc, char **argv) result = MagickPass; break; }; - if (batch_options.is_echo_enabled) + if (batch_options.is_tap_mode || batch_options.is_echo_enabled) { int i; for (i = 1; i < ac; i++) @@ -1636,8 +1654,14 @@ static MagickPassFail BatchCommand(int argc, char **argv) MAX_PARAM); result = MagickFail; } + ++line_no; - if (batch_options.is_feedback_enabled) + if (batch_options.is_tap_mode) + { + /* FIXME: Support TAP test description */ + (void) fprintf(stdout, "%s %u\n", result ? "ok" : "not ok", line_no); + } + else if (batch_options.is_feedback_enabled) { (void) fputs(result ? batch_options.pass : batch_options.fail, stdout); (void) fputc('\n', stdout); @@ -1649,7 +1673,7 @@ static MagickPassFail BatchCommand(int argc, char **argv) break; } - if (batch_options.prompt[0]) + if (!batch_options.is_tap_mode && batch_options.prompt[0]) { (void) fputs("\n", stdout); (void) fflush(stdout); @@ -1697,6 +1721,12 @@ static void BatchOptionUsage(void) " -stop-on-error on|off\n" " when turned on, batch execution quits prematurely when\n" " any command returns error\n" + " -tap-mode on|off\n" + " when turned on, a simple implementation of Test Anything\n" + " Protocol (TAP) is enabled to produce \"ok N\" and \n" + " \"not ok N\" feedback to indicate the test number, and to\n" + " supplant the function of -fail, -pass, -feedback in order\n" + " to support simple TAP output messaging\n" "\n" "Unix escape allows the use backslash(\\), single quote(') and double quote(\") in\n" "the command line. Windows escape only uses double quote(\"). For example,\n" @@ -3796,8 +3826,12 @@ MagickExport MagickPassFail CompositeImageCommand(ImageInfo *image_info, break; if (LocaleCompare("noop",option+1) == 0) { + if (image == NULL) + ThrowCompositeException(OptionError,NoImagesDefined, + "no images in composite image list"); + status&=CompositeImageList(image_info,&image,composite_image, - mask_image,&option_info,exception); + mask_image,&option_info,exception); if (composite_image != (Image *) NULL) { DestroyImageList(composite_image); @@ -5590,6 +5624,11 @@ MagickExport MagickPassFail ConvertImageCommand(ImageInfo *image_info, ThrowConvertException(OptionError,MissingArgument, option); } + else + { + ThrowConvertException(OptionError,MissingArgument, + option); + } break; } if (LocaleCompare("ordered-dither",option+1) == 0) @@ -5778,7 +5817,7 @@ MagickExport MagickPassFail ConvertImageCommand(ImageInfo *image_info, if (*option == '-') { i++; - if ((i == (argc-1)) || !IsGeometry(argv[i])) + if ((i == argc) || !IsGeometry(argv[i])) ThrowConvertException(OptionError,MissingArgument,option); } break; @@ -6215,15 +6254,18 @@ MagickExport MagickPassFail ConvertImageCommand(ImageInfo *image_info, ThrowConvertException(OptionError,MissingAnImageFilename,(char *) NULL); if (image == (Image *) NULL) { - status&=MogrifyImages(image_info,i-j,argv+j,&image_list); + if (!ping) + status&=MogrifyImages(image_info,i-j,argv+j,&image_list); GetImageException(image_list,exception); } else { - status&=MogrifyImages(image_info,i-j,argv+j,&image); + if (!ping) + status&=MogrifyImages(image_info,i-j,argv+j,&image); GetImageException(image,exception); AppendImageToList(&image_list,image); } + image_list=GetFirstImageInList(image_list); status&=WriteImages(image_info,image_list,argv[argc-1],exception); if (metadata != (char **) NULL) { @@ -6481,7 +6523,7 @@ static void ConjureUsage(void) (void) puts(" -verbose print detailed information about the image"); (void) puts(" -version print version information"); (void) puts(""); - (void) puts("In additiion, define any key value pairs required by your script. For"); + (void) puts("In addition, define any key value pairs required by your script. For"); (void) puts("example,"); (void) puts(""); (void) puts(" conjure -size 100x100 -color blue -foo bar script.msl"); @@ -6582,10 +6624,12 @@ MagickExport MagickPassFail ConjureImageCommand(ImageInfo *image_info, Persist key/value pair. */ (void) SetImageAttribute(image_info->attributes,option+1,(char *) NULL); - status&=SetImageAttribute(image_info->attributes,option+1,argv[i+1]); + i++; + if (i == argc) + MagickFatalError(OptionFatalError,MissingArgument,option); + status&=SetImageAttribute(image_info->attributes,option+1,argv[i]); if (status == MagickFail) MagickFatalError(ImageFatalError,UnableToPersistKey,option); - i++; continue; } /* @@ -6922,7 +6966,7 @@ MagickExport MagickPassFail DisplayImageCommand(ImageInfo *image_info, (void) MagickSceneFileName(filename,image_info->filename,".%lu",MagickTrue,scene); (void) strlcpy(image_info->filename,filename,MaxTextExtent); } - (void) strcpy(image_info->magick,"MIFF"); + (void) strlcpy(image_info->magick,"MIFF",sizeof(image_info->magick)); image_info->colorspace=quantize_info->colorspace; image_info->dither=quantize_info->dither; DestroyExceptionInfo(exception); @@ -7590,7 +7634,11 @@ MagickExport MagickPassFail DisplayImageCommand(ImageInfo *image_info, } if (LocaleCompare("map",option+1) == 0) { - (void) strcpy(argv[i]+1,"sans"); + /* + Indicate that option was already handled so + MogrifyImage() will ignore it. + */ + (void) strlcpy(argv[i]+1,"Z",strlen(argv[i]+1)+1); resource_info.map_type=(char *) NULL; if (*option == '-') { @@ -8834,15 +8882,15 @@ static void IdentifyUsage(void) */ static void InitializeBatchOptions(MagickBool prompt) { - strcpy(batch_options.pass, "PASS"); - strcpy(batch_options.fail, "FAIL"); + strlcpy(batch_options.pass, "PASS", sizeof(batch_options.pass)); + strlcpy(batch_options.fail, "FAIL", sizeof(batch_options.fail)); #if defined(MSWINDOWS) batch_options.command_line_parser = ParseWindowsCommandLine; #else batch_options.command_line_parser = ParseUnixCommandLine; #endif if (prompt) - strcpy(batch_options.prompt, "GM> "); + strlcpy(batch_options.prompt, "GM> ", sizeof(batch_options.prompt)); } @@ -8942,12 +8990,9 @@ MagickExport MagickPassFail MagickCommand(ImageInfo *image_info, char command_name[MaxTextExtent]; - const char - *pos; - /* - Append subcommand name to existing client name if end of - existing client name is not identical to subcommand name. + Append subcommand name to existing client name if existing + client name is not identical to subcommand name. */ LockSemaphoreInfo(command_semaphore); if (run_mode == BatchMode) @@ -8955,9 +9000,7 @@ MagickExport MagickPassFail MagickCommand(ImageInfo *image_info, else { GetPathComponent(GetClientName(),BasePath,command_name); - pos=strrchr(command_name,' '); - if ((pos == (const char *) NULL) || - (LocaleCompare(commands[i].command,pos+1) != 0)) + if (LocaleCompare(commands[i].command,command_name) != 0) { char client_name[MaxTextExtent]; @@ -9421,6 +9464,11 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, type=(*option); option=argv[++i]; colorspace=StringToColorspaceType(option); + if (colorspace == UndefinedColorspace) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,"colorspace"); + break; + } quantize_info.colorspace=colorspace; /* Never quantize in CMYK colorspace */ if (IsCMYKColorspace(colorspace)) @@ -9681,7 +9729,12 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, */ MagickFreeMemory(draw_info->primitive); draw_info->primitive=AmpersandTranslateText(clone_info,*image,argv[++i]); - (void) DrawImage(*image,draw_info); + if (draw_info->primitive == (char *) NULL) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option); + break; + } + (void) DrawImage(*image,draw_info); continue; } break; @@ -10093,10 +10146,16 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, /* Local adaptive threshold image. */ - offset=0; - height=3; - width=3; - (void) sscanf(argv[++i],"%lux%lu%lf",&width,&height,&offset); + if (sscanf(argv[++i],"%lux%lu%lf",&width,&height,&offset) != 3) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option); + break; + } + if ((width == 0) || (height == 0)) + { + ThrowException3(&(*image)->exception,OptionError,UnableToThresholdImage,NonzeroWidthAndHeightRequired); + break; + } if (strchr(argv[i],'%') != (char *) NULL) offset*=((double) MaxRGB/100.0); threshold_image=AdaptiveThresholdImage(*image,width,height,offset, @@ -10360,34 +10419,53 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, } if (LocaleCompare("operator",option+1) == 0) { - ChannelType - channel; + if (*option == '-') + { + ChannelType + channel; - QuantumOperator - quantum_operator; + QuantumOperator + quantum_operator; - double - rvalue; + double + rvalue; - /* channel */ - channel=StringToChannelType(argv[++i]); + if (i+3 > argc) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option+1); + break; + } - /* operator id */ - quantum_operator=StringToQuantumOperator(argv[++i]); + /* channel */ + channel=StringToChannelType(argv[++i]); - /* rvalue */ - option=argv[++i]; - rvalue=StringToDouble(option,MaxRGB); - (void) QuantumOperatorImage(*image,channel,quantum_operator, - rvalue,&(*image)->exception); + /* operator id */ + quantum_operator=StringToQuantumOperator(argv[++i]); - continue; + /* rvalue */ + option=argv[++i]; + rvalue=StringToDouble(option,MaxRGBDouble); + (void) QuantumOperatorImage(*image,channel,quantum_operator, + rvalue,&(*image)->exception); + + continue; + } + else + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option+1); + break; + } } if (LocaleCompare("ordered-dither",option+1) == 0) { /* Ordered-dither image. */ + if (i+2 > argc) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option+1); + break; + } (void) RandomChannelThresholdImage(*image,argv[i+1],argv[i+2], &(*image)->exception); i+=2; @@ -10589,6 +10667,11 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, /* Threshold image. */ + if (i+2 > argc) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option+1); + break; + } (void) RandomChannelThresholdImage(*image,argv[i+1],argv[i+2], &(*image)->exception); i+=2; @@ -10685,6 +10768,7 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, region_geometry.y); DestroyImage(*image); *image=region_image; + region_image=(Image *) NULL; } if (*option == '+') continue; @@ -10896,9 +10980,6 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, NormalizeSamplingFactor(clone_info); continue; } - if (LocaleCompare("sans",option+1) == 0) - if (*option == '-') - i++; if (LocaleCompare("scale",option+1) == 0) { Image @@ -10930,10 +11011,20 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, *key, *value; + if (i+1 > argc) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option+1); + break; + } key=argv[++i]; (void) SetImageAttribute(*image,key,(char *) NULL); if (*option == '-') { + if (i+1 > argc) + { + ThrowException(&(*image)->exception,OptionError,MissingArgument,option+1); + break; + } value=argv[++i]; (void) SetImageAttribute(*image,key,value); } @@ -11388,11 +11479,25 @@ MagickExport MagickPassFail MogrifyImage(const ImageInfo *image_info, } break; } + case 'Z': + { + /* + Option -Z (used to be "sans") indicates an already handled + option (so ignore it). + */ + if (LocaleCompare("Z",option+1) == 0) + if (*option == '-') + { + i++; + continue; + } + break; + } default: break; } } - if (region_image != (Image *) NULL) + if ((region_image != (Image *) NULL) && (region_image != *image)) { /* Composite transformed region onto image. @@ -11564,6 +11669,7 @@ MagickExport MagickPassFail MogrifyImages(const ImageInfo *image_info, } AppendImageToList(&mogrify_images,image); } + mogrify_images=GetFirstImageInList(mogrify_images); /* Apply options to the entire image list. @@ -11945,7 +12051,7 @@ static MagickPassFail* TransmogrifyImage(TransmogrifyOptions *options) if (IsWriteable(output_filename)) { (void) strlcpy(temporary_filename,output_filename,MaxTextExtent); - (void) strcat(temporary_filename,"~"); + (void) strlcat(temporary_filename,"~",sizeof(temporary_filename)); if (rename(output_filename,temporary_filename) == 0) { if (image_info->verbose) @@ -12671,7 +12777,7 @@ MagickExport MagickPassFail MogrifyImageCommand(ImageInfo *image_info, option); (void) CloneString(&format,argv[i]); (void) strlcpy(image_info->filename,format,MaxTextExtent); - (void) strcat(image_info->filename,":"); + (void) strlcat(image_info->filename,":",sizeof(image_info->filename)); (void) SetImageInfo(image_info,SETMAGICK_WRITE,exception); if (*image_info->magick == '\0') ThrowMogrifyException(OptionError,UnrecognizedImageFormat,format); @@ -13202,6 +13308,11 @@ MagickExport MagickPassFail MogrifyImageCommand(ImageInfo *image_info, ThrowMogrifyException(OptionError,MissingArgument, option); } + else + { + ThrowMogrifyException(OptionError,MissingArgument, + option); + } break; } if (LocaleCompare("ordered-dither",option+1) == 0) @@ -13378,16 +13489,6 @@ MagickExport MagickPassFail MogrifyImageCommand(ImageInfo *image_info, if (*option == '-') { i++; - if ((i == (argc-1)) || !IsGeometry(argv[i])) - ThrowMogrifyException(OptionError,MissingArgument,option); - } - break; - } - if (LocaleCompare("resize",option+1) == 0) - { - if (*option == '-') - { - i++; if ((i == argc) || !IsGeometry(argv[i])) ThrowMogrifyException(OptionError,MissingArgument,option); } @@ -13399,8 +13500,7 @@ MagickExport MagickPassFail MogrifyImageCommand(ImageInfo *image_info, { i++; if ((i == argc) || !IsGeometry(argv[i])) - ThrowMogrifyException(OptionError,MissingArgument, - option); + ThrowMogrifyException(OptionError,MissingArgument,option); } break; } @@ -14584,7 +14684,11 @@ MagickExport MagickPassFail MontageImageCommand(ImageInfo *image_info, if (LocaleCompare("frame",option+1) == 0) { (void) CloneString(&montage_info->frame,(char *) NULL); - (void) strcpy(argv[i]+1,"sans"); + /* + Indicate that option was already handled so + MogrifyImage() will ignore it. + */ + (void) strlcpy(argv[i]+1,"Z",strlen(argv[i]+1)+1); if (*option == '-') { i++; @@ -14813,6 +14917,10 @@ MagickExport MagickPassFail MontageImageCommand(ImageInfo *image_info, break; ThrowMontageException(OptionError,UnrecognizedOption,option) } + case 'o': + { + ThrowMontageException(OptionError,UnrecognizedOption,option) + } case 'p': { if (LocaleCompare("page",option+1) == 0) @@ -15031,7 +15139,11 @@ MagickExport MagickPassFail MontageImageCommand(ImageInfo *image_info, if (LocaleCompare("tile",option+1) == 0) { (void) CloneString(&montage_info->tile,(char *) NULL); - (void) strcpy(argv[i]+1,"sans"); + /* + Indicate that option was already handled so + MogrifyImage() will ignore it. + */ + (void) strlcpy(argv[i]+1,"Z",strlen(argv[i]+1)+1); if (*option == '-') { i++; @@ -15097,7 +15209,11 @@ MagickExport MagickPassFail MontageImageCommand(ImageInfo *image_info, } break; } - ThrowMontageException(OptionError,UnrecognizedOption,option) + ThrowMontageException(OptionError,UnrecognizedOption,option); + } + case 'u': + { + ThrowMontageException(OptionError,UnrecognizedOption,option); } case 'v': { @@ -15168,6 +15284,7 @@ MagickExport MagickPassFail MontageImageCommand(ImageInfo *image_info, */ (void) strlcpy(montage_info->filename,argv[argc-1],MaxTextExtent); /* (void) memmove(montage_info->filename,argv[argc-1],strlen(argv[argc-1])+1); */ + image_list=GetFirstImageInList(image_list); montage_image=MontageImages(image_list,montage_info,exception); if (montage_image == (Image *) NULL) ThrowMontageException(OptionError,RequestDidNotReturnAnImage,(char *) NULL); @@ -16061,7 +16178,11 @@ MagickExport MagickPassFail ImportImageCommand(ImageInfo *image_info, } if (LocaleCompare("snaps",option+1) == 0) { - (void) strcpy(argv[i]+1,"sans"); + /* + Indicate that option was already handled so + MogrifyImage() will ignore it. + */ + (void) strlcpy(argv[i]+1,"Z",strlen(argv[i]+1)+1); i++; if ((i == argc) || !sscanf(argv[i],"%ld",&x)) MagickFatalError(OptionFatalError,MissingArgument,option); @@ -16178,8 +16299,8 @@ MagickExport MagickPassFail ImportImageCommand(ImageInfo *image_info, status&=next_image != (Image *) NULL; if (next_image == (Image *) NULL) continue; - (void) strlcpy(next_image->filename,filename,MaxTextExtent); - (void) strcpy(next_image->magick,"PS"); + (void) strlcpy(next_image->filename,filename,sizeof(next_image->filename)); + (void) strlcpy(next_image->magick,"PS",sizeof(next_image->magick)); next_image->scene=i; next_image->previous=image; if (image != (Image *) NULL) @@ -16665,6 +16786,10 @@ static int ProcessBatchOptions(int argc, char **argv, BatchOptions *options) if (LocaleCompare(option = "-stop-on-error", p) == 0) status = GetOnOffOptionValue(option, argv[++i], &options->stop_on_error); break; + case 't': + if (LocaleCompare(option = "-tap-mode", p) == 0) + status = GetOnOffOptionValue(option, argv[++i], &options->is_tap_mode); + break; } if (status == OptionSuccess) continue; @@ -16741,6 +16866,8 @@ static unsigned int SetCommand(ImageInfo *image_info, printf("stop-on-error : %s\n", on_off_option_values[batch_options.stop_on_error]); printf("pass : %s\n", batch_options.pass); printf("prompt : %s\n", batch_options.prompt); + printf("tap-mode : %s\n", on_off_option_values[batch_options.is_tap_mode]); + return MagickTrue; } @@ -17366,8 +17493,8 @@ static MagickPassFail RegisterCommand(ImageInfo *image_info, ARG_NOT_USED(exception); memset(szKey, 0, _MAX_PATH*2*sizeof(char)); - strcpy(szKey, szRegPath); - strcat(szKey, "GraphicsMagick"); + strlcpy(szKey, szRegPath, sizeof(szKey)); + strlcat(szKey, "GraphicsMagick", sizeof(szKey)); /* open the registry event source key */ lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, NULL, |