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