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