[Libreoffice-commits] core.git: Branch 'feature/cib_contract57b' - include/sal sal/inc sal/osl sal/util
Thorsten Behrens
thorsten.behrens at CIB.de
Mon Jun 4 07:52:49 UTC 2018
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.behrens at 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*;
More information about the Libreoffice-commits
mailing list