home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / io / prlog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  11.9 KB  |  419 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20. #include "prenv.h"
  21. #include "prprf.h"
  22. #include <string.h>
  23.  
  24. /*
  25.  * Lock used to lock the log.
  26.  *
  27.  * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
  28.  * contain assertions.  We have to avoid assertions in _PR_LOCK_LOG
  29.  * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
  30.  * This can lead to infinite recursion.
  31.  */
  32. static PRLock *_pr_logLock;
  33. #if (defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY))
  34. #define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
  35. #define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
  36. #else
  37.  
  38. #define _PR_LOCK_LOG() \
  39. { \
  40.     PRIntn _is; \
  41.     PRThread *_me = _PR_MD_CURRENT_THREAD(); \
  42.     if (!_PR_IS_NATIVE_THREAD(_me)) \
  43.         _PR_INTSOFF(_is); \
  44.     _PR_LOCK_LOCK(_pr_logLock)
  45.  
  46. #define _PR_UNLOCK_LOG() \
  47.     _PR_LOCK_UNLOCK(_pr_logLock); \
  48.     PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
  49.     if (!_PR_IS_NATIVE_THREAD(_me)) \
  50.         _PR_INTSON(_is); \
  51. }
  52.  
  53. #endif
  54.  
  55. #ifdef XP_PC
  56. #define strcasecmp stricmp
  57. #define strncasecmp strnicmp
  58. #endif
  59.  
  60. /*
  61.  * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
  62.  * because every asynchronous file io operation leads to a fiber context
  63.  * switch.  So we define _PUT_LOG as fputs (from stdio.h).  A side
  64.  * benefit is that fputs handles the LF->CRLF translation.  This
  65.  * code can also be used on other platforms with file stream io.
  66.  */
  67. #if defined(WIN32) || defined(XP_OS2)
  68. #define _PR_USE_STDIO_FOR_LOGGING
  69. #endif
  70.  
  71. /* Macros used to reduce #ifdef pollution */
  72.  
  73. #if defined(_PR_USE_STDIO_FOR_LOGGING)
  74. #define _PUT_LOG(fd, buf, nb) fputs(buf, fd)
  75. #elif defined(_PR_PTHREADS)
  76. #define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
  77. #elif defined(XP_MAC)
  78. #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb)
  79. #else
  80. #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
  81. #endif
  82.  
  83. /************************************************************************/
  84.  
  85. static PRLogModuleInfo *logModules;
  86.  
  87. #ifdef PR_LOGGING
  88. static char *logBuf = NULL;
  89. static char *logp;
  90. static char *logEndp;
  91. #ifdef _PR_USE_STDIO_FOR_LOGGING
  92. static FILE *logFile = NULL;
  93. #else
  94. static PRFileDesc *logFile = 0;
  95. #endif
  96.  
  97. #define LINE_BUF_SIZE                200
  98. #define DEFAULT_BUF_SIZE        16384
  99.  
  100. #ifdef _PR_NEED_STRCASECMP
  101.  
  102. /*
  103.  * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
  104.  * such as NCR and Unixware.  Linking with both libc and libucb
  105.  * may cause some problem, so I just provide our own implementation
  106.  * of strcasecmp here.
  107.  */
  108.  
  109. static const unsigned char uc[] =
  110. {
  111.     '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
  112.     '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
  113.     '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
  114.     '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
  115.     ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
  116.     '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
  117.     '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
  118.     '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
  119.     '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
  120.     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
  121.     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
  122.     'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
  123.     '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
  124.     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
  125.     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
  126.     'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
  127. };
  128.  
  129. PRIntn strcasecmp(const char *a, const char *b)
  130. {
  131.     const unsigned char *ua = (const unsigned char *)a;
  132.     const unsigned char *ub = (const unsigned char *)b;
  133.  
  134.     if( ((const char *)0 == a) || (const char *)0 == b ) 
  135.         return (PRIntn)(a-b);
  136.  
  137.     while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
  138.     {
  139.         a++;
  140.         ua++;
  141.         ub++;
  142.     }
  143.  
  144.     return (PRIntn)(uc[*ua] - uc[*ub]);
  145. }
  146.  
  147. #endif /* _PR_NEED_STRCASECMP */
  148.  
  149. void _PR_InitLog(void)
  150. {
  151.     char *ev;
  152.  
  153.     _pr_logLock = PR_NewLock();
  154.  
  155.     ev = PR_GetEnv("NSPR_LOG_MODULES");
  156.     if (ev && ev[0]) {
  157.         char module[64];
  158.         PRBool isSync = PR_FALSE;
  159.         PRIntn evlen = strlen(ev), pos = 0;
  160.         PRInt32 bufSize = DEFAULT_BUF_SIZE;
  161.         while (pos < evlen) {
  162.             PRIntn level = 1, count = 0, delta = 0;
  163.             count = sscanf(&ev[pos], "%64[A-Za-z0-9]%n:%d%n",
  164.                            module, &delta, &level, &delta);
  165.             pos += delta;
  166.             if (count == 0) break;
  167.  
  168.             /*
  169.             ** If count == 2, then we got module and level. If count
  170.             ** == 1, then level defaults to 1 (module enabled).
  171.             */
  172.             if (strcasecmp(module, "sync") == 0) {
  173.                 isSync = PR_TRUE;
  174.             } else if (strcasecmp(module, "bufsize") == 0) {
  175.                 if (level >= LINE_BUF_SIZE) {
  176.                     bufSize = level;
  177.                 }
  178.             } else {
  179.                 PRLogModuleInfo *lm = logModules;
  180.                 PRBool skip_modcheck =
  181.                     (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE;
  182.  
  183.                 while (lm != NULL) {
  184.                     if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
  185.                     else if (strcasecmp(module, lm->name) == 0) {
  186.                         lm->level = (PRLogModuleLevel)level;
  187.                         break;
  188.                     }
  189.                     lm = lm->next;
  190.                 }
  191.                 if (NULL == lm) {
  192. #ifdef XP_PC
  193.                     char* str = PR_smprintf("Unrecognized NSPR_LOG_MODULE: %s=%d\n",
  194.                                             module, level);
  195.                     if (str) {
  196.                         OutputDebugString(str);
  197.                         PR_smprintf_free(str);
  198.                     }
  199. #else
  200.                     fprintf(stderr, "Unrecognized NSPR_LOG_MODULE: %s=%d\n",
  201.                             module, level);
  202. #endif
  203.                 }
  204.             }
  205.             /*found:*/
  206.             count = sscanf(&ev[pos], " , %n", &delta);
  207.             pos += delta;
  208.             if (count == -1) break;
  209.         }
  210.         PR_SetLogBuffering(isSync ? bufSize : 0);
  211.  
  212.         ev = PR_GetEnv("NSPR_LOG_FILE");
  213.         if (ev && ev[0]) {
  214.             if (!PR_SetLogFile(ev)) {
  215. #ifdef XP_PC
  216.                 char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev);
  217.                 if (str) {
  218.                     OutputDebugString(str);
  219.                     PR_smprintf_free(str);
  220.                 }
  221. #else
  222.                 fprintf(stderr, "Unable to create nspr log file '%s'\n", ev);
  223. #endif
  224.             }
  225.         } else {
  226. #ifdef _PR_USE_STDIO_FOR_LOGGING
  227.             logFile = stderr;
  228. #else
  229.             logFile = _pr_stderr;
  230. #endif
  231.         }
  232.     }
  233. }
  234.  
  235. void _PR_LogCleanup(void)
  236. {
  237.     PR_LogFlush();
  238.  
  239. #ifdef _PR_USE_STDIO_FOR_LOGGING
  240.     if (logFile && logFile != stdout && logFile != stderr) {
  241.         fclose(logFile);
  242.     }
  243. #else
  244.     if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
  245.         PR_Close(logFile);
  246.     }
  247. #endif
  248. }
  249.  
  250. #endif /* PR_LOGGING */
  251.  
  252. PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name)
  253. {
  254.     PRLogModuleInfo *lm;
  255.  
  256.         if (!_pr_initialized) _PR_ImplicitInitialization();
  257.  
  258.     lm = PR_NEWZAP(PRLogModuleInfo);
  259.     if (lm) {
  260.         lm->name = strdup(name);
  261.         lm->level = PR_LOG_NONE;
  262.         lm->next = logModules;
  263.         logModules = lm;
  264.     }
  265.     return lm;
  266. }
  267.  
  268. PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
  269. {
  270. #ifdef PR_LOGGING
  271. #ifdef _PR_USE_STDIO_FOR_LOGGING
  272.     FILE *newLogFile;
  273.  
  274.     newLogFile = fopen(file, "w");
  275.     if (newLogFile) {
  276.         /* We do buffering ourselves. */
  277.         setvbuf(newLogFile, NULL, _IONBF, 0);
  278.         if (logFile && logFile != stdout && logFile != stderr) {
  279.             fclose(logFile);
  280.         }
  281.         logFile = newLogFile;
  282.     }
  283.     return (PRBool) (newLogFile != 0);
  284. #else
  285.     PRFileDesc *newLogFile;
  286.  
  287.     newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE, 0666);
  288.     if (newLogFile) {
  289.         if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
  290.             PR_Close(logFile);
  291.         }
  292.         logFile = newLogFile;
  293. #if defined(XP_MAC)
  294.         SetLogFileTypeCreator(file);
  295. #endif
  296.     }
  297.     return (PRBool) (newLogFile != 0);
  298. #endif /* _PR_USE_STDIO_FOR_LOGGING */
  299. #else /* PR_LOGGING */
  300.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  301.     return PR_FALSE;
  302. #endif /* PR_LOGGING */
  303. }
  304.  
  305. PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size)
  306. {
  307. #ifdef PR_LOGGING
  308.     PR_LogFlush();
  309.  
  310.     if (logBuf)
  311.         PR_DELETE(logBuf);
  312.     logBuf = 0;
  313.  
  314.     if (buffer_size >= LINE_BUF_SIZE) {
  315.         logp = logBuf = (char*) PR_MALLOC(buffer_size);
  316.         logEndp = logp + buffer_size;
  317.     }
  318. #endif /* PR_LOGGING */
  319. }
  320.  
  321. PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...)
  322. {
  323. #ifdef PR_LOGGING
  324.     va_list ap;
  325.     char line[LINE_BUF_SIZE];
  326.     PRUint32 nb;
  327.     PRThread *me;
  328.  
  329.     if (!_pr_initialized) _PR_ImplicitInitialization();
  330.  
  331.     if (!logFile) {
  332.         return;
  333.     }
  334.  
  335.     va_start(ap, fmt);
  336.     me = PR_GetCurrentThread();
  337.     nb = PR_snprintf(line, sizeof(line)-1, "%ld[%p]: ",
  338. #if defined(_PR_DCETHREADS)
  339.              /* The problem is that for _PR_DCETHREADS, pthread_t is not a 
  340.               * pointer, but a structure; so you can't easily print it...
  341.               */
  342.                      me ? &(me->id): 0L, me);
  343. #else
  344.                      me ? me->id : 0L, me);
  345. #endif
  346.  
  347.     nb += PR_vsnprintf(line+nb, sizeof(line)-nb-1, fmt, ap);
  348.     if (nb && (line[nb-1] != '\n')) {
  349. #ifndef XP_MAC
  350.         line[nb++] = '\n';
  351. #else
  352.         line[nb++] = '\015';
  353. #endif 
  354.         line[nb] = '\0';
  355.     } else {
  356. #ifdef XP_MAC
  357.         line[nb-1] = '\015';
  358. #endif
  359.     }
  360.     va_end(ap);
  361.  
  362.     _PR_LOCK_LOG();
  363.     if (logBuf == 0) {
  364.         _PUT_LOG(logFile, line, nb);
  365.     } else {
  366.         if (logp + nb > logEndp) {
  367.             _PUT_LOG(logFile, logBuf, logp - logBuf);
  368.             logp = logBuf;
  369.         }
  370.         memcpy(logp, line, nb);
  371.         logp += nb;
  372.     }
  373.     _PR_UNLOCK_LOG();
  374.     PR_LogFlush();
  375. #endif /* PR_LOGGING */
  376. }
  377.  
  378. PR_IMPLEMENT(void) PR_LogFlush(void)
  379. {
  380. #ifdef PR_LOGGING
  381.     if (logBuf && logFile) {
  382.         _PR_LOCK_LOG();
  383.             if (logp > logBuf) {
  384.                 _PUT_LOG(logFile, logBuf, logp - logBuf);
  385.                 logp = logBuf;
  386.             }
  387.         _PR_UNLOCK_LOG();
  388.     }
  389. #endif /* PR_LOGGING */
  390. }
  391.  
  392. PR_IMPLEMENT(void) PR_Abort(void)
  393. {
  394. #ifdef PR_LOGGING
  395.     PR_LogPrint("Aborting");
  396.     abort();
  397. #endif /* PR_LOGGING */
  398.         PR_ASSERT(1);
  399. }
  400.  
  401. PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
  402. {
  403. #ifdef PR_LOGGING
  404.     PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
  405. #if defined(XP_UNIX) || defined(XP_OS2)
  406.     fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
  407. #endif
  408. #ifdef XP_MAC
  409.     dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln);
  410. #endif
  411. #ifdef WIN32
  412.     DebugBreak();
  413. #endif
  414. #ifndef XP_MAC
  415.     abort();
  416. #endif
  417. #endif /* PR_LOGGING */
  418. }
  419.