include/sal/log.hxx           |   95 ++++++++---
 sal/inc/backtraceasstring.hxx |   14 +
 sal/osl/all/log.cxx           |  358 +++++++++++++++++++++++++++++-------------
 sal/osl/all/logformat.hxx     |   29 ---
 sal/osl/unx/backtraceapi.cxx  |   54 +++++-
 sal/osl/w32/backtrace.cxx     |   29 ++-
 sal/util/sal.map              |    5 
 7 files changed, 399 insertions(+), 185 deletions(-)

New commits:
commit 0360f89f686c430de5fc5f1582692e580f0fd0f9
Author: Thorsten Behrens <thorsten.behr...@cib.de>
Date:   Thu Aug 18 14:07:00 2016 +0300

    Backport SAL_LOG handling & logging.ini feature
    
    This includes:
    
    Add handling of a +TIMESTAMP flag in the SAL_LOG environment variable
    
    No need for nested unnamed namespaces
    
    Add handling of a +RELATIVETIMER flag in the SAL_LOG environment variable
    
    If no WARN in SAL_LOG, use the INFO selection for WARNs, too
    
    sal::detail::logFormat is no longer needed
    
    add an option to pipe log output to file
    
    tdf#91872: Make SAL_INFO and friends more efficient
    
    Clean up C-style interface nonsense
    
    Fold sal_detail_log_backtrace into sal_detail_log
    
    Some clean up
    
    WNT: allow to set log level/path from file
    
    sal: use snprintf for sal log
    
    coverity#1427647 acknowledge Resource leak is deliberate
    
    loplugin:nullptr (clang-cl)
    
    Make SAL_LOG_FILE work on Windows also without logging.ini
    
    sal: log windows trace output to debugger console
    
    Change-Id: I47dd00144273306ec1acaa9c88a1bf4a89ef8079
    sal: log windows traces to debugger console, take two

diff --git a/include/sal/log.hxx b/include/sal/log.hxx
index e01d70870042..c3f5fb05a071 100644
--- a/include/sal/log.hxx
+++ b/include/sal/log.hxx
@@ -27,14 +27,17 @@
 /// @cond INTERNAL
 
 extern "C" SAL_DLLPUBLIC void SAL_CALL sal_detail_log(
-    enum sal_detail_LogLevel level, char const * area, char const * where,
-    char const * message);
+    sal_detail_LogLevel level, char const * area, char const * where,
+    char const * message, sal_uInt32 backtraceDepth);
+
+extern "C" SAL_DLLPUBLIC sal_Bool SAL_CALL sal_detail_log_report(
+    sal_detail_LogLevel level, char const * area);
 
 namespace sal { namespace detail {
 
-inline void SAL_CALL log(
+inline void log(
     sal_detail_LogLevel level, char const * area, char const * where,
-    std::ostringstream const & stream)
+    std::ostringstream const & stream, sal_uInt32 backtraceDepth)
 {
     // An alternative would be to have sal_detail_log take a std::ostringstream
     // pointer (via a C void pointer); the advantage would be smaller client
@@ -44,7 +47,7 @@ inline void SAL_CALL log(
     // on the C++ ABI; as a compromise, the ".str().c_str()" part has been 
moved
     // to this inline function so that it is potentially only emitted once per
     // dynamic library:
-    sal_detail_log(level, area, where, stream.str().c_str());
+    sal_detail_log(level, area, where, stream.str().c_str(), backtraceDepth);
 }
 
 // Special handling of the common case where the message consists of just a
@@ -112,19 +115,20 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER 
StreamIgnore const &) {
 
 #define SAL_DETAIL_LOG_STREAM(condition, level, area, where, stream) \
     do { \
-        if (condition) { \
+        if ((condition) && sal_detail_log_report(level, area)) { \
             if (sizeof ::sal::detail::getResult( \
                     ::sal::detail::StreamStart() << stream) == 1) \
             { \
                 ::sal_detail_log( \
                     (level), (area), (where), \
                     ::sal::detail::unwrapStream( \
-                        ::sal::detail::StreamStart() << stream)); \
+                        ::sal::detail::StreamStart() << stream), \
+                    0); \
             } else { \
                 ::std::ostringstream sal_detail_stream; \
                 sal_detail_stream << stream; \
                 ::sal::detail::log( \
-                    (level), (area), (where), sal_detail_stream); \
+                    (level), (area), (where), sal_detail_stream, 0); \
             } \
         } \
     } while (false)
@@ -228,15 +232,31 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER 
StreamIgnore const &) {
     with
 
     @verbatim
-      <switch> ::= <sense><level>("."<area>)?
+      <switch> ::= <sense><item>
       <sense> ::= "+"|"-"
+      <item> ::= <flag>|<level>("."<area>)?
+      <flag> ::= "TIMESTAMP"|"RELATIVETIMER"
       <level> ::= "INFO"|"WARN"
     @endverbatim
 
-    If the environment variable is unset, "+WARN" is used instead (which 
results
-    in all warnings being output but no infos).  If the given value does not
-    match the regular expression, "+INFO+WARN" is used instead (which in turn
-    results in everything being output).
+    If the environment variable is unset, the setting "+WARN" is
+    assumed instead (which results in all warnings being output but no
+    infos).  If the given value does not match the regular expression,
+    "+INFO+WARN" is used instead (which in turn results in everything
+    being output).
+
+    The "+TIMESTAMP" flag causes each output line (as selected by the level
+    switch(es)) to be prefixed by a timestamp like 2016-08-18:14:04:43.
+
+    The "+RELATIVETIMER" flag causes each output line (as selected by
+    the level switch(es)) to be prefixed by a relative timestamp in
+    seconds since the first output line like 1.312.
+
+    If both +TIMESTAMP and +RELATIVETIMER are specified, they are
+    output in that order.
+
+    Specifying a flag with a negative sense has no effect. Specifying
+    the same flag multiple times has no extra effect.
 
     A given macro call's level (INFO or WARN) and area is matched against the
     given switches as follows:  Only those switches for which the level matches
@@ -246,17 +266,20 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER 
StreamIgnore const &) {
     that has a sense of "+".  (That is, if both +INFO.foo and -INFO.foo are
     present, +INFO.foo wins.)
 
+    If no WARN selection is specified, but an INFO selection is, the
+    INFO selection is used for WARN messages, too.
+
     For example, if SAL_LOG is "+INFO-INFO.foo+INFO.foo.bar", then calls like
     SAL_INFO("foo.bar", ...), SAL_INFO("foo.bar.baz", ...), or
     SAL_INFO("other", ...) generate output, while calls like
     SAL_INFO("foo", ...) or SAL_INFO("foo.barzzz", ...) do not.
 
-    The generated log output consists of the given level ("info" or "warn"), 
the
-    given area, the process ID, the thread ID, the source file, and the source
-    line number, each followed by a colon, followed by a space, the given
-    message, and a newline.  The precise format of the log output is subject to
-    change.  The log output is printed to stderr without further text encoding
-    conversion.
+    The generated log output consists of the optinal timestamp, the given level
+    ("info" or "warn"), the given area, the process ID, the thread ID, the
+    source file, and the source line number, each followed by a colon, followed
+    by a space, the given message, and a newline.  The precise format of the 
log
+    output is subject to change.  The log output is printed to stderr without
+    further text encoding conversion.
 
     @see @ref sal_log_areas
 
@@ -317,16 +340,36 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER 
StreamIgnore const &) {
         SAL_LOG_TRUE, ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, stream)
 
 /**
-  Produce temporary debugging output from stream along with a
-  stack trace of the calling location.  This macro is meant to
-  be used only while working on code and should never exist
-  in production code.
+  Produce temporary debugging output from stream along with a backtrace of the
+  calling location.
+
+  This macro is meant to be used only while working on code and should never
+  exist in production code.
+
+  @param backtraceDepth a sal_uInt32 value indicating the maximum backtrace
+  depth; zero means no backtrace
 
   See @ref sal_log "basic logging functionality" for details.
 */
-#define SAL_DEBUG_TRACE(stream) \
-    SAL_DETAIL_LOG_STREAM( \
-        SAL_LOG_TRUE, ::SAL_DETAIL_LOG_LEVEL_DEBUG_TRACE, NULL, NULL, stream)
+#define SAL_DEBUG_BACKTRACE(stream, backtraceDepth) \
+    do { \
+        if (sizeof ::sal::detail::getResult( \
+                ::sal::detail::StreamStart() << stream) == 1) \
+        { \
+            ::sal_detail_log( \
+                ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, \
+                ::sal::detail::unwrapStream( \
+                    ::sal::detail::StreamStart() << stream), \
+                backtraceDepth); \
+        } else { \
+            ::std::ostringstream sal_detail_stream; \
+            sal_detail_stream << stream; \
+            ::sal::detail::log( \
+                ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, sal_detail_stream, \
+                backtraceDepth); \
+        } \
+    } while (false)
+
 
 #endif
 
diff --git a/sal/inc/misc.hxx b/sal/inc/backtraceasstring.hxx
similarity index 66%
rename from sal/inc/misc.hxx
rename to sal/inc/backtraceasstring.hxx
index b93868e1baab..cd9ce494f789 100644
--- a/sal/inc/misc.hxx
+++ b/sal/inc/backtraceasstring.hxx
@@ -6,13 +6,21 @@
  * 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/.
  */
-#ifndef INCLUDED_SAL_INC_INTERNAL_MISC_H
-#define INCLUDED_SAL_INC_INTERNAL_MISC_H
+
+#ifndef INCLUDED_SAL_INC_BACKTRACEASSTRING_HXX
+#define INCLUDED_SAL_INC_BACKTRACEASSTRING_HXX
+
+#include <sal/config.h>
 
 #include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace osl { namespace detail {
 
 /// Build a debugging backtrace from current PC location.
-rtl_uString *osl_backtraceAsString(void);
+OUString backtraceAsString(sal_uInt32 maxDepth);
+
+} }
 
 #endif // INCLUDED_SAL_INC_INTERNAL_MISC_H
 
diff --git a/sal/osl/all/log.cxx b/sal/osl/all/log.cxx
index 9c75393bd327..4d60536f71dd 100644
--- a/sal/osl/all/log.cxx
+++ b/sal/osl/all/log.cxx
@@ -19,20 +19,21 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <fstream>
 
+#include <config_global.h>
 #include "osl/thread.hxx"
 #include "rtl/string.h"
 #include "sal/detail/log.h"
 #include "sal/log.hxx"
 #include "sal/types.h"
-#include "misc.hxx"
-
-#include "logformat.hxx"
+#include "backtraceasstring.hxx"
 
 #if defined ANDROID
 #include <android/log.h>
 #elif defined WNT
 #include <process.h>
+#include <windows.h>
 #define OSL_DETAIL_GETPID _getpid()
 #else
 #include <unistd.h>
@@ -82,14 +83,14 @@ char const * toString(sal_detail_LogLevel level) {
 // the process is running":
 #if defined ANDROID
 
-char const * getEnvironmentVariable() {
+char const * getLogLevel() {
     return std::getenv("SAL_LOG");
 }
 
 #else
 
-char const * getEnvironmentVariable_() {
-    char const * p1 = std::getenv("SAL_LOG");
+char const * getEnvironmentVariable(const char* env) {
+    char const * p1 = std::getenv(env);
     if (p1 == nullptr) {
         return nullptr;
     }
@@ -100,107 +101,174 @@ char const * getEnvironmentVariable_() {
     return p2;
 }
 
-char const * getEnvironmentVariable() {
-    static char const * env = getEnvironmentVariable_();
-    return env;
+#ifdef WNT
+# define INI_STRINGBUF_SIZE 1024
+
+bool getValueFromLoggingIniFile(const char* key, char* value) {
+    char buffer[MAX_PATH];
+    GetModuleFileName(nullptr, buffer, MAX_PATH);
+    std::string sProgramDirectory = std::string(buffer);
+    std::string::size_type pos = sProgramDirectory.find_last_of( "\\/" );
+    sProgramDirectory = sProgramDirectory.substr(0, pos+1);
+    sProgramDirectory += "logging.ini";
+
+    std::ifstream logFileStream(sProgramDirectory);
+    if (!logFileStream.good())
+        return false;
+
+    std::size_t n;
+    std::string aKey;
+    std::string aValue;
+    std::string sWantedKey(key);
+    std::string sLine;
+    while (std::getline(logFileStream, sLine)) {
+        if (sLine.find('#') == 0)
+            continue;
+        if ( ( n = sLine.find('=') ) != std::string::npos) {
+            aKey = sLine.substr(0, n);
+            if (aKey != sWantedKey)
+                continue;
+            aValue = sLine.substr(n+1, sLine.length());
+            snprintf(value, INI_STRINGBUF_SIZE, "%s", aValue.c_str());
+            return true;
+        }
+    }
+    return false;
 }
+#endif
+
+char const * getLogLevel() {
+    // First check the environment variable, then the setting in logging.ini
+    static char const * env = getEnvironmentVariable("SAL_LOG");
 
+    if (env != nullptr)
+        return env;
+
+#ifdef WNT
+    static char logLevel[INI_STRINGBUF_SIZE];
+    if (getValueFromLoggingIniFile("LogLevel", logLevel))
+        return logLevel;
 #endif
 
-namespace {
-    inline bool isDebug(sal_detail_LogLevel level) {
-        return level == SAL_DETAIL_LOG_LEVEL_DEBUG ||
-               level == SAL_DETAIL_LOG_LEVEL_DEBUG_TRACE;
-    }
+    return nullptr;
 }
 
-bool report(sal_detail_LogLevel level, char const * area) {
-    if (isDebug(level))
-        return true;
-    assert(area != nullptr);
-    char const * env = getEnvironmentVariable();
-    if (env == nullptr) {
-        env = "+WARN";
-    }
-    std::size_t areaLen = std::strlen(area);
-    enum Sense { POSITIVE = 0, NEGATIVE = 1 };
-    std::size_t senseLen[2] = { 0, 1 };
-        // initial senseLen[POSITIVE] < senseLen[NEGATIVE], so that if there 
are
-        // no matching switches at all, the result will be negative (and
-        // initializing with 1 is safe as the length of a valid switch, even
-        // without the "+"/"-" prefix, will always be > 1)
+std::ofstream * getLogFile() {
+    // First check the environment variable, then the setting in logging.ini
+    static char const * logFile = getEnvironmentVariable("SAL_LOG_FILE");
+    if (!logFile)
+        return nullptr;
+
+#ifdef WNT
+    static char logFilePath[INI_STRINGBUF_SIZE];
+    if (getValueFromLoggingIniFile("LogFilePath", logFilePath))
+        logFile = logFilePath;
+#endif
+
+    // stays until process exits
+    static std::ofstream file(logFile, std::ios::app | std::ios::out);
+
+    return &file;
+}
+
+void maybeOutputTimestamp(std::ostringstream &s) {
+    static char const * env = getLogLevel();
+    if (env == nullptr)
+        return;
+    bool outputTimestamp = false;
+    bool outputRelativeTimer = false;
     for (char const * p = env;;) {
-        Sense sense;
         switch (*p++) {
         case '\0':
-            return senseLen[POSITIVE] >= senseLen[NEGATIVE];
-                // if a specific item is both positive and negative
-                // (senseLen[POSITIVE] == senseLen[NEGATIVE]), default to
-                // positive
+            if (outputTimestamp) {
+                char ts[100];
+                TimeValue systemTime;
+                osl_getSystemTime(&systemTime);
+                TimeValue localTime;
+                osl_getLocalTimeFromSystemTime(&systemTime, &localTime);
+                oslDateTime dateTime;
+                osl_getDateTimeFromTimeValue(&localTime, &dateTime);
+                struct tm tm;
+                tm.tm_sec = dateTime.Seconds;
+                tm.tm_min = dateTime.Minutes;
+                tm.tm_hour = dateTime.Hours;
+                tm.tm_mday = dateTime.Day;
+                tm.tm_mon = dateTime.Month - 1;
+                tm.tm_year = dateTime.Year - 1900;
+                strftime(ts, sizeof(ts), "%Y-%m-%d:%H:%M:%S", &tm);
+                char milliSecs[11];
+                snprintf(milliSecs, sizeof(milliSecs), "%03u", 
static_cast<unsigned>(dateTime.NanoSeconds/1000000));
+                s << ts << '.' << milliSecs << ':';
+            }
+            if (outputRelativeTimer) {
+                static bool beenHere = false;
+                static TimeValue first;
+                if (!beenHere) {
+                    osl_getSystemTime(&first);
+                    beenHere = true;
+                }
+                TimeValue now;
+                osl_getSystemTime(&now);
+                int seconds = now.Seconds - first.Seconds;
+                int milliSeconds;
+                if (now.Nanosec < first.Nanosec) {
+                    seconds--;
+                    milliSeconds = 1000-(first.Nanosec-now.Nanosec)/1000000;
+                }
+                else
+                    milliSeconds = (now.Nanosec-first.Nanosec)/1000000;
+                char relativeTimestamp[100];
+                snprintf(relativeTimestamp, sizeof(relativeTimestamp), 
"%d.%03d", seconds, milliSeconds);
+                s << relativeTimestamp << ':';
+            }
+            return;
         case '+':
-            sense = POSITIVE;
-            break;
-        case '-':
-            sense = NEGATIVE;
-            break;
-        default:
-            return true; // upon an illegal SAL_LOG value, enable everything
-        }
-        char const * p1 = p;
-        while (*p1 != '.' && *p1 != '+' && *p1 != '-' && *p1 != '\0') {
-            ++p1;
-        }
-        bool match;
-        if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("INFO"))) {
-            match = level == SAL_DETAIL_LOG_LEVEL_INFO;
-        } else if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("WARN")))
-        {
-            match = level == SAL_DETAIL_LOG_LEVEL_WARN;
-        } else {
-            return true;
-                // upon an illegal SAL_LOG value, everything is considered
-                // positive
-        }
-        char const * p2 = p1;
-        while (*p2 != '+' && *p2 != '-' && *p2 != '\0') {
-            ++p2;
-        }
-        if (match) {
-            if (*p1 == '.') {
-                ++p1;
-                std::size_t n = p2 - p1;
-                if ((n == areaLen && equalStrings(p1, n, area, areaLen))
-                    || (n < areaLen && area[n] == '.'
-                        && equalStrings(p1, n, area, n)))
-                {
-                    senseLen[sense] = p2 - p;
+            {
+                char const * p1 = p;
+                while (*p1 != '.' && *p1 != '+' && *p1 != '-' && *p1 != '\0') {
+                    ++p1;
                 }
-            } else {
-                senseLen[sense] = p1 - p;
+                if (equalStrings(p, p1 - p, 
RTL_CONSTASCII_STRINGPARAM("TIMESTAMP")))
+                    outputTimestamp = true;
+                else if (equalStrings(p, p1 - p, 
RTL_CONSTASCII_STRINGPARAM("RELATIVETIMER")))
+                    outputRelativeTimer = true;
+                char const * p2 = p1;
+                while (*p2 != '+' && *p2 != '-' && *p2 != '\0') {
+                    ++p2;
+                }
+                p = p2;
             }
+            break;
+        default:
+            ; // nothing
         }
-        p = p2;
     }
+    return;
 }
 
-void log(
+#endif
+
+}
+
+void sal_detail_log(
     sal_detail_LogLevel level, char const * area, char const * where,
-    char const * message)
+    char const * message, sal_uInt32 backtraceDepth)
 {
     std::ostringstream s;
 #if !defined ANDROID
     // On Android, the area will be used as the "tag," and log info already
-    // contains the PID
+    // contains timestamp and PID.
     if (!sal_use_syslog) {
+        maybeOutputTimestamp(s);
         s << toString(level) << ':';
     }
-    if (!isDebug(level)) {
+    if (level != SAL_DETAIL_LOG_LEVEL_DEBUG) {
         s << area << ':';
     }
     s << OSL_DETAIL_GETPID << ':';
 #endif
     s << osl::Thread::getCurrentIdentifier() << ':';
-    if (isDebug(level)) {
+    if (level == SAL_DETAIL_LOG_LEVEL_DEBUG) {
         s << ' ';
     } else {
         const size_t nStrLen(std::strlen(SRCDIR "/"));
@@ -208,13 +276,10 @@ void log(
               + (std::strncmp(where, SRCDIR "/", nStrLen) == 0
                  ? nStrLen : 0));
     }
-
     s << message;
-    if (level == SAL_DETAIL_LOG_LEVEL_DEBUG_TRACE) {
-        s << " at:\n";
-        s << OUString(osl_backtraceAsString(), SAL_NO_ACQUIRE);
+    if (backtraceDepth != 0) {
+        s << " at:\n" << osl::detail::backtraceAsString(backtraceDepth);
     }
-    s << '\n';
 
 #if defined ANDROID
     int android_log_level;
@@ -258,48 +323,121 @@ void log(
         syslog(prio, "%s", s.str().c_str());
 #endif
     } else {
-        std::fputs(s.str().c_str(), stderr);
-        std::fflush(stderr);
-    }
+        // avoid calling getLogFile() more than once
+        static std::ofstream * logFile = getLogFile();
+        if (logFile) {
+            *logFile << s.str() << std::endl;
+        }
+        else {
+#ifdef WNT
+            // write to Windows debugger console, too
+            OutputDebugStringA(s.str().c_str());
 #endif
-}
-
-}
-
-void sal_detail_log(
-    sal_detail_LogLevel level, char const * area, char const * where,
-    char const * message)
-{
-    if (report(level, area)) {
-        log(level, area, where, message);
+            s << '\n';
+            std::fputs(s.str().c_str(), stderr);
+            std::fflush(stderr);
+        }
     }
+#endif
 }
 
 void sal_detail_logFormat(
     sal_detail_LogLevel level, char const * area, char const * where,
     char const * format, ...)
 {
-    if (report(level, area)) {
+    if (sal_detail_log_report(level, area)) {
         std::va_list args;
         va_start(args, format);
-        osl::detail::logFormat(level, area, where, format, args);
+        char buf[1024];
+        int const len = sizeof buf - RTL_CONSTASCII_LENGTH("...");
+        int n = vsnprintf(buf, len, format, args);
+        if (n < 0) {
+            std::strcpy(buf, "???");
+        } else if (n >= len) {
+            std::strcpy(buf + len - 1, "...");
+        }
+        sal_detail_log(level, area, where, buf, 0);
         va_end(args);
     }
 }
 
-void osl::detail::logFormat(
-    sal_detail_LogLevel level, char const * area, char const * where,
-    char const * format, std::va_list arguments)
-{
-    char buf[1024];
-    int const len = sizeof buf - RTL_CONSTASCII_LENGTH("...");
-    int n = vsnprintf(buf, len, format, arguments);
-    if (n < 0) {
-        std::strcpy(buf, "???");
-    } else if (n >= len) {
-        std::strcpy(buf + len - 1, "...");
+sal_Bool sal_detail_log_report(sal_detail_LogLevel level, char const * area) {
+    if (level == SAL_DETAIL_LOG_LEVEL_DEBUG) {
+        return true;
+    }
+    assert(area != nullptr);
+    static char const * env = getLogLevel();
+    if (env == nullptr) {
+        env = "+WARN";
+    }
+    std::size_t areaLen = std::strlen(area);
+    enum Sense { POSITIVE = 0, NEGATIVE = 1 };
+    std::size_t senseLen[2] = { 0, 1 };
+        // initial senseLen[POSITIVE] < senseLen[NEGATIVE], so that if there 
are
+        // no matching switches at all, the result will be negative (and
+        // initializing with 1 is safe as the length of a valid switch, even
+        // without the "+"/"-" prefix, will always be > 1)
+    bool seenWarn = false;
+    for (char const * p = env;;) {
+        Sense sense;
+        switch (*p++) {
+        case '\0':
+            if (level == SAL_DETAIL_LOG_LEVEL_WARN && !seenWarn)
+                return sal_detail_log_report(SAL_DETAIL_LOG_LEVEL_INFO, area);
+            return senseLen[POSITIVE] >= senseLen[NEGATIVE];
+                // if a specific item is both positive and negative
+                // (senseLen[POSITIVE] == senseLen[NEGATIVE]), default to
+                // positive
+        case '+':
+            sense = POSITIVE;
+            break;
+        case '-':
+            sense = NEGATIVE;
+            break;
+        default:
+            return true; // upon an illegal SAL_LOG value, enable everything
+        }
+        char const * p1 = p;
+        while (*p1 != '.' && *p1 != '+' && *p1 != '-' && *p1 != '\0') {
+            ++p1;
+        }
+        bool match;
+        if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("INFO"))) {
+            match = level == SAL_DETAIL_LOG_LEVEL_INFO;
+        } else if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("WARN")))
+        {
+            match = level == SAL_DETAIL_LOG_LEVEL_WARN;
+            seenWarn = true;
+        } else if (equalStrings(p, p1 - p, 
RTL_CONSTASCII_STRINGPARAM("TIMESTAMP")) ||
+                   equalStrings(p, p1 - p, 
RTL_CONSTASCII_STRINGPARAM("RELATIVETIMER")))
+        {
+            // handled later
+            match = false;
+        } else {
+            return true;
+                // upon an illegal SAL_LOG value, everything is considered
+                // positive
+        }
+        char const * p2 = p1;
+        while (*p2 != '+' && *p2 != '-' && *p2 != '\0') {
+            ++p2;
+        }
+        if (match) {
+            if (*p1 == '.') {
+                ++p1;
+                std::size_t n = p2 - p1;
+                if ((n == areaLen && equalStrings(p1, n, area, areaLen))
+                    || (n < areaLen && area[n] == '.'
+                        && equalStrings(p1, n, area, n)))
+                {
+                    senseLen[sense] = p2 - p;
+                }
+            } else {
+                senseLen[sense] = p1 - p;
+            }
+        }
+        p = p2;
     }
-    log(level, area, where, buf);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/osl/all/logformat.hxx b/sal/osl/all/logformat.hxx
deleted file mode 100644
index 0e579a9bfc54..000000000000
--- a/sal/osl/all/logformat.hxx
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * 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/.
- */
-
-#ifndef INCLUDED_SAL_OSL_ALL_LOGFORMAT_HXX
-#define INCLUDED_SAL_OSL_ALL_LOGFORMAT_HXX
-
-#include "sal/config.h"
-
-#include <cstdarg>
-
-#include "sal/detail/log.h"
-
-namespace osl { namespace detail {
-
-void logFormat(
-    sal_detail_LogLevel level, char const * area, char const * where,
-    char const * format, std::va_list arguments);
-
-} }
-
-#endif
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/osl/unx/backtraceapi.cxx b/sal/osl/unx/backtraceapi.cxx
index 1895c4360837..a838471f1116 100644
--- a/sal/osl/unx/backtraceapi.cxx
+++ b/sal/osl/unx/backtraceapi.cxx
@@ -9,16 +9,52 @@
 
 #include <sal/config.h>
 
+#include <cassert>
+#include <cstdlib>
+#include <limits>
+#include <memory>
+
 #include <rtl/ustrbuf.hxx>
-#include "misc.hxx"
-
-// FIXME: no-op for now; it needs implementing, cf. above.
-rtl_uString *osl_backtraceAsString()
-{
-    OUStringBuffer aBuf;
-    OUString aStr = aBuf.makeStringAndClear();
-    rtl_uString_acquire( aStr.pData );
-    return aStr.pData;
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include "backtrace.h"
+#include "backtraceasstring.hxx"
+
+namespace {
+
+struct FreeGuard {
+    FreeGuard(char ** theBuffer): buffer(theBuffer) {}
+
+    ~FreeGuard() { std::free(buffer); }
+
+    char ** buffer;
+};
+
+}
+
+OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth) {
+    assert(maxDepth != 0);
+    auto const maxInt = static_cast<unsigned int>(
+        std::numeric_limits<int>::max());
+    if (maxDepth > maxInt) {
+        maxDepth = static_cast<sal_uInt32>(maxInt);
+    }
+    auto b1 = std::unique_ptr<void *[]>(new void *[maxDepth]);
+    int n = backtrace(b1.get(), static_cast<int>(maxDepth));
+    FreeGuard b2(backtrace_symbols(b1.get(), n));
+    b1.reset();
+    if (b2.buffer == nullptr) {
+        return OUString();
+    }
+    OUStringBuffer b3;
+    for (int i = 0; i != n; ++i) {
+        if (i != 0) {
+            b3.append("\n");
+        }
+        // TODO b3.append(o3tl::runtimeToOUString(b2.buffer[i]));
+    }
+    return b3.makeStringAndClear();
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/osl/w32/backtrace.cxx b/sal/osl/w32/backtrace.cxx
index 5095d2053051..5bcf230da8d4 100644
--- a/sal/osl/w32/backtrace.cxx
+++ b/sal/osl/w32/backtrace.cxx
@@ -7,7 +7,10 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include "misc.hxx"
+#include <sal/config.h>
+
+#include <limits>
+#include <memory>
 
 #include <windows.h>
 #include <process.h>
@@ -17,16 +20,28 @@
 
 #include <rtl/ustrbuf.hxx>
 
-// No-op for now; it needs implementing.
-rtl_uString *osl_backtraceAsString()
+#include "backtraceasstring.hxx"
+
+OUString osl::detail::backtraceAsString(sal_uInt32 maxDepth)
 {
+    assert(maxDepth != 0);
+    auto const maxUlong = std::numeric_limits<ULONG>::max();
+    if (maxDepth > maxUlong) {
+        maxDepth = static_cast<sal_uInt32>(maxUlong);
+    }
+
     OUStringBuffer aBuf;
 
     HANDLE hProcess = GetCurrentProcess();
     SymInitialize( hProcess, NULL, true );
 
-    void * aStack[ 512 ];
-    sal_uInt32 nFrames = CaptureStackBackTrace( 0, 512, aStack, NULL );
+    std::unique_ptr<void*[]> aStack(new void*[ maxDepth ]);
+    // <https://msdn.microsoft.com/en-us/library/windows/desktop/
+    // bb204633(v=vs.85).aspx> "CaptureStackBackTrace function" claims that you
+    // "can capture up to MAXUSHORT frames", and on Windows Server 2003 and
+    // Windows XP it even "must be less than 63", but assume that a too large
+    // input value is clamped internally, instead of resulting in an error:
+    sal_uInt32 nFrames = CaptureStackBackTrace( 0, 
static_cast<ULONG>(maxDepth), aStack.get(), nullptr );
 
     SYMBOL_INFO  * pSymbol;
     pSymbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 1024 * sizeof( 
char ), 1 );
@@ -46,9 +61,7 @@ rtl_uString *osl_backtraceAsString()
 
     free( pSymbol );
 
-    OUString aStr = aBuf.makeStringAndClear();
-    rtl_uString_acquire( aStr.pData );
-    return aStr.pData;
+    return aBuf.makeStringAndClear();
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/util/sal.map b/sal/util/sal.map
index 1ccac615b67f..249473bf62e8 100644
--- a/sal/util/sal.map
+++ b/sal/util/sal.map
@@ -716,6 +716,11 @@ PRIVATE_1.2 { # LibreOffice 3.5
         sal_detail_logFormat;
 } PRIVATE_1.1;
 
+PRIVATE_1.3 { # LibreOffice 5.4
+    global:
+        sal_detail_log_report;
+} PRIVATE_1.2;
+
 PRIVATE_textenc.1 { # LibreOffice 3.6
     global:
         _ZN3sal6detail7textenc20convertCharToUnicode*;
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to