WizardsToolkit  1.0.7
log.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                             L       OOO    GGGG                             %
00007 %                             L      O   O  G                                 %
00008 %                             L      O   O  G GG                              %
00009 %                             L      O   O  G   G                             %
00010 %                             LLLLL   OOO    GGG                              %
00011 %                                                                             %
00012 %                                                                             %
00013 %                           Log ImageMagick Events                            %
00014 %                                                                             %
00015 %                               Software Design                               %
00016 %                                 John Cristy                                 %
00017 %                                September 2002                               %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.wizards-toolkit.org/script/license.php                        %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "wizard/studio.h"
00043 #include "wizard/blob.h"
00044 #include "wizard/client.h"
00045 #include "wizard/configure.h"
00046 #include "wizard/exception.h"
00047 #include "wizard/exception-private.h"
00048 #include "wizard/hashmap.h"
00049 #include "wizard/log.h"
00050 #include "wizard/memory_.h"
00051 #include "wizard/option.h"
00052 #include "wizard/semaphore.h"
00053 #include "wizard/string_.h"
00054 #include "wizard/string-private.h"
00055 #include "wizard/thread_.h"
00056 #include "wizard/thread-private.h"
00057 #include "wizard/timer.h"
00058 #include "wizard/token.h"
00059 #include "wizard/utility.h"
00060 #include "wizard/utility-private.h"
00061 #include "wizard/version.h"
00062 #include "wizard/xml-tree.h"
00063 
00064 /*
00065   Define declarations.
00066 */
00067 #define LogFilename  "log.xml"
00068 
00069 /*
00070   Typedef declarations.
00071 */
00072 typedef enum
00073 {
00074   UndefinedHandler = 0x0000,
00075   NoHandler = 0x0000,
00076   ConsoleHandler = 0x0001,
00077   StdoutHandler = 0x0002,
00078   StderrHandler = 0x0004,
00079   FileHandler = 0x0008,
00080   DebugHandler = 0x0010,
00081   EventHandler = 0x0020
00082 } LogHandlerType;
00083 
00084 typedef struct _EventInfo
00085 {
00086   char
00087     *name;
00088 
00089   LogEventType
00090     event;
00091 } EventInfo;
00092 
00093 typedef struct _HandlerInfo
00094 {
00095   const char
00096     *name;
00097 
00098   LogHandlerType
00099     handler;
00100 } HandlerInfo;
00101 
00102 struct _LogInfo
00103 {
00104   LogEventType
00105     event_mask;
00106 
00107   LogHandlerType
00108     handler_mask;
00109 
00110   char
00111     *path,
00112     *name,
00113     *filename,
00114     *format;
00115 
00116   size_t
00117     generations,
00118     limit;
00119 
00120   FILE
00121     *file;
00122 
00123   size_t
00124     generation;
00125 
00126   WizardBooleanType
00127     append,
00128     exempt,
00129     stealth;
00130 
00131   TimerInfo
00132     *timer;
00133 
00134   size_t
00135     signature;
00136 };
00137 
00138 /*
00139   Declare log map.
00140 */
00141 static const HandlerInfo
00142   LogHandlers[] =
00143   {
00144     { "console", ConsoleHandler },
00145     { "debug", DebugHandler },
00146     { "event", EventHandler },
00147     { "file", FileHandler },
00148     { "none", NoHandler },
00149     { "stderr", StderrHandler },
00150     { "stdout", StdoutHandler },
00151     { (char *) NULL, UndefinedHandler }
00152   };
00153 
00154 typedef struct _LogMapInfo
00155 {
00156   const LogEventType
00157     event_mask;
00158 
00159   const LogHandlerType
00160     handler_mask;
00161 
00162   const char
00163     *filename,
00164     *format;
00165 } LogMapInfo;
00166 
00167 /*
00168   Static declarations.
00169 */
00170 static const LogMapInfo
00171   LogMap[] =
00172   {
00173     { NoEvents, ConsoleHandler, "Magick-%d.log",
00174       "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n  %e" }
00175   };
00176 
00177 static char
00178   log_name[MaxTextExtent] = "Wizard";
00179 
00180 static LinkedListInfo
00181   *log_list = (LinkedListInfo *) NULL;
00182 
00183 static SemaphoreInfo
00184   *log_semaphore = (SemaphoreInfo *) NULL;
00185 
00186 static volatile WizardBooleanType
00187   instantiate_log = WizardFalse;
00188 
00189 /*
00190   Forward declarations.
00191 */
00192 static LogHandlerType
00193   ParseLogHandlers(const char *);
00194 
00195 static WizardBooleanType
00196   InitializeLogList(ExceptionInfo *),
00197   LoadLogLists(const char *,ExceptionInfo *);
00198 
00199 /*
00200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00201 %                                                                             %
00202 %                                                                             %
00203 %                                                                             %
00204 %   C l o s e W i z a r d L o g                                               %
00205 %                                                                             %
00206 %                                                                             %
00207 %                                                                             %
00208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00209 %
00210 %  CloseWizardLog() closes the Wizard log.
00211 %
00212 %  The format of the CloseWizardLog method is:
00213 %
00214 %      CloseWizardLog(void)
00215 %
00216 */
00217 WizardExport void CloseWizardLog(void)
00218 {
00219   ExceptionInfo
00220     *exception;
00221 
00222   LogInfo
00223     *log_info;
00224 
00225   if (IsEventLogging() == WizardFalse)
00226     return;
00227   exception=AcquireExceptionInfo();
00228   log_info=(LogInfo *) GetLogInfo("*",exception);
00229   exception=DestroyExceptionInfo(exception);
00230   LockSemaphoreInfo(log_semaphore);
00231   if (log_info->file != (FILE *) NULL)
00232     {
00233       if (log_info->append == WizardFalse)
00234         (void) fprintf(log_info->file,"</log>\n");
00235       (void) fclose(log_info->file);
00236       log_info->file=(FILE *) NULL;
00237     }
00238   UnlockSemaphoreInfo(log_semaphore);
00239 }
00240 
00241 /*
00242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00243 %                                                                             %
00244 %                                                                             %
00245 %                                                                             %
00246 +   G e t L o g I n f o                                                       %
00247 %                                                                             %
00248 %                                                                             %
00249 %                                                                             %
00250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00251 %
00252 %  GetLogInfo() searches the log list for the specified name and if found
00253 %  returns attributes for that log.
00254 %
00255 %  The format of the GetLogInfo method is:
00256 %
00257 %      const LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
00258 %
00259 %  A description of each parameter follows:
00260 %
00261 %    o name: The log name.
00262 %
00263 %    o exception: Return any errors or warnings in this structure.
00264 %
00265 */
00266 WizardExport const LogInfo *GetLogInfo(const char *name,
00267   ExceptionInfo *exception)
00268 {
00269   register const LogInfo
00270     *p;
00271 
00272   assert(exception != (ExceptionInfo *) NULL);
00273   if ((log_list == (LinkedListInfo *) NULL) || (instantiate_log == WizardFalse))
00274     if (InitializeLogList(exception) == WizardFalse)
00275       return((const LogInfo *) NULL);
00276   if ((log_list == (LinkedListInfo *) NULL) ||
00277       (IsLinkedListEmpty(log_list) != WizardFalse))
00278     return((const LogInfo *) NULL);
00279   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
00280     return((const LogInfo *) GetValueFromLinkedList(log_list,0));
00281   /*
00282     Search for named log.
00283   */
00284   LockSemaphoreInfo(log_semaphore);
00285   ResetLinkedListIterator(log_list);
00286   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00287   while (p != (const LogInfo *) NULL)
00288   {
00289     if (LocaleCompare(name,p->name) == 0)
00290       break;
00291     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00292   }
00293   if (p == (LogInfo *) NULL)
00294     (void) ThrowWizardException(exception,GetWizardModule(),OptionWarning,
00295       "no such element `%s'",name);
00296   else
00297     (void) InsertValueInLinkedList(log_list,0,
00298       RemoveElementByValueFromLinkedList(log_list,p));
00299   UnlockSemaphoreInfo(log_semaphore);
00300   return(p);
00301 }
00302 
00303 /*
00304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00305 %                                                                             %
00306 %                                                                             %
00307 %                                                                             %
00308 %   G e t L o g I n f o L i s t                                               %
00309 %                                                                             %
00310 %                                                                             %
00311 %                                                                             %
00312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00313 %
00314 %  GetLogInfoList() returns any logs that match the specified pattern.
00315 %
00316 %  The format of the GetLogInfoList function is:
00317 %
00318 %      const LogInfo **GetLogInfoList(const char *pattern,
00319 %        size_t *number_preferences,ExceptionInfo *exception)
00320 %
00321 %  A description of each parameter follows:
00322 %
00323 %    o pattern: Specifies a pointer to a text string containing a pattern.
00324 %
00325 %    o number_preferences:  This integer returns the number of logs in the list.
00326 %
00327 %    o exception: Return any errors or warnings in this structure.
00328 %
00329 */
00330 #if defined(__cplusplus) || defined(c_plusplus)
00331 extern "C" {
00332 #endif
00333 
00334 static int LogInfoCompare(const void *x,const void *y)
00335 {
00336   const LogInfo
00337     **p,
00338     **q;
00339 
00340   p=(const LogInfo **) x,
00341   q=(const LogInfo **) y;
00342   if (LocaleCompare((*p)->path,(*q)->path) == 0)
00343     return(LocaleCompare((*p)->name,(*q)->name));
00344   return(LocaleCompare((*p)->path,(*q)->path));
00345 }
00346 
00347 #if defined(__cplusplus) || defined(c_plusplus)
00348 }
00349 #endif
00350 
00351 WizardExport const LogInfo **GetLogInfoList(const char *pattern,
00352   size_t *number_preferences,ExceptionInfo *exception)
00353 {
00354   const LogInfo
00355     **preferences;
00356 
00357   register const LogInfo
00358     *p;
00359 
00360   register ssize_t
00361     i;
00362 
00363   /*
00364     Allocate log list.
00365   */
00366   assert(pattern != (char *) NULL);
00367   (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",pattern);
00368   assert(number_preferences != (size_t *) NULL);
00369   *number_preferences=0;
00370   p=GetLogInfo("*",exception);
00371   if (p == (const LogInfo *) NULL)
00372     return((const LogInfo **) NULL);
00373   preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
00374     GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00375   if (preferences == (const LogInfo **) NULL)
00376     return((const LogInfo **) NULL);
00377   /*
00378     Generate log list.
00379   */
00380   LockSemaphoreInfo(log_semaphore);
00381   ResetLinkedListIterator(log_list);
00382   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00383   for (i=0; p != (const LogInfo *) NULL; )
00384   {
00385     if ((p->stealth == WizardFalse) &&
00386         (GlobExpression(p->name,pattern,WizardFalse) != WizardFalse))
00387       preferences[i++]=p;
00388     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00389   }
00390   UnlockSemaphoreInfo(log_semaphore);
00391   qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
00392   preferences[i]=(LogInfo *) NULL;
00393   *number_preferences=(size_t) i;
00394   return(preferences);
00395 }
00396 
00397 /*
00398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00399 %                                                                             %
00400 %                                                                             %
00401 %                                                                             %
00402 %   G e t L o g L i s t                                                       %
00403 %                                                                             %
00404 %                                                                             %
00405 %                                                                             %
00406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00407 %
00408 %  GetLogList() returns any logs that match the specified pattern.
00409 %
00410 %  The format of the GetLogList function is:
00411 %
00412 %      char **GetLogList(const char *pattern,size_t *number_preferences,
00413 %        ExceptionInfo *exception)
00414 %
00415 %  A description of each parameter follows:
00416 %
00417 %    o pattern: Specifies a pointer to a text string containing a pattern.
00418 %
00419 %    o number_preferences:  This integer returns the number of logs in the list.
00420 %
00421 %    o exception: Return any errors or warnings in this structure.
00422 %
00423 */
00424 
00425 #if defined(__cplusplus) || defined(c_plusplus)
00426 extern "C" {
00427 #endif
00428 
00429 static int LogCompare(const void *x,const void *y)
00430 {
00431   register const char
00432     **p,
00433     **q;
00434 
00435   p=(const char **) x;
00436   q=(const char **) y;
00437   return(LocaleCompare(*p,*q));
00438 }
00439 
00440 #if defined(__cplusplus) || defined(c_plusplus)
00441 }
00442 #endif
00443 
00444 WizardExport char **GetLogList(const char *pattern,
00445   size_t *number_preferences,ExceptionInfo *exception)
00446 {
00447   char
00448     **preferences;
00449 
00450   register const LogInfo
00451     *p;
00452 
00453   register ssize_t
00454     i;
00455 
00456   /*
00457     Allocate log list.
00458   */
00459   assert(pattern != (char *) NULL);
00460   (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",pattern);
00461   assert(number_preferences != (size_t *) NULL);
00462   *number_preferences=0;
00463   p=GetLogInfo("*",exception);
00464   if (p == (const LogInfo *) NULL)
00465     return((char **) NULL);
00466   preferences=(char **) AcquireQuantumMemory((size_t)
00467     GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00468   if (preferences == (char **) NULL)
00469     return((char **) NULL);
00470   /*
00471     Generate log list.
00472   */
00473   LockSemaphoreInfo(log_semaphore);
00474   ResetLinkedListIterator(log_list);
00475   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00476   for (i=0; p != (const LogInfo *) NULL; )
00477   {
00478     if ((p->stealth == WizardFalse) &&
00479         (GlobExpression(p->name,pattern,WizardFalse) != WizardFalse))
00480       preferences[i++]=ConstantString(p->name);
00481     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00482   }
00483   UnlockSemaphoreInfo(log_semaphore);
00484   qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
00485   preferences[i]=(char *) NULL;
00486   *number_preferences=(size_t) i;
00487   return(preferences);
00488 }
00489 
00490 /*
00491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00492 %                                                                             %
00493 %                                                                             %
00494 %                                                                             %
00495 %   G e t L o g N a m e                                                       %
00496 %                                                                             %
00497 %                                                                             %
00498 %                                                                             %
00499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00500 %
00501 %  GetLogName() returns the current log name.
00502 %
00503 %  The format of the GetLogName method is:
00504 %
00505 %      const char *GetLogName(void)
00506 %
00507 */
00508 WizardExport const char *GetLogName(void)
00509 {
00510   return(log_name);
00511 }
00512 
00513 /*
00514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00515 %                                                                             %
00516 %                                                                             %
00517 %                                                                             %
00518 +   I n i t i a l i z e L o g L i s t                                         %
00519 %                                                                             %
00520 %                                                                             %
00521 %                                                                             %
00522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00523 %
00524 %  InitializeLogList() initialize the log list.
00525 %
00526 %  The format of the InitializeLogList method is:
00527 %
00528 %      WizardBooleanType InitializeLogList(ExceptionInfo *exception)
00529 %
00530 %  A description of each parameter follows.
00531 %
00532 %    o exception: Return any errors or warnings in this structure.
00533 %
00534 */
00535 static WizardBooleanType InitializeLogList(ExceptionInfo *exception)
00536 {
00537   if ((log_list == (LinkedListInfo *) NULL) && (instantiate_log == WizardFalse))
00538     {
00539       if (log_semaphore == (SemaphoreInfo *) NULL)
00540         AcquireSemaphoreInfo(&log_semaphore);
00541       LockSemaphoreInfo(log_semaphore);
00542       if ((log_list == (LinkedListInfo *) NULL) &&
00543           (instantiate_log == WizardFalse))
00544         {
00545           (void) LoadLogLists(LogFilename,exception);
00546           instantiate_log=WizardTrue;
00547         }
00548       UnlockSemaphoreInfo(log_semaphore);
00549     }
00550   return(log_list != (LinkedListInfo *) NULL ? WizardTrue : WizardFalse);
00551 }
00552 
00553 /*
00554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00555 %                                                                             %
00556 %                                                                             %
00557 %                                                                             %
00558 %  I s E v e n t L o g g i n g                                                %
00559 %                                                                             %
00560 %                                                                             %
00561 %                                                                             %
00562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00563 %
00564 %  IsEventLogging() returns WizardTrue if debug of events is enabled otherwise
00565 %  WizardFalse.
00566 %
00567 %  The format of the IsEventLogging method is:
00568 %
00569 %      WizardBooleanType IsEventLogging(void)
00570 %
00571 */
00572 WizardExport WizardBooleanType IsEventLogging(void)
00573 {
00574   const LogInfo
00575     *log_info;
00576 
00577   ExceptionInfo
00578     *exception;
00579 
00580   if ((log_list == (LinkedListInfo *) NULL) ||
00581       (IsLinkedListEmpty(log_list) != WizardFalse))
00582     return(WizardFalse);
00583   exception=AcquireExceptionInfo();
00584   log_info=GetLogInfo("*",exception);
00585   exception=DestroyExceptionInfo(exception);
00586   return(log_info->event_mask != NoEvents ? WizardTrue : WizardFalse);
00587 }
00588 /*
00589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00590 %                                                                             %
00591 %                                                                             %
00592 %                                                                             %
00593 %  L i s t L o g I n f o                                                      %
00594 %                                                                             %
00595 %                                                                             %
00596 %                                                                             %
00597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00598 %
00599 %  ListLogInfo() lists the log info to a file.
00600 %
00601 %  The format of the ListLogInfo method is:
00602 %
00603 %      WizardBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00604 %
00605 %  A description of each parameter follows.
00606 %
00607 %    o file:  An pointer to a FILE.
00608 %
00609 %    o exception: Return any errors or warnings in this structure.
00610 %
00611 */
00612 WizardExport WizardBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00613 {
00614 #define MegabytesToBytes(value) ((WizardSizeType) (value)*1024*1024)
00615 
00616   char
00617     limit[MaxTextExtent];
00618 
00619   const char
00620     *path;
00621 
00622   const LogInfo
00623     **log_info;
00624 
00625   ssize_t
00626     j;
00627 
00628   register ssize_t
00629     i;
00630 
00631   size_t
00632     number_aliases;
00633 
00634   if (file == (const FILE *) NULL)
00635     file=stdout;
00636   log_info=GetLogInfoList("*",&number_aliases,exception);
00637   if (log_info == (const LogInfo **) NULL)
00638     return(WizardFalse);
00639   j=0;
00640   path=(const char *) NULL;
00641   for (i=0; i < (ssize_t) number_aliases; i++)
00642   {
00643     if (log_info[i]->stealth != WizardFalse)
00644       continue;
00645     if ((path == (const char *) NULL) ||
00646         (LocaleCompare(path,log_info[i]->path) != 0))
00647       {
00648         if (log_info[i]->path != (char *) NULL)
00649           (void) fprintf(file,"\nPath: %s\n\n",log_info[i]->path);
00650         (void) fprintf(file,"Filename       Generations     Limit  Format\n");
00651         (void) fprintf(file,"-------------------------------------------------"
00652           "------------------------------\n");
00653       }
00654     path=log_info[i]->path;
00655     if (log_info[i]->filename != (char *) NULL)
00656       {
00657         (void) fprintf(file,"%s",log_info[i]->filename);
00658         for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
00659           (void) fprintf(file," ");
00660       }
00661     (void) fprintf(file,"%9g  ",(double) log_info[i]->generations);
00662     (void) FormatWizardSize(MegabytesToBytes(log_info[i]->limit),WizardFalse,
00663       limit);
00664     (void) fprintf(file,"%8sB  ",limit);
00665     if (log_info[i]->format != (char *) NULL)
00666       (void) fprintf(file,"%s",log_info[i]->format);
00667     (void) fprintf(file,"\n");
00668   }
00669   (void) fflush(file);
00670   log_info=(const LogInfo **) RelinquishWizardMemory((void *) log_info);
00671   return(WizardTrue);
00672 }
00673 
00674 /*
00675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00676 %                                                                             %
00677 %                                                                             %
00678 %                                                                             %
00679 +   L o g C o m p o n e n t G e n e s i s                                     %
00680 %                                                                             %
00681 %                                                                             %
00682 %                                                                             %
00683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00684 %
00685 %  LogComponentGenesis() instantiates the log component.
00686 %
00687 %  The format of the LogComponentGenesis method is:
00688 %
00689 %      WizardBooleanType LogComponentGenesis(void)
00690 %
00691 */
00692 WizardExport WizardBooleanType LogComponentGenesis(void)
00693 {
00694   AcquireSemaphoreInfo(&log_semaphore);
00695   return(WizardTrue);
00696 }
00697 
00698 /*
00699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00700 %                                                                             %
00701 %                                                                             %
00702 %                                                                             %
00703 +   L o g C o m p o n e n t T e r m i n u s                                   %
00704 %                                                                             %
00705 %                                                                             %
00706 %                                                                             %
00707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00708 %
00709 %  LogComponentTerminus() destroys the log component.
00710 %
00711 %  The format of the LogComponentTerminus method is:
00712 %
00713 %      LogComponentTerminus(void)
00714 %
00715 */
00716 
00717 static void *DestroyLogElement(void *log_info)
00718 {
00719   register LogInfo
00720     *p;
00721 
00722   p=(LogInfo *) log_info;
00723   if (p->file != (FILE *) NULL)
00724     {
00725       if (p->append == WizardFalse)
00726         (void) fprintf(p->file,"</log>\n");
00727       (void) fclose(p->file);
00728       p->file=(FILE *) NULL;
00729     }
00730   if (p->exempt == WizardFalse)
00731     {
00732       if (p->format != (char *) NULL)
00733         p->format=DestroyString(p->format);
00734       if (p->filename != (char *) NULL)
00735         p->filename=DestroyString(p->filename);
00736       if (p->path != (char *) NULL)
00737         p->path=DestroyString(p->path);
00738     }
00739   if (p->timer != (TimerInfo *) NULL)
00740     p->timer=DestroyTimerInfo(p->timer);
00741   p=(LogInfo *) RelinquishWizardMemory(p);
00742   return((void *) NULL);
00743 }
00744 
00745 WizardExport void LogComponentTerminus(void)
00746 {
00747   if (log_semaphore == (SemaphoreInfo *) NULL)
00748     AcquireSemaphoreInfo(&log_semaphore);
00749   LockSemaphoreInfo(log_semaphore);
00750   if (log_list != (LinkedListInfo *) NULL)
00751     log_list=DestroyLinkedList(log_list,DestroyLogElement);
00752   instantiate_log=WizardFalse;
00753   UnlockSemaphoreInfo(log_semaphore);
00754   DestroySemaphoreInfo(&log_semaphore);
00755 }
00756 
00757 /*
00758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00759 %                                                                             %
00760 %                                                                             %
00761 %                                                                             %
00762 %   L o g W i z a r d E v e n t                                               %
00763 %                                                                             %
00764 %                                                                             %
00765 %                                                                             %
00766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00767 %
00768 %  LogWizardEvent() logs an event as determined by the log configuration file.
00769 %  If an error occurs, WizardFalse is returned otherwise WizardTrue.
00770 %
00771 %  The format of the LogWizardEvent method is:
00772 %
00773 %      WizardBooleanType LogWizardEvent(const LogEventType type,
00774 %        const char *module,const char *function,const size_t line,
00775 %        const char *format,...)
00776 %
00777 %  A description of each parameter follows:
00778 %
00779 %    o type: The event type.
00780 %
00781 %    o filename: The source module filename.
00782 %
00783 %    o function: The function name.
00784 %
00785 %    o line: The line number of the source module.
00786 %
00787 %    o format: The output format.
00788 %
00789 */
00790 static char *TranslateEvent(const LogEventType wizard_unused(type),
00791   const char *module,const char *function,const size_t line,
00792   const char *domain,const char *event)
00793 {
00794   char
00795     *text;
00796 
00797   double
00798     elapsed_time,
00799     user_time;
00800 
00801   ExceptionInfo
00802     *exception;
00803 
00804   LogInfo
00805     *log_info;
00806 
00807   register char
00808     *q;
00809 
00810   register const char
00811     *p;
00812 
00813   size_t
00814     extent;
00815 
00816   time_t
00817     seconds;
00818 
00819   exception=AcquireExceptionInfo();
00820   log_info=(LogInfo *) GetLogInfo("*",exception);
00821   exception=DestroyExceptionInfo(exception);
00822   seconds=time((time_t *) NULL);
00823   elapsed_time=GetElapsedTime(log_info->timer);
00824   user_time=GetUserTime(log_info->timer);
00825   text=AcquireString(event);
00826   if (log_info->format == (char *) NULL)
00827     return(text);
00828   extent=strlen(event)+MaxTextExtent;
00829   if (LocaleCompare(log_info->format,"xml") == 0)
00830     {
00831       char
00832         timestamp[MaxTextExtent];
00833 
00834       /*
00835         Translate event in "XML" format.
00836       */
00837       (void) FormatWizardTime(seconds,extent,timestamp);
00838       (void) FormatLocaleString(text,extent,
00839         "<entry>\n"
00840         "  <timestamp>%s</timestamp>\n"
00841         "  <elapsed-time>%lu:%02lu.%03lu</elapsed-time>\n"
00842         "  <user-time>%0.3f</user-time>\n"
00843         "  <process-id>%.20g</process-id>\n"
00844         "  <thread-id>%.20g</thread-id>\n"
00845         "  <module>%s</module>\n"
00846         "  <function>%s</function>\n"
00847         "  <line>%.20g</line>\n"
00848         "  <domain>%s</domain>\n"
00849         "  <event>%s</event>\n"
00850         "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),(unsigned long)
00851         floor(fmod(elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-
00852         floor(elapsed_time))+0.5),user_time,(double) getpid(),(double)
00853         GetWizardThreadSignature(),module,function,(double) line,domain,event);
00854       return(text);
00855     }
00856   /*
00857     Translate event in "human readable" format.
00858   */
00859   q=text;
00860   for (p=log_info->format; *p != '\0'; p++)
00861   {
00862     *q='\0';
00863     if ((size_t) (q-text+MaxTextExtent) >= extent)
00864       {
00865         extent+=MaxTextExtent;
00866         text=(char *) ResizeQuantumMemory(text,extent+MaxTextExtent,
00867           sizeof(*text));
00868         if (text == (char *) NULL)
00869           return((char *) NULL);
00870         q=text+strlen(text);
00871       }
00872     /*
00873       The format of the log is defined by embedding special format characters:
00874 
00875         %c   client name
00876         %d   domain
00877         %e   event
00878         %f   function
00879         %g   generation
00880         %l   line
00881         %m   module
00882         %n   log name
00883         %p   process id
00884         %r   real CPU time
00885         %t   wall clock time
00886         %u   user CPU time
00887         %v   version
00888         %%   percent sign
00889         \n   newline
00890         \r   carriage return
00891     */
00892     if ((*p == '\\') && (*(p+1) == 'r'))
00893       {
00894         *q++='\r';
00895         p++;
00896         continue;
00897       }
00898     if ((*p == '\\') && (*(p+1) == 'n'))
00899       {
00900         *q++='\n';
00901         p++;
00902         continue;
00903       }
00904     if (*p != '%')
00905       {
00906         *q++=(*p);
00907         continue;
00908       }
00909     p++;
00910     switch (*p)
00911     {
00912       case 'c':
00913       {
00914         q+=CopyWizardString(q,GetClientName(),extent);
00915         break;
00916       }
00917       case 'd':
00918       {
00919         q+=CopyWizardString(q,domain,extent);
00920         break;
00921       }
00922       case 'e':
00923       {
00924         q+=CopyWizardString(q,event,extent);
00925         break;
00926       }
00927       case 'f':
00928       {
00929         q+=CopyWizardString(q,function,extent);
00930         break;
00931       }
00932       case 'g':
00933       {
00934         if (log_info->generations == 0)
00935           {
00936             (void) CopyWizardString(q,"0",extent);
00937             q++;
00938             break;
00939           }
00940         q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
00941           log_info->generations));
00942         break;
00943       }
00944       case 'l':
00945       {
00946         q+=FormatLocaleString(q,extent,"%.20g",(double) line);
00947         break;
00948       }
00949       case 'm':
00950       {
00951         register const char
00952           *p;
00953 
00954         for (p=module+strlen(module)-1; p > module; p--)
00955           if (*p == *DirectorySeparator)
00956             {
00957               p++;
00958               break;
00959             }
00960         q+=CopyWizardString(q,p,extent);
00961         break;
00962       }
00963       case 'n':
00964       {
00965         q+=CopyWizardString(q,GetLogName(),extent);
00966         break;
00967       }
00968       case 'p':
00969       {
00970         q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
00971         break;
00972       }
00973       case 'r':
00974       {
00975         q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
00976           (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
00977           (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
00978         break;
00979       }
00980       case 't':
00981       {
00982         q+=FormatWizardTime(seconds,extent,q);
00983         break;
00984       }
00985       case 'u':
00986       {
00987         q+=FormatLocaleString(q,extent,"%0.3fu",user_time);
00988         break;
00989       }
00990       case 'v':
00991       {
00992         q+=CopyWizardString(q,WizardLibVersionText,extent);
00993         break;
00994       }
00995       case '%':
00996       {
00997         *q++=(*p);
00998         break;
00999       }
01000       default:
01001       {
01002         *q++='%';
01003         *q++=(*p);
01004         break;
01005       }
01006     }
01007   }
01008   *q='\0';
01009   return(text);
01010 }
01011 
01012 static char *TranslateFilename(const LogInfo *log_info)
01013 {
01014   char
01015     *filename;
01016 
01017   register char
01018     *q;
01019 
01020   register const char
01021     *p;
01022 
01023   size_t
01024     extent;
01025 
01026   /*
01027     Translate event in "human readable" format.
01028   */
01029   assert(log_info != (LogInfo *) NULL);
01030   assert(log_info->filename != (char *) NULL);
01031   filename=AcquireString((char *) NULL);
01032   extent=MaxTextExtent;
01033   q=filename;
01034   for (p=log_info->filename; *p != '\0'; p++)
01035   {
01036     *q='\0';
01037     if ((size_t) (q-filename+MaxTextExtent) >= extent)
01038       {
01039         extent+=MaxTextExtent;
01040         filename=(char *) ResizeQuantumMemory(filename,extent+MaxTextExtent,
01041           sizeof(*filename));
01042         if (filename == (char *) NULL)
01043           return((char *) NULL);
01044         q=filename+strlen(filename);
01045       }
01046     /*
01047       The format of the filename is defined by embedding special format
01048       characters:
01049 
01050         %c   client name
01051         %n   log name
01052         %p   process id
01053         %v   version
01054         %%   percent sign
01055     */
01056     if (*p != '%')
01057       {
01058         *q++=(*p);
01059         continue;
01060       }
01061     p++;
01062     switch (*p)
01063     {
01064       case 'c':
01065       {
01066         q+=CopyWizardString(q,GetClientName(),extent);
01067         break;
01068       }
01069       case 'g':
01070       {
01071         if (log_info->generations == 0)
01072           {
01073             (void) CopyWizardString(q,"0",extent);
01074             q++;
01075             break;
01076           }
01077         q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
01078           log_info->generations));
01079         break;
01080       }
01081       case 'n':
01082       {
01083         q+=CopyWizardString(q,GetLogName(),extent);
01084         break;
01085       }
01086       case 'p':
01087       {
01088         q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
01089         break;
01090       }
01091       case 'v':
01092       {
01093         q+=CopyWizardString(q,WizardLibVersionText,extent);
01094         break;
01095       }
01096       case '%':
01097       {
01098         *q++=(*p);
01099         break;
01100       }
01101       default:
01102       {
01103         *q++='%';
01104         *q++=(*p);
01105         break;
01106       }
01107     }
01108   }
01109   *q='\0';
01110   return(filename);
01111 }
01112 
01113 WizardBooleanType LogWizardEventList(const LogEventType type,const char *module,
01114   const char *function,const size_t line,const char *format,
01115   va_list operands)
01116 {
01117   char
01118     event[MaxTextExtent],
01119     *text;
01120 
01121   const char
01122     *domain;
01123 
01124   ExceptionInfo
01125     *exception;
01126 
01127   int
01128     n;
01129 
01130   LogInfo
01131     *log_info;
01132 
01133   if (IsEventLogging() == WizardFalse)
01134     return(WizardFalse);
01135   exception=AcquireExceptionInfo();
01136   log_info=(LogInfo *) GetLogInfo("*",exception);
01137   exception=DestroyExceptionInfo(exception);
01138   LockSemaphoreInfo(log_semaphore);
01139   if ((log_info->event_mask & type) == 0)
01140     {
01141       UnlockSemaphoreInfo(log_semaphore);
01142       return(WizardTrue);
01143     }
01144   domain=WizardOptionToMnemonic(WizardLogEventOptions,type);
01145 #if defined(WIZARDSTOOLKIT_HAVE_VSNPRINTF)
01146   n=vsnprintf(event,MaxTextExtent,format,operands);
01147 #else
01148   n=vsprintf(event,format,operands);
01149 #endif
01150   if (n < 0)
01151     event[MaxTextExtent-1]='\0';
01152   text=TranslateEvent(type,module,function,line,domain,event);
01153   if (text == (char *) NULL)
01154     {
01155       (void) ContinueTimer(log_info->timer);
01156       UnlockSemaphoreInfo(log_semaphore);
01157       return(WizardFalse);
01158     }
01159   if ((log_info->handler_mask & ConsoleHandler) != 0)
01160     {
01161       (void) fprintf(stderr,"%s\n",text);
01162       (void) fflush(stderr);
01163     }
01164   if ((log_info->handler_mask & DebugHandler) != 0)
01165     {
01166 #if defined(WIZARDSTOOLKIT_WINDOWS_SUPPORT)
01167       OutputDebugString(text);
01168 #endif
01169     }
01170   if ((log_info->handler_mask & EventHandler) != 0)
01171     {
01172 #if defined(WIZARDSTOOLKIT_WINDOWS_SUPPORT)
01173       (void) NTReportEvent(text,WizardFalse);
01174 #endif
01175     }
01176   if ((log_info->handler_mask & FileHandler) != 0)
01177     {
01178       struct stat
01179         file_info;
01180 
01181       file_info.st_size=0;
01182       if (log_info->file != (FILE *) NULL)
01183         (void) fstat(fileno(log_info->file),&file_info);
01184       if (file_info.st_size > (1024*1024*log_info->limit))
01185         {
01186           (void) fprintf(log_info->file,"</log>\n");
01187           (void) fclose(log_info->file);
01188           log_info->file=(FILE *) NULL;
01189         }
01190       if (log_info->file == (FILE *) NULL)
01191         {
01192           char
01193             *filename;
01194 
01195           filename=TranslateFilename(log_info);
01196           if (filename == (char *) NULL)
01197             {
01198               (void) ContinueTimer(log_info->timer);
01199               UnlockSemaphoreInfo(log_semaphore);
01200               return(WizardFalse);
01201             }
01202           log_info->append=IsAccessible(filename);
01203           log_info->file=fopen_utf8(filename,"ab");
01204           filename=(char  *) RelinquishWizardMemory(filename);
01205           if (log_info->file == (FILE *) NULL)
01206             {
01207               UnlockSemaphoreInfo(log_semaphore);
01208               return(WizardFalse);
01209             }
01210           log_info->generation++;
01211           if (log_info->append == WizardFalse)
01212             {
01213               (void) fprintf(log_info->file,"<?xml version=\"1.0\" "
01214                 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
01215               (void) fprintf(log_info->file,"<log>\n");
01216             }
01217         }
01218       (void) fprintf(log_info->file,"%s\n",text);
01219       (void) fflush(log_info->file);
01220     }
01221   if ((log_info->handler_mask & StdoutHandler) != 0)
01222     {
01223       (void) fprintf(stdout,"%s\n",text);
01224       (void) fflush(stdout);
01225     }
01226   if ((log_info->handler_mask & StderrHandler) != 0)
01227     {
01228       (void) fprintf(stderr,"%s\n",text);
01229       (void) fflush(stderr);
01230     }
01231   text=(char  *) RelinquishWizardMemory(text);
01232   (void) ContinueTimer(log_info->timer);
01233   UnlockSemaphoreInfo(log_semaphore);
01234   return(WizardTrue);
01235 }
01236 
01237 WizardBooleanType LogWizardEvent(const LogEventType type,const char *module,
01238   const char *function,const size_t line,const char *format,...)
01239 {
01240   va_list
01241     operands;
01242 
01243   WizardBooleanType
01244     status;
01245 
01246   va_start(operands,format);
01247   status=LogWizardEventList(type,module,function,line,format,operands);
01248   va_end(operands);
01249   return(status);
01250 }
01251 
01252 /*
01253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01254 %                                                                             %
01255 %                                                                             %
01256 %                                                                             %
01257 +   L o a d L o g L i s t                                                     %
01258 %                                                                             %
01259 %                                                                             %
01260 %                                                                             %
01261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01262 %
01263 %  LoadLogList() loads the log configuration file which provides a
01264 %  mapping between log attributes and log name.
01265 %
01266 %  The format of the LoadLogList method is:
01267 %
01268 %      WizardBooleanType LoadLogList(const char *xml,const char *filename,
01269 %        const size_t depth,ExceptionInfo *exception)
01270 %
01271 %  A description of each parameter follows:
01272 %
01273 %    o xml:  The log list in XML format.
01274 %
01275 %    o filename:  The log list filename.
01276 %
01277 %    o depth: depth of <include /> statements.
01278 %
01279 %    o exception: Return any errors or warnings in this structure.
01280 %
01281 */
01282 static WizardBooleanType LoadLogList(const char *xml,const char *filename,
01283   const size_t depth,ExceptionInfo *exception)
01284 {
01285   char
01286     keyword[MaxTextExtent],
01287     *token;
01288 
01289   const char
01290     *q;
01291 
01292   LogInfo
01293     *log_info = (LogInfo *) NULL;
01294 
01295   WizardStatusType
01296     status;
01297 
01298   /*
01299     Load the log map file.
01300   */
01301   if (xml == (const char *) NULL)
01302     return(WizardFalse);
01303   if (log_list == (LinkedListInfo *) NULL)
01304     {
01305       log_list=NewLinkedList(0);
01306       if (log_list == (LinkedListInfo *) NULL)
01307         {
01308           (void) ThrowWizardException(exception,GetWizardModule(),
01309             ConfigureError,"memory allocation failed: `%s'",filename);
01310           return(WizardFalse);
01311         }
01312     }
01313   status=WizardTrue;
01314   token=AcquireString((char *) xml);
01315   for (q=(char *) xml; *q != '\0'; )
01316   {
01317     /*
01318       Interpret XML.
01319     */
01320     GetWizardToken(q,&q,token);
01321     if (*token == '\0')
01322       break;
01323     (void) CopyWizardString(keyword,token,MaxTextExtent);
01324     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
01325       {
01326         /*
01327           Doctype element.
01328         */
01329         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
01330           GetWizardToken(q,&q,token);
01331         continue;
01332       }
01333     if (LocaleNCompare(keyword,"<!--",4) == 0)
01334       {
01335         /*
01336           Comment element.
01337         */
01338         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
01339           GetWizardToken(q,&q,token);
01340         continue;
01341       }
01342     if (LocaleCompare(keyword,"<include") == 0)
01343       {
01344         /*
01345           Include element.
01346         */
01347         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
01348         {
01349           (void) CopyWizardString(keyword,token,MaxTextExtent);
01350           GetWizardToken(q,&q,token);
01351           if (*token != '=')
01352             continue;
01353           GetWizardToken(q,&q,token);
01354           if (LocaleCompare(keyword,"file") == 0)
01355             {
01356               if (depth > 200)
01357                 (void) ThrowWizardException(exception,GetWizardModule(),
01358                   ConfigureError,"include element nested too deeply: `%s'",
01359                   token);
01360               else
01361                 {
01362                   char
01363                     path[MaxTextExtent],
01364                     *xml;
01365 
01366                   GetPathComponent(filename,HeadPath,path);
01367                   if (*path != '\0')
01368                     (void) ConcatenateWizardString(path,DirectorySeparator,
01369                       MaxTextExtent);
01370                   if (*token == *DirectorySeparator)
01371                     (void) CopyWizardString(path,token,MaxTextExtent);
01372                   else
01373                     (void) ConcatenateWizardString(path,token,MaxTextExtent);
01374                   xml=FileToString(path,~0,exception);
01375                   if (xml != (char *) NULL)
01376                     {
01377                       status|=LoadLogList(xml,path,depth+1,exception);
01378                       xml=DestroyString(xml);
01379                     }
01380                 }
01381             }
01382         }
01383         continue;
01384       }
01385     if (LocaleCompare(keyword,"<logmap>") == 0)
01386       {
01387         /*
01388           Allocate memory for the log list.
01389         */
01390         log_info=(LogInfo *) AcquireWizardMemory(sizeof(*log_info));
01391         if (log_info == (LogInfo *) NULL)
01392           ThrowFatalException(ResourceFatalError,
01393             "memory allocation failed: `%s'");
01394         (void) ResetWizardMemory(log_info,0,sizeof(*log_info));
01395         log_info->path=ConstantString(filename);
01396         log_info->timer=AcquireTimerInfo();
01397         log_info->exempt=WizardFalse;
01398         log_info->signature=WizardSignature;
01399         continue;
01400       }
01401     if (log_info == (LogInfo *) NULL)
01402       continue;
01403     if (LocaleCompare(keyword,"</logmap>") == 0)
01404       {
01405         status=AppendValueToLinkedList(log_list,log_info);
01406         if (status == WizardFalse)
01407           (void) ThrowWizardException(exception,GetWizardModule(),
01408             ResourceError,"memory allocation failed: `%s'",filename);
01409         log_info=(LogInfo *) NULL;
01410       }
01411     GetWizardToken(q,(const char **) NULL,token);
01412     if (*token != '=')
01413       continue;
01414     GetWizardToken(q,&q,token);
01415     GetWizardToken(q,&q,token);
01416     switch (*keyword)
01417     {
01418       case 'E':
01419       case 'e':
01420       {
01421         if (LocaleCompare((char *) keyword,"events") == 0)
01422           {
01423             log_info->event_mask=(LogEventType) (log_info->event_mask |
01424               ParseWizardOption(WizardLogEventOptions,WizardTrue,token));
01425             break;
01426           }
01427         break;
01428       }
01429       case 'F':
01430       case 'f':
01431       {
01432         if (LocaleCompare((char *) keyword,"filename") == 0)
01433           {
01434             if (log_info->filename != (char *) NULL)
01435               log_info->filename=(char *)
01436                 RelinquishWizardMemory(log_info->filename);
01437             log_info->filename=ConstantString(token);
01438             break;
01439           }
01440         if (LocaleCompare((char *) keyword,"format") == 0)
01441           {
01442             if (log_info->format != (char *) NULL)
01443               log_info->format=(char *)
01444                 RelinquishWizardMemory(log_info->format);
01445             log_info->format=ConstantString(token);
01446             break;
01447           }
01448         break;
01449       }
01450       case 'G':
01451       case 'g':
01452       {
01453         if (LocaleCompare((char *) keyword,"generations") == 0)
01454           {
01455             if (LocaleCompare(token,"unlimited") == 0)
01456               {
01457                 log_info->generations=(~0UL);
01458                 break;
01459               }
01460             log_info->generations=StringToUnsignedLong(token);
01461             break;
01462           }
01463         break;
01464       }
01465       case 'L':
01466       case 'l':
01467       {
01468         if (LocaleCompare((char *) keyword,"limit") == 0)
01469           {
01470             if (LocaleCompare(token,"unlimited") == 0)
01471               {
01472                 log_info->limit=(~0UL);
01473                 break;
01474               }
01475             log_info->limit=StringToUnsignedLong(token);
01476             break;
01477           }
01478         break;
01479       }
01480       case 'O':
01481       case 'o':
01482       {
01483         if (LocaleCompare((char *) keyword,"output") == 0)
01484           {
01485             log_info->handler_mask=(LogHandlerType)
01486               (log_info->handler_mask | ParseLogHandlers(token));
01487             break;
01488           }
01489         break;
01490       }
01491       default:
01492         break;
01493     }
01494   }
01495   token=DestroyString(token);
01496   if (log_list == (LinkedListInfo *) NULL)
01497     return(WizardFalse);
01498   return(status != 0 ? WizardTrue : WizardFalse);
01499 }
01500 
01501 /*
01502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01503 %                                                                             %
01504 %                                                                             %
01505 %                                                                             %
01506 %  L o a d L o g L i s t s                                                    %
01507 %                                                                             %
01508 %                                                                             %
01509 %                                                                             %
01510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01511 %
01512 %  LoadLogLists() loads one or more log configuration file which provides a
01513 %  mapping between log attributes and log name.
01514 %
01515 %  The format of the LoadLogLists method is:
01516 %
01517 %      WizardBooleanType LoadLogLists(const char *filename,
01518 %        ExceptionInfo *exception)
01519 %
01520 %  A description of each parameter follows:
01521 %
01522 %    o filename: The log configuration filename.
01523 %
01524 %    o exception: Return any errors or warnings in this structure.
01525 %
01526 */
01527 static WizardBooleanType LoadLogLists(const char *filename,
01528   ExceptionInfo *exception)
01529 {
01530   const StringInfo
01531     *option;
01532 
01533   LinkedListInfo
01534     *options;
01535 
01536   WizardStatusType
01537     status;
01538 
01539   register ssize_t
01540     i;
01541 
01542   /*
01543     Load built-in log map.
01544   */
01545   status=WizardFalse;
01546   if (log_list == (LinkedListInfo *) NULL)
01547     {
01548       log_list=NewLinkedList(0);
01549       if (log_list == (LinkedListInfo *) NULL)
01550         {
01551           ThrowFileException(exception,FileError,filename);
01552           return(WizardFalse);
01553         }
01554     }
01555   for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
01556   {
01557     LogInfo
01558       *log_info;
01559 
01560     register const LogMapInfo
01561       *p;
01562 
01563     p=LogMap+i;
01564     log_info=(LogInfo *) AcquireWizardMemory(sizeof(*log_info));
01565     if (log_info == (LogInfo *) NULL)
01566       {
01567         (void) ThrowWizardException(exception,GetWizardModule(),ResourceError,
01568           "memory allocation failed `%s'",log_info->name);
01569         continue;
01570       }
01571     (void) ResetWizardMemory(log_info,0,sizeof(*log_info));
01572     log_info->path=(char *) "[built-in]";
01573     log_info->timer=AcquireTimerInfo();
01574     log_info->event_mask=p->event_mask;
01575     log_info->handler_mask=p->handler_mask;
01576     log_info->filename=ConstantString(p->filename);
01577     log_info->format=ConstantString(p->format);
01578     log_info->exempt=WizardTrue;
01579     log_info->signature=WizardSignature;
01580     status=AppendValueToLinkedList(log_list,log_info);
01581     if (status == WizardFalse)
01582       (void) ThrowWizardException(exception,GetWizardModule(),ResourceError,
01583         "memory allocation failed `%s'",log_info->name);
01584   }
01585   /*
01586     Load external log map.
01587   */
01588   options=GetConfigureOptions(filename,exception);
01589   option=(const StringInfo *) GetNextValueInLinkedList(options);
01590   while (option != (const StringInfo *) NULL)
01591   {
01592     status|=LoadLogList((const char *) GetStringInfoDatum(option),
01593       GetStringInfoPath(option),0,exception);
01594     option=(const StringInfo *) GetNextValueInLinkedList(options);
01595   }
01596   options=DestroyConfigureOptions(options);
01597   return(status != 0 ? WizardTrue : WizardFalse);
01598 }
01599 
01600 /*
01601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01602 %                                                                             %
01603 %                                                                             %
01604 %                                                                             %
01605 +   P a r s e L o g H a n d l e r s                                           %
01606 %                                                                             %
01607 %                                                                             %
01608 %                                                                             %
01609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01610 %
01611 %  ParseLogHandlers() parses a string defining which handlers takes a log
01612 %  message and exports them.
01613 %
01614 %  The format of the ParseLogHandlers method is:
01615 %
01616 %      LogHandlerType ParseLogHandlers(const char *handlers)
01617 %
01618 %  A description of each parameter follows:
01619 %
01620 %    o handlers: one or more handlers separated by commas.
01621 %
01622 */
01623 static LogHandlerType ParseLogHandlers(const char *handlers)
01624 {
01625   LogHandlerType
01626     handler_mask;
01627 
01628   register const char
01629     *p;
01630 
01631   register ssize_t
01632     i;
01633 
01634   size_t
01635     length;
01636 
01637   handler_mask=NoHandler;
01638   for (p=handlers; p != (char *) NULL; p=strchr(p,','))
01639   {
01640     while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
01641            (*p == ',')))
01642       p++;
01643     for (i=0; LogHandlers[i].name != (char *) NULL; i++)
01644     {
01645       length=strlen(LogHandlers[i].name);
01646       if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
01647         {
01648           handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
01649           break;
01650         }
01651     }
01652     if (LogHandlers[i].name == (char *) NULL)
01653       return(UndefinedHandler);
01654   }
01655   return(handler_mask);
01656 }
01657 
01658 /*
01659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01660 %                                                                             %
01661 %                                                                             %
01662 %                                                                             %
01663 %   S e t L o g E v e n t M a s k                                             %
01664 %                                                                             %
01665 %                                                                             %
01666 %                                                                             %
01667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01668 %
01669 %  SetLogEventMask() accepts a list that determines which events to log.  All
01670 %  other events are ignored.  By default, no debug is enabled.  This method
01671 %  returns the previous log event mask.
01672 %
01673 %  The format of the SetLogEventMask method is:
01674 %
01675 %      LogEventType SetLogEventMask(const char *events)
01676 %
01677 %  A description of each parameter follows:
01678 %
01679 %    o events: log these events.
01680 %
01681 */
01682 WizardExport LogEventType SetLogEventMask(const char *events)
01683 {
01684   ExceptionInfo
01685     *exception;
01686 
01687   LogInfo
01688     *log_info;
01689 
01690   ssize_t
01691     option;
01692 
01693   exception=AcquireExceptionInfo();
01694   log_info=(LogInfo *) GetLogInfo("*",exception);
01695   exception=DestroyExceptionInfo(exception);
01696   option=ParseWizardOption(WizardLogEventOptions,WizardTrue,events);
01697   LockSemaphoreInfo(log_semaphore);
01698   log_info=(LogInfo *) GetValueFromLinkedList(log_list,0);
01699   log_info->event_mask=(LogEventType) option;
01700   if (option == -1)
01701     log_info->event_mask=UndefinedEvents;
01702   UnlockSemaphoreInfo(log_semaphore);
01703   return(log_info->event_mask);
01704 }
01705 
01706 /*
01707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01708 %                                                                             %
01709 %                                                                             %
01710 %                                                                             %
01711 %   S e t L o g F o r m a t                                                   %
01712 %                                                                             %
01713 %                                                                             %
01714 %                                                                             %
01715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01716 %
01717 %  SetLogFormat() sets the format for the "human readable" log record.
01718 %
01719 %  The format of the LogWizardFormat method is:
01720 %
01721 %      SetLogFormat(const char *format)
01722 %
01723 %  A description of each parameter follows:
01724 %
01725 %    o format: The log record format.
01726 %
01727 */
01728 WizardExport void SetLogFormat(const char *format)
01729 {
01730   ExceptionInfo
01731     *exception;
01732 
01733   LogInfo
01734     *log_info;
01735 
01736   exception=AcquireExceptionInfo();
01737   log_info=(LogInfo *) GetLogInfo("*",exception);
01738   exception=DestroyExceptionInfo(exception);
01739   LockSemaphoreInfo(log_semaphore);
01740   if (log_info->format != (char *) NULL)
01741     log_info->format=DestroyString(log_info->format);
01742   log_info->format=ConstantString(format);
01743   UnlockSemaphoreInfo(log_semaphore);
01744 }
01745 
01746 /*
01747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01748 %                                                                             %
01749 %                                                                             %
01750 %                                                                             %
01751 %   S e t L o g N a m e                                                       %
01752 %                                                                             %
01753 %                                                                             %
01754 %                                                                             %
01755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01756 %
01757 %  SetLogName() sets the log name and returns it.
01758 %
01759 %  The format of the SetLogName method is:
01760 %
01761 %      const char *SetLogName(const char *name)
01762 %
01763 %  A description of each parameter follows:
01764 %
01765 %    o log_name: SetLogName() returns the current client name.
01766 %
01767 %    o name: Specifies the new client name.
01768 %
01769 */
01770 WizardExport const char *SetLogName(const char *name)
01771 {
01772   if ((name != (char *) NULL) && (*name != '\0'))
01773     (void) CopyWizardString(log_name,name,MaxTextExtent);
01774   return(log_name);
01775 }