diff nspr/pr/src/io/prlog.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nspr/pr/src/io/prlog.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "primpl.h"
+#include "prenv.h"
+#include "prprf.h"
+#include <string.h>
+#ifdef ANDROID
+#include <android/log.h>
+#endif
+
+/*
+ * Lock used to lock the log.
+ *
+ * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
+ * contain assertions.  We have to avoid assertions in _PR_LOCK_LOG
+ * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
+ * This can lead to infinite recursion.
+ */
+static PRLock *_pr_logLock;
+#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
+#define _PR_LOCK_LOG() PR_Lock(_pr_logLock);
+#define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock);
+#elif defined(_PR_GLOBAL_THREADS_ONLY)
+#define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
+#define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
+#else
+
+#define _PR_LOCK_LOG() \
+{ \
+    PRIntn _is; \
+    PRThread *_me = _PR_MD_CURRENT_THREAD(); \
+    if (!_PR_IS_NATIVE_THREAD(_me)) \
+        _PR_INTSOFF(_is); \
+    _PR_LOCK_LOCK(_pr_logLock)
+
+#define _PR_UNLOCK_LOG() \
+    _PR_LOCK_UNLOCK(_pr_logLock); \
+    PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
+    if (!_PR_IS_NATIVE_THREAD(_me)) \
+        _PR_INTSON(_is); \
+}
+
+#endif
+
+#if defined(XP_PC)
+#define strcasecmp stricmp
+#endif
+
+/*
+ * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
+ * because every asynchronous file io operation leads to a fiber context
+ * switch.  So we define _PUT_LOG as fputs (from stdio.h).  A side
+ * benefit is that fputs handles the LF->CRLF translation.  This
+ * code can also be used on other platforms with file stream io.
+ */
+#if defined(WIN32) || defined(XP_OS2)
+#define _PR_USE_STDIO_FOR_LOGGING
+#endif
+
+/*
+** Coerce Win32 log output to use OutputDebugString() when
+** NSPR_LOG_FILE is set to "WinDebug".
+*/
+#if defined(XP_PC)
+#define WIN32_DEBUG_FILE (FILE*)-2
+#endif
+
+#ifdef WINCE
+static void OutputDebugStringA(const char* msg) {
+    int len = MultiByteToWideChar(CP_ACP, 0, msg, -1, 0, 0);
+    WCHAR *wMsg = (WCHAR *)PR_Malloc(len * sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, msg, -1, wMsg, len);
+    OutputDebugStringW(wMsg);
+    PR_Free(wMsg);
+}
+#endif
+
+/* Macros used to reduce #ifdef pollution */
+
+#if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC)
+#define _PUT_LOG(fd, buf, nb) \
+    PR_BEGIN_MACRO \
+    if (logFile == WIN32_DEBUG_FILE) { \
+        char savebyte = buf[nb]; \
+        buf[nb] = '\0'; \
+        OutputDebugStringA(buf); \
+        buf[nb] = savebyte; \
+    } else { \
+        fwrite(buf, 1, nb, fd); \
+        fflush(fd); \
+    } \
+    PR_END_MACRO
+#elif defined(_PR_USE_STDIO_FOR_LOGGING)
+#define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);}
+#elif defined(ANDROID)
+#define _PUT_LOG(fd, buf, nb)                                \
+    PR_BEGIN_MACRO                                           \
+    if (fd == _pr_stderr) {                                  \
+        char savebyte = buf[nb];                             \
+        buf[nb] = '\0';                                      \
+        __android_log_write(ANDROID_LOG_INFO, "PRLog", buf); \
+        buf[nb] = savebyte;                                  \
+    } else {                                                 \
+        PR_Write(fd, buf, nb);                               \
+    }                                                        \
+    PR_END_MACRO
+#elif defined(_PR_PTHREADS)
+#define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
+#else
+#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
+#endif
+
+/************************************************************************/
+
+static PRLogModuleInfo *logModules;
+
+static char *logBuf = NULL;
+static char *logp;
+static char *logEndp;
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+static FILE *logFile = NULL;
+#else
+static PRFileDesc *logFile = 0;
+#endif
+static PRBool outputTimeStamp = PR_FALSE;
+static PRBool appendToLog = PR_FALSE;
+
+#define LINE_BUF_SIZE           512
+#define DEFAULT_BUF_SIZE        16384
+
+#ifdef _PR_NEED_STRCASECMP
+
+/*
+ * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
+ * such as NCR and Unixware.  Linking with both libc and libucb
+ * may cause some problem, so I just provide our own implementation
+ * of strcasecmp here.
+ */
+
+static const unsigned char uc[] =
+{
+    '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+    '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+    '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+    '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+    ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
+    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
+    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
+};
+
+PRIntn strcasecmp(const char *a, const char *b)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+    }
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
+
+#endif /* _PR_NEED_STRCASECMP */
+
+void _PR_InitLog(void)
+{
+    char *ev;
+
+    _pr_logLock = PR_NewLock();
+
+    ev = PR_GetEnv("NSPR_LOG_MODULES");
+    if (ev && ev[0]) {
+        char module[64];  /* Security-Critical: If you change this
+                           * size, you must also change the sscanf
+                           * format string to be size-1.
+                           */
+        PRBool isSync = PR_FALSE;
+        PRIntn evlen = strlen(ev), pos = 0;
+        PRInt32 bufSize = DEFAULT_BUF_SIZE;
+        while (pos < evlen) {
+            PRIntn level = 1, count = 0, delta = 0;
+            count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
+                           module, &delta, &level, &delta);
+            pos += delta;
+            if (count == 0) break;
+
+            /*
+            ** If count == 2, then we got module and level. If count
+            ** == 1, then level defaults to 1 (module enabled).
+            */
+            if (strcasecmp(module, "sync") == 0) {
+                isSync = PR_TRUE;
+            } else if (strcasecmp(module, "bufsize") == 0) {
+                if (level >= LINE_BUF_SIZE) {
+                    bufSize = level;
+                }
+            } else if (strcasecmp(module, "timestamp") == 0) {
+                outputTimeStamp = PR_TRUE;
+            } else if (strcasecmp(module, "append") == 0) {
+                appendToLog = PR_TRUE;
+            } else {
+                PRLogModuleInfo *lm = logModules;
+                PRBool skip_modcheck =
+                    (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE;
+
+                while (lm != NULL) {
+                    if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
+                    else if (strcasecmp(module, lm->name) == 0) {
+                        lm->level = (PRLogModuleLevel)level;
+                        break;
+                    }
+                    lm = lm->next;
+                }
+            }
+            /*found:*/
+            count = sscanf(&ev[pos], " , %n", &delta);
+            pos += delta;
+            if (count == EOF) break;
+        }
+        PR_SetLogBuffering(isSync ? 0 : bufSize);
+
+#ifdef XP_UNIX
+        if ((getuid() != geteuid()) || (getgid() != getegid())) {
+            return;
+        }
+#endif /* XP_UNIX */
+
+        ev = PR_GetEnv("NSPR_LOG_FILE");
+        if (ev && ev[0]) {
+            if (!PR_SetLogFile(ev)) {
+#ifdef XP_PC
+                char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev);
+                if (str) {
+                    OutputDebugStringA(str);
+                    PR_smprintf_free(str);
+                }
+#else
+                fprintf(stderr, "Unable to create nspr log file '%s'\n", ev);
+#endif
+            }
+        } else {
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+            logFile = stderr;
+#else
+            logFile = _pr_stderr;
+#endif
+        }
+    }
+}
+
+void _PR_LogCleanup(void)
+{
+    PRLogModuleInfo *lm = logModules;
+
+    PR_LogFlush();
+
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+    if (logFile
+        && logFile != stdout
+        && logFile != stderr
+#ifdef XP_PC
+        && logFile != WIN32_DEBUG_FILE
+#endif
+        ) {
+        fclose(logFile);
+    }
+#else
+    if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+        PR_Close(logFile);
+    }
+#endif
+    logFile = NULL;
+
+    if (logBuf)
+        PR_DELETE(logBuf);
+
+    while (lm != NULL) {
+        PRLogModuleInfo *next = lm->next;
+        free((/*const*/ char *)lm->name);
+        PR_Free(lm);
+        lm = next;
+    }
+    logModules = NULL;
+
+    if (_pr_logLock) {
+        PR_DestroyLock(_pr_logLock);
+        _pr_logLock = NULL;
+    }
+}
+
+static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
+{
+    char *ev;
+
+    ev = PR_GetEnv("NSPR_LOG_MODULES");
+    if (ev && ev[0]) {
+        char module[64];  /* Security-Critical: If you change this
+                           * size, you must also change the sscanf
+                           * format string to be size-1.
+                           */
+        PRIntn evlen = strlen(ev), pos = 0;
+        while (pos < evlen) {
+            PRIntn level = 1, count = 0, delta = 0;
+
+            count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
+                           module, &delta, &level, &delta);
+            pos += delta;
+            if (count == 0) break;
+
+            /*
+            ** If count == 2, then we got module and level. If count
+            ** == 1, then level defaults to 1 (module enabled).
+            */
+            if (lm != NULL)
+            {
+                if ((strcasecmp(module, "all") == 0)
+                    || (strcasecmp(module, lm->name) == 0))
+                {
+                    lm->level = (PRLogModuleLevel)level;
+                }
+            }
+            count = sscanf(&ev[pos], " , %n", &delta);
+            pos += delta;
+            if (count == EOF) break;
+        }
+    }
+} /* end _PR_SetLogModuleLevel() */
+
+PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name)
+{
+    PRLogModuleInfo *lm;
+
+        if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    lm = PR_NEWZAP(PRLogModuleInfo);
+    if (lm) {
+        lm->name = strdup(name);
+        lm->level = PR_LOG_NONE;
+        lm->next = logModules;
+        logModules = lm;
+        _PR_SetLogModuleLevel(lm);
+    }
+    return lm;
+}
+
+PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
+{
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+    FILE *newLogFile;
+
+#ifdef XP_PC
+    if ( strcmp( file, "WinDebug") == 0)
+    {
+        newLogFile = WIN32_DEBUG_FILE;
+    }
+    else
+#endif
+    {
+        const char *mode = appendToLog ? "a" : "w";
+        newLogFile = fopen(file, mode);
+        if (!newLogFile)
+            return PR_FALSE;
+
+#ifndef WINCE  /* _IONBF does not exist in the Windows Mobile 6 SDK. */
+        /* We do buffering ourselves. */
+        setvbuf(newLogFile, NULL, _IONBF, 0);
+#endif
+    }
+    if (logFile
+        && logFile != stdout
+        && logFile != stderr
+#ifdef XP_PC
+        && logFile != WIN32_DEBUG_FILE
+#endif
+        ) {
+        fclose(logFile);
+    }
+    logFile = newLogFile;
+    return PR_TRUE;
+#else
+    PRFileDesc *newLogFile;
+    PRIntn flags = PR_WRONLY|PR_CREATE_FILE;
+    if (appendToLog) {
+        flags |= PR_APPEND;
+    } else {
+        flags |= PR_TRUNCATE;
+    }
+
+    newLogFile = PR_Open(file, flags, 0666);
+    if (newLogFile) {
+        if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+            PR_Close(logFile);
+        }
+        logFile = newLogFile;
+    }
+    return (PRBool) (newLogFile != 0);
+#endif /* _PR_USE_STDIO_FOR_LOGGING */
+}
+
+PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size)
+{
+    PR_LogFlush();
+
+    if (logBuf)
+        PR_DELETE(logBuf);
+
+    if (buffer_size >= LINE_BUF_SIZE) {
+        logp = logBuf = (char*) PR_MALLOC(buffer_size);
+        logEndp = logp + buffer_size;
+    }
+}
+
+PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...)
+{
+    va_list ap;
+    char line[LINE_BUF_SIZE];
+    char *line_long = NULL;
+    PRUint32 nb_tid = 0, nb;
+    PRThread *me;
+    PRExplodedTime now;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (!logFile) {
+        return;
+    }
+
+    if (outputTimeStamp) {
+        PR_ExplodeTime(PR_Now(), PR_GMTParameters, &now);
+        nb_tid = PR_snprintf(line, sizeof(line)-1,
+                             "%04d-%02d-%02d %02d:%02d:%02d.%06d UTC - ",
+                             now.tm_year, now.tm_month + 1, now.tm_mday,
+                             now.tm_hour, now.tm_min, now.tm_sec,
+                             now.tm_usec);
+    }
+
+    me = PR_GetCurrentThread();
+    nb_tid += PR_snprintf(line+nb_tid, sizeof(line)-nb_tid-1, "%ld[%p]: ",
+#if defined(_PR_BTHREADS)
+                          me, me);
+#else
+                          me ? me->id : 0L, me);
+#endif
+
+    va_start(ap, fmt);
+    nb = nb_tid + PR_vsnprintf(line+nb_tid, sizeof(line)-nb_tid-1, fmt, ap);
+    va_end(ap);
+
+    /*
+     * Check if we might have run out of buffer space (in case we have a
+     * long line), and malloc a buffer just this once.
+     */
+    if (nb == sizeof(line)-2) {
+        va_start(ap, fmt);
+        line_long = PR_vsmprintf(fmt, ap);
+        va_end(ap);
+        /* If this failed, we'll fall back to writing the truncated line. */
+    }
+
+    if (line_long) {
+        nb = strlen(line_long);
+        _PR_LOCK_LOG();
+        if (logBuf != 0) {
+            _PUT_LOG(logFile, logBuf, logp - logBuf);
+            logp = logBuf;
+        }
+        /*
+         * Write out the thread id (with an optional timestamp) and the
+         * malloc'ed buffer.
+         */
+        _PUT_LOG(logFile, line, nb_tid);
+        _PUT_LOG(logFile, line_long, nb);
+        /* Ensure there is a trailing newline. */
+        if (!nb || (line_long[nb-1] != '\n')) {
+            char eol[2];
+            eol[0] = '\n';
+            eol[1] = '\0';
+            _PUT_LOG(logFile, eol, 1);
+        }
+        _PR_UNLOCK_LOG();
+        PR_smprintf_free(line_long);
+    } else {
+        /* Ensure there is a trailing newline. */
+        if (nb && (line[nb-1] != '\n')) {
+            line[nb++] = '\n';
+            line[nb] = '\0';
+        }
+        _PR_LOCK_LOG();
+        if (logBuf == 0) {
+            _PUT_LOG(logFile, line, nb);
+        } else {
+            /* If nb can't fit into logBuf, write out logBuf first. */
+            if (logp + nb > logEndp) {
+                _PUT_LOG(logFile, logBuf, logp - logBuf);
+                logp = logBuf;
+            }
+            /* nb is guaranteed to fit into logBuf. */
+            memcpy(logp, line, nb);
+            logp += nb;
+        }
+        _PR_UNLOCK_LOG();
+    }
+    PR_LogFlush();
+}
+
+PR_IMPLEMENT(void) PR_LogFlush(void)
+{
+    if (logBuf && logFile) {
+        _PR_LOCK_LOG();
+            if (logp > logBuf) {
+                _PUT_LOG(logFile, logBuf, logp - logBuf);
+                logp = logBuf;
+            }
+        _PR_UNLOCK_LOG();
+    }
+}
+
+PR_IMPLEMENT(void) PR_Abort(void)
+{
+    PR_LogPrint("Aborting");
+    abort();
+}
+
+PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
+{
+    PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
+    fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
+    fflush(stderr);
+#ifdef WIN32
+    DebugBreak();
+#endif
+#ifdef XP_OS2
+    asm("int $3");
+#endif
+    abort();
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)