Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %        EEEEE  X   X   CCCC  EEEEE  PPPP  TTTTT  IIIII   OOO   N   N         %
      7 %        E       X X   C      E      P   P   T      I    O   O  NN  N         %
      8 %        EEE      X    C      EEE    PPPP    T      I    O   O  N N N         %
      9 %        E       X X   C      E      P       T      I    O   O  N  NN         %
     10 %        EEEEE   X  X   CCCC  EEEEE  P       T    IIIII   OOO   N   N         %
     11 %                                                                             %
     12 %                                                                             %
     13 %                        MagickCore Exception Methods                         %
     14 %                                                                             %
     15 %                             Software Design                                 %
     16 %                                  Cristy                                     %
     17 %                                July 1993                                    %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    https://imagemagick.org/script/license.php                               %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 %
     38 */
     39 
     40 /*
     42   Include declarations.
     43 */
     44 #include "MagickCore/studio.h"
     45 #include "MagickCore/client.h"
     46 #include "MagickCore/exception.h"
     47 #include "MagickCore/exception-private.h"
     48 #include "MagickCore/linked-list.h"
     49 #include "MagickCore/locale_.h"
     50 #include "MagickCore/log.h"
     51 #include "MagickCore/magick.h"
     52 #include "MagickCore/memory_.h"
     53 #include "MagickCore/memory-private.h"
     54 #include "MagickCore/string_.h"
     55 #include "MagickCore/utility.h"
     56 #include "MagickCore/utility-private.h"
     57 
     58 /*
     60   Define declarations.
     61 */
     62 #define MaxExceptionList  64
     63 
     64 /*
     66   Forward declarations.
     67 */
     68 #if defined(__cplusplus) || defined(c_plusplus)
     69 extern "C" {
     70 #endif
     71 
     72 static void
     73   DefaultErrorHandler(const ExceptionType,const char *,const char *),
     74   DefaultFatalErrorHandler(const ExceptionType,const char *,const char *),
     75   DefaultWarningHandler(const ExceptionType,const char *,const char *);
     76 
     77 #if defined(__cplusplus) || defined(c_plusplus)
     78 }
     79 #endif
     80 
     81 /*
     83   Global declarations.
     84 */
     85 static ErrorHandler
     86   error_handler = DefaultErrorHandler;
     87 
     88 static FatalErrorHandler
     89   fatal_error_handler = DefaultFatalErrorHandler;
     90 
     91 static WarningHandler
     92   warning_handler = DefaultWarningHandler;
     93 
     94 /*
     96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     97 %                                                                             %
     98 %                                                                             %
     99 %                                                                             %
    100 %   A c q u i r e E x c e p t i o n I n f o                                   %
    101 %                                                                             %
    102 %                                                                             %
    103 %                                                                             %
    104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    105 %
    106 %  AcquireExceptionInfo() allocates the ExceptionInfo structure.
    107 %
    108 %  The format of the AcquireExceptionInfo method is:
    109 %
    110 %      ExceptionInfo *AcquireExceptionInfo(void)
    111 %
    112 */
    113 MagickExport ExceptionInfo *AcquireExceptionInfo(void)
    114 {
    115   ExceptionInfo
    116     *exception;
    117 
    118   exception=(ExceptionInfo *) AcquireCriticalMemory(sizeof(*exception));
    119   InitializeExceptionInfo(exception);
    120   exception->relinquish=MagickTrue;
    121   return(exception);
    122 }
    123 
    124 /*l
    126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    127 %                                                                             %
    128 %                                                                             %
    129 %                                                                             %
    130 %   C l e a r M a g i c k E x c e p t i o n                                   %
    131 %                                                                             %
    132 %                                                                             %
    133 %                                                                             %
    134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    135 %
    136 %  ClearMagickException() clears any exception that may not have been caught
    137 %  yet.
    138 %
    139 %  The format of the ClearMagickException method is:
    140 %
    141 %      ClearMagickException(ExceptionInfo *exception)
    142 %
    143 %  A description of each parameter follows:
    144 %
    145 %    o exception: the exception info.
    146 %
    147 */
    148 
    149 static void *DestroyExceptionElement(void *exception)
    150 {
    151   register ExceptionInfo
    152     *p;
    153 
    154   p=(ExceptionInfo *) exception;
    155   if (p->reason != (char *) NULL)
    156     p->reason=DestroyString(p->reason);
    157   if (p->description != (char *) NULL)
    158     p->description=DestroyString(p->description);
    159   p=(ExceptionInfo *) RelinquishMagickMemory(p);
    160   return((void *) NULL);
    161 }
    162 
    163 MagickExport void ClearMagickException(ExceptionInfo *exception)
    164 {
    165   assert(exception != (ExceptionInfo *) NULL);
    166   assert(exception->signature == MagickCoreSignature);
    167   if (exception->exceptions == (void *) NULL)
    168     return;
    169   LockSemaphoreInfo(exception->semaphore);
    170   ClearLinkedList((LinkedListInfo *) exception->exceptions,
    171     DestroyExceptionElement);
    172   exception->severity=UndefinedException;
    173   exception->reason=(char *) NULL;
    174   exception->description=(char *) NULL;
    175   UnlockSemaphoreInfo(exception->semaphore);
    176   errno=0;
    177 }
    178 
    179 /*
    181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    182 %                                                                             %
    183 %                                                                             %
    184 %                                                                             %
    185 %   C a t c h E x c e p t i o n                                               %
    186 %                                                                             %
    187 %                                                                             %
    188 %                                                                             %
    189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    190 %
    191 %  CatchException() returns if no exceptions is found otherwise it reports
    192 %  the exception as a warning, error, or fatal depending on the severity.
    193 %
    194 %  The format of the CatchException method is:
    195 %
    196 %      CatchException(ExceptionInfo *exception)
    197 %
    198 %  A description of each parameter follows:
    199 %
    200 %    o exception: the exception info.
    201 %
    202 */
    203 MagickExport void CatchException(ExceptionInfo *exception)
    204 {
    205   LinkedListInfo
    206     *exceptions;
    207 
    208   register const ExceptionInfo
    209     *p;
    210 
    211   ssize_t
    212     i;
    213 
    214   assert(exception != (ExceptionInfo *) NULL);
    215   assert(exception->signature == MagickCoreSignature);
    216   if (exception->exceptions  == (void *) NULL)
    217     return;
    218   LockSemaphoreInfo(exception->semaphore);
    219   exceptions=(LinkedListInfo *) exception->exceptions;
    220   ResetLinkedListIterator(exceptions);
    221   p=(const ExceptionInfo *) GetNextValueInLinkedList(exceptions);
    222   for (i=0; p != (const ExceptionInfo *) NULL; i++)
    223   {
    224     if ((p->severity >= WarningException) && (p->severity < ErrorException))
    225       MagickWarning(p->severity,p->reason,p->description);
    226     if ((p->severity >= ErrorException) && (p->severity < FatalErrorException))
    227       MagickError(p->severity,p->reason,p->description);
    228     if (p->severity >= FatalErrorException)
    229       MagickFatalError(p->severity,p->reason,p->description);
    230     p=(const ExceptionInfo *) GetNextValueInLinkedList(exceptions);
    231   }
    232   UnlockSemaphoreInfo(exception->semaphore);
    233   ClearMagickException(exception);
    234 }
    235 
    236 /*
    238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    239 %                                                                             %
    240 %                                                                             %
    241 %                                                                             %
    242 %   C l o n e E x c e p t i o n I n f o                                       %
    243 %                                                                             %
    244 %                                                                             %
    245 %                                                                             %
    246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    247 %
    248 %  CloneExceptionInfo() clones the ExceptionInfo structure.
    249 %
    250 %  The format of the CloneExceptionInfo method is:
    251 %
    252 %      ExceptionInfo *CloneException(ExceptionInfo *exception)
    253 %
    254 %  A description of each parameter follows:
    255 %
    256 %    o exception: the exception info.
    257 %
    258 */
    259 MagickExport ExceptionInfo *CloneExceptionInfo(ExceptionInfo *exception)
    260 {
    261   ExceptionInfo
    262     *clone_exception;
    263 
    264   clone_exception=(ExceptionInfo *) AcquireCriticalMemory(sizeof(*exception));
    265   InitializeExceptionInfo(clone_exception);
    266   InheritException(clone_exception,exception);
    267   clone_exception->relinquish=MagickTrue;
    268   return(clone_exception);
    269 }
    270 
    271 /*
    273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    274 %                                                                             %
    275 %                                                                             %
    276 %                                                                             %
    277 +   D e f a u l t E r r o r H a n d l e r                                     %
    278 %                                                                             %
    279 %                                                                             %
    280 %                                                                             %
    281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    282 %
    283 %  DefaultErrorHandler() displays an error reason.
    284 %
    285 %  The format of the DefaultErrorHandler method is:
    286 %
    287 %      void MagickError(const ExceptionType severity,const char *reason,
    288 %        const char *description)
    289 %
    290 %  A description of each parameter follows:
    291 %
    292 %    o severity: Specifies the numeric error category.
    293 %
    294 %    o reason: Specifies the reason to display before terminating the
    295 %      program.
    296 %
    297 %    o description: Specifies any description to the reason.
    298 %
    299 */
    300 static void DefaultErrorHandler(const ExceptionType magick_unused(severity),
    301   const char *reason,const char *description)
    302 {
    303   magick_unreferenced(severity);
    304 
    305   if (reason == (char *) NULL)
    306     return;
    307   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
    308   if (description != (char *) NULL)
    309     (void) FormatLocaleFile(stderr," (%s)",description);
    310   (void) FormatLocaleFile(stderr,".\n");
    311   (void) fflush(stderr);
    312 }
    313 
    314 /*
    316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    317 %                                                                             %
    318 %                                                                             %
    319 %                                                                             %
    320 +   D e f a u l t F a t a l E r r o r H a n d l e r                           %
    321 %                                                                             %
    322 %                                                                             %
    323 %                                                                             %
    324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    325 %
    326 %  DefaultFatalErrorHandler() displays an error reason and then terminates the
    327 %  program.
    328 %
    329 %  The format of the DefaultFatalErrorHandler method is:
    330 %
    331 %      void MagickFatalError(const ExceptionType severity,const char *reason,
    332 %        const char *description)
    333 %
    334 %  A description of each parameter follows:
    335 %
    336 %    o severity: Specifies the numeric error category.
    337 %
    338 %    o reason: Specifies the reason to display before terminating the program.
    339 %
    340 %    o description: Specifies any description to the reason.
    341 %
    342 */
    343 static void DefaultFatalErrorHandler(const ExceptionType severity,
    344   const char *reason,const char *description)
    345 {
    346   if (reason == (char *) NULL)
    347     return;
    348   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
    349   if (description != (char *) NULL)
    350     (void) FormatLocaleFile(stderr," (%s)",description);
    351   (void) FormatLocaleFile(stderr,".\n");
    352   (void) fflush(stderr);
    353   MagickCoreTerminus();
    354   exit((int) (severity-FatalErrorException)+1);
    355 }
    356 
    357 /*
    359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    360 %                                                                             %
    361 %                                                                             %
    362 %                                                                             %
    363 +   D e f a u l t W a r n i n g H a n d l e r                                 %
    364 %                                                                             %
    365 %                                                                             %
    366 %                                                                             %
    367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    368 %
    369 %  DefaultWarningHandler() displays a warning reason.
    370 %
    371 %  The format of the DefaultWarningHandler method is:
    372 %
    373 %      void DefaultWarningHandler(const ExceptionType severity,
    374 %        const char *reason,const char *description)
    375 %
    376 %  A description of each parameter follows:
    377 %
    378 %    o severity: Specifies the numeric warning category.
    379 %
    380 %    o reason: Specifies the reason to display before terminating the
    381 %      program.
    382 %
    383 %    o description: Specifies any description to the reason.
    384 %
    385 */
    386 static void DefaultWarningHandler(const ExceptionType magick_unused(severity),
    387   const char *reason,const char *description)
    388 {
    389   magick_unreferenced(severity);
    390 
    391   if (reason == (char *) NULL)
    392     return;
    393   (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
    394   if (description != (char *) NULL)
    395     (void) FormatLocaleFile(stderr," (%s)",description);
    396   (void) FormatLocaleFile(stderr,".\n");
    397   (void) fflush(stderr);
    398 }
    399 
    400 /*
    402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    403 %                                                                             %
    404 %                                                                             %
    405 %                                                                             %
    406 %   D e s t r o y E x c e p t i o n I n f o                                   %
    407 %                                                                             %
    408 %                                                                             %
    409 %                                                                             %
    410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    411 %
    412 %  DestroyExceptionInfo() deallocates memory associated with an exception.
    413 %
    414 %  The format of the DestroyExceptionInfo method is:
    415 %
    416 %      ExceptionInfo *DestroyExceptionInfo(ExceptionInfo *exception)
    417 %
    418 %  A description of each parameter follows:
    419 %
    420 %    o exception: the exception info.
    421 %
    422 */
    423 MagickExport ExceptionInfo *DestroyExceptionInfo(ExceptionInfo *exception)
    424 {
    425   MagickBooleanType
    426     relinquish;
    427 
    428   assert(exception != (ExceptionInfo *) NULL);
    429   assert(exception->signature == MagickCoreSignature);
    430   if (exception->semaphore == (SemaphoreInfo *) NULL)
    431     ActivateSemaphoreInfo(&exception->semaphore);
    432   LockSemaphoreInfo(exception->semaphore);
    433   exception->severity=UndefinedException;
    434   if (exception->relinquish != MagickFalse)
    435     {
    436       exception->signature=(~MagickCoreSignature);
    437       if (exception->exceptions != (void *) NULL)
    438         exception->exceptions=(void *) DestroyLinkedList((LinkedListInfo *)
    439           exception->exceptions,DestroyExceptionElement);
    440     }
    441   else
    442     if (exception->exceptions != (void *) NULL)
    443       ClearLinkedList((LinkedListInfo *) exception->exceptions,
    444         DestroyExceptionElement);
    445   relinquish=exception->relinquish;
    446   UnlockSemaphoreInfo(exception->semaphore);
    447   if (relinquish != MagickFalse)
    448     {
    449       RelinquishSemaphoreInfo(&exception->semaphore);
    450       exception=(ExceptionInfo *) RelinquishMagickMemory(exception);
    451     }
    452   return(exception);
    453 }
    454 
    455 /*
    457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    458 %                                                                             %
    459 %                                                                             %
    460 %                                                                             %
    461 %   G e t E x c e p t i o n M e s s a g e                                     %
    462 %                                                                             %
    463 %                                                                             %
    464 %                                                                             %
    465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    466 %
    467 %  GetExceptionMessage() returns the error message defined by the specified
    468 %  error code.
    469 %
    470 %  The format of the GetExceptionMessage method is:
    471 %
    472 %      char *GetExceptionMessage(const int error)
    473 %
    474 %  A description of each parameter follows:
    475 %
    476 %    o error: the error code.
    477 %
    478 */
    479 MagickExport char *GetExceptionMessage(const int error)
    480 {
    481   char
    482     exception[MagickPathExtent];
    483 
    484   *exception='\0';
    485 #if defined(MAGICKCORE_HAVE_STRERROR_R)
    486 #if !defined(MAGICKCORE_STRERROR_R_CHAR_P)
    487   (void) strerror_r(error,exception,sizeof(exception));
    488 #else
    489   (void) CopyMagickString(exception,strerror_r(error,exception,
    490     sizeof(exception)),sizeof(exception));
    491 #endif
    492 #else
    493   (void) CopyMagickString(exception,strerror(error),sizeof(exception));
    494 #endif
    495   return(ConstantString(exception));
    496 }
    497 
    498 /*
    500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    501 %                                                                             %
    502 %                                                                             %
    503 %                                                                             %
    504 %   G e t L o c a l e E x c e p t i o n M e s s a g e                         %
    505 %                                                                             %
    506 %                                                                             %
    507 %                                                                             %
    508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    509 %
    510 %  GetLocaleExceptionMessage() converts a enumerated exception severity and tag
    511 %  to a message in the current locale.
    512 %
    513 %  The format of the GetLocaleExceptionMessage method is:
    514 %
    515 %      const char *GetLocaleExceptionMessage(const ExceptionType severity,
    516 %        const char *tag)
    517 %
    518 %  A description of each parameter follows:
    519 %
    520 %    o severity: the severity of the exception.
    521 %
    522 %    o tag: the message tag.
    523 %
    524 */
    525 
    526 static const char *ExceptionSeverityToTag(const ExceptionType severity)
    527 {
    528   switch (severity)
    529   {
    530     case ResourceLimitWarning: return("Resource/Limit/Warning/");
    531     case TypeWarning: return("Type/Warning/");
    532     case OptionWarning: return("Option/Warning/");
    533     case DelegateWarning: return("Delegate/Warning/");
    534     case MissingDelegateWarning: return("Missing/Delegate/Warning/");
    535     case CorruptImageWarning: return("Corrupt/Image/Warning/");
    536     case FileOpenWarning: return("File/Open/Warning/");
    537     case BlobWarning: return("Blob/Warning/");
    538     case StreamWarning: return("Stream/Warning/");
    539     case CacheWarning: return("Cache/Warning/");
    540     case CoderWarning: return("Coder/Warning/");
    541     case FilterWarning: return("Filter/Warning/");
    542     case ModuleWarning: return("Module/Warning/");
    543     case DrawWarning: return("Draw/Warning/");
    544     case ImageWarning: return("Image/Warning/");
    545     case WandWarning: return("Wand/Warning/");
    546     case XServerWarning: return("XServer/Warning/");
    547     case MonitorWarning: return("Monitor/Warning/");
    548     case RegistryWarning: return("Registry/Warning/");
    549     case ConfigureWarning: return("Configure/Warning/");
    550     case PolicyWarning: return("Policy/Warning/");
    551     case ResourceLimitError: return("Resource/Limit/Error/");
    552     case TypeError: return("Type/Error/");
    553     case OptionError: return("Option/Error/");
    554     case DelegateError: return("Delegate/Error/");
    555     case MissingDelegateError: return("Missing/Delegate/Error/");
    556     case CorruptImageError: return("Corrupt/Image/Error/");
    557     case FileOpenError: return("File/Open/Error/");
    558     case BlobError: return("Blob/Error/");
    559     case StreamError: return("Stream/Error/");
    560     case CacheError: return("Cache/Error/");
    561     case CoderError: return("Coder/Error/");
    562     case FilterError: return("Filter/Error/");
    563     case ModuleError: return("Module/Error/");
    564     case DrawError: return("Draw/Error/");
    565     case ImageError: return("Image/Error/");
    566     case WandError: return("Wand/Error/");
    567     case XServerError: return("XServer/Error/");
    568     case MonitorError: return("Monitor/Error/");
    569     case RegistryError: return("Registry/Error/");
    570     case ConfigureError: return("Configure/Error/");
    571     case PolicyError: return("Policy/Error/");
    572     case ResourceLimitFatalError: return("Resource/Limit/FatalError/");
    573     case TypeFatalError: return("Type/FatalError/");
    574     case OptionFatalError: return("Option/FatalError/");
    575     case DelegateFatalError: return("Delegate/FatalError/");
    576     case MissingDelegateFatalError: return("Missing/Delegate/FatalError/");
    577     case CorruptImageFatalError: return("Corrupt/Image/FatalError/");
    578     case FileOpenFatalError: return("File/Open/FatalError/");
    579     case BlobFatalError: return("Blob/FatalError/");
    580     case StreamFatalError: return("Stream/FatalError/");
    581     case CacheFatalError: return("Cache/FatalError/");
    582     case CoderFatalError: return("Coder/FatalError/");
    583     case FilterFatalError: return("Filter/FatalError/");
    584     case ModuleFatalError: return("Module/FatalError/");
    585     case DrawFatalError: return("Draw/FatalError/");
    586     case ImageFatalError: return("Image/FatalError/");
    587     case WandFatalError: return("Wand/FatalError/");
    588     case XServerFatalError: return("XServer/FatalError/");
    589     case MonitorFatalError: return("Monitor/FatalError/");
    590     case RegistryFatalError: return("Registry/FatalError/");
    591     case ConfigureFatalError: return("Configure/FatalError/");
    592     case PolicyFatalError: return("Policy/FatalError/");
    593     default: break;
    594   }
    595   return("");
    596 }
    597 
    598 MagickExport const char *GetLocaleExceptionMessage(const ExceptionType severity,
    599   const char *tag)
    600 {
    601   char
    602     message[MagickPathExtent];
    603 
    604   const char
    605     *locale_message;
    606 
    607   assert(tag != (const char *) NULL);
    608   (void) FormatLocaleString(message,MagickPathExtent,"Exception/%s%s",
    609     ExceptionSeverityToTag(severity),tag);
    610   locale_message=GetLocaleMessage(message);
    611   if (locale_message == (const char *) NULL)
    612     return(tag);
    613   if (locale_message == message)
    614     return(tag);
    615   return(locale_message);
    616 }
    617 
    618 /*
    620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    621 %                                                                             %
    622 %                                                                             %
    623 %                                                                             %
    624 %   I n h e r i t E x c e p t i o n                                           %
    625 %                                                                             %
    626 %                                                                             %
    627 %                                                                             %
    628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    629 %
    630 %  InheritException() inherits an exception from a related exception.
    631 %
    632 %  The format of the InheritException method is:
    633 %
    634 %      InheritException(ExceptionInfo *exception,const ExceptionInfo *relative)
    635 %
    636 %  A description of each parameter follows:
    637 %
    638 %    o exception: the exception info.
    639 %
    640 %    o relative: the related exception info.
    641 %
    642 */
    643 MagickExport void InheritException(ExceptionInfo *exception,
    644   const ExceptionInfo *relative)
    645 {
    646   register const ExceptionInfo
    647     *p;
    648 
    649   assert(exception != (ExceptionInfo *) NULL);
    650   assert(exception->signature == MagickCoreSignature);
    651   assert(relative != (ExceptionInfo *) NULL);
    652   assert(relative->signature == MagickCoreSignature);
    653   assert(exception != relative);
    654   if (relative->exceptions == (void *) NULL)
    655     return;
    656   LockSemaphoreInfo(relative->semaphore);
    657   ResetLinkedListIterator((LinkedListInfo *) relative->exceptions);
    658   p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
    659     relative->exceptions);
    660   while (p != (const ExceptionInfo *) NULL)
    661   {
    662     (void) ThrowException(exception,p->severity,p->reason,p->description);
    663     p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
    664       relative->exceptions);
    665   }
    666   UnlockSemaphoreInfo(relative->semaphore);
    667 }
    668 
    669 /*
    671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    672 %                                                                             %
    673 %                                                                             %
    674 %                                                                             %
    675 %   I n i t i a l i z e t E x c e p t i o n I n f o                           %
    676 %                                                                             %
    677 %                                                                             %
    678 %                                                                             %
    679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    680 %
    681 %  InitializeExceptionInfo() initializes an exception to default values.
    682 %
    683 %  The format of the InitializeExceptionInfo method is:
    684 %
    685 %      InitializeExceptionInfo(ExceptionInfo *exception)
    686 %
    687 %  A description of each parameter follows:
    688 %
    689 %    o exception: the exception info.
    690 %
    691 */
    692 MagickPrivate void InitializeExceptionInfo(ExceptionInfo *exception)
    693 {
    694   assert(exception != (ExceptionInfo *) NULL);
    695   (void) memset(exception,0,sizeof(*exception));
    696   exception->severity=UndefinedException;
    697   exception->exceptions=(void *) NewLinkedList(0);
    698   exception->semaphore=AcquireSemaphoreInfo();
    699   exception->signature=MagickCoreSignature;
    700 }
    701 
    702 /*
    704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    705 %                                                                             %
    706 %                                                                             %
    707 %                                                                             %
    708 %   M a g i c k E r r o r                                                     %
    709 %                                                                             %
    710 %                                                                             %
    711 %                                                                             %
    712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    713 %
    714 %  MagickError() calls the exception handler methods with an error reason.
    715 %
    716 %  The format of the MagickError method is:
    717 %
    718 %      void MagickError(const ExceptionType error,const char *reason,
    719 %        const char *description)
    720 %
    721 %  A description of each parameter follows:
    722 %
    723 %    o exception: Specifies the numeric error category.
    724 %
    725 %    o reason: Specifies the reason to display before terminating the
    726 %      program.
    727 %
    728 %    o description: Specifies any description to the reason.
    729 %
    730 */
    731 MagickExport void MagickError(const ExceptionType error,const char *reason,
    732   const char *description)
    733 {
    734   if (error_handler != (ErrorHandler) NULL)
    735     (*error_handler)(error,reason,description);
    736 }
    737 
    738 /*
    740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    741 %                                                                             %
    742 %                                                                             %
    743 %                                                                             %
    744 %   M a g i c k F a t al E r r o r                                            %
    745 %                                                                             %
    746 %                                                                             %
    747 %                                                                             %
    748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    749 %
    750 %  MagickFatalError() calls the fatal exception handler methods with an error
    751 %  reason.
    752 %
    753 %  The format of the MagickError method is:
    754 %
    755 %      void MagickFatalError(const ExceptionType error,const char *reason,
    756 %        const char *description)
    757 %
    758 %  A description of each parameter follows:
    759 %
    760 %    o exception: Specifies the numeric error category.
    761 %
    762 %    o reason: Specifies the reason to display before terminating the
    763 %      program.
    764 %
    765 %    o description: Specifies any description to the reason.
    766 %
    767 */
    768 MagickExport void MagickFatalError(const ExceptionType error,const char *reason,
    769   const char *description)
    770 {
    771   if (fatal_error_handler != (ErrorHandler) NULL)
    772     (*fatal_error_handler)(error,reason,description);
    773 }
    774 
    775 /*
    777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    778 %                                                                             %
    779 %                                                                             %
    780 %                                                                             %
    781 %   M a g i c k W a r n i n g                                                 %
    782 %                                                                             %
    783 %                                                                             %
    784 %                                                                             %
    785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    786 %
    787 %  MagickWarning() calls the warning handler methods with a warning reason.
    788 %
    789 %  The format of the MagickWarning method is:
    790 %
    791 %      void MagickWarning(const ExceptionType warning,const char *reason,
    792 %        const char *description)
    793 %
    794 %  A description of each parameter follows:
    795 %
    796 %    o warning: the warning severity.
    797 %
    798 %    o reason: Define the reason for the warning.
    799 %
    800 %    o description: Describe the warning.
    801 %
    802 */
    803 MagickExport void MagickWarning(const ExceptionType warning,const char *reason,
    804   const char *description)
    805 {
    806   if (warning_handler != (WarningHandler) NULL)
    807     (*warning_handler)(warning,reason,description);
    808 }
    809 
    810 /*
    812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    813 %                                                                             %
    814 %                                                                             %
    815 %                                                                             %
    816 %   S e t E r r o r H a n d l e r                                             %
    817 %                                                                             %
    818 %                                                                             %
    819 %                                                                             %
    820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    821 %
    822 %  SetErrorHandler() sets the exception handler to the specified method
    823 %  and returns the previous exception handler.
    824 %
    825 %  The format of the SetErrorHandler method is:
    826 %
    827 %      ErrorHandler SetErrorHandler(ErrorHandler handler)
    828 %
    829 %  A description of each parameter follows:
    830 %
    831 %    o handler: the method to handle errors.
    832 %
    833 */
    834 MagickExport ErrorHandler SetErrorHandler(ErrorHandler handler)
    835 {
    836   ErrorHandler
    837     previous_handler;
    838 
    839   previous_handler=error_handler;
    840   error_handler=handler;
    841   return(previous_handler);
    842 }
    843 
    844 /*
    846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    847 %                                                                             %
    848 %                                                                             %
    849 %                                                                             %
    850 %   S e t F a t a l E r r o r H a n d l e r                                   %
    851 %                                                                             %
    852 %                                                                             %
    853 %                                                                             %
    854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    855 %
    856 %  SetFatalErrorHandler() sets the fatal exception handler to the specified
    857 %  method and returns the previous fatal exception handler.
    858 %
    859 %  The format of the SetErrorHandler method is:
    860 %
    861 %      ErrorHandler SetErrorHandler(ErrorHandler handler)
    862 %
    863 %  A description of each parameter follows:
    864 %
    865 %    o handler: the method to handle errors.
    866 %
    867 */
    868 MagickExport FatalErrorHandler SetFatalErrorHandler(FatalErrorHandler handler)
    869 {
    870   FatalErrorHandler
    871     previous_handler;
    872 
    873   previous_handler=fatal_error_handler;
    874   fatal_error_handler=handler;
    875   return(previous_handler);
    876 }
    877 
    878 /*
    880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    881 %                                                                             %
    882 %                                                                             %
    883 %                                                                             %
    884 %   S e t W a r n i n g H a n d l e r                                         %
    885 %                                                                             %
    886 %                                                                             %
    887 %                                                                             %
    888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    889 %
    890 %  SetWarningHandler() sets the warning handler to the specified method
    891 %  and returns the previous warning handler.
    892 %
    893 %  The format of the SetWarningHandler method is:
    894 %
    895 %      ErrorHandler SetWarningHandler(ErrorHandler handler)
    896 %
    897 %  A description of each parameter follows:
    898 %
    899 %    o handler: the method to handle warnings.
    900 %
    901 */
    902 MagickExport WarningHandler SetWarningHandler(WarningHandler handler)
    903 {
    904   WarningHandler
    905     previous_handler;
    906 
    907   previous_handler=warning_handler;
    908   warning_handler=handler;
    909   return(previous_handler);
    910 }
    911 
    912 /*
    914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    915 %                                                                             %
    916 %                                                                             %
    917 %                                                                             %
    918 %   T h r o w E x c e p t i o n                                               %
    919 %                                                                             %
    920 %                                                                             %
    921 %                                                                             %
    922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    923 %
    924 %  ThrowException() throws an exception with the specified severity code,
    925 %  reason, and optional description.
    926 %
    927 %  The format of the ThrowException method is:
    928 %
    929 %      MagickBooleanType ThrowException(ExceptionInfo *exception,
    930 %        const ExceptionType severity,const char *reason,
    931 %        const char *description)
    932 %
    933 %  A description of each parameter follows:
    934 %
    935 %    o exception: the exception info.
    936 %
    937 %    o severity: the severity of the exception.
    938 %
    939 %    o reason: the reason for the exception.
    940 %
    941 %    o description: the exception description.
    942 %
    943 */
    944 MagickExport MagickBooleanType ThrowException(ExceptionInfo *exception,
    945   const ExceptionType severity,const char *reason,const char *description)
    946 {
    947   LinkedListInfo
    948     *exceptions;
    949 
    950   register ExceptionInfo
    951     *p;
    952 
    953   assert(exception != (ExceptionInfo *) NULL);
    954   assert(exception->signature == MagickCoreSignature);
    955   LockSemaphoreInfo(exception->semaphore);
    956   exceptions=(LinkedListInfo *) exception->exceptions;
    957   if (GetNumberOfElementsInLinkedList(exceptions) > MaxExceptionList)
    958     {
    959       if (severity < ErrorException)
    960         {
    961           UnlockSemaphoreInfo(exception->semaphore);
    962           return(MagickTrue);
    963         }
    964       p=(ExceptionInfo *) GetLastValueInLinkedList(exceptions);
    965       if (p->severity >= ErrorException)
    966         {
    967           UnlockSemaphoreInfo(exception->semaphore);
    968           return(MagickTrue);
    969         }
    970     }
    971   p=(ExceptionInfo *) GetLastValueInLinkedList(exceptions);
    972   if ((p != (ExceptionInfo *) NULL) && (p->severity == severity) &&
    973       (LocaleCompare(exception->reason,reason) == 0) &&
    974       (LocaleCompare(exception->description,description) == 0))
    975     {
    976       UnlockSemaphoreInfo(exception->semaphore);
    977       return(MagickTrue);
    978     }
    979   p=(ExceptionInfo *) AcquireMagickMemory(sizeof(*p));
    980   if (p == (ExceptionInfo *) NULL)
    981     {
    982       UnlockSemaphoreInfo(exception->semaphore);
    983       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    984     }
    985   (void) memset(p,0,sizeof(*p));
    986   p->severity=severity;
    987   if (reason != (const char *) NULL)
    988     p->reason=ConstantString(reason);
    989   if (description != (const char *) NULL)
    990     p->description=ConstantString(description);
    991   p->signature=MagickCoreSignature;
    992   (void) AppendValueToLinkedList(exceptions,p);
    993   if (p->severity > exception->severity)
    994     {
    995       exception->severity=p->severity;
    996       exception->reason=p->reason;
    997       exception->description=p->description;
    998     }
    999   UnlockSemaphoreInfo(exception->semaphore);
   1000   if (GetNumberOfElementsInLinkedList(exceptions) == MaxExceptionList)
   1001     (void) ThrowMagickException(exception,GetMagickModule(),
   1002       ResourceLimitWarning,"TooManyExceptions",
   1003       "(exception processing is suspended)");
   1004   return(MagickTrue);
   1005 }
   1006 
   1007 /*
   1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1010 %                                                                             %
   1011 %                                                                             %
   1012 %                                                                             %
   1013 %   T h r o w M a g i c k E x c e p t i o n                                   %
   1014 %                                                                             %
   1015 %                                                                             %
   1016 %                                                                             %
   1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1018 %
   1019 %  ThrowMagickException logs an exception as determined by the log
   1020 %  configuration file.  If an error occurs, MagickFalse is returned
   1021 %  otherwise MagickTrue.
   1022 %
   1023 %  The format of the ThrowMagickException method is:
   1024 %
   1025 %      MagickBooleanType ThrowFileException(ExceptionInfo *exception,
   1026 %        const char *module,const char *function,const size_t line,
   1027 %        const ExceptionType severity,const char *tag,const char *format,...)
   1028 %
   1029 %  A description of each parameter follows:
   1030 %
   1031 %    o exception: the exception info.
   1032 %
   1033 %    o filename: the source module filename.
   1034 %
   1035 %    o function: the function name.
   1036 %
   1037 %    o line: the line number of the source module.
   1038 %
   1039 %    o severity: Specifies the numeric error category.
   1040 %
   1041 %    o tag: the locale tag.
   1042 %
   1043 %    o format: the output format.
   1044 %
   1045 */
   1046 
   1047 MagickExport MagickBooleanType ThrowMagickExceptionList(
   1048   ExceptionInfo *exception,const char *module,const char *function,
   1049   const size_t line,const ExceptionType severity,const char *tag,
   1050   const char *format,va_list operands)
   1051 {
   1052   char
   1053     message[MagickPathExtent],
   1054     path[MagickPathExtent],
   1055     reason[MagickPathExtent];
   1056 
   1057   const char
   1058     *locale,
   1059     *type;
   1060 
   1061   int
   1062     n;
   1063 
   1064   MagickBooleanType
   1065     status;
   1066 
   1067   size_t
   1068     length;
   1069 
   1070   assert(exception != (ExceptionInfo *) NULL);
   1071   assert(exception->signature == MagickCoreSignature);
   1072   locale=GetLocaleExceptionMessage(severity,tag);
   1073   (void) CopyMagickString(reason,locale,MagickPathExtent);
   1074   (void) ConcatenateMagickString(reason," ",MagickPathExtent);
   1075   length=strlen(reason);
   1076 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
   1077   n=vsnprintf(reason+length,MagickPathExtent-length,format,operands);
   1078 #else
   1079   n=vsprintf(reason+length,format,operands);
   1080 #endif
   1081   if (n < 0)
   1082     reason[MagickPathExtent-1]='\0';
   1083   status=LogMagickEvent(ExceptionEvent,module,function,line,"%s",reason);
   1084   GetPathComponent(module,TailPath,path);
   1085   type="undefined";
   1086   if ((severity >= WarningException) && (severity < ErrorException))
   1087     type="warning";
   1088   if ((severity >= ErrorException) && (severity < FatalErrorException))
   1089     type="error";
   1090   if (severity >= FatalErrorException)
   1091     type="fatal";
   1092   (void) FormatLocaleString(message,MagickPathExtent,"%s @ %s/%s/%s/%.20g",
   1093     reason,type,path,function,(double) line);
   1094   (void) ThrowException(exception,severity,message,(char *) NULL);
   1095   return(status);
   1096 }
   1097 
   1098 MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception,
   1099   const char *module,const char *function,const size_t line,
   1100   const ExceptionType severity,const char *tag,const char *format,...)
   1101 {
   1102   MagickBooleanType
   1103     status;
   1104 
   1105   va_list
   1106     operands;
   1107 
   1108   va_start(operands,format);
   1109   status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
   1110     format,operands);
   1111   va_end(operands);
   1112   return(status);
   1113 }
   1114