blob: 21a3bea5dd6736956071c47c14289f75da8f2006 [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"
anthony43f425d2012-02-26 12:58:58 +000052#include "MagickWand/operation.h"
anthony2052d272012-02-28 12:48:29 +000053#include "MagickWand/operation-private.h"
54#include "MagickWand/magick-cli.h"
anthony1cdc5b72012-03-03 02:31:18 +000055#include "MagickWand/script-token.h"
anthonyfa1e43d2012-02-12 12:55:45 +000056#include "MagickCore/utility-private.h"
anthony668f43a2012-02-20 14:55:32 +000057#include "MagickCore/version.h"
58
anthony43f425d2012-02-26 12:58:58 +000059/* verbose debugging,
anthonyf125a5e2012-04-03 13:14:42 +000060 3 - option type details
61 9 - output options/artifacts/propertys
anthony24aa8822012-03-11 00:56:06 +000062*/
anthonyce51b4a2012-04-06 02:32:25 +000063#define MagickCommandDebug 0
anthony668f43a2012-02-20 14:55:32 +000064
anthony1cdc5b72012-03-03 02:31:18 +000065#define ThrowFileException(exception,severity,tag,context) \
anthony668f43a2012-02-20 14:55:32 +000066{ \
anthonyafa3dfc2012-03-03 11:31:30 +000067 char \
68 *message; \
69 \
70 message=GetExceptionMessage(errno); \
71 (void) ThrowMagickException(exception,GetMagickModule(),severity, \
anthony8226e722012-04-05 14:25:46 +000072 tag == (const char *) NULL ? "unknown" : tag,"'%s': %s",context,message); \
anthonyafa3dfc2012-03-03 11:31:30 +000073 message=DestroyString(message); \
anthony668f43a2012-02-20 14:55:32 +000074}
anthony24aa8822012-03-11 00:56:06 +000075
anthonyf125a5e2012-04-03 13:14:42 +000076#if MagickCommandDebug >= 9
anthony8226e722012-04-05 14:25:46 +000077/*
78 Temporary Debugging Information
79 FUTURE: these should be able to be printed out using 'percent escapes'
80 Actually 'Properities' can already be output with "%[*]"
81*/
anthony24aa8822012-03-11 00:56:06 +000082static void OutputOptions(ImageInfo *image_info)
83{
84 const char
85 *option,
86 *value;
87
anthonyf125a5e2012-04-03 13:14:42 +000088 (void) FormatLocaleFile(stdout," Global Options:\n");
anthony24aa8822012-03-11 00:56:06 +000089 ResetImageOptionIterator(image_info);
90 while ((option=GetNextImageOption(image_info)) != (const char *) NULL ) {
91 (void) FormatLocaleFile(stdout," %s: ",option);
92 value=GetImageOption(image_info,option);
93 if (value != (const char *) NULL)
94 (void) FormatLocaleFile(stdout,"%s\n",value);
95 }
96 ResetImageOptionIterator(image_info);
97}
98
99static void OutputArtifacts(Image *image)
100{
101 const char
102 *artifact,
103 *value;
104
105 (void) FormatLocaleFile(stdout," Image Artifacts:\n");
106 ResetImageArtifactIterator(image);
107 while ((artifact=GetNextImageArtifact(image)) != (const char *) NULL ) {
108 (void) FormatLocaleFile(stdout," %s: ",artifact);
109 value=GetImageArtifact(image,artifact);
110 if (value != (const char *) NULL)
111 (void) FormatLocaleFile(stdout,"%s\n",value);
112 }
113 ResetImageArtifactIterator(image);
114}
anthonyf125a5e2012-04-03 13:14:42 +0000115
116static void OutputProperties(Image *image,ExceptionInfo *exception)
117{
118 const char
119 *property,
120 *value;
121
122 (void) FormatLocaleFile(stdout," Image Properity:\n");
123 ResetImagePropertyIterator(image);
124 while ((property=GetNextImageProperty(image)) != (const char *) NULL ) {
125 (void) FormatLocaleFile(stdout," %s: ",property);
126 value=GetImageProperty(image,property,exception);
127 if (value != (const char *) NULL)
128 (void) FormatLocaleFile(stdout,"%s\n",value);
129 }
130 ResetImagePropertyIterator(image);
131}
anthony24aa8822012-03-11 00:56:06 +0000132#endif
133
anthonyfa1e43d2012-02-12 12:55:45 +0000134
135/*
136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137% %
138% %
139% %
anthony668f43a2012-02-20 14:55:32 +0000140+ 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 +0000141% %
142% %
143% %
144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145%
anthony668f43a2012-02-20 14:55:32 +0000146% ProcessScriptOptions() reads options and processes options as they are
147% found in the given file, or pipeline. The filename to open and read
anthony0b46ebe2012-03-06 04:15:35 +0000148% options is given as the 'index' argument of the argument array given.
anthonyfa1e43d2012-02-12 12:55:45 +0000149%
anthony0b46ebe2012-03-06 04:15:35 +0000150% Other arguments following index may be read by special script options
151% as settings (strings), images, or as operations to be processed in various
152% ways. How they are treated is up to the script being processed.
anthonyfa1e43d2012-02-12 12:55:45 +0000153%
anthony0b46ebe2012-03-06 04:15:35 +0000154% Note that a script not 'return' to the command line processing, nor can
155% they call (and return from) other scripts. At least not at this time.
156%
157% There are no 'ProcessOptionFlags' control flags at this time.
anthony668f43a2012-02-20 14:55:32 +0000158%
159% The format of the ProcessScriptOptions method is:
160%
anthony0b46ebe2012-03-06 04:15:35 +0000161% void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
162% int index)
anthonyfa1e43d2012-02-12 12:55:45 +0000163%
164% A description of each parameter follows:
165%
anthony43f425d2012-02-26 12:58:58 +0000166% o cli_wand: the main CLI Wand to use.
anthonyfa1e43d2012-02-12 12:55:45 +0000167%
168% o argc: the number of elements in the argument vector.
169%
170% o argv: A text array containing the command line arguments.
171%
anthony0b46ebe2012-03-06 04:15:35 +0000172% o index: offset for argc to CLI argumnet count
173%
anthonyfa1e43d2012-02-12 12:55:45 +0000174*/
anthony0b46ebe2012-03-06 04:15:35 +0000175WandExport void ProcessScriptOptions(MagickCLI *cli_wand,int argc,char **argv,
176 int index)
anthony668f43a2012-02-20 14:55:32 +0000177{
anthony1cdc5b72012-03-03 02:31:18 +0000178 ScriptTokenInfo
179 *token_info;
anthony668f43a2012-02-20 14:55:32 +0000180
anthony668f43a2012-02-20 14:55:32 +0000181 CommandOptionFlags
182 option_type;
183
anthony0b46ebe2012-03-06 04:15:35 +0000184 int
anthony1cdc5b72012-03-03 02:31:18 +0000185 count;
anthony668f43a2012-02-20 14:55:32 +0000186
anthony1cdc5b72012-03-03 02:31:18 +0000187 char
188 *option,
189 *arg1,
190 *arg2;
191
anthony0b46ebe2012-03-06 04:15:35 +0000192 assert(argc>index); /* at least one argument - script name */
193 assert(argv != (char **)NULL);
194 assert(argv[index] != (char *)NULL);
195 assert(argv[argc-1] != (char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000196 assert(cli_wand != (MagickCLI *) NULL);
197 assert(cli_wand->signature == WandSignature);
198 if (cli_wand->wand.debug != MagickFalse)
199 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthony668f43a2012-02-20 14:55:32 +0000200
anthony0b46ebe2012-03-06 04:15:35 +0000201 /* open file script or stream, and set up tokenizer */
202 token_info = AcquireScriptTokenInfo(argv[index]);
anthony8ac75b52012-03-18 11:56:44 +0000203 if (token_info == (ScriptTokenInfo *) NULL) {
anthonyafa3dfc2012-03-03 11:31:30 +0000204 ThrowFileException(cli_wand->wand.exception,OptionFatalError,
anthony0b46ebe2012-03-06 04:15:35 +0000205 "UnableToOpenScript",argv[index]);
anthony1cdc5b72012-03-03 02:31:18 +0000206 return;
207 }
anthony668f43a2012-02-20 14:55:32 +0000208
anthony0b46ebe2012-03-06 04:15:35 +0000209 /* define the error location string for use in exceptions
anthony92c93bd2012-03-19 14:02:47 +0000210 order of input escapes: option, (arg), filename, line, column */
anthony0b46ebe2012-03-06 04:15:35 +0000211 cli_wand->location="'%s' in \"%s\" line %u column %u";
anthony92c93bd2012-03-19 14:02:47 +0000212 cli_wand->location2="'%s' '%s' in \"%s\" line %u column %u";
anthony0b46ebe2012-03-06 04:15:35 +0000213 if ( LocaleCompare("-", argv[index]) == 0 )
214 cli_wand->filename="stdin";
215 else
216 cli_wand->filename=argv[index];
anthony668f43a2012-02-20 14:55:32 +0000217
anthony0b46ebe2012-03-06 04:15:35 +0000218 /* Process Options from Script */
219 option = arg1 = arg2 = (char*)NULL;
anthony1cdc5b72012-03-03 02:31:18 +0000220 while (1) {
anthony668f43a2012-02-20 14:55:32 +0000221
anthony1cdc5b72012-03-03 02:31:18 +0000222 /* Get a option */
anthony0b46ebe2012-03-06 04:15:35 +0000223 { MagickBooleanType status = GetScriptToken(token_info);
224 cli_wand->line=token_info->token_line;
225 cli_wand->column=token_info->token_column;
anthony84d42792012-03-30 14:08:38 +0000226 if( IfMagickFalse(status) )
227 break; /* error or end of options */
anthony0b46ebe2012-03-06 04:15:35 +0000228 }
anthony668f43a2012-02-20 14:55:32 +0000229
anthony1cdc5b72012-03-03 02:31:18 +0000230 /* save option details */
231 CloneString(&option,token_info->token);
anthony1cdc5b72012-03-03 02:31:18 +0000232
233 { /* get option type and argument count */
234 const OptionInfo *option_info = GetCommandOptionInfo(option);
235 count=option_info->type;
cristyaa2c16c2012-03-25 22:21:35 +0000236 option_type=(CommandOptionFlags) option_info->flags;
anthonyf125a5e2012-04-03 13:14:42 +0000237#if 0
anthony0b46ebe2012-03-06 04:15:35 +0000238 (void) FormatLocaleFile(stderr, "Script: %u,%u: \"%s\" matched \"%s\"\n",
239 cli_wand->line, cli_wand->line, option, option_info->mnemonic );
anthony668f43a2012-02-20 14:55:32 +0000240#endif
anthony1cdc5b72012-03-03 02:31:18 +0000241 }
anthony668f43a2012-02-20 14:55:32 +0000242
anthony0b46ebe2012-03-06 04:15:35 +0000243 /* handle a undefined option - image read? */
anthony1cdc5b72012-03-03 02:31:18 +0000244 if ( option_type == UndefinedOptionFlag ||
245 (option_type & NonMagickOptionFlag) != 0 ) {
anthonyf125a5e2012-04-03 13:14:42 +0000246#if MagickCommandDebug >= 3
247 (void) FormatLocaleFile(stderr, "Script %u,%u Non-Option: \"%s\"\n",
248 cli_wand->line, cli_wand->line, option);
anthony668f43a2012-02-20 14:55:32 +0000249#endif
anthony84d42792012-03-30 14:08:38 +0000250 if ( IfMagickFalse(IsCommandOption(option)))
anthonyafa3dfc2012-03-03 11:31:30 +0000251 /* non-option -- treat as a image read */
252 CLISpecialOperator(cli_wand,"-read",option);
anthonyafa3dfc2012-03-03 11:31:30 +0000253 else
254 CLIWandExceptionBreak(OptionFatalError,"UnrecognizedOption",option);
anthony24aa8822012-03-11 00:56:06 +0000255 count = 0;
256 goto next_token;
anthonyafa3dfc2012-03-03 11:31:30 +0000257 }
anthony1cdc5b72012-03-03 02:31:18 +0000258
259 if ( count >= 1 ) {
anthony84d42792012-03-30 14:08:38 +0000260 if( IfMagickFalse(GetScriptToken(token_info)) )
anthony24aa8822012-03-11 00:56:06 +0000261 CLIWandException(OptionFatalError,"MissingArgument",option);
anthonyafa3dfc2012-03-03 11:31:30 +0000262 CloneString(&arg1,token_info->token);
263 }
anthony1cdc5b72012-03-03 02:31:18 +0000264 else
anthonyafa3dfc2012-03-03 11:31:30 +0000265 CloneString(&arg1,(char *)NULL);
anthony2052d272012-02-28 12:48:29 +0000266
anthony1cdc5b72012-03-03 02:31:18 +0000267 if ( count >= 2 ) {
anthony84d42792012-03-30 14:08:38 +0000268 if( IfMagickFalse(GetScriptToken(token_info)) )
anthonyafa3dfc2012-03-03 11:31:30 +0000269 CLIWandExceptionBreak(OptionFatalError,"MissingArgument",option);
270 CloneString(&arg2,token_info->token);
271 }
anthony1cdc5b72012-03-03 02:31:18 +0000272 else
273 CloneString(&arg2,(char *)NULL);
anthony668f43a2012-02-20 14:55:32 +0000274
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
anthony668f43a2012-02-20 14:55:32 +0000280
anthony8226e722012-04-05 14:25:46 +0000281 if ( (option_type & GenesisOptionFlag) != 0 ) {
282 /* Genesis Options have no place in a magick script */
283 CLIWandExceptionBreak(OptionError,"InvalidUseOfOption",option);
284 goto next_token;
285 }
anthonya3ef4ed2012-03-17 06:52:53 +0000286 if ( (option_type & DeprecateOptionFlag) != 0 ) {
287 CLIWandException(OptionWarning,"DeprecatedOption",option);
288 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
289 break;
anthony8226e722012-04-05 14:25:46 +0000290 /* fall through - do the depreciated option */
291 }
292 if (((option_type & ImageRequiredFlags) != 0 ) &&
anthony71527252012-04-06 02:31:40 +0000293 ( cli_wand->wand.images == (Image *)NULL ) ) {
anthony8226e722012-04-05 14:25:46 +0000294 CLIWandException(OptionError,"NoImagesFound",option);
295 goto next_token;
anthonya3ef4ed2012-03-17 06:52:53 +0000296 }
297
298 /* handle special script-argument options here */
299 //either continue processing command line
300 // or making use of the command line options.
301 //CLICommandOptions(cli_wand,count+1,argv, MagickScriptArgsFlags);
302
anthony8226e722012-04-05 14:25:46 +0000303 /*
304 Process Option from file
305 */
anthonyafa3dfc2012-03-03 11:31:30 +0000306 if ( (option_type & SpecialOptionFlag) != 0 ) {
anthony8226e722012-04-05 14:25:46 +0000307 if ( LocaleCompare(option,"-exit") == 0 ) {
308 break; /* forced end of script */
309 }
310 if ( LocaleCompare(option,"-script") == 0 ) {
311 CLIWandExceptionBreak(OptionError,"InvalidUseOfOption",option);
312 goto next_token;
313 }
314 /* handle any other special operators now */
anthonyafa3dfc2012-03-03 11:31:30 +0000315 CLISpecialOperator(cli_wand,option,arg1);
316 }
anthony668f43a2012-02-20 14:55:32 +0000317
anthonyafa3dfc2012-03-03 11:31:30 +0000318 if ( (option_type & SettingOptionFlags) != 0 ) {
319 CLISettingOptionInfo(cli_wand, option, arg1);
anthony24aa8822012-03-11 00:56:06 +0000320 // FUTURE: Sync Specific Settings into Image Properities (not global)
anthonyafa3dfc2012-03-03 11:31:30 +0000321 }
anthonyeff71f52012-03-29 12:59:09 +0000322 if ( cli_wand->wand.images != (Image *)NULL )
323 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
324 cli_wand->wand.exception);
anthony668f43a2012-02-20 14:55:32 +0000325
anthony1cdc5b72012-03-03 02:31:18 +0000326 if ( (option_type & SimpleOperatorOptionFlag) != 0)
anthonyafa3dfc2012-03-03 11:31:30 +0000327 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
anthony668f43a2012-02-20 14:55:32 +0000328
anthony1cdc5b72012-03-03 02:31:18 +0000329 if ( (option_type & ListOperatorOptionFlag) != 0 )
anthonyafa3dfc2012-03-03 11:31:30 +0000330 CLIListOperatorImages(cli_wand, option, arg1, arg2);
anthony1cdc5b72012-03-03 02:31:18 +0000331
anthony24aa8822012-03-11 00:56:06 +0000332next_token:
anthonyf125a5e2012-04-03 13:14:42 +0000333#if MagickCommandDebug >= 9
anthony24aa8822012-03-11 00:56:06 +0000334 OutputOptions(cli_wand->wand.image_info);
anthonyf125a5e2012-04-03 13:14:42 +0000335 if ( cli_wand->wand.images != (Image *)NULL ) {
anthony24aa8822012-03-11 00:56:06 +0000336 OutputArtifacts(cli_wand->wand.images);
anthonyf125a5e2012-04-03 13:14:42 +0000337 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
338 }
anthony24aa8822012-03-11 00:56:06 +0000339#endif
anthony1cdc5b72012-03-03 02:31:18 +0000340 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
341 break;
342 }
343
anthonyf125a5e2012-04-03 13:14:42 +0000344#if MagickCommandDebug >= 3
anthony1cdc5b72012-03-03 02:31:18 +0000345 (void) FormatLocaleFile(stderr, "Script End: %d\n", token_info->status);
346#endif
347 switch( token_info->status ) {
348 case TokenStatusOK:
349 case TokenStatusEOF:
anthony8226e722012-04-05 14:25:46 +0000350 if (cli_wand->image_list_stack != (Stack *)NULL)
351 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
352 else if (cli_wand->image_info_stack != (Stack *)NULL)
353 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
anthony1cdc5b72012-03-03 02:31:18 +0000354 break;
355 case TokenStatusBadQuotes:
356 /* Ensure last token has a sane length for error report */
357 if( strlen(token_info->token) > INITAL_TOKEN_LENGTH-1 ) {
358 token_info->token[INITAL_TOKEN_LENGTH-4] = '.';
359 token_info->token[INITAL_TOKEN_LENGTH-3] = '.';
360 token_info->token[INITAL_TOKEN_LENGTH-2] = '.';
361 token_info->token[INITAL_TOKEN_LENGTH-1] = '\0';
362 }
anthonyafa3dfc2012-03-03 11:31:30 +0000363 CLIWandException(OptionFatalError,"ScriptUnbalancedQuotes",
364 token_info->token);
anthony1cdc5b72012-03-03 02:31:18 +0000365 break;
366 case TokenStatusMemoryFailed:
anthonyafa3dfc2012-03-03 11:31:30 +0000367 CLIWandException(OptionFatalError,"ScriptTokenMemoryFailed","");
anthony1cdc5b72012-03-03 02:31:18 +0000368 break;
369 case TokenStatusBinary:
anthonyafa3dfc2012-03-03 11:31:30 +0000370 CLIWandException(OptionFatalError,"ScriptIsBinary","");
anthony1cdc5b72012-03-03 02:31:18 +0000371 break;
372 }
373
374 /* Clean up */
375 token_info = DestroyScriptTokenInfo(token_info);
376
377 CloneString(&option,(char *)NULL);
378 CloneString(&arg1,(char *)NULL);
379 CloneString(&arg2,(char *)NULL);
380
381 return;
anthony668f43a2012-02-20 14:55:32 +0000382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386% %
387% %
388% %
389+ P r o c e s s C o m m a n d O p t i o n s %
390% %
391% %
392% %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
395% ProcessCommandOptions() reads and processes arguments in the given
396% command line argument array. The array does not contain the command
397% being processed, only the options.
398%
399% The 'process_flags' can be used to control and limit option processing.
400% For example, to only process one option, or how unknown and special options
401% are to be handled, and if the last argument in array is to be regarded as a
402% final image write argument (filename or special coder).
403%
404% The format of the ProcessCommandOptions method is:
405%
anthony43f425d2012-02-26 12:58:58 +0000406% int ProcessCommandOptions(MagickCLI *cli_wand,int argc,char **argv,
anthony0b46ebe2012-03-06 04:15:35 +0000407% int index, ProcessOptionFlags process_flags )
anthony668f43a2012-02-20 14:55:32 +0000408%
409% A description of each parameter follows:
410%
anthony43f425d2012-02-26 12:58:58 +0000411% o cli_wand: the main CLI Wand to use.
anthony668f43a2012-02-20 14:55:32 +0000412%
413% o argc: the number of elements in the argument vector.
414%
415% o argv: A text array containing the command line arguments.
416%
anthony0ea037a2012-04-03 12:14:39 +0000417% o process_flags: What type of arguments will be processed, ignored
418% or return errors.
anthony668f43a2012-02-20 14:55:32 +0000419%
anthony0b46ebe2012-03-06 04:15:35 +0000420% o index: index in the argv array to start processing from
421%
422% The function returns the index ot the next option to be processed. This
423% is really only releven if process_flags contains a ProcessOneOptionOnly
424% flag.
425%
anthony668f43a2012-02-20 14:55:32 +0000426*/
anthony0b46ebe2012-03-06 04:15:35 +0000427WandExport int ProcessCommandOptions(MagickCLI *cli_wand, int argc,
428 char **argv, int index, ProcessOptionFlags process_flags )
anthonyfa1e43d2012-02-12 12:55:45 +0000429{
430 const char
431 *option,
432 *arg1,
433 *arg2;
434
anthony0b46ebe2012-03-06 04:15:35 +0000435 int
anthonyfa1e43d2012-02-12 12:55:45 +0000436 i,
anthony668f43a2012-02-20 14:55:32 +0000437 end,
anthonyfa1e43d2012-02-12 12:55:45 +0000438 count;
439
440 CommandOptionFlags
anthony686b1a32012-02-15 14:50:53 +0000441 option_type;
anthonyfa1e43d2012-02-12 12:55:45 +0000442
anthony0b46ebe2012-03-06 04:15:35 +0000443 assert(argc>=index); /* you may have no arguments left! */
444 assert(argv != (char **)NULL);
445 assert(argv[index] != (char *)NULL);
446 assert(argv[argc-1] != (char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000447 assert(cli_wand != (MagickCLI *) NULL);
448 assert(cli_wand->signature == WandSignature);
449 if (cli_wand->wand.debug != MagickFalse)
450 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthonyfa1e43d2012-02-12 12:55:45 +0000451
anthony92c93bd2012-03-19 14:02:47 +0000452 /* define the error location string for use in exceptions
453 order of input escapes: option, (arg), filename, line, column */
454 cli_wand->location="'%s' %s arg %u";
455 cli_wand->location2="'%s' '%s' %s arg %u";
anthonyafa3dfc2012-03-03 11:31:30 +0000456 cli_wand->filename="CLI";
457
anthony668f43a2012-02-20 14:55:32 +0000458 end = argc;
459 if ( ( process_flags & ProcessOutputFile ) != 0 )
460 end--;
anthony0b46ebe2012-03-06 04:15:35 +0000461
462 for (i=index; i < end; i += count +1) {
anthonyafa3dfc2012-03-03 11:31:30 +0000463 /* Finished processing one option? */
anthony0b46ebe2012-03-06 04:15:35 +0000464 if ( ( process_flags & ProcessOneOptionOnly ) != 0 && i != index )
465 return(i);
anthony668f43a2012-02-20 14:55:32 +0000466
anthonyafa3dfc2012-03-03 11:31:30 +0000467 option=argv[i];
468 cli_wand->line=i;
anthonyfa1e43d2012-02-12 12:55:45 +0000469
anthonyafa3dfc2012-03-03 11:31:30 +0000470 { const OptionInfo *option_info = GetCommandOptionInfo(argv[i]);
471 count=option_info->type;
cristyaa2c16c2012-03-25 22:21:35 +0000472 option_type=(CommandOptionFlags) option_info->flags;
anthonyf125a5e2012-04-03 13:14:42 +0000473#if 0
anthony0b46ebe2012-03-06 04:15:35 +0000474 (void) FormatLocaleFile(stderr, "CLI %d: \"%s\" matched \"%s\"\n",
475 i, argv[i], option_info->mnemonic );
anthony686b1a32012-02-15 14:50:53 +0000476#endif
anthonyafa3dfc2012-03-03 11:31:30 +0000477 }
anthonyfa1e43d2012-02-12 12:55:45 +0000478
anthonyafa3dfc2012-03-03 11:31:30 +0000479 if ( option_type == UndefinedOptionFlag ||
480 (option_type & NonMagickOptionFlag) != 0 ) {
anthonyf125a5e2012-04-03 13:14:42 +0000481#if MagickCommandDebug >= 3
482 (void) FormatLocaleFile(stderr, "CLI %d Non-Option: \"%s\"\n", i, option);
anthonyfa1e43d2012-02-12 12:55:45 +0000483#endif
anthony84d42792012-03-30 14:08:38 +0000484 if ( IfMagickFalse(IsCommandOption(option) ) &&
485 (process_flags & ProcessNonOptionImageRead) != 0 )
anthonyafa3dfc2012-03-03 11:31:30 +0000486 /* non-option -- treat as a image read */
487 CLISpecialOperator(cli_wand,"-read",option);
anthonyafa3dfc2012-03-03 11:31:30 +0000488 else if ( (process_flags & ProcessUnknownOptionError) != 0 )
489 CLIWandException(OptionFatalError,"UnrecognizedOption",option);
anthony24aa8822012-03-11 00:56:06 +0000490 count = 0;
491 goto next_argument;
anthonyfa1e43d2012-02-12 12:55:45 +0000492 }
493
anthonyafa3dfc2012-03-03 11:31:30 +0000494 if ((i+count) >= end ) {
anthony0b46ebe2012-03-06 04:15:35 +0000495 CLIWandException(OptionFatalError,"MissingArgument",option);
anthonyafa3dfc2012-03-03 11:31:30 +0000496 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
anthony0b46ebe2012-03-06 04:15:35 +0000497 return(end);
anthony24aa8822012-03-11 00:56:06 +0000498 goto next_argument; /* no more arguments unable to proceed */
anthonyafa3dfc2012-03-03 11:31:30 +0000499 }
500
501 arg1 = ( count >= 1 ) ? argv[i+1] : (char *)NULL;
502 arg2 = ( count >= 2 ) ? argv[i+2] : (char *)NULL;
503
anthonyf125a5e2012-04-03 13:14:42 +0000504#if MagickCommandDebug >= 3
anthonyafa3dfc2012-03-03 11:31:30 +0000505 (void) FormatLocaleFile(stderr,
anthonyf125a5e2012-04-03 13:14:42 +0000506 "CLI %u Option: \"%s\" Count: %d Flags: %04x Args: \"%s\" \"%s\"\n",
507 i,option,count,option_type,arg1,arg2);
anthonyafa3dfc2012-03-03 11:31:30 +0000508#endif
509
anthony8226e722012-04-05 14:25:46 +0000510 if ( (option_type & DeprecateOptionFlag) != 0 ) {
511 CLIWandException(OptionWarning,"DeprecatedOption",option);
512 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
513 return(end);
514 /* fall through - do the depreciated option */
515 }
516 if ( (option_type & GenesisOptionFlag) != 0 ) {
517 goto next_argument; /* ignore genesis options */
518 }
519 if (((option_type & ImageRequiredFlags) != 0 ) &&
520 ( cli_wand->wand.images == (Image *)NULL ) ) {
521 CLIWandException(OptionError,"NoImagesFound",option);
522 goto next_argument;
523 }
524
anthonyafa3dfc2012-03-03 11:31:30 +0000525 if ( (option_type & SpecialOptionFlag) != 0 ) {
526 if ( ( process_flags & ProcessExitOption ) != 0
527 && LocaleCompare(option,"-exit") == 0 )
anthony0b46ebe2012-03-06 04:15:35 +0000528 return(i+count);
anthonyafa3dfc2012-03-03 11:31:30 +0000529 if ( ( process_flags & ProcessScriptOption ) != 0
anthony0b46ebe2012-03-06 04:15:35 +0000530 && LocaleCompare(option,"-script") == 0) {
anthony0b46ebe2012-03-06 04:15:35 +0000531 // Call Script, with a filename as a zeroth argument
532 ProcessScriptOptions(cli_wand,argc,argv,i+1);
533 return(argc); /* no more options after script process! */
534 }
anthony8226e722012-04-05 14:25:46 +0000535 /* handle any other special operators now */
anthonyafa3dfc2012-03-03 11:31:30 +0000536 CLISpecialOperator(cli_wand,option,arg1);
537 }
538
539 if ( (option_type & SettingOptionFlags) != 0 ) {
540 CLISettingOptionInfo(cli_wand, option, arg1);
anthony24aa8822012-03-11 00:56:06 +0000541 // FUTURE: Sync Specific Settings into Image Properities (not global)
anthonyafa3dfc2012-03-03 11:31:30 +0000542 }
anthonyeff71f52012-03-29 12:59:09 +0000543 if ( cli_wand->wand.images != (Image *)NULL )
544 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
545 cli_wand->wand.exception);
anthonyafa3dfc2012-03-03 11:31:30 +0000546
547 if ( (option_type & SimpleOperatorOptionFlag) != 0)
548 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
549
550 if ( (option_type & ListOperatorOptionFlag) != 0 )
551 CLIListOperatorImages(cli_wand, option, arg1, arg2);
552
anthony24aa8822012-03-11 00:56:06 +0000553next_argument:
anthonyf125a5e2012-04-03 13:14:42 +0000554#if MagickCommandDebug >= 9
anthony24aa8822012-03-11 00:56:06 +0000555 OutputOptions(cli_wand->wand.image_info);
anthonyf125a5e2012-04-03 13:14:42 +0000556 if ( cli_wand->wand.images != (Image *)NULL ) {
anthony24aa8822012-03-11 00:56:06 +0000557 OutputArtifacts(cli_wand->wand.images);
anthonyf125a5e2012-04-03 13:14:42 +0000558 OutputProperties(cli_wand->wand.images,cli_wand->wand.exception);
559 }
anthony24aa8822012-03-11 00:56:06 +0000560#endif
anthonyafa3dfc2012-03-03 11:31:30 +0000561 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
anthony0b46ebe2012-03-06 04:15:35 +0000562 return(i+count);
anthonyafa3dfc2012-03-03 11:31:30 +0000563 }
anthony0b46ebe2012-03-06 04:15:35 +0000564 assert(i==end);
anthony2052d272012-02-28 12:48:29 +0000565
anthony668f43a2012-02-20 14:55:32 +0000566 if ( ( process_flags & ProcessOutputFile ) == 0 )
anthony0b46ebe2012-03-06 04:15:35 +0000567 return(end);
568
anthony668f43a2012-02-20 14:55:32 +0000569 assert(end==argc-1);
570
571 /*
anthony43f425d2012-02-26 12:58:58 +0000572 Implicit Write of images to final CLI argument
anthony668f43a2012-02-20 14:55:32 +0000573 */
574 option=argv[i];
anthony799889a2012-03-11 11:00:32 +0000575 cli_wand->line=i;
anthony686b1a32012-02-15 14:50:53 +0000576
anthonyf125a5e2012-04-03 13:14:42 +0000577#if MagickCommandDebug >= 3
578 (void) FormatLocaleFile(stderr, "CLI %d Write File: \"%s\"\n", i, option );
anthonyfa1e43d2012-02-12 12:55:45 +0000579#endif
580
anthony8226e722012-04-05 14:25:46 +0000581 /* check that stacks are empty */
582 if (cli_wand->image_list_stack != (Stack *)NULL)
583 CLIWandException(OptionError,"UnbalancedParenthesis", "(eof)");
584 else if (cli_wand->image_info_stack != (Stack *)NULL)
585 CLIWandException(OptionError,"UnbalancedBraces", "(eof)");
586 if ( CLICatchException(cli_wand, MagickFalse) != MagickFalse )
587 return(argc);
anthonyfa1e43d2012-02-12 12:55:45 +0000588
anthony8226e722012-04-05 14:25:46 +0000589 /* This is a valid 'do no write' option - no images needed */
anthonyfa1e43d2012-02-12 12:55:45 +0000590 if (LocaleCompare(option,"-exit") == 0 )
anthony0b46ebe2012-03-06 04:15:35 +0000591 return(argc); /* just exit, no image write */
anthonyfa1e43d2012-02-12 12:55:45 +0000592
anthony8226e722012-04-05 14:25:46 +0000593 /* If filename looks like an option -- produce an error */
anthony0b46ebe2012-03-06 04:15:35 +0000594 if (IsCommandOption(option) != MagickFalse) {
595 CLIWandException(OptionError,"MissingOutputFilename",option);
596 return(argc);
597 }
anthonyfa1e43d2012-02-12 12:55:45 +0000598
anthony43f425d2012-02-26 12:58:58 +0000599 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
600 cli_wand->wand.exception);
anthony8226e722012-04-05 14:25:46 +0000601 CLISpecialOperator(cli_wand,"-write",option);
anthony0b46ebe2012-03-06 04:15:35 +0000602 return(argc);
anthonyfa1e43d2012-02-12 12:55:45 +0000603}
604
605/*
606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
607% %
608% %
609% %
610+ M a g i c k I m a g e C o m m a n d %
611% %
612% %
613% %
614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
615%
anthony668f43a2012-02-20 14:55:32 +0000616% MagickImageCommand() Handle special use CLI arguments and prepare a
anthony43f425d2012-02-26 12:58:58 +0000617% CLI MagickCLI to process the command line or directly specified script.
anthony668f43a2012-02-20 14:55:32 +0000618%
619% This is essentualy interface function between the MagickCore library
anthony43f425d2012-02-26 12:58:58 +0000620% initialization function MagickCommandGenesis(), and the option MagickCLI
anthony668f43a2012-02-20 14:55:32 +0000621% processing functions ProcessCommandOptions() or ProcessScriptOptions()
anthonyfa1e43d2012-02-12 12:55:45 +0000622%
623% The format of the MagickImageCommand method is:
624%
625% MagickBooleanType MagickImageCommand(ImageInfo *image_info,
626% int argc, char **argv, char **metadata, ExceptionInfo *exception)
627%
628% A description of each parameter follows:
629%
630% o image_info: the starting image_info structure
631% (for compatibilty with MagickCommandGenisis())
632%
633% o argc: the number of elements in the argument vector.
634%
635% o argv: A text array containing the command line arguments.
636%
anthony0ea037a2012-04-03 12:14:39 +0000637% o metadata: any metadata (for VBS) is returned here.
anthonyfa1e43d2012-02-12 12:55:45 +0000638% (for compatibilty with MagickCommandGenisis())
639%
640% o exception: return any errors or warnings in this structure.
641%
642*/
643
anthony40b60152012-04-04 06:13:37 +0000644static void MagickUsage(MagickBooleanType verbose)
anthonyfa1e43d2012-02-12 12:55:45 +0000645{
anthony40b60152012-04-04 06:13:37 +0000646 (void) FormatLocaleFile(stdout,
647 "Usage: %s [{option}|{image}...] {output_image}\n",GetClientName());
648 (void) FormatLocaleFile(stdout,
649 " %s [{option}|{image}...] -script {filename} [{script_args}...]\n",
650 GetClientName());
651 (void) FormatLocaleFile(stdout,
652 " %s -help|-version|-usage|-list {option}\n",
653 GetClientName());
654
655 if (IfMagickFalse(verbose))
656 return;
657
658 (void) FormatLocaleFile(stdout,"\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
659 "All options are performed in a strict 'as you see them' order\n",
660 "You must read-in images before you can operate on them.\n",
661 "\n",
662 "Magick Script files can use any of the following forms...\n",
663 " #!/path/to/magick -script\n",
664 "or\n",
665 " #!/bin/sh\n",
666 " :; exec magick -script \"$0\" \"$@\"; exit 10\n",
667 " # Magick script from here...\n",
668 "or\n",
669 " #!/usr/bin/env magick-script\n",
670 "The latter two forms do not require the path to the command hard coded.\n",
671 "Note: \"magick-script\" needs to be linked to the \"magick\" command.\n",
672 "\n",
673 "For more information on usage, options, examples, and techniques\n",
674 "see the ImageMagick website at ", MagickAuthoritativeURL);
675
676 return;
anthonyfa1e43d2012-02-12 12:55:45 +0000677}
678
679/*
680 Concatanate given file arguments to the given output argument.
681 Used for a special -concatenate option used for specific 'delegates'.
682 The option is not formally documented.
683
684 magick -concatenate files... output
685
686 This is much like the UNIX "cat" command, but for both UNIX and Windows,
687 however the last argument provides the output filename.
688*/
anthonyfa1e43d2012-02-12 12:55:45 +0000689static MagickBooleanType ConcatenateImages(int argc,char **argv,
690 ExceptionInfo *exception)
691{
692 FILE
693 *input,
694 *output;
695
696 int
697 c;
698
699 register ssize_t
700 i;
701
702 output=fopen_utf8(argv[argc-1],"wb");
anthonyafa3dfc2012-03-03 11:31:30 +0000703 if (output == (FILE *) NULL) {
704 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
705 argv[argc-1]);
706 return(MagickFalse);
707 }
708 for (i=2; i < (ssize_t) (argc-1); i++) {
anthonyfa1e43d2012-02-12 12:55:45 +0000709 input=fopen_utf8(argv[i],"rb");
710 if (input == (FILE *) NULL)
711 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
712 for (c=fgetc(input); c != EOF; c=fgetc(input))
713 (void) fputc((char) c,output);
714 (void) fclose(input);
715 (void) remove_utf8(argv[i]);
716 }
717 (void) fclose(output);
718 return(MagickTrue);
719}
720
721WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
722 int argc,char **argv,char **metadata,ExceptionInfo *exception)
723{
anthony43f425d2012-02-26 12:58:58 +0000724 MagickCLI
725 *cli_wand;
anthonyfa1e43d2012-02-12 12:55:45 +0000726
727 const char
728 *option;
729
anthony0ea037a2012-04-03 12:14:39 +0000730 ProcessOptionFlags
731 process_flags = MagickCommandOptionFlags;
732
anthony4cb37262012-03-18 11:18:45 +0000733 /* For specific OS command line requirements */
734 ReadCommandlLine(argc,&argv);
735
736#if 0
anthony4cb37262012-03-18 11:18:45 +0000737 status=ExpandFilenames(&argc,&argv);
anthony0ea037a2012-04-03 12:14:39 +0000738 if ( IfMagickFalse(status) )
anthony4cb37262012-03-18 11:18:45 +0000739 ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed",
740 GetExceptionMessage(errno));
741#endif
anthonyeff71f52012-03-29 12:59:09 +0000742
anthony668f43a2012-02-20 14:55:32 +0000743 /* Initialize special "CLI Wand" to hold images and settings (empty) */
anthony43f425d2012-02-26 12:58:58 +0000744 cli_wand=AcquireMagickCLI(image_info,exception);
anthony8226e722012-04-05 14:25:46 +0000745 cli_wand->line=1;
anthonyfa1e43d2012-02-12 12:55:45 +0000746
anthonyeff71f52012-03-29 12:59:09 +0000747 GetPathComponent(argv[0],TailPath,cli_wand->wand.name);
748 ConcatenateMagickString(cli_wand->wand.name,"-CLI",MaxTextExtent);
749
anthonyeff71f52012-03-29 12:59:09 +0000750 /* "convert" command - give a "depreciation" warning" */
anthony0ea037a2012-04-03 12:14:39 +0000751 if ( (LocaleCompare("convert",argv[0]+strlen((argv[0])-7)) == 0) ||
anthonyeff71f52012-03-29 12:59:09 +0000752 (LocaleNCompare("convert",argv[0],7) == 0) ||
753 (LocaleNCompare("lt-convert",argv[0],10) == 0) ) {
anthony0ea037a2012-04-03 12:14:39 +0000754 process_flags = ConvertCommandOptionFlags;
755 /*(void) FormatLocaleFile(stderr,"WARNING: %s\n",
756 "The convert is depreciated in IMv7, use \"magick\"\n");*/
anthonyeff71f52012-03-29 12:59:09 +0000757 }
anthonyeff71f52012-03-29 12:59:09 +0000758
anthony8226e722012-04-05 14:25:46 +0000759 /* Special Case: If command name ends with "script" implied "-script" */
anthony52bef752012-03-27 13:54:47 +0000760 if (LocaleCompare("script",argv[0]+strlen(argv[0])-6) == 0) {
anthony52bef752012-03-27 13:54:47 +0000761 GetPathComponent(argv[1],TailPath,cli_wand->wand.name);
762 ProcessScriptOptions(cli_wand,argc,argv,1);
763 goto Magick_Command_Cleanup;
764 }
765
766 /* Special Case: Version Information and Abort */
767 if (argc == 2) {
768 option=argv[1];
anthony40b60152012-04-04 06:13:37 +0000769 if (LocaleCompare("-version",option) == 0) {
anthony52bef752012-03-27 13:54:47 +0000770 CLISpecialOperator(cli_wand, "-version", (char *)NULL);
771 goto Magick_Command_Exit;
772 }
anthony40b60152012-04-04 06:13:37 +0000773 if ((LocaleCompare("-help",option) == 0) || /* GNU standard option */
774 (LocaleCompare("--help",option) == 0) ) {
775 MagickUsage(MagickFalse);
776 goto Magick_Command_Exit;
777 }
778 if (LocaleCompare("-usage",option) == 0) {
779 CLISpecialOperator(cli_wand, "-version", (char *)NULL);
780 MagickUsage(MagickTrue);
781 goto Magick_Command_Exit;
782 }
anthony52bef752012-03-27 13:54:47 +0000783 }
784
785 /* not enough arguments -- including -help */
786 if (argc < 3) {
anthony40b60152012-04-04 06:13:37 +0000787 (void) FormatLocaleFile(stderr,
788 "Error: Invalid argument or not enough arguments\n\n");
789 MagickUsage(MagickFalse);
anthony52bef752012-03-27 13:54:47 +0000790 goto Magick_Command_Exit;
791 }
792
anthony52bef752012-03-27 13:54:47 +0000793 /* List Information and Abort */
794 if (LocaleCompare("-list",argv[1]) == 0) {
anthonyafa3dfc2012-03-03 11:31:30 +0000795 CLISpecialOperator(cli_wand, argv[1], argv[2]);
anthony52bef752012-03-27 13:54:47 +0000796 goto Magick_Command_Exit;
797 }
798
anthony0ea037a2012-04-03 12:14:39 +0000799 /* Special "concatenate option (hidden) for delegate usage */
800 if (LocaleCompare("-concatenate",argv[1]) == 0) {
801 ConcatenateImages(argc,argv,exception);
802 goto Magick_Command_Exit;
803 }
804
anthony52bef752012-03-27 13:54:47 +0000805 /* ------------- */
806 /* The Main Call */
807
808 if (LocaleCompare("-script",argv[1]) == 0) {
anthonyafa3dfc2012-03-03 11:31:30 +0000809 /* Start processing directly from script, no pre-script options
anthony0b46ebe2012-03-06 04:15:35 +0000810 Replace wand command name with script name
811 First argument in the argv array is the script name to read.
anthonyafa3dfc2012-03-03 11:31:30 +0000812 */
813 GetPathComponent(argv[2],TailPath,cli_wand->wand.name);
anthony0b46ebe2012-03-06 04:15:35 +0000814 ProcessScriptOptions(cli_wand,argc,argv,2);
anthonyafa3dfc2012-03-03 11:31:30 +0000815 }
anthony0b46ebe2012-03-06 04:15:35 +0000816 else {
anthony52bef752012-03-27 13:54:47 +0000817 /* Normal Command Line, assumes output file as last option */
anthony0ea037a2012-04-03 12:14:39 +0000818 ProcessCommandOptions(cli_wand,argc,argv,1, process_flags);
anthony0b46ebe2012-03-06 04:15:35 +0000819 }
anthony52bef752012-03-27 13:54:47 +0000820 /* ------------- */
anthonyfa1e43d2012-02-12 12:55:45 +0000821
anthony4cb37262012-03-18 11:18:45 +0000822Magick_Command_Cleanup:
anthony8226e722012-04-05 14:25:46 +0000823 /* recover original image_info and clean up stacks */
824 while (cli_wand->image_list_stack != (Stack *)NULL)
825 CLISpecialOperator(cli_wand,")",(const char *)NULL);
anthony43f425d2012-02-26 12:58:58 +0000826 while (cli_wand->image_info_stack != (Stack *)NULL)
827 CLISpecialOperator(cli_wand,"}",(const char *)NULL);
anthony2052d272012-02-28 12:48:29 +0000828
anthony1cdc5b72012-03-03 02:31:18 +0000829 /* assert we have recovered the original structures */
anthony43f425d2012-02-26 12:58:58 +0000830 assert(cli_wand->wand.image_info == image_info);
831 assert(cli_wand->wand.exception == exception);
anthonyfa1e43d2012-02-12 12:55:45 +0000832
833 /* Handle metadata for ImageMagickObject COM object for Windows VBS */
anthonyafa3dfc2012-03-03 11:31:30 +0000834 if (metadata != (char **) NULL) {
835 const char
836 *format;
anthonyfa1e43d2012-02-12 12:55:45 +0000837
anthonyafa3dfc2012-03-03 11:31:30 +0000838 char
839 *text;
anthonyfa1e43d2012-02-12 12:55:45 +0000840
anthonyafa3dfc2012-03-03 11:31:30 +0000841 format="%w,%h,%m"; // Get this from image_info Option splaytree
anthonyfa1e43d2012-02-12 12:55:45 +0000842
anthonyafa3dfc2012-03-03 11:31:30 +0000843 text=InterpretImageProperties(image_info,cli_wand->wand.images,format,
844 exception);
845 if (text == (char *) NULL)
846 ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
847 "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
848 else {
849 (void) ConcatenateString(&(*metadata),text);
850 text=DestroyString(text);
anthonyfa1e43d2012-02-12 12:55:45 +0000851 }
anthonyafa3dfc2012-03-03 11:31:30 +0000852 }
anthony4cb37262012-03-18 11:18:45 +0000853
anthony52bef752012-03-27 13:54:47 +0000854Magick_Command_Exit:
anthonyfa1e43d2012-02-12 12:55:45 +0000855 /* Destroy the special CLI Wand */
anthony43f425d2012-02-26 12:58:58 +0000856 cli_wand->wand.image_info = (ImageInfo *)NULL; /* not these */
857 cli_wand->wand.exception = (ExceptionInfo *)NULL;
858 cli_wand=DestroyMagickCLI(cli_wand);
anthonyfa1e43d2012-02-12 12:55:45 +0000859
anthonyc2b913e2012-03-31 00:22:33 +0000860 return(IsMagickTrue(exception->severity > ErrorException));
anthonyfa1e43d2012-02-12 12:55:45 +0000861}