MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
log.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % L OOO GGGG %
7 % L O O G %
8 % L O O G GG %
9 % L O O G G %
10 % LLLLL OOO GGG %
11 % %
12 % %
13 % MagickCore Log Events %
14 % %
15 % Software Design %
16 % Cristy %
17 % September 2002 %
18 % %
19 % %
20 % Copyright @ 1999 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/license/ %
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  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/configure-private.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/linked-list.h"
50 #include "MagickCore/linked-list-private.h"
51 #include "MagickCore/log.h"
52 #include "MagickCore/log-private.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/nt-base-private.h"
55 #include "MagickCore/option.h"
56 #include "MagickCore/resource-private.h"
57 #include "MagickCore/semaphore.h"
58 #include "MagickCore/string_.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/thread_.h"
61 #include "MagickCore/thread-private.h"
62 #include "MagickCore/timer.h"
63 #include "MagickCore/timer-private.h"
64 #include "MagickCore/token.h"
65 #include "MagickCore/utility.h"
66 #include "MagickCore/utility-private.h"
67 #include "MagickCore/version.h"
68 #include "MagickCore/xml-tree.h"
69 #include "MagickCore/xml-tree-private.h"
70 ␌
71 /*
72  Define declarations.
73 */
74 #define LogFilename "log.xml"
75 ␌
76 /*
77  Typedef declarations.
78 */
79 typedef enum
80 {
81  UndefinedHandler = 0x0000,
82  NoHandler = 0x0000,
83  ConsoleHandler = 0x0001,
84  StdoutHandler = 0x0002,
85  StderrHandler = 0x0004,
86  FileHandler = 0x0008,
87  DebugHandler = 0x0010,
88  EventHandler = 0x0020,
89  MethodHandler = 0x0040
90 } LogHandlerType;
91 
92 typedef struct _EventInfo
93 {
94  char
95  *name;
96 
97  LogEventType
98  event;
99 } EventInfo;
100 
101 typedef struct _HandlerInfo
102 {
103  const char
104  name[10];
105 
106  LogHandlerType
107  handler;
108 } HandlerInfo;
109 
110 struct _LogInfo
111 {
112  LogEventType
113  event_mask;
114 
115  LogHandlerType
116  handler_mask;
117 
118  char
119  *path,
120  *name,
121  *filename,
122  *format;
123 
124  size_t
125  generations;
126 
127  FILE
128  *file;
129 
130  MagickBooleanType
131  append,
132  stealth;
133 
134  MagickSizeType
135  limit;
136 
137  TimerInfo
138  timer;
139 
140  MagickLogMethod
141  method;
142 
144  *event_semaphore;
145 
146  size_t
147  signature;
148 };
149 
150 typedef struct _LogMapInfo
151 {
152  const LogEventType
153  event_mask;
154 
155  const LogHandlerType
156  handler_mask;
157 
158  const char
159  *filename,
160  *format;
161 } LogMapInfo;
162 ␌
163 /*
164  Static declarations.
165 */
166 static const HandlerInfo
167  LogHandlers[32] =
168  {
169  { "Console", ConsoleHandler },
170  { "Debug", DebugHandler },
171  { "Event", EventHandler },
172  { "File", FileHandler },
173  { "None", NoHandler },
174  { "Stderr", StderrHandler },
175  { "Stdout", StdoutHandler },
176  { "", UndefinedHandler },
177  { "", UndefinedHandler },
178  { "", UndefinedHandler },
179  { "", UndefinedHandler },
180  { "", UndefinedHandler },
181  { "", UndefinedHandler },
182  { "", UndefinedHandler },
183  { "", UndefinedHandler },
184  { "", UndefinedHandler },
185  { "", UndefinedHandler },
186  { "", UndefinedHandler },
187  { "", UndefinedHandler },
188  { "", UndefinedHandler },
189  { "", UndefinedHandler },
190  { "", UndefinedHandler },
191  { "", UndefinedHandler },
192  { "", UndefinedHandler },
193  { "", UndefinedHandler },
194  { "", UndefinedHandler },
195  { "", UndefinedHandler },
196  { "", UndefinedHandler },
197  { "", UndefinedHandler },
198  { "", UndefinedHandler },
199  { "", UndefinedHandler },
200  { "", UndefinedHandler }
201  };
202 
203 static const LogMapInfo
204  LogMap[] =
205  {
206  { NoEvents, ConsoleHandler, "Magick-%g.log",
207  "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\\n %e" }
208  };
209 
210 static char
211  log_name[MagickPathExtent] = "Magick";
212 
213 static LinkedListInfo
214  *log_cache = (LinkedListInfo *) NULL;
215 
216 static MagickBooleanType
217  event_logging = MagickFalse;
218 
219 static SemaphoreInfo
220  *log_semaphore = (SemaphoreInfo *) NULL;
221 ␌
222 /*
223  Forward declarations.
224 */
225 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
226 static LogHandlerType
227  ParseLogHandlers(const char *) magick_attribute((__pure__));
228 #endif
229 
230 static LogInfo
231  *GetLogInfo(const char *,ExceptionInfo *);
232 
233 static MagickBooleanType
234  IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__));
235 
236 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
237 static MagickBooleanType
238  LoadLogCache(LinkedListInfo *,const char *,const char *,const size_t,
239  ExceptionInfo *);
240 #endif
241 ␌
242 /*
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 % %
245 % %
246 % %
247 % A c q u i r e L o g C a c h e %
248 % %
249 % %
250 % %
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 %
253 % AcquireLogCache() caches one or more log configurations which provides a
254 % mapping between log attributes and log name.
255 %
256 % The format of the AcquireLogCache method is:
257 %
258 % LinkedListInfo *AcquireLogCache(const char *filename,
259 % ExceptionInfo *exception)
260 %
261 % A description of each parameter follows:
262 %
263 % o filename: the log configuration filename.
264 %
265 % o exception: return any errors or warnings in this structure.
266 %
267 */
268 static LinkedListInfo *AcquireLogCache(const char *filename,
269  ExceptionInfo *exception)
270 {
272  *cache;
273 
274  MagickStatusType
275  status;
276 
277  ssize_t
278  i;
279 
280  /*
281  Load external log map.
282  */
283  cache=NewLinkedList(0);
284  status=MagickTrue;
285 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
286  {
287  const StringInfo
288  *option;
289 
291  *options;
292 
293  options=GetConfigureOptions(filename,exception);
294  option=(const StringInfo *) GetNextValueInLinkedList(options);
295  while (option != (const StringInfo *) NULL)
296  {
297  status&=(MagickStatusType) LoadLogCache(cache,(const char *)
298  GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
299  option=(const StringInfo *) GetNextValueInLinkedList(options);
300  }
301  options=DestroyConfigureOptions(options);
302  }
303 #else
304  magick_unreferenced(filename);
305 #endif
306  /*
307  Load built-in log map.
308  */
309  for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
310  {
311  LogInfo
312  *log_info;
313 
314  const LogMapInfo
315  *p;
316 
317  p=LogMap+i;
318  log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
319  if (log_info == (LogInfo *) NULL)
320  {
321  (void) ThrowMagickException(exception,GetMagickModule(),
322  ResourceLimitError,"MemoryAllocationFailed","`%s'",p->filename);
323  continue;
324  }
325  (void) memset(log_info,0,sizeof(*log_info));
326  log_info->path=ConstantString("[built-in]");
327  GetTimerInfo((TimerInfo *) &log_info->timer);
328  log_info->event_mask=p->event_mask;
329  log_info->handler_mask=p->handler_mask;
330  log_info->filename=ConstantString(p->filename);
331  log_info->format=ConstantString(p->format);
332  log_info->signature=MagickCoreSignature;
333  status&=(MagickStatusType) AppendValueToLinkedList(cache,log_info);
334  if (status == MagickFalse)
335  (void) ThrowMagickException(exception,GetMagickModule(),
336  ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
337  }
338  return(cache);
339 }
340 ␌
341 /*
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 % %
344 % %
345 % %
346 % C l o s e M a g i c k L o g %
347 % %
348 % %
349 % %
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 %
352 % CloseMagickLog() closes the Magick log.
353 %
354 % The format of the CloseMagickLog method is:
355 %
356 % CloseMagickLog(void)
357 %
358 */
359 MagickExport void CloseMagickLog(void)
360 {
362  *exception;
363 
364  LogInfo
365  *log_info;
366 
367  if (IsEventLogging() == MagickFalse)
368  return;
369  exception=AcquireExceptionInfo();
370  log_info=GetLogInfo("*",exception);
371  exception=DestroyExceptionInfo(exception);
372  if (log_info == (LogInfo *) NULL)
373  return;
374  LockSemaphoreInfo(log_semaphore);
375  if ((log_info != (LogInfo *) NULL) && (log_info->file != (FILE *) NULL))
376  {
377  (void) FormatLocaleFile(log_info->file,"</log>\n");
378  (void) fclose(log_info->file);
379  log_info->file=(FILE *) NULL;
380  }
381  UnlockSemaphoreInfo(log_semaphore);
382 }
383 ␌
384 /*
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 % %
387 % %
388 % %
389 % G e t L o g E v e n t M a s k %
390 % %
391 % %
392 % %
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 %
395 % GetLogEventMask() returns the current log event mask.
396 %
397 % The format of the GetLogEventMask method is:
398 %
399 % LogEventType GetLogEventMask(void)
400 %
401 */
402 MagickExport LogEventType GetLogEventMask(void)
403 {
405  *exception;
406 
407  LogInfo
408  *log_info;
409 
410  exception=AcquireExceptionInfo();
411  log_info=GetLogInfo("*",exception);
412  exception=DestroyExceptionInfo(exception);
413  if (log_info == (const LogInfo *) NULL)
414  return(NoEvents);
415  return(log_info->event_mask);
416 }
417 ␌
418 /*
419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420 % %
421 % %
422 % %
423 + G e t L o g I n f o %
424 % %
425 % %
426 % %
427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 %
429 % GetLogInfo() searches the log list for the specified name and if found
430 % returns attributes for that log.
431 %
432 % The format of the GetLogInfo method is:
433 %
434 % LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
435 %
436 % A description of each parameter follows:
437 %
438 % o name: the log name.
439 %
440 % o exception: return any errors or warnings in this structure.
441 %
442 */
443 static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
444 {
445  LogInfo
446  *log_info;
447 
449  *p;
450 
451  assert(exception != (ExceptionInfo *) NULL);
452  if (IsLogCacheInstantiated(exception) == MagickFalse)
453  return((LogInfo *) NULL);
454  /*
455  Search for log tag.
456  */
457  log_info=(LogInfo *) NULL;
458  LockSemaphoreInfo(log_semaphore);
459  p=GetHeadElementInLinkedList(log_cache);
460  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
461  {
462  if (p != (ElementInfo *) NULL)
463  log_info=(LogInfo *) p->value;
464  UnlockSemaphoreInfo(log_semaphore);
465  return(log_info);
466  }
467  while (p != (ElementInfo *) NULL)
468  {
469  log_info=(LogInfo* ) p->value;
470  if (LocaleCompare(name,log_info->name) == 0)
471  break;
472  p=p->next;
473  }
474  if (p == (ElementInfo *) NULL)
475  log_info=(LogInfo *) NULL;
476  else
477  SetHeadElementInLinkedList(log_cache,p);
478  UnlockSemaphoreInfo(log_semaphore);
479  return(log_info);
480 }
481 ␌
482 /*
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % %
485 % %
486 % %
487 % G e t L o g I n f o L i s t %
488 % %
489 % %
490 % %
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 %
493 % GetLogInfoList() returns any logs that match the specified pattern.
494 %
495 % The format of the GetLogInfoList function is:
496 %
497 % const LogInfo **GetLogInfoList(const char *pattern,
498 % size_t *number_preferences,ExceptionInfo *exception)
499 %
500 % A description of each parameter follows:
501 %
502 % o pattern: Specifies a pointer to a text string containing a pattern.
503 %
504 % o number_preferences: This integer returns the number of logs in the list.
505 %
506 % o exception: return any errors or warnings in this structure.
507 %
508 */
509 #if defined(__cplusplus) || defined(c_plusplus)
510 extern "C" {
511 #endif
512 
513 static int LogInfoCompare(const void *x,const void *y)
514 {
515  const LogInfo
516  **p,
517  **q;
518 
519  p=(const LogInfo **) x,
520  q=(const LogInfo **) y;
521  if (LocaleCompare((*p)->path,(*q)->path) == 0)
522  return(LocaleCompare((*p)->name,(*q)->name));
523  return(LocaleCompare((*p)->path,(*q)->path));
524 }
525 
526 #if defined(__cplusplus) || defined(c_plusplus)
527 }
528 #endif
529 
530 MagickExport const LogInfo **GetLogInfoList(const char *pattern,
531  size_t *number_preferences,ExceptionInfo *exception)
532 {
533  const LogInfo
534  **preferences;
535 
537  *p;
538 
539  ssize_t
540  i;
541 
542  assert(pattern != (char *) NULL);
543  assert(number_preferences != (size_t *) NULL);
544  if (IsEventLogging() != MagickFalse)
545  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
546  *number_preferences=0;
547  if (IsLogCacheInstantiated(exception) == MagickFalse)
548  return((const LogInfo **) NULL);
549  preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
550  GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
551  if (preferences == (const LogInfo **) NULL)
552  return((const LogInfo **) NULL);
553  LockSemaphoreInfo(log_semaphore);
554  p=GetHeadElementInLinkedList(log_cache);
555  for (i=0; p != (ElementInfo *) NULL; )
556  {
557  const LogInfo
558  *log_info;
559 
560  log_info=(const LogInfo *) p->value;
561  if ((log_info->stealth == MagickFalse) &&
562  (GlobExpression(log_info->name,pattern,MagickFalse) != MagickFalse))
563  preferences[i++]=log_info;
564  p=p->next;
565  }
566  UnlockSemaphoreInfo(log_semaphore);
567  if (i == 0)
568  preferences=(const LogInfo **) RelinquishMagickMemory((void*) preferences);
569  else
570  {
571  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
572  preferences[i]=(LogInfo *) NULL;
573  }
574  *number_preferences=(size_t) i;
575  return(preferences);
576 }
577 ␌
578 /*
579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
580 % %
581 % %
582 % %
583 % G e t L o g L i s t %
584 % %
585 % %
586 % %
587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588 %
589 % GetLogList() returns any logs that match the specified pattern.
590 %
591 % The format of the GetLogList function is:
592 %
593 % char **GetLogList(const char *pattern,size_t *number_preferences,
594 % ExceptionInfo *exception)
595 %
596 % A description of each parameter follows:
597 %
598 % o pattern: Specifies a pointer to a text string containing a pattern.
599 %
600 % o number_preferences: This integer returns the number of logs in the list.
601 %
602 % o exception: return any errors or warnings in this structure.
603 %
604 */
605 
606 #if defined(__cplusplus) || defined(c_plusplus)
607 extern "C" {
608 #endif
609 
610 static int LogCompare(const void *x,const void *y)
611 {
612  const char
613  **p,
614  **q;
615 
616  p=(const char **) x;
617  q=(const char **) y;
618  return(LocaleCompare(*p,*q));
619 }
620 
621 #if defined(__cplusplus) || defined(c_plusplus)
622 }
623 #endif
624 
625 MagickExport char **GetLogList(const char *pattern,size_t *number_preferences,
626  ExceptionInfo *exception)
627 {
628  char
629  **preferences;
630 
632  *p;
633 
634  ssize_t
635  i;
636 
637  assert(pattern != (char *) NULL);
638  assert(number_preferences != (size_t *) NULL);
639  if (IsEventLogging() != MagickFalse)
640  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
641  *number_preferences=0;
642  if (IsLogCacheInstantiated(exception) == MagickFalse)
643  return((char **) NULL);
644  preferences=(char **) AcquireQuantumMemory((size_t)
645  GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
646  if (preferences == (char **) NULL)
647  return((char **) NULL);
648  LockSemaphoreInfo(log_semaphore);
649  p=GetHeadElementInLinkedList(log_cache);
650  for (i=0; p != (ElementInfo *) NULL; )
651  {
652  const LogInfo
653  *log_info;
654 
655  log_info=(const LogInfo *) p->value;
656  if ((log_info->stealth == MagickFalse) &&
657  (GlobExpression(log_info->name,pattern,MagickFalse) != MagickFalse))
658  preferences[i++]=ConstantString(log_info->name);
659  p=p->next;
660  }
661  UnlockSemaphoreInfo(log_semaphore);
662  if (i == 0)
663  preferences=(char **) RelinquishMagickMemory(preferences);
664  else
665  {
666  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
667  preferences[i]=(char *) NULL;
668  }
669  *number_preferences=(size_t) i;
670  return(preferences);
671 }
672 ␌
673 /*
674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675 % %
676 % %
677 % %
678 % G e t L o g N a m e %
679 % %
680 % %
681 % %
682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 %
684 % GetLogName() returns the current log name.
685 %
686 % The format of the GetLogName method is:
687 %
688 % const char *GetLogName(void)
689 %
690 */
691 MagickExport const char *GetLogName(void)
692 {
693  return(log_name);
694 }
695 ␌
696 /*
697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698 % %
699 % %
700 % %
701 + I s L o g C a c h e I n s t a n t i a t e d %
702 % %
703 % %
704 % %
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706 %
707 % IsLogCacheInstantiated() determines if the log list is instantiated. If
708 % not, it instantiates the list and returns it.
709 %
710 % The format of the IsLogInstantiated method is:
711 %
712 % MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
713 %
714 % A description of each parameter follows.
715 %
716 % o exception: return any errors or warnings in this structure.
717 %
718 */
719 
720 static inline void CheckEventLogging(void)
721 {
722  /*
723  Are we logging events?
724  */
725  if (IsLinkedListEmpty(log_cache) != MagickFalse)
726  event_logging=MagickFalse;
727  else
728  {
730  *p;
731 
732  p=GetHeadElementInLinkedList(log_cache);
733  event_logging=(p != (ElementInfo *) NULL) &&
734  (((LogInfo *) p->value)->event_mask != NoEvents) ?
735  MagickTrue: MagickFalse;
736  }
737 }
738 
739 static MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
740 {
741  if (log_cache == (LinkedListInfo *) NULL)
742  {
743  if (log_semaphore == (SemaphoreInfo *) NULL)
744  ActivateSemaphoreInfo(&log_semaphore);
745  LockSemaphoreInfo(log_semaphore);
746  if (log_cache == (LinkedListInfo *) NULL)
747  {
748  log_cache=AcquireLogCache(LogFilename,exception);
749  CheckEventLogging();
750  }
751  UnlockSemaphoreInfo(log_semaphore);
752  }
753  return(log_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
754 }
755 ␌
756 /*
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 % %
759 % %
760 % %
761 % I s E v e n t L o g g i n g %
762 % %
763 % %
764 % %
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 %
767 % IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
768 % MagickFalse.
769 %
770 % The format of the IsEventLogging method is:
771 %
772 % MagickBooleanType IsEventLogging(void)
773 %
774 */
775 MagickExport MagickBooleanType IsEventLogging(void)
776 {
777  return(event_logging);
778 }
779 ␌
780 /*
781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 % %
783 % %
784 % %
785 % L i s t L o g I n f o %
786 % %
787 % %
788 % %
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 %
791 % ListLogInfo() lists the log info to a file.
792 %
793 % The format of the ListLogInfo method is:
794 %
795 % MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
796 %
797 % A description of each parameter follows.
798 %
799 % o file: An pointer to a FILE.
800 %
801 % o exception: return any errors or warnings in this structure.
802 %
803 */
804 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
805 {
806 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
807 
808  const char
809  *path;
810 
811  const LogInfo
812  **log_info;
813 
814  ssize_t
815  i;
816 
817  size_t
818  number_aliases;
819 
820  ssize_t
821  j;
822 
823  if (file == (const FILE *) NULL)
824  file=stdout;
825  log_info=GetLogInfoList("*",&number_aliases,exception);
826  if (log_info == (const LogInfo **) NULL)
827  return(MagickFalse);
828  j=0;
829  path=(const char *) NULL;
830  for (i=0; i < (ssize_t) number_aliases; i++)
831  {
832  char
833  limit[MagickPathExtent];
834 
835  if (log_info[i]->stealth != MagickFalse)
836  continue;
837  if ((path == (const char *) NULL) ||
838  (LocaleCompare(path,log_info[i]->path) != 0))
839  {
840  if (log_info[i]->path != (char *) NULL)
841  (void) FormatLocaleFile(file,"\nPath: %s\nHandler: ",
842  log_info[i]->path);
843  for (j=0; j < (ssize_t) (8*sizeof(LogHandlerType)); j++)
844  {
845  size_t
846  mask;
847 
848  if (*LogHandlers[j].name == '\0')
849  break;
850  mask=1;
851  mask<<=j;
852  if (((size_t) log_info[i]->handler_mask & mask) != 0)
853  (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name);
854  }
855  (void) FormatLocaleFile(file,"\n\n");
856  }
857  (void) FormatLocaleFile(file,
858  "Generations Limit Filename\n");
859  (void) FormatLocaleFile(file,"---------------------------------------------"
860  "----------------------------------\n");
861  (void) FormatLocaleFile(file,"%g ",(double) log_info[i]->generations);
862  (void) CopyMagickString(limit,"unlimited",MagickPathExtent);
863  if (log_info[i]->limit > 0)
864  (void) FormatMagickSize(log_info[i]->limit,MagickTrue,"B",
865  MagickFormatExtent,limit);
866  (void) FormatLocaleFile(file," %9s",limit);
867  if (log_info[i]->filename != (char *) NULL)
868  (void) FormatLocaleFile(file," %s",log_info[i]->filename);
869  (void) FormatLocaleFile(file,"\n");
870  if (log_info[i]->format != (char *) NULL)
871  (void) FormatLocaleFile(file," Format: %s\n",log_info[i]->format);
872  (void) FormatLocaleFile(file,"\n");
873  path=log_info[i]->path;
874  }
875  (void) fflush(file);
876  log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
877  return(MagickTrue);
878 }
879 ␌
880 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
881 /*
882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883 % %
884 % %
885 % %
886 % L o a d L o g C a c h e %
887 % %
888 % %
889 % %
890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891 %
892 % LoadLogCache() loads the log configurations which provides a
893 % mapping between log attributes and log name.
894 %
895 % The format of the LoadLogCache method is:
896 %
897 % MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
898 % const char *filename,const size_t depth,ExceptionInfo *exception)
899 %
900 % A description of each parameter follows:
901 %
902 % o xml: The log list in XML format.
903 %
904 % o filename: The log list filename.
905 %
906 % o depth: depth of <include /> statements.
907 %
908 % o exception: return any errors or warnings in this structure.
909 %
910 */
911 static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
912  const char *filename,const size_t depth,ExceptionInfo *exception)
913 {
914  char
915  keyword[MagickPathExtent],
916  *token;
917 
918  const char
919  *q;
920 
921  LogInfo
922  *log_info = (LogInfo *) NULL;
923 
924  MagickStatusType
925  status;
926 
927  size_t
928  extent;
929 
930  /*
931  Load the log map file.
932  */
933  if (xml == (const char *) NULL)
934  return(MagickFalse);
935  status=MagickTrue;
936  token=AcquireString(xml);
937  extent=strlen(token)+MagickPathExtent;
938  for (q=(const char *) xml; *q != '\0'; )
939  {
940  /*
941  Interpret XML.
942  */
943  (void) GetNextToken(q,&q,extent,token);
944  if (*token == '\0')
945  break;
946  (void) CopyMagickString(keyword,token,MagickPathExtent);
947  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
948  {
949  /*
950  Doctype element.
951  */
952  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
953  (void) GetNextToken(q,&q,extent,token);
954  continue;
955  }
956  if (LocaleNCompare(keyword,"<!--",4) == 0)
957  {
958  /*
959  Comment element.
960  */
961  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
962  (void) GetNextToken(q,&q,extent,token);
963  continue;
964  }
965  if (LocaleCompare(keyword,"<include") == 0)
966  {
967  /*
968  Include element.
969  */
970  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
971  {
972  (void) CopyMagickString(keyword,token,MagickPathExtent);
973  (void) GetNextToken(q,&q,extent,token);
974  if (*token != '=')
975  continue;
976  (void) GetNextToken(q,&q,extent,token);
977  if (LocaleCompare(keyword,"file") == 0)
978  {
979  if (depth > MagickMaxRecursionDepth)
980  (void) ThrowMagickException(exception,GetMagickModule(),
981  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
982  else
983  {
984  char
985  path[MagickPathExtent],
986  *file_xml;
987 
988  GetPathComponent(filename,HeadPath,path);
989  if (*path != '\0')
990  (void) ConcatenateMagickString(path,DirectorySeparator,
991  MagickPathExtent);
992  if (*token == *DirectorySeparator)
993  (void) CopyMagickString(path,token,MagickPathExtent);
994  else
995  (void) ConcatenateMagickString(path,token,MagickPathExtent);
996  file_xml=FileToXML(path,~0UL);
997  if (file_xml != (char *) NULL)
998  {
999  status&=(MagickStatusType) LoadLogCache(cache,file_xml,
1000  path,depth+1,exception);
1001  file_xml=DestroyString(file_xml);
1002  }
1003  }
1004  }
1005  }
1006  continue;
1007  }
1008  if (LocaleCompare(keyword,"<logmap>") == 0)
1009  {
1010  /*
1011  Allocate memory for the log list.
1012  */
1013  log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info));
1014  (void) memset(log_info,0,sizeof(*log_info));
1015  log_info->path=ConstantString(filename);
1016  GetTimerInfo((TimerInfo *) &log_info->timer);
1017  log_info->signature=MagickCoreSignature;
1018  continue;
1019  }
1020  if (log_info == (LogInfo *) NULL)
1021  continue;
1022  if (LocaleCompare(keyword,"</logmap>") == 0)
1023  {
1024  status=AppendValueToLinkedList(cache,log_info);
1025  if (status == MagickFalse)
1026  (void) ThrowMagickException(exception,GetMagickModule(),
1027  ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1028  log_info=(LogInfo *) NULL;
1029  continue;
1030  }
1031  (void) GetNextToken(q,(const char **) NULL,extent,token);
1032  if (*token != '=')
1033  continue;
1034  (void) GetNextToken(q,&q,extent,token);
1035  (void) GetNextToken(q,&q,extent,token);
1036  switch (*keyword)
1037  {
1038  case 'E':
1039  case 'e':
1040  {
1041  if (LocaleCompare((char *) keyword,"events") == 0)
1042  {
1043  log_info->event_mask=(LogEventType) (log_info->event_mask |
1044  ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
1045  break;
1046  }
1047  break;
1048  }
1049  case 'F':
1050  case 'f':
1051  {
1052  if (LocaleCompare((char *) keyword,"filename") == 0)
1053  {
1054  if (log_info->filename != (char *) NULL)
1055  log_info->filename=(char *)
1056  RelinquishMagickMemory(log_info->filename);
1057  log_info->filename=ConstantString(token);
1058  break;
1059  }
1060  if (LocaleCompare((char *) keyword,"format") == 0)
1061  {
1062  if (log_info->format != (char *) NULL)
1063  log_info->format=(char *)
1064  RelinquishMagickMemory(log_info->format);
1065  log_info->format=ConstantString(token);
1066  break;
1067  }
1068  break;
1069  }
1070  case 'G':
1071  case 'g':
1072  {
1073  if (LocaleCompare((char *) keyword,"generations") == 0)
1074  {
1075  if (LocaleCompare(token,"unlimited") == 0)
1076  {
1077  log_info->generations=(~0UL);
1078  break;
1079  }
1080  log_info->generations=StringToUnsignedLong(token);
1081  break;
1082  }
1083  break;
1084  }
1085  case 'L':
1086  case 'l':
1087  {
1088  if (LocaleCompare((char *) keyword,"limit") == 0)
1089  {
1090  if (LocaleCompare(token,"unlimited") == 0)
1091  {
1092  log_info->limit=(~0UL);
1093  break;
1094  }
1095  log_info->limit=StringToMagickSizeType(token,100.0);
1096  if (log_info->limit < 1024)
1097  log_info->limit=1024*1024*StringToUnsignedLong(token);
1098  break;
1099  }
1100  break;
1101  }
1102  case 'O':
1103  case 'o':
1104  {
1105  if (LocaleCompare((char *) keyword,"output") == 0)
1106  {
1107  log_info->handler_mask=(LogHandlerType)
1108  (log_info->handler_mask | ParseLogHandlers(token));
1109  break;
1110  }
1111  break;
1112  }
1113  default:
1114  break;
1115  }
1116  }
1117  token=DestroyString(token);
1118  if (cache == (LinkedListInfo *) NULL)
1119  return(MagickFalse);
1120  return(status != 0 ? MagickTrue : MagickFalse);
1121 }
1122 #endif
1123 ␌
1124 /*
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 % %
1127 % %
1128 % %
1129 + L o g C o m p o n e n t G e n e s i s %
1130 % %
1131 % %
1132 % %
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1134 %
1135 % LogComponentGenesis() instantiates the log component.
1136 %
1137 % The format of the LogComponentGenesis method is:
1138 %
1139 % MagickBooleanType LogComponentGenesis(void)
1140 %
1141 */
1142 MagickPrivate MagickBooleanType LogComponentGenesis(void)
1143 {
1145  *exception;
1146 
1147  if (log_semaphore == (SemaphoreInfo *) NULL)
1148  log_semaphore=AcquireSemaphoreInfo();
1149  exception=AcquireExceptionInfo();
1150  (void) GetLogInfo("*",exception);
1151  exception=DestroyExceptionInfo(exception);
1152  return(MagickTrue);
1153 }
1154 ␌
1155 /*
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157 % %
1158 % %
1159 % %
1160 + L o g C o m p o n e n t T e r m i n u s %
1161 % %
1162 % %
1163 % %
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 %
1166 % LogComponentTerminus() destroys the logging component.
1167 %
1168 % The format of the LogComponentTerminus method is:
1169 %
1170 % LogComponentTerminus(void)
1171 %
1172 */
1173 
1174 static void *DestroyLogElement(void *log_info)
1175 {
1176  LogInfo
1177  *p;
1178 
1179  p=(LogInfo *) log_info;
1180  if (p->file != (FILE *) NULL)
1181  {
1182  (void) FormatLocaleFile(p->file,"</log>\n");
1183  (void) fclose(p->file);
1184  p->file=(FILE *) NULL;
1185  }
1186  if (p->format != (char *) NULL)
1187  p->format=DestroyString(p->format);
1188  if (p->path != (char *) NULL)
1189  p->path=DestroyString(p->path);
1190  if (p->filename != (char *) NULL)
1191  p->filename=DestroyString(p->filename);
1192  if (p->event_semaphore != (SemaphoreInfo *) NULL)
1193  RelinquishSemaphoreInfo(&p->event_semaphore);
1194  p=(LogInfo *) RelinquishMagickMemory(p);
1195  return((void *) NULL);
1196 }
1197 
1198 MagickPrivate void LogComponentTerminus(void)
1199 {
1200  if (log_semaphore == (SemaphoreInfo *) NULL)
1201  ActivateSemaphoreInfo(&log_semaphore);
1202  LockSemaphoreInfo(log_semaphore);
1203  if (log_cache != (LinkedListInfo *) NULL)
1204  log_cache=DestroyLinkedList(log_cache,DestroyLogElement);
1205  event_logging=MagickFalse;
1206  UnlockSemaphoreInfo(log_semaphore);
1207  RelinquishSemaphoreInfo(&log_semaphore);
1208 }
1209 ␌
1210 /*
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 % %
1213 % %
1214 % %
1215 % L o g M a g i c k E v e n t %
1216 % %
1217 % %
1218 % %
1219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1220 %
1221 % LogMagickEvent() logs an event as determined by the log configuration file.
1222 % If an error occurs, MagickFalse is returned otherwise MagickTrue.
1223 %
1224 % The format of the LogMagickEvent method is:
1225 %
1226 % MagickBooleanType LogMagickEvent(const LogEventType type,
1227 % const char *module,const char *function,const size_t line,
1228 % const char *format,...)
1229 %
1230 % A description of each parameter follows:
1231 %
1232 % o type: the event type.
1233 %
1234 % o filename: the source module filename.
1235 %
1236 % o function: the function name.
1237 %
1238 % o line: the line number of the source module.
1239 %
1240 % o format: the output format.
1241 %
1242 */
1243 
1244 static void FormatLogFilename(const LogInfo *log_info,const ssize_t generation,
1245  char *filename)
1246 {
1247  char
1248  *q;
1249 
1250  const char
1251  *p;
1252 
1253  /*
1254  Translate event in "human readable" format.
1255  */
1256  assert(log_info != (LogInfo *) NULL);
1257  q=filename;
1258  for (p=log_info->filename; *p != '\0'; p++)
1259  {
1260  /*
1261  The format of the filename is defined by embedding special format
1262  characters:
1263 
1264  %c client name
1265  %n log name
1266  %p process id
1267  %v version
1268  %% percent sign
1269  */
1270  if (*p != '%')
1271  {
1272  *q++=(*p);
1273  continue;
1274  }
1275  p++;
1276  if (*p == '\0')
1277  break;
1278  switch (*p)
1279  {
1280  case '\0':
1281  {
1282  p--;
1283  break;
1284  }
1285  case 'c':
1286  {
1287  q+=(ptrdiff_t) CopyMagickString(q,GetClientName(),MagickPathExtent);
1288  break;
1289  }
1290  case 'g':
1291  {
1292  if (log_info->generations == 0)
1293  {
1294  (void) CopyMagickString(q,"0",MagickPathExtent);
1295  q++;
1296  break;
1297  }
1298  q+=(ptrdiff_t) FormatLocaleString(q,MagickPathExtent,"%.17g",(double)
1299  (generation % log_info->generations));
1300  break;
1301  }
1302  case 'n':
1303  {
1304  q+=(ptrdiff_t) CopyMagickString(q,GetLogName(),MagickPathExtent);
1305  break;
1306  }
1307  case 'p':
1308  {
1309  q+=(ptrdiff_t) FormatLocaleString(q,MagickPathExtent,"%.17g",(double)
1310  getpid());
1311  break;
1312  }
1313  case 'v':
1314  {
1315  q+=(ptrdiff_t) CopyMagickString(q,MagickLibVersionText,
1316  MagickPathExtent);
1317  break;
1318  }
1319  case '%':
1320  {
1321  *q++=(*p);
1322  break;
1323  }
1324  default:
1325  {
1326  *q++='%';
1327  *q++=(*p);
1328  break;
1329  }
1330  }
1331  }
1332  *q='\0';
1333 }
1334 
1335 static char *TranslateEvent(const char *module,const char *function,
1336  const size_t line,const char *domain,const char *event)
1337 {
1338  char
1339  *text;
1340 
1341  double
1342  elapsed_time,
1343  user_time;
1344 
1346  *exception;
1347 
1348  LogInfo
1349  *log_info;
1350 
1351  char
1352  *q;
1353 
1354  const char
1355  *p;
1356 
1357  size_t
1358  extent;
1359 
1360  time_t
1361  seconds;
1362 
1363  exception=AcquireExceptionInfo();
1364  log_info=GetLogInfo("*",exception);
1365  exception=DestroyExceptionInfo(exception);
1366  text=AcquireString(event);
1367  if (log_info == (LogInfo *) NULL)
1368  return(text);
1369  seconds=GetMagickTime();
1370  elapsed_time=GetElapsedTime(&log_info->timer);
1371  user_time=GetUserTime(&log_info->timer);
1372  if (log_info->format == (char *) NULL)
1373  return(text);
1374  extent=strlen(event)+MagickPathExtent;
1375  if (LocaleCompare(log_info->format,"xml") == 0)
1376  {
1377  char
1378  timestamp[MagickTimeExtent];
1379 
1380  /*
1381  Translate event in "XML" format.
1382  */
1383  (void) FormatMagickTime(seconds,sizeof(timestamp),timestamp);
1384  (void) FormatLocaleString(text,extent,
1385  "<entry>\n"
1386  " <timestamp>%s</timestamp>\n"
1387  " <elapsed-time>%lu:%02lu.%06lu</elapsed-time>\n"
1388  " <user-time>%0.3f</user-time>\n"
1389  " <process-id>%.17g</process-id>\n"
1390  " <thread-id>%.17g</thread-id>\n"
1391  " <module>%s</module>\n"
1392  " <function>%s</function>\n"
1393  " <line>%.17g</line>\n"
1394  " <domain>%s</domain>\n"
1395  " <event>%s</event>\n"
1396  "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
1397  (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
1398  (1000000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
1399  (double) getpid(),(double) GetMagickThreadSignature(),module,function,
1400  (double) line,domain,event);
1401  return(text);
1402  }
1403  /*
1404  Translate event in "human readable" format.
1405  */
1406  q=text;
1407  for (p=log_info->format; *p != '\0'; p++)
1408  {
1409  *q='\0';
1410  if ((size_t) (q-text+MagickPathExtent) >= extent)
1411  {
1412  extent<<=1;
1413  text=(char *) ResizeQuantumMemory(text,extent,sizeof(*text));
1414  if (text == (char *) NULL)
1415  return((char *) NULL);
1416  q=text+strlen(text);
1417  }
1418  /*
1419  The format of the log is defined by embedding special format characters:
1420 
1421  %c client name
1422  %d domain
1423  %e event
1424  %f function
1425  %i thread id
1426  %l line
1427  %m module
1428  %n log name
1429  %p process id
1430  %r real CPU time
1431  %t wall clock time
1432  %u user CPU time
1433  %v version
1434  %% percent sign
1435  \n newline
1436  \r carriage return
1437  */
1438  if ((*p == '\\') && (*(p+1) == 'r'))
1439  {
1440  *q++='\r';
1441  p++;
1442  continue;
1443  }
1444  if ((*p == '\\') && (*(p+1) == 'n'))
1445  {
1446  *q++='\n';
1447  p++;
1448  continue;
1449  }
1450  if (*p != '%')
1451  {
1452  *q++=(*p);
1453  continue;
1454  }
1455  p++;
1456  if (*p == '\0')
1457  break;
1458  switch (*p)
1459  {
1460  case 'c':
1461  {
1462  q+=(ptrdiff_t) CopyMagickString(q,GetClientName(),extent-(q-text));
1463  break;
1464  }
1465  case 'd':
1466  {
1467  q+=(ptrdiff_t) CopyMagickString(q,domain,extent-(q-text));
1468  break;
1469  }
1470  case 'e':
1471  {
1472  q+=(ptrdiff_t) CopyMagickString(q,event,extent-(q-text));
1473  break;
1474  }
1475  case 'f':
1476  {
1477  q+=(ptrdiff_t) CopyMagickString(q,function,extent-(q-text));
1478  break;
1479  }
1480  case 'i':
1481  {
1482  q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%.17g",(double)
1483  GetMagickThreadSignature());
1484  break;
1485  }
1486  case 'l':
1487  {
1488  q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%.17g",(double)
1489  line);
1490  break;
1491  }
1492  case 'm':
1493  {
1494  const char
1495  *r;
1496 
1497  for (r=module+strlen(module)-1; r > module; r--)
1498  if (*r == *DirectorySeparator)
1499  {
1500  r++;
1501  break;
1502  }
1503  q+=(ptrdiff_t) CopyMagickString(q,r,extent-(q-text));
1504  break;
1505  }
1506  case 'n':
1507  {
1508  q+=(ptrdiff_t) CopyMagickString(q,GetLogName(),extent-(q-text));
1509  break;
1510  }
1511  case 'p':
1512  {
1513  q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%.17g",(double)
1514  getpid());
1515  break;
1516  }
1517  case 'r':
1518  {
1519  q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%lu:%02lu.%03lu",
1520  (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod(
1521  elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor(
1522  elapsed_time))+0.5));
1523  break;
1524  }
1525  case 't':
1526  {
1527  q+=(ptrdiff_t) FormatMagickTime(seconds,extent-(q-text),q);
1528  break;
1529  }
1530  case 'u':
1531  {
1532  q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%0.3fu",user_time);
1533  break;
1534  }
1535  case 'v':
1536  {
1537  q+=(ptrdiff_t) CopyMagickString(q,MagickLibVersionText,extent-(q-text));
1538  break;
1539  }
1540  case '%':
1541  {
1542  *q++=(*p);
1543  break;
1544  }
1545  default:
1546  {
1547  *q++='%';
1548  *q++=(*p);
1549  break;
1550  }
1551  }
1552  }
1553  *q='\0';
1554  return(text);
1555 }
1556 
1557 MagickExport MagickBooleanType LogMagickEventList(const LogEventType type,
1558  const char *module,const char *function,const size_t line,const char *format,
1559  va_list operands)
1560 {
1561  char
1562  event[MagickPathExtent],
1563  *text;
1564 
1565  const char
1566  *domain;
1567 
1569  *exception;
1570 
1571  int
1572  n;
1573 
1574  LogInfo
1575  *log_info;
1576 
1577  exception=AcquireExceptionInfo();
1578  log_info=(LogInfo *) GetLogInfo("*",exception);
1579  exception=DestroyExceptionInfo(exception);
1580  if (log_info == (LogInfo *) NULL)
1581  return(MagickFalse);
1582  if (log_info->event_semaphore == (SemaphoreInfo *) NULL)
1583  ActivateSemaphoreInfo(&log_info->event_semaphore);
1584  LockSemaphoreInfo(log_info->event_semaphore);
1585  if ((log_info->event_mask & type) == 0)
1586  {
1587  UnlockSemaphoreInfo(log_info->event_semaphore);
1588  return(MagickTrue);
1589  }
1590  domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
1591  n=vsnprintf(event,MagickPathExtent,format,operands);
1592  if (n < 0)
1593  event[MagickPathExtent-1]='\0';
1594  text=TranslateEvent(module,function,line,domain,event);
1595  if (text == (char *) NULL)
1596  {
1597  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1598  UnlockSemaphoreInfo(log_info->event_semaphore);
1599  return(MagickFalse);
1600  }
1601  if ((log_info->handler_mask & ConsoleHandler) != 0)
1602  {
1603  (void) FormatLocaleFile(stderr,"%s\n",text);
1604  (void) fflush(stderr);
1605  }
1606  if ((log_info->handler_mask & DebugHandler) != 0)
1607  {
1608 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1609  OutputDebugString(text);
1610  OutputDebugString("\n");
1611 #endif
1612  }
1613  if ((log_info->handler_mask & EventHandler) != 0)
1614  {
1615 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1616  (void) NTReportEvent(text,MagickFalse);
1617 #endif
1618  }
1619  if ((log_info->handler_mask & FileHandler) != 0)
1620  {
1621  struct stat
1622  file_info;
1623 
1624  file_info.st_size=0;
1625  if (log_info->file != (FILE *) NULL)
1626  (void) fstat(fileno(log_info->file),&file_info);
1627  if (file_info.st_size > (MagickOffsetType) log_info->limit)
1628  {
1629  ssize_t
1630  i;
1631 
1632  /*
1633  Close log.
1634  */
1635  (void) FormatLocaleFile(log_info->file,"</log>\n");
1636  (void) FormatLocaleFile(log_info->file,"</logEntries>\n");
1637  (void) fclose(log_info->file);
1638  for (i=(ssize_t) log_info->generations-1; i > 0; i--)
1639  {
1640  char
1641  new_filename[MagickPathExtent],
1642  old_filename[MagickPathExtent];
1643 
1644  /*
1645  Rotate logs.
1646  */
1647  FormatLogFilename(log_info,i-1,old_filename);
1648  FormatLogFilename(log_info,i,new_filename);
1649  (void) rename_utf8(old_filename,new_filename);
1650  }
1651  log_info->file=(FILE *) NULL;
1652  }
1653  if (log_info->file == (FILE *) NULL)
1654  {
1655  char
1656  log_filename[MagickPathExtent];
1657 
1658  FormatLogFilename(log_info,0,log_filename);
1659  log_info->append=IsPathAccessible(log_filename);
1660  log_info->file=fopen_utf8(log_filename,"ab");
1661  if (log_info->file == (FILE *) NULL)
1662  {
1663  UnlockSemaphoreInfo(log_info->event_semaphore);
1664  return(MagickFalse);
1665  }
1666  if (log_info->append == MagickFalse)
1667  {
1668  (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1669  "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1670  (void) FormatLocaleFile(log_info->file,"<logEntries>\n");
1671  }
1672  (void) FormatLocaleFile(log_info->file,"<log>\n");
1673  }
1674  (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1675  (void) fflush(log_info->file);
1676  }
1677  if ((log_info->handler_mask & MethodHandler) != 0)
1678  {
1679  if (log_info->method != (MagickLogMethod) NULL)
1680  log_info->method(type,text);
1681  }
1682  if ((log_info->handler_mask & StdoutHandler) != 0)
1683  {
1684  (void) FormatLocaleFile(stdout,"%s\n",text);
1685  (void) fflush(stdout);
1686  }
1687  if ((log_info->handler_mask & StderrHandler) != 0)
1688  {
1689  (void) FormatLocaleFile(stderr,"%s\n",text);
1690  (void) fflush(stderr);
1691  }
1692  text=(char *) RelinquishMagickMemory(text);
1693  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1694  UnlockSemaphoreInfo(log_info->event_semaphore);
1695  return(MagickTrue);
1696 }
1697 
1698 MagickExport MagickBooleanType LogMagickEvent(const LogEventType type,
1699  const char *module,const char *function,const size_t line,
1700  const char *format,...)
1701 {
1702  va_list
1703  operands;
1704 
1705  MagickBooleanType
1706  status;
1707 
1708  if (IsEventLogging() == MagickFalse)
1709  return(MagickFalse);
1710  va_start(operands,format);
1711  status=LogMagickEventList(type,module,function,line,format,operands);
1712  va_end(operands);
1713  return(status);
1714 }
1715 ␌
1716 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1717 /*
1718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719 % %
1720 % %
1721 % %
1722 % P a r s e L o g H a n d l e r s %
1723 % %
1724 % %
1725 % %
1726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727 %
1728 % ParseLogHandlers() parses a string defining which handlers takes a log
1729 % message and exports them.
1730 %
1731 % The format of the ParseLogHandlers method is:
1732 %
1733 % LogHandlerType ParseLogHandlers(const char *handlers)
1734 %
1735 % A description of each parameter follows:
1736 %
1737 % o handlers: one or more handlers separated by commas.
1738 %
1739 */
1740 static LogHandlerType ParseLogHandlers(const char *handlers)
1741 {
1742  LogHandlerType
1743  handler_mask;
1744 
1745  const char
1746  *p;
1747 
1748  ssize_t
1749  i;
1750 
1751  size_t
1752  length;
1753 
1754  handler_mask=NoHandler;
1755  for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1756  {
1757  while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1758  (*p == ',')))
1759  p++;
1760  for (i=0; *LogHandlers[i].name != '\0'; i++)
1761  {
1762  length=strlen(LogHandlers[i].name);
1763  if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1764  {
1765  handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1766  break;
1767  }
1768  }
1769  if (*LogHandlers[i].name == '\0')
1770  return(UndefinedHandler);
1771  }
1772  return(handler_mask);
1773 }
1774 #endif
1775 ␌
1776 /*
1777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1778 % %
1779 % %
1780 % %
1781 % S e t L o g E v e n t M a s k %
1782 % %
1783 % %
1784 % %
1785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1786 %
1787 % SetLogEventMask() accepts a list that determines which events to log. All
1788 % other events are ignored. By default, no debug is enabled. This method
1789 % returns the previous log event mask.
1790 %
1791 % The format of the SetLogEventMask method is:
1792 %
1793 % LogEventType SetLogEventMask(const char *events)
1794 %
1795 % A description of each parameter follows:
1796 %
1797 % o events: log these events.
1798 %
1799 */
1800 MagickExport LogEventType SetLogEventMask(const char *events)
1801 {
1803  *exception;
1804 
1805  LogEventType
1806  event_mask;
1807 
1808  LogInfo
1809  *log_info;
1810 
1811  ssize_t
1812  option;
1813 
1814  event_mask=UndefinedEvents;
1815  exception=AcquireExceptionInfo();
1816  log_info=GetLogInfo("*",exception);
1817  exception=DestroyExceptionInfo(exception);
1818  if (log_info == (LogInfo *) NULL)
1819  return(event_mask);
1820  option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
1821  LockSemaphoreInfo(log_semaphore);
1822  event_mask=log_info->event_mask;
1823  if (option == -1)
1824  log_info->event_mask=UndefinedEvents;
1825  else
1826  log_info->event_mask=(LogEventType) option;
1827  CheckEventLogging();
1828  UnlockSemaphoreInfo(log_semaphore);
1829  return(event_mask);
1830 }
1831 ␌
1832 /*
1833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1834 % %
1835 % %
1836 % %
1837 % S e t L o g F o r m a t %
1838 % %
1839 % %
1840 % %
1841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842 %
1843 % SetLogFormat() sets the format for the "human readable" log record.
1844 %
1845 % The format of the LogMagickFormat method is:
1846 %
1847 % SetLogFormat(const char *format)
1848 %
1849 % A description of each parameter follows:
1850 %
1851 % o format: the log record format.
1852 %
1853 */
1854 MagickExport void SetLogFormat(const char *format)
1855 {
1856  LogInfo
1857  *log_info;
1858 
1860  *exception;
1861 
1862  exception=AcquireExceptionInfo();
1863  log_info=(LogInfo *) GetLogInfo("*",exception);
1864  exception=DestroyExceptionInfo(exception);
1865  if (log_info == (LogInfo *) NULL)
1866  return;
1867  LockSemaphoreInfo(log_semaphore);
1868  if (log_info->format != (char *) NULL)
1869  log_info->format=DestroyString(log_info->format);
1870  log_info->format=ConstantString(format);
1871  UnlockSemaphoreInfo(log_semaphore);
1872 }
1873 ␌
1874 /*
1875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1876 % %
1877 % %
1878 % %
1879 % S e t L o g M e t h o d %
1880 % %
1881 % %
1882 % %
1883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1884 %
1885 % SetLogMethod() sets the method that will be called when an event is logged.
1886 %
1887 % The format of the SetLogMethod method is:
1888 %
1889 % void SetLogMethod(MagickLogMethod method)
1890 %
1891 % A description of each parameter follows:
1892 %
1893 % o method: pointer to a method that will be called when LogMagickEvent is
1894 % being called.
1895 %
1896 */
1897 MagickExport void SetLogMethod(MagickLogMethod method)
1898 {
1900  *exception;
1901 
1902  LogInfo
1903  *log_info;
1904 
1905  exception=AcquireExceptionInfo();
1906  log_info=(LogInfo *) GetLogInfo("*",exception);
1907  exception=DestroyExceptionInfo(exception);
1908  if (log_info == (LogInfo *) NULL)
1909  return;
1910  LockSemaphoreInfo(log_semaphore);
1911  log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1912  log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1913  MethodHandler);
1914  log_info->method=method;
1915  UnlockSemaphoreInfo(log_semaphore);
1916 }
1917 ␌
1918 /*
1919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1920 % %
1921 % %
1922 % %
1923 % S e t L o g N a m e %
1924 % %
1925 % %
1926 % %
1927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1928 %
1929 % SetLogName() sets the log name and returns it.
1930 %
1931 % The format of the SetLogName method is:
1932 %
1933 % const char *SetLogName(const char *name)
1934 %
1935 % A description of each parameter follows:
1936 %
1937 % o log_name: SetLogName() returns the current client name.
1938 %
1939 % o name: Specifies the new client name.
1940 %
1941 */
1942 MagickExport const char *SetLogName(const char *name)
1943 {
1944  if ((name != (char *) NULL) && (*name != '\0'))
1945  (void) CopyMagickString(log_name,name,MagickPathExtent);
1946  return(log_name);
1947 }
Definition: log.c:93
Definition: log.c:111