server/dep/acelite/ace/OS_NS_stdio.cpp
2020-02-16 01:55:18 +00:00

1598 lines
47 KiB
C++

#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_Thread.h"
#if !defined (ACE_HAS_INLINED_OSCALLS)
# include "ace/OS_NS_stdio.inl"
#endif /* ACE_HAS_INLINED_OSCALLS */
#if !defined (ACE_LACKS_STDINT_H)
# include <stdint.h>
#endif
#include "ace/Malloc_Base.h"
#include <cctype>
#include <clocale>
#include <cmath>
#ifndef ACE_LACKS_WCHAR_H
# include <cwchar>
#endif
# if defined (ACE_WIN32)
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
ACE_TEXT_OSVERSIONINFO ACE_OS::win32_versioninfo_;
HINSTANCE ACE_OS::win32_resource_module_;
ACE_END_VERSIONED_NAMESPACE_DECL
# if defined (ACE_HAS_DLL) && (ACE_HAS_DLL == 1) && !defined (ACE_HAS_WINCE)
// This function is called by the OS when the ACE DLL is loaded. We
// use it to determine the default module containing ACE's resources.
extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
{
# if defined (ACE_DISABLES_THREAD_LIBRARY_CALLS) && (ACE_DISABLES_THREAD_LIBRARY_CALLS == 1)
::DisableThreadLibraryCalls (instance);
# endif /* ACE_DISABLES_THREAD_LIBRARY_CALLS */
ACE_OS::set_win32_resource_module(instance);
}
else if (reason == DLL_THREAD_DETACH)
{
ACE_OS::cleanup_tss (0);
}
return TRUE;
}
# endif /* ACE_HAS_DLL && ACE_HAS_DLL == 1 */
# endif /* ACE_WIN32 */
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
namespace ACE_OS
{
void
ace_flock_t::dump (void) const
{
#if defined (ACE_HAS_DUMP)
ACE_OS_TRACE ("ACE_OS::ace_flock_t::dump");
# if 0
ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("handle_ = %u"), this->handle_));
# if defined (ACE_WIN32)
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nInternal = %d"),
this->overlapped_.Internal));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nInternalHigh = %d"),
this->overlapped_.InternalHigh));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nOffsetHigh = %d"),
this->overlapped_.OffsetHigh));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nhEvent = %d"),
this->overlapped_.hEvent));
# else
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_whence = %d"),
this->lock_.l_whence));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_start = %d"), this->lock_.l_start));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_len = %d"), this->lock_.l_len));
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nl_type = %d"), this->lock_.l_type));
# endif /* ACE_WIN32 */
ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
# endif /* 0 */
#endif /* ACE_HAS_DUMP */
}
} /* namespace ACE_OS */
/*****************************************************************************/
#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
namespace
{
/// Translate fopen's mode char to open's mode. This helper function
/// is here to avoid maintaining several pieces of identical code.
void
fopen_mode_to_open_mode_converter (ACE_TCHAR x, int & hmode)
{
switch (x)
{
case ACE_TEXT ('r'):
if (ACE_BIT_DISABLED (hmode, _O_RDWR))
{
ACE_CLR_BITS (hmode, _O_WRONLY);
ACE_SET_BITS (hmode, _O_RDONLY);
}
break;
case ACE_TEXT ('w'):
if (ACE_BIT_DISABLED (hmode, _O_RDWR))
{
ACE_CLR_BITS (hmode, _O_RDONLY);
ACE_SET_BITS (hmode, _O_WRONLY);
}
ACE_SET_BITS (hmode, _O_CREAT | _O_TRUNC);
break;
case ACE_TEXT ('a'):
if (ACE_BIT_DISABLED (hmode, _O_RDWR))
{
ACE_CLR_BITS (hmode, _O_RDONLY);
ACE_SET_BITS (hmode, _O_WRONLY);
}
ACE_SET_BITS (hmode, _O_CREAT | _O_APPEND);
break;
case ACE_TEXT ('+'):
ACE_CLR_BITS (hmode, _O_RDONLY | _O_WRONLY);
ACE_SET_BITS (hmode, _O_RDWR);
break;
case ACE_TEXT ('t'):
ACE_CLR_BITS (hmode, _O_BINARY);
ACE_SET_BITS (hmode, _O_TEXT);
break;
case ACE_TEXT ('b'):
ACE_CLR_BITS (hmode, _O_TEXT);
ACE_SET_BITS (hmode, _O_BINARY);
break;
}
}
} // Close anonymous namespace
FILE *
ACE_OS::fopen (const char *filename,
const ACE_TCHAR *mode)
{
ACE_OS_TRACE ("ACE_OS::fopen");
#if defined (ACE_LACKS_FOPEN)
ACE_UNUSED_ARG (filename);
ACE_UNUSED_ARG (mode);
ACE_NOTSUP_RETURN (0);
#else
int hmode = _O_TEXT;
// Let the chips fall where they may if the user passes in a NULL
// mode string. Convert to an empty mode string to prevent a
// crash.
ACE_TCHAR const empty_mode[] = ACE_TEXT ("");
if (!mode)
mode = empty_mode;
for (ACE_TCHAR const* mode_ptr = mode; *mode_ptr != 0; ++mode_ptr)
fopen_mode_to_open_mode_converter (*mode_ptr, hmode);
ACE_HANDLE const handle = ACE_OS::open (filename, hmode);
if (handle != ACE_INVALID_HANDLE)
{
hmode &= _O_TEXT | _O_RDONLY | _O_APPEND;
int const fd = ::_open_osfhandle (intptr_t (handle), hmode);
if (fd != -1)
{
# if defined (ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)
FILE * const fp = ::_fdopen (fd, const_cast<ACE_TCHAR *> (mode));
# elif defined (ACE_HAS_NONCONST_FDOPEN) && defined (ACE_USES_WCHAR)
FILE * const fp = ::_wfdopen (fd, const_cast<ACE_TCHAR *> (mode));
# elif defined (ACE_USES_WCHAR)
FILE * const fp = ::_wfdopen (fd, mode);
# else
FILE * const fp = ::fdopen (fd, mode);
# endif /* defined(ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)) */
if (fp != 0)
{
return fp;
}
::_close (fd);
}
ACE_OS::close (handle);
}
return 0;
#endif
}
#if defined (ACE_HAS_WCHAR)
FILE *
ACE_OS::fopen (const char *filename,
const ACE_ANTI_TCHAR *mode)
{
return ACE_OS::fopen (filename, ACE_TEXT_ANTI_TO_TCHAR (mode));
}
FILE *
ACE_OS::fopen (const wchar_t *filename,
const ACE_ANTI_TCHAR *mode)
{
return ACE_OS::fopen (filename, ACE_TEXT_ANTI_TO_TCHAR (mode));
}
FILE *
ACE_OS::fopen (const wchar_t *filename,
const ACE_TCHAR *mode)
{
ACE_OS_TRACE ("ACE_OS::fopen");
#if defined (ACE_LACKS_FOPEN)
ACE_UNUSED_ARG (filename);
ACE_UNUSED_ARG (mode);
ACE_NOTSUP_RETURN (0);
#else
int hmode = _O_TEXT;
for (const ACE_TCHAR *mode_ptr = mode; *mode_ptr != 0; mode_ptr++)
fopen_mode_to_open_mode_converter (*mode_ptr, hmode);
ACE_HANDLE handle = ACE_OS::open (filename, hmode);
if (handle != ACE_INVALID_HANDLE)
{
hmode &= _O_TEXT | _O_RDONLY | _O_APPEND;
int const fd = ::_open_osfhandle (intptr_t (handle), hmode);
if (fd != -1)
{
# if defined (ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)
FILE *fp = ::_fdopen (fd, const_cast<char *> (mode));
# elif defined (ACE_HAS_NONCONST_FDOPEN) && defined (ACE_USES_WCHAR)
FILE *fp = ::_wfdopen (fd, const_cast<wchar_t *> (mode));
# elif defined (ACE_USES_WCHAR)
FILE *fp = ::_wfdopen (fd, mode);
# else
FILE *fp = ::fdopen (fd, mode);
# endif /* defined(ACE_HAS_NONCONST_FDOPEN) && !defined (ACE_USES_WCHAR)) */
if (fp != 0)
{
return fp;
}
::_close (fd);
}
ACE_OS::close (handle);
}
return 0;
#endif
}
#endif /* ACE_HAS_WCHAR */
#endif /* ACE_WIN32 */
#ifndef ACE_STDIO_USE_STDLIB_FOR_VARARGS
// The following *printf functions aren't inline because
// they use varargs.
int
ACE_OS::fprintf (FILE *fp, const char *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::fprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (fp);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vfprintf (fp, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_STDIO_USE_STDLIB_FOR_VARARGS */
#if defined (ACE_HAS_WCHAR)
int
ACE_OS::fprintf (FILE *fp, const wchar_t *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::fprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (fp);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vfprintf (fp, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_HAS_WCHAR */
int
ACE_OS::asprintf (char **bufp, const char *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::asprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (bufp);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vasprintf (bufp, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#if defined (ACE_HAS_WCHAR)
int
ACE_OS::asprintf (wchar_t **bufp, const wchar_t *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::asprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (bufp);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vasprintf (bufp, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_HAS_WCHAR */
#if !defined ACE_FACE_DEV || !defined ACE_STDIO_USE_STDLIB_FOR_VARARGS
int
ACE_OS::printf (const char *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::printf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vprintf (format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* !ACE_FACE_DEV || !ACE_STDIO_USE_STDLIB_FOR_VARARGS */
#if defined (ACE_HAS_WCHAR)
int
ACE_OS::printf (const wchar_t *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::printf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vprintf (format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_HAS_WCHAR */
#if !defined ACE_STDIO_USE_STDLIB_FOR_VARARGS || defined ACE_LACKS_SNPRINTF
int
ACE_OS::snprintf (char *buf, size_t maxlen, const char *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::snprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (buf);
ACE_UNUSED_ARG (maxlen);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vsnprintf (buf, maxlen, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_STDIO_USE_STDLIB_FOR_VARARGS */
#if defined (ACE_HAS_WCHAR)
int
ACE_OS::snprintf (wchar_t *buf, size_t maxlen, const wchar_t *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::snprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (buf);
ACE_UNUSED_ARG (maxlen);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vsnprintf (buf, maxlen, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_HAS_WCHAR */
int
ACE_OS::sprintf (char *buf, const char *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::sprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (buf);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vsprintf (buf, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#if defined (ACE_HAS_WCHAR)
int
ACE_OS::sprintf (wchar_t *buf, const wchar_t *format, ...)
{
// ACE_OS_TRACE ("ACE_OS::sprintf");
#if defined (ACE_LACKS_VA_FUNCTIONS)
ACE_UNUSED_ARG (buf);
ACE_UNUSED_ARG (format);
ACE_NOTSUP_RETURN (-1);
#else
va_list ap;
va_start (ap, format);
int const result = ACE_OS::vsprintf (buf, format, ap);
va_end (ap);
return result;
#endif /* ACE_LACKS_VA_FUNCTIONS */
}
#endif /* ACE_HAS_WCHAR */
#if !defined (ACE_HAS_VASPRINTF) && !defined (ACE_LACKS_VA_COPY)
int
ACE_OS::vasprintf_emulation(char **bufp, const char *format, va_list argptr)
{
va_list ap;
va_copy (ap, argptr);
int size = ACE_OS::vsnprintf (0, 0, format, ap);
va_end (ap);
if (size != -1)
{
char *buf = reinterpret_cast<char*>(ACE_OS::malloc(size + 1));
if (!buf)
return -1;
va_list aq;
va_copy (aq, argptr);
size = ACE_OS::vsnprintf(buf, size + 1, format, aq);
va_end (aq);
if (size != -1)
*bufp = buf;
}
return size;
}
#endif
#if !defined (ACE_HAS_VASWPRINTF) && !defined (ACE_LACKS_VA_COPY)
#if defined (ACE_HAS_WCHAR)
int
ACE_OS::vaswprintf_emulation(wchar_t **bufp, const wchar_t *format, va_list argptr)
{
va_list ap;
va_copy (ap, argptr);
int size = ACE_OS::vsnprintf(0, 0, format, ap);
va_end (ap);
if (size != -1)
{
wchar_t *buf = reinterpret_cast<wchar_t*>
(ACE_OS::malloc((size + 1) * sizeof(wchar_t)));
if (!buf)
return -1;
va_list aq;
va_copy (aq, argptr);
size = ACE_OS::vsnprintf(buf, size + 1, format, aq);
va_end (aq);
if (size != -1)
*bufp = buf;
}
return size;
}
#endif /* ACE_HAS_WCHAR */
#endif /* !ACE_HAS_VASPRINTF */
#if defined (ACE_HAS_VSNPRINTF_EMULATION)
#ifdef ACE_LACKS_WCHAR_H
typedef int wint_t;
#elif !defined ACE_LACKS_WCHAR_STD_NAMESPACE
using std::wint_t;
# ifndef ACE_LACKS_WCSRTOMBS
using std::wcsrtombs;
# endif
#endif
namespace { // helpers for vsnprintf_emulation
enum Flag { SNPRINTF_NONE, SNPRINTF_GROUP, SNPRINTF_LEFT,
SNPRINTF_SIGN = 4, SNPRINTF_SPACE = 8, SNPRINTF_ALT = 0x10,
SNPRINTF_ZERO = 0x20, SNPRINTF_CHAR = 0x40, SNPRINTF_SHORT = 0x80,
SNPRINTF_LONG = 0x100, SNPRINTF_LONGLONG = 0x200, SNPRINTF_INTMAX = 0x400,
SNPRINTF_SIZET = 0x800, SNPRINTF_PTRDIFF = 0x1000,
SNPRINTF_LONGDOUBLE = 0x2000, SNPRINTF_UCASE = 0x4000,
SNPRINTF_UNSIGNED = 0x8000, SNPRINTF_NEGATIVE = 0x10000,
SNPRINTF_EXPONENT = 0x20000, SNPRINTF_FLEXPONENT = 0x40000,
SNPRINTF_HEXPONENT = 0x80000,
SNPRINTF_LARGE_INT = (SNPRINTF_LONG|SNPRINTF_LONGLONG|SNPRINTF_INTMAX|
SNPRINTF_SIZET|SNPRINTF_PTRDIFF)
};
struct Snprintf_Flags
{
Snprintf_Flags ()
: val_ (SNPRINTF_NONE)
{}
explicit Snprintf_Flags (const char *&fmt)
: val_ (SNPRINTF_NONE)
{
this->parse_flags (fmt);
if (this->has (SNPRINTF_LEFT))
this->remove (SNPRINTF_ZERO);
if (this->has (SNPRINTF_SIGN))
this->remove (SNPRINTF_SPACE);
}
void parse_flags (const char *&fmt)
{
for (; true; ++fmt)
{
switch (*fmt)
{
// ' used as a flag is a POSIX extension to ISO std C
case '\'': this->add (SNPRINTF_GROUP); break;
case '-': this->add (SNPRINTF_LEFT); break;
case '+': this->add (SNPRINTF_SIGN); break;
case ' ': this->add (SNPRINTF_SPACE); break;
case '#': this->add (SNPRINTF_ALT); break;
case '0': this->add (SNPRINTF_ZERO); break;
default: return;
}
}
}
void parse_length (const char *&fmt)
{
if (fmt[0] == 'h' && fmt[1] == 'h')
this->add (SNPRINTF_CHAR), fmt += 2;
else if (fmt[0] == 'h')
this->add (SNPRINTF_SHORT), ++fmt;
else if (fmt[0] == 'l' && fmt[1] == 'l')
this->add (SNPRINTF_LONGLONG), fmt += 2;
else if (fmt[0] == 'l')
this->add (SNPRINTF_LONG), ++fmt;
else if (fmt[0] == 'j')
this->add (SNPRINTF_INTMAX), ++fmt;
else if (fmt[0] == 'z')
this->add (SNPRINTF_SIZET), ++fmt;
else if (fmt[0] == 't')
this->add (SNPRINTF_PTRDIFF), ++fmt;
else if (fmt[0] == 'L')
this->add (SNPRINTF_LONGDOUBLE), ++fmt;
}
void width (int &w)
{
if (w < 0)
{
this->add (SNPRINTF_LEFT);
w = -w;
}
}
template <typename T>
void value (T &v)
{
if (v < 0)
{
this->add (SNPRINTF_NEGATIVE);
v = -v;
}
}
void conv_spec (char &c)
{
if (std::isupper (c))
{
if (c == 'C' || c == 'S') // C,S specs are POSIX extensions
this->add (SNPRINTF_LONG);
else
this->add (SNPRINTF_UCASE);
c = std::tolower (c);
}
switch (c)
{
case 'o': case 'u': case 'x': this->add (SNPRINTF_UNSIGNED); break;
case 'p': this->add (SNPRINTF_ALT); break;
case 'e': this->add (SNPRINTF_EXPONENT); break;
case 'g': this->add (SNPRINTF_FLEXPONENT); break;
case 'a': this->add (SNPRINTF_HEXPONENT); break;
default: break;
}
}
void add (Flag f) { this->val_ |= f; }
void remove (Flag f) { this->val_ &= ~f; }
bool has (Flag f) const { return (this->val_ & f) == f; }
bool has_some (Flag f) const { return this->val_ & f; }
int val_;
};
struct Snprintf_Digit_Grouping
{
Snprintf_Digit_Grouping (Snprintf_Flags flags, const char *grouping,
char thousands)
: grouping_ (flags.has (SNPRINTF_GROUP) ? grouping : 0)
, separator_ (flags.has (SNPRINTF_GROUP) ? *grouping : CHAR_MAX)
, next_sep_ (this->separator_)
, thousands_ (thousands)
{
if (!this->separator_)
{
this->grouping_ = 0;
this->separator_ = this->next_sep_ = CHAR_MAX;
}
}
int separators_needed (int digits) const
{
if (!this->grouping_)
return 0;
const char *grouping = this->grouping_;
int group = *grouping;
int separators = 0;
while (group > 0 && group < CHAR_MAX && digits > group)
{
digits -= group;
++separators;
if (grouping[1])
group = *++grouping;
}
return separators;
}
bool next (char *&buf)
{
const bool separate = this->next_sep_ == 0;
if (separate)
{
*--buf = this->thousands_;
if (this->grouping_[1])
this->separator_ = *++this->grouping_;
this->next_sep_ = this->separator_;
}
if (this->next_sep_ > 0 && this->next_sep_ < CHAR_MAX)
--this->next_sep_;
return separate;
}
const char *grouping_;
int separator_, next_sep_;
const char thousands_;
};
struct Snprintf_Buffer
{
Snprintf_Buffer (char *buf, size_t max)
: buf_ (buf)
, avail_ (max - 1) // last byte is not available for writes, must be null
, written_ (0)
{}
void out (const char *s, size_t n)
{
if (n == 0)
return;
const size_t m = n > this->avail_ ? this->avail_ : n;
ACE_OS::memcpy (this->buf_, s, m);
this->buf_ += m;
this->avail_ -= m;
this->written_ += n;
}
void fill (char c, size_t n)
{
if (n == 0)
return;
const size_t m = n > this->avail_ ? this->avail_ : n;
ACE_OS::memset (this->buf_, c, m);
this->buf_ += m;
this->avail_ -= m;
this->written_ += n;
}
void pad (const char *s, size_t n, Snprintf_Flags flags, int width)
{
const int used = static_cast<int> (n);
if (!flags.has (SNPRINTF_LEFT) && width > used)
this->fill (' ', width - used);
this->out (s, n);
if (flags.has (SNPRINTF_LEFT) && width > used)
this->fill (' ', width - used);
}
void conv_int (ACE_UINT64 val, Snprintf_Flags flags,
int width, int precision, int base = 10)
{
if (val == 0 && precision == 0)
{
if (flags.has (SNPRINTF_SPACE) && !flags.has (SNPRINTF_UNSIGNED))
this->fill (' ', 1);
if (flags.has (SNPRINTF_ALT) && base == 8)
this->fill ('0', 1);
return;
}
if (precision >= 0)
flags.remove (SNPRINTF_ZERO);
if (precision == -1)
precision = 1;
#ifdef ACE_LACKS_LOCALECONV
static const char thousands_sep = 0;
static const char grouping[] = "";
#else
# ifdef localeconv
# undef localeconv
# endif
const std::lconv *const conv = std::localeconv ();
const char thousands_sep =
conv && *conv->thousands_sep ? *conv->thousands_sep : ',';
const char *grouping = conv ? conv->grouping : "";
#endif
if (base != 10)
flags.remove (SNPRINTF_GROUP);
Snprintf_Digit_Grouping dg (flags, grouping, thousands_sep);
char buf[100];
char *it = buf + sizeof buf;
const char a = flags.has (SNPRINTF_UCASE) ? 'A' : 'a';
int sep_chars = 0;
for (ACE_UINT64 v = val; v; v /= base)
{
if (dg.next (it))
++sep_chars;
*--it = static_cast<char> (v % base < 10 ?
'0' + v % base : a + v % base - 10);
}
const int digits = static_cast<int> (buf + sizeof buf - it - sep_chars);
if (base == 8 && flags.has (SNPRINTF_ALT) && precision <= digits)
precision = digits + 1;
if (flags.has (SNPRINTF_NEGATIVE))
*--it = '-';
else if (flags.has (SNPRINTF_SPACE) && !flags.has (SNPRINTF_UNSIGNED))
*--it = ' ';
else if (flags.has (SNPRINTF_SIGN) && !flags.has (SNPRINTF_UNSIGNED))
*--it = '+';
const bool has_sign = it < buf + sizeof buf - digits - sep_chars;
bool has_0x = false;
if (val != 0 && base == 16 && flags.has (SNPRINTF_ALT))
{
*--it = flags.has (SNPRINTF_UCASE) ? 'X' : 'x';
*--it = '0';
has_0x = true;
}
int padding = 0;
if (flags.has (SNPRINTF_ZERO) || precision > digits)
{
if (precision > digits)
padding = precision - digits;
const int prefix = has_sign ? 1 : (has_0x ? 2 : 0);
if (flags.has (SNPRINTF_ZERO) && width > digits + sep_chars + prefix)
padding = width - digits - prefix - sep_chars;
if (!flags.has (SNPRINTF_LEFT) && digits + padding + prefix < width)
{
this->fill (' ', width - digits - padding - prefix - sep_chars);
width = -1;
}
this->out (it, prefix);
it += prefix;
this->fill ('0', padding);
padding += prefix;
}
this->pad (it, buf + sizeof buf - it, flags, width - padding);
}
void conv_float (long double val, Snprintf_Flags flags,
int width, int precision)
{
char buf[LDBL_MAX_10_EXP + 2];
char *it = buf;
// Find the sign bit manually, signbit() is only available with C99/C++11
const void *const ptr = &val;
const char *const pval = static_cast<const char *> (ptr);
#if ACE_BYTE_ORDER == ACE_LITTLE_ENDIAN
# if defined LDBL_MANT_DIG && LDBL_MANT_DIG == 64
# define SIGN_OFFSET 9
# else
# define SIGN_OFFSET (ACE_SIZEOF_LONG_DOUBLE - 1)
# endif
#else
# define SIGN_OFFSET 0
#endif
if (pval[SIGN_OFFSET] & 0x80)
val = -val, *it++ = '-';
else if (flags.has (SNPRINTF_SIGN))
*it++ = '+';
else if (flags.has (SNPRINTF_SPACE))
*it++ = ' ';
const bool has_sign = it > buf;
if (!(val >= -(std::numeric_limits<long double>::max)()
&& val <= (std::numeric_limits<long double>::max)()))
{
if (val != val)
ACE_OS::strcpy (it, flags.has (SNPRINTF_UCASE) ? "NAN" : "nan");
else
ACE_OS::strcpy (it, flags.has (SNPRINTF_UCASE) ? "INF" : "inf");
this->conv_str (buf, flags, width, -1);
return;
}
#ifdef ACE_LACKS_LOCALECONV
static const char radix = '.', thousands_sep = 0;
static const char grouping[] = "";
#else
const std::lconv *const conv = std::localeconv ();
const char radix = conv ? *conv->decimal_point : '.';
const char thousands_sep =
conv && *conv->thousands_sep ? *conv->thousands_sep : ',';
const char *grouping = conv ? conv->grouping : "";
#endif
const long double log = val > 0 ? std::log10 (val) : 0;
int dig_left = static_cast<int> (1 + ((val >= 1) ? log : 0));
#if defined __HP_aCC && __HP_aCC < 40000
int exp = static_cast<int> (log);
#else
int exp = static_cast<int> (std::floor (log));
#endif
if (flags.has (SNPRINTF_FLEXPONENT))
{
const int p = precision > 0 ? precision : (precision < 0 ? 6 : 1);
precision = p - 1;
if (exp < p && exp >= -4)
precision -= exp;
else
flags.add (SNPRINTF_EXPONENT);
}
if (flags.has (SNPRINTF_EXPONENT))
{
dig_left = 1;
val /= std::pow (10.L, exp);
}
if (flags.has (SNPRINTF_HEXPONENT))
{
*it++ = '0';
*it++ = flags.has (SNPRINTF_UCASE) ? 'X' : 'x';
long double mant = std::frexp (val, &exp);
if (mant != 0)
exp -= 4;
const char a = flags.has (SNPRINTF_UCASE) ? 'A' : 'a';
*it++ = hex_digit (mant, a);
if (precision >= 0 || flags.has (SNPRINTF_ALT) || mant > 0)
*it++ = radix;
for (int i = 0; i < precision || precision == -1; ++i)
{
if ((precision == -1 && mant == 0) || it == buf + sizeof buf - 8)
break;
*it++ = hex_digit (mant, a);
}
flags.add (SNPRINTF_EXPONENT);
*it++ = flags.has (SNPRINTF_UCASE) ? 'P' : 'p';
}
else
{
#if (defined __MINGW32__ && defined __x86_64__) \
|| (defined ACE_VXWORKS && !defined __RTP__)
// Avoid std::modf(long double, long double*) on MinGW-W64 64-bit:
// see https://sourceforge.net/p/mingw-w64/bugs/478
double int_part;
double frac_part = std::modf (static_cast<double> (val), &int_part);
#else
long double int_part;
long double frac_part = std::modf (val, &int_part);
#endif
Snprintf_Digit_Grouping dg (flags, grouping, thousands_sep);
dig_left += dg.separators_needed (dig_left);
for (char *dec = it + dig_left; dec > it; int_part /= 10)
{
dg.next (dec);
*--dec = '0' + static_cast<int> (std::fmod (int_part, 10));
}
it += dig_left;
const char *const frac_start = it;
if (precision == -1)
precision = 6;
if (precision > 0 || flags.has (SNPRINTF_ALT))
*it++ = radix;
for (int i = 0; i < precision && it < buf + sizeof buf; ++i)
{
frac_part *= 10;
const int digit = static_cast<int> (frac_part);
*it++ = '0' + digit;
frac_part -= digit;
}
if (flags.has (SNPRINTF_FLEXPONENT) && !flags.has (SNPRINTF_ALT))
{
for (char *f = it - 1; f >= frac_start; --f)
{
if (*f == '0' || *f == radix)
{
--it;
}
else
{
break;
}
}
}
}
if (flags.has (SNPRINTF_EXPONENT))
{
if (!flags.has (SNPRINTF_HEXPONENT))
*it++ = flags.has (SNPRINTF_UCASE) ? 'E' : 'e';
Snprintf_Buffer sb (it, buf + sizeof buf - it);
Snprintf_Flags exp_flags;
exp_flags.add (SNPRINTF_SIGN);
exp_flags.value (exp);
const int exp_prec = flags.has (SNPRINTF_HEXPONENT) ? 1 : 2;
sb.conv_int (exp, exp_flags, -1, exp_prec);
it = sb.buf_;
}
int used = static_cast<int> (it - buf);
const char *const end = it;
it = buf;
if (flags.has (SNPRINTF_ZERO) && used < width)
{
if (has_sign)
this->fill (*it++, 1);
if (flags.has (SNPRINTF_HEXPONENT))
this->out (it, 2), it += 2;
if (width > used)
this->fill ('0', width - used);
width = -1;
}
this->pad (it, end - it, flags, width);
}
static char hex_digit (long double &mant, char a)
{
mant *= 16;
int m = static_cast<int> (mant);
mant -= m;
return m < 10 ? '0' + m : a + m - 10;
}
void conv_char (unsigned char c, Snprintf_Flags flags, int width)
{
this->pad (reinterpret_cast<char *> (&c), 1, flags, width);
}
void conv_str (const char *str, Snprintf_Flags flags,
int width, int precision)
{
const size_t len = ACE_OS::strlen (str),
n = (precision >= 0 && precision < int (len)) ? precision : len;
this->pad (str, n, flags, width);
}
void conv_str (const wchar_t *str, Snprintf_Flags flags,
int width, int precision)
{
#ifdef ACE_LACKS_WCSRTOMBS
ACE_UNUSED_ARG (str);
this->conv_str ("(error: no wide string conversion)",
flags, width, precision);
#else
std::mbstate_t mbstate = std::mbstate_t ();
const size_t n = 1 + wcsrtombs (0, &str, 0, &mbstate);
char *buf = static_cast<char *> (ACE_Allocator::instance ()->malloc (n));
if (buf)
{
wcsrtombs (buf, &str, n, &mbstate);
this->conv_str (buf, flags, width, precision);
}
ACE_Allocator::instance ()->free (buf);
#endif
}
char *buf_;
size_t avail_, written_;
};
#ifdef EOVERFLOW
# define ACE_SNPRINTF_EOVERFLOW EOVERFLOW
#else
# define ACE_SNPRINTF_EOVERFLOW EINVAL
#endif
int snprintf_read_int (const char *&fmt)
{
char *end = 0;
const unsigned long i = ACE_OS::strtoul (fmt, &end, 10);
fmt = end;
if (i > INT_MAX)
{
errno = ACE_SNPRINTF_EOVERFLOW;
return -1;
}
return static_cast<int> (i);
}
int snprintf_positional (const char *&fmt)
{
const char *f = fmt;
const int i = snprintf_read_int (f);
if (i > 0 && *f == '$')
{
fmt = f + 1;
return i;
}
return 0;
}
struct Snprintf_Positional_Args
{
Snprintf_Positional_Args ()
: pos_arg_ (this->pos_storage_)
, scanned_ (false)
{}
~Snprintf_Positional_Args ()
{
if (this->pos_arg_ != this->pos_storage_)
ACE_Allocator::instance ()->free (this->pos_arg_);
}
struct Positional_Arg
{
Positional_Arg ()
: type_ (PA_UNUSED)
{}
enum {
PA_UNUSED,
PA_INT, PA_LONG, PA_LONGLONG, PA_INTMAX, PA_PTRDIFF, PA_SSIZE,
PA_UINT, PA_ULONG, PA_ULONGLONG, PA_UINTMAX, PA_UPTRDIFF, PA_SIZE,
PA_WINT, PA_DOUBLE, PA_LONGDOUBLE,
PA_PCHAR, PA_PWCHAR, PA_PVOID,
PA_PINT, PA_PINTMAX, PA_PLONG, PA_PLONGLONG, PA_PPTRDIFF, PA_PSHORT,
PA_PSCHAR, PA_PSSIZE
} type_;
union
{
int i;
ACE_UINT64 ui64;
ACE_INT64 i64;
long double f;
void *p;
};
};
static void conv_storage_needed (const char *fmt, int &storage_needed)
{
while (const char *f = ACE_OS::strpbrk (fmt, "*%"))
{
if (!*f || *f == '%')
break;
const int p = snprintf_positional (++f);
if (p > storage_needed)
storage_needed = p;
fmt = f;
}
}
void scan (int n, const char *fmt, va_list ap)
{
int storage_needed = n;
const char *f = fmt;
conv_storage_needed (f, storage_needed);
while (const char *const pct = ACE_OS::strchr (f, '%'))
if (pct[1] == '%')
f = pct + 2;
else
{
const int p = snprintf_positional (++f);
if (p > storage_needed)
storage_needed = p;
conv_storage_needed (f, storage_needed);
}
if (size_t (storage_needed) >
sizeof this->pos_storage_ / sizeof (Positional_Arg))
this->pos_arg_ = static_cast<Positional_Arg *> (
ACE_Allocator::instance ()->calloc (
sizeof (Positional_Arg) * storage_needed));
f = fmt;
while (true)
{
static const char digits[] = "0123456789";
f += ACE_OS::strspn (f, "-+ #0'");
if (*f == '*')
(*this)[snprintf_positional (++f)].type_ = Positional_Arg::PA_INT;
else
f += ACE_OS::strspn (f, digits);
if (f[0] == '.' && f[1] == '*')
{
f += 2;
(*this)[snprintf_positional (f)].type_ = Positional_Arg::PA_INT;
}
else if (*f == '.')
{
++f;
f += ACE_OS::strspn (f, digits);
}
Snprintf_Flags flags;
flags.parse_length (f);
switch (*f)
{
case 'd': case 'i':
if (flags.has (SNPRINTF_LONG))
(*this)[n].type_ = Positional_Arg::PA_LONG;
else if (flags.has (SNPRINTF_LONGLONG))
(*this)[n].type_ = Positional_Arg::PA_LONGLONG;
else if (flags.has (SNPRINTF_INTMAX))
(*this)[n].type_ = Positional_Arg::PA_INTMAX;
else if (flags.has (SNPRINTF_SIZET))
(*this)[n].type_ = Positional_Arg::PA_SSIZE;
else if (flags.has (SNPRINTF_PTRDIFF))
(*this)[n].type_ = Positional_Arg::PA_PTRDIFF;
else
(*this)[n].type_ = Positional_Arg::PA_INT;
break;
case 'o': case 'u': case 'x': case 'X':
if (flags.has (SNPRINTF_LONG))
(*this)[n].type_ = Positional_Arg::PA_ULONG;
else if (flags.has (SNPRINTF_LONGLONG))
(*this)[n].type_ = Positional_Arg::PA_ULONGLONG;
else if (flags.has (SNPRINTF_INTMAX))
(*this)[n].type_ = Positional_Arg::PA_UINTMAX;
else if (flags.has (SNPRINTF_SIZET))
(*this)[n].type_ = Positional_Arg::PA_SIZE;
else if (flags.has (SNPRINTF_PTRDIFF))
(*this)[n].type_ = Positional_Arg::PA_UPTRDIFF;
else
(*this)[n].type_ = Positional_Arg::PA_UINT;
break;
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
(*this)[n].type_ = flags.has (SNPRINTF_LONGDOUBLE) ?
Positional_Arg::PA_LONGDOUBLE : Positional_Arg::PA_DOUBLE;
break;
case 'c':
(*this)[n].type_ = flags.has (SNPRINTF_LONG) ?
Positional_Arg::PA_WINT : Positional_Arg::PA_INT;
break;
case 'C':
(*this)[n].type_ = Positional_Arg::PA_WINT;
break;
case 's':
(*this)[n].type_ = flags.has (SNPRINTF_LONG) ?
Positional_Arg::PA_PWCHAR : Positional_Arg::PA_PCHAR;
break;
case 'S':
(*this)[n].type_ = Positional_Arg::PA_PWCHAR;
break;
case 'p':
(*this)[n].type_ = Positional_Arg::PA_PVOID;
break;
case 'n':
if (flags.has (SNPRINTF_LONG))
(*this)[n].type_ = Positional_Arg::PA_PLONG;
else if (flags.has (SNPRINTF_LONGLONG))
(*this)[n].type_ = Positional_Arg::PA_PLONGLONG;
else if (flags.has (SNPRINTF_INTMAX))
(*this)[n].type_ = Positional_Arg::PA_PINTMAX;
else if (flags.has (SNPRINTF_SIZET))
(*this)[n].type_ = Positional_Arg::PA_PSSIZE;
else if (flags.has (SNPRINTF_PTRDIFF))
(*this)[n].type_ = Positional_Arg::PA_PPTRDIFF;
else if (flags.has (SNPRINTF_SHORT))
(*this)[n].type_ = Positional_Arg::PA_PSHORT;
else if (flags.has (SNPRINTF_CHAR))
(*this)[n].type_ = Positional_Arg::PA_PSCHAR;
else
(*this)[n].type_ = Positional_Arg::PA_PINT;
break;
default:
break;
}
// Find the next conversion and set n to the positional arg number
do
f = ACE_OS::strchr (f + 1, '%');
while (f && f[1] == '%' && ++f);
if (!f)
break;
n = snprintf_positional (++f);
}
for (int i = 1; i <= storage_needed; ++i)
switch ((*this)[i].type_)
{
case Positional_Arg::PA_INT:
(*this)[i].i = va_arg (ap, int);
break;
case Positional_Arg::PA_LONG:
(*this)[i].i64 = va_arg (ap, long);
break;
case Positional_Arg::PA_LONGLONG:
(*this)[i].i64 = va_arg (ap, long long);
break;
#ifndef ACE_LACKS_STDINT_H
case Positional_Arg::PA_INTMAX:
(*this)[i].i64 = va_arg (ap, intmax_t);
break;
#endif
case Positional_Arg::PA_PTRDIFF:
(*this)[i].i64 = va_arg (ap, ptrdiff_t);
break;
case Positional_Arg::PA_SSIZE:
(*this)[i].i64 = va_arg (ap, ssize_t);
break;
case Positional_Arg::PA_UINT:
(*this)[i].ui64 = va_arg (ap, unsigned int);
break;
case Positional_Arg::PA_ULONG:
(*this)[i].ui64 = va_arg (ap, unsigned long);
break;
case Positional_Arg::PA_ULONGLONG:
(*this)[i].ui64 = va_arg (ap, unsigned long long);
break;
#ifndef ACE_LACKS_STDINT_H
case Positional_Arg::PA_UINTMAX:
(*this)[i].ui64 = va_arg (ap, uintmax_t);
break;
#endif
case Positional_Arg::PA_UPTRDIFF:
(*this)[i].ui64 = static_cast<uintptr_t> (va_arg (ap, ptrdiff_t));
break;
case Positional_Arg::PA_SIZE:
(*this)[i].ui64 = va_arg (ap, size_t);
break;
#ifdef __MINGW32__
#define ACE_WINT_T_VA_ARG int
#else
#define ACE_WINT_T_VA_ARG wint_t
#endif
case Positional_Arg::PA_WINT:
(*this)[i].ui64 = va_arg (ap, ACE_WINT_T_VA_ARG);
break;
case Positional_Arg::PA_DOUBLE:
(*this)[i].f = va_arg (ap, double);
break;
case Positional_Arg::PA_LONGDOUBLE:
(*this)[i].f = va_arg (ap, long double);
break;
case Positional_Arg::PA_PCHAR:
(*this)[i].p = va_arg (ap, char *);
break;
case Positional_Arg::PA_PWCHAR:
(*this)[i].p = va_arg (ap, wchar_t *);
break;
case Positional_Arg::PA_PVOID:
(*this)[i].p = va_arg (ap, void *);
break;
case Positional_Arg::PA_PINT:
(*this)[i].p = va_arg (ap, int *);
break;
#ifndef ACE_LACKS_STDINT_H
case Positional_Arg::PA_PINTMAX:
(*this)[i].p = va_arg (ap, intmax_t *);
break;
#endif
case Positional_Arg::PA_PLONG:
(*this)[i].p = va_arg (ap, long *);
break;
case Positional_Arg::PA_PLONGLONG:
(*this)[i].p = va_arg (ap, long long *);
break;
case Positional_Arg::PA_PPTRDIFF:
(*this)[i].p = va_arg (ap, ptrdiff_t *);
break;
case Positional_Arg::PA_PSHORT:
(*this)[i].p = va_arg (ap, short *);
break;
case Positional_Arg::PA_PSCHAR:
(*this)[i].p = va_arg (ap, signed char *);
break;
case Positional_Arg::PA_PSSIZE:
(*this)[i].p = va_arg (ap, ssize_t *);
break;
default:
break;
}
this->scanned_ = true;
}
Positional_Arg &operator[] (int idx)
{
return this->pos_arg_[idx - 1];
}
Positional_Arg pos_storage_[10], *pos_arg_;
bool scanned_;
private:
Snprintf_Positional_Args (const Snprintf_Positional_Args&);
Snprintf_Positional_Args& operator= (const Snprintf_Positional_Args&);
};
}
int
ACE_OS::vsnprintf_emulation (char *buf, size_t max, const char *fmt, va_list ap)
{
if (max > INT_MAX)
{
errno = ACE_SNPRINTF_EOVERFLOW;
return -1;
}
Snprintf_Buffer sb (buf, max);
Snprintf_Positional_Args pos_arg;
while (const char *const pct = ACE_OS::strchr (fmt, '%'))
{
// Output up to next % in format string
const bool escaped = pct[1] == '%';
const size_t non_conv = pct - fmt + escaped;
sb.out (fmt, non_conv);
fmt += 1 + non_conv;
if (escaped)
continue;
// Check if positional args are used (%1$d)
const int posn = snprintf_positional (fmt);
if (posn && !pos_arg.scanned_)
pos_arg.scan (posn, fmt, ap); // POSIX extension
// Parse flags (+- #'0)
Snprintf_Flags flags (fmt);
// Parse field width (integer, *, or *n$)
static const int WIDTH_PREC_UNSPEC = -1;
int width = WIDTH_PREC_UNSPEC;
if (*fmt == '*')
{
++fmt;
const int width_p = snprintf_positional (fmt);
width = width_p ? pos_arg[width_p].i : va_arg (ap, int);
flags.width (width);
}
else if (*fmt >= '1' && *fmt <= '9')
{
width = snprintf_read_int (fmt);
if (width == -1)
return -1;
}
// Parse precision (.integer, .*, or .*n$)
int precision = WIDTH_PREC_UNSPEC;
if (fmt[0] == '.' && fmt[1] == '*')
{
fmt += 2;
const int prec_p = snprintf_positional (fmt);
precision = prec_p ? pos_arg[prec_p].i : va_arg (ap, int);
if (precision < 0)
precision = WIDTH_PREC_UNSPEC;
}
else if (*fmt == '.')
{
precision = snprintf_read_int (++fmt);
if (precision == -1)
return -1;
}
flags.parse_length (fmt);
// would be nice to have a helper function for this, but va_list
// can't portably be passed to another function (even by pointer)
#ifdef ACE_LACKS_STDINT_H
# define GET_UNSIGNED_INTMAX
#else
# define GET_UNSIGNED_INTMAX \
else if (flags.has (SNPRINTF_INTMAX)) \
val = va_arg (ap, uintmax_t);
#endif
#define GET_UNSIGNED_VA \
if (posn) \
val = pos_arg[posn].ui64; \
else if (flags.has (SNPRINTF_LONGLONG)) \
val = va_arg (ap, unsigned long long); \
else if (flags.has (SNPRINTF_LONG)) \
val = va_arg (ap, unsigned long); \
GET_UNSIGNED_INTMAX \
else if (flags.has (SNPRINTF_SIZET)) \
val = va_arg (ap, size_t); \
else if (flags.has (SNPRINTF_PTRDIFF)) \
val = static_cast<uintptr_t> (va_arg (ap, ptrdiff_t)); \
else \
val = va_arg (ap, unsigned int); \
if (flags.has (SNPRINTF_SHORT)) \
val = static_cast<unsigned short> (val); \
else if (flags.has (SNPRINTF_CHAR)) \
val = static_cast<unsigned char> (val)
#define GET_ARG(MEMBER, TYPE) \
(posn ? static_cast<TYPE> (pos_arg[posn].MEMBER) : va_arg (ap, TYPE))
ACE_UINT64 val;
ACE_INT64 sval;
long double fval;
wchar_t tmp_wstr[2] = {};
// Parse conversion specifier (diouxXfFeEgGaAcCsSpn) and convert arg
char spec = *fmt++;
flags.conv_spec (spec);
switch (spec)
{
case 'd': case 'i':
if (posn)
sval = flags.has_some (SNPRINTF_LARGE_INT)
? pos_arg[posn].i64 : pos_arg[posn].i;
else if (flags.has (SNPRINTF_LONGLONG))
sval = va_arg (ap, long long);
else if (flags.has (SNPRINTF_LONG))
sval = va_arg (ap, long);
#ifndef ACE_LACKS_STDINT_H
else if (flags.has (SNPRINTF_INTMAX))
sval = va_arg (ap, intmax_t);
#endif
else if (flags.has (SNPRINTF_SIZET))
sval = va_arg (ap, ssize_t);
else if (flags.has (SNPRINTF_PTRDIFF))
sval = va_arg (ap, ptrdiff_t);
else
sval = va_arg (ap, int);
if (flags.has (SNPRINTF_SHORT))
sval = static_cast<short> (sval);
else if (flags.has (SNPRINTF_CHAR))
sval = static_cast<signed char> (sval);
flags.value (sval);
sb.conv_int (sval, flags, width, precision);
break;
case 'o':
GET_UNSIGNED_VA;
sb.conv_int (val, flags, width, precision, 8);
break;
case 'u':
GET_UNSIGNED_VA;
sb.conv_int (val, flags, width, precision);
break;
case 'x':
GET_UNSIGNED_VA;
sb.conv_int (val, flags, width, precision, 16);
break;
case 'f':
fval = posn ? pos_arg[posn].f :
(flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
: va_arg (ap, double));
sb.conv_float (fval, flags, width, precision);
break;
case 'e':
fval = posn ? pos_arg[posn].f :
(flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
: va_arg (ap, double));
sb.conv_float (fval, flags, width, precision);
break;
case 'g':
fval = posn ? pos_arg[posn].f :
(flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
: va_arg (ap, double));
sb.conv_float (fval, flags, width, precision);
break;
case 'a':
fval = posn ? pos_arg[posn].f :
(flags.has (SNPRINTF_LONGDOUBLE) ? va_arg (ap, long double)
: va_arg (ap, double));
sb.conv_float (fval, flags, width, precision);
break;
case 'c':
if (flags.has (SNPRINTF_LONG))
{
*tmp_wstr = static_cast<wchar_t> (
posn ? pos_arg[posn].ui64 : va_arg (ap, ACE_WINT_T_VA_ARG));
sb.conv_str (tmp_wstr, flags, width, precision);
}
else
sb.conv_char (static_cast<unsigned char> (GET_ARG (i, int)),
flags, width);
break;
case 's':
if (flags.has (SNPRINTF_LONG))
sb.conv_str (GET_ARG (p, const wchar_t *), flags, width, precision);
else
sb.conv_str (GET_ARG (p, const char *), flags, width, precision);
break;
case 'p':
val = reinterpret_cast<ACE_UINT64> (GET_ARG (p, void *));
sb.conv_int (val, flags, width, precision, 16);
break;
case 'n':
if (flags.has (SNPRINTF_LONGLONG))
*GET_ARG (p, long long *) = sb.written_;
else if (flags.has (SNPRINTF_LONG))
*GET_ARG (p, long *) = static_cast<long> (sb.written_);
#ifndef ACE_LACKS_STDINT_H
else if (flags.has (SNPRINTF_INTMAX))
*GET_ARG (p, intmax_t *) = sb.written_;
#endif
else if (flags.has (SNPRINTF_SIZET))
*GET_ARG (p, ssize_t *) = sb.written_;
else if (flags.has (SNPRINTF_PTRDIFF))
*GET_ARG (p, ptrdiff_t *) = sb.written_;
else if (flags.has (SNPRINTF_SHORT))
*GET_ARG (p, short *) = static_cast<short> (sb.written_);
else if (flags.has (SNPRINTF_CHAR))
*GET_ARG (p, signed char *) =
static_cast<signed char> (sb.written_);
else
*GET_ARG (p, int *) = static_cast<int> (sb.written_);
break;
default:
break;
}
}
// Output remaining part of format string
sb.out (fmt, ACE_OS::strlen (fmt));
*sb.buf_ = 0;
return static_cast<int> (sb.written_);
}
#endif // ACE_HAS_VSNPRINTF_EMULATION
ACE_END_VERSIONED_NAMESPACE_DECL