First public contribution.
1 /************************************************************************
3 * printf.cpp - definitions of the rw_printf family of functions
5 * $Id: printf.cpp 351515 2005-12-01 23:19:44Z sebor $
7 ************************************************************************
9 * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave
10 * Software division. Licensed under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance with the
12 * License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0. Unless required by
14 * applicable law or agreed to in writing, software distributed under
15 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
16 * CONDITIONS OF ANY KIND, either express or implied. See the License
17 * for the specific language governing permissions and limitations under
20 **************************************************************************/
22 // expand _TEST_EXPORT macros
23 #define _RWSTD_TEST_SRC
27 #include <assert.h> // for assert
28 #include <errno.h> // for errno, errno constants
29 #include <float.h> // for floating point macros
32 #include <signal.h> // for signal constant
34 #include <stdarg.h> // for va_list, va_start, ...
41 #if (defined (_WIN32) || defined (_WIN64)) && !defined(__SYMBIAN32__)
42 // define macros to enable Win98 + WinNT support in <windows.h>
43 # define _WIN32_WINNT 0x0410
45 # include <windows.h> // for IsDebuggerPresent()
57 #pragma diag_suppress 61
58 #pragma diag_suppress 63
61 #define _RWSTD_NO_EXT_BIN_IO
62 #define _RWSTD_NO_EXT_REENTRANT_IO
66 _RWSTD_NAMESPACE (__rw) {
68 _RWSTD_EXPORT _RWSTD_SSIZE_T
69 __rw_memattr (const void*, size_t, int);
75 /********************************************************************/
79 unsigned char bytes [sizeof (int)];
83 _rw_big_endian = '\0' == _rw_one.bytes [0];
86 /********************************************************************/
91 _rw_fmtlong (const FmtSpec&, char**, size_t*, long);
93 #ifdef _RWSTD_LONG_LONG
96 _rw_fmtllong (const FmtSpec&, char**, size_t*, _RWSTD_LONG_LONG);
98 #endif // _RWSTD_LONG_LONG
101 _rw_fmtinteger (FmtSpec*, size_t, char**, size_t*, va_list*);
104 _rw_fmtfloating (const FmtSpec&, char**, size_t*, const void*);
107 _rw_fmtptr (const FmtSpec&, char**, size_t*, const void*);
109 typedef void (*funptr_t)();
112 _rw_fmtfunptr (const FmtSpec&, char**, size_t*, funptr_t);
115 typedef void (DummyStruct::*memptr_t)() const;
118 _rw_fmtmemptr (const FmtSpec&, char**, size_t*, memptr_t);
121 _rw_fmtstr (const FmtSpec&, char**, size_t*, const char*, size_t);
124 _rw_fmtchr (const FmtSpec&, char**, size_t*, int);
127 _rw_fmtwchr (const FmtSpec&, char**, size_t*, wint_t);
130 _rw_fmtwstr (const FmtSpec&, char**, size_t*, const wchar_t*, size_t);
133 _rw_fmterrno (const FmtSpec&, char**, size_t*, int);
136 _rw_fmtopenmode (const FmtSpec&, char**, size_t*, int);
139 _rw_fmtevent (const FmtSpec&, char**, size_t*, int);
142 _rw_fmtmonpat (const FmtSpec&, char**, size_t*, const char [4]);
145 _rw_fmtsignal (const FmtSpec&, char**, size_t*, int);
147 /********************************************************************/
152 unsigned fl_minus : 1;
153 unsigned fl_plus : 1;
154 unsigned fl_pound : 1;
155 unsigned fl_space : 1;
156 unsigned fl_zero : 1;
158 // optional modifiers
159 unsigned mod_A : 1; // extension (Arrays)
160 unsigned mod_h : 1; // short modifier
161 unsigned mod_hh : 1; // char modifier
162 unsigned mod_l : 1; // long modifier
163 unsigned mod_ll : 1; // long long modifier
164 unsigned mod_j : 1; // intmax_t modifier
165 unsigned mod_z : 1; // size_t modifier
166 unsigned mod_t : 1; // ptrdiff_t modifier
167 unsigned mod_L : 1; // long double modifier
168 unsigned mod_I : 1; // extension
170 unsigned cond : 1; // have an if/else clause
171 unsigned cond_true : 1; // if/else clause is active (true)
172 unsigned cond_begin : 1; // beginning of an if/else clause
173 unsigned cond_end : 1; // end of an if/else clause
175 // note that the signedness of a bitfield is implementation-defined
176 // unless explicitly declared signed or unsigned
178 // extension: 8, 16, 32, and 64 bit integer width modifier
179 signed int iwidth : 4;
181 // extension: optional numerical base 2 - 36
184 // extension: optional parameter number
187 // optional width and precision
191 // extension: string argument
194 // required conversion specifier
197 // extension: fill character
202 #ifndef _RWSTD_NO_LONG_DOUBLE
206 #endif // _RWSTD_NO_LONG_DOUBLE
208 #ifdef _RWSTD_LONG_LONG
210 _RWSTD_LONG_LONG llong;
212 #endif // _RWSTD_LONG_LONG
221 #ifdef _RWSTD_INT64_T
223 #endif // _RWSTD_INT64_T
235 /********************************************************************/
239 C99 format specifier:
241 % flags width [ . prec ] mod cvtspec
244 GNU glibc format specifier:
246 % [ paramno $] flags width [ . prec ] mod cvtspec
248 % [ paramno $] flags width . * [ paramno $] mod cvtspec
251 Extended format specifier:
253 % { [ paramno $] [ flags ] [ width [. prec ]] mod cvtspec }
255 % { [ paramno $] [ flags ] [@ base [. width [. prec ]]] mod cvtspec }
263 _rw_fmtspec (FmtSpec *pspec, bool ext, const char *fmt, va_list *pva)
269 memset (pspec, 0, sizeof *pspec);
271 pspec->iwidth = -1; // integer width not specified
272 pspec->width = -1; // width not specified
273 pspec->prec = -1; // precision not specified
274 pspec->base = -1; // base not specified
275 pspec->paramno = -1; // paramno not specified
277 const char* const fmtbeg = fmt;
286 str = va_arg (*pva, char*);
296 char *tmp = (char*)malloc (strlen (str));
297 pspec->strarg = strcpy (tmp, str);
299 return int (fmt - fmtbeg);
303 // extension: extract the parameter number (if followed by '$')
304 if ('1' <= *fmt && *fmt <= '9') {
306 const long tmp = strtol (fmt, &end, 10);
311 pspec->paramno = tmp;
315 // when not followed by '$' interpret the number
316 // as the width (i.e., that follows the empty set
318 pspec->width = int (tmp);
322 if (-1 == pspec->width) {
323 // extract any number of optional flags
326 case '-': pspec->fl_minus = true; continue;
327 case '+': pspec->fl_plus = true; continue;
328 case '#': pspec->fl_pound = true; continue;
329 case ' ': pspec->fl_space = true; continue;
330 case '0': pspec->fl_zero = true; continue;
336 if (ext && '@' == *fmt) {
340 // extract the numerical base
341 if ('0' <= fmt [1] && fmt [1] <= '9') {
343 pspec->base = int (strtol (fmt, &end, 10));
346 else if ('*' == *fmt) {
347 pspec->base = va_arg (*pva, int);
355 if (-1 == pspec->width) {
356 // extract the optional width
357 if ('0' <= *fmt && *fmt <= '9') {
359 pspec->width = int (strtol (fmt, &end, 10));
362 else if ('*' == *fmt) {
363 pspec->width = va_arg (*pva, int);
365 if (pspec->width < 0) {
366 // 7.19.6.1, p5 of ISO/IEC 9899:1999:
367 // A negative field width argument is taken
368 // as a - flag followed by a positive field width.
369 pspec->width = -pspec->width;
370 pspec->fl_minus = true;
377 // extract the optional precision
382 if ('0' <= *fmt && *fmt <= '9') {
384 pspec->prec = int (strtol (fmt, &end, 10));
387 else if ('*' == *fmt) {
388 pspec->prec = va_arg (*pva, int);
393 // extract an optional modifier
404 if ('h' == fmt [1]) {
406 pspec->mod_hh = true;
414 if ('l' == fmt [1]) {
416 pspec->mod_ll = true;
423 case 'j': pspec->mod_j = true; ++fmt; break;
424 case 'z': pspec->mod_z = true; ++fmt; break;
425 case 't': pspec->mod_t = true; ++fmt; break;
426 case 'L': pspec->mod_L = true; ++fmt; break;
437 else if ('1' == fmt [0] && '6' == fmt [1]) {
441 else if ('3' == fmt [0] && '2' == fmt [1]) {
445 else if ('6' == fmt [0] && '4' == fmt [1]) {
456 pspec->cvtspec = *fmt;
461 return int (fmt - fmtbeg);
464 /********************************************************************/
466 _RWSTD_INTERNAL char*
467 _rw_bufcat (char **pbuf, size_t *pbufsize, const char *str, size_t len)
470 assert (0 != pbufsize);
472 size_t buflen = *pbuf ? strlen (*pbuf) : 0;
473 const size_t bufree = *pbuf ? *pbufsize - buflen : 0;
475 if (bufree <= len || !*pbuf) {
478 static const char deadbeef[] = "\xde\xad\xbe\xef";
480 size_t newbufsize = *pbufsize * 2 + 4;
482 if (newbufsize <= buflen + len + 4)
483 newbufsize = 2 * (buflen + len + 1) + 4;
485 char* const newbuf = (char*)malloc (newbufsize);
487 // return 0 on failure to allocate, let caller deal with it
491 memcpy (newbuf, *pbuf, buflen);
493 // append a guard block to the end of the buffer
494 memcpy (newbuf + newbufsize - 4, deadbeef, 4);
497 // verify that we didn't write past the end of the buffer
498 assert (0 == memcmp (*pbuf + *pbufsize, deadbeef, 4));
503 *pbufsize = newbufsize - 4;
505 (*pbuf)[buflen] = '\0';
509 memcpy (*pbuf + buflen, str, len);
511 (*pbuf)[buflen] = '\0';
514 return *pbuf + buflen;
517 /********************************************************************/
519 // rw_asnprintf_cb is called to format a character string according
520 // to the single format specifier `fmt' to the end of the provided
521 // buffer `*pbuf'; the function can reallocate the buffer
522 // returns the number of characters appended to the buffer
524 (*rw_vasnprintf_cb)(FmtSpec*, size_t, char**, size_t*, const char*, va_list*);
526 /********************************************************************/
529 _rw_vasnprintf_c99 (FmtSpec *pspec, size_t paramno,
530 char **pbuf, size_t *pbufsize, va_list *pva)
532 _RWSTD_UNUSED (paramno);
534 _RWSTD_ASSERT (0 != pspec);
538 FmtSpec &spec = pspec [paramno];
540 #define PARAM(T, name) \
541 (0 < spec.paramno ? pspec [spec.paramno - 1].param.name : va_arg (*pva, T))
543 switch (spec.cvtspec) {
551 len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva);
561 spec.param.ldbl = PARAM (long double, ldbl);
562 len = _rw_fmtfloating (spec, pbuf, pbufsize, &spec.param.ldbl);
565 spec.param.dbl = PARAM (double, dbl);
566 len = _rw_fmtfloating (spec, pbuf, pbufsize, &spec.param.dbl);
571 assert (!"%a not implemented");
575 assert (!"%A not implemented");
579 // If no l length modifier is present, the int argument is converted
580 // to an unsigned char, and the resulting character is written. If
581 // an l length modifier is present, the wint_t argument is converted
582 // as if by an ls conversion specification with no precision and an
583 // argument that points to the initial element of a two-element array
584 // of wchar_t, the first element containing the wint_t argument to
585 // the lc conversion specification and the second a null wide
588 spec.param.wi = PARAM (wint_t, wi);
589 len = _rw_fmtwchr (spec, pbuf, pbufsize, spec.param.wi);
592 spec.param.i = PARAM (int, i);
593 len = _rw_fmtchr (spec, pbuf, pbufsize, spec.param.i);
599 spec.param.ptr = PARAM (wchar_t*, ptr);
600 const wchar_t* const str = (wchar_t*)spec.param.ptr;
601 len = _rw_fmtwstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX);
604 spec.param.ptr = PARAM (char*, ptr);
605 const char* const str = (char*)spec.param.ptr;
606 len = _rw_fmtstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX);
611 // The argument shall be a pointer to void. The value of the pointer
612 // is converted to a sequence of printing characters, in an
613 // implementation-defined manner.
614 spec.param.ptr = PARAM (char*, ptr);
615 len = _rw_fmtptr (spec, pbuf, pbufsize, spec.param.ptr);
619 case 'm': { // %m (popular extension)
620 spec.param.i = errno;
621 len = _rw_fmterrno (spec, pbuf, pbufsize, spec.param.i);
626 // The argument shall be a pointer to signed integer into which
627 // is written the number of characters written to the output
628 // stream so far by this call to fprintf. No argument is converted,
629 // but one is consumed. If the conversion specification includes
630 // any flags, a field width, or a precision, the behavior is
636 len = int (strlen (*pbuf));
638 spec.param.ptr = PARAM (void*, ptr);
641 unsigned char* const ptr = (unsigned char*)spec.param.ptr;
647 else if (spec.mod_h) {
648 short* const ptr = (short*)spec.param.ptr;
654 else if (spec.mod_L) {
655 #ifdef _RWSTD_LONG_LONG
656 _RWSTD_LONG_LONG* const ptr = (_RWSTD_LONG_LONG*)spec.param.ptr;
661 #else // if !defined (_RWSTD_LONG_LONG)
662 assert (!"%Ln not implemented");
663 #endif // _RWSTD_LONG_LONG
665 else if (spec.mod_l) {
666 long* const ptr = (long*)spec.param.ptr;
672 else if (spec.mod_t) {
673 ptrdiff_t* const ptr = (ptrdiff_t*)spec.param.ptr;
677 *ptr = ptrdiff_t (unsigned (len));
680 int* const ptr = (int*)spec.param.ptr;
696 /********************************************************************/
699 rw_vasnprintf (char **pbuf, size_t *pbufsize, const char *fmt, va_list varg)
704 // create a copy of va whose address can be passed to a function
705 // taking a va_list* so that it can modify the original; note that
706 // passing &va is not portable since when declared as a function
707 // argument, va_list that is an array type decays into a pointer
708 // and the address of the pointer will not match va_list* (as is
709 // the case on EM64T)
711 va_copy (vacpy, varg);
714 #else // if !defined (va_copy)
718 // use the gcc 3.x builtin when the va_copy macro is not defined
719 // (e.g., with gcc -ansi or Intel C++ icc -ansi or -strict_ansi)
721 __builtin_va_copy (vacpy, varg);
724 # else // if !defined (__GNUG__)
726 // use varg (in)directly and assume it's safe (e.g., HP aCC on PA)
729 # endif // 2 < __GNUG__
733 // do not use varg of vacpy below this point -- use *pva instead
734 #define varg DONT_TOUCH_ME
735 #define vacpy DONT_TOUCH_ME
739 // save the initial value of `pbuf'
740 char* const pbuf_save = *pbuf;
745 // local buffer for a small number of conversion specifiers
746 // will grow dynamically if their number exceeds its capacity
747 FmtSpec specbuf [32];
748 FmtSpec *pspec = specbuf;
750 // local buffer for backtrack offsets implementing conditionals
754 size_t default_bufsize = 1024;
757 pbufsize = &default_bufsize;
763 size_t spec_bufsize = sizeof specbuf / sizeof *specbuf;
766 for (const char *fc = fmt; *fc; ) {
768 const char* const pcnt = strchr (fc, '%');
770 size_t nchars = pcnt ? pcnt - fmt : strlen (fc);
772 next = _rw_bufcat (pbuf, pbufsize, fmt, nchars);
777 assert (0 != *pbufsize);
786 next = _rw_bufcat (pbuf, pbufsize, "%", 1);
794 if (spec_bufsize == paramno) {
795 // grow the buffer of conversion specifiers
796 FmtSpec *tmp = (FmtSpec*)malloc (spec_bufsize * 2);
798 memcpy (tmp, pspec, spec_bufsize);
799 if (pspec != specbuf)
808 const char* const endbrace = strchr (++fc, '}');
810 assert (0 != endbrace);
812 const size_t fmtlen = endbrace - fc;
814 memcpy (fmtspec, fc, fmtlen);
815 fmtspec [fmtlen] = '\0';
817 // compute the length of the buffer so far
818 const size_t buflen = next - *pbuf;
820 assert (0 != rw_vasnprintf_cb);
822 // initiaze the current format specification, setting
823 // all unused bits to 0
825 _rw_fmtspec (pspec + paramno, true, fc, pva);
827 _RWSTD_UNUSED (speclen);
829 // copy the current backtrack offset if one exists
830 // and set the condition and condition true bits
833 // set the condition valid bit
834 pspec [paramno].cond = 1;
836 if (backtrack [nextoff - 1] < 0) {
837 // negative offset indicates an active clause
838 pspec [paramno].cond_true = 1;
841 // non-negative offset indicates an inactive clause
846 // append formatted string to the end of the buffer
847 // reallocating it if necessary; callee may change
848 // the specification as necessary (e.g., based on
849 // the if/else clause)
852 rw_vasnprintf_cb (pspec, paramno, pbuf, pbufsize,
855 // the callback returns a negative value on error
859 assert (size_t (len) < *pbufsize);
860 assert (strlen (*pbuf) < *pbufsize);
862 const size_t offinx = nextoff - 1;
864 if (pspec [paramno].cond_end && pspec [paramno].cond_begin) {
865 // change from an if to an else clause
867 assert (0 < nextoff);
870 if (pspec [paramno].cond_true) {
871 // change from an inactive if to an active else
872 // (same as the end of an inactive clause)
874 assert (0 <= backtrack [offinx]);
876 // set the length so as to backtrack to the position
877 // saved on the top of the backtrack stack
878 len = -int (buflen) + backtrack [offinx];
880 // invert the offset to indicate an active clause
881 backtrack [offinx] = ~backtrack [offinx];
884 // change from an active if to an inactive else
885 assert (backtrack [offinx] < 0);
887 // save the current length of the buffer
888 // as the new backtrack offset
889 backtrack [offinx] = int (buflen);
892 else if (pspec [paramno].cond_begin) {
893 // start of a new if clause
895 // push it on the stack of backtracking offsets using
896 // negative values to indicate active clauses and
897 // non-negative values inactive ones
898 if (pspec [paramno].cond_true)
899 backtrack [nextoff++] = ~int (buflen);
901 backtrack [nextoff++] = int (buflen);
903 else if (pspec [paramno].cond_end) {
904 // the end of an if/else clause
906 if (!pspec [paramno].cond_true) {
907 // the end of an inactive clause
909 assert (backtrack [offinx] <= int (buflen));
911 // set the length so as to backtrack to the position
912 // saved on the top of the backtrack stack
913 len = -int (buflen) + backtrack [offinx];
916 // pop it off the top of the stack
920 assert (len + buflen < *pbufsize);
922 // adjust the next pointer to point to the terminating
923 // NUL in the (possibly reallocated) buffer
924 next = *pbuf + buflen + len;
930 _rw_fmtspec (pspec + paramno, false, fc, pva);
935 _rw_vasnprintf_c99 (pspec, paramno, pbuf, pbufsize, pva);
940 // discard positional specifiers
941 if (-1 == pspec [paramno].paramno)
944 next = _rw_bufcat (pbuf, pbufsize, 0, size_t (len));
952 next = _rw_bufcat (pbuf, pbufsize, "%", 1);
961 // deallocate if dynamically allocated
962 if (pspec != specbuf)
965 return int (next - *pbuf);
967 fail: // function failed
969 fprintf (stderr, "%s:%d: rw_vasnprintf(%p, %p, \"%s\", va_list) "
970 "error: errno = %d: %s\n",
971 __FILE__, __LINE__, (void*)pbuf, (void*)pbufsize, fmt,
972 errno, strerror (errno));
974 if (pspec != specbuf)
977 if (*pbuf != pbuf_save) {
978 // free any allocated memory
990 /********************************************************************/
992 static const char _rw_digits[] = {
993 "0123456789abcdefghijklmnopqrstuvwxyz"
994 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
998 _rw_fmtlong (const FmtSpec &spec, char **pbuf, size_t *pbufsize, long val)
1000 char buffer [130]; // big enough for a 128-bit long in base 2
1004 const char *pfx = 0;
1006 if ('X' == spec.cvtspec)
1009 if (spec.fl_pound) {
1010 if (16 == spec.base)
1011 pfx = upoff ? "0X" : "0x";
1012 else if (8 == spec.base && val)
1016 const int base = 1 < spec.base && spec.base < 37 ? spec.base : 10;
1018 typedef unsigned long ULong;
1025 neg = 'd' == spec.cvtspec || 'i' == spec.cvtspec;
1026 uval = ULong (neg ? -val : val);
1034 *end++ = _rw_digits [upoff + uval % base];
1035 } while (uval /= base);
1037 int size = int (end - buffer);
1039 // insert as many zeros as specified by precision
1040 if (-1 < spec.prec && size < spec.prec) {
1041 // FIXME: prevent buffer overrun
1042 for (int i = size; i != spec.prec; ++i)
1046 // insert octal or hex prefix for non-zero values
1055 else if (spec.fl_plus && ('d' == spec.cvtspec || 'i' == spec.cvtspec))
1058 if (0 == spec.prec && 0 == val) {
1059 // 7.19.6.1 of ISO/IEC 9899:1999:
1060 // The result of converting a zero value with a precision
1061 // of zero is no characters.
1067 size = int (end - buffer);
1069 for (char *pc = buffer; pc < end; ++pc) {
1070 const char tmp = *pc;
1075 // reset precision to -1 (already handled above)
1076 FmtSpec newspec (spec);
1077 newspec.fl_pound = 0;
1080 // handle justification by formatting the resulting string
1081 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (size));
1084 /********************************************************************/
1086 #ifdef _RWSTD_LONG_LONG
1089 _rw_fmtllong (const FmtSpec &spec,
1090 char **pbuf, size_t *pbufsize, _RWSTD_LONG_LONG val)
1092 char buffer [130]; // big enough for a 128-bit long long in base 2
1096 const char *pfx = 0;
1098 if ('X' == spec.cvtspec)
1101 if (spec.fl_pound) {
1102 if (16 == spec.base)
1103 pfx = upoff ? "0X" : "0x";
1104 else if (8 == spec.base && val)
1108 const int base = 1 < spec.base && spec.base < 37 ? spec.base : 10;
1110 typedef unsigned _RWSTD_LONG_LONG ULLong;
1117 neg = 'd' == spec.cvtspec || 'i' == spec.cvtspec;
1118 uval = ULLong (neg ? -val : val);
1122 uval = ULLong (val);
1126 *end++ = _rw_digits [upoff + uval % base];
1127 } while (uval /= base);
1139 else if (spec.fl_plus && ('d' == spec.cvtspec || 'i' == spec.cvtspec))
1144 assert (buffer < end);
1145 size_t size = size_t (end - buffer);
1147 // FIXME: prevent buffer overrun
1148 if (0 < spec.prec && size < size_t (spec.prec)) {
1149 for (size_t i = size; i != size_t (spec.prec); ++i)
1158 assert (buffer < end);
1159 size = size_t (end - buffer);
1161 for (char *pc = buffer; pc < end; ++pc) {
1162 const char tmp = *pc;
1167 // handle justification by formatting the resulting string
1168 return _rw_fmtstr (spec, pbuf, pbufsize, buffer, size);
1171 #endif // _RWSTD_LONG_LONG
1173 /********************************************************************/
1176 _rw_fmtinteger (FmtSpec *pspec, size_t paramno,
1177 char **pbuf, size_t *pbufsize, va_list *pva)
1181 FmtSpec &spec = pspec [paramno];
1183 switch (spec.cvtspec) {
1187 // promoted signed char argument
1188 spec.param.i = PARAM (int, i);
1189 const signed char val = spec.param.i;
1190 len = _rw_fmtlong (spec, pbuf, pbufsize, long (val));
1192 else if (spec.mod_h) {
1193 // promoted signed short argument
1194 spec.param.i = PARAM (int, i);
1195 const short val = spec.param.i;
1196 len = _rw_fmtlong (spec, pbuf, pbufsize, long (val));
1198 else if (spec.mod_l) { // %li
1199 spec.param.lng = PARAM (long, lng);
1200 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.lng);
1202 else if (spec.mod_ll) { // %lli
1204 #ifdef _RWSTD_LONG_LONG
1205 spec.param.llong = PARAM (_RWSTD_LONG_LONG, llong);
1206 len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.llong);
1207 #elif 8 == _RWSTD_LONG_SIZE
1208 spec.param.llong = PARAM (long, lnng);
1209 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.llong);
1211 assert (!"%lld, %lli: long long not supported");
1213 #endif // _RWSTD_LONG_LONG
1215 else if (spec.mod_t) {
1216 spec.param.diff = PARAM (ptrdiff_t, diff);
1217 if (sizeof (ptrdiff_t) == sizeof (long)) {
1218 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.diff);
1221 #ifdef _RWSTD_LONG_LONG
1222 len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.diff);
1223 #else // if !defined (_RWSTD_LONG_LONG)
1224 assert (!"%td, %ti: 64-bit types not supported");
1225 #endif // _RWSTD_LONG_LONG
1228 else if (1 == spec.iwidth) {
1229 spec.param.i = PARAM (int, i);
1230 const _RWSTD_INT8_T val = spec.param.i;
1231 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1233 else if (2 == spec.iwidth) {
1234 spec.param.i = PARAM (int, i);
1235 const _RWSTD_INT16_T val = spec.param.i;
1236 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1238 else if (3 == spec.iwidth) {
1239 spec.param.i32 = PARAM (_RWSTD_INT32_T, i32);
1240 const long val = long (spec.param.i32);
1241 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1243 else if (4 == spec.iwidth) {
1245 #ifdef _RWSTD_INT64_T
1246 spec.param.i64 = PARAM (_RWSTD_INT64_T, i64);
1247 #else // if !defined (_RWSTD_INT64_T)
1248 assert (!"%I64d, %I64i: 64-bit types not supported");
1249 #endif // _RWSTD_INT64_T
1251 #if 8 == _RWSTD_LONG_SIZE
1252 const long val = spec.param.i64;
1253 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1254 #elif defined (_RWSTD_LONG_LONG)
1255 const _RWSTD_LONG_LONG val = spec.param.i64;
1256 len = _rw_fmtllong (spec, pbuf, pbufsize, val);
1258 assert (!"%I64d, %I64i: 64-bit types not supported");
1262 spec.param.i = PARAM (int, i);
1263 len = _rw_fmtlong (spec, pbuf, pbufsize, long (spec.param.i));
1268 assert (-1 == spec.base);
1273 if (-1 == spec.base)
1278 if (-1 == spec.base)
1283 // promoted unsigned char argument
1284 spec.param.i = PARAM (unsigned, i);
1285 const unsigned char val = spec.param.i;
1286 len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val);
1288 else if (spec.mod_h) {
1289 // promoted unsigned short argument
1290 spec.param.i = PARAM (unsigned, i);
1291 const unsigned short val = spec.param.i;
1292 len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val);
1294 else if (spec.mod_ll) {
1295 #ifdef _RWSTD_LONG_LONG
1296 spec.param.llong = PARAM (unsigned _RWSTD_LONG_LONG, llong);
1297 const unsigned _RWSTD_LONG_LONG val = spec.param.llong;
1298 len = _rw_fmtllong (spec, pbuf, pbufsize, val);
1299 #elif 8 == _RWSTD_LONG_SIZE
1300 spec.param.lng = PARAM (unsigned long, lng);
1301 const unsigned long val = spec.param.lng;
1302 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1304 assert (!"long long not supported");
1305 #endif // _RWSTD_LONG_LONG
1308 else if (spec.mod_l) {
1309 spec.param.lng = PARAM (unsigned long, lng);
1310 const unsigned long val = spec.param.lng;
1311 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1313 else if (spec.mod_t) {
1314 spec.param.lng = PARAM (size_t, size);
1315 if (sizeof (size_t) == sizeof (unsigned long)) {
1316 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.size);
1319 #ifdef _RWSTD_LONG_LONG
1320 len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.size);
1321 #else // if defined (_RWSTD_LONG_LONG)
1322 assert (!"%to, %tu, %tx: 64-bit types not implemented");
1323 #endif // _RWSTD_LONG_LONG
1326 else if (1 == spec.iwidth) {
1327 spec.param.i = PARAM (int, i);
1328 const _RWSTD_UINT8_T val = spec.param.i;
1329 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1331 else if (2 == spec.iwidth) {
1332 spec.param.i = PARAM (int, i);
1333 const long val = (unsigned short)spec.param.i;
1334 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1336 else if (3 == spec.iwidth) {
1337 spec.param.i32 = PARAM (_RWSTD_INT32_T, i32);
1338 const long val = long (unsigned (spec.param.i));
1339 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1341 else if (4 == spec.iwidth) {
1342 #ifdef _RWSTD_INT64_T
1343 spec.param.i64 = PARAM (_RWSTD_INT64_T, i64);
1344 #else // if defined 9_RWSTD_INT64_T)
1345 assert (!"%I64o, %I64u, %I64x: 64-bit types not supported");
1346 #endif // _RWSTD_INT64_T
1348 #if 8 == _RWSTD_LONG_SIZE
1349 const unsigned long val = spec.param.i64;
1350 len = _rw_fmtlong (spec, pbuf, pbufsize, val);
1351 #elif defined (_RWSTD_LONG_LONG)
1352 const unsigned _RWSTD_LONG_LONG val = spec.param.i64;
1353 len = _rw_fmtllong (spec, pbuf, pbufsize, val);
1355 assert (!"%I64o, %I64u, %I64x: 64-bit types not supported");
1359 spec.param.i = PARAM (unsigned, i);
1360 const unsigned val = spec.param.i;
1361 len = _rw_fmtlong (spec, pbuf, pbufsize, long (val));
1370 /********************************************************************/
1373 _rw_fmtfloating (const FmtSpec &spec,
1374 char **pbuf, size_t *pbufsize, const void *pval)
1398 else if (spec.mod_hh) {
1402 else if (spec.mod_l)
1404 else if (spec.mod_ll) {
1408 else if (spec.mod_j)
1410 else if (spec.mod_z)
1412 else if (spec.mod_t)
1414 else if (spec.mod_L) {
1415 strcpy (pf, _RWSTD_LDBL_PRINTF_PREFIX);
1418 else if (spec.mod_A && _RWSTD_LDBL_SIZE == spec.width) {
1419 strcpy (pf, _RWSTD_LDBL_PRINTF_PREFIX);
1423 if (!spec.mod_A && 0 <= spec.width) {
1424 pf += sprintf (pf, "%i", spec.width);
1428 pf += sprintf (pf, ".%i", spec.prec);
1430 *pf++ = char (spec.cvtspec);
1433 // verify that the format buffer hasn't overflowed
1434 assert (size_t (pf - fmt) + 1 < sizeof fmt);
1436 // this might make the buffer almost 5KB
1437 char buffer [_RWSTD_LDBL_MAX_10_EXP + _RWSTD_LDBL_DIG + 3];
1442 if (_RWSTD_FLT_SIZE == spec.width) {
1443 len = sprintf (buffer, fmt, *(const float*)pval);
1445 else if (_RWSTD_DBL_SIZE == spec.width) {
1446 len = sprintf (buffer, fmt, *(const double*)pval);
1448 else if (_RWSTD_LDBL_SIZE == spec.width) {
1449 len = sprintf (buffer, fmt, *(const long double*)pval);
1452 assert (!"unknown floating point size");
1455 else if (spec.mod_L)
1456 len = sprintf (buffer, fmt, *(const long double*)pval);
1458 len = sprintf (buffer, fmt, *(const double*)pval);
1460 assert (size_t (len) < sizeof buffer);
1465 // remove redundant zeros from the exponent (if present)
1466 if ( ('e' == buffer [len - 5] || 'E' == buffer [len - 5])
1467 && '0' == buffer [len - 3]) {
1468 buffer [len - 3] = buffer [len - 2];
1469 buffer [len - 2] = buffer [len - 1];
1470 buffer [len - 1] = buffer [len];
1477 if (-1 < len && 0 == _rw_bufcat (pbuf, pbufsize, buffer, size_t (len)))
1483 /********************************************************************/
1485 // formats a data, function, or class member pointer as follows
1486 // 0x<hex-long-0>[:<hex-long-1>[:...[:<hex-long-N>]]]
1487 // where N is the size of the pointer in long ints
1491 _rw_fmtpointer (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
1492 const void *pptr, size_t nelems)
1494 FmtSpec newspec (spec);
1496 // always format data pointers in hexadecimal
1499 // set the number of digits
1500 newspec.prec = _RWSTD_LONG_SIZE * 2;
1504 const unsigned long *lptr;
1509 if (newspec.fl_pound) {
1510 // prepend the 0x prefix even to null pointers
1511 if (0 == _rw_bufcat (pbuf, pbufsize, "0x", len = 2)) {
1515 // reset the pound flag to prevent the integer formatter
1516 // from inserting it again
1517 newspec.fl_pound = 0;
1520 for (size_t i = 0; i != nelems; ++i) {
1521 const size_t inx = _rw_big_endian ? nelems - i - 1 : i;
1523 len += _rw_fmtlong (newspec, pbuf, pbufsize, uptr.lptr [inx]);
1529 // separate pointer components with colons
1531 if (i + 1 < nelems) {
1532 if (0 == _rw_bufcat (pbuf, pbufsize, ":", n = 1)) {
1544 /********************************************************************/
1547 _rw_fmtptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
1550 return _rw_fmtpointer (spec, pbuf, pbufsize, &val,
1551 sizeof val / sizeof (long));
1554 /********************************************************************/
1557 _rw_fmtfunptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
1562 #if 0 // disabled until this is implemented on other platforms
1563 #ifdef _RWSTD_OS_SUNOS
1569 // find the symbol corresponding to the address
1570 if (dladdr ((void*)val, &dli)) {
1572 dli.dli_fname = "unknown";
1574 const size_t sym_off = size_t (dli.dli_saddr);
1576 // compute the offset of the address from the address
1577 // of the symbol dladdr() found in the address space
1578 // of the calling process
1579 const size_t addr_off = size_t (val) < sym_off ?
1580 sym_off - size_t (val) : size_t (val) - sym_off;
1582 // format the address folowed by the name of the symbol
1583 // followed by the offset
1584 const int len = sprintf (buffer, "%#x=%s%c%lu",
1585 size_t (val), dli.dli_sname,
1586 size_t (val) < sym_off ? '-' : '+',
1589 FmtSpec newspec (spec);
1590 newspec.mod_l = false;
1592 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len));
1595 #endif // _RWSTD_OS_SUNOS
1599 return _rw_fmtpointer (spec, pbuf, pbufsize, &val,
1600 sizeof val / sizeof (long));
1603 /********************************************************************/
1606 _rw_fmtmemptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, memptr_t val)
1608 return _rw_fmtpointer (spec, pbuf, pbufsize, &val,
1609 sizeof val / sizeof (long));
1612 /********************************************************************/
1615 _rw_fmterrno (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
1617 static const struct {
1623 #define ERRNO(val) { val, #val }
1798 #endif // EOWNERDEAD
1799 #ifdef ENOTRECOVERABLE
1800 ERRNO (ENOTRECOVERABLE),
1801 #endif // ENOTRECOVERABLE
1835 #ifdef ELOCKUNMAPPED
1836 ERRNO (ELOCKUNMAPPED),
1837 #endif // ELOCKUNMAPPED
1840 #endif // ENOTACTIVE
1848 ERRNO (ENAMETOOLONG),
1849 #endif // ENAMETOOLONG
1902 ERRNO (EDESTADDRREQ),
1903 #endif // EDESTADDRREQ
1909 #endif // EPROTOTYPE
1911 ERRNO (ENOPROTOOPT),
1912 #endif // ENOPROTOOPT
1913 #ifdef EPROTONOSUPPORT
1914 ERRNO (EPROTONOSUPPORT),
1915 #endif // EPROTONOSUPPORT
1916 #ifdef ESOCKTNOSUPPORT
1917 ERRNO (ESOCKTNOSUPPORT),
1918 #endif // ESOCKTNOSUPPORT
1921 #endif // EOPNOTSUPP
1923 ERRNO (EPFNOSUPPORT),
1924 #endif // EPFNOSUPPORT
1926 ERRNO (EAFNOSUPPORT),
1927 #endif // EAFNOSUPPORT
1930 #endif // EADDRINUSE
1931 #ifdef EADDRNOTAVAIL
1932 ERRNO (EADDRNOTAVAIL),
1933 #endif // EADDRNOTAVAIL
1938 ERRNO (ENETUNREACH),
1939 #endif // ENETUNREACH
1944 ERRNO (ECONNABORTED),
1945 #endif // ECONNABORTED
1948 #endif // ECONNRESET
1962 ERRNO (ETOOMANYREFS),
1963 #endif // ETOOMANYREFS
1968 ERRNO (ECONNREFUSED),
1969 #endif // ECONNREFUSED
1974 ERRNO (EHOSTUNREACH),
1975 #endif // EHOSTUNREACH
1977 ERRNO (EWOULDBLOCK),
1978 #endif // EWOULDBLOCK
1983 ERRNO (EINPROGRESS),
1984 #endif // EINPROGRESS
1991 if (spec.fl_pound) {
1994 const char *name = 0;
1996 for (size_t i = 0; i != sizeof names / sizeof *names; ++i) {
1997 if (names [i].val == val) {
1998 name = names [i].str;
2006 len = sprintf (buffer, "E#%d", val);
2010 len = int (strlen (name));
2012 if (0 == _rw_bufcat (pbuf, pbufsize, name, size_t (len)))
2018 const char* const str = strerror (val);
2019 const size_t len = strlen (str);
2021 if (0 == _rw_bufcat (pbuf, pbufsize, str, len))
2027 /********************************************************************/
2030 _rw_fmtsignal (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
2032 static const struct {
2038 #define SIGNAL(val) { val, #val }
2122 SIGNAL (SIGPTRESCHED),
2123 #endif // SIGPTRESCHED
2131 SIGNAL (SIGRESTART),
2132 #endif // SIGRESTART
2182 SIGNAL (SIGWAITING),
2183 #endif // SIGWAITING
2203 const char *name = 0;
2205 for (size_t i = 0; i != sizeof names / sizeof *names; ++i) {
2206 if (names [i].val == val) {
2207 name = names [i].str;
2213 sprintf (buffer, "SIG#%d", val);
2217 return _rw_fmtstr (spec, pbuf, pbufsize, name, _RWSTD_SIZE_MAX);
2220 /********************************************************************/
2222 template <class charT>
2223 int rw_quotechar (char *buf, charT wc, int noesc)
2225 #if _RWSTD_WCHAR_T_MIN < 0
2227 // wchar_t is signed, convert its value to unsigned long
2228 // without widening (i.e., treat it as an unsigned type)
2230 # if _RWSTD_WCHAR_T_MIN == _RWSTD_SHRT_MIN
2231 const unsigned long wi = (unsigned short)wc;
2232 # elif _RWSTD_WCHAR_T_MIN ==_RWSTD_INT_MIN
2233 const unsigned long wi = (unsigned int)wc;
2234 # elif _RWSTD_WCHAR_T_MIN == _RWSTD_LONG_MIN
2235 const unsigned long wi = (unsigned long)wc;
2238 #else // if _RWSTD_WCHAR_T_MIN >= 0
2240 // wchar_t is unsigned
2241 const unsigned long wi = (unsigned long)wc;
2243 #endif // _RWSTD_WCHAR_T_MIN < 0
2245 if ((1 == sizeof wc || wi < 0x100) && noesc) {
2246 buf [0] = char (wc);
2257 case '\a': buf [1] = 'a'; buf [len = 2] = '\0'; break;
2258 case '\b': buf [1] = 'b'; buf [len = 2] = '\0'; break;
2259 case '\f': buf [1] = 'f'; buf [len = 2] = '\0'; break;
2260 case '\n': buf [1] = 'n'; buf [len = 2] = '\0'; break;
2261 case '\r': buf [1] = 'r'; buf [len = 2] = '\0'; break;
2262 case '\t': buf [1] = 't'; buf [len = 2] = '\0'; break;
2263 case '\v': buf [1] = 'v'; buf [len = 2] = '\0'; break;
2264 case '\\': buf [1] = '\\'; buf [len = 2] = '\0'; break;
2265 case '"' : buf [1] = '"'; buf [len = 2] = '\0'; break;
2267 if (wc < ' ' || wc > '~') {
2274 else if (1 == sizeof wc) {
2275 len = 1 + sprintf (buf + 1, "x%02x", (unsigned char)wc);
2280 wi > 0xfffffffUL ? 8 : wi > 0xffffffUL ? 7
2281 : wi > 0xfffffUL ? 6 : wi > 0xffffUL ? 5
2282 : wi > 0xfffUL ? 4 : wi > 0xffUL ? 3
2283 : wi > 0xfUL ? 2 : 2;
2285 len = 1 + sprintf (buf + 1, "x%0*lx", width, (unsigned long)wi);
2299 template <class charT>
2300 int rw_quotestr (const FmtSpec &spec, char **pbuf, size_t *pbufsize,
2301 const charT *wstr, size_t nchars, int noesc)
2309 static const charT null[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' };
2311 nchars = sizeof null / sizeof *null - 1;
2314 if (0 > _RW::__rw_memattr (wstr, _RWSTD_SIZE_MAX, 0)) {
2316 const size_t buflen = *pbuf ? strlen (*pbuf) : 0;
2318 if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18))
2321 FmtSpec newspec (spec);
2322 newspec.fl_pound = 1;
2323 if (-1 == ::_rw_fmtptr (newspec, pbuf, pbufsize, wstr))
2325 if (0 == _rw_bufcat (pbuf, pbufsize, ")", 2))
2328 return int (strlen (*pbuf) - buflen);
2331 if (_RWSTD_SIZE_MAX == nchars) {
2332 // compute the length of the NUL-terminate string
2334 for (const charT *pc = wstr; *pc; ++pc, ++nchars);
2337 char *next = _rw_bufcat (pbuf, pbufsize, 0, (nchars + 1) * 12 + 3);
2338 const char* const bufend = next;
2346 #if 0 // width handling disabled (width used for array formatting)
2347 for (int w = 0; w < spec.width; ++w)
2353 if (_RWSTD_WCHAR_T_SIZE == sizeof (charT))
2357 #if 0 // width handling disabled (width used for array formatting)
2358 for (int w = 0; w < spec.width; ++w)
2364 return int (next - bufend);
2369 const charT *last = wstr;
2371 bool any_repeats = false;
2372 long last_repeat = noesc ? 0L : -1L;
2376 const ptrdiff_t N = ptrdiff_t (noesc ? 0 : 20);
2378 for (const charT *pwc = last + 1; ; ++pwc) {
2380 if (*pwc == *last && size_t (pwc - wstr) < nchars) {
2381 // if the last processed character repeats, continue
2382 // until a different character is encountered
2386 if (N > 1 && pwc - last > N) {
2388 // if the last processed character repeats N or more
2389 // times, format the repeat count instead of all the
2390 // repeated occurrences of the character to conserve
2391 // space and make the string more readable
2393 const long repeat = pwc - last;
2395 rw_quotechar (chstr, *last, noesc);
2397 s += sprintf (s, "%s'%s' <repeats %ld times>",
2398 -1 == last_repeat ? ""
2399 : 0 == last_repeat ? "\", " : ", ",
2405 last_repeat = repeat;
2408 // otherwise (if the last processed character repeats
2409 // fewer than N times) format the character that many
2412 if (last_repeat < 0) {
2414 if (_RWSTD_WCHAR_T_SIZE == sizeof (charT)) {
2419 else if (last_repeat > 0) {
2425 rw_quotechar (chstr, *last, noesc);
2427 while (last != pwc) {
2428 s += sprintf (s, "%s", chstr);
2434 if (size_t (pwc - wstr) == nchars) {
2442 if (size_t (pwc - wstr) == nchars)
2447 const size_t len = strlen (next);
2448 memmove (next + 2, next, len);
2451 next [len + 2] = ' ';
2452 next [len + 3] = '}';
2453 next [len + 4] = '\0';
2457 return int (s - bufend);
2461 /********************************************************************/
2464 _rw_fmtchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
2466 typedef unsigned char UChar;
2467 const UChar uc = UChar (val);
2470 int len = rw_quotechar (buffer + spec.fl_pound, uc, !spec.fl_pound);
2471 if (spec.fl_pound) {
2472 buffer [0] = buffer [len + 1] = '\'';
2473 buffer [len + 2] = '\0';
2477 FmtSpec newspec (spec);
2478 newspec.fl_pound = 0;
2479 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len));
2482 /********************************************************************/
2485 _rw_fmtwchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, wint_t val)
2487 const wchar_t wc = wchar_t (val);
2490 int len = rw_quotechar (buffer + 2 * spec.fl_pound, wc, !spec.fl_pound);
2491 if (spec.fl_pound) {
2493 buffer [1] = buffer [len + 2] = '\'';
2494 buffer [len + 3] = '\0';
2498 FmtSpec newspec (spec);
2499 newspec.fl_pound = 0;
2500 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len));
2503 /********************************************************************/
2506 _rw_fmtstr (const FmtSpec &spec,
2507 char **pbuf, size_t *pbufsize, const char *str, size_t len)
2513 return rw_quotestr (spec, pbuf, pbufsize, str, len, 0);
2518 if (0 > _RW::__rw_memattr (str, _RWSTD_SIZE_MAX, 0)) {
2520 const size_t buflen = *pbuf ? strlen (*pbuf) : 0;
2522 if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18))
2525 FmtSpec newspec (spec);
2526 newspec.fl_pound = 1;
2528 if (-1 == _rw_fmtptr (newspec, pbuf, pbufsize, str))
2531 if (0 == _rw_bufcat (pbuf, pbufsize, ")", 2))
2534 return int (strlen (*pbuf) - buflen);
2537 if (_RWSTD_SIZE_MAX == len)
2540 // compute the minimum number of characters to be generated
2541 if (-1 < spec.prec && size_t (spec.prec) < len)
2542 len = size_t (spec.prec);
2544 // the number of generated characters depends on three variables:
2545 // -- the optional field width,
2546 // -- the optional precision, and
2547 // -- the length of the argument
2549 // compute the field width
2550 const size_t width =
2551 -1 < spec.width && len < size_t (spec.width) ?
2552 size_t (spec.width) : len;
2554 // compute the size of padding
2555 const size_t pad = len < width ? width - len : 0;
2557 // [re]allocate enough space in the buffer
2558 if (0 == _rw_bufcat (pbuf, pbufsize, 0, pad + len))
2561 assert (0 != *pbuf);
2562 char *next = *pbuf + strlen (*pbuf);
2564 if (!spec.fl_minus) {
2565 for (size_t i = 0; i != pad; ++i)
2569 memcpy (next, str, len);
2572 if (spec.fl_minus) {
2573 for (size_t i = 0; i != pad; ++i)
2579 return int (pad + len);
2583 /********************************************************************/
2586 _rw_fmtwstr (const FmtSpec &spec,
2587 char **pbuf, size_t *pbufsize, const wchar_t *wstr, size_t len)
2589 return rw_quotestr (spec, pbuf, pbufsize, wstr, len, 1);
2592 /********************************************************************/
2596 const char *longname;
2601 #define BITNAME(qual, name) { #qual "::" #name, #name, qual::name }
2604 rw_bmpfmt (const FmtSpec&, char **pbuf, size_t *pbufsize,
2605 const Bitnames bmap[], size_t size, int bits)
2612 // string to use when no bits are set
2613 const char* all_clear = "0";
2615 for (size_t i = 0; i != size; ++i) {
2616 if (bmap [i].bits) {
2617 if ((bits & bmap [i].bits) == bmap [i].bits) {
2618 strcat (*buffer ? strcat (buffer, " | ") : buffer,
2620 bits &= ~bmap [i].bits;
2624 // save the name of the constant to use for 0
2625 all_clear = bmap [i].name;
2631 if ('\0' == *buffer) {
2632 // no constant matched, format teh value either as a number
2633 // or, when 0, using the all_clear name (see above)
2635 sprintf (buffer, "%#x", bits);
2637 strcpy (buffer, all_clear);
2639 buffersize = strlen (buffer) + 1;
2642 buffersize = strlen (buffer) + 1;
2644 // verify that buffer wasn't overflowed
2645 assert (buffersize <= sizeof buffer);
2648 const int n = sprintf (bitstr, "%#x | ", bits);
2652 memmove (buffer + n, buffer, buffersize);
2653 memcpy (buffer, bitstr, size_t (n));
2658 buffersize = strlen (buffer) + 1;
2661 // verify that buffer wasn't overflowed
2662 assert (buffersize <= sizeof buffer);
2664 if (0 == _rw_bufcat (pbuf, pbufsize, buffer, buffersize))
2667 return int (buffersize);
2670 /********************************************************************/
2673 rw_fmtflags (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits)
2675 static const Bitnames names [] = {
2676 BITNAME (std::ios, adjustfield),
2677 BITNAME (std::ios, basefield),
2678 BITNAME (std::ios, boolalpha),
2679 BITNAME (std::ios, dec),
2680 BITNAME (std::ios, fixed),
2681 BITNAME (std::ios, hex),
2682 BITNAME (std::ios, internal),
2683 BITNAME (std::ios, left),
2684 BITNAME (std::ios, oct),
2685 BITNAME (std::ios, right),
2686 BITNAME (std::ios, scientific),
2687 BITNAME (std::ios, showbase),
2688 BITNAME (std::ios, showpoint),
2689 BITNAME (std::ios, showpos),
2690 BITNAME (std::ios, skipws),
2691 BITNAME (std::ios, unitbuf),
2692 BITNAME (std::ios, uppercase),
2694 #ifndef _RWSTD_NO_EXT_BIN_IO
2696 // extension: produce binary output (similar to oct, dec, and hex)
2697 BITNAME (std::ios, bin),
2699 #endif // _RWSTD_NO_EXT_BIN_IO
2701 #ifndef _RWSTD_NO_EXT_REENTRANT_IO
2703 // extension: allow unsychronized access to stream and/or its buffer
2704 BITNAME (std::ios, nolock),
2705 BITNAME (std::ios, nolockbuf)
2707 #endif // _RWSTD_NO_EXT_REENTRANT_IO
2711 static const size_t count = sizeof names / sizeof *names;
2713 const int base = (bits >> _RWSTD_IOS_BASEOFF) & _RWSTD_IOS_BASEMASK;
2715 // zero out bits representingthe numeric base
2716 bits &= ~(_RWSTD_IOS_BASEMASK << _RWSTD_IOS_BASEOFF);
2718 int len = rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits);
2720 if (base && base != 8 && base != 10 && base != 16) {
2722 // for numeric bases other than those required by the standard,
2723 // use the text "base (%d)" to show the extended numeric base
2725 #ifndef _RWSTD_NO_EXT_BIN_IO
2727 if (bits & std::ios::bin)
2730 #endif // _RWSTD_NO_EXT_BIN_IO
2733 sprintf (basestr, " | std::ios::base(%d)", base);
2735 strcat (*pbuf, basestr);
2737 len = int (strlen (*pbuf));
2743 /********************************************************************/
2746 rw_fmtiostate (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits)
2748 static const Bitnames names [] = {
2749 BITNAME (std::ios, goodbit),
2750 BITNAME (std::ios, badbit),
2751 BITNAME (std::ios, eofbit),
2752 BITNAME (std::ios, failbit)
2755 static const size_t count = sizeof names / sizeof *names;
2757 return rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits);
2760 /********************************************************************/
2763 _rw_fmtopenmode (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits)
2765 static const Bitnames names [] = {
2767 #ifndef __SYMBIAN32__
2769 #ifndef _RWSTD_NO_EXTENSIONS
2771 { "std::ios::nocreate", "nocreate", std::ios::nocreate },
2772 { "std::ios::noreplace", "noreplace", std::ios::noreplace },
2774 #else // if defined (_RWSTD_NO_EXTENSIONS)
2776 { "__rw:::__rw_nocreate", "__rw_nocreate", _RW::__rw_nocreate },
2777 { "__rw::__rw_noreplace", "__rw_noreplace", _RW::__rw_noreplace },
2779 #endif // _RWSTD_NO_EXTENSIONS
2781 #ifndef _RWSTD_NO_EXT_STDIO
2783 { "std::ios::stdio", "stdio", std::ios::stdio },
2784 { "std::ios::native", "native", std::ios::native },
2786 #else // if defined (_RWSTD_NO_EXT_STDIO)
2788 { "__rw::__rw_stdio", "__rw_stdio", _RW::__rw_stdio },
2789 { "__rw::__rw_native", "__rw_native", _RW::__rw_native },
2791 #endif // _RWSTD_NO_EXT_STDIO
2793 BITNAME (std::ios, app),
2794 BITNAME (std::ios, binary),
2795 BITNAME (std::ios, in),
2796 BITNAME (std::ios, out),
2797 BITNAME (std::ios, trunc),
2798 BITNAME (std::ios, ate)
2801 static const size_t count = sizeof names / sizeof *names;
2803 return rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits);
2806 /********************************************************************/
2809 _rw_fmtevent (const FmtSpec&, char **pbuf, size_t *pbufsize, int event)
2812 std::ios::copyfmt_event == event ? "copyfmt_event"
2813 : std::ios::imbue_event == event ? "imbue_event"
2814 : std::ios::erase_event == event ? "erase_event"
2820 sprintf (buffer, "copyfmt_event(%d)", event);
2824 const size_t len = strlen (str);
2826 if (0 == _rw_bufcat (pbuf, pbufsize, str, len))
2832 /********************************************************************/
2835 rw_fmtlc (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val)
2837 const char *str = 0;
2840 case LC_ALL: str = "LC_ALL"; break;
2841 case LC_COLLATE: str = "LC_COLLATE"; break;
2842 case LC_CTYPE: str = "LC_CTYPE"; break;
2843 case LC_MONETARY: str = "LC_MONETARY"; break;
2844 case LC_NUMERIC: str = "LC_NUMERIC"; break;
2845 case LC_TIME: str = "LC_TIME"; break;
2848 case LC_MESSAGES: str = "LC_MESSAGES"; break;
2849 #endif // LC_MESSAGES
2854 const std::size_t len = strlen (str);
2856 if (0 == _rw_bufcat (pbuf, pbufsize, str, len))
2862 static const Bitnames names [] = {
2863 BITNAME (std::locale, all),
2864 BITNAME (std::locale, none),
2865 BITNAME (std::locale, collate),
2866 BITNAME (std::locale, ctype),
2867 BITNAME (std::locale, monetary),
2868 BITNAME (std::locale, numeric),
2869 BITNAME (std::locale, messages),
2870 BITNAME (std::locale, time)
2873 static const size_t count = sizeof names / sizeof *names;
2875 return rw_bmpfmt (spec, pbuf, pbufsize, names, count, val);
2878 /********************************************************************/
2881 _rw_fmtmonpat (const FmtSpec&,
2882 char **pbuf, size_t *pbufsize, const char pat [4])
2888 for (int i = 0; i != 4; ++i) {
2890 case std::money_base::symbol:
2891 strcat (buffer, "symbol ");
2894 case std::money_base::sign:
2895 strcat (buffer, "sign ");
2898 case std::money_base::none:
2899 strcat (buffer, "none ");
2902 case std::money_base::value:
2903 strcat (buffer, "value ");
2906 case std::money_base::space:
2907 strcat (buffer, "space ");
2911 sprintf (buffer + strlen (buffer), "\\%03o", pat [i]);
2916 const size_t len = strlen (buffer);
2918 if (0 == _rw_bufcat (pbuf, pbufsize, buffer, len))
2924 /********************************************************************/
2927 libstd_vasnprintf (FmtSpec *pspec, size_t paramno,
2928 char **pbuf, size_t *pbufsize,
2929 const char *fmt, va_list *pva)
2932 assert (0 != pspec);
2934 _RWSTD_UNUSED (fmt);
2936 FmtSpec &spec = pspec [paramno];
2938 // the length of the sequence appended to the buffer to return
2939 // to the caller, or a negative value (such as -1) on error
2942 switch (spec.cvtspec) {
2945 // beginning of an if clause
2947 spec.cond_begin = 1;
2948 spec.cond_true = 0 != va_arg (*pva, int);
2954 // end of an active if clause and the beginning
2955 // of an inactive else clause
2957 spec.cond_begin = 1; // beginning of an else clause
2958 spec.cond_end = 1; // end of an if clause
2959 spec.cond_true = !spec.cond_true;
2963 // misplaced "%{:}"?
2964 static const char str[] = "%{:}";
2965 len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0);
2971 spec.cond_end = 1; // end of an if or else clause
2975 // misplaced "%{;}"?
2976 static const char str[] = "%{;}";
2977 len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0);
2981 case 'c': // %{c}, %{Ac}, %{Lc}, %{lc}
2983 if (-1 == spec.width || 1 == spec.width) {
2984 spec.param.ptr = PARAM (_RWSTD_UINT8_T*, ptr);
2985 const _RWSTD_UINT8_T* const array =
2986 (_RWSTD_UINT8_T*)spec.param.ptr;
2987 len = rw_quotestr (spec, pbuf, pbufsize, array,
2988 _RWSTD_SIZE_MAX, 0);
2990 else if (2 == spec.width) {
2991 spec.param.ptr = PARAM (_RWSTD_UINT16_T*, ptr);
2992 const _RWSTD_UINT16_T* const array =
2993 (_RWSTD_UINT16_T*)spec.param.ptr;
2994 len = rw_quotestr (spec, pbuf, pbufsize, array,
2995 _RWSTD_SIZE_MAX, 0);
2997 else if (4 == spec.width) {
2998 spec.param.ptr = PARAM (_RWSTD_UINT32_T*, ptr);
2999 const _RWSTD_UINT32_T* const array =
3000 (_RWSTD_UINT32_T*)spec.param.ptr;
3001 len = rw_quotestr (spec, pbuf, pbufsize, array,
3002 _RWSTD_SIZE_MAX, 0);
3005 #ifdef _RWSTD_UINT64_T
3007 else if (8 == spec.width) {
3008 spec.param.ptr = PARAM (_RWSTD_UINT64_T*, ptr);
3009 const _RWSTD_UINT64_T* const array =
3010 (_RWSTD_UINT64_T*)spec.param.ptr;
3011 len = rw_quotestr (spec, pbuf, pbufsize, array,
3012 _RWSTD_SIZE_MAX, 0);
3015 #endif // _RWSTD_UINT64_T
3018 assert (!"%{Ac} not implemented for this character size");
3021 else if (spec.mod_L) { // locale category or LC_XXX constant
3022 spec.param.i = PARAM (int, i);
3023 len = rw_fmtlc (spec, pbuf, pbufsize, spec.param.i);
3025 else if (spec.mod_l) { // wchar_t
3026 spec.param.wi = PARAM (wint_t, i);
3027 return _rw_fmtwchr (spec, pbuf, pbufsize, spec.param.wi);
3030 spec.param.i = PARAM (int, i);
3031 return _rw_fmtchr (spec, pbuf, pbufsize, spec.param.i);
3035 case 'e': // %{e}, %{Ae}
3036 if (spec.mod_A) { // array of floating point values
3037 spec.param.ptr = PARAM (void*, ptr);
3038 len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr);
3040 else if (spec.mod_I) { // ios::copyfmt_event
3041 spec.param.i = PARAM (int, i);
3042 len = _rw_fmtevent (spec, pbuf, pbufsize, spec.param.i);
3046 case 'f': // %{f}, %{Af}, %{If}
3047 if (spec.mod_A) { // array of floating point values
3048 spec.param.ptr = PARAM (void*, ptr);
3049 len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr);
3051 if (spec.mod_I) { // ios::fmtflags
3052 spec.param.i = PARAM (int, i);
3053 len = rw_fmtflags (spec, pbuf, pbufsize, spec.param.i);
3055 else { // function pointer
3056 spec.param.funptr = PARAM (funptr_t, funptr);
3057 len = _rw_fmtfunptr (spec, pbuf, pbufsize, spec.param.funptr);
3061 case 'g': // %{g}, %{Ag}
3062 if (spec.mod_A) { // array of floating point values
3063 spec.param.ptr = PARAM (void*, ptr);
3064 len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr);
3067 assert (!"%{g} not implemented");
3073 if (spec.mod_I) { // ios::openmode
3074 spec.param.i = PARAM (int, i);
3075 len = _rw_fmtopenmode (spec, pbuf, pbufsize, spec.param.i);
3081 len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva);
3084 case 'K': // %{K} -- signal
3085 spec.param.i = PARAM (int, i);
3086 len = _rw_fmtsignal (spec, pbuf, pbufsize, spec.param.i);
3089 case 'm': // %{m} -- errno
3090 if (-1 == spec.width)
3091 len = _rw_fmterrno (spec, pbuf, pbufsize, errno);
3093 len = _rw_fmterrno (spec, pbuf, pbufsize, spec.width);
3096 case 'M': // %{M}, %{LM}
3097 if (spec.mod_L) { // money_base::pattern
3098 spec.param.ptr = PARAM (char*, ptr);
3099 len = _rw_fmtmonpat (spec, pbuf, pbufsize, (char*)spec.param.ptr);
3101 else { // member pointer
3102 spec.param.memptr = PARAM (memptr_t, memptr);
3103 len = _rw_fmtmemptr (spec, pbuf, pbufsize, spec.param.memptr);
3108 // The argument shall be a pointer to signed integer into which
3109 // is written the size of the buffer allocated by this call to
3110 // fprintf. No argument is converted, but one is consumed. If
3111 // the conversion specification includes any flags, a field
3112 // width, or a precision, the behavior is undefined.
3115 assert (0 != *pbuf);
3117 const size_t nbytes = pbufsize ? *pbufsize : 0;
3119 spec.param.ptr = PARAM (void*, ptr);
3122 unsigned char* const ptr = (unsigned char*)spec.param.ptr;
3126 *ptr = (unsigned char)nbytes;
3128 else if (spec.mod_h) {
3129 short* const ptr = (short*)spec.param.ptr;
3133 *ptr = short (nbytes);
3135 else if (spec.mod_L) {
3136 #ifdef _RWSTD_LONG_LONG
3137 _RWSTD_LONG_LONG* const ptr = (_RWSTD_LONG_LONG*)spec.param.ptr;
3141 *ptr = (_RWSTD_LONG_LONG)(nbytes);
3142 #else // if !defined (_RWSTD_LONG_LONG)
3143 assert (!"%{Ln} not implemented");
3144 #endif // _RWSTD_LONG_LONG
3146 else if (spec.mod_l) {
3147 long* const ptr = (long*)spec.param.ptr;
3151 *ptr = long (nbytes);
3153 else if (spec.mod_t) {
3154 ptrdiff_t* const ptr = (ptrdiff_t*)spec.param.ptr;
3158 *ptr = ptrdiff_t (nbytes);
3161 int* const ptr = (int*)spec.param.ptr;
3165 *ptr = int (nbytes);
3171 case 's': // %{s}, %{Is}, %{ls}
3172 if (spec.mod_I) { // ios::iostate
3173 spec.param.i = PARAM (int, i);
3174 len = rw_fmtiostate (spec, pbuf, pbufsize, spec.param.i);
3176 else if (spec.mod_l) { // wchar_t*
3177 spec.param.ptr = PARAM (wchar_t*, ptr);
3178 const wchar_t* const wstr = (wchar_t*)spec.param.ptr;
3179 len = rw_quotestr (spec, pbuf, pbufsize, wstr, _RWSTD_SIZE_MAX, 0);
3182 spec.param.ptr = PARAM (char*, ptr);
3183 const char* const str = (char*)spec.param.ptr;
3184 len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0);
3188 case 'S': // %{S}, %{lS}
3189 if (spec.mod_l) { // std::wstring
3190 spec.param.ptr = PARAM (std::wstring*, ptr);
3192 const std::wstring* const pstr = (std::wstring*)spec.param.ptr;
3193 const wchar_t* const wstr = pstr->data ();
3194 const std::wstring::size_type size = pstr->size ();
3196 len = _rw_fmtwstr (spec, pbuf, pbufsize, wstr, size);
3198 else { // std::string
3199 spec.param.ptr = PARAM (std::string*, ptr);
3201 const std::string* const pstr = (std::string*)spec.param.ptr;
3202 const char* const str = pstr->data ();
3203 const std::string::size_type size = pstr->size ();
3205 len = _rw_fmtstr (spec, pbuf, pbufsize, str, size);
3211 // environment variable
3212 const char* val = getenv (spec.strarg);
3217 len = int (strlen (val));
3219 if (0 == _rw_bufcat (pbuf, pbufsize, val, size_t (len)))
3225 assert (!"not implemented");
3232 /********************************************************************/
3235 (*rw_vasnprintf_cb)(FmtSpec*, size_t, char**, size_t*, const char*, va_list*)
3236 = libstd_vasnprintf;
3238 /********************************************************************/
3241 rw_asnprintf (char **pbuf, size_t *pbufsize, const char *fmt, ...)
3243 assert (0 == pbuf || 0 == *pbuf || pbufsize);
3252 // if pbyf is 0 (i.e., this is a request for the size of the
3253 // buffer necessary to format all the arguments), set pbuf to
3254 // point to a local buf
3258 if (0 == pbufsize) {
3259 // pbuf may be 0 regardless of the value of pbuf
3260 pbufsize = &bufsize;
3263 const int nchars = rw_vasnprintf (pbuf, pbufsize, fmt, va);
3267 // verify that the length of the fomatted buffer is less than
3268 // its size (this test is unreliable if there are any embedded
3269 // NULs in the output)
3270 assert (nchars < 0 || strlen (*pbuf) < *pbufsize);
3273 // free the character buffer if pbuf was initially 0
3280 /********************************************************************/
3283 rw_snprintfa (char *buf, size_t bufsize, const char* fmt, ...)
3291 const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va);
3295 // verify that the length of the fomatted buffer is less than
3296 // its size (this test is unreliable if there are any embedded
3297 // NULs in the output)
3298 assert (nchars < 0 || strlen (buf) < bufsize);
3300 _RWSTD_UNUSED (nchars);
3305 /********************************************************************/
3308 rw_sprintfa (const char *fmt, ...)
3316 const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va);
3320 // verify that the length of the fomatted buffer is less than
3321 // its size (this test is unreliable if there are any embedded
3322 // NULs in the output)
3323 assert (nchars < 0 || strlen (buf) < bufsize);
3325 _RWSTD_UNUSED (nchars);
3331 /********************************************************************/
3333 // avoid re-declaring these as exported here and instead rely on the
3334 // declaration in the header #included above in order to prevent the
3335 // bogus MSVC error:
3336 // error C2201: 'rw_stdout' : must have external linkage in order to
3337 // be exported/imported
3339 /* _TEST_EXPORT */ rw_file* const
3340 rw_stdout = _RWSTD_REINTERPRET_CAST (rw_file*, stdout);
3342 /* _TEST_EXPORT */ rw_file* const
3343 rw_stderr = _RWSTD_REINTERPRET_CAST (rw_file*, stderr);
3345 /********************************************************************/
3348 _rw_vfprintf (rw_file *file, const char *fmt, va_list va)
3355 const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va);
3357 // FIXME: implement this in terms of POSIX write()
3358 // for async-signal safety
3359 FILE* const stdio_file = _RWSTD_REINTERPRET_CAST (FILE*, file);
3361 const int nwrote = 0 < nchars ?
3362 fwrite (buf, 1, nchars, stdio_file) : nchars;
3364 // flush in case stderr isn't line-buffered (e.g., when
3365 // it's determined not to refer to a terminal device,
3366 // for example after it has been redirected to a file)
3367 fflush (stdio_file);
3371 // IsDebuggerPresent() depends on the macros _WIN32_WINNT and WINVER
3372 // being appropriately #defined prior to the #inclusion of <windows.h>
3373 if (IsDebuggerPresent ()) {
3375 // write string to the attached debugger (if any)
3376 OutputDebugString (buf);
3386 /********************************************************************/
3389 rw_fprintf (rw_file *file, const char *fmt, ...)
3394 const int nchars = _rw_vfprintf (file, fmt, va);
3401 /********************************************************************/
3404 rw_printf (const char *fmt, ...)
3409 const int nchars = _rw_vfprintf (rw_stdout, fmt, va);