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