MagickCore  7.1.0
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 "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/configure-private.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/linked-list.h"
50 #include "MagickCore/log.h"
51 #include "MagickCore/log-private.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/semaphore.h"
56 #include "MagickCore/timer.h"
57 #include "MagickCore/string_.h"
58 #include "MagickCore/string-private.h"
59 #include "MagickCore/thread_.h"
60 #include "MagickCore/thread-private.h"
61 #include "MagickCore/timer-private.h"
62 #include "MagickCore/token.h"
63 #include "MagickCore/utility.h"
64 #include "MagickCore/utility-private.h"
65 #include "MagickCore/version.h"
66 #include "MagickCore/xml-tree.h"
67 #include "MagickCore/xml-tree-private.h"
68 ␌
69 /*
70  Define declarations.
71 */
72 #define LogFilename "log.xml"
73 ␌
74 /*
75  Typedef declarations.
76 */
77 typedef enum
78 {
79  UndefinedHandler = 0x0000,
80  NoHandler = 0x0000,
81  ConsoleHandler = 0x0001,
82  StdoutHandler = 0x0002,
83  StderrHandler = 0x0004,
84  FileHandler = 0x0008,
85  DebugHandler = 0x0010,
86  EventHandler = 0x0020,
87  MethodHandler = 0x0040
88 } LogHandlerType;
89 
90 typedef struct _EventInfo
91 {
92  char
93  *name;
94 
95  LogEventType
96  event;
97 } EventInfo;
98 
99 typedef struct _HandlerInfo
100 {
101  const char
102  name[10];
103 
104  LogHandlerType
105  handler;
106 } HandlerInfo;
107 
108 struct _LogInfo
109 {
110  LogEventType
111  event_mask;
112 
113  LogHandlerType
114  handler_mask;
115 
116  char
117  *path,
118  *name,
119  *filename,
120  *format;
121 
122  size_t
123  generations,
124  limit;
125 
126  FILE
127  *file;
128 
129  size_t
130  generation;
131 
132  MagickBooleanType
133  append,
134  stealth;
135 
136  TimerInfo
137  timer;
138 
139  MagickLogMethod
140  method;
141 
143  *event_semaphore;
144 
145  size_t
146  signature;
147 };
148 
149 typedef struct _LogMapInfo
150 {
151  const LogEventType
152  event_mask;
153 
154  const LogHandlerType
155  handler_mask;
156 
157  const char
158  *filename,
159  *format;
160 } LogMapInfo;
161 ␌
162 /*
163  Static declarations.
164 */
165 static const HandlerInfo
166  LogHandlers[32] =
167  {
168  { "Console", ConsoleHandler },
169  { "Debug", DebugHandler },
170  { "Event", EventHandler },
171  { "File", FileHandler },
172  { "None", NoHandler },
173  { "Stderr", StderrHandler },
174  { "Stdout", StdoutHandler },
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  { "", UndefinedHandler },
199  { "", UndefinedHandler }
200  };
201 
202 static const LogMapInfo
203  LogMap[] =
204  {
205  { NoEvents, ConsoleHandler, "Magick-%g.log",
206  "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\\n %e" }
207  };
208 
209 static char
210  log_name[MagickPathExtent] = "Magick";
211 
212 static LinkedListInfo
213  *log_cache = (LinkedListInfo *) NULL;
214 
215 static MagickBooleanType
216  event_logging = MagickFalse;
217 
218 static SemaphoreInfo
219  *log_semaphore = (SemaphoreInfo *) NULL;
220 ␌
221 /*
222  Forward declarations.
223 */
224 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
225 static LogHandlerType
226  ParseLogHandlers(const char *) magick_attribute((__pure__));
227 #endif
228 
229 static LogInfo
230  *GetLogInfo(const char *,ExceptionInfo *);
231 
232 static MagickBooleanType
233  IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__));
234 
235 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
236 static MagickBooleanType
237  LoadLogCache(LinkedListInfo *,const char *,const char *,const size_t,
238  ExceptionInfo *);
239 #endif
240 ␌
241 /*
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243 % %
244 % %
245 % %
246 % A c q u i r e L o g C a c h e %
247 % %
248 % %
249 % %
250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 %
252 % AcquireLogCache() caches one or more log configurations which provides a
253 % mapping between log attributes and log name.
254 %
255 % The format of the AcquireLogCache method is:
256 %
257 % LinkedListInfo *AcquireLogCache(const char *filename,
258 % ExceptionInfo *exception)
259 %
260 % A description of each parameter follows:
261 %
262 % o filename: the log configuration filename.
263 %
264 % o exception: return any errors or warnings in this structure.
265 %
266 */
267 static LinkedListInfo *AcquireLogCache(const char *filename,
268  ExceptionInfo *exception)
269 {
271  *cache;
272 
273  MagickStatusType
274  status;
275 
276  ssize_t
277  i;
278 
279  /*
280  Load external log map.
281  */
282  cache=NewLinkedList(0);
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 #else
303  magick_unreferenced(filename);
304 #endif
305  /*
306  Load built-in log map.
307  */
308  for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
309  {
310  LogInfo
311  *log_info;
312 
313  const LogMapInfo
314  *p;
315 
316  p=LogMap+i;
317  log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
318  if (log_info == (LogInfo *) NULL)
319  {
320  (void) ThrowMagickException(exception,GetMagickModule(),
321  ResourceLimitError,"MemoryAllocationFailed","`%s'",p->filename);
322  continue;
323  }
324  (void) memset(log_info,0,sizeof(*log_info));
325  log_info->path=ConstantString("[built-in]");
326  GetTimerInfo((TimerInfo *) &log_info->timer);
327  log_info->event_mask=p->event_mask;
328  log_info->handler_mask=p->handler_mask;
329  log_info->filename=ConstantString(p->filename);
330  log_info->format=ConstantString(p->format);
331  log_info->signature=MagickCoreSignature;
332  status&=AppendValueToLinkedList(cache,log_info);
333  if (status == MagickFalse)
334  (void) ThrowMagickException(exception,GetMagickModule(),
335  ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
336  }
337  return(cache);
338 }
339 ␌
340 /*
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 % %
343 % %
344 % %
345 % C l o s e M a g i c k L o g %
346 % %
347 % %
348 % %
349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 %
351 % CloseMagickLog() closes the Magick log.
352 %
353 % The format of the CloseMagickLog method is:
354 %
355 % CloseMagickLog(void)
356 %
357 */
358 MagickExport void CloseMagickLog(void)
359 {
361  *exception;
362 
363  LogInfo
364  *log_info;
365 
366  if (IsEventLogging() == MagickFalse)
367  return;
368  exception=AcquireExceptionInfo();
369  log_info=GetLogInfo("*",exception);
370  exception=DestroyExceptionInfo(exception);
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 % LogEventType 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,size_t *number_preferences,
615  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 const 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()
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 % %
773 % L i s t L o g I n f o %
774 % %
775 % %
776 % %
777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778 %
779 % ListLogInfo() lists the log info to a file.
780 %
781 % The format of the ListLogInfo method is:
782 %
783 % MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
784 %
785 % A description of each parameter follows.
786 %
787 % o file: An pointer to a FILE.
788 %
789 % o exception: return any errors or warnings in this structure.
790 %
791 */
792 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
793 {
794 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
795 
796  const char
797  *path;
798 
799  const LogInfo
800  **log_info;
801 
802  ssize_t
803  i;
804 
805  size_t
806  number_aliases;
807 
808  ssize_t
809  j;
810 
811  if (file == (const FILE *) NULL)
812  file=stdout;
813  log_info=GetLogInfoList("*",&number_aliases,exception);
814  if (log_info == (const LogInfo **) NULL)
815  return(MagickFalse);
816  j=0;
817  path=(const char *) NULL;
818  for (i=0; i < (ssize_t) number_aliases; i++)
819  {
820  if (log_info[i]->stealth != MagickFalse)
821  continue;
822  if ((path == (const char *) NULL) ||
823  (LocaleCompare(path,log_info[i]->path) != 0))
824  {
825  size_t
826  length;
827 
828  if (log_info[i]->path != (char *) NULL)
829  (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path);
830  length=0;
831  for (j=0; j < (ssize_t) (8*sizeof(LogHandlerType)); j++)
832  {
833  size_t
834  mask;
835 
836  if (*LogHandlers[j].name == '\0')
837  break;
838  mask=1;
839  mask<<=j;
840  if ((log_info[i]->handler_mask & mask) != 0)
841  {
842  (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name);
843  length+=strlen(LogHandlers[j].name);
844  }
845  }
846  for (j=(ssize_t) length; j <= 12; j++)
847  (void) FormatLocaleFile(file," ");
848  (void) FormatLocaleFile(file," Generations Limit Format\n");
849  (void) FormatLocaleFile(file,"-----------------------------------------"
850  "--------------------------------------\n");
851  }
852  path=log_info[i]->path;
853  if (log_info[i]->filename != (char *) NULL)
854  {
855  (void) FormatLocaleFile(file,"%s",log_info[i]->filename);
856  for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
857  (void) FormatLocaleFile(file," ");
858  }
859  (void) FormatLocaleFile(file,"%9g ",(double) log_info[i]->generations);
860  (void) FormatLocaleFile(file,"%8g ",(double) log_info[i]->limit);
861  if (log_info[i]->format != (char *) NULL)
862  (void) FormatLocaleFile(file,"%s",log_info[i]->format);
863  (void) FormatLocaleFile(file,"\n");
864  }
865  (void) fflush(file);
866  log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
867  return(MagickTrue);
868 }
869 ␌
870 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
871 /*
872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
873 % %
874 % %
875 % %
876 % L o a d L o g C a c h e %
877 % %
878 % %
879 % %
880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
881 %
882 % LoadLogCache() loads the log configurations which provides a
883 % mapping between log attributes and log name.
884 %
885 % The format of the LoadLogCache method is:
886 %
887 % MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
888 % const char *filename,const size_t depth,ExceptionInfo *exception)
889 %
890 % A description of each parameter follows:
891 %
892 % o xml: The log list in XML format.
893 %
894 % o filename: The log list filename.
895 %
896 % o depth: depth of <include /> statements.
897 %
898 % o exception: return any errors or warnings in this structure.
899 %
900 */
901 static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
902  const char *filename,const size_t depth,ExceptionInfo *exception)
903 {
904  char
905  keyword[MagickPathExtent],
906  *token;
907 
908  const char
909  *q;
910 
911  LogInfo
912  *log_info = (LogInfo *) NULL;
913 
914  MagickStatusType
915  status;
916 
917  size_t
918  extent;
919 
920  /*
921  Load the log map file.
922  */
923  if (xml == (const char *) NULL)
924  return(MagickFalse);
925  status=MagickTrue;
926  token=AcquireString(xml);
927  extent=strlen(token)+MagickPathExtent;
928  for (q=(const char *) xml; *q != '\0'; )
929  {
930  /*
931  Interpret XML.
932  */
933  (void) GetNextToken(q,&q,extent,token);
934  if (*token == '\0')
935  break;
936  (void) CopyMagickString(keyword,token,MagickPathExtent);
937  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
938  {
939  /*
940  Doctype element.
941  */
942  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
943  (void) GetNextToken(q,&q,extent,token);
944  continue;
945  }
946  if (LocaleNCompare(keyword,"<!--",4) == 0)
947  {
948  /*
949  Comment element.
950  */
951  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
952  (void) GetNextToken(q,&q,extent,token);
953  continue;
954  }
955  if (LocaleCompare(keyword,"<include") == 0)
956  {
957  /*
958  Include element.
959  */
960  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
961  {
962  (void) CopyMagickString(keyword,token,MagickPathExtent);
963  (void) GetNextToken(q,&q,extent,token);
964  if (*token != '=')
965  continue;
966  (void) GetNextToken(q,&q,extent,token);
967  if (LocaleCompare(keyword,"file") == 0)
968  {
969  if (depth > MagickMaxRecursionDepth)
970  (void) ThrowMagickException(exception,GetMagickModule(),
971  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
972  else
973  {
974  char
975  path[MagickPathExtent],
976  *file_xml;
977 
978  GetPathComponent(filename,HeadPath,path);
979  if (*path != '\0')
980  (void) ConcatenateMagickString(path,DirectorySeparator,
981  MagickPathExtent);
982  if (*token == *DirectorySeparator)
983  (void) CopyMagickString(path,token,MagickPathExtent);
984  else
985  (void) ConcatenateMagickString(path,token,MagickPathExtent);
986  file_xml=FileToXML(path,~0UL);
987  if (file_xml != (char *) NULL)
988  {
989  status&=LoadLogCache(cache,file_xml,path,depth+1,
990  exception);
991  file_xml=DestroyString(file_xml);
992  }
993  }
994  }
995  }
996  continue;
997  }
998  if (LocaleCompare(keyword,"<logmap>") == 0)
999  {
1000  /*
1001  Allocate memory for the log list.
1002  */
1003  log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info));
1004  (void) memset(log_info,0,sizeof(*log_info));
1005  log_info->path=ConstantString(filename);
1006  GetTimerInfo((TimerInfo *) &log_info->timer);
1007  log_info->signature=MagickCoreSignature;
1008  continue;
1009  }
1010  if (log_info == (LogInfo *) NULL)
1011  continue;
1012  if (LocaleCompare(keyword,"</logmap>") == 0)
1013  {
1014  status=AppendValueToLinkedList(cache,log_info);
1015  if (status == MagickFalse)
1016  (void) ThrowMagickException(exception,GetMagickModule(),
1017  ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1018  log_info=(LogInfo *) NULL;
1019  continue;
1020  }
1021  (void) GetNextToken(q,(const char **) NULL,extent,token);
1022  if (*token != '=')
1023  continue;
1024  (void) GetNextToken(q,&q,extent,token);
1025  (void) GetNextToken(q,&q,extent,token);
1026  switch (*keyword)
1027  {
1028  case 'E':
1029  case 'e':
1030  {
1031  if (LocaleCompare((char *) keyword,"events") == 0)
1032  {
1033  log_info->event_mask=(LogEventType) (log_info->event_mask |
1034  ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
1035  break;
1036  }
1037  break;
1038  }
1039  case 'F':
1040  case 'f':
1041  {
1042  if (LocaleCompare((char *) keyword,"filename") == 0)
1043  {
1044  if (log_info->filename != (char *) NULL)
1045  log_info->filename=(char *)
1046  RelinquishMagickMemory(log_info->filename);
1047  log_info->filename=ConstantString(token);
1048  break;
1049  }
1050  if (LocaleCompare((char *) keyword,"format") == 0)
1051  {
1052  if (log_info->format != (char *) NULL)
1053  log_info->format=(char *)
1054  RelinquishMagickMemory(log_info->format);
1055  log_info->format=ConstantString(token);
1056  break;
1057  }
1058  break;
1059  }
1060  case 'G':
1061  case 'g':
1062  {
1063  if (LocaleCompare((char *) keyword,"generations") == 0)
1064  {
1065  if (LocaleCompare(token,"unlimited") == 0)
1066  {
1067  log_info->generations=(~0UL);
1068  break;
1069  }
1070  log_info->generations=StringToUnsignedLong(token);
1071  break;
1072  }
1073  break;
1074  }
1075  case 'L':
1076  case 'l':
1077  {
1078  if (LocaleCompare((char *) keyword,"limit") == 0)
1079  {
1080  if (LocaleCompare(token,"unlimited") == 0)
1081  {
1082  log_info->limit=(~0UL);
1083  break;
1084  }
1085  log_info->limit=StringToUnsignedLong(token);
1086  break;
1087  }
1088  break;
1089  }
1090  case 'O':
1091  case 'o':
1092  {
1093  if (LocaleCompare((char *) keyword,"output") == 0)
1094  {
1095  log_info->handler_mask=(LogHandlerType)
1096  (log_info->handler_mask | ParseLogHandlers(token));
1097  break;
1098  }
1099  break;
1100  }
1101  default:
1102  break;
1103  }
1104  }
1105  token=DestroyString(token);
1106  if (cache == (LinkedListInfo *) NULL)
1107  return(MagickFalse);
1108  return(status != 0 ? MagickTrue : MagickFalse);
1109 }
1110 #endif
1111 ␌
1112 /*
1113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114 % %
1115 % %
1116 % %
1117 + L o g C o m p o n e n t G e n e s i s %
1118 % %
1119 % %
1120 % %
1121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122 %
1123 % LogComponentGenesis() instantiates the log component.
1124 %
1125 % The format of the LogComponentGenesis method is:
1126 %
1127 % MagickBooleanType LogComponentGenesis(void)
1128 %
1129 */
1130 MagickPrivate MagickBooleanType LogComponentGenesis(void)
1131 {
1133  *exception;
1134 
1135  if (log_semaphore == (SemaphoreInfo *) NULL)
1136  log_semaphore=AcquireSemaphoreInfo();
1137  exception=AcquireExceptionInfo();
1138  (void) GetLogInfo("*",exception);
1139  exception=DestroyExceptionInfo(exception);
1140  return(MagickTrue);
1141 }
1142 ␌
1143 /*
1144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1145 % %
1146 % %
1147 % %
1148 + L o g C o m p o n e n t T e r m i n u s %
1149 % %
1150 % %
1151 % %
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153 %
1154 % LogComponentTerminus() destroys the logging component.
1155 %
1156 % The format of the LogComponentTerminus method is:
1157 %
1158 % LogComponentTerminus(void)
1159 %
1160 */
1161 
1162 static void *DestroyLogElement(void *log_info)
1163 {
1164  LogInfo
1165  *p;
1166 
1167  p=(LogInfo *) log_info;
1168  if (p->file != (FILE *) NULL)
1169  {
1170  (void) FormatLocaleFile(p->file,"</log>\n");
1171  (void) fclose(p->file);
1172  p->file=(FILE *) NULL;
1173  }
1174  if (p->format != (char *) NULL)
1175  p->format=DestroyString(p->format);
1176  if (p->path != (char *) NULL)
1177  p->path=DestroyString(p->path);
1178  if (p->filename != (char *) NULL)
1179  p->filename=DestroyString(p->filename);
1180  if (p->event_semaphore != (SemaphoreInfo *) NULL)
1181  RelinquishSemaphoreInfo(&p->event_semaphore);
1182  p=(LogInfo *) RelinquishMagickMemory(p);
1183  return((void *) NULL);
1184 }
1185 
1186 MagickPrivate void LogComponentTerminus(void)
1187 {
1188  if (log_semaphore == (SemaphoreInfo *) NULL)
1189  ActivateSemaphoreInfo(&log_semaphore);
1190  LockSemaphoreInfo(log_semaphore);
1191  if (log_cache != (LinkedListInfo *) NULL)
1192  log_cache=DestroyLinkedList(log_cache,DestroyLogElement);
1193  event_logging=MagickFalse;
1194  UnlockSemaphoreInfo(log_semaphore);
1195  RelinquishSemaphoreInfo(&log_semaphore);
1196 }
1197 ␌
1198 /*
1199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200 % %
1201 % %
1202 % %
1203 % L o g M a g i c k E v e n t %
1204 % %
1205 % %
1206 % %
1207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1208 %
1209 % LogMagickEvent() logs an event as determined by the log configuration file.
1210 % If an error occurs, MagickFalse is returned otherwise MagickTrue.
1211 %
1212 % The format of the LogMagickEvent method is:
1213 %
1214 % MagickBooleanType LogMagickEvent(const LogEventType type,
1215 % const char *module,const char *function,const size_t line,
1216 % const char *format,...)
1217 %
1218 % A description of each parameter follows:
1219 %
1220 % o type: the event type.
1221 %
1222 % o filename: the source module filename.
1223 %
1224 % o function: the function name.
1225 %
1226 % o line: the line number of the source module.
1227 %
1228 % o format: the output format.
1229 %
1230 */
1231 
1232 static char *TranslateEvent(const char *module,const char *function,
1233  const size_t line,const char *domain,const char *event)
1234 {
1235  char
1236  *text;
1237 
1238  double
1239  elapsed_time,
1240  user_time;
1241 
1243  *exception;
1244 
1245  LogInfo
1246  *log_info;
1247 
1248  char
1249  *q;
1250 
1251  const char
1252  *p;
1253 
1254  size_t
1255  extent;
1256 
1257  time_t
1258  seconds;
1259 
1260  exception=AcquireExceptionInfo();
1261  log_info=(LogInfo *) GetLogInfo("*",exception);
1262  exception=DestroyExceptionInfo(exception);
1263  seconds=GetMagickTime();
1264  elapsed_time=GetElapsedTime(&log_info->timer);
1265  user_time=GetUserTime(&log_info->timer);
1266  text=AcquireString(event);
1267  if (log_info->format == (char *) NULL)
1268  return(text);
1269  extent=strlen(event)+MagickPathExtent;
1270  if (LocaleCompare(log_info->format,"xml") == 0)
1271  {
1272  char
1273  timestamp[MagickTimeExtent];
1274 
1275  /*
1276  Translate event in "XML" format.
1277  */
1278  (void) FormatMagickTime(seconds,sizeof(timestamp),timestamp);
1279  (void) FormatLocaleString(text,extent,
1280  "<entry>\n"
1281  " <timestamp>%s</timestamp>\n"
1282  " <elapsed-time>%lu:%02lu.%06lu</elapsed-time>\n"
1283  " <user-time>%0.3f</user-time>\n"
1284  " <process-id>%.20g</process-id>\n"
1285  " <thread-id>%.20g</thread-id>\n"
1286  " <module>%s</module>\n"
1287  " <function>%s</function>\n"
1288  " <line>%.20g</line>\n"
1289  " <domain>%s</domain>\n"
1290  " <event>%s</event>\n"
1291  "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
1292  (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
1293  (1000000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
1294  (double) getpid(),(double) GetMagickThreadSignature(),module,function,
1295  (double) line,domain,event);
1296  return(text);
1297  }
1298  /*
1299  Translate event in "human readable" format.
1300  */
1301  q=text;
1302  for (p=log_info->format; *p != '\0'; p++)
1303  {
1304  *q='\0';
1305  if ((size_t) (q-text+MagickPathExtent) >= extent)
1306  {
1307  extent+=MagickPathExtent;
1308  text=(char *) ResizeQuantumMemory(text,extent+MagickPathExtent,
1309  sizeof(*text));
1310  if (text == (char *) NULL)
1311  return((char *) NULL);
1312  q=text+strlen(text);
1313  }
1314  /*
1315  The format of the log is defined by embedding special format characters:
1316 
1317  %c client name
1318  %d domain
1319  %e event
1320  %f function
1321  %g generation
1322  %i thread id
1323  %l line
1324  %m module
1325  %n log name
1326  %p process id
1327  %r real CPU time
1328  %t wall clock time
1329  %u user CPU time
1330  %v version
1331  %% percent sign
1332  \n newline
1333  \r carriage return
1334  */
1335  if ((*p == '\\') && (*(p+1) == 'r'))
1336  {
1337  *q++='\r';
1338  p++;
1339  continue;
1340  }
1341  if ((*p == '\\') && (*(p+1) == 'n'))
1342  {
1343  *q++='\n';
1344  p++;
1345  continue;
1346  }
1347  if (*p != '%')
1348  {
1349  *q++=(*p);
1350  continue;
1351  }
1352  p++;
1353  if (*p == '\0')
1354  break;
1355  switch (*p)
1356  {
1357  case 'c':
1358  {
1359  q+=CopyMagickString(q,GetClientName(),extent);
1360  break;
1361  }
1362  case 'd':
1363  {
1364  q+=CopyMagickString(q,domain,extent);
1365  break;
1366  }
1367  case 'e':
1368  {
1369  q+=CopyMagickString(q,event,extent);
1370  break;
1371  }
1372  case 'f':
1373  {
1374  q+=CopyMagickString(q,function,extent);
1375  break;
1376  }
1377  case 'g':
1378  {
1379  if (log_info->generations == 0)
1380  {
1381  (void) CopyMagickString(q,"0",extent);
1382  q++;
1383  break;
1384  }
1385  q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1386  log_info->generations));
1387  break;
1388  }
1389  case 'i':
1390  {
1391  q+=FormatLocaleString(q,extent,"%.20g",(double)
1392  GetMagickThreadSignature());
1393  break;
1394  }
1395  case 'l':
1396  {
1397  q+=FormatLocaleString(q,extent,"%.20g",(double) line);
1398  break;
1399  }
1400  case 'm':
1401  {
1402  const char
1403  *r;
1404 
1405  for (r=module+strlen(module)-1; r > module; r--)
1406  if (*r == *DirectorySeparator)
1407  {
1408  r++;
1409  break;
1410  }
1411  q+=CopyMagickString(q,r,extent);
1412  break;
1413  }
1414  case 'n':
1415  {
1416  q+=CopyMagickString(q,GetLogName(),extent);
1417  break;
1418  }
1419  case 'p':
1420  {
1421  q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
1422  break;
1423  }
1424  case 'r':
1425  {
1426  q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
1427  (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
1428  (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
1429  break;
1430  }
1431  case 't':
1432  {
1433  q+=FormatMagickTime(seconds,extent,q);
1434  break;
1435  }
1436  case 'u':
1437  {
1438  q+=FormatLocaleString(q,extent,"%0.3fu",user_time);
1439  break;
1440  }
1441  case 'v':
1442  {
1443  q+=CopyMagickString(q,MagickLibVersionText,extent);
1444  break;
1445  }
1446  case '%':
1447  {
1448  *q++=(*p);
1449  break;
1450  }
1451  default:
1452  {
1453  *q++='%';
1454  *q++=(*p);
1455  break;
1456  }
1457  }
1458  }
1459  *q='\0';
1460  return(text);
1461 }
1462 
1463 static char *TranslateFilename(const LogInfo *log_info)
1464 {
1465  char
1466  *filename;
1467 
1468  char
1469  *q;
1470 
1471  const char
1472  *p;
1473 
1474  size_t
1475  extent;
1476 
1477  /*
1478  Translate event in "human readable" format.
1479  */
1480  assert(log_info != (LogInfo *) NULL);
1481  assert(log_info->filename != (char *) NULL);
1482  filename=AcquireString((char *) NULL);
1483  extent=MagickPathExtent;
1484  q=filename;
1485  for (p=log_info->filename; *p != '\0'; p++)
1486  {
1487  *q='\0';
1488  if ((size_t) (q-filename+MagickPathExtent) >= extent)
1489  {
1490  extent+=MagickPathExtent;
1491  filename=(char *) ResizeQuantumMemory(filename,extent+MagickPathExtent,
1492  sizeof(*filename));
1493  if (filename == (char *) NULL)
1494  return((char *) NULL);
1495  q=filename+strlen(filename);
1496  }
1497  /*
1498  The format of the filename is defined by embedding special format
1499  characters:
1500 
1501  %c client name
1502  %n log name
1503  %p process id
1504  %v version
1505  %% percent sign
1506  */
1507  if (*p != '%')
1508  {
1509  *q++=(*p);
1510  continue;
1511  }
1512  p++;
1513  if (*p == '\0')
1514  break;
1515  switch (*p)
1516  {
1517  case '\0':
1518  {
1519  p--;
1520  break;
1521  }
1522  case 'c':
1523  {
1524  q+=CopyMagickString(q,GetClientName(),extent);
1525  break;
1526  }
1527  case 'g':
1528  {
1529  if (log_info->generations == 0)
1530  {
1531  (void) CopyMagickString(q,"0",extent);
1532  q++;
1533  break;
1534  }
1535  q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1536  log_info->generations));
1537  break;
1538  }
1539  case 'n':
1540  {
1541  q+=CopyMagickString(q,GetLogName(),extent);
1542  break;
1543  }
1544  case 'p':
1545  {
1546  q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
1547  break;
1548  }
1549  case 'v':
1550  {
1551  q+=CopyMagickString(q,MagickLibVersionText,extent);
1552  break;
1553  }
1554  case '%':
1555  {
1556  *q++=(*p);
1557  break;
1558  }
1559  default:
1560  {
1561  *q++='%';
1562  *q++=(*p);
1563  break;
1564  }
1565  }
1566  }
1567  *q='\0';
1568  return(filename);
1569 }
1570 
1571 MagickExport MagickBooleanType LogMagickEventList(const LogEventType type,
1572  const char *module,const char *function,const size_t line,const char *format,
1573  va_list operands)
1574 {
1575  char
1576  event[MagickPathExtent],
1577  *text;
1578 
1579  const char
1580  *domain;
1581 
1583  *exception;
1584 
1585  int
1586  n;
1587 
1588  LogInfo
1589  *log_info;
1590 
1591  exception=AcquireExceptionInfo();
1592  log_info=(LogInfo *) GetLogInfo("*",exception);
1593  exception=DestroyExceptionInfo(exception);
1594  if (log_info->event_semaphore == (SemaphoreInfo *) NULL)
1595  ActivateSemaphoreInfo(&log_info->event_semaphore);
1596  LockSemaphoreInfo(log_info->event_semaphore);
1597  if ((log_info->event_mask & type) == 0)
1598  {
1599  UnlockSemaphoreInfo(log_info->event_semaphore);
1600  return(MagickTrue);
1601  }
1602  domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
1603 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
1604  n=vsnprintf(event,MagickPathExtent,format,operands);
1605 #else
1606  n=vsprintf(event,format,operands);
1607 #endif
1608  if (n < 0)
1609  event[MagickPathExtent-1]='\0';
1610  text=TranslateEvent(module,function,line,domain,event);
1611  if (text == (char *) NULL)
1612  {
1613  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1614  UnlockSemaphoreInfo(log_info->event_semaphore);
1615  return(MagickFalse);
1616  }
1617  if ((log_info->handler_mask & ConsoleHandler) != 0)
1618  {
1619  (void) FormatLocaleFile(stderr,"%s\n",text);
1620  (void) fflush(stderr);
1621  }
1622  if ((log_info->handler_mask & DebugHandler) != 0)
1623  {
1624 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1625  OutputDebugString(text);
1626  OutputDebugString("\n");
1627 #endif
1628  }
1629  if ((log_info->handler_mask & EventHandler) != 0)
1630  {
1631 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1632  (void) NTReportEvent(text,MagickFalse);
1633 #endif
1634  }
1635  if ((log_info->handler_mask & FileHandler) != 0)
1636  {
1637  struct stat
1638  file_info;
1639 
1640  file_info.st_size=0;
1641  if (log_info->file != (FILE *) NULL)
1642  (void) fstat(fileno(log_info->file),&file_info);
1643  if (file_info.st_size > (MagickOffsetType) (1024*1024*log_info->limit))
1644  {
1645  (void) FormatLocaleFile(log_info->file,"</log>\n");
1646  (void) fclose(log_info->file);
1647  log_info->file=(FILE *) NULL;
1648  }
1649  if (log_info->file == (FILE *) NULL)
1650  {
1651  char
1652  *filename;
1653 
1654  filename=TranslateFilename(log_info);
1655  if (filename == (char *) NULL)
1656  {
1657  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1658  UnlockSemaphoreInfo(log_info->event_semaphore);
1659  return(MagickFalse);
1660  }
1661  log_info->append=IsPathAccessible(filename);
1662  log_info->file=fopen_utf8(filename,"ab");
1663  filename=(char *) RelinquishMagickMemory(filename);
1664  if (log_info->file == (FILE *) NULL)
1665  {
1666  UnlockSemaphoreInfo(log_info->event_semaphore);
1667  return(MagickFalse);
1668  }
1669  log_info->generation++;
1670  if (log_info->append == MagickFalse)
1671  (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1672  "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1673  (void) FormatLocaleFile(log_info->file,"<log>\n");
1674  }
1675  (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1676  (void) fflush(log_info->file);
1677  }
1678  if ((log_info->handler_mask & MethodHandler) != 0)
1679  {
1680  if (log_info->method != (MagickLogMethod) NULL)
1681  log_info->method(type,text);
1682  }
1683  if ((log_info->handler_mask & StdoutHandler) != 0)
1684  {
1685  (void) FormatLocaleFile(stdout,"%s\n",text);
1686  (void) fflush(stdout);
1687  }
1688  if ((log_info->handler_mask & StderrHandler) != 0)
1689  {
1690  (void) FormatLocaleFile(stderr,"%s\n",text);
1691  (void) fflush(stderr);
1692  }
1693  text=(char *) RelinquishMagickMemory(text);
1694  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1695  UnlockSemaphoreInfo(log_info->event_semaphore);
1696  return(MagickTrue);
1697 }
1698 
1699 MagickExport MagickBooleanType LogMagickEvent(const LogEventType type,
1700  const char *module,const char *function,const size_t line,
1701  const char *format,...)
1702 {
1703  va_list
1704  operands;
1705 
1706  MagickBooleanType
1707  status;
1708 
1709  if (IsEventLogging() == MagickFalse)
1710  return(MagickFalse);
1711  va_start(operands,format);
1712  status=LogMagickEventList(type,module,function,line,format,operands);
1713  va_end(operands);
1714  return(status);
1715 }
1716 ␌
1717 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1718 /*
1719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1720 % %
1721 % %
1722 % %
1723 % P a r s e L o g H a n d l e r s %
1724 % %
1725 % %
1726 % %
1727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1728 %
1729 % ParseLogHandlers() parses a string defining which handlers takes a log
1730 % message and exports them.
1731 %
1732 % The format of the ParseLogHandlers method is:
1733 %
1734 % LogHandlerType ParseLogHandlers(const char *handlers)
1735 %
1736 % A description of each parameter follows:
1737 %
1738 % o handlers: one or more handlers separated by commas.
1739 %
1740 */
1741 static LogHandlerType ParseLogHandlers(const char *handlers)
1742 {
1743  LogHandlerType
1744  handler_mask;
1745 
1746  const char
1747  *p;
1748 
1749  ssize_t
1750  i;
1751 
1752  size_t
1753  length;
1754 
1755  handler_mask=NoHandler;
1756  for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1757  {
1758  while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1759  (*p == ',')))
1760  p++;
1761  for (i=0; *LogHandlers[i].name != '\0'; i++)
1762  {
1763  length=strlen(LogHandlers[i].name);
1764  if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1765  {
1766  handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1767  break;
1768  }
1769  }
1770  if (*LogHandlers[i].name == '\0')
1771  return(UndefinedHandler);
1772  }
1773  return(handler_mask);
1774 }
1775 #endif
1776 ␌
1777 /*
1778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1779 % %
1780 % %
1781 % %
1782 % S e t L o g E v e n t M a s k %
1783 % %
1784 % %
1785 % %
1786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1787 %
1788 % SetLogEventMask() accepts a list that determines which events to log. All
1789 % other events are ignored. By default, no debug is enabled. This method
1790 % returns the previous log event mask.
1791 %
1792 % The format of the SetLogEventMask method is:
1793 %
1794 % LogEventType SetLogEventMask(const char *events)
1795 %
1796 % A description of each parameter follows:
1797 %
1798 % o events: log these events.
1799 %
1800 */
1801 MagickExport LogEventType SetLogEventMask(const char *events)
1802 {
1804  *exception;
1805 
1806  LogInfo
1807  *log_info;
1808 
1809  ssize_t
1810  option;
1811 
1812  exception=AcquireExceptionInfo();
1813  log_info=(LogInfo *) GetLogInfo("*",exception);
1814  exception=DestroyExceptionInfo(exception);
1815  option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
1816  LockSemaphoreInfo(log_semaphore);
1817  log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1818  log_info->event_mask=(LogEventType) option;
1819  if (option == -1)
1820  log_info->event_mask=UndefinedEvents;
1821  CheckEventLogging();
1822  UnlockSemaphoreInfo(log_semaphore);
1823  return(log_info->event_mask);
1824 }
1825 ␌
1826 /*
1827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1828 % %
1829 % %
1830 % %
1831 % S e t L o g F o r m a t %
1832 % %
1833 % %
1834 % %
1835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1836 %
1837 % SetLogFormat() sets the format for the "human readable" log record.
1838 %
1839 % The format of the LogMagickFormat method is:
1840 %
1841 % SetLogFormat(const char *format)
1842 %
1843 % A description of each parameter follows:
1844 %
1845 % o format: the log record format.
1846 %
1847 */
1848 MagickExport void SetLogFormat(const char *format)
1849 {
1850  LogInfo
1851  *log_info;
1852 
1854  *exception;
1855 
1856  exception=AcquireExceptionInfo();
1857  log_info=(LogInfo *) GetLogInfo("*",exception);
1858  exception=DestroyExceptionInfo(exception);
1859  LockSemaphoreInfo(log_semaphore);
1860  if (log_info->format != (char *) NULL)
1861  log_info->format=DestroyString(log_info->format);
1862  log_info->format=ConstantString(format);
1863  UnlockSemaphoreInfo(log_semaphore);
1864 }
1865 ␌
1866 /*
1867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1868 % %
1869 % %
1870 % %
1871 % S e t L o g M e t h o d %
1872 % %
1873 % %
1874 % %
1875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1876 %
1877 % SetLogMethod() sets the method that will be called when an event is logged.
1878 %
1879 % The format of the SetLogMethod method is:
1880 %
1881 % void SetLogMethod(MagickLogMethod method)
1882 %
1883 % A description of each parameter follows:
1884 %
1885 % o method: pointer to a method that will be called when LogMagickEvent is
1886 % being called.
1887 %
1888 */
1889 MagickExport void SetLogMethod(MagickLogMethod method)
1890 {
1892  *exception;
1893 
1894  LogInfo
1895  *log_info;
1896 
1897  exception=AcquireExceptionInfo();
1898  log_info=(LogInfo *) GetLogInfo("*",exception);
1899  exception=DestroyExceptionInfo(exception);
1900  LockSemaphoreInfo(log_semaphore);
1901  log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1902  log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1903  MethodHandler);
1904  log_info->method=method;
1905  UnlockSemaphoreInfo(log_semaphore);
1906 }
1907 ␌
1908 /*
1909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910 % %
1911 % %
1912 % %
1913 % S e t L o g N a m e %
1914 % %
1915 % %
1916 % %
1917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1918 %
1919 % SetLogName() sets the log name and returns it.
1920 %
1921 % The format of the SetLogName method is:
1922 %
1923 % const char *SetLogName(const char *name)
1924 %
1925 % A description of each parameter follows:
1926 %
1927 % o log_name: SetLogName() returns the current client name.
1928 %
1929 % o name: Specifies the new client name.
1930 %
1931 */
1932 MagickExport const char *SetLogName(const char *name)
1933 {
1934  if ((name != (char *) NULL) && (*name != '\0'))
1935  (void) CopyMagickString(log_name,name,MagickPathExtent);
1936  return(log_name);
1937 }
Definition: log.c:91
Definition: log.c:109