MagickCore 6.9.13
Loading...
Searching...
No Matches
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*/
75typedef 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
88typedef struct _EventInfo
89{
90 char
91 *name;
92
93 LogEventType
94 event;
95} EventInfo;
96
97typedef struct _HandlerInfo
98{
99 const char
100 name[10];
101
102 LogHandlerType
103 handler;
104} HandlerInfo;
105
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
147typedef 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*/
163static 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
200static 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
207static char
208 log_name[MaxTextExtent] = "Magick";
209
210static LinkedListInfo
211 *log_cache = (LinkedListInfo *) NULL;
212
213static MagickBooleanType
214 event_logging = MagickFalse;
215
216static SemaphoreInfo
217 *log_semaphore = (SemaphoreInfo *) NULL;
218
219/*
220 Forward declarations.
221*/
222#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
223static LogHandlerType
224 ParseLogHandlers(const char *) magick_attribute((__pure__));
225#endif
226
227static LogInfo
228 *GetLogInfo(const char *,ExceptionInfo *);
229
230static MagickBooleanType
231 IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__));
232
233#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
234static 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*/
265static LinkedListInfo *AcquireLogCache(const char *filename,
266 ExceptionInfo *exception)
267{
268 LinkedListInfo
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
289 LinkedListInfo
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*/
356MagickExport void CloseMagickLog(void)
357{
358 ExceptionInfo
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*/
399MagickExport LogEventType GetLogEventMask(void)
400{
401 ExceptionInfo
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*/
440static 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)
500extern "C" {
501#endif
502
503static 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
520MagickExport 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)
596extern "C" {
597#endif
598
599static 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
614MagickExport 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*/
679MagickExport 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
708static 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
727static 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*/
763MagickExport 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*/
791MagickExport 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*/
887MagickExport MagickBooleanType LogComponentGenesis(void)
888{
889 ExceptionInfo
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
919static 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
943MagickExport 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*/
988static 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
999 ExceptionInfo
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
1226static 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
1336MagickExport 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
1347 ExceptionInfo
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#if defined(MAGICKCORE_HAVE_VSNPRINTF)
1371 n=vsnprintf(event,MaxTextExtent,format,operands);
1372#else
1373 n=vsprintf(event,format,operands);
1374#endif
1375 if (n < 0)
1376 event[MaxTextExtent-1]='\0';
1377 text=TranslateEvent(type,module,function,line,domain,event);
1378 if (text == (char *) NULL)
1379 {
1380 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1381 UnlockSemaphoreInfo(log_info->event_semaphore);
1382 return(MagickFalse);
1383 }
1384 if ((log_info->handler_mask & ConsoleHandler) != 0)
1385 {
1386 (void) FormatLocaleFile(stderr,"%s\n",text);
1387 (void) fflush(stderr);
1388 }
1389 if ((log_info->handler_mask & DebugHandler) != 0)
1390 {
1391#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1392 OutputDebugString(text);
1393 OutputDebugString("\n");
1394#endif
1395 }
1396 if ((log_info->handler_mask & EventHandler) != 0)
1397 {
1398#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1399 (void) NTReportEvent(text,MagickFalse);
1400#endif
1401 }
1402 if ((log_info->handler_mask & FileHandler) != 0)
1403 {
1404 struct stat
1405 file_info;
1406
1407 file_info.st_size=0;
1408 if (log_info->file != (FILE *) NULL)
1409 (void) fstat(fileno(log_info->file),&file_info);
1410 if (file_info.st_size > (MagickOffsetType) (1024*1024*log_info->limit))
1411 {
1412 (void) FormatLocaleFile(log_info->file,"</log>\n");
1413 (void) fclose(log_info->file);
1414 log_info->file=(FILE *) NULL;
1415 }
1416 if (log_info->file == (FILE *) NULL)
1417 {
1418 char
1419 *filename;
1420
1421 filename=TranslateFilename(log_info);
1422 if (filename == (char *) NULL)
1423 {
1424 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1425 UnlockSemaphoreInfo(log_info->event_semaphore);
1426 return(MagickFalse);
1427 }
1428 log_info->append=IsPathAccessible(filename);
1429 log_info->file=fopen_utf8(filename,"ab");
1430 filename=(char *) RelinquishMagickMemory(filename);
1431 if (log_info->file == (FILE *) NULL)
1432 {
1433 UnlockSemaphoreInfo(log_info->event_semaphore);
1434 return(MagickFalse);
1435 }
1436 log_info->generation++;
1437 if (log_info->append == MagickFalse)
1438 (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1439 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1440 (void) FormatLocaleFile(log_info->file,"<log>\n");
1441 }
1442 (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1443 (void) fflush(log_info->file);
1444 }
1445 if ((log_info->handler_mask & MethodHandler) != 0)
1446 {
1447 if (log_info->method != (MagickLogMethod) NULL)
1448 log_info->method(type,text);
1449 }
1450 if ((log_info->handler_mask & StdoutHandler) != 0)
1451 {
1452 (void) FormatLocaleFile(stdout,"%s\n",text);
1453 (void) fflush(stdout);
1454 }
1455 if ((log_info->handler_mask & StderrHandler) != 0)
1456 {
1457 (void) FormatLocaleFile(stderr,"%s\n",text);
1458 (void) fflush(stderr);
1459 }
1460 text=(char *) RelinquishMagickMemory(text);
1461 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1462 UnlockSemaphoreInfo(log_info->event_semaphore);
1463 return(MagickTrue);
1464}
1465
1466MagickExport MagickBooleanType LogMagickEvent(const LogEventType type,
1467 const char *module,const char *function,const size_t line,
1468 const char *format,...)
1469{
1470 va_list
1471 operands;
1472
1473 MagickBooleanType
1474 status;
1475
1476 if (IsEventLogging() == MagickFalse)
1477 return(MagickFalse);
1478 va_start(operands,format);
1479 status=LogMagickEventList(type,module,function,line,format,operands);
1480 va_end(operands);
1481 return(status);
1482}
1483
1484#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1485/*
1486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487% %
1488% %
1489% %
1490+ L o a d L o g C a c h e %
1491% %
1492% %
1493% %
1494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495%
1496% LoadLogCache() loads the log configurations which provides a
1497% mapping between log attributes and log name.
1498%
1499% The format of the LoadLogCache method is:
1500%
1501% MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
1502% const char *filename,const size_t depth,ExceptionInfo *exception)
1503%
1504% A description of each parameter follows:
1505%
1506% o xml: The log list in XML format.
1507%
1508% o filename: The log list filename.
1509%
1510% o depth: depth of <include /> statements.
1511%
1512% o exception: return any errors or warnings in this structure.
1513%
1514*/
1515static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
1516 const char *filename,const size_t depth,ExceptionInfo *exception)
1517{
1518 char
1519 keyword[MaxTextExtent],
1520 *token;
1521
1522 const char
1523 *q;
1524
1525 LogInfo
1526 *log_info = (LogInfo *) NULL;
1527
1528 MagickStatusType
1529 status;
1530
1531 size_t
1532 extent;
1533
1534 /*
1535 Load the log map file.
1536 */
1537 if (xml == (const char *) NULL)
1538 return(MagickFalse);
1539 status=MagickTrue;
1540 token=AcquireString(xml);
1541 extent=strlen(token)+MaxTextExtent;
1542 for (q=(const char *) xml; *q != '\0'; )
1543 {
1544 /*
1545 Interpret XML.
1546 */
1547 (void) GetNextToken(q,&q,extent,token);
1548 if (*token == '\0')
1549 break;
1550 (void) CopyMagickString(keyword,token,MaxTextExtent);
1551 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1552 {
1553 /*
1554 Doctype element.
1555 */
1556 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1557 (void) GetNextToken(q,&q,extent,token);
1558 continue;
1559 }
1560 if (LocaleNCompare(keyword,"<!--",4) == 0)
1561 {
1562 /*
1563 Comment element.
1564 */
1565 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1566 (void) GetNextToken(q,&q,extent,token);
1567 continue;
1568 }
1569 if (LocaleCompare(keyword,"<include") == 0)
1570 {
1571 /*
1572 Include element.
1573 */
1574 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1575 {
1576 (void) CopyMagickString(keyword,token,MaxTextExtent);
1577 (void) GetNextToken(q,&q,extent,token);
1578 if (*token != '=')
1579 continue;
1580 (void) GetNextToken(q,&q,extent,token);
1581 if (LocaleCompare(keyword,"file") == 0)
1582 {
1583 if (depth > MagickMaxRecursionDepth)
1584 (void) ThrowMagickException(exception,GetMagickModule(),
1585 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1586 else
1587 {
1588 char
1589 path[MaxTextExtent],
1590 *xml;
1591
1592 GetPathComponent(filename,HeadPath,path);
1593 if (*path != '\0')
1594 (void) ConcatenateMagickString(path,DirectorySeparator,
1595 MaxTextExtent);
1596 if (*token == *DirectorySeparator)
1597 (void) CopyMagickString(path,token,MaxTextExtent);
1598 else
1599 (void) ConcatenateMagickString(path,token,MaxTextExtent);
1600 xml=FileToXML(path,~0UL);
1601 if (xml != (char *) NULL)
1602 {
1603 status&=LoadLogCache(cache,xml,path,depth+1,
1604 exception);
1605 xml=DestroyString(xml);
1606 }
1607 }
1608 }
1609 }
1610 continue;
1611 }
1612 if (LocaleCompare(keyword,"<logmap>") == 0)
1613 {
1614 /*
1615 Allocate memory for the log list.
1616 */
1617 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
1618 if (log_info == (LogInfo *) NULL)
1619 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1620 (void) memset(log_info,0,sizeof(*log_info));
1621 log_info->path=ConstantString(filename);
1622 GetTimerInfo((TimerInfo *) &log_info->timer);
1623 log_info->signature=MagickCoreSignature;
1624 continue;
1625 }
1626 if (log_info == (LogInfo *) NULL)
1627 continue;
1628 if (LocaleCompare(keyword,"</logmap>") == 0)
1629 {
1630 status=AppendValueToLinkedList(cache,log_info);
1631 if (status == MagickFalse)
1632 (void) ThrowMagickException(exception,GetMagickModule(),
1633 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1634 log_info=(LogInfo *) NULL;
1635 continue;
1636 }
1637 (void) GetNextToken(q,(const char **) NULL,extent,token);
1638 if (*token != '=')
1639 continue;
1640 (void) GetNextToken(q,&q,extent,token);
1641 (void) GetNextToken(q,&q,extent,token);
1642 switch (*keyword)
1643 {
1644 case 'E':
1645 case 'e':
1646 {
1647 if (LocaleCompare((char *) keyword,"events") == 0)
1648 {
1649 log_info->event_mask=(LogEventType) (log_info->event_mask |
1650 ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
1651 break;
1652 }
1653 break;
1654 }
1655 case 'F':
1656 case 'f':
1657 {
1658 if (LocaleCompare((char *) keyword,"filename") == 0)
1659 {
1660 if (log_info->filename != (char *) NULL)
1661 log_info->filename=(char *)
1662 RelinquishMagickMemory(log_info->filename);
1663 log_info->filename=ConstantString(token);
1664 break;
1665 }
1666 if (LocaleCompare((char *) keyword,"format") == 0)
1667 {
1668 if (log_info->format != (char *) NULL)
1669 log_info->format=(char *)
1670 RelinquishMagickMemory(log_info->format);
1671 log_info->format=ConstantString(token);
1672 break;
1673 }
1674 break;
1675 }
1676 case 'G':
1677 case 'g':
1678 {
1679 if (LocaleCompare((char *) keyword,"generations") == 0)
1680 {
1681 if (LocaleCompare(token,"unlimited") == 0)
1682 {
1683 log_info->generations=(~0UL);
1684 break;
1685 }
1686 log_info->generations=StringToUnsignedLong(token);
1687 break;
1688 }
1689 break;
1690 }
1691 case 'L':
1692 case 'l':
1693 {
1694 if (LocaleCompare((char *) keyword,"limit") == 0)
1695 {
1696 if (LocaleCompare(token,"unlimited") == 0)
1697 {
1698 log_info->limit=(~0UL);
1699 break;
1700 }
1701 log_info->limit=StringToUnsignedLong(token);
1702 break;
1703 }
1704 break;
1705 }
1706 case 'O':
1707 case 'o':
1708 {
1709 if (LocaleCompare((char *) keyword,"output") == 0)
1710 {
1711 log_info->handler_mask=(LogHandlerType)
1712 (log_info->handler_mask | ParseLogHandlers(token));
1713 break;
1714 }
1715 break;
1716 }
1717 default:
1718 break;
1719 }
1720 }
1721 token=DestroyString(token);
1722 if (cache == (LinkedListInfo *) NULL)
1723 return(MagickFalse);
1724 return(status != 0 ? MagickTrue : MagickFalse);
1725}
1726#endif
1727
1728#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1729/*
1730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731% %
1732% %
1733% %
1734+ P a r s e L o g H a n d l e r s %
1735% %
1736% %
1737% %
1738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739%
1740% ParseLogHandlers() parses a string defining which handlers takes a log
1741% message and exports them.
1742%
1743% The format of the ParseLogHandlers method is:
1744%
1745% LogHandlerType ParseLogHandlers(const char *handlers)
1746%
1747% A description of each parameter follows:
1748%
1749% o handlers: one or more handlers separated by commas.
1750%
1751*/
1752static LogHandlerType ParseLogHandlers(const char *handlers)
1753{
1754 LogHandlerType
1755 handler_mask;
1756
1757 const char
1758 *p;
1759
1760 ssize_t
1761 i;
1762
1763 size_t
1764 length;
1765
1766 handler_mask=NoHandler;
1767 for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1768 {
1769 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1770 (*p == ',')))
1771 p++;
1772 for (i=0; *LogHandlers[i].name != '\0'; i++)
1773 {
1774 length=strlen(LogHandlers[i].name);
1775 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1776 {
1777 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1778 break;
1779 }
1780 }
1781 if (*LogHandlers[i].name == '\0')
1782 return(UndefinedHandler);
1783 }
1784 return(handler_mask);
1785}
1786#endif
1787
1788/*
1789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790% %
1791% %
1792% %
1793% S e t L o g E v e n t M a s k %
1794% %
1795% %
1796% %
1797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1798%
1799% SetLogEventMask() accepts a list that determines which events to log. All
1800% other events are ignored. By default, no debug is enabled. This method
1801% returns the previous log event mask.
1802%
1803% The format of the SetLogEventMask method is:
1804%
1805% LogEventType SetLogEventMask(const char *events)
1806%
1807% A description of each parameter follows:
1808%
1809% o events: log these events.
1810%
1811*/
1812MagickExport LogEventType SetLogEventMask(const char *events)
1813{
1814 ExceptionInfo
1815 *exception;
1816
1817 LogInfo
1818 *log_info;
1819
1820 ssize_t
1821 option;
1822
1823 exception=AcquireExceptionInfo();
1824 log_info=(LogInfo *) GetLogInfo("*",exception);
1825 exception=DestroyExceptionInfo(exception);
1826 if (log_info == (LogInfo *) NULL)
1827 return(NoEvents);
1828 option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
1829 LockSemaphoreInfo(log_semaphore);
1830 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1831 if (log_info == (LogInfo *) NULL)
1832 {
1833 UnlockSemaphoreInfo(log_semaphore);
1834 return(NoEvents);
1835 }
1836 log_info->event_mask=(LogEventType) option;
1837 if (option == -1)
1838 log_info->event_mask=UndefinedEvents;
1839 CheckEventLogging();
1840 UnlockSemaphoreInfo(log_semaphore);
1841 return(log_info->event_mask);
1842}
1843
1844/*
1845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846% %
1847% %
1848% %
1849% S e t L o g F o r m a t %
1850% %
1851% %
1852% %
1853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854%
1855% SetLogFormat() sets the format for the "human readable" log record.
1856%
1857% The format of the LogMagickFormat method is:
1858%
1859% SetLogFormat(const char *format)
1860%
1861% A description of each parameter follows:
1862%
1863% o format: the log record format.
1864%
1865*/
1866MagickExport void SetLogFormat(const char *format)
1867{
1868 LogInfo
1869 *log_info;
1870
1871 ExceptionInfo
1872 *exception;
1873
1874 exception=AcquireExceptionInfo();
1875 log_info=(LogInfo *) GetLogInfo("*",exception);
1876 exception=DestroyExceptionInfo(exception);
1877 if (log_info == (LogInfo *) NULL)
1878 return;
1879 LockSemaphoreInfo(log_semaphore);
1880 if (log_info->format != (char *) NULL)
1881 log_info->format=DestroyString(log_info->format);
1882 log_info->format=ConstantString(format);
1883 UnlockSemaphoreInfo(log_semaphore);
1884}
1885
1886/*
1887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1888% %
1889% %
1890% %
1891% S e t L o g M e t h o d %
1892% %
1893% %
1894% %
1895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896%
1897% SetLogMethod() sets the method that will be called when an event is logged.
1898%
1899% The format of the SetLogMethod method is:
1900%
1901% void SetLogMethod(MagickLogMethod method)
1902%
1903% A description of each parameter follows:
1904%
1905% o method: pointer to a method that will be called when LogMagickEvent is
1906% being called.
1907%
1908*/
1909MagickExport void SetLogMethod(MagickLogMethod method)
1910{
1911 ExceptionInfo
1912 *exception;
1913
1914 LogInfo
1915 *log_info;
1916
1917 exception=AcquireExceptionInfo();
1918 log_info=(LogInfo *) GetLogInfo("*",exception);
1919 exception=DestroyExceptionInfo(exception);
1920 if (log_info == (LogInfo *) NULL)
1921 return;
1922 LockSemaphoreInfo(log_semaphore);
1923 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1924 if (log_info == (LogInfo *) NULL)
1925 {
1926 UnlockSemaphoreInfo(log_semaphore);
1927 return;
1928 }
1929 log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1930 MethodHandler);
1931 log_info->method=method;
1932 UnlockSemaphoreInfo(log_semaphore);
1933}
1934
1935/*
1936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937% %
1938% %
1939% %
1940% S e t L o g N a m e %
1941% %
1942% %
1943% %
1944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945%
1946% SetLogName() sets the log name and returns it.
1947%
1948% The format of the SetLogName method is:
1949%
1950% const char *SetLogName(const char *name)
1951%
1952% A description of each parameter follows:
1953%
1954% o log_name: SetLogName() returns the current client name.
1955%
1956% o name: Specifies the new client name.
1957%
1958*/
1959MagickExport char *SetLogName(const char *name)
1960{
1961 if ((name != (char *) NULL) && (*name != '\0'))
1962 (void) CopyMagickString(log_name,name,MaxTextExtent);
1963 return(log_name);
1964}