1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % W W AA N N DDD CCC L III %
7 % W W A A NN N D D C L I %
8 % W W W AAAA N N N D D C L I %
9 % W W W A A N NN D D C L I %
10 % W W A A N N DDD CCC LLLL III %
11 % %
12 % WandCLI Structure Methods %
13 % %
14 % Dragon Computing %
15 % Anthony Thyssen %
16 % April 2011 %
17 % %
18 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
19 % dedicated to making software imaging solutions freely available. %
20 % %
21 % You may not use this file except in compliance with the License. You may %
22 % obtain a copy of the License at %
23 % %
24 % https://imagemagick.org/script/license.php %
25 % %
26 % Unless required by applicable law or agreed to in writing, software %
27 % distributed under the License is distributed on an "AS IS" BASIS, %
28 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
29 % See the License for the specific language governing permissions and %
30 % limitations under the License. %
31 % %
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 %
34 % General methds for handling the WandCLI structure used for Command Line.
35 %
36 % Anthony Thyssen, April 2011
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickWand/studio.h"
43 #include "MagickWand/MagickWand.h"
44 #include "MagickWand/wand.h"
45 #include "MagickWand/magick-wand-private.h"
46 #include "MagickWand/wandcli.h"
47 #include "MagickWand/wandcli-private.h"
48 #include "MagickCore/exception.h"
49
50 /*
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 % %
53 % %
54 % %
55 + A c q u i r e W a n d C L I %
56 % %
57 % %
58 % %
59 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60 %
61 % AcquireMagickCLI() creates a new CLI wand (an expanded form of Magick
62 % Wand). The given image_info and exception is included as is if provided.
63 %
64 % Use DestroyMagickCLI() to dispose of the CLI wand when it is no longer
65 % needed.
66 %
67 % The format of the NewMagickWand method is:
68 %
69 % MagickCLI *AcquireMagickCLI(ImageInfo *image_info,
70 % ExceptionInfo *exception)
71 %
72 */
AcquireMagickCLI(ImageInfo * image_info,ExceptionInfo * exception)73 WandExport MagickCLI *AcquireMagickCLI(ImageInfo *image_info,
74 ExceptionInfo *exception)
75 {
76 MagickCLI
77 *cli_wand;
78
79 /* precaution - as per NewMagickWand() */
80 {
81 size_t depth = MAGICKCORE_QUANTUM_DEPTH;
82 const char *quantum = GetMagickQuantumDepth(&depth);
83 if (depth != MAGICKCORE_QUANTUM_DEPTH)
84 ThrowWandFatalException(WandError,"QuantumDepthMismatch",quantum);
85 }
86
87 /* allocate memory for MgaickCLI */
88 cli_wand=(MagickCLI *) AcquireCriticalMemory(sizeof(*cli_wand));
89
90 /* Initialize Wand Part of MagickCLI
91 FUTURE: this is a repeat of code from NewMagickWand()
92 However some parts may be given fro man external source!
93 */
94 cli_wand->wand.id=AcquireWandId();
95 (void) FormatLocaleString(cli_wand->wand.name,MagickPathExtent,
96 "%s-%.20g","MagickWandCLI", (double) cli_wand->wand.id);
97 cli_wand->wand.images=NewImageList();
98 if ( image_info == (ImageInfo *) NULL)
99 cli_wand->wand.image_info=AcquireImageInfo();
100 else
101 cli_wand->wand.image_info=image_info;
102 if ( exception == (ExceptionInfo *) NULL)
103 cli_wand->wand.exception=AcquireExceptionInfo();
104 else
105 cli_wand->wand.exception=exception;
106 cli_wand->wand.debug=IsEventLogging();
107 cli_wand->wand.signature=MagickWandSignature;
108
109 /* Initialize CLI Part of MagickCLI */
110 cli_wand->draw_info=CloneDrawInfo(cli_wand->wand.image_info,(DrawInfo *) NULL);
111 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
112 cli_wand->process_flags=MagickCommandOptionFlags; /* assume "magick" CLI */
113 cli_wand->command=(const OptionInfo *) NULL; /* no option at this time */
114 cli_wand->image_list_stack=(Stack *) NULL;
115 cli_wand->image_info_stack=(Stack *) NULL;
116
117 /* default exception location...
118 EG: sprintf(locaiton, filename, line, column);
119 */
120 cli_wand->location="from \"%s\""; /* location format using arguments: */
121 /* filename, line, column */
122 cli_wand->filename="unknown"; /* script filename, unknown source */
123 cli_wand->line=0; /* line from script OR CLI argument */
124 cli_wand->column=0; /* column from script */
125
126 cli_wand->signature=MagickWandSignature;
127 if (cli_wand->wand.debug != MagickFalse)
128 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
129 return(cli_wand);
130 }
131
132 /*
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 % %
135 % %
136 % %
137 + D e s t r o y W a n d C L I %
138 % %
139 % %
140 % %
141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 %
143 % DestroyMagickCLI() destorys everything in a CLI wand, including image_info
144 % and any exceptions, if still present in the wand.
145 %
146 % The format of the NewMagickWand method is:
147 %
148 % MagickWand *DestroyMagickCLI()
149 % Exception *exception)
150 %
151 */
DestroyMagickCLI(MagickCLI * cli_wand)152 WandExport MagickCLI *DestroyMagickCLI(MagickCLI *cli_wand)
153 {
154 Stack
155 *node;
156
157 assert(cli_wand != (MagickCLI *) NULL);
158 assert(cli_wand->signature == MagickWandSignature);
159 assert(cli_wand->wand.signature == MagickWandSignature);
160 if (cli_wand->wand.debug != MagickFalse)
161 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
162
163 /* Destroy CLI part of MagickCLI */
164 if (cli_wand->draw_info != (DrawInfo *) NULL )
165 cli_wand->draw_info=DestroyDrawInfo(cli_wand->draw_info);
166 if (cli_wand->quantize_info != (QuantizeInfo *) NULL )
167 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
168 while(cli_wand->image_list_stack != (Stack *) NULL)
169 {
170 node=cli_wand->image_list_stack;
171 cli_wand->image_list_stack=node->next;
172 (void) DestroyImageList((Image *)node->data);
173 (void) RelinquishMagickMemory(node);
174 }
175 while(cli_wand->image_info_stack != (Stack *) NULL)
176 {
177 node=cli_wand->image_info_stack;
178 cli_wand->image_info_stack=node->next;
179 (void) DestroyImageInfo((ImageInfo *)node->data);
180 (void) RelinquishMagickMemory(node);
181 }
182 cli_wand->signature=(~MagickWandSignature);
183
184 /* Destroy Wand part MagickCLI */
185 cli_wand->wand.images=DestroyImageList(cli_wand->wand.images);
186 if (cli_wand->wand.image_info != (ImageInfo *) NULL )
187 cli_wand->wand.image_info=DestroyImageInfo(cli_wand->wand.image_info);
188 if (cli_wand->wand.exception != (ExceptionInfo *) NULL )
189 cli_wand->wand.exception=DestroyExceptionInfo(cli_wand->wand.exception);
190 RelinquishWandId(cli_wand->wand.id);
191 cli_wand->wand.signature=(~MagickWandSignature);
192 cli_wand=(MagickCLI *) RelinquishMagickMemory(cli_wand);
193 return((MagickCLI *) NULL);
194 }
195
196 /*
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % %
199 % %
200 % %
201 + C L I C a t c h E x c e p t i o n %
202 % %
203 % %
204 % %
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 %
207 % CLICatchException() will report exceptions, either just non-fatal warnings
208 % only, or all errors, according to 'all_execeptions' boolean argument.
209 %
210 % The function returns true if errors are fatal, in which case the caller
211 % should abort and re-call with an 'all_exceptions' argument of true before
212 % quitting.
213 %
214 % The cut-off level between fatal and non-fatal may be controlled by options
215 % (FUTURE), but defaults to 'Error' exceptions.
216 %
217 % The format of the CLICatchException method is:
218 %
219 % MagickBooleanType CLICatchException(MagickCLI *cli_wand,
220 % const MagickBooleanType all_exceptions );
221 %
222 % Arguments are
223 %
224 % o cli_wand: The Wand CLI that holds the exception Information
225 %
226 % o all_exceptions: Report all exceptions, including the fatal one
227 %
228 */
CLICatchException(MagickCLI * cli_wand,const MagickBooleanType all_exceptions)229 WandExport MagickBooleanType CLICatchException(MagickCLI *cli_wand,
230 const MagickBooleanType all_exceptions)
231 {
232 MagickBooleanType
233 status;
234
235 assert(cli_wand != (MagickCLI *) NULL);
236 assert(cli_wand->signature == MagickWandSignature);
237 assert(cli_wand->wand.signature == MagickWandSignature);
238 if (cli_wand->wand.debug != MagickFalse)
239 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
240
241 /*
242 FUTURE: '-regard_warning' should make this more sensitive.
243 Note pipelined options may like more control over this level
244 */
245
246 status=cli_wand->wand.exception->severity > ErrorException ? MagickTrue :
247 MagickFalse;
248
249 if ((status == MagickFalse) || (all_exceptions != MagickFalse))
250 CatchException(cli_wand->wand.exception); /* output and clear exceptions */
251
252 return(status);
253 }
254
255 /*
256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257 % %
258 % %
259 % %
260 + C L I L o g E v e n t %
261 % %
262 % %
263 % %
264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265 %
266 % CLILogEvent() is a wrapper around LogMagickEvent(), adding to it the
267 % location of the option that is (about) to be executed.
268 %
269 */
CLILogEvent(MagickCLI * cli_wand,const LogEventType type,const char * magick_module,const char * function,const size_t line,const char * format,...)270 WandExport MagickBooleanType CLILogEvent(MagickCLI *cli_wand,
271 const LogEventType type,const char *magick_module,const char *function,
272 const size_t line,const char *format,...)
273 {
274 char
275 new_format[MagickPathExtent];
276
277 MagickBooleanType
278 status;
279
280 va_list
281 operands;
282
283 if (IsEventLogging() == MagickFalse)
284 return(MagickFalse);
285
286 /* HACK - prepend the CLI location to format string.
287 The better way would be add more arguments to to the 'va' oparands
288 list, but that does not appear to be possible! So we do some
289 pre-formating of the location info here.
290 */
291 (void) FormatLocaleString(new_format,MagickPathExtent,cli_wand->location,
292 cli_wand->filename, cli_wand->line, cli_wand->column);
293 (void) ConcatenateMagickString(new_format," ",MagickPathExtent);
294 (void) ConcatenateMagickString(new_format,format,MagickPathExtent);
295
296 va_start(operands,format);
297 status=LogMagickEventList(type,magick_module,function,line,new_format,
298 operands);
299 va_end(operands);
300
301 return(status);
302 }
303
304 /*
305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 % %
307 % %
308 % %
309 + C L I T h r o w E x c e p t i o n %
310 % %
311 % %
312 % %
313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314 %
315 % CLIThrowException() is a wrapper around ThrowMagickException(), adding to
316 % it the location of the option that caused the exception to occur.
317 */
CLIThrowException(MagickCLI * cli_wand,const char * magick_module,const char * function,const size_t line,const ExceptionType severity,const char * tag,const char * format,...)318 WandExport MagickBooleanType CLIThrowException(MagickCLI *cli_wand,
319 const char *magick_module,const char *function,const size_t line,
320 const ExceptionType severity,const char *tag,const char *format,...)
321 {
322 char
323 new_format[MagickPathExtent];
324
325 size_t
326 len;
327
328 MagickBooleanType
329 status;
330
331 va_list
332 operands;
333
334 /* HACK - append location to format string.
335 The better way would be add more arguments to to the 'va' oparands
336 list, but that does not appear to be possible! So we do some
337 pre-formating of the location info here.
338 */
339 (void) CopyMagickString(new_format,format,MagickPathExtent);
340 (void) ConcatenateMagickString(new_format," ",MagickPathExtent);
341
342 len=strlen(new_format);
343 (void) FormatLocaleString(new_format+len,MagickPathExtent-len,
344 cli_wand->location,cli_wand->filename,cli_wand->line,cli_wand->column);
345
346 va_start(operands,format);
347 status=ThrowMagickExceptionList(cli_wand->wand.exception,magick_module,
348 function,line,severity,tag,new_format,operands);
349 va_end(operands);
350 return(status);
351 }
352