/************************************************************************
*
* printf.cpp - definitions of the rw_printf family of functions
*
* $Id: printf.cpp 351515 2005-12-01 23:19:44Z sebor $
*
************************************************************************
*
* Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave
* Software division. Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0. Unless required by
* applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under
* the License.
*
**************************************************************************/
// expand _TEST_EXPORT macros
#define _RWSTD_TEST_SRC
#include <testdefs.h>
#include <printf.h>
#include <assert.h> // for assert
#include <errno.h> // for errno, errno constants
#include <float.h> // for floating point macros
#include <locale.h>
#ifndef __SYMBIAN32__
#include <signal.h> // for signal constant
#endif
#include <stdarg.h> // for va_list, va_start, ...
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#if (defined (_WIN32) || defined (_WIN64)) && !defined(__SYMBIAN32__)
// define macros to enable Win98 + WinNT support in <windows.h>
# define _WIN32_WINNT 0x0410
# define WINVER 0x400
# include <windows.h> // for IsDebuggerPresent()
#else
# include <dlfcn.h>
#endif // _WIN{32,64}
#include <ios>
#include <iostream>
#include <locale>
//#include <string>
#include <string.h>
#ifdef __ARMCC__
#pragma diag_suppress 61
#pragma diag_suppress 63
#endif
#define _RWSTD_NO_EXT_BIN_IO
#define _RWSTD_NO_EXT_REENTRANT_IO
#ifndef __SYMBIAN32__
_RWSTD_NAMESPACE (__rw) {
_RWSTD_EXPORT _RWSTD_SSIZE_T
__rw_memattr (const void*, size_t, int);
}
#endif
/********************************************************************/
static const union {
int ival;
unsigned char bytes [sizeof (int)];
} _rw_one = { 1 };
static const int
_rw_big_endian = '\0' == _rw_one.bytes [0];
/********************************************************************/
struct FmtSpec;
static int
_rw_fmtlong (const FmtSpec&, char**, size_t*, long);
#ifdef _RWSTD_LONG_LONG
static int
_rw_fmtllong (const FmtSpec&, char**, size_t*, _RWSTD_LONG_LONG);
#endif // _RWSTD_LONG_LONG
static int
_rw_fmtinteger (FmtSpec*, size_t, char**, size_t*, va_list*);
static int
_rw_fmtfloating (const FmtSpec&, char**, size_t*, const void*);
_RWSTD_INTERNAL int
_rw_fmtptr (const FmtSpec&, char**, size_t*, const void*);
typedef void (*funptr_t)();
static int
_rw_fmtfunptr (const FmtSpec&, char**, size_t*, funptr_t);
struct DummyStruct;
typedef void (DummyStruct::*memptr_t)() const;
static int
_rw_fmtmemptr (const FmtSpec&, char**, size_t*, memptr_t);
static int
_rw_fmtstr (const FmtSpec&, char**, size_t*, const char*, size_t);
static int
_rw_fmtchr (const FmtSpec&, char**, size_t*, int);
static int
_rw_fmtwchr (const FmtSpec&, char**, size_t*, wint_t);
static int
_rw_fmtwstr (const FmtSpec&, char**, size_t*, const wchar_t*, size_t);
static int
_rw_fmterrno (const FmtSpec&, char**, size_t*, int);
static int
_rw_fmtopenmode (const FmtSpec&, char**, size_t*, int);
static int
_rw_fmtevent (const FmtSpec&, char**, size_t*, int);
static int
_rw_fmtmonpat (const FmtSpec&, char**, size_t*, const char [4]);
static int
_rw_fmtsignal (const FmtSpec&, char**, size_t*, int);
/********************************************************************/
struct FmtSpec
{
// optional flags
unsigned fl_minus : 1;
unsigned fl_plus : 1;
unsigned fl_pound : 1;
unsigned fl_space : 1;
unsigned fl_zero : 1;
// optional modifiers
unsigned mod_A : 1; // extension (Arrays)
unsigned mod_h : 1; // short modifier
unsigned mod_hh : 1; // char modifier
unsigned mod_l : 1; // long modifier
unsigned mod_ll : 1; // long long modifier
unsigned mod_j : 1; // intmax_t modifier
unsigned mod_z : 1; // size_t modifier
unsigned mod_t : 1; // ptrdiff_t modifier
unsigned mod_L : 1; // long double modifier
unsigned mod_I : 1; // extension
unsigned cond : 1; // have an if/else clause
unsigned cond_true : 1; // if/else clause is active (true)
unsigned cond_begin : 1; // beginning of an if/else clause
unsigned cond_end : 1; // end of an if/else clause
// note that the signedness of a bitfield is implementation-defined
// unless explicitly declared signed or unsigned
// extension: 8, 16, 32, and 64 bit integer width modifier
signed int iwidth : 4;
// extension: optional numerical base 2 - 36
signed int base : 7;
// extension: optional parameter number
long paramno;
// optional width and precision
int width;
int prec;
// extension: string argument
char *strarg;
// required conversion specifier
int cvtspec;
// extension: fill character
int fill;
union {
#ifndef _RWSTD_NO_LONG_DOUBLE
long double ldbl;
#endif // _RWSTD_NO_LONG_DOUBLE
#ifdef _RWSTD_LONG_LONG
_RWSTD_LONG_LONG llong;
#endif // _RWSTD_LONG_LONG
void* ptr;
int i;
long lng;
_RWSTD_INT32_T i32;
#ifdef _RWSTD_INT64_T
_RWSTD_INT64_T i64;
#endif // _RWSTD_INT64_T
ptrdiff_t diff;
size_t size;
wint_t wi;
double dbl;
memptr_t memptr;
funptr_t funptr;
} param;
};
/********************************************************************/
/*
C99 format specifier:
% flags width [ . prec ] mod cvtspec
GNU glibc format specifier:
% [ paramno $] flags width [ . prec ] mod cvtspec
or
% [ paramno $] flags width . * [ paramno $] mod cvtspec
Extended format specifier:
% { [ paramno $] [ flags ] [ width [. prec ]] mod cvtspec }
or
% { [ paramno $] [ flags ] [@ base [. width [. prec ]]] mod cvtspec }
or
% { $ envvar }
*/
static int
_rw_fmtspec (FmtSpec *pspec, bool ext, const char *fmt, va_list *pva)
{
assert (0 != pspec);
assert (0 != fmt);
assert (0 != pva);
memset (pspec, 0, sizeof *pspec);
pspec->iwidth = -1; // integer width not specified
pspec->width = -1; // width not specified
pspec->prec = -1; // precision not specified
pspec->base = -1; // base not specified
pspec->paramno = -1; // paramno not specified
const char* const fmtbeg = fmt;
if (ext) {
if ('$' == *fmt) {
++fmt;
const char *str;
if ('*' == *fmt) {
str = va_arg (*pva, char*);
if (!str)
str = "";
++fmt;
}
else {
str = fmt;
fmt += strlen (fmt);
}
char *tmp = (char*)malloc (strlen (str));
pspec->strarg = strcpy (tmp, str);
return int (fmt - fmtbeg);
}
}
// extension: extract the parameter number (if followed by '$')
if ('1' <= *fmt && *fmt <= '9') {
char *end;
const long tmp = strtol (fmt, &end, 10);
fmt = end;
if ('$' == *fmt) {
pspec->paramno = tmp;
++fmt;
}
else {
// when not followed by '$' interpret the number
// as the width (i.e., that follows the empty set
// of flags)
pspec->width = int (tmp);
}
}
if (-1 == pspec->width) {
// extract any number of optional flags
for ( ; ; ++fmt) {
switch (*fmt) {
case '-': pspec->fl_minus = true; continue;
case '+': pspec->fl_plus = true; continue;
case '#': pspec->fl_pound = true; continue;
case ' ': pspec->fl_space = true; continue;
case '0': pspec->fl_zero = true; continue;
}
break;
}
}
if (ext && '@' == *fmt) {
++fmt;
// extract the numerical base
if ('0' <= fmt [1] && fmt [1] <= '9') {
char *end;
pspec->base = int (strtol (fmt, &end, 10));
fmt = end;
}
else if ('*' == *fmt) {
pspec->base = va_arg (*pva, int);
++fmt;
}
if ('.' == *fmt)
++fmt;
}
if (-1 == pspec->width) {
// extract the optional width
if ('0' <= *fmt && *fmt <= '9') {
char *end;
pspec->width = int (strtol (fmt, &end, 10));
fmt = end;
}
else if ('*' == *fmt) {
pspec->width = va_arg (*pva, int);
if (pspec->width < 0) {
// 7.19.6.1, p5 of ISO/IEC 9899:1999:
// A negative field width argument is taken
// as a - flag followed by a positive field width.
pspec->width = -pspec->width;
pspec->fl_minus = true;
}
++fmt;
}
}
// extract the optional precision
if ('.' == *fmt) {
++fmt;
if ('0' <= *fmt && *fmt <= '9') {
char *end;
pspec->prec = int (strtol (fmt, &end, 10));
fmt = end;
}
else if ('*' == *fmt) {
pspec->prec = va_arg (*pva, int);
++fmt;
}
}
// extract an optional modifier
switch (*fmt) {
case 'A':
if (ext) {
++fmt;
pspec->mod_A = true;
break;
}
// fall thru
case 'h':
if ('h' == fmt [1]) {
++fmt;
pspec->mod_hh = true;
}
else
pspec->mod_h = true;
++fmt;
break;
case 'l':
if ('l' == fmt [1]) {
++fmt;
pspec->mod_ll = true;
}
else
pspec->mod_l = true;
++fmt;
break;
case 'j': pspec->mod_j = true; ++fmt; break;
case 'z': pspec->mod_z = true; ++fmt; break;
case 't': pspec->mod_t = true; ++fmt; break;
case 'L': pspec->mod_L = true; ++fmt; break;
case 'I':
if (ext) {
++fmt;
if ('8' == *fmt) {
pspec->iwidth = 1;
++fmt;
}
else if ('1' == fmt [0] && '6' == fmt [1]) {
pspec->iwidth = 2;
fmt += 2;
}
else if ('3' == fmt [0] && '2' == fmt [1]) {
pspec->iwidth = 3;
fmt += 2;
}
else if ('6' == fmt [0] && '4' == fmt [1]) {
pspec->iwidth = 4;
fmt += 2;
}
else {
pspec->mod_I = true;
}
break;
}
}
pspec->cvtspec = *fmt;
if (pspec->cvtspec)
++fmt;
return int (fmt - fmtbeg);
}
/********************************************************************/
_RWSTD_INTERNAL char*
_rw_bufcat (char **pbuf, size_t *pbufsize, const char *str, size_t len)
{
assert (0 != pbuf);
assert (0 != pbufsize);
size_t buflen = *pbuf ? strlen (*pbuf) : 0;
const size_t bufree = *pbuf ? *pbufsize - buflen : 0;
if (bufree <= len || !*pbuf) {
// for guard block
static const char deadbeef[] = "\xde\xad\xbe\xef";
size_t newbufsize = *pbufsize * 2 + 4;
if (newbufsize <= buflen + len + 4)
newbufsize = 2 * (buflen + len + 1) + 4;
char* const newbuf = (char*)malloc (newbufsize);
// return 0 on failure to allocate, let caller deal with it
if (0 == newbuf)
return 0;
memcpy (newbuf, *pbuf, buflen);
// append a guard block to the end of the buffer
memcpy (newbuf + newbufsize - 4, deadbeef, 4);
if (*pbuf) {
// verify that we didn't write past the end of the buffer
assert (0 == memcmp (*pbuf + *pbufsize, deadbeef, 4));
free (*pbuf);
}
*pbuf = newbuf;
*pbufsize = newbufsize - 4;
(*pbuf)[buflen] = '\0';
}
if (0 != str) {
memcpy (*pbuf + buflen, str, len);
buflen += len;
(*pbuf)[buflen] = '\0';
}
return *pbuf + buflen;
}
/********************************************************************/
// rw_asnprintf_cb is called to format a character string according
// to the single format specifier `fmt' to the end of the provided
// buffer `*pbuf'; the function can reallocate the buffer
// returns the number of characters appended to the buffer
extern int
(*rw_vasnprintf_cb)(FmtSpec*, size_t, char**, size_t*, const char*, va_list*);
/********************************************************************/
static int
_rw_vasnprintf_c99 (FmtSpec *pspec, size_t paramno,
char **pbuf, size_t *pbufsize, va_list *pva)
{
_RWSTD_UNUSED (paramno);
_RWSTD_ASSERT (0 != pspec);
int len = -1;
FmtSpec &spec = pspec [paramno];
#define PARAM(T, name) \
(0 < spec.paramno ? pspec [spec.paramno - 1].param.name : va_arg (*pva, T))
switch (spec.cvtspec) {
case 'd':
case 'i':
case 'o':
case 'x':
case 'X':
case 'u':
len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva);
break;
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
if (spec.mod_L) {
spec.param.ldbl = PARAM (long double, ldbl);
len = _rw_fmtfloating (spec, pbuf, pbufsize, &spec.param.ldbl);
}
else {
spec.param.dbl = PARAM (double, dbl);
len = _rw_fmtfloating (spec, pbuf, pbufsize, &spec.param.dbl);
}
break;
case 'a':
assert (!"%a not implemented");
break;
case 'A':
assert (!"%A not implemented");
break;
case 'c':
// If no l length modifier is present, the int argument is converted
// to an unsigned char, and the resulting character is written. If
// an l length modifier is present, the wint_t argument is converted
// as if by an ls conversion specification with no precision and an
// argument that points to the initial element of a two-element array
// of wchar_t, the first element containing the wint_t argument to
// the lc conversion specification and the second a null wide
// character.
if (spec.mod_l) {
spec.param.wi = PARAM (wint_t, wi);
len = _rw_fmtwchr (spec, pbuf, pbufsize, spec.param.wi);
}
else {
spec.param.i = PARAM (int, i);
len = _rw_fmtchr (spec, pbuf, pbufsize, spec.param.i);
}
break;
case 's':
if (spec.mod_l) {
spec.param.ptr = PARAM (wchar_t*, ptr);
const wchar_t* const str = (wchar_t*)spec.param.ptr;
len = _rw_fmtwstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX);
}
else {
spec.param.ptr = PARAM (char*, ptr);
const char* const str = (char*)spec.param.ptr;
len = _rw_fmtstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX);
}
break;
case 'p': {
// The argument shall be a pointer to void. The value of the pointer
// is converted to a sequence of printing characters, in an
// implementation-defined manner.
spec.param.ptr = PARAM (char*, ptr);
len = _rw_fmtptr (spec, pbuf, pbufsize, spec.param.ptr);
break;
}
case 'm': { // %m (popular extension)
spec.param.i = errno;
len = _rw_fmterrno (spec, pbuf, pbufsize, spec.param.i);
break;
}
case 'n': {
// The argument shall be a pointer to signed integer into which
// is written the number of characters written to the output
// stream so far by this call to fprintf. No argument is converted,
// but one is consumed. If the conversion specification includes
// any flags, a field width, or a precision, the behavior is
// undefined.
assert (0 != pbuf);
assert (0 != *pbuf);
len = int (strlen (*pbuf));
spec.param.ptr = PARAM (void*, ptr);
if (spec.mod_hh) {
unsigned char* const ptr = (unsigned char*)spec.param.ptr;
assert (0 != ptr);
*ptr = len;
}
else if (spec.mod_h) {
short* const ptr = (short*)spec.param.ptr;
assert (0 != ptr);
*ptr = len;
}
else if (spec.mod_L) {
#ifdef _RWSTD_LONG_LONG
_RWSTD_LONG_LONG* const ptr = (_RWSTD_LONG_LONG*)spec.param.ptr;
assert (0 != ptr);
*ptr = len;
#else // if !defined (_RWSTD_LONG_LONG)
assert (!"%Ln not implemented");
#endif // _RWSTD_LONG_LONG
}
else if (spec.mod_l) {
long* const ptr = (long*)spec.param.ptr;
assert (0 != ptr);
*ptr = len;
}
else if (spec.mod_t) {
ptrdiff_t* const ptr = (ptrdiff_t*)spec.param.ptr;
assert (0 != ptr);
*ptr = ptrdiff_t (unsigned (len));
}
else {
int* const ptr = (int*)spec.param.ptr;
assert (0 != ptr);
*ptr = len;
}
break;
}
case '%':
break;
}
return len;
}
/********************************************************************/
_TEST_EXPORT int
rw_vasnprintf (char **pbuf, size_t *pbufsize, const char *fmt, va_list varg)
{
va_list *pva;
#ifdef va_copy
// create a copy of va whose address can be passed to a function
// taking a va_list* so that it can modify the original; note that
// passing &va is not portable since when declared as a function
// argument, va_list that is an array type decays into a pointer
// and the address of the pointer will not match va_list* (as is
// the case on EM64T)
va_list vacpy;
va_copy (vacpy, varg);
pva = &vacpy;
#else // if !defined (va_copy)
# if 2 < __GNUG__
// use the gcc 3.x builtin when the va_copy macro is not defined
// (e.g., with gcc -ansi or Intel C++ icc -ansi or -strict_ansi)
va_list vacpy;
__builtin_va_copy (vacpy, varg);
pva = &vacpy;
# else // if !defined (__GNUG__)
// use varg (in)directly and assume it's safe (e.g., HP aCC on PA)
pva = &varg;
# endif // 2 < __GNUG__
#endif // va_copy
// do not use varg of vacpy below this point -- use *pva instead
#define varg DONT_TOUCH_ME
#define vacpy DONT_TOUCH_ME
assert (0 != pbuf);
// save the initial value of `pbuf'
char* const pbuf_save = *pbuf;
if (*pbuf)
**pbuf = '\0';
// local buffer for a small number of conversion specifiers
// will grow dynamically if their number exceeds its capacity
FmtSpec specbuf [32];
FmtSpec *pspec = specbuf;
// local buffer for backtrack offsets implementing conditionals
int backtrack [32];
int nextoff = 0;
size_t default_bufsize = 1024;
if (0 == pbufsize)
pbufsize = &default_bufsize;
char fmtspec [64];
char *next = *pbuf;
size_t spec_bufsize = sizeof specbuf / sizeof *specbuf;
size_t paramno = 0;
for (const char *fc = fmt; *fc; ) {
const char* const pcnt = strchr (fc, '%');
size_t nchars = pcnt ? pcnt - fmt : strlen (fc);
next = _rw_bufcat (pbuf, pbufsize, fmt, nchars);
if (0 == next)
goto fail;
assert (0 != *pbuf);
assert (0 != *pbufsize);
if (0 == pcnt)
break;
fc = pcnt + 1;
if ('%' == *fc) {
// handle "%%"
next = _rw_bufcat (pbuf, pbufsize, "%", 1);
if (0 == next)
goto fail;
fmt = ++fc;
continue;
}
if (spec_bufsize == paramno) {
// grow the buffer of conversion specifiers
FmtSpec *tmp = (FmtSpec*)malloc (spec_bufsize * 2);
if (tmp) {
memcpy (tmp, pspec, spec_bufsize);
if (pspec != specbuf)
free (pspec);
pspec = tmp;
}
else
goto fail;
}
if ('{' == *fc) {
const char* const endbrace = strchr (++fc, '}');
assert (0 != endbrace);
const size_t fmtlen = endbrace - fc;
memcpy (fmtspec, fc, fmtlen);
fmtspec [fmtlen] = '\0';
// compute the length of the buffer so far
const size_t buflen = next - *pbuf;
assert (0 != rw_vasnprintf_cb);
// initiaze the current format specification, setting
// all unused bits to 0
const int speclen =
_rw_fmtspec (pspec + paramno, true, fc, pva);
_RWSTD_UNUSED (speclen);
// copy the current backtrack offset if one exists
// and set the condition and condition true bits
if (nextoff) {
// set the condition valid bit
pspec [paramno].cond = 1;
if (backtrack [nextoff - 1] < 0) {
// negative offset indicates an active clause
pspec [paramno].cond_true = 1;
}
else {
// non-negative offset indicates an inactive clause
// no-op
}
}
// append formatted string to the end of the buffer
// reallocating it if necessary; callee may change
// the specification as necessary (e.g., based on
// the if/else clause)
int len =
rw_vasnprintf_cb (pspec, paramno, pbuf, pbufsize,
fmtspec, pva);
// the callback returns a negative value on error
if (len < 0)
goto fail;
assert (size_t (len) < *pbufsize);
assert (strlen (*pbuf) < *pbufsize);
const size_t offinx = nextoff - 1;
if (pspec [paramno].cond_end && pspec [paramno].cond_begin) {
// change from an if to an else clause
assert (0 < nextoff);
assert (0 == len);
if (pspec [paramno].cond_true) {
// change from an inactive if to an active else
// (same as the end of an inactive clause)
assert (0 <= backtrack [offinx]);
// set the length so as to backtrack to the position
// saved on the top of the backtrack stack
len = -int (buflen) + backtrack [offinx];
// invert the offset to indicate an active clause
backtrack [offinx] = ~backtrack [offinx];
}
else {
// change from an active if to an inactive else
assert (backtrack [offinx] < 0);
// save the current length of the buffer
// as the new backtrack offset
backtrack [offinx] = int (buflen);
}
}
else if (pspec [paramno].cond_begin) {
// start of a new if clause
// push it on the stack of backtracking offsets using
// negative values to indicate active clauses and
// non-negative values inactive ones
if (pspec [paramno].cond_true)
backtrack [nextoff++] = ~int (buflen);
else
backtrack [nextoff++] = int (buflen);
}
else if (pspec [paramno].cond_end) {
// the end of an if/else clause
if (!pspec [paramno].cond_true) {
// the end of an inactive clause
assert (backtrack [offinx] <= int (buflen));
// set the length so as to backtrack to the position
// saved on the top of the backtrack stack
len = -int (buflen) + backtrack [offinx];
}
// pop it off the top of the stack
--nextoff;
}
assert (len + buflen < *pbufsize);
// adjust the next pointer to point to the terminating
// NUL in the (possibly reallocated) buffer
next = *pbuf + buflen + len;
*next = '\0';
fc = endbrace + 1;
}
else {
const int speclen =
_rw_fmtspec (pspec + paramno, false, fc, pva);
if (speclen) {
const int len =
_rw_vasnprintf_c99 (pspec, paramno, pbuf, pbufsize, pva);
if (-1 == len)
goto fail;
// discard positional specifiers
if (-1 == pspec [paramno].paramno)
++paramno;
next = _rw_bufcat (pbuf, pbufsize, 0, size_t (len));
if (0 == next)
goto fail;
next += len;
fc += speclen;
}
else {
next = _rw_bufcat (pbuf, pbufsize, "%", 1);
if (0 == next)
goto fail;
}
}
fmt = fc;
}
// deallocate if dynamically allocated
if (pspec != specbuf)
free (pspec);
return int (next - *pbuf);
fail: // function failed
fprintf (stderr, "%s:%d: rw_vasnprintf(%p, %p, \"%s\", va_list) "
"error: errno = %d: %s\n",
__FILE__, __LINE__, (void*)pbuf, (void*)pbufsize, fmt,
errno, strerror (errno));
if (pspec != specbuf)
free (pspec);
if (*pbuf != pbuf_save) {
// free any allocated memory
free (*pbuf);
*pbuf = 0;
}
return -1;
#undef varg
#undef vacpy
}
/********************************************************************/
static const char _rw_digits[] = {
"0123456789abcdefghijklmnopqrstuvwxyz"
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
};
static int
_rw_fmtlong (const FmtSpec &spec, char **pbuf, size_t *pbufsize, long val)
{
char buffer [130]; // big enough for a 128-bit long in base 2
char *end = buffer;
long upoff = 0;
const char *pfx = 0;
if ('X' == spec.cvtspec)
upoff = 36;
if (spec.fl_pound) {
if (16 == spec.base)
pfx = upoff ? "0X" : "0x";
else if (8 == spec.base && val)
pfx = "0";
}
const int base = 1 < spec.base && spec.base < 37 ? spec.base : 10;
typedef unsigned long ULong;
ULong uval;
bool neg;
if (val < 0) {
neg = 'd' == spec.cvtspec || 'i' == spec.cvtspec;
uval = ULong (neg ? -val : val);
}
else {
neg = false;
uval = ULong (val);
}
do {
*end++ = _rw_digits [upoff + uval % base];
} while (uval /= base);
int size = int (end - buffer);
// insert as many zeros as specified by precision
if (-1 < spec.prec && size < spec.prec) {
// FIXME: prevent buffer overrun
for (int i = size; i != spec.prec; ++i)
*end++ = '0';
}
// insert octal or hex prefix for non-zero values
if (pfx && val) {
if (pfx [1])
*end++ = pfx [1];
*end++ = pfx [0];
}
if (neg)
*end++ = '-';
else if (spec.fl_plus && ('d' == spec.cvtspec || 'i' == spec.cvtspec))
*end++ = '+';
if (0 == spec.prec && 0 == val) {
// 7.19.6.1 of ISO/IEC 9899:1999:
// The result of converting a zero value with a precision
// of zero is no characters.
end = buffer;
}
*end = '\0';
size = int (end - buffer);
for (char *pc = buffer; pc < end; ++pc) {
const char tmp = *pc;
*pc = *--end;
*end = tmp;
}
// reset precision to -1 (already handled above)
FmtSpec newspec (spec);
newspec.fl_pound = 0;
newspec.prec = -1;
// handle justification by formatting the resulting string
return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (size));
}
/********************************************************************/
#ifdef _RWSTD_LONG_LONG
static int
_rw_fmtllong (const FmtSpec &spec,
char **pbuf, size_t *pbufsize, _RWSTD_LONG_LONG val)
{
char buffer [130]; // big enough for a 128-bit long long in base 2
char *end = buffer;
long upoff = 0;
const char *pfx = 0;
if ('X' == spec.cvtspec)
upoff = 36;
if (spec.fl_pound) {
if (16 == spec.base)
pfx = upoff ? "0X" : "0x";
else if (8 == spec.base && val)
pfx = "0";
}
const int base = 1 < spec.base && spec.base < 37 ? spec.base : 10;
typedef unsigned _RWSTD_LONG_LONG ULLong;
ULLong uval;
bool neg;
if (val < 0) {
neg = 'd' == spec.cvtspec || 'i' == spec.cvtspec;
uval = ULLong (neg ? -val : val);
}
else {
neg = false;
uval = ULLong (val);
}
do {
*end++ = _rw_digits [upoff + uval % base];
} while (uval /= base);
if (pfx) {
if (pfx [1])
*end++ = pfx [1];
*end++ = pfx [0];
}
char sign;
if (neg)
sign = '-';
else if (spec.fl_plus && ('d' == spec.cvtspec || 'i' == spec.cvtspec))
sign= '+';
else
sign = '\0';
assert (buffer < end);
size_t size = size_t (end - buffer);
// FIXME: prevent buffer overrun
if (0 < spec.prec && size < size_t (spec.prec)) {
for (size_t i = size; i != size_t (spec.prec); ++i)
*end++ = '0';
}
if (sign)
*end++ = sign;
*end = '\0';
assert (buffer < end);
size = size_t (end - buffer);
for (char *pc = buffer; pc < end; ++pc) {
const char tmp = *pc;
*pc = *--end;
*end = tmp;
}
// handle justification by formatting the resulting string
return _rw_fmtstr (spec, pbuf, pbufsize, buffer, size);
}
#endif // _RWSTD_LONG_LONG
/********************************************************************/
static int
_rw_fmtinteger (FmtSpec *pspec, size_t paramno,
char **pbuf, size_t *pbufsize, va_list *pva)
{
int len = -1;
FmtSpec &spec = pspec [paramno];
switch (spec.cvtspec) {
case 'd':
case 'i':
if (spec.mod_hh) {
// promoted signed char argument
spec.param.i = PARAM (int, i);
const signed char val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, long (val));
}
else if (spec.mod_h) {
// promoted signed short argument
spec.param.i = PARAM (int, i);
const short val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, long (val));
}
else if (spec.mod_l) { // %li
spec.param.lng = PARAM (long, lng);
len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.lng);
}
else if (spec.mod_ll) { // %lli
#ifdef _RWSTD_LONG_LONG
spec.param.llong = PARAM (_RWSTD_LONG_LONG, llong);
len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.llong);
#elif 8 == _RWSTD_LONG_SIZE
spec.param.llong = PARAM (long, lnng);
len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.llong);
#else
assert (!"%lld, %lli: long long not supported");
#endif // _RWSTD_LONG_LONG
}
else if (spec.mod_t) {
spec.param.diff = PARAM (ptrdiff_t, diff);
if (sizeof (ptrdiff_t) == sizeof (long)) {
len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.diff);
}
else {
#ifdef _RWSTD_LONG_LONG
len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.diff);
#else // if !defined (_RWSTD_LONG_LONG)
assert (!"%td, %ti: 64-bit types not supported");
#endif // _RWSTD_LONG_LONG
}
}
else if (1 == spec.iwidth) {
spec.param.i = PARAM (int, i);
const _RWSTD_INT8_T val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (2 == spec.iwidth) {
spec.param.i = PARAM (int, i);
const _RWSTD_INT16_T val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (3 == spec.iwidth) {
spec.param.i32 = PARAM (_RWSTD_INT32_T, i32);
const long val = long (spec.param.i32);
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (4 == spec.iwidth) {
#ifdef _RWSTD_INT64_T
spec.param.i64 = PARAM (_RWSTD_INT64_T, i64);
#else // if !defined (_RWSTD_INT64_T)
assert (!"%I64d, %I64i: 64-bit types not supported");
#endif // _RWSTD_INT64_T
#if 8 == _RWSTD_LONG_SIZE
const long val = spec.param.i64;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
#elif defined (_RWSTD_LONG_LONG)
const _RWSTD_LONG_LONG val = spec.param.i64;
len = _rw_fmtllong (spec, pbuf, pbufsize, val);
#else
assert (!"%I64d, %I64i: 64-bit types not supported");
#endif
}
else { // %i
spec.param.i = PARAM (int, i);
len = _rw_fmtlong (spec, pbuf, pbufsize, long (spec.param.i));
}
break;
case 'o':
assert (-1 == spec.base);
spec.base = 8;
// fall thru
case 'x':
if (-1 == spec.base)
spec.base = 16;
// fall thru
case 'X':
if (-1 == spec.base)
spec.base = 16;
case 'u':
if (spec.mod_hh) {
// promoted unsigned char argument
spec.param.i = PARAM (unsigned, i);
const unsigned char val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val);
}
else if (spec.mod_h) {
// promoted unsigned short argument
spec.param.i = PARAM (unsigned, i);
const unsigned short val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val);
}
else if (spec.mod_ll) {
#ifdef _RWSTD_LONG_LONG
spec.param.llong = PARAM (unsigned _RWSTD_LONG_LONG, llong);
const unsigned _RWSTD_LONG_LONG val = spec.param.llong;
len = _rw_fmtllong (spec, pbuf, pbufsize, val);
#elif 8 == _RWSTD_LONG_SIZE
spec.param.lng = PARAM (unsigned long, lng);
const unsigned long val = spec.param.lng;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
#else
assert (!"long long not supported");
#endif // _RWSTD_LONG_LONG
}
else if (spec.mod_l) {
spec.param.lng = PARAM (unsigned long, lng);
const unsigned long val = spec.param.lng;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (spec.mod_t) {
spec.param.lng = PARAM (size_t, size);
if (sizeof (size_t) == sizeof (unsigned long)) {
len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.size);
}
else {
#ifdef _RWSTD_LONG_LONG
len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.size);
#else // if defined (_RWSTD_LONG_LONG)
assert (!"%to, %tu, %tx: 64-bit types not implemented");
#endif // _RWSTD_LONG_LONG
}
}
else if (1 == spec.iwidth) {
spec.param.i = PARAM (int, i);
const _RWSTD_UINT8_T val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (2 == spec.iwidth) {
spec.param.i = PARAM (int, i);
const long val = (unsigned short)spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (3 == spec.iwidth) {
spec.param.i32 = PARAM (_RWSTD_INT32_T, i32);
const long val = long (unsigned (spec.param.i));
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
}
else if (4 == spec.iwidth) {
#ifdef _RWSTD_INT64_T
spec.param.i64 = PARAM (_RWSTD_INT64_T, i64);
#else // if defined 9_RWSTD_INT64_T)
assert (!"%I64o, %I64u, %I64x: 64-bit types not supported");
#endif // _RWSTD_INT64_T
#if 8 == _RWSTD_LONG_SIZE
const unsigned long val = spec.param.i64;
len = _rw_fmtlong (spec, pbuf, pbufsize, val);
#elif defined (_RWSTD_LONG_LONG)
const unsigned _RWSTD_LONG_LONG val = spec.param.i64;
len = _rw_fmtllong (spec, pbuf, pbufsize, val);
#else
assert (!"%I64o, %I64u, %I64x: 64-bit types not supported");
#endif
}
else {
spec.param.i = PARAM (unsigned, i);
const unsigned val = spec.param.i;
len = _rw_fmtlong (spec, pbuf, pbufsize, long (val));
}
break;
}
return len;
}
/********************************************************************/
static int
_rw_fmtfloating (const FmtSpec &spec,
char **pbuf, size_t *pbufsize, const void *pval)
{
char fmt [128];
char *pf = fmt;
*pf++ = '%';
if (spec.fl_minus)
*pf++ = '-';
if (spec.fl_plus)
*pf++ = '+';
if (spec.fl_pound)
*pf++ = '#';
if (spec.fl_space)
*pf++ = ' ';
if (spec.fl_zero)
*pf++ = '0';
if (spec.mod_h)
*pf++ = 'h';
else if (spec.mod_hh) {
*pf++ = 'h';
*pf++ = 'h';
}
else if (spec.mod_l)
*pf++ = 'l';
else if (spec.mod_ll) {
*pf++ = 'l';
*pf++ = 'l';
}
else if (spec.mod_j)
*pf++ = 'j';
else if (spec.mod_z)
*pf++ = 'z';
else if (spec.mod_t)
*pf++ = 't';
else if (spec.mod_L) {
strcpy (pf, _RWSTD_LDBL_PRINTF_PREFIX);
for ( ; *pf; ++pf);
}
else if (spec.mod_A && _RWSTD_LDBL_SIZE == spec.width) {
strcpy (pf, _RWSTD_LDBL_PRINTF_PREFIX);
for ( ; *pf; ++pf);
}
if (!spec.mod_A && 0 <= spec.width) {
pf += sprintf (pf, "%i", spec.width);
}
if (0 <= spec.prec)
pf += sprintf (pf, ".%i", spec.prec);
*pf++ = char (spec.cvtspec);
*pf = '\0';
// verify that the format buffer hasn't overflowed
assert (size_t (pf - fmt) + 1 < sizeof fmt);
// this might make the buffer almost 5KB
char buffer [_RWSTD_LDBL_MAX_10_EXP + _RWSTD_LDBL_DIG + 3];
int len = -1;
if (spec.mod_A) {
if (_RWSTD_FLT_SIZE == spec.width) {
len = sprintf (buffer, fmt, *(const float*)pval);
}
else if (_RWSTD_DBL_SIZE == spec.width) {
len = sprintf (buffer, fmt, *(const double*)pval);
}
else if (_RWSTD_LDBL_SIZE == spec.width) {
len = sprintf (buffer, fmt, *(const long double*)pval);
}
else {
assert (!"unknown floating point size");
}
}
else if (spec.mod_L)
len = sprintf (buffer, fmt, *(const long double*)pval);
else
len = sprintf (buffer, fmt, *(const double*)pval);
assert (size_t (len) < sizeof buffer);
#ifdef _MSC_VER
if (5 < len) {
// remove redundant zeros from the exponent (if present)
if ( ('e' == buffer [len - 5] || 'E' == buffer [len - 5])
&& '0' == buffer [len - 3]) {
buffer [len - 3] = buffer [len - 2];
buffer [len - 2] = buffer [len - 1];
buffer [len - 1] = buffer [len];
}
}
#endif // _MSC_VER
if (-1 < len && 0 == _rw_bufcat (pbuf, pbufsize, buffer, size_t (len)))
return -1;
return len;
}
/********************************************************************/
// formats a data, function, or class member pointer as follows
// 0x<hex-long-0>[:<hex-long-1>[:...[:<hex-long-N>]]]
// where N is the size of the pointer in long ints
static int
_rw_fmtpointer (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
const void *pptr, size_t nelems)
{
FmtSpec newspec (spec);
// always format data pointers in hexadecimal
newspec.base = 16;
// set the number of digits
newspec.prec = _RWSTD_LONG_SIZE * 2;
const union {
const void *ptr;
const unsigned long *lptr;
} uptr = { pptr };
int len = 0;
if (newspec.fl_pound) {
// prepend the 0x prefix even to null pointers
if (0 == _rw_bufcat (pbuf, pbufsize, "0x", len = 2)) {
return -1;
}
// reset the pound flag to prevent the integer formatter
// from inserting it again
newspec.fl_pound = 0;
}
for (size_t i = 0; i != nelems; ++i) {
const size_t inx = _rw_big_endian ? nelems - i - 1 : i;
len += _rw_fmtlong (newspec, pbuf, pbufsize, uptr.lptr [inx]);
if (len < 0) {
break;
}
// separate pointer components with colons
int n = 0;
if (i + 1 < nelems) {
if (0 == _rw_bufcat (pbuf, pbufsize, ":", n = 1)) {
len = -1;
break;
}
}
len += n;
}
return len;
}
/********************************************************************/
_RWSTD_INTERNAL int
_rw_fmtptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
const void *val)
{
return _rw_fmtpointer (spec, pbuf, pbufsize, &val,
sizeof val / sizeof (long));
}
/********************************************************************/
static int
_rw_fmtfunptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
funptr_t val)
{
if (spec.mod_l) {
#if 0 // disabled until this is implemented on other platforms
#ifdef _RWSTD_OS_SUNOS
char buffer [256];
Dl_info dli;
// find the symbol corresponding to the address
if (dladdr ((void*)val, &dli)) {
if (!dli.dli_sname)
dli.dli_fname = "unknown";
const size_t sym_off = size_t (dli.dli_saddr);
// compute the offset of the address from the address
// of the symbol dladdr() found in the address space
// of the calling process
const size_t addr_off = size_t (val) < sym_off ?
sym_off - size_t (val) : size_t (val) - sym_off;
// format the address folowed by the name of the symbol
// followed by the offset
const int len = sprintf (buffer, "%#x=%s%c%lu",
size_t (val), dli.dli_sname,
size_t (val) < sym_off ? '-' : '+',
addr_off);
FmtSpec newspec (spec);
newspec.mod_l = false;
return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len));
}
#endif // _RWSTD_OS_SUNOS
#endif // 0/1
}
return _rw_fmtpointer (spec, pbuf, pbufsize, &val,
sizeof val / sizeof (long));
}
/********************************************************************/
static int
_rw_fmtmemptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, memptr_t val)
{
return _rw_fmtpointer (spec, pbuf, pbufsize, &val,
sizeof val / sizeof (long));
}
/********************************************************************/
static int
_rw_fmterrno (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
{
static const struct {
int val;
const char* str;
} names[] = {
#undef ERRNO
#define ERRNO(val) { val, #val }
#ifdef EPERM
ERRNO (EPERM),
#endif // EPERM
#ifdef ENOENT
ERRNO (ENOENT),
#endif // ENOENT
#ifdef ESRCH
ERRNO (ESRCH),
#endif // ESRCH
#ifdef EINTR
ERRNO (EINTR),
#endif // EINTR
#ifdef EIO
ERRNO (EIO),
#endif // EIO
#ifdef ENXIO
ERRNO (ENXIO),
#endif // ENXIO
#ifdef E2BIG
ERRNO (E2BIG),
#endif // E2BIG
#ifdef ENOEXEC
ERRNO (ENOEXEC),
#endif // ENOEXEC
#ifdef EBADF
ERRNO (EBADF),
#endif // EBADF
#ifdef ECHILD
ERRNO (ECHILD),
#endif // ECHILD
#ifdef EAGAIN
ERRNO (EAGAIN),
#endif // EAGAIN
#ifdef ENOMEM
ERRNO (ENOMEM),
#endif // ENOMEM
#ifdef EACCES
ERRNO (EACCES),
#endif // EACCES
#ifdef EFAULT
ERRNO (EFAULT),
#endif // EFAULT
#ifdef ENOTBLK
ERRNO (ENOTBLK),
#endif // ENOTBLK
#ifdef EBUSY
ERRNO (EBUSY),
#endif // EBUSY
#ifdef EEXIST
ERRNO (EEXIST),
#endif // EEXIST
#ifdef EXDEV
ERRNO (EXDEV),
#endif // EXDEV
#ifdef ENODEV
ERRNO (ENODEV),
#endif // ENODEV
#ifdef ENOTDIR
ERRNO (ENOTDIR),
#endif // ENOTDIR
#ifdef EISDIR
ERRNO (EISDIR),
#endif // EISDIR
#ifdef EINVAL
ERRNO (EINVAL),
#endif // EINVAL
#ifdef ENFILE
ERRNO (ENFILE),
#endif // ENFILE
#ifdef EMFILE
ERRNO (EMFILE),
#endif // EMFILE
#ifdef ENOTTY
ERRNO (ENOTTY),
#endif // ENOTTY
#ifdef ETXTBSY
ERRNO (ETXTBSY),
#endif // ETXTBSY
#ifdef EFBIG
ERRNO (EFBIG),
#endif // EFBIG
#ifdef ENOSPC
ERRNO (ENOSPC),
#endif // ENOSPC
#ifdef ESPIPE
ERRNO (ESPIPE),
#endif // ESPIPE
#ifdef EROFS
ERRNO (EROFS),
#endif // EROFS
#ifdef EMLINK
ERRNO (EMLINK),
#endif // EMLINK
#ifdef EPIPE
ERRNO (EPIPE),
#endif // EPIPE
#ifdef EDOM
ERRNO (EDOM),
#endif // EDOM
#ifdef ERANGE
ERRNO (ERANGE),
#endif // ERANGE
#ifdef ENOMSG
ERRNO (ENOMSG),
#endif // ENOMSG
#ifdef EIDRM
ERRNO (EIDRM),
#endif // EIDRM
#ifdef ECHRNG
ERRNO (ECHRNG),
#endif // ECHRNG
#ifdef EL2NSYNC
ERRNO (EL2NSYNC),
#endif // EL2NSYNC
#ifdef EL3HLT
ERRNO (EL3HLT),
#endif // EL3HLT
#ifdef EL3RST
ERRNO (EL3RST),
#endif // EL3RST
#ifdef ELNRNG
ERRNO (ELNRNG),
#endif // ELNRNG
#ifdef EUNATCH
ERRNO (EUNATCH),
#endif // EUNATCH
#ifdef ENOCSI
ERRNO (ENOCSI),
#endif // ENOCSI
#ifdef EL2HLT
ERRNO (EL2HLT),
#endif // EL2HLT
#ifdef EDEADLK
ERRNO (EDEADLK),
#endif // EDEADLK
#ifdef ENOLCK
ERRNO (ENOLCK),
#endif // ENOLCK
#ifdef ECANCELED
ERRNO (ECANCELED),
#endif // ECANCELED
#ifdef ENOTSUP
ERRNO (ENOTSUP),
#endif // ENOTSUP
#ifdef EDQUOT
ERRNO (EDQUOT),
#endif // EDQUOT
#ifdef EBADE
ERRNO (EBADE),
#endif // EBADE
#ifdef EBADR
ERRNO (EBADR),
#endif // EBADR
#ifdef EXFULL
ERRNO (EXFULL),
#endif // EXFULL
#ifdef ENOANO
ERRNO (ENOANO),
#endif // ENOANO
#ifdef EBADRQC
ERRNO (EBADRQC),
#endif // EBADRQC
#ifdef EBADSLT
ERRNO (EBADSLT),
#endif // EBADSLT
#ifdef EDEADLOCK
ERRNO (EDEADLOCK),
#endif // EDEADLOCK
#ifdef EBFONT
ERRNO (EBFONT),
#endif // EBFONT
#ifdef EOWNERDEAD
ERRNO (EOWNERDEAD),
#endif // EOWNERDEAD
#ifdef ENOTRECOVERABLE
ERRNO (ENOTRECOVERABLE),
#endif // ENOTRECOVERABLE
#ifdef ENOSTR
ERRNO (ENOSTR),
#endif // ENOSTR
#ifdef ENODATA
ERRNO (ENODATA),
#endif // ENODATA
#ifdef ETIME
ERRNO (ETIME),
#endif // ETIME
#ifdef ENOSR
ERRNO (ENOSR),
#endif // ENOSR
#ifdef ENONET
ERRNO (ENONET),
#endif // ENONET
#ifdef ENOPKG
ERRNO (ENOPKG),
#endif // ENOPKG
#ifdef EREMOTE
ERRNO (EREMOTE),
#endif // EREMOTE
#ifdef ENOLINK
ERRNO (ENOLINK),
#endif // ENOLINK
#ifdef EADV
ERRNO (EADV),
#endif // EADV
#ifdef ESRMNT
ERRNO (ESRMNT),
#endif // ESRMNT
#ifdef ECOMM
ERRNO (ECOMM),
#endif // ECOMM
#ifdef ELOCKUNMAPPED
ERRNO (ELOCKUNMAPPED),
#endif // ELOCKUNMAPPED
#ifdef ENOTACTIVE
ERRNO (ENOTACTIVE),
#endif // ENOTACTIVE
#ifdef EMULTIHOP
ERRNO (EMULTIHOP),
#endif // EMULTIHOP
#ifdef EBADMSG
ERRNO (EBADMSG),
#endif // EBADMSG
#ifdef ENAMETOOLONG
ERRNO (ENAMETOOLONG),
#endif // ENAMETOOLONG
#ifdef EOVERFLOW
ERRNO (EOVERFLOW),
#endif // EOVERFLOW
#ifdef ENOTUNIQ
ERRNO (ENOTUNIQ),
#endif // ENOTUNIQ
#ifdef EBADFD
ERRNO (EBADFD),
#endif // EBADFD
#ifdef EREMCHG
ERRNO (EREMCHG),
#endif // EREMCHG
#ifdef ELIBACC
ERRNO (ELIBACC),
#endif // ELIBACC
#ifdef ELIBBAD
ERRNO (ELIBBAD),
#endif // ELIBBAD
#ifdef ELIBSCN
ERRNO (ELIBSCN),
#endif // ELIBSCN
#ifdef ELIBMAX
ERRNO (ELIBMAX),
#endif // ELIBMAX
#ifdef ELIBEXEC
ERRNO (ELIBEXEC),
#endif // ELIBEXEC
#ifdef EILSEQ
ERRNO (EILSEQ),
#endif // EILSEQ
#ifdef ENOSYS
ERRNO (ENOSYS),
#endif // ENOSYS
#ifdef ELOOP
ERRNO (ELOOP),
#endif // ELOOP
#ifdef ERESTART
ERRNO (ERESTART),
#endif // ERESTART
#ifdef ESTRPIPE
ERRNO (ESTRPIPE),
#endif // ESTRPIPE
#ifdef ENOTEMPTY
ERRNO (ENOTEMPTY),
#endif // ENOTEMPTY
#ifdef EUSERS
ERRNO (EUSERS),
#endif // EUSERS
#ifdef ENOTSOCK
ERRNO (ENOTSOCK),
#endif // ENOTSOCK
#ifdef EDESTADDRREQ
ERRNO (EDESTADDRREQ),
#endif // EDESTADDRREQ
#ifdef EMSGSIZE
ERRNO (EMSGSIZE),
#endif // EMSGSIZE
#ifdef EPROTOTYPE
ERRNO (EPROTOTYPE),
#endif // EPROTOTYPE
#ifdef ENOPROTOOPT
ERRNO (ENOPROTOOPT),
#endif // ENOPROTOOPT
#ifdef EPROTONOSUPPORT
ERRNO (EPROTONOSUPPORT),
#endif // EPROTONOSUPPORT
#ifdef ESOCKTNOSUPPORT
ERRNO (ESOCKTNOSUPPORT),
#endif // ESOCKTNOSUPPORT
#ifdef EOPNOTSUPP
ERRNO (EOPNOTSUPP),
#endif // EOPNOTSUPP
#ifdef EPFNOSUPPORT
ERRNO (EPFNOSUPPORT),
#endif // EPFNOSUPPORT
#ifdef EAFNOSUPPORT
ERRNO (EAFNOSUPPORT),
#endif // EAFNOSUPPORT
#ifdef EADDRINUSE
ERRNO (EADDRINUSE),
#endif // EADDRINUSE
#ifdef EADDRNOTAVAIL
ERRNO (EADDRNOTAVAIL),
#endif // EADDRNOTAVAIL
#ifdef ENETDOWN
ERRNO (ENETDOWN),
#endif // ENETDOWN
#ifdef ENETUNREACH
ERRNO (ENETUNREACH),
#endif // ENETUNREACH
#ifdef ENETRESET
ERRNO (ENETRESET),
#endif // ENETRESET
#ifdef ECONNABORTED
ERRNO (ECONNABORTED),
#endif // ECONNABORTED
#ifdef ECONNRESET
ERRNO (ECONNRESET),
#endif // ECONNRESET
#ifdef ENOBUFS
ERRNO (ENOBUFS),
#endif // ENOBUFS
#ifdef EISCONN
ERRNO (EISCONN),
#endif // EISCONN
#ifdef ENOTCONN
ERRNO (ENOTCONN),
#endif // ENOTCONN
#ifdef ESHUTDOWN
ERRNO (ESHUTDOWN),
#endif // ESHUTDOWN
#ifdef ETOOMANYREFS
ERRNO (ETOOMANYREFS),
#endif // ETOOMANYREFS
#ifdef ETIMEDOUT
ERRNO (ETIMEDOUT),
#endif // ETIMEDOUT
#ifdef ECONNREFUSED
ERRNO (ECONNREFUSED),
#endif // ECONNREFUSED
#ifdef EHOSTDOWN
ERRNO (EHOSTDOWN),
#endif // EHOSTDOWN
#ifdef EHOSTUNREACH
ERRNO (EHOSTUNREACH),
#endif // EHOSTUNREACH
#ifdef EWOULDBLOCK
ERRNO (EWOULDBLOCK),
#endif // EWOULDBLOCK
#ifdef EALREADY
ERRNO (EALREADY),
#endif // EALREADY
#ifdef EINPROGRESS
ERRNO (EINPROGRESS),
#endif // EINPROGRESS
#ifdef ESTALE
ERRNO (ESTALE),
#endif // ESTALE
{ -1, 0 }
};
if (spec.fl_pound) {
char buffer [64];
const char *name = 0;
for (size_t i = 0; i != sizeof names / sizeof *names; ++i) {
if (names [i].val == val) {
name = names [i].str;
break;
}
}
int len;
if (0 == name) {
len = sprintf (buffer, "E#%d", val);
name = buffer;
}
else
len = int (strlen (name));
if (0 == _rw_bufcat (pbuf, pbufsize, name, size_t (len)))
return -1;
return len;
}
const char* const str = strerror (val);
const size_t len = strlen (str);
if (0 == _rw_bufcat (pbuf, pbufsize, str, len))
return -1;
return int (len);
}
/********************************************************************/
static int
_rw_fmtsignal (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
{
static const struct {
int val;
const char* str;
} names[] = {
#undef SIGNAL
#define SIGNAL(val) { val, #val }
#ifdef SIGABRT
SIGNAL (SIGABRT),
#endif // SIGABRT
#ifdef SIGALRM
SIGNAL (SIGALRM),
#endif // SIGALRM
#ifdef SIGBUS
SIGNAL (SIGBUS),
#endif // SIGBUS
#ifdef SIGCANCEL
SIGNAL (SIGCANCEL),
#endif // SIGCANCEL
#ifdef SIGCHLD
SIGNAL (SIGCHLD),
#endif // SIGCHLD
#ifdef SIGCKPT
SIGNAL (SIGCKPT),
#endif // SIGCKPT
#ifdef SIGCLD
SIGNAL (SIGCLD),
#endif // SIGCLD
#ifdef SIGCONT
SIGNAL (SIGCONT),
#endif // SIGCONT
#ifdef SIGDIL
SIGNAL (SIGDIL),
#endif // SIGDIL
#ifdef SIGEMT
SIGNAL (SIGEMT),
#endif // SIGEMT
#ifdef SIGFPE
SIGNAL (SIGFPE),
#endif // SIGFPE
#ifdef SIGFREEZE
SIGNAL (SIGFREEZE),
#endif // SIGFREEZE
#ifdef SIGGFAULT
SIGNAL (SIGGFAULT),
#endif // SIGGFAULT
#ifdef SIGHUP
SIGNAL (SIGHUP),
#endif // SIGHUP
#ifdef SIGILL
SIGNAL (SIGILL),
#endif // SIGILL
#ifdef SIGINFO
SIGNAL (SIGINFO),
#endif // SIGINFO
#ifdef SIGINT
SIGNAL (SIGINT),
#endif // SIGINT
#ifdef SIGIO
SIGNAL (SIGIO),
#endif // SIGIO
#ifdef SIGIOT
SIGNAL (SIGIOT),
#endif // SIGIOT
#ifdef SIGK32
SIGNAL (SIGK32),
#endif // SIGK32
#ifdef SIGKILL
SIGNAL (SIGKILL),
#endif // SIGKILL
#ifdef SIGLOST
SIGNAL (SIGLOST),
#endif // SIGLOST
#ifdef SIGLWP
SIGNAL (SIGLWP),
#endif // SIGLWP
#ifdef SIGPIPE
SIGNAL (SIGPIPE),
#endif // SIGPIPE
#ifdef SIGPOLL
SIGNAL (SIGPOLL),
#endif // SIGPOLL
#ifdef SIGPROF
SIGNAL (SIGPROF),
#endif // SIGPROF
#ifdef SIGPTINTR
SIGNAL (SIGPTINTR),
#endif // SIGPTINTR
#ifdef SIGPTRESCHED
SIGNAL (SIGPTRESCHED),
#endif // SIGPTRESCHED
#ifdef SIGPWR
SIGNAL (SIGPWR),
#endif // SIGPWR
#ifdef SIGQUIT
SIGNAL (SIGQUIT),
#endif // SIGQUIT
#ifdef SIGRESTART
SIGNAL (SIGRESTART),
#endif // SIGRESTART
#ifdef SIGRESV
SIGNAL (SIGRESV),
#endif // SIGRESV
#ifdef SIGSEGV
SIGNAL (SIGSEGV),
#endif // SIGSEGV
#ifdef SIGSTKFLT
SIGNAL (SIGSTKFLT),
#endif // SIGSTKFLT
#ifdef SIGSTOP
SIGNAL (SIGSTOP),
#endif // SIGSTOP
#ifdef SIGSYS
SIGNAL (SIGSYS),
#endif // SIGSYS
#ifdef SIGTERM
SIGNAL (SIGTERM),
#endif // SIGTERM
#ifdef SIGTHAW
SIGNAL (SIGTHAW),
#endif // SIGTHAW
#ifdef SIGTRAP
SIGNAL (SIGTRAP),
#endif // SIGTRAP
#ifdef SIGTSTP
SIGNAL (SIGTSTP),
#endif // SIGTSTP
#ifdef SIGTTIN
SIGNAL (SIGTTIN),
#endif // SIGTTIN
#ifdef SIGTTOU
SIGNAL (SIGTTOU),
#endif // SIGTTOU
#ifdef SIGUNUSED
SIGNAL (SIGUNUSED),
#endif // SIGUNUSED
#ifdef SIGURG
SIGNAL (SIGURG),
#endif // SIGURG
#ifdef SIGUSR1
SIGNAL (SIGUSR1),
#endif // SIGUSR1
#ifdef SIGUSR2
SIGNAL (SIGUSR2),
#endif // SIGUSR2
#ifdef SIGVTALRM
SIGNAL (SIGVTALRM),
#endif // SIGVTALRM
#ifdef SIGWAITING
SIGNAL (SIGWAITING),
#endif // SIGWAITING
#ifdef SIGWINCH
SIGNAL (SIGWINCH),
#endif // SIGWINCH
#ifdef SIGWINDOW
SIGNAL (SIGWINDOW),
#endif // SIGWINDOW
#ifdef SIGXCPU
SIGNAL (SIGXCPU),
#endif // SIGXCPU
#ifdef SIGXFSZ
SIGNAL (SIGXFSZ),
#endif // SIGXFSZ
#ifdef SIGXRES
SIGNAL (SIGXRES),
#endif // SIGXRES
{ -1, 0 }
};
char buffer [64];
const char *name = 0;
for (size_t i = 0; i != sizeof names / sizeof *names; ++i) {
if (names [i].val == val) {
name = names [i].str;
break;
}
}
if (0 == name) {
sprintf (buffer, "SIG#%d", val);
name = buffer;
}
return _rw_fmtstr (spec, pbuf, pbufsize, name, _RWSTD_SIZE_MAX);
}
/********************************************************************/
template <class charT>
int rw_quotechar (char *buf, charT wc, int noesc)
{
#if _RWSTD_WCHAR_T_MIN < 0
// wchar_t is signed, convert its value to unsigned long
// without widening (i.e., treat it as an unsigned type)
# if _RWSTD_WCHAR_T_MIN == _RWSTD_SHRT_MIN
const unsigned long wi = (unsigned short)wc;
# elif _RWSTD_WCHAR_T_MIN ==_RWSTD_INT_MIN
const unsigned long wi = (unsigned int)wc;
# elif _RWSTD_WCHAR_T_MIN == _RWSTD_LONG_MIN
const unsigned long wi = (unsigned long)wc;
# endif
#else // if _RWSTD_WCHAR_T_MIN >= 0
// wchar_t is unsigned
const unsigned long wi = (unsigned long)wc;
#endif // _RWSTD_WCHAR_T_MIN < 0
if ((1 == sizeof wc || wi < 0x100) && noesc) {
buf [0] = char (wc);
buf [1] = '\0';
return 1;
}
int len = 3;
buf [0] = '\\';
buf [2] = '\0';
switch (wc) {
case '\a': buf [1] = 'a'; buf [len = 2] = '\0'; break;
case '\b': buf [1] = 'b'; buf [len = 2] = '\0'; break;
case '\f': buf [1] = 'f'; buf [len = 2] = '\0'; break;
case '\n': buf [1] = 'n'; buf [len = 2] = '\0'; break;
case '\r': buf [1] = 'r'; buf [len = 2] = '\0'; break;
case '\t': buf [1] = 't'; buf [len = 2] = '\0'; break;
case '\v': buf [1] = 'v'; buf [len = 2] = '\0'; break;
case '\\': buf [1] = '\\'; buf [len = 2] = '\0'; break;
case '"' : buf [1] = '"'; buf [len = 2] = '\0'; break;
default:
if (wc < ' ' || wc > '~') {
if (0 == wc) {
buf [1] = '0';
buf [2] = '\0';
len = 2;
}
else if (1 == sizeof wc) {
len = 1 + sprintf (buf + 1, "x%02x", (unsigned char)wc);
}
else {
const int width =
wi > 0xfffffffUL ? 8 : wi > 0xffffffUL ? 7
: wi > 0xfffffUL ? 6 : wi > 0xffffUL ? 5
: wi > 0xfffUL ? 4 : wi > 0xffUL ? 3
: wi > 0xfUL ? 2 : 2;
len = 1 + sprintf (buf + 1, "x%0*lx", width, (unsigned long)wi);
}
}
else {
buf [0] = wc;
buf [1] = '\0';
len = 1;
}
}
return len;
}
template <class charT>
int rw_quotestr (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
const charT *wstr, size_t nchars, int noesc)
{
assert(1);
return 0;
#if 0
assert (0 != pbuf);
if (!wstr) {
static const charT null[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' };
wstr = null;
nchars = sizeof null / sizeof *null - 1;
}
if (0 > _RW::__rw_memattr (wstr, _RWSTD_SIZE_MAX, 0)) {
const size_t buflen = *pbuf ? strlen (*pbuf) : 0;
if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18))
return -1;
FmtSpec newspec (spec);
newspec.fl_pound = 1;
if (-1 == ::_rw_fmtptr (newspec, pbuf, pbufsize, wstr))
return -1;
if (0 == _rw_bufcat (pbuf, pbufsize, ")", 2))
return -1;
return int (strlen (*pbuf) - buflen);
}
if (_RWSTD_SIZE_MAX == nchars) {
// compute the length of the NUL-terminate string
nchars = 0;
for (const charT *pc = wstr; *pc; ++pc, ++nchars);
}
char *next = _rw_bufcat (pbuf, pbufsize, 0, (nchars + 1) * 12 + 3);
const char* const bufend = next;
if (0 == next)
return -1;
if (0 == nchars) {
if (noesc) {
#if 0 // width handling disabled (width used for array formatting)
for (int w = 0; w < spec.width; ++w)
*next++ = ' ';
#endif // 0/1
}
else {
if (_RWSTD_WCHAR_T_SIZE == sizeof (charT))
*next++ = 'L';
*next++ = '"';
#if 0 // width handling disabled (width used for array formatting)
for (int w = 0; w < spec.width; ++w)
*next++ = ' ';
#endif // 0/1
*next++ = '"';
}
*next++ = '\0';
return int (next - bufend);
}
char *s = next;
const charT *last = wstr;
bool any_repeats = false;
long last_repeat = noesc ? 0L : -1L;
char chstr [16];
const ptrdiff_t N = ptrdiff_t (noesc ? 0 : 20);
for (const charT *pwc = last + 1; ; ++pwc) {
if (*pwc == *last && size_t (pwc - wstr) < nchars) {
// if the last processed character repeats, continue
// until a different character is encountered
continue;
}
if (N > 1 && pwc - last > N) {
// if the last processed character repeats N or more
// times, format the repeat count instead of all the
// repeated occurrences of the character to conserve
// space and make the string more readable
const long repeat = pwc - last;
rw_quotechar (chstr, *last, noesc);
s += sprintf (s, "%s'%s' <repeats %ld times>",
-1 == last_repeat ? ""
: 0 == last_repeat ? "\", " : ", ",
chstr, repeat);
last = pwc;
any_repeats = true;
last_repeat = repeat;
}
else {
// otherwise (if the last processed character repeats
// fewer than N times) format the character that many
// times
if (last_repeat < 0) {
// opening quote
if (_RWSTD_WCHAR_T_SIZE == sizeof (charT)) {
*s++ = 'L';
}
*s++ = '\"';
}
else if (last_repeat > 0) {
*s++ = ',';
*s++ = ' ';
*s++ = '\"';
}
rw_quotechar (chstr, *last, noesc);
while (last != pwc) {
s += sprintf (s, "%s", chstr);
++last;
}
last_repeat = 0;
if (size_t (pwc - wstr) == nchars) {
if (!noesc)
*s++ = '\"';
*s = '\0';
break;
}
}
if (size_t (pwc - wstr) == nchars)
break;
}
if (any_repeats) {
const size_t len = strlen (next);
memmove (next + 2, next, len);
next [0] = '{';
next [1] = ' ';
next [len + 2] = ' ';
next [len + 3] = '}';
next [len + 4] = '\0';
s = next + len + 4;
}
return int (s - bufend);
#endif
}
/********************************************************************/
static int
_rw_fmtchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
{
typedef unsigned char UChar;
const UChar uc = UChar (val);
char buffer [8];
int len = rw_quotechar (buffer + spec.fl_pound, uc, !spec.fl_pound);
if (spec.fl_pound) {
buffer [0] = buffer [len + 1] = '\'';
buffer [len + 2] = '\0';
len += 2;
}
FmtSpec newspec (spec);
newspec.fl_pound = 0;
return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len));
}
/********************************************************************/
static int
_rw_fmtwchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, wint_t val)
{
const wchar_t wc = wchar_t (val);
char buffer [16];
int len = rw_quotechar (buffer + 2 * spec.fl_pound, wc, !spec.fl_pound);
if (spec.fl_pound) {
buffer [0] = 'L';
buffer [1] = buffer [len + 2] = '\'';
buffer [len + 3] = '\0';
len += 3;
}
FmtSpec newspec (spec);
newspec.fl_pound = 0;
return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len));
}
/********************************************************************/
static int
_rw_fmtstr (const FmtSpec &spec,
char **pbuf, size_t *pbufsize, const char *str, size_t len)
{
assert (1);
return 0;
#if 0
if (spec.fl_pound)
return rw_quotestr (spec, pbuf, pbufsize, str, len, 0);
if (0 == str)
str = "(null)";
if (0 > _RW::__rw_memattr (str, _RWSTD_SIZE_MAX, 0)) {
const size_t buflen = *pbuf ? strlen (*pbuf) : 0;
if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18))
return -1;
FmtSpec newspec (spec);
newspec.fl_pound = 1;
if (-1 == _rw_fmtptr (newspec, pbuf, pbufsize, str))
return -1;
if (0 == _rw_bufcat (pbuf, pbufsize, ")", 2))
return -1;
return int (strlen (*pbuf) - buflen);
}
if (_RWSTD_SIZE_MAX == len)
len = strlen (str);
// compute the minimum number of characters to be generated
if (-1 < spec.prec && size_t (spec.prec) < len)
len = size_t (spec.prec);
// the number of generated characters depends on three variables:
// -- the optional field width,
// -- the optional precision, and
// -- the length of the argument
// compute the field width
const size_t width =
-1 < spec.width && len < size_t (spec.width) ?
size_t (spec.width) : len;
// compute the size of padding
const size_t pad = len < width ? width - len : 0;
// [re]allocate enough space in the buffer
if (0 == _rw_bufcat (pbuf, pbufsize, 0, pad + len))
return -1;
assert (0 != *pbuf);
char *next = *pbuf + strlen (*pbuf);
if (!spec.fl_minus) {
for (size_t i = 0; i != pad; ++i)
*next++ = ' ';
}
memcpy (next, str, len);
next += len;
if (spec.fl_minus) {
for (size_t i = 0; i != pad; ++i)
*next++ = ' ';
}
*next++ = '\0';
return int (pad + len);
#endif
}
/********************************************************************/
static int
_rw_fmtwstr (const FmtSpec &spec,
char **pbuf, size_t *pbufsize, const wchar_t *wstr, size_t len)
{
return rw_quotestr (spec, pbuf, pbufsize, wstr, len, 1);
}
/********************************************************************/
struct Bitnames
{
const char *longname;
const char *name;
int bits;
};
#define BITNAME(qual, name) { #qual "::" #name, #name, qual::name }
static int
rw_bmpfmt (const FmtSpec&, char **pbuf, size_t *pbufsize,
const Bitnames bmap[], size_t size, int bits)
{
assert (0 != pbuf);
char buffer [1024];
*buffer = '\0';
// string to use when no bits are set
const char* all_clear = "0";
for (size_t i = 0; i != size; ++i) {
if (bmap [i].bits) {
if ((bits & bmap [i].bits) == bmap [i].bits) {
strcat (*buffer ? strcat (buffer, " | ") : buffer,
bmap [i].name);
bits &= ~bmap [i].bits;
}
}
else {
// save the name of the constant to use for 0
all_clear = bmap [i].name;
}
}
size_t buffersize;
if ('\0' == *buffer) {
// no constant matched, format teh value either as a number
// or, when 0, using the all_clear name (see above)
if (bits)
sprintf (buffer, "%#x", bits);
else
strcpy (buffer, all_clear);
buffersize = strlen (buffer) + 1;
}
else if (bits) {
buffersize = strlen (buffer) + 1;
// verify that buffer wasn't overflowed
assert (buffersize <= sizeof buffer);
char bitstr [32];
const int n = sprintf (bitstr, "%#x | ", bits);
assert (0 < n);
memmove (buffer + n, buffer, buffersize);
memcpy (buffer, bitstr, size_t (n));
buffersize += n;
}
else {
buffersize = strlen (buffer) + 1;
}
// verify that buffer wasn't overflowed
assert (buffersize <= sizeof buffer);
if (0 == _rw_bufcat (pbuf, pbufsize, buffer, buffersize))
return -1;
return int (buffersize);
}
/********************************************************************/
static int
rw_fmtflags (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits)
{
static const Bitnames names [] = {
BITNAME (std::ios, adjustfield),
BITNAME (std::ios, basefield),
BITNAME (std::ios, boolalpha),
BITNAME (std::ios, dec),
BITNAME (std::ios, fixed),
BITNAME (std::ios, hex),
BITNAME (std::ios, internal),
BITNAME (std::ios, left),
BITNAME (std::ios, oct),
BITNAME (std::ios, right),
BITNAME (std::ios, scientific),
BITNAME (std::ios, showbase),
BITNAME (std::ios, showpoint),
BITNAME (std::ios, showpos),
BITNAME (std::ios, skipws),
BITNAME (std::ios, unitbuf),
BITNAME (std::ios, uppercase),
#ifndef _RWSTD_NO_EXT_BIN_IO
// extension: produce binary output (similar to oct, dec, and hex)
BITNAME (std::ios, bin),
#endif // _RWSTD_NO_EXT_BIN_IO
#ifndef _RWSTD_NO_EXT_REENTRANT_IO
// extension: allow unsychronized access to stream and/or its buffer
BITNAME (std::ios, nolock),
BITNAME (std::ios, nolockbuf)
#endif // _RWSTD_NO_EXT_REENTRANT_IO
};
static const size_t count = sizeof names / sizeof *names;
const int base = (bits >> _RWSTD_IOS_BASEOFF) & _RWSTD_IOS_BASEMASK;
// zero out bits representingthe numeric base
bits &= ~(_RWSTD_IOS_BASEMASK << _RWSTD_IOS_BASEOFF);
int len = rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits);
if (base && base != 8 && base != 10 && base != 16) {
// for numeric bases other than those required by the standard,
// use the text "base (%d)" to show the extended numeric base
#ifndef _RWSTD_NO_EXT_BIN_IO
if (bits & std::ios::bin)
return len;
#endif // _RWSTD_NO_EXT_BIN_IO
char basestr [64];
sprintf (basestr, " | std::ios::base(%d)", base);
strcat (*pbuf, basestr);
len = int (strlen (*pbuf));
}
return len;
}
/********************************************************************/
static int
rw_fmtiostate (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits)
{
static const Bitnames names [] = {
BITNAME (std::ios, goodbit),
BITNAME (std::ios, badbit),
BITNAME (std::ios, eofbit),
BITNAME (std::ios, failbit)
};
static const size_t count = sizeof names / sizeof *names;
return rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits);
}
/********************************************************************/
static int
_rw_fmtopenmode (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits)
{
static const Bitnames names [] = {
#ifndef __SYMBIAN32__
#ifndef _RWSTD_NO_EXTENSIONS
{ "std::ios::nocreate", "nocreate", std::ios::nocreate },
{ "std::ios::noreplace", "noreplace", std::ios::noreplace },
#else // if defined (_RWSTD_NO_EXTENSIONS)
{ "__rw:::__rw_nocreate", "__rw_nocreate", _RW::__rw_nocreate },
{ "__rw::__rw_noreplace", "__rw_noreplace", _RW::__rw_noreplace },
#endif // _RWSTD_NO_EXTENSIONS
#ifndef _RWSTD_NO_EXT_STDIO
{ "std::ios::stdio", "stdio", std::ios::stdio },
{ "std::ios::native", "native", std::ios::native },
#else // if defined (_RWSTD_NO_EXT_STDIO)
{ "__rw::__rw_stdio", "__rw_stdio", _RW::__rw_stdio },
{ "__rw::__rw_native", "__rw_native", _RW::__rw_native },
#endif // _RWSTD_NO_EXT_STDIO
#endif
BITNAME (std::ios, app),
BITNAME (std::ios, binary),
BITNAME (std::ios, in),
BITNAME (std::ios, out),
BITNAME (std::ios, trunc),
BITNAME (std::ios, ate)
};
static const size_t count = sizeof names / sizeof *names;
return rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits);
}
/********************************************************************/
static int
_rw_fmtevent (const FmtSpec&, char **pbuf, size_t *pbufsize, int event)
{
const char* str =
std::ios::copyfmt_event == event ? "copyfmt_event"
: std::ios::imbue_event == event ? "imbue_event"
: std::ios::erase_event == event ? "erase_event"
: 0;
char buffer [64];
if (!str) {
sprintf (buffer, "copyfmt_event(%d)", event);
str = buffer;
}
const size_t len = strlen (str);
if (0 == _rw_bufcat (pbuf, pbufsize, str, len))
return -1;
return int (len);
}
/********************************************************************/
static int
rw_fmtlc (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
{
const char *str = 0;
switch (val) {
case LC_ALL: str = "LC_ALL"; break;
case LC_COLLATE: str = "LC_COLLATE"; break;
case LC_CTYPE: str = "LC_CTYPE"; break;
case LC_MONETARY: str = "LC_MONETARY"; break;
case LC_NUMERIC: str = "LC_NUMERIC"; break;
case LC_TIME: str = "LC_TIME"; break;
#ifdef LC_MESSAGES
case LC_MESSAGES: str = "LC_MESSAGES"; break;
#endif // LC_MESSAGES
}
if (str) {
const std::size_t len = strlen (str);
if (0 == _rw_bufcat (pbuf, pbufsize, str, len))
return -1;
return int (len);
}
static const Bitnames names [] = {
BITNAME (std::locale, all),
BITNAME (std::locale, none),
BITNAME (std::locale, collate),
BITNAME (std::locale, ctype),
BITNAME (std::locale, monetary),
BITNAME (std::locale, numeric),
BITNAME (std::locale, messages),
BITNAME (std::locale, time)
};
static const size_t count = sizeof names / sizeof *names;
return rw_bmpfmt (spec, pbuf, pbufsize, names, count, val);
}
/********************************************************************/
static int
_rw_fmtmonpat (const FmtSpec&,
char **pbuf, size_t *pbufsize, const char pat [4])
{
char buffer [80];
buffer [0] = '\0';
for (int i = 0; i != 4; ++i) {
switch (pat [i]) {
case std::money_base::symbol:
strcat (buffer, "symbol ");
break;
case std::money_base::sign:
strcat (buffer, "sign ");
break;
case std::money_base::none:
strcat (buffer, "none ");
break;
case std::money_base::value:
strcat (buffer, "value ");
break;
case std::money_base::space:
strcat (buffer, "space ");
break;
default:
sprintf (buffer + strlen (buffer), "\\%03o", pat [i]);
break;
}
}
const size_t len = strlen (buffer);
if (0 == _rw_bufcat (pbuf, pbufsize, buffer, len))
return -1;
return int (len);
}
/********************************************************************/
static int
libstd_vasnprintf (FmtSpec *pspec, size_t paramno,
char **pbuf, size_t *pbufsize,
const char *fmt, va_list *pva)
{
assert (0 != pva);
assert (0 != pspec);
_RWSTD_UNUSED (fmt);
FmtSpec &spec = pspec [paramno];
// the length of the sequence appended to the buffer to return
// to the caller, or a negative value (such as -1) on error
int len = -1;
switch (spec.cvtspec) {
case '?': // %{?}
// beginning of an if clause
spec.cond = 1;
spec.cond_begin = 1;
spec.cond_true = 0 != va_arg (*pva, int);
len = 0;
break;
case ':': // %{:}
if (spec.cond) {
// end of an active if clause and the beginning
// of an inactive else clause
spec.cond_begin = 1; // beginning of an else clause
spec.cond_end = 1; // end of an if clause
spec.cond_true = !spec.cond_true;
len = 0;
}
else {
// misplaced "%{:}"?
static const char str[] = "%{:}";
len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0);
}
break;
case ';': // %{;}
if (spec.cond) {
spec.cond_end = 1; // end of an if or else clause
len = 0;
}
else {
// misplaced "%{;}"?
static const char str[] = "%{;}";
len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0);
}
break;
case 'c': // %{c}, %{Ac}, %{Lc}, %{lc}
if (spec.mod_A) {
if (-1 == spec.width || 1 == spec.width) {
spec.param.ptr = PARAM (_RWSTD_UINT8_T*, ptr);
const _RWSTD_UINT8_T* const array =
(_RWSTD_UINT8_T*)spec.param.ptr;
len = rw_quotestr (spec, pbuf, pbufsize, array,
_RWSTD_SIZE_MAX, 0);
}
else if (2 == spec.width) {
spec.param.ptr = PARAM (_RWSTD_UINT16_T*, ptr);
const _RWSTD_UINT16_T* const array =
(_RWSTD_UINT16_T*)spec.param.ptr;
len = rw_quotestr (spec, pbuf, pbufsize, array,
_RWSTD_SIZE_MAX, 0);
}
else if (4 == spec.width) {
spec.param.ptr = PARAM (_RWSTD_UINT32_T*, ptr);
const _RWSTD_UINT32_T* const array =
(_RWSTD_UINT32_T*)spec.param.ptr;
len = rw_quotestr (spec, pbuf, pbufsize, array,
_RWSTD_SIZE_MAX, 0);
}
#ifdef _RWSTD_UINT64_T
else if (8 == spec.width) {
spec.param.ptr = PARAM (_RWSTD_UINT64_T*, ptr);
const _RWSTD_UINT64_T* const array =
(_RWSTD_UINT64_T*)spec.param.ptr;
len = rw_quotestr (spec, pbuf, pbufsize, array,
_RWSTD_SIZE_MAX, 0);
}
#endif // _RWSTD_UINT64_T
else {
assert (!"%{Ac} not implemented for this character size");
}
}
else if (spec.mod_L) { // locale category or LC_XXX constant
spec.param.i = PARAM (int, i);
len = rw_fmtlc (spec, pbuf, pbufsize, spec.param.i);
}
else if (spec.mod_l) { // wchar_t
spec.param.wi = PARAM (wint_t, i);
return _rw_fmtwchr (spec, pbuf, pbufsize, spec.param.wi);
}
else { // char
spec.param.i = PARAM (int, i);
return _rw_fmtchr (spec, pbuf, pbufsize, spec.param.i);
}
break;
case 'e': // %{e}, %{Ae}
if (spec.mod_A) { // array of floating point values
spec.param.ptr = PARAM (void*, ptr);
len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr);
}
else if (spec.mod_I) { // ios::copyfmt_event
spec.param.i = PARAM (int, i);
len = _rw_fmtevent (spec, pbuf, pbufsize, spec.param.i);
}
break;
case 'f': // %{f}, %{Af}, %{If}
if (spec.mod_A) { // array of floating point values
spec.param.ptr = PARAM (void*, ptr);
len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr);
}
if (spec.mod_I) { // ios::fmtflags
spec.param.i = PARAM (int, i);
len = rw_fmtflags (spec, pbuf, pbufsize, spec.param.i);
}
else { // function pointer
spec.param.funptr = PARAM (funptr_t, funptr);
len = _rw_fmtfunptr (spec, pbuf, pbufsize, spec.param.funptr);
}
break;
case 'g': // %{g}, %{Ag}
if (spec.mod_A) { // array of floating point values
spec.param.ptr = PARAM (void*, ptr);
len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr);
}
else {
assert (!"%{g} not implemented");
}
case 'd': // %{Id}
case 'i': // %{Ii}
case 'o': // %{Io}
if (spec.mod_I) { // ios::openmode
spec.param.i = PARAM (int, i);
len = _rw_fmtopenmode (spec, pbuf, pbufsize, spec.param.i);
break;
}
case 'x': // %{x}
case 'X': // %{X}
case 'u': // %{u}
len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva);
break;
case 'K': // %{K} -- signal
spec.param.i = PARAM (int, i);
len = _rw_fmtsignal (spec, pbuf, pbufsize, spec.param.i);
break;
case 'm': // %{m} -- errno
if (-1 == spec.width)
len = _rw_fmterrno (spec, pbuf, pbufsize, errno);
else
len = _rw_fmterrno (spec, pbuf, pbufsize, spec.width);
break;
case 'M': // %{M}, %{LM}
if (spec.mod_L) { // money_base::pattern
spec.param.ptr = PARAM (char*, ptr);
len = _rw_fmtmonpat (spec, pbuf, pbufsize, (char*)spec.param.ptr);
}
else { // member pointer
spec.param.memptr = PARAM (memptr_t, memptr);
len = _rw_fmtmemptr (spec, pbuf, pbufsize, spec.param.memptr);
}
break;
case 'n': { // %{n}
// The argument shall be a pointer to signed integer into which
// is written the size of the buffer allocated by this call to
// fprintf. No argument is converted, but one is consumed. If
// the conversion specification includes any flags, a field
// width, or a precision, the behavior is undefined.
assert (0 != pbuf);
assert (0 != *pbuf);
const size_t nbytes = pbufsize ? *pbufsize : 0;
spec.param.ptr = PARAM (void*, ptr);
if (spec.mod_hh) {
unsigned char* const ptr = (unsigned char*)spec.param.ptr;
assert (0 != ptr);
*ptr = (unsigned char)nbytes;
}
else if (spec.mod_h) {
short* const ptr = (short*)spec.param.ptr;
assert (0 != ptr);
*ptr = short (nbytes);
}
else if (spec.mod_L) {
#ifdef _RWSTD_LONG_LONG
_RWSTD_LONG_LONG* const ptr = (_RWSTD_LONG_LONG*)spec.param.ptr;
assert (0 != ptr);
*ptr = (_RWSTD_LONG_LONG)(nbytes);
#else // if !defined (_RWSTD_LONG_LONG)
assert (!"%{Ln} not implemented");
#endif // _RWSTD_LONG_LONG
}
else if (spec.mod_l) {
long* const ptr = (long*)spec.param.ptr;
assert (0 != ptr);
*ptr = long (nbytes);
}
else if (spec.mod_t) {
ptrdiff_t* const ptr = (ptrdiff_t*)spec.param.ptr;
assert (0 != ptr);
*ptr = ptrdiff_t (nbytes);
}
else {
int* const ptr = (int*)spec.param.ptr;
assert (0 != ptr);
*ptr = int (nbytes);
}
len = 0;
break;
}
case 's': // %{s}, %{Is}, %{ls}
if (spec.mod_I) { // ios::iostate
spec.param.i = PARAM (int, i);
len = rw_fmtiostate (spec, pbuf, pbufsize, spec.param.i);
}
else if (spec.mod_l) { // wchar_t*
spec.param.ptr = PARAM (wchar_t*, ptr);
const wchar_t* const wstr = (wchar_t*)spec.param.ptr;
len = rw_quotestr (spec, pbuf, pbufsize, wstr, _RWSTD_SIZE_MAX, 0);
}
else { // char*
spec.param.ptr = PARAM (char*, ptr);
const char* const str = (char*)spec.param.ptr;
len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0);
}
break;
case 'S': // %{S}, %{lS}
if (spec.mod_l) { // std::wstring
spec.param.ptr = PARAM (std::wstring*, ptr);
const std::wstring* const pstr = (std::wstring*)spec.param.ptr;
const wchar_t* const wstr = pstr->data ();
const std::wstring::size_type size = pstr->size ();
len = _rw_fmtwstr (spec, pbuf, pbufsize, wstr, size);
}
else { // std::string
spec.param.ptr = PARAM (std::string*, ptr);
const std::string* const pstr = (std::string*)spec.param.ptr;
const char* const str = pstr->data ();
const std::string::size_type size = pstr->size ();
len = _rw_fmtstr (spec, pbuf, pbufsize, str, size);
}
break;
default:
if (spec.strarg) {
// environment variable
const char* val = getenv (spec.strarg);
if (!val)
val = "";
len = int (strlen (val));
if (0 == _rw_bufcat (pbuf, pbufsize, val, size_t (len)))
return -1;
free (spec.strarg);
}
else {
assert (!"not implemented");
}
}
return len;
}
/********************************************************************/
/* extern */ int
(*rw_vasnprintf_cb)(FmtSpec*, size_t, char**, size_t*, const char*, va_list*)
= libstd_vasnprintf;
/********************************************************************/
_TEST_EXPORT int
rw_asnprintf (char **pbuf, size_t *pbufsize, const char *fmt, ...)
{
assert (0 == pbuf || 0 == *pbuf || pbufsize);
va_list va;
va_start (va, fmt);
char* buf = 0;
size_t bufsize = 0;
if (0 == pbuf) {
// if pbyf is 0 (i.e., this is a request for the size of the
// buffer necessary to format all the arguments), set pbuf to
// point to a local buf
pbuf = &buf;
}
if (0 == pbufsize) {
// pbuf may be 0 regardless of the value of pbuf
pbufsize = &bufsize;
}
const int nchars = rw_vasnprintf (pbuf, pbufsize, fmt, va);
va_end (va);
// verify that the length of the fomatted buffer is less than
// its size (this test is unreliable if there are any embedded
// NULs in the output)
assert (nchars < 0 || strlen (*pbuf) < *pbufsize);
if (pbuf == &buf) {
// free the character buffer if pbuf was initially 0
free (pbuf);
}
return nchars;
}
/********************************************************************/
_TEST_EXPORT char*
rw_snprintfa (char *buf, size_t bufsize, const char* fmt, ...)
{
if (buf)
*buf = '\0';
va_list va;
va_start (va, fmt);
const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va);
va_end (va);
// verify that the length of the fomatted buffer is less than
// its size (this test is unreliable if there are any embedded
// NULs in the output)
assert (nchars < 0 || strlen (buf) < bufsize);
_RWSTD_UNUSED (nchars);
return buf;
}
/********************************************************************/
_TEST_EXPORT char*
rw_sprintfa (const char *fmt, ...)
{
char* buf = 0;
size_t bufsize = 0;
va_list va;
va_start (va, fmt);
const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va);
va_end (va);
// verify that the length of the fomatted buffer is less than
// its size (this test is unreliable if there are any embedded
// NULs in the output)
assert (nchars < 0 || strlen (buf) < bufsize);
_RWSTD_UNUSED (nchars);
return buf;
}
/********************************************************************/
// avoid re-declaring these as exported here and instead rely on the
// declaration in the header #included above in order to prevent the
// bogus MSVC error:
// error C2201: 'rw_stdout' : must have external linkage in order to
// be exported/imported
/* _TEST_EXPORT */ rw_file* const
rw_stdout = _RWSTD_REINTERPRET_CAST (rw_file*, stdout);
/* _TEST_EXPORT */ rw_file* const
rw_stderr = _RWSTD_REINTERPRET_CAST (rw_file*, stderr);
/********************************************************************/
static int
_rw_vfprintf (rw_file *file, const char *fmt, va_list va)
{
assert (0 != file);
char* buf = 0;
size_t bufsize = 0;
const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va);
// FIXME: implement this in terms of POSIX write()
// for async-signal safety
FILE* const stdio_file = _RWSTD_REINTERPRET_CAST (FILE*, file);
const int nwrote = 0 < nchars ?
fwrite (buf, 1, nchars, stdio_file) : nchars;
// flush in case stderr isn't line-buffered (e.g., when
// it's determined not to refer to a terminal device,
// for example after it has been redirected to a file)
fflush (stdio_file);
#ifdef _MSC_VER
// IsDebuggerPresent() depends on the macros _WIN32_WINNT and WINVER
// being appropriately #defined prior to the #inclusion of <windows.h>
if (IsDebuggerPresent ()) {
// write string to the attached debugger (if any)
OutputDebugString (buf);
}
#endif // _MSC_VER
free (buf);
return nwrote;
}
/********************************************************************/
_TEST_EXPORT int
rw_fprintf (rw_file *file, const char *fmt, ...)
{
va_list va;
va_start (va, fmt);
const int nchars = _rw_vfprintf (file, fmt, va);
va_end (va);
return nchars;
}
/********************************************************************/
_TEST_EXPORT int
rw_printf (const char *fmt, ...)
{
va_list va;
va_start (va, fmt);
const int nchars = _rw_vfprintf (rw_stdout, fmt, va);
va_end (va);
return nchars;
}