blob: 1d29d9aabd6e6372f1a8758cd6fa5a4fad97009d [file] [log] [blame]
anthonyfa1e43d2012-02-12 12:55:45 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% M M AAA GGGG IIIII CCCC K K %
7% MM MM A A G I C K K %
8% M M M AAAAA G GGG I C KKK %
9% M M A A G G I C K K %
10% M M A A GGGG IIIII CCCC K K %
11% %
12% CCCC L IIIII %
13% C L I %
14% C L I %
15% C L I %
16% CCCC LLLLL IIIII %
17% %
18% Perform "Magick" on Images via the Command Line Interface %
19% %
20% Dragon Computing %
21% Anthony Thyssen %
22% January 2012 %
23% %
24% %
25% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
26% dedicated to making software imaging solutions freely available. %
27% %
28% You may not use this file except in compliance with the License. You may %
29% obtain a copy of the License at %
30% %
31% http://www.imagemagick.org/script/license.php %
32% %
33% Unless required by applicable law or agreed to in writing, software %
34% distributed under the License is distributed on an "AS IS" BASIS, %
35% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36% See the License for the specific language governing permissions and %
37% limitations under the License. %
38% %
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40%
41% Read CLI arguments, script files, and pipelines, to provide options that
42% manipulate images from many different formats.
43%
44*/
45
46/*
47 Include declarations.
48*/
49#include "MagickWand/studio.h"
50#include "MagickWand/MagickWand.h"
51#include "MagickWand/magick-wand-private.h"
anthony756cd0d2012-04-08 12:41:44 +000052#include "MagickWand/wandcli.h"
53#include "MagickWand/wandcli-private.h"
anthony43f425d2012-02-26 12:58:58 +000054#include "MagickWand/operation.h"
anthony2052d272012-02-28 12:48:29 +000055#include "MagickWand/magick-cli.h"
anthony1cdc5b72012-03-03 02:31:18 +000056#include "MagickWand/script-token.h"
anthonyfa1e43d2012-02-12 12:55:45 +000057#include "MagickCore/utility-private.h"
anthony5216f822012-04-10 13:02:37 +000058#include "MagickCore/exception-private.h"
anthony668f43a2012-02-20 14:55:32 +000059#include "MagickCore/version.h"
60
anthony43f425d2012-02-26 12:58:58 +000061/* verbose debugging,
anthonyf125a5e2012-04-03 13:14:42 +000062 3 - option type details
63 9 - output options/artifacts/propertys
anthony24aa8822012-03-11 00:56:06 +000064*/
anthonyce51b4a2012-04-06 02:32:25 +000065#define MagickCommandDebug 0
anthony668f43a2012-02-20 14:55:32 +000066
anthony24aa8822012-03-11 00:56:06 +000067
anthonyf125a5e2012-04-03 13:14:42 +000068#if MagickCommandDebug >= 9
anthony8226e722012-04-05 14:25:46 +000069/*
70 Temporary Debugging Information
71 FUTURE: these should be able to be printed out using 'percent escapes'
72 Actually 'Properities' can already be output with "%[*]"
73*/
anthony24aa8822012-03-11 00:56:06 +000074static void OutputOptions(ImageInfo *image_info)
75{
76 const char
77 *option,
78 *value;
79
anthonyf125a5e2012-04-03 13:14:42 +000080 (void) FormatLocaleFile(stdout," Global Options:\n");
anthony24aa8822012-03-11 00:56:06 +000081 ResetImageOptionIterator(image_info);
82 while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) {
83 (void) FormatLocaleFile(stdout," %s: ",option);
84 value=GetImageOption(image_info,option);
85 if (value != (const char *) NULL)
86 (void) FormatLocaleFile(stdout,"%s\n",value);
87 }
anthony5216f822012-04-10 13:02:37 +000088 ResetImageOptionIterator(image_info);
anthony24aa8822012-03-11 00:56:06 +000089}
90
91static void OutputArtifacts(Image *image)
92{
93 const char
94 *artifact,
95 *value;
96
97 (void) FormatLocaleFile(stdout," Image Artifacts:\n");
98 ResetImageArtifactIterator(image);
99 while ((artifact=GetNextImageArtifact(image)) != (const char *) NULL ) {
100 (void) FormatLocaleFile(stdout," %s: ",artifact);
101 value=GetImageArtifact(image,artifact);
102 if (value != (const char *) NULL)
103 (void) FormatLocaleFile(stdout,"%s\n",value);
104 }
105 ResetImageArtifactIterator(image);
106}
anthonyf125a5e2012-04-03 13:14:42 +0000107
108static void OutputProperties(Image *image,ExceptionInfo *exception)
109{
110 const char
111 *property,
112 *value;
113
114 (void) FormatLocaleFile(stdout," Image Properity:\n");
115 ResetImagePropertyIterator(image);
116 while ((property=GetNextImageProperty(image)) != (const char *) NULL ) {
117 (void) FormatLocaleFile(stdout," %s: ",property);
118 value=GetImageProperty(image,property,exception);
119 if (value != (const char *) NULL)
120 (void) FormatLocaleFile(stdout,"%s\n",value);
121 }
122 ResetImagePropertyIterator(image);
123}
anthony24aa8822012-03-11 00:56:06 +0000124#endif
125
anthonyfa1e43d2012-02-12 12:55:45 +0000126
127/*
128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129% %
130% %
131% %
anthony668f43a2012-02-20 14:55:32 +0000132+ P r o c e s s S c r i p t O p t i o n s %
anthonyfa1e43d2012-02-12 12:55:45 +0000133% %
134% %
135% %
136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137%
anthony668f43a2012-02-20 14:55:32 +0000138% ProcessScriptOptions() reads options and processes options as they are
139% found in the given file, or pipeline. The filename to open and read
anthony0b46ebe2012-03-06 04:15:35 +0000140% options is given as the 'index' argument of the argument array given.
anthonyfa1e43d2012-02-12 12:55:45 +0000141%
anthony0b46ebe2012-03-06 04:15:35 +0000142% Other arguments following index may be read by special script options
143% as settings (strings), images, or as operations to be processed in various
144% ways. How they are treated is up to the script being processed.
anthonyfa1e43d2012-02-12 12:55:45 +0000145%
anthony0b46ebe2012-03-06 04:15:35 +0000146% Note that a script not 'return' to the command line processing, nor can
147% they call (and return from) other scripts. At least not at this time.
148%
149% There are no 'ProcessOptionFlags' control flags at this time.
anthony668f43a2012-02-20 14:55:32 +0000150%
151% The format of the ProcessScriptOptions method is:
152%
anthony0b46ebe2012-03-06 04:15:35 +0000153% void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
154% int index)
anthonyfa1e43d2012-02-12 12:55:45 +0000155%
156% A description of each parameter follows:
157%
anthony43f425d2012-02-26 12:58:58 +0000158% o cli_wand: the main CLI Wand to use.
anthonyfa1e43d2012-02-12 12:55:45 +0000159%
160% o argc: the number of elements in the argument vector.
161%
162% o argv: A text array containing the command line arguments.
163%
anthony0b46ebe2012-03-06 04:15:35 +0000164% o index: offset for argc to CLI argumnet count
165%
anthonyfa1e43d2012-02-12 12:55:45 +0000166*/
anthony0b46ebe2012-03-06 04:15:35 +0000167WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
168 int index)
anthony668f43a2012-02-20 14:55:32 +0000169{
anthony1cdc5b72012-03-03 02:31:18 +0000170 ScriptTokenInfo
171 *token_info;
anthony668f43a2012-02-20 14:55:32 +0000172
anthony668f43a2012-02-20 14:55:32 +0000173 CommandOptionFlags
174 option_type;
175
anthony0b46ebe2012-03-06 04:15:35 +0000176 int
anthony1cdc5b72012-03-03 02:31:18 +0000177 count;
anthony668f43a2012-02-20 14:55:32 +0000178
anthony1cdc5b72012-03-03 02:31:18 +0000179 char
180 *option,
181 *arg1,
182 *arg2;
183
anthony0b46ebe2012-03-06 04:15:35 +0000184 assert(argc>index); /* at least one argument - script name */
185 assert(argv != (char **)NULL);
186 assert(argv[index] != (char *)NULL);
187 assert(argv[argc-1] != (char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000188 assert(cli_wand != (MagickCLI *) NULL);
189 assert(cli_wand->signature == WandSignature);
190 if (cli_wand->wand.debug != MagickFalse)
191 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthony668f43a2012-02-20 14:55:32 +0000192
anthony0b46ebe2012-03-06 04:15:35 +0000193 /* open file script or stream, and set up tokenizer */
194 token_info = AcquireScriptTokenInfo(argv[index]);
anthony8ac75b52012-03-18 11:56:44 +0000195 if (token_info == (ScriptTokenInfo *) NULL) {
anthony5216f822012-04-10 13:02:37 +0000196 CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",argv[index]);
anthony1cdc5b72012-03-03 02:31:18 +0000197 return;
198 }
anthony668f43a2012-02-20 14:55:32 +0000199
anthony0b46ebe2012-03-06 04:15:35 +0000200 /* define the error location string for use in exceptions
anthony5216f822012-04-10 13:02:37 +0000201 order of localtion format escapes: filename, line, column */
202 cli_wand->location="in \"%s\" at line %u,column %u";
anthony0b46ebe2012-03-06 04:15:35 +0000203 if ( LocaleCompare("-", argv[index]) == 0 )
204 cli_wand->filename="stdin";
205 else
206 cli_wand->filename=argv[index];
anthony668f43a2012-02-20 14:55:32 +0000207
anthony0b46ebe2012-03-06 04:15:35 +0000208 /* Process Options from Script */
209 option = arg1 = arg2 = (char*)NULL;
anthony1cdc5b72012-03-03 02:31:18 +0000210 while (1) {
anthony668f43a2012-02-20 14:55:32 +0000211
anthony1cdc5b72012-03-03 02:31:18 +0000212 /* Get a option */
anthony0b46ebe2012-03-06 04:15:35 +0000213 { MagickBooleanType status = GetScriptToken(token_info);
214 cli_wand->line=token_info->token_line;
215 cli_wand->column=token_info->token_column;
anthony84d42792012-03-30 14:08:38 +0000216 if( IfMagickFalse(status) )
217 break; /* error or end of options */
anthony0b46ebe2012-03-06 04:15:35 +0000218 }
anthony668f43a2012-02-20 14:55:32 +0000219
anthony1cdc5b72012-03-03 02:31:18 +0000220 /* save option details */
221 CloneString(&option,token_info->token);
anthony1cdc5b72012-03-03 02:31:18 +0000222
223 { /* get option type and argument count */
224 const OptionInfo *option_info = GetCommandOptionInfo(option);
225 count=option_info->type;
cristyaa2c16c2012-03-25 22:21:35 +0000226 option_type=(CommandOptionFlags) option_info->flags;
anthonyf125a5e2012-04-03 13:14:42 +0000227#if 0
anthony0b46ebe2012-03-06 04:15:35 +0000228 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
229 cli_wand->line, cli_wand->line, option, option_info->mnemonic );
anthony668f43a2012-02-20 14:55:32 +0000230#endif
anthony1cdc5b72012-03-03 02:31:18 +0000231 }
anthony668f43a2012-02-20 14:55:32 +0000232
anthony0b46ebe2012-03-06 04:15:35 +0000233 /* handle a undefined option - image read? */
anthony1cdc5b72012-03-03 02:31:18 +0000234 if ( option_type == UndefinedOptionFlag ||
235 (option_type & NonMagickOptionFlag) != 0 ) {
anthonyf125a5e2012-04-03 13:14:42 +0000236#if MagickCommandDebug >= 3
237 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
238 cli_wand->line, cli_wand->line, option);
anthony668f43a2012-02-20 14:55:32 +0000239#endif
anthony756cd0d2012-04-08 12:41:44 +0000240 if ( IfMagickFalse(IsCommandOption(option))) {
anthonyafa3dfc2012-03-03 11:31:30 +0000241 /* non-option -- treat as a image read */
242 CLISpecialOperator(cli_wand,"-read",option);
anthony756cd0d2012-04-08 12:41:44 +0000243 goto next_token;
244 }
245 if ( LocaleCompare(option,"-script") == 0 ) {
246 option_type=SpecialOptionFlag;
247 count=1;
248 /* fall thru - collect one argument */
249 }
250 else {
anthonyafa3dfc2012-03-03 11:31:30 +0000251 CLIWandExceptionBreak(OptionFatalError,"UnrecognizedOption",option);
anthony756cd0d2012-04-08 12:41:44 +0000252 goto next_token;
253 }
anthonyafa3dfc2012-03-03 11:31:30 +0000254 }
anthony1cdc5b72012-03-03 02:31:18 +0000255
256 if ( count >= 1 ) {
anthony84d42792012-03-30 14:08:38 +0000257 if( IfMagickFalse(GetScriptToken(token_info)) )
anthony24aa8822012-03-11 00:56:06 +0000258 CLIWandException(OptionFatalError,"MissingArgument",option);
anthonyafa3dfc2012-03-03 11:31:30 +0000259 CloneString(&arg1,token_info->token);
260 }
anthony1cdc5b72012-03-03 02:31:18 +0000261 else
anthonyafa3dfc2012-03-03 11:31:30 +0000262 CloneString(&arg1,(char *)NULL);
anthony2052d272012-02-28 12:48:29 +0000263
anthony1cdc5b72012-03-03 02:31:18 +0000264 if ( count >= 2 ) {
anthony84d42792012-03-30 14:08:38 +0000265 if( IfMagickFalse(GetScriptToken(token_info)) )
anthonyafa3dfc2012-03-03 11:31:30 +0000266 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
267 CloneString(&arg2,token_info->token);
268 }
anthony1cdc5b72012-03-03 02:31:18 +0000269 else
270 CloneString(&arg2,(char *)NULL);
anthony668f43a2012-02-20 14:55:32 +0000271
anthonyb1d483a2012-04-14 12:53:56 +0000272 /*
273 Process Options
274 */
anthonyf125a5e2012-04-03 13:14:42 +0000275#if MagickCommandDebug >= 3
anthony1cdc5b72012-03-03 02:31:18 +0000276 (void) FormatLocaleFile(stderr,
anthonyf125a5e2012-04-03 13:14:42 +0000277 "Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
278 cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
anthony668f43a2012-02-20 14:55:32 +0000279#endif
anthonyb1d483a2012-04-14 12:53:56 +0000280 /* Hard Depreciated Options, no code to execute - error */
281 if ( (option_type & DeprecateOptionFlag) != 0 ) {
282 CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
283 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
284 break;
285 goto next_token;
286 }
anthony668f43a2012-02-20 14:55:32 +0000287
anthonyb1d483a2012-04-14 12:53:56 +0000288 /* MagickCommandGenesis() options have no place in a magick script */
anthony8226e722012-04-05 14:25:46 +0000289 if ( (option_type & GenesisOptionFlag) != 0 ) {
anthony8226e722012-04-05 14:25:46 +0000290 CLIWandExceptionBreak(OptionError,"InvalidUseOfOption",option);
291 goto next_token;
292 }
anthonya3ef4ed2012-03-17 06:52:53 +0000293
anthonyafa3dfc2012-03-03 11:31:30 +0000294 if ( (option_type & SpecialOptionFlag) != 0 ) {
anthony8226e722012-04-05 14:25:46 +0000295 if ( LocaleCompare(option,"-exit") == 0 ) {
296 break; /* forced end of script */
297 }
anthony756cd0d2012-04-08 12:41:44 +0000298 else if ( LocaleCompare(option,"-script") == 0 ) {
299 /* FUTURE: call new script from this script */
anthony8226e722012-04-05 14:25:46 +0000300 CLIWandExceptionBreak(OptionError,"InvalidUseOfOption",option);
301 goto next_token;
302 }
anthonyb1d483a2012-04-14 12:53:56 +0000303 /* FUTURE: handle special script-argument options here */
anthony8226e722012-04-05 14:25:46 +0000304 /* handle any other special operators now */
anthonyafa3dfc2012-03-03 11:31:30 +0000305 CLISpecialOperator(cli_wand,option,arg1);
306 }
anthony668f43a2012-02-20 14:55:32 +0000307
anthonyafa3dfc2012-03-03 11:31:30 +0000308 if ( (option_type & SettingOptionFlags) != 0 ) {
anthonye5fcd362012-04-09 04:02:09 +0000309 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
anthony24aa8822012-03-11 00:56:06 +0000310 // FUTURE: Sync Specific Settings into Image Properities (not global)
anthonyafa3dfc2012-03-03 11:31:30 +0000311 }
anthonyb1d483a2012-04-14 12:53:56 +0000312
313 /* FUTURE: The not a setting part below is a temporary hack to stop gap
314 * measure for options that are BOTH settings and optional 'Simple/List'
anthonydf323722012-04-16 01:17:38 +0000315 * operators. Specifically -monitor, -depth, and -colorspace */
anthonyb1d483a2012-04-14 12:53:56 +0000316 if ( cli_wand->wand.images == (Image *)NULL ) {
317 if (((option_type & ImageRequiredFlags) != 0 ) &&
318 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
319 CLIWandException(OptionError,"NoImagesFound",option);
320 goto next_token;
321 }
322
323 /* FUTURE: this is temporary - get 'settings' to handle
324 distribution of settings to images attributes,proprieties,artifacts */
325 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
326 cli_wand->wand.exception);
anthony668f43a2012-02-20 14:55:32 +0000327
anthony1cdc5b72012-03-03 02:31:18 +0000328 if ( (option_type & SimpleOperatorOptionFlag) != 0)
anthonyafa3dfc2012-03-03 11:31:30 +0000329 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
anthony668f43a2012-02-20 14:55:32 +0000330
anthony1cdc5b72012-03-03 02:31:18 +0000331 if ( (option_type & ListOperatorOptionFlag) != 0 )
anthonyafa3dfc2012-03-03 11:31:30 +0000332 CLIListOperatorImages(cli_wand, option, arg1, arg2);
anthony1cdc5b72012-03-03 02:31:18 +0000333
anthony24aa8822012-03-11 00:56:06 +0000334next_token:
anthonyf125a5e2012-04-03 13:14:42 +0000335#if MagickCommandDebug >= 9
anthony24aa8822012-03-11 00:56:06 +0000336 OutputOptions(cli_wand->wand.image_info);
anthonyf125a5e2012-04-03 13:14:42 +0000337 if ( cli_wand->wand.images != (Image *)NULL ) {
anthony24aa8822012-03-11 00:56:06 +0000338 OutputArtifacts(cli_wand->wand.images);
anthonyf125a5e2012-04-03 13:14:42 +0000339 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
340 }
anthony24aa8822012-03-11 00:56:06 +0000341#endif
anthony1cdc5b72012-03-03 02:31:18 +0000342 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
343 break;
344 }
345
anthonyf125a5e2012-04-03 13:14:42 +0000346#if MagickCommandDebug >= 3
anthony1cdc5b72012-03-03 02:31:18 +0000347 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
348#endif
349 switch( token_info->status ) {
350 case TokenStatusOK:
351 case TokenStatusEOF:
anthony8226e722012-04-05 14:25:46 +0000352 if (cli_wand->image_list_stack != (Stack *)NULL)
353 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
354 else if (cli_wand->image_info_stack != (Stack *)NULL)
355 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
anthony1cdc5b72012-03-03 02:31:18 +0000356 break;
357 case TokenStatusBadQuotes:
358 /* Ensure last token has a sane length for error report */
359 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
360 token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
361 token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
362 token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
363 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
364 }
anthonyafa3dfc2012-03-03 11:31:30 +0000365 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
366 token_info->token);
anthony1cdc5b72012-03-03 02:31:18 +0000367 break;
368 case TokenStatusMemoryFailed:
anthonyafa3dfc2012-03-03 11:31:30 +0000369 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
anthony1cdc5b72012-03-03 02:31:18 +0000370 break;
371 case TokenStatusBinary:
anthonyafa3dfc2012-03-03 11:31:30 +0000372 CLIWandException(OptionFatalError,"ScriptIsBinary","");
anthony1cdc5b72012-03-03 02:31:18 +0000373 break;
374 }
375
376 /* Clean up */
377 token_info = DestroyScriptTokenInfo(token_info);
378
379 CloneString(&option,(char *)NULL);
380 CloneString(&arg1,(char *)NULL);
381 CloneString(&arg2,(char *)NULL);
382
383 return;
anthony668f43a2012-02-20 14:55:32 +0000384}
385
386/*
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388% %
389% %
390% %
391+ P r o c e s s C o m m a n d O p t i o n s %
392% %
393% %
394% %
395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396%
397% ProcessCommandOptions() reads and processes arguments in the given
398% command line argument array. The array does not contain the command
399% being processed, only the options.
400%
401% The 'process_flags' can be used to control and limit option processing.
402% For example, to only process one option, or how unknown and special options
403% are to be handled, and if the last argument in array is to be regarded as a
404% final image write argument (filename or special coder).
405%
406% The format of the ProcessCommandOptions method is:
407%
anthony43f425d2012-02-26 12:58:58 +0000408% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
anthony0b46ebe2012-03-06 04:15:35 +0000409% int index, ProcessOptionFlags process_flags )
anthony668f43a2012-02-20 14:55:32 +0000410%
411% A description of each parameter follows:
412%
anthony43f425d2012-02-26 12:58:58 +0000413% o cli_wand: the main CLI Wand to use.
anthony668f43a2012-02-20 14:55:32 +0000414%
415% o argc: the number of elements in the argument vector.
416%
417% o argv: A text array containing the command line arguments.
418%
anthony0ea037a2012-04-03 12:14:39 +0000419% o process_flags: What type of arguments will be processed, ignored
420% or return errors.
anthony668f43a2012-02-20 14:55:32 +0000421%
anthony0b46ebe2012-03-06 04:15:35 +0000422% o index: index in the argv array to start processing from
423%
424% The function returns the index ot the next option to be processed. This
425% is really only releven if process_flags contains a ProcessOneOptionOnly
426% flag.
427%
anthony668f43a2012-02-20 14:55:32 +0000428*/
anthony0b46ebe2012-03-06 04:15:35 +0000429WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc,
anthony5216f822012-04-10 13:02:37 +0000430 char **argv, int index )
anthonyfa1e43d2012-02-12 12:55:45 +0000431{
432 const char
433 *option,
434 *arg1,
435 *arg2;
436
anthony0b46ebe2012-03-06 04:15:35 +0000437 int
anthonyfa1e43d2012-02-12 12:55:45 +0000438 i,
anthony668f43a2012-02-20 14:55:32 +0000439 end,
anthonyfa1e43d2012-02-12 12:55:45 +0000440 count;
441
442 CommandOptionFlags
anthony686b1a32012-02-15 14:50:53 +0000443 option_type;
anthonyfa1e43d2012-02-12 12:55:45 +0000444
anthony0b46ebe2012-03-06 04:15:35 +0000445 assert(argc>=index); /* you may have no arguments left! */
446 assert(argv != (char **)NULL);
447 assert(argv[index] != (char *)NULL);
448 assert(argv[argc-1] != (char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000449 assert(cli_wand != (MagickCLI *) NULL);
450 assert(cli_wand->signature == WandSignature);
451 if (cli_wand->wand.debug != MagickFalse)
452 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthonyfa1e43d2012-02-12 12:55:45 +0000453
anthony92c93bd2012-03-19 14:02:47 +0000454 /* define the error location string for use in exceptions
anthony5216f822012-04-10 13:02:37 +0000455 order of localtion format escapes: filename, line, column */
456 cli_wand->location="at %s argument %u";
anthonyafa3dfc2012-03-03 11:31:30 +0000457 cli_wand->filename="CLI";
458
anthony668f43a2012-02-20 14:55:32 +0000459 end = argc;
anthony5216f822012-04-10 13:02:37 +0000460 if ( (cli_wand->process_flags & ProcessImpliedWrite) != 0 )
461 end--; /* the last arument is an implied write, do not process directly */
anthony0b46ebe2012-03-06 04:15:35 +0000462
463 for (i=index; i < end; i += count +1) {
anthonyafa3dfc2012-03-03 11:31:30 +0000464 /* Finished processing one option? */
anthony5216f822012-04-10 13:02:37 +0000465 if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index )
anthony0b46ebe2012-03-06 04:15:35 +0000466 return(i);
anthony668f43a2012-02-20 14:55:32 +0000467
anthonyafa3dfc2012-03-03 11:31:30 +0000468 option=argv[i];
anthony5216f822012-04-10 13:02:37 +0000469 cli_wand->line=i; /* note the argument for this option */
anthonyfa1e43d2012-02-12 12:55:45 +0000470
anthonyafa3dfc2012-03-03 11:31:30 +0000471 { const OptionInfo *option_info = GetCommandOptionInfo(argv[i]);
472 count=option_info->type;
cristyaa2c16c2012-03-25 22:21:35 +0000473 option_type=(CommandOptionFlags) option_info->flags;
anthonyf125a5e2012-04-03 13:14:42 +0000474#if 0
anthony0b46ebe2012-03-06 04:15:35 +0000475 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
476 i, argv[i], option_info->mnemonic );
anthony686b1a32012-02-15 14:50:53 +0000477#endif
anthonyafa3dfc2012-03-03 11:31:30 +0000478 }
anthonyfa1e43d2012-02-12 12:55:45 +0000479
anthonyafa3dfc2012-03-03 11:31:30 +0000480 if ( option_type == UndefinedOptionFlag ||
481 (option_type & NonMagickOptionFlag) != 0 ) {
anthonyf125a5e2012-04-03 13:14:42 +0000482#if MagickCommandDebug >= 3
483 (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option);
anthonyfa1e43d2012-02-12 12:55:45 +0000484#endif
anthony756cd0d2012-04-08 12:41:44 +0000485 if ( IfMagickFalse(IsCommandOption(option)) ) {
anthony5216f822012-04-10 13:02:37 +0000486 if ( (cli_wand->process_flags & ProcessNonOptionImageRead) != 0 )
anthony756cd0d2012-04-08 12:41:44 +0000487 /* non-option -- treat as a image read */
488 CLISpecialOperator(cli_wand,"-read",option);
489 else
490 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
491 goto next_argument;
492 }
anthony5216f822012-04-10 13:02:37 +0000493 if ( ((cli_wand->process_flags & ProcessScriptOption) != 0) &&
anthony756cd0d2012-04-08 12:41:44 +0000494 (LocaleCompare(option,"-script") == 0) ) {
495 /* Call Script from CLI, with a filename as a zeroth argument.
496 NOTE: -script may need to use 'implict write filename' so it
497 must be handled here to prevent 'missing argument' error.
498 */
499 ProcessScriptOptions(cli_wand,argc,argv,i+1);
500 return(argc); /* Script does not return to CLI -- Yet -- FUTURE */
501 }
502 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
anthony24aa8822012-03-11 00:56:06 +0000503 goto next_argument;
anthonyfa1e43d2012-02-12 12:55:45 +0000504 }
505
anthonyafa3dfc2012-03-03 11:31:30 +0000506 if ((i+count) >= end ) {
anthony0b46ebe2012-03-06 04:15:35 +0000507 CLIWandException(OptionFatalError,"MissingArgument",option);
anthonyafa3dfc2012-03-03 11:31:30 +0000508 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
anthony0b46ebe2012-03-06 04:15:35 +0000509 return(end);
anthony24aa8822012-03-11 00:56:06 +0000510 goto next_argument; /* no more arguments unable to proceed */
anthonyafa3dfc2012-03-03 11:31:30 +0000511 }
512
513 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL;
514 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL;
515
anthonyb1d483a2012-04-14 12:53:56 +0000516 /*
517 Process Known Options
518 */
anthonyf125a5e2012-04-03 13:14:42 +0000519#if MagickCommandDebug >= 3
anthonyafa3dfc2012-03-03 11:31:30 +0000520 (void) FormatLocaleFile(stderr,
anthonyf125a5e2012-04-03 13:14:42 +0000521 "CLI %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
522 i,option,count,option_type,arg1,arg2);
anthonyafa3dfc2012-03-03 11:31:30 +0000523#endif
anthonyb1d483a2012-04-14 12:53:56 +0000524 /* Hard Depreciated Options, no code to execute - error */
anthony8226e722012-04-05 14:25:46 +0000525 if ( (option_type & DeprecateOptionFlag) != 0 ) {
anthony975a8d72012-04-12 13:54:36 +0000526 CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
527 goto next_argument;
anthony8226e722012-04-05 14:25:46 +0000528 }
anthonyb1d483a2012-04-14 12:53:56 +0000529
530 /* Ignore MagickCommandGenesis() only option on CLI */
531 if ( (option_type & GenesisOptionFlag) != 0 )
anthony8226e722012-04-05 14:25:46 +0000532 goto next_argument;
anthony8226e722012-04-05 14:25:46 +0000533
anthonyafa3dfc2012-03-03 11:31:30 +0000534 if ( (option_type & SpecialOptionFlag) != 0 ) {
anthony5216f822012-04-10 13:02:37 +0000535 if ( (cli_wand->process_flags & ProcessExitOption) != 0
anthonyafa3dfc2012-03-03 11:31:30 +0000536 && LocaleCompare(option,"-exit") == 0 )
anthony0b46ebe2012-03-06 04:15:35 +0000537 return(i+count);
anthony8226e722012-04-05 14:25:46 +0000538 /* handle any other special operators now */
anthonyafa3dfc2012-03-03 11:31:30 +0000539 CLISpecialOperator(cli_wand,option,arg1);
540 }
541
542 if ( (option_type & SettingOptionFlags) != 0 ) {
anthonye5fcd362012-04-09 04:02:09 +0000543 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
anthony756cd0d2012-04-08 12:41:44 +0000544 // FUTURE: Sync individual Settings into images (no SyncImageSettings())
anthonyafa3dfc2012-03-03 11:31:30 +0000545 }
anthonyb1d483a2012-04-14 12:53:56 +0000546
547 /* FUTURE: The not a setting part below is a temporary hack to stop gap
548 * measure for options that are BOTH settings and optional 'Simple/List'
anthonydf323722012-04-16 01:17:38 +0000549 * operators. Specifically -monitor, -depth, and -colorspace */
anthonyb1d483a2012-04-14 12:53:56 +0000550 if ( cli_wand->wand.images == (Image *)NULL ) {
551 if (((option_type & ImageRequiredFlags) != 0 ) &&
552 ((option_type & SettingOptionFlags) == 0 ) ) /* temp hack */
553 CLIWandException(OptionError,"NoImagesFound",option);
554 goto next_argument;
555 }
556
557 /* FUTURE: this is temporary - get 'settings' to handle
558 distribution of settings to images attributes,proprieties,artifacts */
559 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
anthonyeff71f52012-03-29 12:59:09 +0000560 cli_wand->wand.exception);
anthonyafa3dfc2012-03-03 11:31:30 +0000561
562 if ( (option_type & SimpleOperatorOptionFlag) != 0)
563 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
564
565 if ( (option_type & ListOperatorOptionFlag) != 0 )
566 CLIListOperatorImages(cli_wand, option, arg1, arg2);
567
anthony24aa8822012-03-11 00:56:06 +0000568next_argument:
anthonyf125a5e2012-04-03 13:14:42 +0000569#if MagickCommandDebug >= 9
anthony24aa8822012-03-11 00:56:06 +0000570 OutputOptions(cli_wand->wand.image_info);
anthonyf125a5e2012-04-03 13:14:42 +0000571 if ( cli_wand->wand.images != (Image *)NULL ) {
anthony24aa8822012-03-11 00:56:06 +0000572 OutputArtifacts(cli_wand->wand.images);
anthonyf125a5e2012-04-03 13:14:42 +0000573 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
574 }
anthony24aa8822012-03-11 00:56:06 +0000575#endif
anthonyafa3dfc2012-03-03 11:31:30 +0000576 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
anthony0b46ebe2012-03-06 04:15:35 +0000577 return(i+count);
anthonyafa3dfc2012-03-03 11:31:30 +0000578 }
anthony0b46ebe2012-03-06 04:15:35 +0000579 assert(i==end);
anthony2052d272012-02-28 12:48:29 +0000580
anthony5216f822012-04-10 13:02:37 +0000581 if ( (cli_wand->process_flags & ProcessImpliedWrite) == 0 )
582 return(end); /* no implied write -- just return to caller */
anthony0b46ebe2012-03-06 04:15:35 +0000583
anthony5216f822012-04-10 13:02:37 +0000584 assert(end==argc-1); /* end should not include last argument */
anthony668f43a2012-02-20 14:55:32 +0000585
586 /*
anthony43f425d2012-02-26 12:58:58 +0000587 Implicit Write of images to final CLI argument
anthony668f43a2012-02-20 14:55:32 +0000588 */
589 option=argv[i];
anthony799889a2012-03-11 11:00:32 +0000590 cli_wand->line=i;
anthony686b1a32012-02-15 14:50:53 +0000591
anthonyf125a5e2012-04-03 13:14:42 +0000592#if MagickCommandDebug >= 3
593 (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option );
anthonyfa1e43d2012-02-12 12:55:45 +0000594#endif
595
anthony8226e722012-04-05 14:25:46 +0000596 /* check that stacks are empty */
597 if (cli_wand->image_list_stack != (Stack *)NULL)
598 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
599 else if (cli_wand->image_info_stack != (Stack *)NULL)
600 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
601 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
602 return(argc);
anthonyfa1e43d2012-02-12 12:55:45 +0000603
anthony8226e722012-04-05 14:25:46 +0000604 /* This is a valid 'do no write' option - no images needed */
anthonyfa1e43d2012-02-12 12:55:45 +0000605 if (LocaleCompare(option,"-exit") == 0 )
anthony0b46ebe2012-03-06 04:15:35 +0000606 return(argc); /* just exit, no image write */
anthonyfa1e43d2012-02-12 12:55:45 +0000607
anthony8226e722012-04-05 14:25:46 +0000608 /* If filename looks like an option -- produce an error */
anthony0b46ebe2012-03-06 04:15:35 +0000609 if (IsCommandOption(option) != MagickFalse) {
610 CLIWandException(OptionError,"MissingOutputFilename",option);
611 return(argc);
612 }
anthonyfa1e43d2012-02-12 12:55:45 +0000613
anthony8226e722012-04-05 14:25:46 +0000614 CLISpecialOperator(cli_wand,"-write",option);
anthony0b46ebe2012-03-06 04:15:35 +0000615 return(argc);
anthonyfa1e43d2012-02-12 12:55:45 +0000616}
617
618/*
619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620% %
621% %
622% %
623+ M a g i c k I m a g e C o m m a n d %
624% %
625% %
626% %
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628%
anthony668f43a2012-02-20 14:55:32 +0000629% MagickImageCommand() Handle special use CLI arguments and prepare a
anthony43f425d2012-02-26 12:58:58 +0000630% CLI MagickCLI to process the command line or directly specified script.
anthony668f43a2012-02-20 14:55:32 +0000631%
632% This is essentualy interface function between the MagickCore library
anthony43f425d2012-02-26 12:58:58 +0000633% initialization function MagickCommandGenesis(), and the option MagickCLI
anthony668f43a2012-02-20 14:55:32 +0000634% processing functions ProcessCommandOptions() or ProcessScriptOptions()
anthonyfa1e43d2012-02-12 12:55:45 +0000635%
636% The format of the MagickImageCommand method is:
637%
638% MagickBooleanType MagickImageCommand(ImageInfo *image_info,
639% int argc, char **argv, char **metadata, ExceptionInfo *exception)
640%
641% A description of each parameter follows:
642%
643% o image_info: the starting image_info structure
644% (for compatibilty with MagickCommandGenisis())
645%
646% o argc: the number of elements in the argument vector.
647%
648% o argv: A text array containing the command line arguments.
649%
anthony0ea037a2012-04-03 12:14:39 +0000650% o metadata: any metadata (for VBS) is returned here.
anthonyfa1e43d2012-02-12 12:55:45 +0000651% (for compatibilty with MagickCommandGenisis())
652%
653% o exception: return any errors or warnings in this structure.
654%
655*/
656
anthony40b60152012-04-04 06:13:37 +0000657static void MagickUsage(MagickBooleanType verbose)
anthonyfa1e43d2012-02-12 12:55:45 +0000658{
anthonye5fcd362012-04-09 04:02:09 +0000659 const char
660 *name;
661
662 size_t
663 len;
664
665 name=GetClientName();
666 len=strlen(name);
667
anthonyd22bf402012-04-10 01:32:03 +0000668 if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
anthonye5fcd362012-04-09 04:02:09 +0000669 /* convert usage */
670 (void) FormatLocaleFile(stdout,
671 "Usage: %s [{option}|{image}...] {output_image}\n",name);
672 (void) FormatLocaleFile(stdout,
anthonyd22bf402012-04-10 01:32:03 +0000673 " %s -help|-version|-usage|-list {option}\n\n",name);
674 return;
675 }
676 else if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
677 /* magick-script usage */
678 (void) FormatLocaleFile(stdout,
679 "Usage: %s {filename} [{script_args}...]\n",name);
anthonye5fcd362012-04-09 04:02:09 +0000680 }
681 else {
682 /* magick usage */
683 (void) FormatLocaleFile(stdout,
684 "Usage: %s [{option}|{image}...] {output_image}\n",name);
685 (void) FormatLocaleFile(stdout,
anthony40b60152012-04-04 06:13:37 +0000686 " %s [{option}|{image}...] -script {filename} [{script_args}...]\n",
anthonye5fcd362012-04-09 04:02:09 +0000687 name);
anthonye5fcd362012-04-09 04:02:09 +0000688 }
anthonyd22bf402012-04-10 01:32:03 +0000689 (void) FormatLocaleFile(stdout,
690 " %s -help|-version|-usage|-list {option}\n\n",name);
anthony40b60152012-04-04 06:13:37 +0000691
692 if (IfMagickFalse(verbose))
693 return;
694
anthonyd22bf402012-04-10 01:32:03 +0000695 (void) FormatLocaleFile(stdout,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
anthony40b60152012-04-04 06:13:37 +0000696 "All options are performed in a strict 'as you see them' order\n",
697 "You must read-in images before you can operate on them.\n",
698 "\n",
699 "Magick Script files can use any of the following forms...\n",
700 " #!/path/to/magick -script\n",
701 "or\n",
702 " #!/bin/sh\n",
703 " :; exec magick -script \"$0\" \"$@\"; exit 10\n",
704 " # Magick script from here...\n",
705 "or\n",
706 " #!/usr/bin/env magick-script\n",
707 "The latter two forms do not require the path to the command hard coded.\n",
708 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
709 "\n",
710 "For more information on usage, options, examples, and techniques\n",
711 "see the ImageMagick website at ", MagickAuthoritativeURL);
712
713 return;
anthonyfa1e43d2012-02-12 12:55:45 +0000714}
715
716/*
717 Concatanate given file arguments to the given output argument.
718 Used for a special -concatenate option used for specific 'delegates'.
719 The option is not formally documented.
720
721 magick -concatenate files... output
722
723 This is much like the UNIX "cat" command, but for both UNIX and Windows,
724 however the last argument provides the output filename.
725*/
anthonyfa1e43d2012-02-12 12:55:45 +0000726static MagickBooleanType ConcatenateImages(int argc,char **argv,
anthony5216f822012-04-10 13:02:37 +0000727 ExceptionInfo *exception )
anthonyfa1e43d2012-02-12 12:55:45 +0000728{
729 FILE
730 *input,
731 *output;
732
733 int
734 c;
735
736 register ssize_t
737 i;
738
739 output=fopen_utf8(argv[argc-1],"wb");
anthonyafa3dfc2012-03-03 11:31:30 +0000740 if (output == (FILE *) NULL) {
anthony5216f822012-04-10 13:02:37 +0000741 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[argc-1]);
anthonyafa3dfc2012-03-03 11:31:30 +0000742 return(MagickFalse);
743 }
744 for (i=2; i < (ssize_t) (argc-1); i++) {
anthonyfa1e43d2012-02-12 12:55:45 +0000745 input=fopen_utf8(argv[i],"rb");
746 if (input == (FILE *) NULL)
747 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
748 for (c=fgetc(input); c != EOF; c=fgetc(input))
749 (void) fputc((char) c,output);
750 (void) fclose(input);
751 (void) remove_utf8(argv[i]);
752 }
753 (void) fclose(output);
754 return(MagickTrue);
755}
756
757WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
758 int argc,char **argv,char **metadata,ExceptionInfo *exception)
759{
anthony43f425d2012-02-26 12:58:58 +0000760 MagickCLI
761 *cli_wand;
anthonyfa1e43d2012-02-12 12:55:45 +0000762
anthonye5fcd362012-04-09 04:02:09 +0000763 size_t
764 len;
765
anthony4cb37262012-03-18 11:18:45 +0000766 /* For specific OS command line requirements */
767 ReadCommandlLine(argc,&argv);
768
769#if 0
anthony4cb37262012-03-18 11:18:45 +0000770 status=ExpandFilenames(&argc,&argv);
anthony0ea037a2012-04-03 12:14:39 +0000771 if ( IfMagickFalse(status) )
anthony4cb37262012-03-18 11:18:45 +0000772 ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed",
773 GetExceptionMessage(errno));
774#endif
anthonyeff71f52012-03-29 12:59:09 +0000775
anthony668f43a2012-02-20 14:55:32 +0000776 /* Initialize special "CLI Wand" to hold images and settings (empty) */
anthony43f425d2012-02-26 12:58:58 +0000777 cli_wand=AcquireMagickCLI(image_info,exception);
anthony8226e722012-04-05 14:25:46 +0000778 cli_wand->line=1;
anthonyfa1e43d2012-02-12 12:55:45 +0000779
anthonyeff71f52012-03-29 12:59:09 +0000780 GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
anthonye5fcd362012-04-09 04:02:09 +0000781 SetClientName(cli_wand->wand.name);
anthonyeff71f52012-03-29 12:59:09 +0000782 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent);
783
anthonye5fcd362012-04-09 04:02:09 +0000784 len=strlen(argv[0]); /* precaution */
785
anthonyeff71f52012-03-29 12:59:09 +0000786 /* "convert" command - give a "depreciation" warning" */
anthonye5fcd362012-04-09 04:02:09 +0000787 if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
anthony5216f822012-04-10 13:02:37 +0000788 cli_wand->process_flags = ConvertCommandOptionFlags;
anthony0ea037a2012-04-03 12:14:39 +0000789 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n",
790 "The convert is depreciated in IMv7, use \"magick\"\n");*/
anthonyeff71f52012-03-29 12:59:09 +0000791 }
anthonyeff71f52012-03-29 12:59:09 +0000792
anthony8226e722012-04-05 14:25:46 +0000793 /* Special Case: If command name ends with "script" implied "-script" */
anthonye5fcd362012-04-09 04:02:09 +0000794 if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
anthonyd22bf402012-04-10 01:32:03 +0000795 if (argc >= 2 && ( (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) {
anthonye5fcd362012-04-09 04:02:09 +0000796 GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
797 ProcessScriptOptions(cli_wand,argc,argv,1);
798 goto Magick_Command_Cleanup;
799 }
anthony52bef752012-03-27 13:54:47 +0000800 }
801
802 /* Special Case: Version Information and Abort */
803 if (argc == 2) {
anthony5216f822012-04-10 13:02:37 +0000804 if (LocaleCompare("-version",argv[1]) == 0) {
anthony52bef752012-03-27 13:54:47 +0000805 CLISpecialOperator(cli_wand, "-version", (char *)NULL);
806 goto Magick_Command_Exit;
807 }
anthony5216f822012-04-10 13:02:37 +0000808 if ((LocaleCompare("-help",argv[1]) == 0) || /* GNU standard option */
809 (LocaleCompare("--help",argv[1]) == 0) ) {
anthony40b60152012-04-04 06:13:37 +0000810 MagickUsage(MagickFalse);
811 goto Magick_Command_Exit;
812 }
anthony5216f822012-04-10 13:02:37 +0000813 if (LocaleCompare("-usage",argv[1]) == 0) {
anthony40b60152012-04-04 06:13:37 +0000814 CLISpecialOperator(cli_wand, "-version", (char *)NULL);
815 MagickUsage(MagickTrue);
816 goto Magick_Command_Exit;
817 }
anthony52bef752012-03-27 13:54:47 +0000818 }
819
820 /* not enough arguments -- including -help */
821 if (argc < 3) {
anthony40b60152012-04-04 06:13:37 +0000822 (void) FormatLocaleFile(stderr,
823 "Error: Invalid argument or not enough arguments\n\n");
824 MagickUsage(MagickFalse);
anthony52bef752012-03-27 13:54:47 +0000825 goto Magick_Command_Exit;
826 }
827
anthony52bef752012-03-27 13:54:47 +0000828 /* List Information and Abort */
829 if (LocaleCompare("-list",argv[1]) == 0) {
anthonyafa3dfc2012-03-03 11:31:30 +0000830 CLISpecialOperator(cli_wand, argv[1], argv[2]);
anthony52bef752012-03-27 13:54:47 +0000831 goto Magick_Command_Exit;
832 }
833
anthony0ea037a2012-04-03 12:14:39 +0000834 /* Special "concatenate option (hidden) for delegate usage */
835 if (LocaleCompare("-concatenate",argv[1]) == 0) {
836 ConcatenateImages(argc,argv,exception);
837 goto Magick_Command_Exit;
838 }
839
anthony52bef752012-03-27 13:54:47 +0000840 /* ------------- */
841 /* The Main Call */
842
843 if (LocaleCompare("-script",argv[1]) == 0) {
anthonyafa3dfc2012-03-03 11:31:30 +0000844 /* Start processing directly from script, no pre-script options
anthony0b46ebe2012-03-06 04:15:35 +0000845 Replace wand command name with script name
846 First argument in the argv array is the script name to read.
anthonyafa3dfc2012-03-03 11:31:30 +0000847 */
848 GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
anthony0b46ebe2012-03-06 04:15:35 +0000849 ProcessScriptOptions(cli_wand,argc,argv,2);
anthonyafa3dfc2012-03-03 11:31:30 +0000850 }
anthony0b46ebe2012-03-06 04:15:35 +0000851 else {
anthony52bef752012-03-27 13:54:47 +0000852 /* Normal Command Line, assumes output file as last option */
anthony5216f822012-04-10 13:02:37 +0000853 ProcessCommandOptions(cli_wand,argc,argv,1);
anthony0b46ebe2012-03-06 04:15:35 +0000854 }
anthony52bef752012-03-27 13:54:47 +0000855 /* ------------- */
anthonyfa1e43d2012-02-12 12:55:45 +0000856
anthony4cb37262012-03-18 11:18:45 +0000857Magick_Command_Cleanup:
anthony5216f822012-04-10 13:02:37 +0000858 /* recover original image_info and clean up stacks
859 FUTURE: "-reset stacks" option */
anthony8226e722012-04-05 14:25:46 +0000860 while (cli_wand->image_list_stack != (Stack *)NULL)
861 CLISpecialOperator(cli_wand,")",(const char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000862 while (cli_wand->image_info_stack != (Stack *)NULL)
863 CLISpecialOperator(cli_wand,"}",(const char *)NULL);
anthony2052d272012-02-28 12:48:29 +0000864
anthony1cdc5b72012-03-03 02:31:18 +0000865 /* assert we have recovered the original structures */
anthony43f425d2012-02-26 12:58:58 +0000866 assert(cli_wand->wand.image_info == image_info);
867 assert(cli_wand->wand.exception == exception);
anthonyfa1e43d2012-02-12 12:55:45 +0000868
869 /* Handle metadata for ImageMagickObject COM object for Windows VBS */
anthonyafa3dfc2012-03-03 11:31:30 +0000870 if (metadata != (char **) NULL) {
871 const char
872 *format;
anthonyfa1e43d2012-02-12 12:55:45 +0000873
anthonyafa3dfc2012-03-03 11:31:30 +0000874 char
875 *text;
anthonyfa1e43d2012-02-12 12:55:45 +0000876
anthonyafa3dfc2012-03-03 11:31:30 +0000877 format="%w,%h,%m"; // Get this from image_info Option splaytree
anthonyfa1e43d2012-02-12 12:55:45 +0000878
anthonyafa3dfc2012-03-03 11:31:30 +0000879 text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
880 exception);
881 if (text == (char *) NULL)
882 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
883 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
884 else {
885 (void) ConcatenateString(&(*metadata),text);
886 text=DestroyString(text);
anthonyfa1e43d2012-02-12 12:55:45 +0000887 }
anthonyafa3dfc2012-03-03 11:31:30 +0000888 }
anthony4cb37262012-03-18 11:18:45 +0000889
anthony52bef752012-03-27 13:54:47 +0000890Magick_Command_Exit:
anthonyfa1e43d2012-02-12 12:55:45 +0000891 /* Destroy the special CLI Wand */
anthony43f425d2012-02-26 12:58:58 +0000892 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
893 cli_wand->wand.exception = (ExceptionInfo *)NULL;
894 cli_wand=DestroyMagickCLI(cli_wand);
anthonyfa1e43d2012-02-12 12:55:45 +0000895
anthonyc2b913e2012-03-31 00:22:33 +0000896 return(IsMagickTrue(exception->severity > ErrorException));
anthonyfa1e43d2012-02-12 12:55:45 +0000897}