MagickCore  6.7.5
log.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                             L       OOO    GGGG                             %
00007 %                             L      O   O  G                                 %
00008 %                             L      O   O  G GG                              %
00009 %                             L      O   O  G   G                             %
00010 %                             LLLLL   OOO    GGG                              %
00011 %                                                                             %
00012 %                                                                             %
00013 %                             MagickCore Log Events                           %
00014 %                                                                             %
00015 %                               Software Design                               %
00016 %                                 John Cristy                                 %
00017 %                                September 2002                               %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "MagickCore/studio.h"
00043 #include "MagickCore/blob.h"
00044 #include "MagickCore/client.h"
00045 #include "MagickCore/configure.h"
00046 #include "MagickCore/configure-private.h"
00047 #include "MagickCore/exception.h"
00048 #include "MagickCore/exception-private.h"
00049 #include "MagickCore/hashmap.h"
00050 #include "MagickCore/log.h"
00051 #include "MagickCore/log-private.h"
00052 #include "MagickCore/memory_.h"
00053 #include "MagickCore/option.h"
00054 #include "MagickCore/semaphore.h"
00055 #include "MagickCore/timer.h"
00056 #include "MagickCore/string_.h"
00057 #include "MagickCore/string-private.h"
00058 #include "MagickCore/token.h"
00059 #include "MagickCore/thread_.h"
00060 #include "MagickCore/thread-private.h"
00061 #include "MagickCore/utility.h"
00062 #include "MagickCore/utility-private.h"
00063 #include "MagickCore/version.h"
00064 #include "MagickCore/xml-tree.h"
00065 
00066 /*
00067   Define declarations.
00068 */
00069 #define LogFilename  "log.xml"
00070 
00071 /*
00072   Typedef declarations.
00073 */
00074 typedef enum
00075 {
00076   UndefinedHandler = 0x0000,
00077   NoHandler = 0x0000,
00078   ConsoleHandler = 0x0001,
00079   StdoutHandler = 0x0002,
00080   StderrHandler = 0x0004,
00081   FileHandler = 0x0008,
00082   DebugHandler = 0x0010,
00083   EventHandler = 0x0020
00084 } LogHandlerType;
00085 
00086 typedef struct _EventInfo
00087 {
00088   char
00089     *name;
00090 
00091   LogEventType
00092     event;
00093 } EventInfo;
00094 
00095 typedef struct _HandlerInfo
00096 {
00097   const char
00098     *name;
00099 
00100   LogHandlerType
00101     handler;
00102 } HandlerInfo;
00103 
00104 struct _LogInfo
00105 {
00106   LogEventType
00107     event_mask;
00108 
00109   LogHandlerType
00110     handler_mask;
00111 
00112   char
00113     *path,
00114     *name,
00115     *filename,
00116     *format;
00117 
00118   size_t
00119     generations,
00120     limit;
00121 
00122   FILE
00123     *file;
00124 
00125   size_t
00126     generation;
00127 
00128   MagickBooleanType
00129     append,
00130     exempt,
00131     stealth;
00132 
00133   TimerInfo
00134     timer;
00135 
00136   size_t
00137     signature;
00138 };
00139 
00140 typedef struct _LogMapInfo
00141 {
00142   const LogEventType
00143     event_mask;
00144 
00145   const LogHandlerType
00146     handler_mask;
00147 
00148   const char
00149     *filename,
00150     *format;
00151 } LogMapInfo;
00152 
00153 /*
00154   Static declarations.
00155 */
00156 static const HandlerInfo
00157   LogHandlers[] =
00158   {
00159     { "console", ConsoleHandler },
00160     { "debug", DebugHandler },
00161     { "event", EventHandler },
00162     { "file", FileHandler },
00163     { "none", NoHandler },
00164     { "stderr", StderrHandler },
00165     { "stdout", StdoutHandler },
00166     { (char *) NULL, UndefinedHandler }
00167   };
00168 
00169 static const LogMapInfo
00170   LogMap[] =
00171   {
00172     { NoEvents, ConsoleHandler, "Magick-%d.log",
00173       "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n  %e" }
00174   };
00175 
00176 static char
00177   log_name[MaxTextExtent] = "Magick";
00178 
00179 static LinkedListInfo
00180   *log_list = (LinkedListInfo *) NULL;
00181 
00182 static SemaphoreInfo
00183   *log_semaphore = (SemaphoreInfo *) NULL;
00184 
00185 static volatile MagickBooleanType
00186   instantiate_log = MagickFalse;
00187 
00188 /*
00189   Forward declarations.
00190 */
00191 static LogHandlerType
00192   ParseLogHandlers(const char *);
00193 
00194 static LogInfo
00195   *GetLogInfo(const char *,ExceptionInfo *);
00196 
00197 static MagickBooleanType
00198   InitializeLogList(ExceptionInfo *),
00199   LoadLogLists(const char *,ExceptionInfo *);
00200 
00201 /*
00202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00203 %                                                                             %
00204 %                                                                             %
00205 %                                                                             %
00206 %   C l o s e M a g i c k L o g                                               %
00207 %                                                                             %
00208 %                                                                             %
00209 %                                                                             %
00210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00211 %
00212 %  CloseMagickLog() closes the Magick log.
00213 %
00214 %  The format of the CloseMagickLog method is:
00215 %
00216 %      CloseMagickLog(void)
00217 %
00218 */
00219 MagickExport void CloseMagickLog(void)
00220 {
00221   ExceptionInfo
00222     *exception;
00223 
00224   LogInfo
00225     *log_info;
00226 
00227   if (IsEventLogging() == MagickFalse)
00228     return;
00229   exception=AcquireExceptionInfo();
00230   log_info=GetLogInfo("*",exception);
00231   exception=DestroyExceptionInfo(exception);
00232   LockSemaphoreInfo(log_semaphore);
00233   if (log_info->file != (FILE *) NULL)
00234     {
00235       if (log_info->append == MagickFalse)
00236         (void) FormatLocaleFile(log_info->file,"</log>\n");
00237       (void) fclose(log_info->file);
00238       log_info->file=(FILE *) NULL;
00239     }
00240   UnlockSemaphoreInfo(log_semaphore);
00241 }
00242 
00243 /*
00244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00245 %                                                                             %
00246 %                                                                             %
00247 %                                                                             %
00248 +   G e t L o g I n f o                                                       %
00249 %                                                                             %
00250 %                                                                             %
00251 %                                                                             %
00252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00253 %
00254 %  GetLogInfo() searches the log list for the specified name and if found
00255 %  returns attributes for that log.
00256 %
00257 %  The format of the GetLogInfo method is:
00258 %
00259 %      LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
00260 %
00261 %  A description of each parameter follows:
00262 %
00263 %    o name: the log name.
00264 %
00265 %    o exception: return any errors or warnings in this structure.
00266 %
00267 */
00268 static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
00269 {
00270   register LogInfo
00271     *p;
00272 
00273   assert(exception != (ExceptionInfo *) NULL);
00274   if ((log_list == (LinkedListInfo *) NULL) || (instantiate_log == MagickFalse))
00275     if (InitializeLogList(exception) == MagickFalse)
00276       return((LogInfo *) NULL);
00277   if ((log_list == (LinkedListInfo *) NULL) ||
00278       (IsLinkedListEmpty(log_list) != MagickFalse))
00279     return((LogInfo *) NULL);
00280   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
00281     return((LogInfo *) GetValueFromLinkedList(log_list,0));
00282   /*
00283     Search for log tag.
00284   */
00285   LockSemaphoreInfo(log_semaphore);
00286   ResetLinkedListIterator(log_list);
00287   p=(LogInfo *) GetNextValueInLinkedList(log_list);
00288   while (p != (LogInfo *) NULL)
00289   {
00290     if (LocaleCompare(name,p->name) == 0)
00291       break;
00292     p=(LogInfo *) GetNextValueInLinkedList(log_list);
00293   }
00294   if (p != (LogInfo *) NULL)
00295     (void) InsertValueInLinkedList(log_list,0,
00296       RemoveElementByValueFromLinkedList(log_list,p));
00297   UnlockSemaphoreInfo(log_semaphore);
00298   return(p);
00299 }
00300 
00301 /*
00302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00303 %                                                                             %
00304 %                                                                             %
00305 %                                                                             %
00306 %   G e t L o g I n f o L i s t                                               %
00307 %                                                                             %
00308 %                                                                             %
00309 %                                                                             %
00310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00311 %
00312 %  GetLogInfoList() returns any logs that match the specified pattern.
00313 %
00314 %  The format of the GetLogInfoList function is:
00315 %
00316 %      const LogInfo **GetLogInfoList(const char *pattern,
00317 %        size_t *number_preferences,ExceptionInfo *exception)
00318 %
00319 %  A description of each parameter follows:
00320 %
00321 %    o pattern: Specifies a pointer to a text string containing a pattern.
00322 %
00323 %    o number_preferences:  This integer returns the number of logs in the list.
00324 %
00325 %    o exception: return any errors or warnings in this structure.
00326 %
00327 */
00328 #if defined(__cplusplus) || defined(c_plusplus)
00329 extern "C" {
00330 #endif
00331 
00332 static int LogInfoCompare(const void *x,const void *y)
00333 {
00334   const LogInfo
00335     **p,
00336     **q;
00337 
00338   p=(const LogInfo **) x,
00339   q=(const LogInfo **) y;
00340   if (LocaleCompare((*p)->path,(*q)->path) == 0)
00341     return(LocaleCompare((*p)->name,(*q)->name));
00342   return(LocaleCompare((*p)->path,(*q)->path));
00343 }
00344 
00345 #if defined(__cplusplus) || defined(c_plusplus)
00346 }
00347 #endif
00348 
00349 MagickExport const LogInfo **GetLogInfoList(const char *pattern,
00350   size_t *number_preferences,ExceptionInfo *exception)
00351 {
00352   const LogInfo
00353     **preferences;
00354 
00355   register const LogInfo
00356     *p;
00357 
00358   register ssize_t
00359     i;
00360 
00361   /*
00362     Allocate log list.
00363   */
00364   assert(pattern != (char *) NULL);
00365   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00366   assert(number_preferences != (size_t *) NULL);
00367   *number_preferences=0;
00368   p=GetLogInfo("*",exception);
00369   if (p == (const LogInfo *) NULL)
00370     return((const LogInfo **) NULL);
00371   preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
00372     GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00373   if (preferences == (const LogInfo **) NULL)
00374     return((const LogInfo **) NULL);
00375   /*
00376     Generate log list.
00377   */
00378   LockSemaphoreInfo(log_semaphore);
00379   ResetLinkedListIterator(log_list);
00380   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00381   for (i=0; p != (const LogInfo *) NULL; )
00382   {
00383     if ((p->stealth == MagickFalse) &&
00384         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
00385       preferences[i++]=p;
00386     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00387   }
00388   UnlockSemaphoreInfo(log_semaphore);
00389   qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
00390   preferences[i]=(LogInfo *) NULL;
00391   *number_preferences=(size_t) i;
00392   return(preferences);
00393 }
00394 
00395 /*
00396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00397 %                                                                             %
00398 %                                                                             %
00399 %                                                                             %
00400 %   G e t L o g L i s t                                                       %
00401 %                                                                             %
00402 %                                                                             %
00403 %                                                                             %
00404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00405 %
00406 %  GetLogList() returns any logs that match the specified pattern.
00407 %
00408 %  The format of the GetLogList function is:
00409 %
00410 %      char **GetLogList(const char *pattern,size_t *number_preferences,
00411 %        ExceptionInfo *exception)
00412 %
00413 %  A description of each parameter follows:
00414 %
00415 %    o pattern: Specifies a pointer to a text string containing a pattern.
00416 %
00417 %    o number_preferences:  This integer returns the number of logs in the list.
00418 %
00419 %    o exception: return any errors or warnings in this structure.
00420 %
00421 */
00422 
00423 #if defined(__cplusplus) || defined(c_plusplus)
00424 extern "C" {
00425 #endif
00426 
00427 static int LogCompare(const void *x,const void *y)
00428 {
00429   register const char
00430     **p,
00431     **q;
00432 
00433   p=(const char **) x;
00434   q=(const char **) y;
00435   return(LocaleCompare(*p,*q));
00436 }
00437 
00438 #if defined(__cplusplus) || defined(c_plusplus)
00439 }
00440 #endif
00441 
00442 MagickExport char **GetLogList(const char *pattern,
00443   size_t *number_preferences,ExceptionInfo *exception)
00444 {
00445   char
00446     **preferences;
00447 
00448   register const LogInfo
00449     *p;
00450 
00451   register ssize_t
00452     i;
00453 
00454   /*
00455     Allocate log list.
00456   */
00457   assert(pattern != (char *) NULL);
00458   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00459   assert(number_preferences != (size_t *) NULL);
00460   *number_preferences=0;
00461   p=GetLogInfo("*",exception);
00462   if (p == (const LogInfo *) NULL)
00463     return((char **) NULL);
00464   preferences=(char **) AcquireQuantumMemory((size_t)
00465     GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00466   if (preferences == (char **) NULL)
00467     return((char **) NULL);
00468   /*
00469     Generate log list.
00470   */
00471   LockSemaphoreInfo(log_semaphore);
00472   ResetLinkedListIterator(log_list);
00473   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00474   for (i=0; p != (const LogInfo *) NULL; )
00475   {
00476     if ((p->stealth == MagickFalse) &&
00477         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
00478       preferences[i++]=ConstantString(p->name);
00479     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00480   }
00481   UnlockSemaphoreInfo(log_semaphore);
00482   qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
00483   preferences[i]=(char *) NULL;
00484   *number_preferences=(size_t) i;
00485   return(preferences);
00486 }
00487 
00488 /*
00489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00490 %                                                                             %
00491 %                                                                             %
00492 %                                                                             %
00493 %   G e t L o g N a m e                                                       %
00494 %                                                                             %
00495 %                                                                             %
00496 %                                                                             %
00497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00498 %
00499 %  GetLogName() returns the current log name.
00500 %
00501 %  The format of the GetLogName method is:
00502 %
00503 %      const char *GetLogName(void)
00504 %
00505 */
00506 MagickExport const char *GetLogName(void)
00507 {
00508   return(log_name);
00509 }
00510 
00511 /*
00512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00513 %                                                                             %
00514 %                                                                             %
00515 %                                                                             %
00516 +   I n i t i a l i z e L o g L i s t                                         %
00517 %                                                                             %
00518 %                                                                             %
00519 %                                                                             %
00520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00521 %
00522 %  InitializeLogList() initialize the log list.
00523 %
00524 %  The format of the InitializeLogList method is:
00525 %
00526 %      MagickBooleanType InitializeLogList(ExceptionInfo *exception)
00527 %
00528 %  A description of each parameter follows.
00529 %
00530 %    o exception: return any errors or warnings in this structure.
00531 %
00532 */
00533 static MagickBooleanType InitializeLogList(ExceptionInfo *exception)
00534 {
00535   if ((log_list == (LinkedListInfo *) NULL) && (instantiate_log == MagickFalse))
00536     {
00537       if (log_semaphore == (SemaphoreInfo *) NULL)
00538         AcquireSemaphoreInfo(&log_semaphore);
00539       LockSemaphoreInfo(log_semaphore);
00540       if ((log_list == (LinkedListInfo *) NULL) &&
00541           (instantiate_log == MagickFalse))
00542         {
00543           (void) LoadLogLists(LogFilename,exception);
00544           instantiate_log=MagickTrue;
00545         }
00546       UnlockSemaphoreInfo(log_semaphore);
00547     }
00548   return(log_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
00549 }
00550 
00551 /*
00552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00553 %                                                                             %
00554 %                                                                             %
00555 %                                                                             %
00556 %  I s E v e n t L o g g i n g                                                %
00557 %                                                                             %
00558 %                                                                             %
00559 %                                                                             %
00560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00561 %
00562 %  IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
00563 %  MagickFalse.
00564 %
00565 %  The format of the IsEventLogging method is:
00566 %
00567 %      MagickBooleanType IsEventLogging(void)
00568 %
00569 */
00570 MagickExport MagickBooleanType IsEventLogging(void)
00571 {
00572   const LogInfo
00573     *log_info;
00574 
00575   ExceptionInfo
00576     *exception;
00577 
00578   if ((log_list == (LinkedListInfo *) NULL) ||
00579       (IsLinkedListEmpty(log_list) != MagickFalse))
00580     return(MagickFalse);
00581   exception=AcquireExceptionInfo();
00582   log_info=GetLogInfo("*",exception);
00583   exception=DestroyExceptionInfo(exception);
00584   return(log_info->event_mask != NoEvents ? MagickTrue : MagickFalse);
00585 }
00586 /*
00587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00588 %                                                                             %
00589 %                                                                             %
00590 %                                                                             %
00591 %  L i s t L o g I n f o                                                      %
00592 %                                                                             %
00593 %                                                                             %
00594 %                                                                             %
00595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00596 %
00597 %  ListLogInfo() lists the log info to a file.
00598 %
00599 %  The format of the ListLogInfo method is:
00600 %
00601 %      MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00602 %
00603 %  A description of each parameter follows.
00604 %
00605 %    o file:  An pointer to a FILE.
00606 %
00607 %    o exception: return any errors or warnings in this structure.
00608 %
00609 */
00610 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00611 {
00612 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
00613 
00614   char
00615     limit[MaxTextExtent];
00616 
00617   const char
00618     *path;
00619 
00620   const LogInfo
00621     **log_info;
00622 
00623   register ssize_t
00624     i;
00625 
00626   size_t
00627     number_aliases;
00628 
00629   ssize_t
00630     j;
00631 
00632   if (file == (const FILE *) NULL)
00633     file=stdout;
00634   log_info=GetLogInfoList("*",&number_aliases,exception);
00635   if (log_info == (const LogInfo **) NULL)
00636     return(MagickFalse);
00637   j=0;
00638   path=(const char *) NULL;
00639   for (i=0; i < (ssize_t) number_aliases; i++)
00640   {
00641     if (log_info[i]->stealth != MagickFalse)
00642       continue;
00643     if ((path == (const char *) NULL) ||
00644         (LocaleCompare(path,log_info[i]->path) != 0))
00645       {
00646         if (log_info[i]->path != (char *) NULL)
00647           (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path);
00648         (void) FormatLocaleFile(file,
00649           "Filename       Generations     Limit  Format\n");
00650         (void) FormatLocaleFile(file,
00651           "-------------------------------------------------"
00652           "------------------------------\n");
00653       }
00654     path=log_info[i]->path;
00655     if (log_info[i]->filename != (char *) NULL)
00656       {
00657         (void) FormatLocaleFile(file,"%s",log_info[i]->filename);
00658         for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
00659           (void) FormatLocaleFile(file," ");
00660       }
00661     (void) FormatLocaleFile(file,"%9g  ",(double) log_info[i]->generations);
00662     (void) FormatMagickSize(MegabytesToBytes(log_info[i]->limit),MagickFalse,
00663       limit);
00664     (void) FormatLocaleFile(file,"%8sB  ",limit);
00665     if (log_info[i]->format != (char *) NULL)
00666       (void) FormatLocaleFile(file,"%s",log_info[i]->format);
00667     (void) FormatLocaleFile(file,"\n");
00668   }
00669   (void) fflush(file);
00670   log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
00671   return(MagickTrue);
00672 }
00673 
00674 /*
00675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00676 %                                                                             %
00677 %                                                                             %
00678 %                                                                             %
00679 +   L o g C o m p o n e n t G e n e s i s                                     %
00680 %                                                                             %
00681 %                                                                             %
00682 %                                                                             %
00683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00684 %
00685 %  LogComponentGenesis() instantiates the log component.
00686 %
00687 %  The format of the LogComponentGenesis method is:
00688 %
00689 %      MagickBooleanType LogComponentGenesis(void)
00690 %
00691 */
00692 MagickPrivate MagickBooleanType LogComponentGenesis(void)
00693 {
00694   AcquireSemaphoreInfo(&log_semaphore);
00695   return(MagickTrue);
00696 }
00697 
00698 /*
00699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00700 %                                                                             %
00701 %                                                                             %
00702 %                                                                             %
00703 +   L o g C o m p o n e n t T e r m i n u s                                   %
00704 %                                                                             %
00705 %                                                                             %
00706 %                                                                             %
00707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00708 %
00709 %  LogComponentTerminus() destroys the logging component.
00710 %
00711 %  The format of the LogComponentTerminus method is:
00712 %
00713 %      LogComponentTerminus(void)
00714 %
00715 */
00716 
00717 static void *DestroyLogElement(void *log_info)
00718 {
00719   register LogInfo
00720     *p;
00721 
00722   p=(LogInfo *) log_info;
00723   if (p->file != (FILE *) NULL)
00724     {
00725       if (p->append == MagickFalse)
00726         (void) FormatLocaleFile(p->file,"</log>\n");
00727       (void) fclose(p->file);
00728       p->file=(FILE *) NULL;
00729     }
00730   if (p->exempt == MagickFalse)
00731     {
00732       if (p->format != (char *) NULL)
00733         p->format=DestroyString(p->format);
00734       if (p->path != (char *) NULL)
00735         p->path=DestroyString(p->path);
00736       if (p->filename != (char *) NULL)
00737         p->filename=DestroyString(p->filename);
00738     }
00739   p=(LogInfo *) RelinquishMagickMemory(p);
00740   return((void *) NULL);
00741 }
00742 
00743 MagickPrivate void LogComponentTerminus(void)
00744 {
00745   if (log_semaphore == (SemaphoreInfo *) NULL)
00746     AcquireSemaphoreInfo(&log_semaphore);
00747   LockSemaphoreInfo(log_semaphore);
00748   if (log_list != (LinkedListInfo *) NULL)
00749     log_list=DestroyLinkedList(log_list,DestroyLogElement);
00750   instantiate_log=MagickFalse;
00751   UnlockSemaphoreInfo(log_semaphore);
00752   DestroySemaphoreInfo(&log_semaphore);
00753 }
00754 
00755 /*
00756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00757 %                                                                             %
00758 %                                                                             %
00759 %                                                                             %
00760 %   L o g M a g i c k E v e n t                                               %
00761 %                                                                             %
00762 %                                                                             %
00763 %                                                                             %
00764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00765 %
00766 %  LogMagickEvent() logs an event as determined by the log configuration file.
00767 %  If an error occurs, MagickFalse is returned otherwise MagickTrue.
00768 %
00769 %  The format of the LogMagickEvent method is:
00770 %
00771 %      MagickBooleanType LogMagickEvent(const LogEventType type,
00772 %        const char *module,const char *function,const size_t line,
00773 %        const char *format,...)
00774 %
00775 %  A description of each parameter follows:
00776 %
00777 %    o type: the event type.
00778 %
00779 %    o filename: the source module filename.
00780 %
00781 %    o function: the function name.
00782 %
00783 %    o line: the line number of the source module.
00784 %
00785 %    o format: the output format.
00786 %
00787 */
00788 static char *TranslateEvent(const LogEventType magick_unused(type),
00789   const char *module,const char *function,const size_t line,
00790   const char *domain,const char *event)
00791 {
00792   char
00793     *text;
00794 
00795   double
00796     elapsed_time,
00797     user_time;
00798 
00799   ExceptionInfo
00800     *exception;
00801 
00802   LogInfo
00803     *log_info;
00804 
00805   register char
00806     *q;
00807 
00808   register const char
00809     *p;
00810 
00811   size_t
00812     extent;
00813 
00814   time_t
00815     seconds;
00816 
00817   exception=AcquireExceptionInfo();
00818   log_info=(LogInfo *) GetLogInfo("*",exception);
00819   exception=DestroyExceptionInfo(exception);
00820   seconds=time((time_t *) NULL);
00821   elapsed_time=GetElapsedTime(&log_info->timer);
00822   user_time=GetUserTime(&log_info->timer);
00823   text=AcquireString(event);
00824   if (log_info->format == (char *) NULL)
00825     return(text);
00826   extent=strlen(event)+MaxTextExtent;
00827   if (LocaleCompare(log_info->format,"xml") == 0)
00828     {
00829       char
00830         timestamp[MaxTextExtent];
00831 
00832       /*
00833         Translate event in "XML" format.
00834       */
00835       (void) FormatMagickTime(seconds,extent,timestamp);
00836       (void) FormatLocaleString(text,extent,
00837         "<entry>\n"
00838         "  <timestamp>%s</timestamp>\n"
00839         "  <elapsed-time>%lu:%02lu.%03lu</elapsed-time>\n"
00840         "  <user-time>%0.3f</user-time>\n"
00841         "  <process-id>%.20g</process-id>\n"
00842         "  <thread-id>%.20g</thread-id>\n"
00843         "  <module>%s</module>\n"
00844         "  <function>%s</function>\n"
00845         "  <line>%.20g</line>\n"
00846         "  <domain>%s</domain>\n"
00847         "  <event>%s</event>\n"
00848         "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
00849         (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
00850         (1000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
00851         (double) getpid(),(double) GetMagickThreadSignature(),module,function,
00852         (double) line,domain,event);
00853       return(text);
00854     }
00855   /*
00856     Translate event in "human readable" format.
00857   */
00858   q=text;
00859   for (p=log_info->format; *p != '\0'; p++)
00860   {
00861     *q='\0';
00862     if ((size_t) (q-text+MaxTextExtent) >= extent)
00863       {
00864         extent+=MaxTextExtent;
00865         text=(char *) ResizeQuantumMemory(text,extent+MaxTextExtent,
00866           sizeof(*text));
00867         if (text == (char *) NULL)
00868           return((char *) NULL);
00869         q=text+strlen(text);
00870       }
00871     /*
00872       The format of the log is defined by embedding special format characters:
00873 
00874         %c   client name
00875         %d   domain
00876         %e   event
00877         %f   function
00878         %g   generation
00879         %l   line
00880         %m   module
00881         %n   log name
00882         %p   process id
00883         %r   real CPU time
00884         %t   wall clock time
00885         %u   user CPU time
00886         %v   version
00887         %%   percent sign
00888         \n   newline
00889         \r   carriage return
00890     */
00891     if ((*p == '\\') && (*(p+1) == 'r'))
00892       {
00893         *q++='\r';
00894         p++;
00895         continue;
00896       }
00897     if ((*p == '\\') && (*(p+1) == 'n'))
00898       {
00899         *q++='\n';
00900         p++;
00901         continue;
00902       }
00903     if (*p != '%')
00904       {
00905         *q++=(*p);
00906         continue;
00907       }
00908     p++;
00909     switch (*p)
00910     {
00911       case 'c':
00912       {
00913         q+=CopyMagickString(q,GetClientName(),extent);
00914         break;
00915       }
00916       case 'd':
00917       {
00918         q+=CopyMagickString(q,domain,extent);
00919         break;
00920       }
00921       case 'e':
00922       {
00923         q+=CopyMagickString(q,event,extent);
00924         break;
00925       }
00926       case 'f':
00927       {
00928         q+=CopyMagickString(q,function,extent);
00929         break;
00930       }
00931       case 'g':
00932       {
00933         if (log_info->generations == 0)
00934           {
00935             (void) CopyMagickString(q,"0",extent);
00936             q++;
00937             break;
00938           }
00939         q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
00940           log_info->generations));
00941         break;
00942       }
00943       case 'l':
00944       {
00945         q+=FormatLocaleString(q,extent,"%.20g",(double) line);
00946         break;
00947       }
00948       case 'm':
00949       {
00950         register const char
00951           *p;
00952 
00953         for (p=module+strlen(module)-1; p > module; p--)
00954           if (*p == *DirectorySeparator)
00955             {
00956               p++;
00957               break;
00958             }
00959         q+=CopyMagickString(q,p,extent);
00960         break;
00961       }
00962       case 'n':
00963       {
00964         q+=CopyMagickString(q,GetLogName(),extent);
00965         break;
00966       }
00967       case 'p':
00968       {
00969         q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
00970         break;
00971       }
00972       case 'r':
00973       {
00974         q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
00975           (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
00976           (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
00977         break;
00978       }
00979       case 't':
00980       {
00981         q+=FormatMagickTime(seconds,extent,q);
00982         break;
00983       }
00984       case 'u':
00985       {
00986         q+=FormatLocaleString(q,extent,"%0.3fu",user_time);
00987         break;
00988       }
00989       case 'v':
00990       {
00991         q+=CopyMagickString(q,MagickLibVersionText,extent);
00992         break;
00993       }
00994       case '%':
00995       {
00996         *q++=(*p);
00997         break;
00998       }
00999       default:
01000       {
01001         *q++='%';
01002         *q++=(*p);
01003         break;
01004       }
01005     }
01006   }
01007   *q='\0';
01008   return(text);
01009 }
01010 
01011 static char *TranslateFilename(const LogInfo *log_info)
01012 {
01013   char
01014     *filename;
01015 
01016   register char
01017     *q;
01018 
01019   register const char
01020     *p;
01021 
01022   size_t
01023     extent;
01024 
01025   /*
01026     Translate event in "human readable" format.
01027   */
01028   assert(log_info != (LogInfo *) NULL);
01029   assert(log_info->filename != (char *) NULL);
01030   filename=AcquireString((char *) NULL);
01031   extent=MaxTextExtent;
01032   q=filename;
01033   for (p=log_info->filename; *p != '\0'; p++)
01034   {
01035     *q='\0';
01036     if ((size_t) (q-filename+MaxTextExtent) >= extent)
01037       {
01038         extent+=MaxTextExtent;
01039         filename=(char *) ResizeQuantumMemory(filename,extent+MaxTextExtent,
01040           sizeof(*filename));
01041         if (filename == (char *) NULL)
01042           return((char *) NULL);
01043         q=filename+strlen(filename);
01044       }
01045     /*
01046       The format of the filename is defined by embedding special format
01047       characters:
01048 
01049         %c   client name
01050         %n   log name
01051         %p   process id
01052         %v   version
01053         %%   percent sign
01054     */
01055     if (*p != '%')
01056       {
01057         *q++=(*p);
01058         continue;
01059       }
01060     p++;
01061     switch (*p)
01062     {
01063       case 'c':
01064       {
01065         q+=CopyMagickString(q,GetClientName(),extent);
01066         break;
01067       }
01068       case 'g':
01069       {
01070         if (log_info->generations == 0)
01071           {
01072             (void) CopyMagickString(q,"0",extent);
01073             q++;
01074             break;
01075           }
01076         q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
01077           log_info->generations));
01078         break;
01079       }
01080       case 'n':
01081       {
01082         q+=CopyMagickString(q,GetLogName(),extent);
01083         break;
01084       }
01085       case 'p':
01086       {
01087         q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
01088         break;
01089       }
01090       case 'v':
01091       {
01092         q+=CopyMagickString(q,MagickLibVersionText,extent);
01093         break;
01094       }
01095       case '%':
01096       {
01097         *q++=(*p);
01098         break;
01099       }
01100       default:
01101       {
01102         *q++='%';
01103         *q++=(*p);
01104         break;
01105       }
01106     }
01107   }
01108   *q='\0';
01109   return(filename);
01110 }
01111 
01112 MagickBooleanType LogMagickEventList(const LogEventType type,const char *module,
01113   const char *function,const size_t line,const char *format,
01114   va_list operands)
01115 {
01116   char
01117     event[MaxTextExtent],
01118     *text;
01119 
01120   const char
01121     *domain;
01122 
01123   ExceptionInfo
01124     *exception;
01125 
01126   int
01127     n;
01128 
01129   LogInfo
01130     *log_info;
01131 
01132   if (IsEventLogging() == MagickFalse)
01133     return(MagickFalse);
01134   exception=AcquireExceptionInfo();
01135   log_info=(LogInfo *) GetLogInfo("*",exception);
01136   exception=DestroyExceptionInfo(exception);
01137   LockSemaphoreInfo(log_semaphore);
01138   if ((log_info->event_mask & type) == 0)
01139     {
01140       UnlockSemaphoreInfo(log_semaphore);
01141       return(MagickTrue);
01142     }
01143   domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
01144 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
01145   n=vsnprintf(event,MaxTextExtent,format,operands);
01146 #else
01147   n=vsprintf(event,format,operands);
01148 #endif
01149   if (n < 0)
01150     event[MaxTextExtent-1]='\0';
01151   text=TranslateEvent(type,module,function,line,domain,event);
01152   if (text == (char *) NULL)
01153     {
01154       (void) ContinueTimer((TimerInfo *) &log_info->timer);
01155       UnlockSemaphoreInfo(log_semaphore);
01156       return(MagickFalse);
01157     }
01158   if ((log_info->handler_mask & ConsoleHandler) != 0)
01159     {
01160       (void) FormatLocaleFile(stderr,"%s\n",text);
01161       (void) fflush(stderr);
01162     }
01163   if ((log_info->handler_mask & DebugHandler) != 0)
01164     {
01165 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
01166       OutputDebugString(text);
01167 #endif
01168     }
01169   if ((log_info->handler_mask & EventHandler) != 0)
01170     {
01171 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
01172       (void) NTReportEvent(text,MagickFalse);
01173 #endif
01174     }
01175   if ((log_info->handler_mask & FileHandler) != 0)
01176     {
01177       struct stat
01178         file_info;
01179 
01180       file_info.st_size=0;
01181       if (log_info->file != (FILE *) NULL)
01182         (void) fstat(fileno(log_info->file),&file_info);
01183       if (file_info.st_size > (ssize_t) (1024*1024*log_info->limit))
01184         {
01185           (void) FormatLocaleFile(log_info->file,"</log>\n");
01186           (void) fclose(log_info->file);
01187           log_info->file=(FILE *) NULL;
01188         }
01189       if (log_info->file == (FILE *) NULL)
01190         {
01191           char
01192             *filename;
01193 
01194           filename=TranslateFilename(log_info);
01195           if (filename == (char *) NULL)
01196             {
01197               (void) ContinueTimer((TimerInfo *) &log_info->timer);
01198               UnlockSemaphoreInfo(log_semaphore);
01199               return(MagickFalse);
01200             }
01201           log_info->append=IsPathAccessible(filename);
01202           log_info->file=fopen_utf8(filename,"ab");
01203           filename=(char  *) RelinquishMagickMemory(filename);
01204           if (log_info->file == (FILE *) NULL)
01205             {
01206               UnlockSemaphoreInfo(log_semaphore);
01207               return(MagickFalse);
01208             }
01209           log_info->generation++;
01210           if (log_info->append == MagickFalse)
01211             {
01212               (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
01213                 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
01214               (void) FormatLocaleFile(log_info->file,"<log>\n");
01215             }
01216         }
01217       (void) FormatLocaleFile(log_info->file,"%s\n",text);
01218       (void) fflush(log_info->file);
01219     }
01220   if ((log_info->handler_mask & StdoutHandler) != 0)
01221     {
01222       (void) FormatLocaleFile(stdout,"%s\n",text);
01223       (void) fflush(stdout);
01224     }
01225   if ((log_info->handler_mask & StderrHandler) != 0)
01226     {
01227       (void) FormatLocaleFile(stderr,"%s\n",text);
01228       (void) fflush(stderr);
01229     }
01230   text=(char  *) RelinquishMagickMemory(text);
01231   (void) ContinueTimer((TimerInfo *) &log_info->timer);
01232   UnlockSemaphoreInfo(log_semaphore);
01233   return(MagickTrue);
01234 }
01235 
01236 MagickBooleanType LogMagickEvent(const LogEventType type,const char *module,
01237   const char *function,const size_t line,const char *format,...)
01238 {
01239   va_list
01240     operands;
01241 
01242   MagickBooleanType
01243     status;
01244 
01245   va_start(operands,format);
01246   status=LogMagickEventList(type,module,function,line,format,operands);
01247   va_end(operands);
01248   return(status);
01249 }
01250 
01251 /*
01252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01253 %                                                                             %
01254 %                                                                             %
01255 %                                                                             %
01256 +   L o a d L o g L i s t                                                     %
01257 %                                                                             %
01258 %                                                                             %
01259 %                                                                             %
01260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01261 %
01262 %  LoadLogList() loads the log configuration file which provides a
01263 %  mapping between log attributes and log name.
01264 %
01265 %  The format of the LoadLogList method is:
01266 %
01267 %      MagickBooleanType LoadLogList(const char *xml,const char *filename,
01268 %        const size_t depth,ExceptionInfo *exception)
01269 %
01270 %  A description of each parameter follows:
01271 %
01272 %    o xml:  The log list in XML format.
01273 %
01274 %    o filename:  The log list filename.
01275 %
01276 %    o depth: depth of <include /> statements.
01277 %
01278 %    o exception: return any errors or warnings in this structure.
01279 %
01280 */
01281 static MagickBooleanType LoadLogList(const char *xml,const char *filename,
01282   const size_t depth,ExceptionInfo *exception)
01283 {
01284   char
01285     keyword[MaxTextExtent],
01286     *token;
01287 
01288   const char
01289     *q;
01290 
01291   LogInfo
01292     *log_info = (LogInfo *) NULL;
01293 
01294   MagickStatusType
01295     status;
01296 
01297   /*
01298     Load the log map file.
01299   */
01300   if (xml == (const char *) NULL)
01301     return(MagickFalse);
01302   if (log_list == (LinkedListInfo *) NULL)
01303     {
01304       log_list=NewLinkedList(0);
01305       if (log_list == (LinkedListInfo *) NULL)
01306         {
01307           ThrowFileException(exception,ResourceLimitError,
01308             "MemoryAllocationFailed",filename);
01309           return(MagickFalse);
01310         }
01311     }
01312   status=MagickTrue;
01313   token=AcquireString((const char *) xml);
01314   for (q=(const char *) xml; *q != '\0'; )
01315   {
01316     /*
01317       Interpret XML.
01318     */
01319     GetMagickToken(q,&q,token);
01320     if (*token == '\0')
01321       break;
01322     (void) CopyMagickString(keyword,token,MaxTextExtent);
01323     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
01324       {
01325         /*
01326           Doctype element.
01327         */
01328         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
01329           GetMagickToken(q,&q,token);
01330         continue;
01331       }
01332     if (LocaleNCompare(keyword,"<!--",4) == 0)
01333       {
01334         /*
01335           Comment element.
01336         */
01337         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
01338           GetMagickToken(q,&q,token);
01339         continue;
01340       }
01341     if (LocaleCompare(keyword,"<include") == 0)
01342       {
01343         /*
01344           Include element.
01345         */
01346         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
01347         {
01348           (void) CopyMagickString(keyword,token,MaxTextExtent);
01349           GetMagickToken(q,&q,token);
01350           if (*token != '=')
01351             continue;
01352           GetMagickToken(q,&q,token);
01353           if (LocaleCompare(keyword,"file") == 0)
01354             {
01355               if (depth > 200)
01356                 (void) ThrowMagickException(exception,GetMagickModule(),
01357                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
01358               else
01359                 {
01360                   char
01361                     path[MaxTextExtent],
01362                     *xml;
01363 
01364                   GetPathComponent(filename,HeadPath,path);
01365                   if (*path != '\0')
01366                     (void) ConcatenateMagickString(path,DirectorySeparator,
01367                       MaxTextExtent);
01368                   if (*token == *DirectorySeparator)
01369                     (void) CopyMagickString(path,token,MaxTextExtent);
01370                   else
01371                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
01372                   xml=FileToString(path,~0,exception);
01373                   if (xml != (char *) NULL)
01374                     {
01375                       status|=LoadLogList(xml,path,depth+1,exception);
01376                       xml=DestroyString(xml);
01377                     }
01378                 }
01379             }
01380         }
01381         continue;
01382       }
01383     if (LocaleCompare(keyword,"<logmap>") == 0)
01384       {
01385         /*
01386           Allocate memory for the log list.
01387         */
01388         log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
01389         if (log_info == (LogInfo *) NULL)
01390           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
01391         (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
01392         log_info->path=ConstantString(filename);
01393         GetTimerInfo((TimerInfo *) &log_info->timer);
01394         log_info->exempt=MagickFalse;
01395         log_info->signature=MagickSignature;
01396         continue;
01397       }
01398     if (log_info == (LogInfo *) NULL)
01399       continue;
01400     if (LocaleCompare(keyword,"</logmap>") == 0)
01401       {
01402         status=AppendValueToLinkedList(log_list,log_info);
01403         if (status == MagickFalse)
01404           (void) ThrowMagickException(exception,GetMagickModule(),
01405             ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
01406         log_info=(LogInfo *) NULL;
01407       }
01408     GetMagickToken(q,(const char **) NULL,token);
01409     if (*token != '=')
01410       continue;
01411     GetMagickToken(q,&q,token);
01412     GetMagickToken(q,&q,token);
01413     switch (*keyword)
01414     {
01415       case 'E':
01416       case 'e':
01417       {
01418         if (LocaleCompare((char *) keyword,"events") == 0)
01419           {
01420             log_info->event_mask=(LogEventType) (log_info->event_mask |
01421               ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
01422             break;
01423           }
01424         break;
01425       }
01426       case 'F':
01427       case 'f':
01428       {
01429         if (LocaleCompare((char *) keyword,"filename") == 0)
01430           {
01431             if (log_info->filename != (char *) NULL)
01432               log_info->filename=(char *)
01433                 RelinquishMagickMemory(log_info->filename);
01434             log_info->filename=ConstantString(token);
01435             break;
01436           }
01437         if (LocaleCompare((char *) keyword,"format") == 0)
01438           {
01439             if (log_info->format != (char *) NULL)
01440               log_info->format=(char *)
01441                 RelinquishMagickMemory(log_info->format);
01442             log_info->format=ConstantString(token);
01443             break;
01444           }
01445         break;
01446       }
01447       case 'G':
01448       case 'g':
01449       {
01450         if (LocaleCompare((char *) keyword,"generations") == 0)
01451           {
01452             if (LocaleCompare(token,"unlimited") == 0)
01453               {
01454                 log_info->generations=(~0UL);
01455                 break;
01456               }
01457             log_info->generations=StringToUnsignedLong(token);
01458             break;
01459           }
01460         break;
01461       }
01462       case 'L':
01463       case 'l':
01464       {
01465         if (LocaleCompare((char *) keyword,"limit") == 0)
01466           {
01467             if (LocaleCompare(token,"unlimited") == 0)
01468               {
01469                 log_info->limit=(~0UL);
01470                 break;
01471               }
01472             log_info->limit=StringToUnsignedLong(token);
01473             break;
01474           }
01475         break;
01476       }
01477       case 'O':
01478       case 'o':
01479       {
01480         if (LocaleCompare((char *) keyword,"output") == 0)
01481           {
01482             log_info->handler_mask=(LogHandlerType)
01483               (log_info->handler_mask | ParseLogHandlers(token));
01484             break;
01485           }
01486         break;
01487       }
01488       default:
01489         break;
01490     }
01491   }
01492   token=DestroyString(token);
01493   if (log_list == (LinkedListInfo *) NULL)
01494     return(MagickFalse);
01495   return(status != 0 ? MagickTrue : MagickFalse);
01496 }
01497 
01498 /*
01499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01500 %                                                                             %
01501 %                                                                             %
01502 %                                                                             %
01503 %  L o a d L o g L i s t s                                                    %
01504 %                                                                             %
01505 %                                                                             %
01506 %                                                                             %
01507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01508 %
01509 %  LoadLogLists() loads one or more log configuration file which provides a
01510 %  mapping between log attributes and log name.
01511 %
01512 %  The format of the LoadLogLists method is:
01513 %
01514 %      MagickBooleanType LoadLogLists(const char *filename,
01515 %        ExceptionInfo *exception)
01516 %
01517 %  A description of each parameter follows:
01518 %
01519 %    o filename: the log configuration filename.
01520 %
01521 %    o exception: return any errors or warnings in this structure.
01522 %
01523 */
01524 static MagickBooleanType LoadLogLists(const char *filename,
01525   ExceptionInfo *exception)
01526 {
01527   const StringInfo
01528     *option;
01529 
01530   LinkedListInfo
01531     *options;
01532 
01533   MagickStatusType
01534     status;
01535 
01536   register ssize_t
01537     i;
01538 
01539   /*
01540     Load built-in log map.
01541   */
01542   status=MagickFalse;
01543   if (log_list == (LinkedListInfo *) NULL)
01544     {
01545       log_list=NewLinkedList(0);
01546       if (log_list == (LinkedListInfo *) NULL)
01547         {
01548           ThrowFileException(exception,ResourceLimitError,
01549             "MemoryAllocationFailed",filename);
01550           return(MagickFalse);
01551         }
01552     }
01553   for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
01554   {
01555     LogInfo
01556       *log_info;
01557 
01558     register const LogMapInfo
01559       *p;
01560 
01561     p=LogMap+i;
01562     log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
01563     if (log_info == (LogInfo *) NULL)
01564       {
01565         (void) ThrowMagickException(exception,GetMagickModule(),
01566           ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
01567         continue;
01568       }
01569     (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
01570     log_info->path=(char *) "[built-in]";
01571     GetTimerInfo((TimerInfo *) &log_info->timer);
01572     log_info->event_mask=p->event_mask;
01573     log_info->handler_mask=p->handler_mask;
01574     log_info->filename=ConstantString(p->filename);
01575     log_info->format=ConstantString(p->format);
01576     log_info->exempt=MagickTrue;
01577     log_info->signature=MagickSignature;
01578     status=AppendValueToLinkedList(log_list,log_info);
01579     if (status == MagickFalse)
01580       (void) ThrowMagickException(exception,GetMagickModule(),
01581         ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
01582   }
01583   /*
01584     Load external log map.
01585   */
01586   options=GetConfigureOptions(filename,exception);
01587   option=(const StringInfo *) GetNextValueInLinkedList(options);
01588   while (option != (const StringInfo *) NULL)
01589   {
01590     status|=LoadLogList((const char *) GetStringInfoDatum(option),
01591       GetStringInfoPath(option),0,exception);
01592     option=(const StringInfo *) GetNextValueInLinkedList(options);
01593   }
01594   options=DestroyConfigureOptions(options);
01595   return(status != 0 ? MagickTrue : MagickFalse);
01596 }
01597 
01598 /*
01599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01600 %                                                                             %
01601 %                                                                             %
01602 %                                                                             %
01603 +   P a r s e L o g H a n d l e r s                                           %
01604 %                                                                             %
01605 %                                                                             %
01606 %                                                                             %
01607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01608 %
01609 %  ParseLogHandlers() parses a string defining which handlers takes a log
01610 %  message and exports them.
01611 %
01612 %  The format of the ParseLogHandlers method is:
01613 %
01614 %      LogHandlerType ParseLogHandlers(const char *handlers)
01615 %
01616 %  A description of each parameter follows:
01617 %
01618 %    o handlers: one or more handlers separated by commas.
01619 %
01620 */
01621 static LogHandlerType ParseLogHandlers(const char *handlers)
01622 {
01623   LogHandlerType
01624     handler_mask;
01625 
01626   register const char
01627     *p;
01628 
01629   register ssize_t
01630     i;
01631 
01632   size_t
01633     length;
01634 
01635   handler_mask=NoHandler;
01636   for (p=handlers; p != (char *) NULL; p=strchr(p,','))
01637   {
01638     while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
01639            (*p == ',')))
01640       p++;
01641     for (i=0; LogHandlers[i].name != (char *) NULL; i++)
01642     {
01643       length=strlen(LogHandlers[i].name);
01644       if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
01645         {
01646           handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
01647           break;
01648         }
01649     }
01650     if (LogHandlers[i].name == (char *) NULL)
01651       return(UndefinedHandler);
01652   }
01653   return(handler_mask);
01654 }
01655 
01656 /*
01657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01658 %                                                                             %
01659 %                                                                             %
01660 %                                                                             %
01661 %   S e t L o g E v e n t M a s k                                             %
01662 %                                                                             %
01663 %                                                                             %
01664 %                                                                             %
01665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01666 %
01667 %  SetLogEventMask() accepts a list that determines which events to log.  All
01668 %  other events are ignored.  By default, no debug is enabled.  This method
01669 %  returns the previous log event mask.
01670 %
01671 %  The format of the SetLogEventMask method is:
01672 %
01673 %      LogEventType SetLogEventMask(const char *events)
01674 %
01675 %  A description of each parameter follows:
01676 %
01677 %    o events: log these events.
01678 %
01679 */
01680 MagickExport LogEventType SetLogEventMask(const char *events)
01681 {
01682   ExceptionInfo
01683     *exception;
01684 
01685   LogInfo
01686     *log_info;
01687 
01688   ssize_t
01689     option;
01690 
01691   exception=AcquireExceptionInfo();
01692   log_info=(LogInfo *) GetLogInfo("*",exception);
01693   exception=DestroyExceptionInfo(exception);
01694   option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
01695   LockSemaphoreInfo(log_semaphore);
01696   log_info=(LogInfo *) GetValueFromLinkedList(log_list,0);
01697   log_info->event_mask=(LogEventType) option;
01698   if (option == -1)
01699     log_info->event_mask=UndefinedEvents;
01700   UnlockSemaphoreInfo(log_semaphore);
01701   return(log_info->event_mask);
01702 }
01703 
01704 /*
01705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01706 %                                                                             %
01707 %                                                                             %
01708 %                                                                             %
01709 %   S e t L o g F o r m a t                                                   %
01710 %                                                                             %
01711 %                                                                             %
01712 %                                                                             %
01713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01714 %
01715 %  SetLogFormat() sets the format for the "human readable" log record.
01716 %
01717 %  The format of the LogMagickFormat method is:
01718 %
01719 %      SetLogFormat(const char *format)
01720 %
01721 %  A description of each parameter follows:
01722 %
01723 %    o format: the log record format.
01724 %
01725 */
01726 MagickExport void SetLogFormat(const char *format)
01727 {
01728   LogInfo
01729     *log_info;
01730 
01731   ExceptionInfo
01732     *exception;
01733 
01734   exception=AcquireExceptionInfo();
01735   log_info=(LogInfo *) GetLogInfo("*",exception);
01736   exception=DestroyExceptionInfo(exception);
01737   LockSemaphoreInfo(log_semaphore);
01738   if (log_info->format != (char *) NULL)
01739     log_info->format=DestroyString(log_info->format);
01740   log_info->format=ConstantString(format);
01741   UnlockSemaphoreInfo(log_semaphore);
01742 }
01743 
01744 /*
01745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01746 %                                                                             %
01747 %                                                                             %
01748 %                                                                             %
01749 %   S e t L o g N a m e                                                       %
01750 %                                                                             %
01751 %                                                                             %
01752 %                                                                             %
01753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01754 %
01755 %  SetLogName() sets the log name and returns it.
01756 %
01757 %  The format of the SetLogName method is:
01758 %
01759 %      const char *SetLogName(const char *name)
01760 %
01761 %  A description of each parameter follows:
01762 %
01763 %    o log_name: SetLogName() returns the current client name.
01764 %
01765 %    o name: Specifies the new client name.
01766 %
01767 */
01768 MagickExport const char *SetLogName(const char *name)
01769 {
01770   if ((name != (char *) NULL) && (*name != '\0'))
01771     (void) CopyMagickString(log_name,name,MaxTextExtent);
01772   return(log_name);
01773 }