diff -r e20de85af2ee -r ce057bb09d0b stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/printf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/printf.cpp Fri Jun 04 16:20:51 2010 +0100 @@ -0,0 +1,3414 @@ +/************************************************************************ + * + * 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 +#include + +#include // for assert +#include // for errno, errno constants +#include // for floating point macros +#include +#ifndef __SYMBIAN32__ +#include // for signal constant +#endif +#include // for va_list, va_start, ... +#include +#include +#include +#include +#include + +#if (defined (_WIN32) || defined (_WIN64)) && !defined(__SYMBIAN32__) + // define macros to enable Win98 + WinNT support in +# define _WIN32_WINNT 0x0410 +# define WINVER 0x400 +# include // for IsDebuggerPresent() +#else +# include +#endif // _WIN{32,64} + +#include +#include +#include +//#include +#include + +#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[:[:...[:]]] +// 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 +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 +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' ", + -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 + 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; +}