blob: c21a2113999d194e8c8f86b4db70bdf830223032 [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*/
anthony2cfa1a12012-05-12 05:18:07 +000065#define MagickCommandDebug 0
anthony668f43a2012-02-20 14:55:32 +000066
anthonyf125a5e2012-04-03 13:14:42 +000067#if MagickCommandDebug >= 9
anthony8226e722012-04-05 14:25:46 +000068/*
69 Temporary Debugging Information
70 FUTURE: these should be able to be printed out using 'percent escapes'
71 Actually 'Properities' can already be output with "%[*]"
72*/
anthony24aa8822012-03-11 00:56:06 +000073static void OutputOptions(ImageInfo *image_info)
74{
75 const char
76 *option,
77 *value;
78
anthony964d28e2012-05-17 23:39:46 +000079 (void) FormatLocaleFile(stderr," Global Options:\n");
anthony24aa8822012-03-11 00:56:06 +000080 ResetImageOptionIterator(image_info);
81 while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) {
anthony964d28e2012-05-17 23:39:46 +000082 (void) FormatLocaleFile(stderr," %s: ",option);
anthony24aa8822012-03-11 00:56:06 +000083 value=GetImageOption(image_info,option);
84 if (value != (const char *) NULL)
anthony964d28e2012-05-17 23:39:46 +000085 (void) FormatLocaleFile(stderr,"%s\n",value);
anthony24aa8822012-03-11 00:56:06 +000086 }
anthony5216f822012-04-10 13:02:37 +000087 ResetImageOptionIterator(image_info);
anthony24aa8822012-03-11 00:56:06 +000088}
89
90static void OutputArtifacts(Image *image)
91{
92 const char
93 *artifact,
94 *value;
95
anthony964d28e2012-05-17 23:39:46 +000096 (void) FormatLocaleFile(stderr," Image Artifacts:\n");
anthony24aa8822012-03-11 00:56:06 +000097 ResetImageArtifactIterator(image);
98 while ((artifact=GetNextImageArtifact(image)) != (const char *) NULL ) {
anthony964d28e2012-05-17 23:39:46 +000099 (void) FormatLocaleFile(stderr," %s: ",artifact);
anthony24aa8822012-03-11 00:56:06 +0000100 value=GetImageArtifact(image,artifact);
101 if (value != (const char *) NULL)
anthony964d28e2012-05-17 23:39:46 +0000102 (void) FormatLocaleFile(stderr,"%s\n",value);
anthony24aa8822012-03-11 00:56:06 +0000103 }
104 ResetImageArtifactIterator(image);
105}
anthonyf125a5e2012-04-03 13:14:42 +0000106
107static void OutputProperties(Image *image,ExceptionInfo *exception)
108{
109 const char
110 *property,
111 *value;
112
anthony964d28e2012-05-17 23:39:46 +0000113 (void) FormatLocaleFile(stderr," Image Properity:\n");
anthonyf125a5e2012-04-03 13:14:42 +0000114 ResetImagePropertyIterator(image);
115 while ((property=GetNextImageProperty(image)) != (const char *) NULL ) {
anthony964d28e2012-05-17 23:39:46 +0000116 (void) FormatLocaleFile(stderr," %s: ",property);
anthonyf125a5e2012-04-03 13:14:42 +0000117 value=GetImageProperty(image,property,exception);
118 if (value != (const char *) NULL)
anthony964d28e2012-05-17 23:39:46 +0000119 (void) FormatLocaleFile(stderr,"%s\n",value);
anthonyf125a5e2012-04-03 13:14:42 +0000120 }
121 ResetImagePropertyIterator(image);
122}
anthony24aa8822012-03-11 00:56:06 +0000123#endif
124
anthonyfa1e43d2012-02-12 12:55:45 +0000125
126/*
127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128% %
129% %
130% %
anthony668f43a2012-02-20 14:55:32 +0000131+ 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 +0000132% %
133% %
134% %
135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136%
anthony668f43a2012-02-20 14:55:32 +0000137% ProcessScriptOptions() reads options and processes options as they are
138% found in the given file, or pipeline. The filename to open and read
anthony0b46ebe2012-03-06 04:15:35 +0000139% options is given as the 'index' argument of the argument array given.
anthonyfa1e43d2012-02-12 12:55:45 +0000140%
anthony0b46ebe2012-03-06 04:15:35 +0000141% Other arguments following index may be read by special script options
142% as settings (strings), images, or as operations to be processed in various
143% ways. How they are treated is up to the script being processed.
anthonyfa1e43d2012-02-12 12:55:45 +0000144%
anthony0b46ebe2012-03-06 04:15:35 +0000145% Note that a script not 'return' to the command line processing, nor can
146% they call (and return from) other scripts. At least not at this time.
147%
148% There are no 'ProcessOptionFlags' control flags at this time.
anthony668f43a2012-02-20 14:55:32 +0000149%
150% The format of the ProcessScriptOptions method is:
151%
anthony0b46ebe2012-03-06 04:15:35 +0000152% void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
153% int index)
anthonyfa1e43d2012-02-12 12:55:45 +0000154%
155% A description of each parameter follows:
156%
anthony43f425d2012-02-26 12:58:58 +0000157% o cli_wand: the main CLI Wand to use.
anthonyfa1e43d2012-02-12 12:55:45 +0000158%
159% o argc: the number of elements in the argument vector.
160%
161% o argv: A text array containing the command line arguments.
162%
anthony0b46ebe2012-03-06 04:15:35 +0000163% o index: offset for argc to CLI argumnet count
164%
anthonyfa1e43d2012-02-12 12:55:45 +0000165*/
anthony0b46ebe2012-03-06 04:15:35 +0000166WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
167 int index)
anthony668f43a2012-02-20 14:55:32 +0000168{
anthony1cdc5b72012-03-03 02:31:18 +0000169 ScriptTokenInfo
170 *token_info;
anthony668f43a2012-02-20 14:55:32 +0000171
anthony668f43a2012-02-20 14:55:32 +0000172 CommandOptionFlags
173 option_type;
174
anthony0b46ebe2012-03-06 04:15:35 +0000175 int
anthony1cdc5b72012-03-03 02:31:18 +0000176 count;
anthony668f43a2012-02-20 14:55:32 +0000177
anthony1cdc5b72012-03-03 02:31:18 +0000178 char
179 *option,
180 *arg1,
181 *arg2;
182
anthony0b46ebe2012-03-06 04:15:35 +0000183 assert(argc>index); /* at least one argument - script name */
184 assert(argv != (char **)NULL);
185 assert(argv[index] != (char *)NULL);
186 assert(argv[argc-1] != (char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000187 assert(cli_wand != (MagickCLI *) NULL);
188 assert(cli_wand->signature == WandSignature);
189 if (cli_wand->wand.debug != MagickFalse)
190 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthony668f43a2012-02-20 14:55:32 +0000191
anthony0b46ebe2012-03-06 04:15:35 +0000192 /* open file script or stream, and set up tokenizer */
193 token_info = AcquireScriptTokenInfo(argv[index]);
anthony8ac75b52012-03-18 11:56:44 +0000194 if (token_info == (ScriptTokenInfo *) NULL) {
anthony5216f822012-04-10 13:02:37 +0000195 CLIWandExceptionFile(OptionFatalError,"UnableToOpenScript",argv[index]);
anthony1cdc5b72012-03-03 02:31:18 +0000196 return;
197 }
anthony668f43a2012-02-20 14:55:32 +0000198
anthony0b46ebe2012-03-06 04:15:35 +0000199 /* define the error location string for use in exceptions
anthony5216f822012-04-10 13:02:37 +0000200 order of localtion format escapes: filename, line, column */
201 cli_wand->location="in \"%s\" at line %u,column %u";
anthony0b46ebe2012-03-06 04:15:35 +0000202 if ( LocaleCompare("-", argv[index]) == 0 )
203 cli_wand->filename="stdin";
204 else
205 cli_wand->filename=argv[index];
anthony668f43a2012-02-20 14:55:32 +0000206
anthony0b46ebe2012-03-06 04:15:35 +0000207 /* Process Options from Script */
208 option = arg1 = arg2 = (char*)NULL;
anthony1cdc5b72012-03-03 02:31:18 +0000209 while (1) {
anthony668f43a2012-02-20 14:55:32 +0000210
anthony0b46ebe2012-03-06 04:15:35 +0000211 { MagickBooleanType status = GetScriptToken(token_info);
212 cli_wand->line=token_info->token_line;
213 cli_wand->column=token_info->token_column;
anthony84d42792012-03-30 14:08:38 +0000214 if( IfMagickFalse(status) )
215 break; /* error or end of options */
anthony0b46ebe2012-03-06 04:15:35 +0000216 }
anthony668f43a2012-02-20 14:55:32 +0000217
anthony964d28e2012-05-17 23:39:46 +0000218 do { /* use break to loop to exception handler and loop */
anthony1cdc5b72012-03-03 02:31:18 +0000219
anthony964d28e2012-05-17 23:39:46 +0000220 /* save option details */
221 CloneString(&option,token_info->token);
222
223 /* get option, its argument count, and option type */
224 cli_wand->command = GetCommandOptionInfo(option);
225 count=cli_wand->command->type;
226 option_type=(CommandOptionFlags) cli_wand->command->flags;
anthonyf125a5e2012-04-03 13:14:42 +0000227#if 0
anthony964d28e2012-05-17 23:39:46 +0000228 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
anthony464f1c42012-04-22 08:51:01 +0000229 cli_wand->line, cli_wand->line, option, cli_wand->command->mnemonic );
anthony668f43a2012-02-20 14:55:32 +0000230#endif
anthony668f43a2012-02-20 14:55:32 +0000231
anthony964d28e2012-05-17 23:39:46 +0000232 /* handle a undefined option - image read - always for "magick-script" */
233 if ( option_type == UndefinedOptionFlag ||
234 (option_type & NonMagickOptionFlag) != 0 ) {
anthonyf125a5e2012-04-03 13:14:42 +0000235#if MagickCommandDebug >= 3
anthony964d28e2012-05-17 23:39:46 +0000236 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
237 cli_wand->line, cli_wand->line, option);
anthony668f43a2012-02-20 14:55:32 +0000238#endif
anthony964d28e2012-05-17 23:39:46 +0000239 if ( IfMagickFalse(IsCommandOption(option))) {
240 /* non-option -- treat as a image read */
241 cli_wand->command=(const OptionInfo *)NULL;
242 CLIOption(cli_wand,"-read",option);
243 break; /* next option */
244 }
245 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
246 break; /* next option */
anthony756cd0d2012-04-08 12:41:44 +0000247 }
anthony1cdc5b72012-03-03 02:31:18 +0000248
anthony964d28e2012-05-17 23:39:46 +0000249 if ( count >= 1 ) {
250 if( IfMagickFalse(GetScriptToken(token_info)) )
251 CLIWandException(OptionFatalError,"MissingArgument",option);
252 CloneString(&arg1,token_info->token);
253 }
254 else
255 CloneString(&arg1,(char *)NULL);
anthony2052d272012-02-28 12:48:29 +0000256
anthony964d28e2012-05-17 23:39:46 +0000257 if ( count >= 2 ) {
258 if( IfMagickFalse(GetScriptToken(token_info)) )
259 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
260 CloneString(&arg2,token_info->token);
261 }
262 else
263 CloneString(&arg2,(char *)NULL);
anthony668f43a2012-02-20 14:55:32 +0000264
anthony964d28e2012-05-17 23:39:46 +0000265 /*
266 Process Options
267 */
anthonyf125a5e2012-04-03 13:14:42 +0000268#if MagickCommandDebug >= 3
anthony964d28e2012-05-17 23:39:46 +0000269 (void) FormatLocaleFile(stderr,
270 "Script %u,%u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
271 cli_wand->line,cli_wand->line,option,count,option_type,arg1,arg2);
anthony668f43a2012-02-20 14:55:32 +0000272#endif
anthony964d28e2012-05-17 23:39:46 +0000273 /* Hard Depreciated Options, no code to execute - error */
274 if ( (option_type & DeprecateOptionFlag) != 0 ) {
275 CLIWandException(OptionError,"DeprecatedOptionNoCode",option);
276 break; /* next option */
anthony8226e722012-04-05 14:25:46 +0000277 }
anthony964d28e2012-05-17 23:39:46 +0000278
279 /* MagickCommandGenesis() options have no place in a magick script */
280 if ( (option_type & GenesisOptionFlag) != 0 ) {
281 CLIWandException(OptionError,"InvalidUseOfOption",option);
282 break; /* next option */
anthony8226e722012-04-05 14:25:46 +0000283 }
anthonyb1d483a2012-04-14 12:53:56 +0000284
anthony964d28e2012-05-17 23:39:46 +0000285 /* handle any special 'script' options */
286 if ( (option_type & SpecialOptionFlag) != 0 ) {
287 if ( LocaleCompare(option,"-exit") == 0 ) {
anthony4837ac22012-05-18 23:39:48 +0000288 goto loop_exit; /* break out of loop - return from script */
anthony964d28e2012-05-17 23:39:46 +0000289 }
290 if ( LocaleCompare(option,"-script") == 0 ) {
291 /* FUTURE: call new script from this script - error for now */
292 CLIWandException(OptionError,"InvalidUseOfOption",option);
293 break; /* next option */
294 }
295 /* FUTURE: handle special script-argument options here */
296 /* handle any other special operators now */
297 CLIWandException(OptionError,"InvalidUseOfOption",option);
298 break; /* next option */
299 }
anthony1cdc5b72012-03-03 02:31:18 +0000300
anthony964d28e2012-05-17 23:39:46 +0000301 /* Process non-specific Option */
302 CLIOption(cli_wand, option, arg1, arg2);
303
304 } while (0); /* break block to next option */
305
anthonyf125a5e2012-04-03 13:14:42 +0000306#if MagickCommandDebug >= 9
anthony24aa8822012-03-11 00:56:06 +0000307 OutputOptions(cli_wand->wand.image_info);
anthonyf125a5e2012-04-03 13:14:42 +0000308 if ( cli_wand->wand.images != (Image *)NULL ) {
anthony24aa8822012-03-11 00:56:06 +0000309 OutputArtifacts(cli_wand->wand.images);
anthonyf125a5e2012-04-03 13:14:42 +0000310 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
311 }
anthony24aa8822012-03-11 00:56:06 +0000312#endif
anthony964d28e2012-05-17 23:39:46 +0000313 if ( IfMagickTrue(CLICatchException(cli_wand, MagickFalse)) )
314 break; /* exit loop */
anthony1cdc5b72012-03-03 02:31:18 +0000315 }
316
anthony964d28e2012-05-17 23:39:46 +0000317 /*
318 Loop exit - check for some tokenization error
319 */
anthony4837ac22012-05-18 23:39:48 +0000320loop_exit:
anthonyf125a5e2012-04-03 13:14:42 +0000321#if MagickCommandDebug >= 3
anthony1cdc5b72012-03-03 02:31:18 +0000322 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
323#endif
324 switch( token_info->status ) {
325 case TokenStatusOK:
326 case TokenStatusEOF:
anthony8226e722012-04-05 14:25:46 +0000327 if (cli_wand->image_list_stack != (Stack *)NULL)
328 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
329 else if (cli_wand->image_info_stack != (Stack *)NULL)
330 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
anthony1cdc5b72012-03-03 02:31:18 +0000331 break;
332 case TokenStatusBadQuotes:
333 /* Ensure last token has a sane length for error report */
334 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
335 token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
336 token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
337 token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
338 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
339 }
anthonyafa3dfc2012-03-03 11:31:30 +0000340 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
341 token_info->token);
anthony1cdc5b72012-03-03 02:31:18 +0000342 break;
343 case TokenStatusMemoryFailed:
anthonyafa3dfc2012-03-03 11:31:30 +0000344 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
anthony1cdc5b72012-03-03 02:31:18 +0000345 break;
346 case TokenStatusBinary:
anthonyafa3dfc2012-03-03 11:31:30 +0000347 CLIWandException(OptionFatalError,"ScriptIsBinary","");
anthony1cdc5b72012-03-03 02:31:18 +0000348 break;
349 }
350
351 /* Clean up */
352 token_info = DestroyScriptTokenInfo(token_info);
353
354 CloneString(&option,(char *)NULL);
355 CloneString(&arg1,(char *)NULL);
356 CloneString(&arg2,(char *)NULL);
357
358 return;
anthony668f43a2012-02-20 14:55:32 +0000359}
360
361/*
362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363% %
364% %
365% %
366+ P r o c e s s C o m m a n d O p t i o n s %
367% %
368% %
369% %
370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371%
372% ProcessCommandOptions() reads and processes arguments in the given
373% command line argument array. The array does not contain the command
374% being processed, only the options.
375%
376% The 'process_flags' can be used to control and limit option processing.
377% For example, to only process one option, or how unknown and special options
378% are to be handled, and if the last argument in array is to be regarded as a
379% final image write argument (filename or special coder).
380%
381% The format of the ProcessCommandOptions method is:
382%
anthony43f425d2012-02-26 12:58:58 +0000383% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
anthony0b46ebe2012-03-06 04:15:35 +0000384% int index, ProcessOptionFlags process_flags )
anthony668f43a2012-02-20 14:55:32 +0000385%
386% A description of each parameter follows:
387%
anthony43f425d2012-02-26 12:58:58 +0000388% o cli_wand: the main CLI Wand to use.
anthony668f43a2012-02-20 14:55:32 +0000389%
390% o argc: the number of elements in the argument vector.
391%
392% o argv: A text array containing the command line arguments.
393%
anthony0ea037a2012-04-03 12:14:39 +0000394% o process_flags: What type of arguments will be processed, ignored
395% or return errors.
anthony668f43a2012-02-20 14:55:32 +0000396%
anthony0b46ebe2012-03-06 04:15:35 +0000397% o index: index in the argv array to start processing from
398%
399% The function returns the index ot the next option to be processed. This
400% is really only releven if process_flags contains a ProcessOneOptionOnly
401% flag.
402%
anthony668f43a2012-02-20 14:55:32 +0000403*/
anthony0b46ebe2012-03-06 04:15:35 +0000404WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc,
anthony5216f822012-04-10 13:02:37 +0000405 char **argv, int index )
anthonyfa1e43d2012-02-12 12:55:45 +0000406{
407 const char
408 *option,
409 *arg1,
410 *arg2;
411
anthony0b46ebe2012-03-06 04:15:35 +0000412 int
anthonyfa1e43d2012-02-12 12:55:45 +0000413 i,
anthony668f43a2012-02-20 14:55:32 +0000414 end,
anthonyfa1e43d2012-02-12 12:55:45 +0000415 count;
416
417 CommandOptionFlags
anthony686b1a32012-02-15 14:50:53 +0000418 option_type;
anthonyfa1e43d2012-02-12 12:55:45 +0000419
anthony0b46ebe2012-03-06 04:15:35 +0000420 assert(argc>=index); /* you may have no arguments left! */
421 assert(argv != (char **)NULL);
422 assert(argv[index] != (char *)NULL);
423 assert(argv[argc-1] != (char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000424 assert(cli_wand != (MagickCLI *) NULL);
425 assert(cli_wand->signature == WandSignature);
426 if (cli_wand->wand.debug != MagickFalse)
427 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthonyfa1e43d2012-02-12 12:55:45 +0000428
anthony92c93bd2012-03-19 14:02:47 +0000429 /* define the error location string for use in exceptions
anthony5216f822012-04-10 13:02:37 +0000430 order of localtion format escapes: filename, line, column */
431 cli_wand->location="at %s argument %u";
anthonyafa3dfc2012-03-03 11:31:30 +0000432 cli_wand->filename="CLI";
433
anthony668f43a2012-02-20 14:55:32 +0000434 end = argc;
anthony964d28e2012-05-17 23:39:46 +0000435 if ( (cli_wand->process_flags & ProcessImplictWrite) != 0 )
anthony5216f822012-04-10 13:02:37 +0000436 end--; /* the last arument is an implied write, do not process directly */
anthony0b46ebe2012-03-06 04:15:35 +0000437
438 for (i=index; i < end; i += count +1) {
anthonyafa3dfc2012-03-03 11:31:30 +0000439 /* Finished processing one option? */
anthony5216f822012-04-10 13:02:37 +0000440 if ( (cli_wand->process_flags & ProcessOneOptionOnly) != 0 && i != index )
anthony0b46ebe2012-03-06 04:15:35 +0000441 return(i);
anthony668f43a2012-02-20 14:55:32 +0000442
anthony964d28e2012-05-17 23:39:46 +0000443 do { /* use break to loop to exception handler and loop */
anthonyfa1e43d2012-02-12 12:55:45 +0000444
anthony964d28e2012-05-17 23:39:46 +0000445 option=argv[i];
446 cli_wand->line=i; /* note the argument for this option */
447
448 /* get option, its argument count, and option type */
449 cli_wand->command = GetCommandOptionInfo(argv[i]);
450 count=cli_wand->command->type;
451 option_type=(CommandOptionFlags) cli_wand->command->flags;
anthonyf125a5e2012-04-03 13:14:42 +0000452#if 0
anthony964d28e2012-05-17 23:39:46 +0000453 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
454 i, argv[i], cli_wand->command->mnemonic );
anthony686b1a32012-02-15 14:50:53 +0000455#endif
anthonyfa1e43d2012-02-12 12:55:45 +0000456
anthony964d28e2012-05-17 23:39:46 +0000457 if ( option_type == UndefinedOptionFlag ||
458 (option_type & NonMagickOptionFlag) != 0 ) {
anthonyf125a5e2012-04-03 13:14:42 +0000459#if MagickCommandDebug >= 3
anthony964d28e2012-05-17 23:39:46 +0000460 (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option);
anthonyfa1e43d2012-02-12 12:55:45 +0000461#endif
anthony964d28e2012-05-17 23:39:46 +0000462 if ( IfMagickFalse(IsCommandOption(option)) ) {
463 if ( (cli_wand->process_flags & ProcessImplictRead) != 0 ) {
464 /* non-option -- treat as a image read */
465 cli_wand->command=(const OptionInfo *)NULL;
466 CLIOption(cli_wand,"-read",option);
467 break; /* next option */
468 }
anthony464f1c42012-04-22 08:51:01 +0000469 }
anthony964d28e2012-05-17 23:39:46 +0000470 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
471 break; /* next option */
anthony756cd0d2012-04-08 12:41:44 +0000472 }
anthonyfa1e43d2012-02-12 12:55:45 +0000473
anthony964d28e2012-05-17 23:39:46 +0000474 if ( ((option_type & SpecialOptionFlag) != 0 ) &&
475 ((cli_wand->process_flags & ProcessScriptOption) != 0) &&
476 (LocaleCompare(option,"-script") == 0) ) {
477 /* Call Script from CLI, with a filename as a zeroth argument.
478 NOTE: -script may need to use the 'implict write filename' argument
479 so it must be handled specially to prevent a 'missing argument' error.
480 */
481 if ( (i+count) >= argc )
482 CLIWandException(OptionFatalError,"MissingArgument",option);
483 ProcessScriptOptions(cli_wand,argc,argv,i+1);
484 return(argc); /* Script does not return to CLI -- Yet */
485 /* FUTURE: when it does, their may be no write arg! */
486 }
487
488 if ((i+count) >= end ) {
anthony464f1c42012-04-22 08:51:01 +0000489 CLIWandException(OptionFatalError,"MissingArgument",option);
anthony964d28e2012-05-17 23:39:46 +0000490 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
491 return(end);
492 break; /* next option - not that their is any! */
493 }
anthony464f1c42012-04-22 08:51:01 +0000494
anthony964d28e2012-05-17 23:39:46 +0000495 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL;
496 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL;
anthonyafa3dfc2012-03-03 11:31:30 +0000497
anthony964d28e2012-05-17 23:39:46 +0000498 /*
499 Process Known Options
500 */
anthonyf125a5e2012-04-03 13:14:42 +0000501#if MagickCommandDebug >= 3
anthony964d28e2012-05-17 23:39:46 +0000502 (void) FormatLocaleFile(stderr,
503 "CLI %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
504 i,option,count,option_type,arg1,arg2);
anthonyafa3dfc2012-03-03 11:31:30 +0000505#endif
anthonyb1d483a2012-04-14 12:53:56 +0000506
anthony964d28e2012-05-17 23:39:46 +0000507 /* ignore 'genesis options' in command line args */
508 if ( (option_type & GenesisOptionFlag) != 0 )
509 break; /* next option */
anthony8226e722012-04-05 14:25:46 +0000510
anthony964d28e2012-05-17 23:39:46 +0000511 /* Handle any special options for CLI (-script handled above) */
512 if ( (option_type & SpecialOptionFlag) != 0 ) {
513 if ( (cli_wand->process_flags & ProcessExitOption) != 0
514 && LocaleCompare(option,"-exit") == 0 )
515 return(i+count);
516 break; /* next option */
517 }
anthonyb1d483a2012-04-14 12:53:56 +0000518
anthony964d28e2012-05-17 23:39:46 +0000519 /* Process standard image option */
520 CLIOption(cli_wand, option, arg1, arg2);
anthonyafa3dfc2012-03-03 11:31:30 +0000521
anthony964d28e2012-05-17 23:39:46 +0000522 } while (0); /* break block to next option */
523
anthonyf125a5e2012-04-03 13:14:42 +0000524#if MagickCommandDebug >= 9
anthony24aa8822012-03-11 00:56:06 +0000525 OutputOptions(cli_wand->wand.image_info);
anthonyf125a5e2012-04-03 13:14:42 +0000526 if ( cli_wand->wand.images != (Image *)NULL ) {
anthony24aa8822012-03-11 00:56:06 +0000527 OutputArtifacts(cli_wand->wand.images);
anthonyf125a5e2012-04-03 13:14:42 +0000528 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
529 }
anthony24aa8822012-03-11 00:56:06 +0000530#endif
anthonyafa3dfc2012-03-03 11:31:30 +0000531 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
anthony0b46ebe2012-03-06 04:15:35 +0000532 return(i+count);
anthonyafa3dfc2012-03-03 11:31:30 +0000533 }
anthony0b46ebe2012-03-06 04:15:35 +0000534 assert(i==end);
anthony2052d272012-02-28 12:48:29 +0000535
anthony964d28e2012-05-17 23:39:46 +0000536 if ( (cli_wand->process_flags & ProcessImplictWrite) == 0 )
anthony5216f822012-04-10 13:02:37 +0000537 return(end); /* no implied write -- just return to caller */
anthony0b46ebe2012-03-06 04:15:35 +0000538
anthony5216f822012-04-10 13:02:37 +0000539 assert(end==argc-1); /* end should not include last argument */
anthony668f43a2012-02-20 14:55:32 +0000540
541 /*
anthony43f425d2012-02-26 12:58:58 +0000542 Implicit Write of images to final CLI argument
anthony668f43a2012-02-20 14:55:32 +0000543 */
544 option=argv[i];
anthony799889a2012-03-11 11:00:32 +0000545 cli_wand->line=i;
anthony686b1a32012-02-15 14:50:53 +0000546
anthony964d28e2012-05-17 23:39:46 +0000547 /* check that stacks are empty - or cause exception */
548 if (cli_wand->image_list_stack != (Stack *)NULL)
549 CLIWandException(OptionError,"UnbalancedParenthesis", "(end of cli)");
550 else if (cli_wand->image_info_stack != (Stack *)NULL)
551 CLIWandException(OptionError,"UnbalancedBraces", "(end of cli)");
552 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
553 return(argc);
554
anthonyf125a5e2012-04-03 13:14:42 +0000555#if MagickCommandDebug >= 3
556 (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option );
anthonyfa1e43d2012-02-12 12:55:45 +0000557#endif
558
anthony964d28e2012-05-17 23:39:46 +0000559 /* Valid 'do no write' replacement option (instead of "null:") */
anthonyfa1e43d2012-02-12 12:55:45 +0000560 if (LocaleCompare(option,"-exit") == 0 )
anthony0b46ebe2012-03-06 04:15:35 +0000561 return(argc); /* just exit, no image write */
anthonyfa1e43d2012-02-12 12:55:45 +0000562
anthonye5b39652012-04-21 05:37:29 +0000563 /* If filename looks like an option,
564 Or the common 'end of line' error of a single space.
565 -- produce an error */
566 if (IfMagickTrue(IsCommandOption(option)) ||
567 (option[0] == ' ' && option[1] == '\0') ) {
anthony0b46ebe2012-03-06 04:15:35 +0000568 CLIWandException(OptionError,"MissingOutputFilename",option);
569 return(argc);
570 }
anthonyfa1e43d2012-02-12 12:55:45 +0000571
anthony464f1c42012-04-22 08:51:01 +0000572 cli_wand->command=(const OptionInfo *)NULL;
573 CLIOption(cli_wand,"-write",option);
anthony0b46ebe2012-03-06 04:15:35 +0000574 return(argc);
anthonyfa1e43d2012-02-12 12:55:45 +0000575}
576
577/*
578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
579% %
580% %
581% %
582+ M a g i c k I m a g e C o m m a n d %
583% %
584% %
585% %
586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
587%
anthony668f43a2012-02-20 14:55:32 +0000588% MagickImageCommand() Handle special use CLI arguments and prepare a
anthony43f425d2012-02-26 12:58:58 +0000589% CLI MagickCLI to process the command line or directly specified script.
anthony668f43a2012-02-20 14:55:32 +0000590%
591% This is essentualy interface function between the MagickCore library
anthony43f425d2012-02-26 12:58:58 +0000592% initialization function MagickCommandGenesis(), and the option MagickCLI
anthony668f43a2012-02-20 14:55:32 +0000593% processing functions ProcessCommandOptions() or ProcessScriptOptions()
anthonyfa1e43d2012-02-12 12:55:45 +0000594%
595% The format of the MagickImageCommand method is:
596%
597% MagickBooleanType MagickImageCommand(ImageInfo *image_info,
598% int argc, char **argv, char **metadata, ExceptionInfo *exception)
599%
600% A description of each parameter follows:
601%
602% o image_info: the starting image_info structure
603% (for compatibilty with MagickCommandGenisis())
604%
605% o argc: the number of elements in the argument vector.
606%
607% o argv: A text array containing the command line arguments.
608%
anthony0ea037a2012-04-03 12:14:39 +0000609% o metadata: any metadata (for VBS) is returned here.
anthonyfa1e43d2012-02-12 12:55:45 +0000610% (for compatibilty with MagickCommandGenisis())
611%
612% o exception: return any errors or warnings in this structure.
613%
614*/
615
anthony40b60152012-04-04 06:13:37 +0000616static void MagickUsage(MagickBooleanType verbose)
anthonyfa1e43d2012-02-12 12:55:45 +0000617{
anthonye5fcd362012-04-09 04:02:09 +0000618 const char
619 *name;
620
621 size_t
622 len;
623
624 name=GetClientName();
625 len=strlen(name);
626
anthonyd22bf402012-04-10 01:32:03 +0000627 if (len>=7 && LocaleCompare("convert",name+len-7) == 0) {
anthonye5fcd362012-04-09 04:02:09 +0000628 /* convert usage */
629 (void) FormatLocaleFile(stdout,
630 "Usage: %s [{option}|{image}...] {output_image}\n",name);
631 (void) FormatLocaleFile(stdout,
anthonyd22bf402012-04-10 01:32:03 +0000632 " %s -help|-version|-usage|-list {option}\n\n",name);
633 return;
634 }
635 else if (len>=6 && LocaleCompare("script",name+len-6) == 0) {
636 /* magick-script usage */
637 (void) FormatLocaleFile(stdout,
638 "Usage: %s {filename} [{script_args}...]\n",name);
anthonye5fcd362012-04-09 04:02:09 +0000639 }
640 else {
641 /* magick usage */
642 (void) FormatLocaleFile(stdout,
643 "Usage: %s [{option}|{image}...] {output_image}\n",name);
644 (void) FormatLocaleFile(stdout,
anthony40b60152012-04-04 06:13:37 +0000645 " %s [{option}|{image}...] -script {filename} [{script_args}...]\n",
anthonye5fcd362012-04-09 04:02:09 +0000646 name);
anthonye5fcd362012-04-09 04:02:09 +0000647 }
anthonyd22bf402012-04-10 01:32:03 +0000648 (void) FormatLocaleFile(stdout,
649 " %s -help|-version|-usage|-list {option}\n\n",name);
anthony40b60152012-04-04 06:13:37 +0000650
651 if (IfMagickFalse(verbose))
652 return;
653
anthonyd22bf402012-04-10 01:32:03 +0000654 (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 +0000655 "All options are performed in a strict 'as you see them' order\n",
656 "You must read-in images before you can operate on them.\n",
657 "\n",
658 "Magick Script files can use any of the following forms...\n",
659 " #!/path/to/magick -script\n",
660 "or\n",
661 " #!/bin/sh\n",
662 " :; exec magick -script \"$0\" \"$@\"; exit 10\n",
663 " # Magick script from here...\n",
664 "or\n",
665 " #!/usr/bin/env magick-script\n",
666 "The latter two forms do not require the path to the command hard coded.\n",
667 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
668 "\n",
669 "For more information on usage, options, examples, and techniques\n",
670 "see the ImageMagick website at ", MagickAuthoritativeURL);
671
672 return;
anthonyfa1e43d2012-02-12 12:55:45 +0000673}
674
675/*
676 Concatanate given file arguments to the given output argument.
677 Used for a special -concatenate option used for specific 'delegates'.
678 The option is not formally documented.
679
680 magick -concatenate files... output
681
682 This is much like the UNIX "cat" command, but for both UNIX and Windows,
683 however the last argument provides the output filename.
684*/
anthonyfa1e43d2012-02-12 12:55:45 +0000685static MagickBooleanType ConcatenateImages(int argc,char **argv,
anthony5216f822012-04-10 13:02:37 +0000686 ExceptionInfo *exception )
anthonyfa1e43d2012-02-12 12:55:45 +0000687{
688 FILE
689 *input,
690 *output;
691
692 int
693 c;
694
695 register ssize_t
696 i;
697
anthony451f9092012-05-11 01:56:24 +0000698 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
anthony3b2e6072012-05-03 13:00:39 +0000699 ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
700 GetExceptionMessage(errno));
701
anthonyfa1e43d2012-02-12 12:55:45 +0000702 output=fopen_utf8(argv[argc-1],"wb");
anthonyafa3dfc2012-03-03 11:31:30 +0000703 if (output == (FILE *) NULL) {
anthony5216f822012-04-10 13:02:37 +0000704 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[argc-1]);
anthonyafa3dfc2012-03-03 11:31:30 +0000705 return(MagickFalse);
706 }
707 for (i=2; i < (ssize_t) (argc-1); i++) {
anthony3b2e6072012-05-03 13:00:39 +0000708#if 0
709 fprintf(stderr, "DEBUG: Concatenate Image: \"%s\"\n", argv[i]);
710#endif
anthonyfa1e43d2012-02-12 12:55:45 +0000711 input=fopen_utf8(argv[i],"rb");
anthony3b2e6072012-05-03 13:00:39 +0000712 if (input == (FILE *) NULL) {
cristy6a0d3612012-05-02 15:39:55 +0000713 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
714 continue;
715 }
anthonyfa1e43d2012-02-12 12:55:45 +0000716 for (c=fgetc(input); c != EOF; c=fgetc(input))
717 (void) fputc((char) c,output);
718 (void) fclose(input);
719 (void) remove_utf8(argv[i]);
720 }
721 (void) fclose(output);
722 return(MagickTrue);
723}
724
725WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
726 int argc,char **argv,char **metadata,ExceptionInfo *exception)
727{
anthony43f425d2012-02-26 12:58:58 +0000728 MagickCLI
729 *cli_wand;
anthonyfa1e43d2012-02-12 12:55:45 +0000730
anthonye5fcd362012-04-09 04:02:09 +0000731 size_t
732 len;
733
anthony4cb37262012-03-18 11:18:45 +0000734 /* For specific OS command line requirements */
735 ReadCommandlLine(argc,&argv);
736
anthony668f43a2012-02-20 14:55:32 +0000737 /* Initialize special "CLI Wand" to hold images and settings (empty) */
anthony43f425d2012-02-26 12:58:58 +0000738 cli_wand=AcquireMagickCLI(image_info,exception);
anthony8226e722012-04-05 14:25:46 +0000739 cli_wand->line=1;
anthonyfa1e43d2012-02-12 12:55:45 +0000740
anthonyeff71f52012-03-29 12:59:09 +0000741 GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
anthonye5fcd362012-04-09 04:02:09 +0000742 SetClientName(cli_wand->wand.name);
anthonyeff71f52012-03-29 12:59:09 +0000743 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent);
744
anthonye5fcd362012-04-09 04:02:09 +0000745 len=strlen(argv[0]); /* precaution */
746
anthonyeff71f52012-03-29 12:59:09 +0000747 /* "convert" command - give a "depreciation" warning" */
anthonye5fcd362012-04-09 04:02:09 +0000748 if (len>=7 && LocaleCompare("convert",argv[0]+len-7) == 0) {
anthony5216f822012-04-10 13:02:37 +0000749 cli_wand->process_flags = ConvertCommandOptionFlags;
anthony0ea037a2012-04-03 12:14:39 +0000750 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n",
751 "The convert is depreciated in IMv7, use \"magick\"\n");*/
anthonyeff71f52012-03-29 12:59:09 +0000752 }
anthonyeff71f52012-03-29 12:59:09 +0000753
anthony8226e722012-04-05 14:25:46 +0000754 /* Special Case: If command name ends with "script" implied "-script" */
anthonye5fcd362012-04-09 04:02:09 +0000755 if (len>=6 && LocaleCompare("script",argv[0]+len-6) == 0) {
anthonyd22bf402012-04-10 01:32:03 +0000756 if (argc >= 2 && ( (*(argv[1]) != '-') || (strlen(argv[1]) == 1) )) {
anthonye5fcd362012-04-09 04:02:09 +0000757 GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
758 ProcessScriptOptions(cli_wand,argc,argv,1);
759 goto Magick_Command_Cleanup;
760 }
anthony52bef752012-03-27 13:54:47 +0000761 }
762
763 /* Special Case: Version Information and Abort */
764 if (argc == 2) {
anthony464f1c42012-04-22 08:51:01 +0000765 if (LocaleCompare("-version",argv[1]) == 0) { /* just version */
766 CLIOption(cli_wand, "-version");
anthony52bef752012-03-27 13:54:47 +0000767 goto Magick_Command_Exit;
768 }
anthony5216f822012-04-10 13:02:37 +0000769 if ((LocaleCompare("-help",argv[1]) == 0) || /* GNU standard option */
anthony464f1c42012-04-22 08:51:01 +0000770 (LocaleCompare("--help",argv[1]) == 0) ) { /* just a brief summary */
anthony40b60152012-04-04 06:13:37 +0000771 MagickUsage(MagickFalse);
772 goto Magick_Command_Exit;
773 }
anthony464f1c42012-04-22 08:51:01 +0000774 if (LocaleCompare("-usage",argv[1]) == 0) { /* both version & usage */
anthonyca487682012-04-27 07:59:27 +0000775 CLIOption(cli_wand, "-version" );
anthony40b60152012-04-04 06:13:37 +0000776 MagickUsage(MagickTrue);
777 goto Magick_Command_Exit;
778 }
anthony52bef752012-03-27 13:54:47 +0000779 }
780
781 /* not enough arguments -- including -help */
782 if (argc < 3) {
anthony40b60152012-04-04 06:13:37 +0000783 (void) FormatLocaleFile(stderr,
784 "Error: Invalid argument or not enough arguments\n\n");
785 MagickUsage(MagickFalse);
anthony52bef752012-03-27 13:54:47 +0000786 goto Magick_Command_Exit;
787 }
788
anthony0ea037a2012-04-03 12:14:39 +0000789 /* Special "concatenate option (hidden) for delegate usage */
790 if (LocaleCompare("-concatenate",argv[1]) == 0) {
791 ConcatenateImages(argc,argv,exception);
792 goto Magick_Command_Exit;
793 }
794
anthony06762232012-04-29 11:45:40 +0000795 /* List Information and Abort */
796 if (argc == 3 && LocaleCompare("-list",argv[1]) == 0) {
797 CLIOption(cli_wand, argv[1], argv[2]);
798 goto Magick_Command_Exit;
799 }
800
anthony52bef752012-03-27 13:54:47 +0000801 /* ------------- */
802 /* The Main Call */
803
804 if (LocaleCompare("-script",argv[1]) == 0) {
anthonyafa3dfc2012-03-03 11:31:30 +0000805 /* Start processing directly from script, no pre-script options
anthony0b46ebe2012-03-06 04:15:35 +0000806 Replace wand command name with script name
807 First argument in the argv array is the script name to read.
anthonyafa3dfc2012-03-03 11:31:30 +0000808 */
809 GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
anthony0b46ebe2012-03-06 04:15:35 +0000810 ProcessScriptOptions(cli_wand,argc,argv,2);
anthonyafa3dfc2012-03-03 11:31:30 +0000811 }
anthony0b46ebe2012-03-06 04:15:35 +0000812 else {
anthony52bef752012-03-27 13:54:47 +0000813 /* Normal Command Line, assumes output file as last option */
anthony5216f822012-04-10 13:02:37 +0000814 ProcessCommandOptions(cli_wand,argc,argv,1);
anthony0b46ebe2012-03-06 04:15:35 +0000815 }
anthony52bef752012-03-27 13:54:47 +0000816 /* ------------- */
anthonyfa1e43d2012-02-12 12:55:45 +0000817
anthony4cb37262012-03-18 11:18:45 +0000818Magick_Command_Cleanup:
anthony5216f822012-04-10 13:02:37 +0000819 /* recover original image_info and clean up stacks
820 FUTURE: "-reset stacks" option */
anthony8226e722012-04-05 14:25:46 +0000821 while (cli_wand->image_list_stack != (Stack *)NULL)
anthony464f1c42012-04-22 08:51:01 +0000822 CLIOption(cli_wand,")");
anthony43f425d2012-02-26 12:58:58 +0000823 while (cli_wand->image_info_stack != (Stack *)NULL)
anthony464f1c42012-04-22 08:51:01 +0000824 CLIOption(cli_wand,"}");
anthony2052d272012-02-28 12:48:29 +0000825
anthony1cdc5b72012-03-03 02:31:18 +0000826 /* assert we have recovered the original structures */
anthony43f425d2012-02-26 12:58:58 +0000827 assert(cli_wand->wand.image_info == image_info);
828 assert(cli_wand->wand.exception == exception);
anthonyfa1e43d2012-02-12 12:55:45 +0000829
830 /* Handle metadata for ImageMagickObject COM object for Windows VBS */
anthonyafa3dfc2012-03-03 11:31:30 +0000831 if (metadata != (char **) NULL) {
832 const char
833 *format;
anthonyfa1e43d2012-02-12 12:55:45 +0000834
anthonyafa3dfc2012-03-03 11:31:30 +0000835 char
836 *text;
anthonyfa1e43d2012-02-12 12:55:45 +0000837
anthonyafa3dfc2012-03-03 11:31:30 +0000838 format="%w,%h,%m"; // Get this from image_info Option splaytree
anthonyfa1e43d2012-02-12 12:55:45 +0000839
anthonyafa3dfc2012-03-03 11:31:30 +0000840 text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
841 exception);
842 if (text == (char *) NULL)
843 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
anthonye5b39652012-04-21 05:37:29 +0000844 "MemoryAllocationFailed","'%s'", GetExceptionMessage(errno));
anthonyafa3dfc2012-03-03 11:31:30 +0000845 else {
846 (void) ConcatenateString(&(*metadata),text);
847 text=DestroyString(text);
anthonyfa1e43d2012-02-12 12:55:45 +0000848 }
anthonyafa3dfc2012-03-03 11:31:30 +0000849 }
anthony4cb37262012-03-18 11:18:45 +0000850
anthony52bef752012-03-27 13:54:47 +0000851Magick_Command_Exit:
anthonyfa1e43d2012-02-12 12:55:45 +0000852 /* Destroy the special CLI Wand */
anthony43f425d2012-02-26 12:58:58 +0000853 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
854 cli_wand->wand.exception = (ExceptionInfo *)NULL;
855 cli_wand=DestroyMagickCLI(cli_wand);
anthonyfa1e43d2012-02-12 12:55:45 +0000856
anthonyc2b913e2012-03-31 00:22:33 +0000857 return(IsMagickTrue(exception->severity > ErrorException));
anthonyfa1e43d2012-02-12 12:55:45 +0000858}