summaryrefslogtreecommitdiff
path: root/sal/inc
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2011-11-22 09:34:46 +0100
committerStephan Bergmann <sbergman@redhat.com>2011-11-22 09:41:47 +0100
commit70a6b9ffbd676a1384433a86205d2cd4f2d4f4b1 (patch)
treeffb31ef817b5f2037cf7c332da422b9179d613d5 /sal/inc
parentf2972242673cc9608960e9ca70e82766be5275e3 (diff)
New sal/log.h obsoletes osl/diagnose.h and tools/debug.hxx.
* New SAL_INFO..., SAL_WARN... macros. * New SAL_STREAM supersedes OSL_FORMAT. * oustringostreaminserter.hxx moved from unotest to rtl (and always UTF-8 now). * TODO to enable GCC __attribute__((format)) in sal/log.h (requires call-site cleanup). * Further functionality in tools/debug.hxx (DBG_MEMTEST, DBG_CTOR, etc.) not yet addressed. * Some replacements tools String -> rtl::OUString.
Diffstat (limited to 'sal/inc')
-rw-r--r--sal/inc/osl/diagnose.h79
-rw-r--r--sal/inc/osl/diagnose.hxx27
-rw-r--r--sal/inc/osl/thread.hxx10
-rw-r--r--sal/inc/rtl/oustringostreaminserter.hxx61
-rw-r--r--sal/inc/rtl/strbuf.hxx11
-rw-r--r--sal/inc/rtl/string.hxx19
-rw-r--r--sal/inc/rtl/ustrbuf.hxx15
-rw-r--r--sal/inc/rtl/ustring.hxx29
-rw-r--r--sal/inc/sal/log.h305
9 files changed, 455 insertions, 101 deletions
diff --git a/sal/inc/osl/diagnose.h b/sal/inc/osl/diagnose.h
index aab76b320f2a..8e889ac5a37a 100644
--- a/sal/inc/osl/diagnose.h
+++ b/sal/inc/osl/diagnose.h
@@ -30,10 +30,25 @@
#ifndef _OSL_DIAGNOSE_H_
#define _OSL_DIAGNOSE_H_
+#include "sal/config.h"
+
+#include <sal/log.h>
#include <sal/types.h>
/** provides simple diagnostic support
+ The facilities provided by this header are deprecated. True assertions
+ (that detect broken program logic) should use standard assert (which aborts
+ if an assertion fails, and is controlled by the standard NDEBUG macro).
+ Logging of warnings (e.g., about malformed input) and traces (e.g., about
+ steps taken while executing some protocol) should use the facilities
+ provided by sal/log.h.
+
+ Because the assertion macros (OSL_ASSERT, OSL_ENSURE, OSL_FAIL, OSL_PRECOND,
+ and OSL_POSTCOND) have been used for true assertions as well as for logged
+ warnings, they map to SAL_WARN instead of standard assert. OSL_TRACE maps
+ to SAL_INFO.
+
The functions defined in this header are not intended to be used directly,
but through defined macros. The macros can be divided into three categories:
assertions, traces and other stuff .-) Their usability depends on the value
@@ -122,14 +137,25 @@ pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc( pf
#define OSL_THIS_FILE __FILE__
-/* the macro OSL_LOG_PREFIX is intended to be an office internal macro for now */
-#define OSL_LOG_PREFIX OSL_THIS_FILE ":" SAL_STRINGIFY( __LINE__ ) "; "
+/* the macro OSL_LOG_PREFIX is intended to be an office internal macro for now
+
+ it is deprecated and superseded by SAL_WHERE
+*/
+#define OSL_LOG_PREFIX SAL_WHERE
#define OSL_DEBUG_ONLY(s) _OSL_DEBUG_ONLY(s)
-#define OSL_TRACE _OSL_TRACE
-#define OSL_ASSERT(c) _OSL_ENSURE(c, OSL_THIS_FILE, __LINE__, 0)
-#define OSL_ENSURE(c, m) _OSL_ENSURE(c, OSL_THIS_FILE, __LINE__, m)
-#define OSL_FAIL(m) _OSL_ENSURE(0, OSL_THIS_FILE, __LINE__, m)
+
+#if OSL_DEBUG_LEVEL > 0
+#define OSL_TRACE(...) SAL_INFO("legacy.osl", __VA_ARGS__)
+#define OSL_ASSERT(c) SAL_WARN_IF(!(c), "legacy.osl", "OSL_ASSERT")
+#define OSL_ENSURE(c, m) SAL_WARN_IF(!(c), "legacy.osl", "%s", m)
+#define OSL_FAIL(m) SAL_WARN_IF(sal_True, "legacy.osl", "%s", m)
+#else
+#define OSL_TRACE(...) ((void) 0)
+#define OSL_ASSERT(c) ((void) 0)
+#define OSL_ENSURE(c, m) ((void) 0)
+#define OSL_FAIL(m) ((void) 0)
+#endif
#define OSL_VERIFY(c) do { if (!(c)) OSL_ASSERT(0); } while (0)
#define OSL_PRECOND(c, m) OSL_ENSURE(c, m)
@@ -145,27 +171,10 @@ pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc( pf
#if OSL_DEBUG_LEVEL > 0
#define _OSL_DEBUG_ONLY(f) (f)
-#define _OSL_ENSURE(c, f, l, m) \
- do \
- { \
- if (!(c) && _OSL_GLOBAL osl_assertFailedLine(f, l, m)) \
- _OSL_GLOBAL osl_breakDebug(); \
- } while (0)
#else
#define _OSL_DEBUG_ONLY(f) ((void)0)
-#define _OSL_ENSURE(c, f, l, m) ((void)0)
-
-#endif /* OSL_DEBUG_LEVEL */
-
-#if OSL_DEBUG_LEVEL > 1
-
-#define _OSL_TRACE _OSL_GLOBAL osl_trace
-
-#else
-
-#define _OSL_TRACE 1 ? ((void)0) : _OSL_GLOBAL osl_trace
#endif /* OSL_DEBUG_LEVEL */
@@ -192,30 +201,6 @@ pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc( pf
#define OSL_THIS_FUNC ""
#endif
-#if defined __cplusplus
-
-#include "rtl/string.hxx"
-
-/** @internal */
-extern "C" struct _rtl_String * SAL_CALL osl_detail_formatString(
- char const * format, ...) SAL_THROW_EXTERN_C();
- // "struct _rtl_String" instead of "rtl_String" for the case where
- // osl/diagnose.h is included in rtl/string.hxx
-
-/** A facility for printf-style messages in OSL_ENSURE, OSL_FAIL, etc.
-
- Use like: OSL_ENSURE(i == 5, OSL_FORMAT("i should be 5 but is %d", i));
-*/
-#define OSL_FORMAT(format, ...) \
- (::rtl::OString( \
- ::osl_detail_formatString(format, __VA_ARGS__), \
- ::SAL_NO_ACQUIRE).getStr())
- // it appears that all relevant compilers (esp. GCC 4.0 and MS VS 2008
- // Express) already support variadic macros in C++; see also
- // <http://wiki.apache.org/stdcxx/C++0xCompilerSupport>
-
-#endif
-
#endif /* _OSL_DIAGNOSE_H_ */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/inc/osl/diagnose.hxx b/sal/inc/osl/diagnose.hxx
index a9aba130d72b..42e4b8dd7f2f 100644
--- a/sal/inc/osl/diagnose.hxx
+++ b/sal/inc/osl/diagnose.hxx
@@ -25,27 +25,22 @@
* for a copy of the LGPLv3 License.
*
************************************************************************/
-#if ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
+#ifndef OSL_DIAGNOSE_HXX_INCLUDED
#define OSL_DIAGNOSE_HXX_INCLUDED
-#if ! defined(_OSL_DIAGNOSE_H_)
+#include "sal/config.h"
+
+#include <functional>
+#include <typeinfo>
+
+#include "boost/unordered_set.hpp"
#include "osl/diagnose.h"
-#endif
-#if ! defined(_OSL_INTERLOCK_H_)
#include "osl/interlck.h"
-#endif
-#if ! defined(_OSL_MUTEX_HXX_)
#include "osl/mutex.hxx"
-#endif
-#if ! defined(INCLUDED_RTL_ALLOCATOR_HXX)
#include "rtl/allocator.hxx"
-#endif
-#if ! defined(_RTL_INSTANCE_HXX_)
#include "rtl/instance.hxx"
-#endif
-#include <boost/unordered_set.hpp>
-#include <functional>
-#include <typeinfo>
+#include "sal/log.h"
+#include "sal/types.h"
namespace osl {
/// @internal
@@ -126,7 +121,7 @@ public:
VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin());
VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end());
for ( ; iPos != iEnd; ++iPos ) {
- OSL_ASSERT( *iPos != 0 );
+ SAL_WARN_IF( *iPos == 0, "sal.debug", "null pointer" );
}
}
return bRet;
@@ -179,7 +174,7 @@ public:
static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
#else // OSL_DEBUG_LEVEL > 0
/** @return whether the expected number of objects is alive,
- else this function OSL_ASSERTs
+ else this function SAL_WARNs
*/
static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
return StaticObjectRegistry::get().checkObjectCount(nExpected);
diff --git a/sal/inc/osl/thread.hxx b/sal/inc/osl/thread.hxx
index 2bcc82fd07eb..2916ff7443d6 100644
--- a/sal/inc/osl/thread.hxx
+++ b/sal/inc/osl/thread.hxx
@@ -29,7 +29,9 @@
#ifndef _THREAD_HXX_
#define _THREAD_HXX_
-#ifdef __cplusplus
+#include "sal/config.h"
+
+#include <cassert>
#include <osl/time.h>
@@ -71,7 +73,7 @@ public:
sal_Bool SAL_CALL create()
{
- OSL_ASSERT(m_hThread == 0); // only one running thread per instance
+ assert(m_hThread == 0); // only one running thread per instance
if (m_hThread)
return sal_False;
@@ -84,7 +86,7 @@ public:
sal_Bool SAL_CALL createSuspended()
{
- OSL_ASSERT(m_hThread == 0); // only one running thread per instance
+ assert(m_hThread == 0); // only one running thread per instance
if( m_hThread)
return sal_False;
m_hThread= osl_createSuspendedThread( threadFunc,
@@ -233,7 +235,7 @@ private:
};
} // end namespace osl
-#endif
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/inc/rtl/oustringostreaminserter.hxx b/sal/inc/rtl/oustringostreaminserter.hxx
new file mode 100644
index 000000000000..579ffa0cd045
--- /dev/null
+++ b/sal/inc/rtl/oustringostreaminserter.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2000, 2010 Oracle and/or its affiliates.
+*
+* OpenOffice.org - a multi-platform office productivity suite
+*
+* This file is part of OpenOffice.org.
+*
+* OpenOffice.org is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License version 3
+* only, as published by the Free Software Foundation.
+*
+* OpenOffice.org is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License version 3 for more details
+* (a copy is included in the LICENSE file that accompanied this code).
+*
+* You should have received a copy of the GNU Lesser General Public License
+* version 3 along with OpenOffice.org. If not, see
+* <http://www.openoffice.org/license.html>
+* for a copy of the LGPLv3 License.
+************************************************************************/
+
+#ifndef INCLUDED_RTL_OUSTRINGOSTREAMINSERTER_HXX
+#define INCLUDED_RTL_OUSTRINGOSTREAMINSERTER_HXX
+
+#include "sal/config.h"
+
+#include <ostream>
+
+#include "rtl/textenc.h"
+#include "rtl/ustring.hxx"
+
+/** Include this header to support rtl::OUString in std::ostream (and thus in
+ CPPUNIT_ASSERT macros, for example).
+
+ The rtl::OUString is converted to UTF-8.
+
+ @since LibreOffice 3.5.
+*/
+
+namespace rtl {
+
+template< typename charT, typename traits > std::basic_ostream<charT, traits> &
+operator <<(
+ std::basic_ostream<charT, traits> & stream, rtl::OUString const & string)
+{
+ return stream <<
+ rtl::OUStringToOString(string, RTL_TEXTENCODING_UTF8).getStr();
+ // best effort; potentially loses data due to conversion failures
+ // (stray surrogate halves) and embedded null characters
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/inc/rtl/strbuf.hxx b/sal/inc/rtl/strbuf.hxx
index 962d3dfda8a0..5f0b9b3fecc0 100644
--- a/sal/inc/rtl/strbuf.hxx
+++ b/sal/inc/rtl/strbuf.hxx
@@ -29,7 +29,10 @@
#ifndef _RTL_STRBUF_HXX_
#define _RTL_STRBUF_HXX_
-#include "osl/diagnose.h"
+#include "sal/config.h"
+
+#include <cassert>
+
#include <rtl/strbuf.h>
#include <rtl/string.hxx>
@@ -253,7 +256,7 @@ public:
*/
void setLength(sal_Int32 newLength)
{
- OSL_ASSERT(newLength >= 0);
+ assert(newLength >= 0);
// Avoid modifications if pData points to const empty string:
if( newLength != pData->length )
{
@@ -280,7 +283,7 @@ public:
*/
sal_Char charAt( sal_Int32 index )
{
- OSL_ASSERT(index >= 0 && index < pData->length);
+ assert(index >= 0 && index < pData->length);
return pData->buffer[ index ];
}
@@ -321,7 +324,7 @@ public:
*/
OStringBuffer & setCharAt(sal_Int32 index, sal_Char ch)
{
- OSL_ASSERT(index >= 0 && index < pData->length);
+ assert(index >= 0 && index < pData->length);
pData->buffer[ index ] = ch;
return *this;
}
diff --git a/sal/inc/rtl/string.hxx b/sal/inc/rtl/string.hxx
index ee4101188013..007129a7dc0f 100644
--- a/sal/inc/rtl/string.hxx
+++ b/sal/inc/rtl/string.hxx
@@ -29,12 +29,15 @@
#ifndef _RTL_STRING_HXX_
#define _RTL_STRING_HXX_
-#ifdef __cplusplus
+#include "sal/config.h"
+
+#include <cassert>
#include <osl/diagnose.h>
#include <rtl/memory.h>
#include <rtl/textenc.h>
#include <rtl/string.h>
+#include "sal/log.h"
#if !defined EXCEPTIONS_OFF
#include <new>
@@ -183,13 +186,13 @@ public:
{
pData = 0;
rtl_uString2String( &pData, value, length, encoding, convertFlags );
+ if (pData == 0) {
#if defined EXCEPTIONS_OFF
- OSL_ASSERT(pData != NULL);
+ SAL_WARN("sal", "std::bad_alloc but EXCEPTIONS_OFF");
#else
- if (pData == 0) {
throw std::bad_alloc();
- }
#endif
+ }
}
/**
@@ -655,7 +658,7 @@ public:
*/
OString copy( sal_Int32 beginIndex ) const SAL_THROW(())
{
- OSL_ASSERT(beginIndex >= 0 && beginIndex <= getLength());
+ assert(beginIndex >= 0 && beginIndex <= getLength());
if ( beginIndex == 0 )
return *this;
else
@@ -679,8 +682,8 @@ public:
*/
OString copy( sal_Int32 beginIndex, sal_Int32 count ) const SAL_THROW(())
{
- OSL_ASSERT(beginIndex >= 0 && beginIndex <= getLength()
- && count >= 0 && count <= getLength() - beginIndex);
+ assert(beginIndex >= 0 && beginIndex <= getLength()
+ && count >= 0 && count <= getLength() - beginIndex);
if ( (beginIndex == 0) && (count == getLength()) )
return *this;
else
@@ -1034,8 +1037,6 @@ struct OStringHash
} /* Namespace */
-#endif /* __cplusplus */
-
#endif /* _RTL_STRING_HXX_ */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/inc/rtl/ustrbuf.hxx b/sal/inc/rtl/ustrbuf.hxx
index 60bb750a1dc7..2456316274d2 100644
--- a/sal/inc/rtl/ustrbuf.hxx
+++ b/sal/inc/rtl/ustrbuf.hxx
@@ -29,12 +29,14 @@
#ifndef _RTL_USTRBUF_HXX_
#define _RTL_USTRBUF_HXX_
+#include "sal/config.h"
+
+#include <cassert>
+
#include <osl/diagnose.h>
#include <rtl/ustrbuf.h>
#include <rtl/ustring.hxx>
-#ifdef __cplusplus
-
namespace rtl
{
@@ -233,7 +235,7 @@ public:
*/
void setLength(sal_Int32 newLength)
{
- OSL_ASSERT(newLength >= 0);
+ assert(newLength >= 0);
// Avoid modifications if pData points to const empty string:
if( newLength != pData->length )
{
@@ -260,7 +262,7 @@ public:
*/
sal_Unicode charAt( sal_Int32 index ) const
{
- OSL_ASSERT(index >= 0 && index < pData->length);
+ assert(index >= 0 && index < pData->length);
return pData->buffer[ index ];
}
@@ -301,7 +303,7 @@ public:
*/
OUStringBuffer & setCharAt(sal_Int32 index, sal_Unicode ch)
{
- OSL_ASSERT(index >= 0 && index < pData->length);
+ assert(index >= 0 && index < pData->length);
pData->buffer[ index ] = ch;
return *this;
}
@@ -434,7 +436,7 @@ public:
*/
OUStringBuffer & append(char c)
{
- OSL_ASSERT(static_cast< unsigned char >(c) <= 0x7F);
+ assert(static_cast< unsigned char >(c) <= 0x7F);
return append(sal_Unicode(c));
}
@@ -819,7 +821,6 @@ private:
}
-#endif /* __cplusplus */
#endif /* _RTL_USTRBUF_HXX_ */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/inc/rtl/ustring.hxx b/sal/inc/rtl/ustring.hxx
index edf7c9747962..ef13dd1da387 100644
--- a/sal/inc/rtl/ustring.hxx
+++ b/sal/inc/rtl/ustring.hxx
@@ -29,12 +29,15 @@
#ifndef _RTL_USTRING_HXX_
#define _RTL_USTRING_HXX_
-#ifdef __cplusplus
+#include "sal/config.h"
+
+#include <cassert>
#include "osl/diagnose.h"
#include <rtl/ustring.h>
#include <rtl/string.hxx>
#include <rtl/memory.h>
+#include "sal/log.h"
#if defined EXCEPTIONS_OFF
#include <stdlib.h>
@@ -184,13 +187,13 @@ public:
{
pData = 0;
rtl_string2UString( &pData, value, length, encoding, convertFlags );
+ if (pData == 0) {
#if defined EXCEPTIONS_OFF
- OSL_ASSERT(pData != NULL);
+ SAL_WARN("sal", "std::bad_alloc but EXCEPTIONS_OFF");
#else
- if (pData == 0) {
throw std::bad_alloc();
- }
#endif
+ }
}
/** Create a new string from an array of Unicode code points.
@@ -967,7 +970,7 @@ public:
*/
OUString copy( sal_Int32 beginIndex ) const SAL_THROW(())
{
- OSL_ASSERT(beginIndex >= 0 && beginIndex <= getLength());
+ assert(beginIndex >= 0 && beginIndex <= getLength());
if ( beginIndex == 0 )
return *this;
else
@@ -991,7 +994,7 @@ public:
*/
OUString copy( sal_Int32 beginIndex, sal_Int32 count ) const SAL_THROW(())
{
- OSL_ASSERT(beginIndex >= 0 && beginIndex <= getLength() && count >= 0);
+ assert(beginIndex >= 0 && beginIndex <= getLength() && count >= 0);
if ( (beginIndex == 0) && (count == getLength()) )
return *this;
else
@@ -1243,13 +1246,13 @@ public:
{
rtl_uString * pNew = 0;
rtl_uString_intern( &pNew, pData );
+ if (pNew == 0) {
#if defined EXCEPTIONS_OFF
- OSL_ASSERT(pNew != NULL);
+ SAL_WARN("sal", "std::bad_alloc but EXCEPTIONS_OFF");
#else
- if (pNew == 0) {
throw std::bad_alloc();
- }
#endif
+ }
return OUString( pNew, (DO_NOT_ACQUIRE *)0 );
}
@@ -1286,13 +1289,13 @@ public:
rtl_uString * pNew = 0;
rtl_uString_internConvert( &pNew, value, length, encoding,
convertFlags, pInfo );
+ if (pNew == 0) {
#if defined EXCEPTIONS_OFF
- OSL_ASSERT(pNew != NULL);
+ SAL_WARN("sal", "std::bad_alloc but EXCEPTIONS_OFF");
#else
- if (pNew == 0) {
throw std::bad_alloc();
- }
#endif
+ }
return OUString( pNew, (DO_NOT_ACQUIRE *)0 );
}
@@ -1576,8 +1579,6 @@ inline OString OUStringToOString( const OUString & rUnicode,
} /* Namespace */
-#endif /* __cplusplus */
-
#endif /* _RTL_USTRING_HXX */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/inc/sal/log.h b/sal/inc/sal/log.h
new file mode 100644
index 000000000000..9e15560aa2c1
--- /dev/null
+++ b/sal/inc/sal/log.h
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * [ Copyright (C) 2011 Stephan Bergmann, Red Hat <sbergman@redhat.com> (initial
+ * developer) ]
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#ifndef INCLUDED_SAL_LOG_H
+#define INCLUDED_SAL_LOG_H
+
+#include "sal/config.h"
+
+#if defined __cplusplus
+#include <sstream>
+#include <string>
+#endif
+
+#include "sal/types.h"
+
+/* This header uses variadic macros in both C (where they are officially only
+ supported since C99) and C++ (where they are officially only supported since
+ C++11). It appears that all relevant compilers (esp. GCC 4.0 and MS VS 2008
+ Express) already support them in their C and C++ dialects. See also
+ <http://wiki.apache.org/stdcxx/C++0xCompilerSupport>.
+
+ Avoid the use of other sal code in this header as much as possible, so that
+ this code can be called from other sal code without causing endless
+ recursion.
+*/
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/** @internal */
+enum sal_detail_LogLevel {
+ SAL_DETAIL_LOG_LEVEL_INFO, SAL_DETAIL_LOG_LEVEL_WARN,
+ SAL_DETAIL_MAKE_FIXED_SIZE = SAL_MAX_ENUM
+};
+
+/** @internal */
+void SAL_CALL sal_detail_log(
+ enum sal_detail_LogLevel level, char const * area, char const * where,
+ char const * message);
+
+/** @internal */
+void SAL_CALL sal_detail_logFormat(
+ enum sal_detail_LogLevel level, char const * area, char const * where,
+ char const * format, ...)
+/* TODO: enabling this will produce a huge amount of -Werror=format errors: */
+#if defined GCC && 0
+ __attribute__((format(printf, 4, 5)))
+#endif
+ ;
+
+#if defined __cplusplus
+}
+#endif
+
+/** @internal */
+#define SAL_DETAIL_LOG_FORMAT(condition, level, area, where, ...) \
+ do { \
+ if (condition) { \
+ sal_detail_logFormat((level), (area), (where), __VA_ARGS__); \
+ } \
+ } while (sal_False)
+
+#if defined __cplusplus
+
+namespace sal { namespace detail {
+
+/// @internal
+inline void SAL_CALL log(
+ sal_detail_LogLevel level, char const * area, char const * where,
+ std::ostringstream const & stream)
+{
+ // 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
+ // code (the ".str().c_str()" part would move into the implementation of
+ // sal_detail_log) and potential for proper support of embedded null
+ // characters within the message, but the disadvantage would be dependence
+ // 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());
+}
+
+} }
+
+/// @internal
+#define SAL_DETAIL_LOG_STREAM(condition, level, area, where, stream) \
+ do { \
+ if (condition) { \
+ ::std::ostringstream sal_detail_stream; \
+ sal_detail_stream << stream; \
+ ::sal::detail::log((level), (area), (where), sal_detail_stream); \
+ } \
+ } while (false)
+
+#endif
+
+/** A simple macro to create a "file and line number" string.
+
+ Potentially not only useful within the log framework (where it is used
+ automatically), but also when creating exception messages.
+
+ @since LibreOffice 3.5
+*/
+#define SAL_WHERE __FILE__ ":" SAL_STRINGIFY(__LINE__) ": "
+
+#if defined __cplusplus
+
+/** A facility for generating temporary string messages by piping items into a
+ C++ std::ostringstream.
+
+ This can be useful for example in a call to SAL_INFO_S when depending on
+ some boolean condition data of incompatible types shall be streamed into the
+ message, as in:
+
+ SAL_INFO_S(
+ "foo", "object: " << (hasName ? obj->name : SAL_STREAM(obj)));
+
+ @since LibreOffice 3.5
+*/
+#define SAL_STREAM(stream) \
+ (dynamic_cast< ::std::ostringstream & >(::std::ostringstream() << stream). \
+ str())
+
+#endif
+
+/** Basic logging functionality.
+
+ SAL_INFO(char const * area, char const * format, ...),
+ SAL_INFO_IF(bool condition, char const * area, char const * format, ...),
+ SAL_WARN(char const * area, char const * format, ...), and
+ SAL_WARN_IF(bool condition, char const * area, char const * format, ...)
+ produce an info resp. warning log entry with a printf-style message. The
+ given format argument and any following arguments must be so that that
+ sequence of arguments would be appropriate for a call to printf.
+
+ SAL_INFO_S(char const * area, expr),
+ SAL_INFO_IF_S(bool condition, char const * area, expr),
+ SAL_WARN_S(char const * area, expr), and
+ SAL_WARN_IF_S(bool condition, char const * area, expr) produce an info resp.
+ warning log entry with a message produced by piping items into a C++
+ std::ostringstream (and are only available in C++). The given expr must be
+ so that the full expression "stream << expr" is valid, where stream is a
+ variable of type std::ostringstream.
+
+ SAL_INFO_S("foo", "string " << s << " of length " << n)
+
+ would be an example of such a call; if the given s is of type rtl::OUString,
+
+ #include "rtl/oustringostreaminserter.hxx"
+
+ would make sure that an appropriate operator << is available.
+
+ In either case, the composed message should be in UTF-8 and it should
+ contain no vertical formatting characters and no null characters
+
+ For the _IF variants, log output is only generated if the given condition is
+ true (in addition to the other conditions that have to be met).
+
+ For all these macros, the given area argument must be non-null and must
+ match the regular expression
+
+ <area> ::= <segment>("."<segment>)*
+
+ with
+
+ <segment> ::= [0-9a-z]+
+
+ Whether these macros generate any log output is controlled in a two-stage
+ process.
+
+ First, at compile time the macros SAL_LOG_INFO and SAL_LOG_WARN,
+ respectively, control whether the INFO and WARN macros, respectively,
+ expand to actual code (in case the macro is defined, to any value) or to
+ no-ops (in case the macro is not defined).
+
+ Second, at runtime the environment variable SAL_LOG further limits which
+ macro calls actually generate log output. The environment variable SAL_LOG
+ must either be unset or must match the regular expression
+
+ <env> ::= <switch>*
+
+ with
+
+ <switch> ::= <sense><level>("."<area>)?
+ <sense> ::= "+"|"-"
+ <level> ::= "INFO"|"WARN"
+
+ 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).
+
+ 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
+ the given level and for which the area is a prefix (including both empty and
+ full prefixes) of the given area are considered. Log output is generated if
+ and only if among the longest such switches (if any), there is at least one
+ that has a sense of "+". (That is, if both +INFO.foo and -INFO.foo are
+ present, +INFO.foo wins.)
+
+ 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.
+
+ @since LibreOffice 3.5
+*/
+
+#if defined SAL_LOG_INFO
+
+#define SAL_INFO(area, ...) \
+ SAL_DETAIL_LOG_FORMAT( \
+ sal_True, SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, __VA_ARGS__)
+#define SAL_INFO_IF(condition, area, ...) \
+ SAL_DETAIL_LOG_FORMAT( \
+ condition, SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, __VA_ARGS__)
+
+#if defined __cplusplus
+#define SAL_INFO_S(area, stream) \
+ SAL_DETAIL_LOG_STREAM( \
+ true, ::SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, stream)
+#define SAL_INFO_IF_S(condition, area, stream) \
+ SAL_DETAIL_LOG_STREAM( \
+ condition, ::SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, stream)
+#endif
+
+#else
+
+#define SAL_INFO(area, format, ...) ((void) 0)
+#define SAL_INFO_IF(condition, area, format, ...) ((void) 0)
+
+#if defined __cplusplus
+#define SAL_INFO_S(area, stream) ((void) 0)
+#define SAL_INFO_IF_S(condition, area, stream) ((void) 0)
+#endif
+
+#endif
+
+#if defined SAL_LOG_WARN
+
+#define SAL_WARN(area, ...) \
+ SAL_DETAIL_LOG_FORMAT( \
+ sal_True, SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, __VA_ARGS__)
+#define SAL_WARN_IF(condition, area, ...) \
+ SAL_DETAIL_LOG_FORMAT( \
+ condition, SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, __VA_ARGS__)
+
+#if defined __cplusplus
+#define SAL_WARN_S(area, stream) \
+ SAL_DETAIL_LOG_STREAM( \
+ true, ::SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, stream)
+#define SAL_WARN_IF_S(condition, area, stream) \
+ SAL_DETAIL_LOG_STREAM( \
+ condition, ::SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, stream)
+#endif
+
+#else
+
+#define SAL_WARN(area, format, ...) ((void) 0)
+#define SAL_WARN_IF(condition, area, format, ...) ((void) 0)
+
+#if defined __cplusplus
+#define SAL_WARN_S(area, stream) ((void) 0)
+#define SAL_WARN_IF_S(condition, area, stream) ((void) 0)
+#endif
+
+#endif
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */