You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

857 lines
31 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% M M AAA GGGG IIIII CCCC K K %
% MM MM A A G I C K K %
% M M M AAAAA G GGG I C KKK %
% M M A A G G I C K K %
% M M A A GGGG IIIII CCCC K K %
% %
% CCCC L IIIII %
% C L I %
% C L I %
% C L I %
% CCCC LLLLL IIIII %
% %
% Perform "Magick" on Images via the Command Line Interface %
% %
% Dragon Computing %
% Anthony Thyssen %
% January 2012 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Read CLI arguments, script files, and pipelines, to provide options that
% manipulate images from many different formats.
%
*/
/*
Include declarations.
*/
#include "MagickWand/studio.h"
#include "MagickWand/MagickWand.h"
#include "MagickWand/magick-wand-private.h"
#include "MagickWand/wandcli.h"
#include "MagickWand/wandcli-private.h"
#include "MagickWand/operation.h"
#include "MagickWand/magick-cli.h"
#include "MagickWand/script-token.h"
#include "MagickCore/utility-private.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/version.h"
/* verbose debugging,
0 - no debug lines
3 - show option details (better to use -debug Command now)
5 - image counts (after option runs)
*/
#define MagickCommandDebug 0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ P r o c e s s S c r i p t O p t i o n s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ProcessScriptOptions() reads options and processes options as they are
% found in the given file, or pipeline. The filename to open and read
% options is given as the 'index' argument of the argument array given.
%
% Other arguments following index may be read by special script options
% as settings (strings), images, or as operations to be processed in various
% ways. How they are treated is up to the script being processed.
%
% Note that a script not 'return' to the command line processing, nor can
% they call (and return from) other scripts. At least not at this time.
%
% There are no 'ProcessOptionFlags' control flags at this time.
%
% The format of the ProcessScriptOptions method is:
%
% void ProcessScriptOptions(MagickCLI *cli_wand,const char *filename,
% int argc,char **argv,int index)
%
% A description of each parameter follows:
%
% o cli_wand: the main CLI Wand to use.
%
% o filename: the filename of script to process
%
% o argc: the number of elements in the argument vector. (optional)
%
% o argv: A text array containing the command line arguments. (optional)
%
% o index: offset of next argment in argv (script arguments) (optional)
%
*/
WandExport void ProcessScriptOptions(MagickCLI *cli_wand,const char *filename,
int magick_unused(argc),char **magick_unused(argv),int magick_unused(index))
{
ScriptTokenInfo
*token_info;
CommandOptionFlags
option_type;
int
count;
char
*option,
*arg1,
*arg2;
magick_unreferenced(argc);
magick_unreferenced(argv);
magick_unreferenced(index);
assert(filename != (char *) NULL ); /* at least one argument - script name */
assert(cli_wand != (MagickCLI *) NULL);
assert(cli_wand->signature == MagickWandSignature);
if (cli_wand->wand.debug != MagickFalse)
(void) LogMagickEvent(CommandEvent,GetMagickModule(),
"Processing script \"%s\"", filename);
/* open file script or stream, and set up tokenizer */
token_info = AcquireScriptTokenInfo(filename);
if (token_info == (ScriptTokenInfo *) NULL) {
CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",filename);
return;
}
/* define the error location string for use in exceptions
order of localtion format escapes: filename, line, column */
cli_wand->location="in \"%s\" at line %u,column %u";
if ( LocaleCompare("-", filename) == 0 )
cli_wand->filename="stdin";
else
cli_wand->filename=filename;
/* Process Options from Script */
option = arg1 = arg2 = (char*) NULL;
DisableMSCWarning(4127)
while (1) {
RestoreMSCWarning
{ MagickBooleanType status = GetScriptToken(token_info);
cli_wand->line=token_info->token_line;
cli_wand->column=token_info->token_column;
if (status == MagickFalse)
break; /* error or end of options */
}
do { /* use break to loop to exception handler and loop */
/* save option details */
CloneString(&option,token_info->token);
/* get option, its argument count, and option type */
cli_wand->command = GetCommandOptionInfo(option);
count=cli_wand->command->type;
option_type=(CommandOptionFlags) cli_wand->command->flags;
#if 0
(void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
cli_wand->line, cli_wand->line, option, cli_wand->command->mnemonic );
#endif
/* handle a undefined option - image read - always for "magick-script" */
if ( option_type == UndefinedOptionFlag ||
(option_type & NonMagickOptionFlag) != 0 ) {
#if MagickCommandDebug >= 3
(void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
cli_wand->line, cli_wand->line, option);
#endif
if (IsCommandOption(option) == MagickFalse) {
/* non-option -- treat as a image read */
cli_wand->command=(const OptionInfo *) NULL;
CLIOption(cli_wand,"-read",option);
break; /* next option */
}
CLIWandException(OptionFatalError,"UnrecognizedOption",option);
break; /* next option */
}
if ( count >= 1 ) {
if (GetScriptToken(token_info) == MagickFalse)
CLIWandException(OptionFatalError,"MissingArgument",option);
CloneString(&arg1,token_info->token);
}
else
CloneString(&arg1,(char *) NULL);
if ( count >= 2 ) {
if (GetScriptToken(token_info) == MagickFalse)
CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
CloneString(&arg2,token_info->token);
}
else
CloneString(&arg2,(char *) NULL);
/*
Process Options
*/
#if MagickCommandDebug >= 3
(void) FormatLocaleFile(stderr,
"Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
#endif
/* Hard Deprecated Options, no code to execute - error */
if ( (option_type & DeprecateOptionFlag) != 0 ) {
CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
break; /* next option */
}
/* MagickCommandGenesis() options have no place in a magick script */
if ( (option_type & GenesisOptionFlag) != 0 ) {
CLIWandException(OptionError,"InvalidUseOfOption",option);
break; /* next option */
}
/* handle any special 'script' options */
if ( (option_type & SpecialOptionFlag) != 0 ) {
if ( LocaleCompare(option,"-exit") == 0 ) {
goto loop_exit; /* break out of loop - return from script */
}
if ( LocaleCompare(option,"-script") == 0 ) {
/* FUTURE: call new script from this script - error for now */
CLIWandException(OptionError,"InvalidUseOfOption",option);
break; /* next option */
}
/* FUTURE: handle special script-argument options here */
/* handle any other special operators now */
CLIWandException(OptionError,"InvalidUseOfOption",option);
break; /* next option */
}
/* Process non-specific Option */
CLIOption(cli_wand, option, arg1, arg2);
(void) fflush(stdout);
(void) fflush(stderr);
DisableMSCWarning(4127)
} while (0); /* break block to next option */
RestoreMSCWarning
#if MagickCommandDebug >= 5
fprintf(stderr, "Script Image Count = %ld\n",
GetImageListLength(cli_wand->wand.images) );
#endif
if (CLICatchException(cli_wand, MagickFalse) != MagickFalse)
break; /* exit loop */
}
/*
Loop exit - check for some tokenization error
*/
loop_exit:
#if MagickCommandDebug >= 3
(void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
#endif
switch( token_info->status ) {
case TokenStatusOK:
case TokenStatusEOF:
if (cli_wand->image_list_stack != (Stack *) NULL)
CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
else if (cli_wand->image_info_stack != (Stack *) NULL)
CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
break;
case TokenStatusBadQuotes:
/* Ensure last token has a sane length for error report */
if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
}
CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
token_info->token);
break;
case TokenStatusMemoryFailed:
CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
break;
case TokenStatusBinary:
CLIWandException(OptionFatalError,"ScriptIsBinary","");
break;
}
(void) fflush(stdout);
(void) fflush(stderr);
if (cli_wand->wand.debug != MagickFalse)
(void) LogMagickEvent(CommandEvent,GetMagickModule(),
"Script End \"%s\"", filename);
/* Clean up */
token_info = DestroyScriptTokenInfo(token_info);
CloneString(&option,(char *) NULL);
CloneString(&arg1,(char *) NULL);
CloneString(&arg2,(char *) NULL);
return;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ P r o c e s s C o m m a n d O p t i o n s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ProcessCommandOptions() reads and processes arguments in the given
% command line argument array. The 'index' defines where in the array we
% should begin processing
%
% The 'process_flags' can be used to control and limit option processing.
% For example, to only process one option, or how unknown and special options
% are to be handled, and if the last argument in array is to be regarded as a
% final image write argument (filename or special coder).
%
% The format of the ProcessCommandOptions method is:
%
% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
% int index)
%
% A description of each parameter follows:
%
% o cli_wand: the main CLI Wand to use.
%
% o argc: the number of elements in the argument vector.
%
% o argv: A text array containing the command line arguments.
%
% o process_flags: What type of arguments will be processed, ignored
% or return errors.
%
% o index: index in the argv array to start processing from
%
% The function returns the index ot the next option to be processed. This
% is really only releven if process_flags contains a ProcessOneOptionOnly
% flag.
%
*/
WandExport int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
int index)
{
const char
*option,
*arg1,
*arg2;
int
i,
end,
count;
CommandOptionFlags
option_type;
assert(argc>=index); /* you may have no arguments left! */
assert(argv != (char **) NULL);
assert(argv[index] != (char *) NULL);
assert(argv[argc-1] != (char *) NULL);
assert(cli_wand != (MagickCLI *) NULL);
assert(cli_wand->signature == MagickWandSignature);
/* define the error location string for use in exceptions
order of localtion format escapes: filename, line, column */
cli_wand->location="at %s arg %u";
cli_wand->filename="CLI";
cli_wand->line=index; /* note first argument we will process */
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"- Starting (\"%s\")", argv[index]);
end = argc;
if ( (cli_wand->process_flags & ProcessImplictWrite) != 0 )
end--; /* the last arument is an implied write, do not process directly */
for (i=index; i < end; i += count +1) {
/* Finished processing one option? */
if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index )
return(i);
do { /* use break to loop to exception handler and loop */
option=argv[i];
cli_wand->line=i; /* note the argument for this option */
/* get option, its argument count, and option type */
cli_wand->command = GetCommandOptionInfo(argv[i]);
count=cli_wand->command->type;
option_type=(CommandOptionFlags) cli_wand->command->flags;
#if 0
(void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
i, argv[i], cli_wand->command->mnemonic );
#endif
if ( option_type == UndefinedOptionFlag ||
(option_type & NonMagickOptionFlag) != 0 ) {
#if MagickCommandDebug >= 3
(void) FormatLocaleFile(stderr, "CLI arg %d Non-Option: \"%s\"\n",
i, option);
#endif
if (IsCommandOption(option) == MagickFalse) {
if ( (cli_wand->process_flags & ProcessImplictRead) != 0 ) {
/* non-option -- treat as a image read */
cli_wand->command=(const OptionInfo *) NULL;
CLIOption(cli_wand,"-read",option);
break; /* next option */
}
}
CLIWandException(OptionFatalError,"UnrecognizedOption",option);
break; /* next option */
}
if ( ((option_type & SpecialOptionFlag) != 0 ) &&
((cli_wand->process_flags & ProcessScriptOption) != 0) &&
(LocaleCompare(option,"-script") == 0) ) {
/* Call Script from CLI, with a filename as a zeroth argument.
NOTE: -script may need to use the 'implict write filename' argument
so it must be handled specially to prevent a 'missing argument' error.
*/
if ( (i+count) >= argc )
CLIWandException(OptionFatalError,"MissingArgument",option);
ProcessScriptOptions(cli_wand,argv[i+1],argc,argv,i+count);
return(argc); /* Script does not return to CLI -- Yet */
/* FUTURE: when it does, their may be no write arg! */
}
if ((i+count) >= end ) {
CLIWandException(OptionFatalError,"MissingArgument",option);
if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
return(end);
break; /* next option - not that their is any! */
}
arg1 = ( count >= 1 ) ? argv[i+1] : (char *) NULL;
arg2 = ( count >= 2 ) ? argv[i+2] : (char *) NULL;
/*
Process Known Options
*/
#if MagickCommandDebug >= 3
(void) FormatLocaleFile(stderr,
"CLI arg %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
i,option,count,option_type,arg1,arg2);
#endif
/* ignore 'genesis options' in command line args */
if ( (option_type & GenesisOptionFlag) != 0 )
break; /* next option */
/* Handle any special options for CLI (-script handled above) */
if ( (option_type & SpecialOptionFlag) != 0 ) {
if ( (cli_wand->process_flags & ProcessExitOption) != 0
&& LocaleCompare(option,"-exit") == 0 )
return(i+count);
break; /* next option */
}
/* Process standard image option */
CLIOption(cli_wand, option, arg1, arg2);
DisableMSCWarning(4127)
} while (0); /* break block to next option */
RestoreMSCWarning
#if MagickCommandDebug >= 5
(void) FormatLocaleFile(stderr, "CLI-post Image Count = %ld\n",
(long) GetImageListLength(cli_wand->wand.images) );
#endif
if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
return(i+count);
}
assert(i==end);
if ( (cli_wand->process_flags & ProcessImplictWrite) == 0 )
return(end); /* no implied write -- just return to caller */
assert(end==argc-1); /* end should not include last argument */
/*
Implicit Write of images to final CLI argument
*/
option=argv[i];
cli_wand->line=i;
/* check that stacks are empty - or cause exception */
if (cli_wand->image_list_stack != (Stack *) NULL)
CLIWandException(OptionError,"UnbalancedParenthesis", "(end of cli)");
else if (cli_wand->image_info_stack != (Stack *) NULL)
CLIWandException(OptionError,"UnbalancedBraces", "(end of cli)");
if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
return(argc);
#if MagickCommandDebug >= 3
(void) FormatLocaleFile(stderr,"CLI arg %d Write File: \"%s\"\n",i,option);
#endif
/* Valid 'do no write' replacement option (instead of "null:") */
if (LocaleCompare(option,"-exit") == 0 )
return(argc); /* just exit, no image write */
/* If filename looks like an option,
Or the common 'end of line' error of a single space.
-- produce an error */
if (IsCommandOption(option) != MagickFalse ||
(option[0] == ' ' && option[1] == '\0') ) {
CLIWandException(OptionError,"MissingOutputFilename",option);
return(argc);
}
cli_wand->command=(const OptionInfo *) NULL;
CLIOption(cli_wand,"-write",option);
return(argc);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ M a g i c k I m a g e C o m m a n d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MagickImageCommand() Handle special use CLI arguments and prepare a
% 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 MagickCLI
% processing functions ProcessCommandOptions() or ProcessScriptOptions()
%
% The format of the MagickImageCommand method is:
%
% MagickBooleanType MagickImageCommand(ImageInfo *image_info,int argc,
% char **argv,char **metadata,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the starting image_info structure
% (for compatibilty with MagickCommandGenisis())
%
% o argc: the number of elements in the argument vector.
%
% o argv: A text array containing the command line arguments.
%
% o metadata: any metadata (for VBS) is returned here.
% (for compatibilty with MagickCommandGenisis())
%
% o exception: return any errors or warnings in this structure.
%
*/
static void MagickUsage(MagickBooleanType verbose)
{
const char
*name;
size_t
len;
name=GetClientName();
len=strlen(name);
if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
/* convert usage */
(void) FormatLocaleFile(stdout,
"Usage: %s [ {option} | {image} ... ] {output_image}\n",name);
(void) FormatLocaleFile(stdout,
" %s -help | -version | -usage | -list {option}\n\n",name);
return;
}
else if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
/* magick-script usage */
(void) FormatLocaleFile(stdout,
"Usage: %s {filename} [ {script_args} ... ]\n",name);
}
else {
/* magick usage */
(void) FormatLocaleFile(stdout,
"Usage: %s tool [ {option} | {image} ... ] {output_image}\n",name);
(void) FormatLocaleFile(stdout,
"Usage: %s [ {option} | {image} ... ] {output_image}\n",name);
(void) FormatLocaleFile(stdout,
" %s [ {option} | {image} ... ] -script {filename} [ {script_args} ...]\n",
name);
}
(void) FormatLocaleFile(stdout,
" %s -help | -version | -usage | -list {option}\n\n",name);
if (verbose == MagickFalse)
return;
(void) FormatLocaleFile(stdout,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
"All options are performed in a strict 'as you see them' order\n",
"You must read-in images before you can operate on them.\n",
"\n",
"Magick Script files can use any of the following forms...\n",
" #!/path/to/magick -script\n",
"or\n",
" #!/bin/sh\n",
" :; exec magick -script \"$0\" \"$@\"; exit 10\n",
" # Magick script from here...\n",
"or\n",
" #!/usr/bin/env magick-script\n",
"The latter two forms do not require the path to the command hard coded.\n",
"Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
"\n",
"For more information on usage, options, examples, and techniques\n",
"see the ImageMagick website at ", MagickAuthoritativeURL);
return;
}
/*
Concatanate given file arguments to the given output argument.
Used for a special -concatenate option used for specific 'delegates'.
The option is not formally documented.
magick -concatenate files... output
This is much like the UNIX "cat" command, but for both UNIX and Windows,
however the last argument provides the output filename.
*/
static MagickBooleanType ConcatenateImages(int argc,char **argv,
ExceptionInfo *exception )
{
FILE
*input,
*output;
MagickBooleanType
status;
int
c;
ssize_t
i;
if (ExpandFilenames(&argc,&argv) == MagickFalse)
ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
GetExceptionMessage(errno));
output=fopen_utf8(argv[argc-1],"wb");
if (output == (FILE *) NULL)
{
ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
argv[argc-1]);
return(MagickFalse);
}
status=MagickTrue;
for (i=2; i < (ssize_t) (argc-1); i++)
{
input=fopen_utf8(argv[i],"rb");
if (input == (FILE *) NULL)
{
ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
continue;
}
for (c=fgetc(input); c != EOF; c=fgetc(input))
if (fputc((char) c,output) != c)
status=MagickFalse;
(void) fclose(input);
(void) remove_utf8(argv[i]);
}
(void) fclose(output);
return(status);
}
WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,int argc,
char **argv,char **metadata,ExceptionInfo *exception)
{
MagickCLI
*cli_wand;
size_t
len;
assert(image_info != (ImageInfo *) NULL);
/* For specific OS command line requirements */
ReadCommandlLine(argc,&argv);
/* Initialize special "CLI Wand" to hold images and settings (empty) */
cli_wand=AcquireMagickCLI(image_info,exception);
cli_wand->location="Initializing";
cli_wand->filename=argv[0];
cli_wand->line=1;
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"\"%s\"",argv[0]);
GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
SetClientName(cli_wand->wand.name);
ConcatenateMagickString(cli_wand->wand.name,"-CLI",MagickPathExtent);
len=strlen(argv[0]); /* precaution */
/* "convert" command - give a "deprecated" warning" */
if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
cli_wand->process_flags = ConvertCommandOptionFlags;
(void) FormatLocaleFile(stderr,"WARNING: %s\n",
"The convert command is deprecated in IMv7, use \"magick\"\n");
}
/* Special Case: If command name ends with "script" implied "-script" */
if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
if (argc >= 2 && ( (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) {
GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
ProcessScriptOptions(cli_wand,argv[1],argc,argv,2);
goto Magick_Command_Cleanup;
}
}
/* Special Case: Version Information and Abort */
if (argc == 2) {
if ((LocaleCompare("-version",argv[1]) == 0) || /* GNU standard option */
(LocaleCompare("--version",argv[1]) == 0) ) { /* just version */
CLIOption(cli_wand, "-version");
goto Magick_Command_Exit;
}
if ((LocaleCompare("-help",argv[1]) == 0) || /* GNU standard option */
(LocaleCompare("--help",argv[1]) == 0) ) { /* just a brief summary */
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"- Special Option \"%s\"", argv[1]);
MagickUsage(MagickFalse);
goto Magick_Command_Exit;
}
if (LocaleCompare("-usage",argv[1]) == 0) { /* both version & usage */
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"- Special Option \"%s\"", argv[1]);
CLIOption(cli_wand, "-version" );
MagickUsage(MagickTrue);
goto Magick_Command_Exit;
}
}
/* not enough arguments -- including -help */
if (argc < 3) {
(void) FormatLocaleFile(stderr,
"Error: Invalid argument or not enough arguments\n\n");
MagickUsage(MagickFalse);
goto Magick_Command_Exit;
}
/* Special "concatenate option (hidden) for delegate usage */
if (LocaleCompare("-concatenate",argv[1]) == 0) {
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"- Special Option \"%s\"", argv[1]);
ConcatenateImages(argc,argv,exception);
goto Magick_Command_Exit;
}
/* List Information and Abort */
if (argc == 3 && LocaleCompare("-list",argv[1]) == 0) {
CLIOption(cli_wand, argv[1], argv[2]);
goto Magick_Command_Exit;
}
/* ------------- */
/* The Main Call */
if (LocaleCompare("-script",argv[1]) == 0) {
/* Start processing directly from script, no pre-script options
Replace wand command name with script name
First argument in the argv array is the script name to read.
*/
GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
ProcessScriptOptions(cli_wand,argv[2],argc,argv,3);
}
else {
/* Normal Command Line, assumes output file as last option */
ProcessCommandOptions(cli_wand,argc,argv,1);
}
/* ------------- */
Magick_Command_Cleanup:
cli_wand->location="Cleanup";
cli_wand->filename=argv[0];
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"\"%s\"",argv[0]);
/* recover original image_info and clean up stacks
FUTURE: "-reset stacks" option */
while ((cli_wand->image_list_stack != (Stack *) NULL) &&
(cli_wand->image_list_stack->next != (Stack *) NULL))
CLIOption(cli_wand,")");
while ((cli_wand->image_info_stack != (Stack *) NULL) &&
(cli_wand->image_info_stack->next != (Stack *) NULL))
CLIOption(cli_wand,"}");
/* assert we have recovered the original structures */
assert(cli_wand->wand.image_info == image_info);
assert(cli_wand->wand.exception == exception);
/* Handle metadata for ImageMagickObject COM object for Windows VBS */
if ((cli_wand->wand.images != (Image *) NULL) &&
(metadata != (char **) NULL))
{
const char
*format;
char
*text;
format="%w,%h,%m"; /* Get this from image_info Option splaytree */
text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
exception);
if (text == (char *) NULL)
ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
"MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
else
{
(void) ConcatenateString(&(*metadata),text);
text=DestroyString(text);
}
}
Magick_Command_Exit:
cli_wand->location="Exiting";
cli_wand->filename=argv[0];
if (cli_wand->wand.debug != MagickFalse)
(void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
"\"%s\"",argv[0]);
/* Destroy the special CLI 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 ? MagickTrue : MagickFalse);
}