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