You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
6.4 KiB
242 lines
6.4 KiB
// Copyright (C) 2010, Vaclav Haisman. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modifica-
|
|
// tion, are permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
// APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
|
|
// DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include <log4cplus/helpers/snprintf.h>
|
|
#include <log4cplus/helpers/loglog.h>
|
|
#include <log4cplus/internal/internal.h>
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
#if defined (UNICODE)
|
|
#include <cwchar>
|
|
#endif
|
|
#if defined (LOG4CPLUS_HAVE_STDARG_H)
|
|
# include <stdarg.h>
|
|
#endif
|
|
#if defined (LOG4CPLUS_HAVE_WCHAR_H)
|
|
# include <wchar.h>
|
|
#endif
|
|
#if defined (LOG4CPLUS_HAVE_STDIO_H)
|
|
# include <stdio.h>
|
|
#endif
|
|
|
|
|
|
namespace log4cplus { namespace helpers {
|
|
|
|
|
|
std::size_t const START_BUF_SIZE = 512;
|
|
|
|
#if defined (_WIN32)
|
|
char const NULL_FILE[] = "NUL";
|
|
#else
|
|
char const NULL_FILE[] = "/dev/null";
|
|
#endif
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
|
|
#if defined (LOG4CPLUS_USE_POOR_MANS_SNPRINTF)
|
|
|
|
static inline int vftprintf (std::FILE * file, tchar const * fmt,
|
|
std::va_list args) LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 2, 0);
|
|
|
|
static inline
|
|
int
|
|
vftprintf (std::FILE * file, tchar const * fmt, std::va_list args)
|
|
{
|
|
#if defined (UNICODE)
|
|
# if defined (LOG4CPLUS_HAVE_VFWPRINTF_S)
|
|
return vfwprintf_s (file, fmt, args);
|
|
# else
|
|
return std::vfwprintf (file, fmt, args);
|
|
# endif
|
|
#else
|
|
# if defined (LOG4CPLUS_HAVE_VFPRINTF_S)
|
|
return vfprintf_s (file, fmt, args);
|
|
# else
|
|
return std::vfprintf (file, fmt, args);
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
|
|
static inline int vstprintf (tchar * dest, std::size_t dest_size,
|
|
tchar const * fmt, std::va_list args)
|
|
LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 0);
|
|
|
|
static inline
|
|
int
|
|
vstprintf (tchar * dest, std::size_t dest_size, tchar const * fmt,
|
|
std::va_list args)
|
|
{
|
|
int ret;
|
|
#if defined (UNICODE)
|
|
# if defined (LOG4CPLUS_HAVE_VSWPRINTF_S)
|
|
ret = vswprintf_s (dest, dest_size, fmt, args);
|
|
# else
|
|
ret = std::vswprintf (dest, dest_size, fmt, args);
|
|
# endif
|
|
#else
|
|
# if defined (LOG4CPLUS_HAVE_VSPRINTF_S)
|
|
ret = vsprintf_s (dest, dest_size, fmt, args);
|
|
# else
|
|
ret = std::vsprintf (dest, fmt, args);
|
|
# endif
|
|
#endif
|
|
|
|
if (ret >= 0)
|
|
assert (static_cast<std::size_t>(ret) <= dest_size);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#else /* ?defined (LOG4CPLUS_USE_POOR_MANS_SNPRINTF) */
|
|
|
|
static inline int vsntprintf (tchar * dest, std::size_t dest_size,
|
|
tchar const * fmt, std::va_list args)
|
|
LOG4CPLUS_FORMAT_ATTRIBUTE (__printf__, 3, 0);
|
|
|
|
static inline
|
|
int
|
|
vsntprintf (tchar * dest, std::size_t dest_size, tchar const * fmt,
|
|
std::va_list args)
|
|
{
|
|
int ret;
|
|
|
|
#if defined (UNICODE)
|
|
# if defined (LOG4CPLUS_HAVE__VSNWPRINTF_S) && defined (_TRUNCATE)
|
|
ret = _vsnwprintf_s (dest, dest_size, _TRUNCATE, fmt, args);
|
|
# else
|
|
ret = std::vswprintf (dest, dest_size, fmt, args);
|
|
# endif
|
|
#else
|
|
# if defined (LOG4CPLUS_HAVE_VSNPRINTF_S) && defined (_TRUNCATE)
|
|
ret = vsnprintf_s (dest, dest_size, _TRUNCATE, fmt, args);
|
|
# elif defined (LOG4CPLUS_HAVE__VSNPRINTF_S) && defined (_TRUNCATE)
|
|
ret = _vsnprintf_s (dest, dest_size, _TRUNCATE, fmt, args);
|
|
# elif defined (LOG4CPLUS_HAVE_VSNPRINTF)
|
|
ret = vsnprintf (dest, dest_size, fmt, args);
|
|
# elif defined (LOG4CPLUS_HAVE__VSNPRINTF)
|
|
ret = _vsnprintf (dest, dest_size, fmt, args);
|
|
# else
|
|
# error "None of vsnprintf_s, _vsnprintf_s, vsnprintf or _vsnprintf is available."
|
|
# endif
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
snprintf_buf::snprintf_buf ()
|
|
: buf (START_BUF_SIZE)
|
|
{ }
|
|
|
|
|
|
tchar const *
|
|
snprintf_buf::print (tchar const * fmt, ...)
|
|
{
|
|
assert (fmt);
|
|
|
|
std::va_list args;
|
|
va_start (args, fmt);
|
|
tchar const * ret = print_va_list (fmt, args);
|
|
va_end (args);
|
|
return ret;
|
|
}
|
|
|
|
|
|
tchar const *
|
|
snprintf_buf::print_va_list(tchar const * fmt, std::va_list args)
|
|
{
|
|
int printed;
|
|
std::size_t const fmt_len = std::char_traits<tchar>::length (fmt);
|
|
std::size_t buf_size = buf.size ();
|
|
std::size_t const output_estimate = fmt_len + fmt_len / 2 + 1;
|
|
if (output_estimate > buf_size)
|
|
buf.resize (output_estimate);
|
|
|
|
#if defined (LOG4CPLUS_USE_POOR_MANS_SNPRINTF)
|
|
std::FILE * & fnull = internal::get_ptd ()->fnull;
|
|
if (! fnull)
|
|
{
|
|
fnull = std::fopen (NULL_FILE, "wb");
|
|
if (! fnull)
|
|
{
|
|
LogLog::getLogLog ()->error (
|
|
LOG4CPLUS_TEXT ("Could not open NULL_FILE."));
|
|
buf.clear ();
|
|
buf.push_back (0);
|
|
return &buf[0];
|
|
}
|
|
}
|
|
|
|
printed = vftprintf (fnull, fmt, args);
|
|
if (printed == -1)
|
|
{
|
|
LogLog::getLogLog ()->error (
|
|
LOG4CPLUS_TEXT ("Error printing into NULL_FILE."));
|
|
buf.clear ();
|
|
buf.push_back (0);
|
|
return &buf[0];
|
|
}
|
|
|
|
buf.resize (printed + 1);
|
|
int sprinted = vstprintf (&buf[0], buf.size (), fmt, args);
|
|
if (sprinted == -1)
|
|
{
|
|
LogLog::getLogLog ()->error (
|
|
LOG4CPLUS_TEXT ("Error printing into string."));
|
|
buf.clear ();
|
|
buf.push_back (0);
|
|
return &buf[0];
|
|
}
|
|
assert (printed == sprinted);
|
|
|
|
buf[sprinted] = 0;
|
|
|
|
#else
|
|
do
|
|
{
|
|
printed = vsntprintf (&buf[0], buf_size - 1, fmt, args);
|
|
if (printed == -1)
|
|
{
|
|
buf_size *= 2;
|
|
buf.resize (buf_size);
|
|
}
|
|
else
|
|
buf[printed] = 0;
|
|
}
|
|
while (printed == -1);
|
|
|
|
#endif
|
|
|
|
return &buf[0];
|
|
}
|
|
|
|
|
|
} } // namespace log4cplus { namespace helpers
|