Return-Path: Delivered-To: apmail-incubator-stdcxx-commits-archive@www.apache.org Received: (qmail 44577 invoked from network); 17 Jan 2006 18:48:44 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 17 Jan 2006 18:48:44 -0000 Received: (qmail 82473 invoked by uid 500); 17 Jan 2006 18:48:44 -0000 Delivered-To: apmail-incubator-stdcxx-commits-archive@incubator.apache.org Received: (qmail 82460 invoked by uid 500); 17 Jan 2006 18:48:43 -0000 Mailing-List: contact stdcxx-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stdcxx-dev@incubator.apache.org Delivered-To: mailing list stdcxx-commits@incubator.apache.org Received: (qmail 82449 invoked by uid 500); 17 Jan 2006 18:48:43 -0000 Delivered-To: apmail-incubator-stdcxx-cvs@incubator.apache.org Received: (qmail 82442 invoked by uid 99); 17 Jan 2006 18:48:43 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 17 Jan 2006 10:48:43 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Tue, 17 Jan 2006 10:48:41 -0800 Received: (qmail 44449 invoked by uid 65534); 17 Jan 2006 18:48:21 -0000 Message-ID: <20060117184821.44448.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r369862 - in /incubator/stdcxx/trunk/tests: self/0.printf.cpp src/printf.cpp Date: Tue, 17 Jan 2006 18:48:20 -0000 To: stdcxx-cvs@incubator.apache.org From: sebor@apache.org X-Mailer: svnmailer-1.0.5 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: sebor Date: Tue Jan 17 10:48:13 2006 New Revision: 369862 URL: http://svn.apache.org/viewcvs?rev=369862&view=rev Log: 2006-01-17 Martin Sebor * src/printf.cpp (): Included for isalpha, et al. (, ): Guarded header include directives. (_rw_fmtmask): New (yet unused) function for the formatting of character classification bits/masks. (_rw_fmtlong, _rw_fmtllong): Avoided unnecessarily NUL-terminating buffer (done later in _rw_fmtstr). (rw_fmtinteger): New template function for the generic formatting of arbitrary integral types. (_rw_fmtinteger): Simplified by calling rw_fmtinteger. (_rw_fmtbadaddr): Handled the formatting of null pointers. (_rw_fmttm): Simplified the formatting of invalid pointers. (rw_quotestr): Renamed to... (rw_fmtarray): ...this and implemented the formatting of arrays of arbitrary integral types (in addition to characters). (_rw_fmtarray): New function for the formatting of arrays of arbitrary integral types. (_rw_fmtwstr): Called rw_fmtarray instead of rw_quotestr. (libstd_vasnprintf): Called the higher-level _rw_fmtstr instead of the rw_quotestr helper. Factored out the handling of character arrays into _rw_fmtarray. Implemented the handling of %{Ad}, %{Ai}, %{Ao}, %{Au}, and %{Ax} (arrays of integral values). * self/0.printf.cpp (test_array): Renamed to... (test_chararray): ...this function. (test_intarray): New function exercising the formatting of arrays of integral values. (main): Called test_chararray and test_intarray. Modified: incubator/stdcxx/trunk/tests/self/0.printf.cpp incubator/stdcxx/trunk/tests/src/printf.cpp Modified: incubator/stdcxx/trunk/tests/self/0.printf.cpp URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/self/0.printf.cpp?rev=369862&r1=369861&r2=369862&view=diff ============================================================================== --- incubator/stdcxx/trunk/tests/self/0.printf.cpp (original) +++ incubator/stdcxx/trunk/tests/self/0.printf.cpp Tue Jan 17 10:48:13 2006 @@ -377,7 +377,7 @@ /***********************************************************************/ -void test_array () +void test_chararray () { ////////////////////////////////////////////////////////////////// printf ("%s\n", "extension: \"%{Ac}\": quoted character array"); @@ -936,6 +936,184 @@ /***********************************************************************/ +void* make_array (int width, // element width in bytes + int a0 = 0, int a1 = 0, int a2 = 0, int a3 = 0, + int a4 = 0, int a5 = 0, int a6 = 0, int a7 = 0, + int a8 = 0, int a9 = 0, int a10 = 0, int a11 = 0, + int a12 = 0, int a13 = 0, int a14 = 0, int a15 = 0) +{ + RW_ASSERT (8 == width || 4 == width || 2 == width || 1 == width); + + static union { +#ifdef _RWSTD_INT64_T + _RWSTD_INT64_T i64; +#else + _RWSTD_INT32_T i64; +#endif // _RWSTD_INT64_T + _RWSTD_INT32_T i32; + _RWSTD_INT16_T i16; + _RWSTD_INT8_T i8; + } array [17]; + + union { +#ifdef _RWSTD_INT64_T + _RWSTD_INT64_T* pi64; +#else + _RWSTD_INT32_T* pi64; +#endif // _RWSTD_INT64_T + _RWSTD_INT32_T* pi32; + _RWSTD_INT16_T* pi16; + _RWSTD_INT8_T* pi8; + } ptr = { &array [0].i64 }; + +#define ADD_ELEMENT(n) \ + switch (width) { \ + case 8 /* bytes */: *ptr.pi64++ = a##n; break; \ + case 4 /* bytes */: *ptr.pi32++ = a##n; break; \ + case 2 /* bytes */: *ptr.pi16++ = a##n; break; \ + case 1 /* byte */: *ptr.pi8++ = a##n; break; \ + } (void)0 + + ADD_ELEMENT ( 0); ADD_ELEMENT ( 1); ADD_ELEMENT ( 2); ADD_ELEMENT ( 3); + ADD_ELEMENT ( 4); ADD_ELEMENT ( 5); ADD_ELEMENT ( 6); ADD_ELEMENT ( 7); + ADD_ELEMENT ( 8); ADD_ELEMENT ( 9); ADD_ELEMENT (10); ADD_ELEMENT (11); + ADD_ELEMENT (12); ADD_ELEMENT (13); ADD_ELEMENT (14); ADD_ELEMENT (15); + + // zero-terminate + const int a16 = 0; + ADD_ELEMENT (16); + + return array; +} + +void test_intarray () +{ + ////////////////////////////////////////////////////////////////// + printf ("%s\n", "extension: \"%{Ao}\": array of octal integers"); + +#define AR make_array + + // null 1, 2, 4, and 8-byte integer arrays + TEST ("%{1Ao}", 0, 0, 0, "(null)"); + TEST ("%{2Ao}", 0, 0, 0, "(null)"); + TEST ("%{4Ao}", 0, 0, 0, "(null)"); + TEST ("%{8Ao}", 0, 0, 0, "(null)"); + + // 2-byte integer arrays + TEST ("%{2Ao}", AR (2, 0), 0, 0, ""); + TEST ("%{2Ao}", AR (2, 1, 2), 0, 0, "1,2"); + TEST ("%{2Ao}", AR (2, 2, 3, 4), 0, 0, "2,3,4"); + TEST ("%{2Ao}", AR (2, 3, 4, 5, 6), 0, 0, "3,4,5,6"); + TEST ("%{2Ao}", AR (2, 4, 5, 6, 7, 8), 0, 0, "4,5,6,7,10"); + + TEST ("%{*Ao}", 2, AR (2, 4, 5, 6, 7, 8), 0, "4,5,6,7,10"); + TEST ("%{*.*Ao}", 2, 2, AR (2, 4, 0, 6, 0, 8), "4,0"); + TEST ("%{*.*Ao}", 2, 3, AR (2, 4, 0, 6, 0, 8), "4,0,6"); + TEST ("%{*.*Ao}", 2, 4, AR (2, 4, 0, 6, 0, 8), "4,0,6,0"); + TEST ("%{*.*Ao}", 2, 5, AR (2, 4, 0, 6, 0, 8), "4,0,6,0,10"); + + // the pound flag alone has no affect on the '0' prefix + TEST ("%{#2Ao}", AR (2, 5, 6, 7, 8, 9), 0, 0, "5,6,7,10,11"); + // zero and pound flags add the '0' prefix + TEST ("%{0#2Ao}", AR (2, 6, 7, 8, 9, 10), 0, 0, "06,07,010,011,012"); + + _RWSTD_INT8_T array8 [] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* terminate */ + }; + + _RWSTD_INT16_T array16 [] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* terminate */ + }; + + _RWSTD_INT32_T array32 [] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* terminate */ + }; + +#ifdef _RWSTD_INT64_T + + _RWSTD_INT64_T array64 [] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* terminate */ + }; + + // set array element at index inx to value val +# define SET_ELEM(inx, val) \ + RW_ASSERT (unsigned (inx) < array_size); \ + array8 [inx] = val; array16 [inx] = val; \ + array32 [inx] = val; array64 [inx] = val; \ + array_str [inx * 2] = '0' + val + +#else // if !defined (_RWSTD_INT64_T) + + // set array element at index inx to value val +# define SET_ELEM(inx, val) \ + RW_ASSERT (unsigned (inx) < array_size); \ + array8 [inx] = val; array16 [inx] = val; \ + array32 [inx] = val; \ + array_str [inx * 2] = '0' + val + +#endif // _RWSTD_INT64_T + + const unsigned array_size = sizeof array16 / sizeof *array16; + + char array_str [2 * array_size] = { + "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," + "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1" + }; + + TEST ("%{1Ao}", array8, 0, 0, array_str); + TEST ("%{#1Ao}", array8, 0, 0, "{ 1 }"); + + TEST ("%{2Ao}", array16, 0, 0, array_str); + TEST ("%{#2Ao}", array16, 0, 0, "{ 1 }"); + + TEST ("%{4Ao}", array32, 0, 0, array_str); + TEST ("%{#4Ao}", array32, 0, 0, "{ 1 }"); + + SET_ELEM (1, 2); + + TEST ("%{2Ao}", array16, 0, 0, array_str); + TEST ("%{#2Ao}", array16, 0, 0, "{ 1,2,1 }"); + + SET_ELEM ( 1, 1); + SET_ELEM (30, 2); + + TEST ("%{2Ao}", array16, 0, 0, array_str); + TEST ("%{#2Ao}", array16, 0, 0, "{ 1 ,2,1 }"); + + SET_ELEM (30, 1); + SET_ELEM (31, 2); + + TEST ("%{2Ao}", array16, 0, 0, array_str); + TEST ("%{#2Ao}", array16, 0, 0, "{ 1 ,2 }"); + + ////////////////////////////////////////////////////////////////// + printf ("%s\n", "extension: \"%{Ad}\": array of decimal integers"); + + TEST ("%{4Ad}", AR (4, 0), 0, 0, ""); + TEST ("%{4Ad}", AR (4, 20, 31), 0, 0, "20,31"); + TEST ("%{4Ad}", AR (4, 21, 32, 43), 0, 0, "21,32,43"); + TEST ("%{4Ad}", AR (4, 22, 33, 44, 55), 0, 0, "22,33,44,55"); + TEST ("%{4Ad}", AR (4, 23, 34, 45, 56, 67), 0, 0, "23,34,45,56,67"); + + ////////////////////////////////////////////////////////////////// + printf ("%s\n", "extension: \"%{Ax}\": array of hexadecimal integers"); + + TEST ("%{4Ax}", AR (4, 0), 0, 0, ""); + TEST ("%{4Ax}", AR (4, 0xa, 0xb), 0, 0, "a,b"); + TEST ("%{4Ax}", AR (4, 0xb, 0xc, 0xd), 0, 0, "b,c,d"); + TEST ("%{4Ax}", AR (4, 0xc, 0xd, 0xe, 0xf), 0, 0, "c,d,e,f"); + TEST ("%{4Ax}", AR (4, 0xc9, 0xda, 0xeb, 0xfc), 0, 0, "c9,da,eb,fc"); + + TEST ("%{#4Ax}", AR (4, 0xd, 0xe, 0xa, 0xd), 0, 0, "d,e,a,d"); + TEST ("%{0#4Ax}", AR (4, 0xb, 0xe, 0xe, 0xf), 0, 0, "0xb,0xe,0xe,0xf"); +} + +/***********************************************************************/ + void test_floating () { ////////////////////////////////////////////////////////////////// @@ -1733,8 +1911,11 @@ test_character (); test_string (); - test_array (); + test_chararray (); + test_integer (); + test_intarray (); + test_floating (); test_pointer (); Modified: incubator/stdcxx/trunk/tests/src/printf.cpp URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/src/printf.cpp?rev=369862&r1=369861&r2=369862&view=diff ============================================================================== --- incubator/stdcxx/trunk/tests/src/printf.cpp (original) +++ incubator/stdcxx/trunk/tests/src/printf.cpp Tue Jan 17 10:48:13 2006 @@ -24,6 +24,7 @@ #include #include +#include // for isalpha(), ... #include // for errno, errno constants #include // for floating point macros #include @@ -33,7 +34,14 @@ #include #include #include -#include + +#ifndef _RWSTD_NO_WCHAR_H +# include +#endif // _RWSTD_NO_WCHAR_H + +#ifndef _RWSTD_NO_WCTYPE_H +# include // for iswalpha(), ... +#endif // _RWSTD_NO_WCTYPE_H #if defined (_WIN32) || defined (_WIN64) // define macros to enable Win98 + WinNT support in @@ -122,6 +130,10 @@ static int _rw_fmterrno (const FmtSpec&, char**, size_t*, int); +// format a character mask (alpha|alnum|...|xdigit) +static int +_rw_fmtmask (const FmtSpec&, char**, size_t*, int); + // format struct tm static int _rw_fmttm (const FmtSpec&, char**, size_t*, const tm*); @@ -181,7 +193,7 @@ // extension: optional parameter number long paramno; - // optional width and precision + // optional field width and precision int width; int prec; @@ -276,6 +288,9 @@ if (ext) { if ('$' == *fmt) { + // %{$}: introduces the name of an environment + // variable (or some other string) + ++fmt; const char *str; @@ -1082,8 +1097,8 @@ end = buffer; } - *end = '\0'; - + // not NUL-terminated + RW_ASSERT (buffer < end); size = int (end - buffer); for (char *pc = buffer; pc < end; ++pc) { @@ -1173,8 +1188,7 @@ if (sign) *end++ = sign; - *end = '\0'; - + // not NUL-terminated RW_ASSERT (buffer < end); size = size_t (end - buffer); @@ -1192,9 +1206,32 @@ /********************************************************************/ +template +inline int +rw_fmtinteger (const FmtSpec &spec, char **pbuf, size_t *pbufsize, IntT val) +{ +#ifdef _RWSTD_LONG_LONG + + typedef _RWSTD_LONG_LONG LLong; + + const int len = sizeof (val) <= sizeof (long) ? + _rw_fmtlong (spec, pbuf, pbufsize, long (val)) + : _rw_fmtllong (spec, pbuf, pbufsize, LLong (val)); + +#else // if !defined (_RWSTD_LONG_LONG) + + const int len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); + +#endif // _RWSTD_LONG_LONG + + return len; +} + +/********************************************************************/ + static int _rw_fmtinteger (FmtSpec *pspec, size_t paramno, - char **pbuf, size_t *pbufsize, va_list *pva) + char **pbuf, size_t *pbufsize, va_list *pva) { int len = -1; @@ -1214,26 +1251,26 @@ // promoted signed char argument spec.param.i = PARAM (int, i); const signed char val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (spec.mod_h) { // promoted signed short argument spec.param.i = PARAM (int, i); const short val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (spec.mod_l) { // %li spec.param.lng = PARAM (long, lng); - len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.lng); + len = rw_fmtinteger (spec, pbuf, pbufsize, spec.param.lng); } else if (spec.mod_ll) { // %lli #ifdef _RWSTD_LONG_LONG spec.param.llong = PARAM (_RWSTD_LONG_LONG, llong); - len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.llong); + len = rw_fmtinteger (spec, pbuf, pbufsize, spec.param.llong); #elif 8 == _RWSTD_LONG_SIZE - spec.param.llong = PARAM (long, lnng); - len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.llong); + spec.param.lng = PARAM (long, lng); + len = rw_fmtinteger (spec, pbuf, pbufsize, spec.param.lng); #else RW_ASSERT (!"%lld, %lli: long long not supported"); @@ -1241,31 +1278,22 @@ } else if (spec.mod_t) { spec.param.diff = PARAM (ptrdiff_t, diff); - if (sizeof (ptrdiff_t) == sizeof (long)) { - len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.diff); - } - else { -#ifdef _RWSTD_LONG_LONG - len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.diff); -#else // if !defined (_RWSTD_LONG_LONG) - RW_ASSERT (!"%td, %ti: 64-bit types not supported"); -#endif // _RWSTD_LONG_LONG - } + len = rw_fmtinteger (spec, pbuf, pbufsize, spec.param.diff); } else if (1 == spec.iwidth) { spec.param.i = PARAM (int, i); const _RWSTD_INT8_T val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (2 == spec.iwidth) { spec.param.i = PARAM (int, i); const _RWSTD_INT16_T val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (3 == spec.iwidth) { spec.param.i32 = PARAM (_RWSTD_INT32_T, i32); const long val = long (spec.param.i32); - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (4 == spec.iwidth) { @@ -1277,17 +1305,17 @@ #if 8 == _RWSTD_LONG_SIZE const long val = spec.param.i64; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); #elif defined (_RWSTD_LONG_LONG) const _RWSTD_LONG_LONG val = spec.param.i64; - len = _rw_fmtllong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); #else RW_ASSERT (!"%I64d, %I64i: 64-bit types not supported"); #endif } else { // %i spec.param.i = PARAM (int, i); - len = _rw_fmtlong (spec, pbuf, pbufsize, long (spec.param.i)); + len = rw_fmtinteger (spec, pbuf, pbufsize, spec.param.i); } break; @@ -1310,23 +1338,23 @@ // promoted unsigned char argument spec.param.i = PARAM (unsigned, i); const unsigned char val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (spec.mod_h) { // promoted unsigned short argument spec.param.i = PARAM (unsigned, i); const unsigned short val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (spec.mod_ll) { #ifdef _RWSTD_LONG_LONG spec.param.llong = PARAM (unsigned _RWSTD_LONG_LONG, llong); const unsigned _RWSTD_LONG_LONG val = spec.param.llong; - len = _rw_fmtllong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); #elif 8 == _RWSTD_LONG_SIZE spec.param.lng = PARAM (unsigned long, lng); const unsigned long val = spec.param.lng; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); #else RW_ASSERT (!"long long not supported"); #endif // _RWSTD_LONG_LONG @@ -1335,35 +1363,26 @@ else if (spec.mod_l) { spec.param.lng = PARAM (unsigned long, lng); const unsigned long val = spec.param.lng; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (spec.mod_t) { - spec.param.lng = PARAM (size_t, size); - if (sizeof (size_t) == sizeof (unsigned long)) { - len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.size); - } - else { -#ifdef _RWSTD_LONG_LONG - len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.size); -#else // if defined (_RWSTD_LONG_LONG) - RW_ASSERT (!"%to, %tu, %tx: 64-bit types not implemented"); -#endif // _RWSTD_LONG_LONG - } + spec.param.size = PARAM (size_t, size); + len = rw_fmtinteger (spec, pbuf, pbufsize, spec.param.size); } else if (1 == spec.iwidth) { spec.param.i = PARAM (int, i); const _RWSTD_UINT8_T val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (2 == spec.iwidth) { spec.param.i = PARAM (int, i); const long val = (unsigned short)spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (3 == spec.iwidth) { spec.param.i32 = PARAM (_RWSTD_INT32_T, i32); const long val = long (unsigned (spec.param.i)); - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } else if (4 == spec.iwidth) { #ifdef _RWSTD_INT64_T @@ -1374,10 +1393,10 @@ #if 8 == _RWSTD_LONG_SIZE const unsigned long val = spec.param.i64; - len = _rw_fmtlong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); #elif defined (_RWSTD_LONG_LONG) const unsigned _RWSTD_LONG_LONG val = spec.param.i64; - len = _rw_fmtllong (spec, pbuf, pbufsize, val); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); #else RW_ASSERT (!"%I64o, %I64u, %I64x: 64-bit types not supported"); #endif @@ -1385,7 +1404,7 @@ else { spec.param.i = PARAM (unsigned, i); const unsigned val = spec.param.i; - len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); + len = rw_fmtinteger (spec, pbuf, pbufsize, val); } break; @@ -1586,6 +1605,9 @@ { const size_t buflen = *pbuf ? strlen (*pbuf) : 0; + if (0 == addr) + return _rw_bufcat (pbuf, pbufsize, "(null)", 6) ? 6 : -1; + if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18)) return -1; @@ -2077,13 +2099,101 @@ /********************************************************************/ static int -_rw_fmttm (const FmtSpec &spec, char **pbuf, size_t *pbufsize, const tm *tmb) +_rw_fmtmask (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int c) { - if (0 == tmb) { - return _rw_fmtstr (spec, pbuf, pbufsize, "(null)", _RWSTD_SIZE_MAX); + enum { + bit_alnum = 1, + bit_alpha = 1 << 1, + bit_cntrl = 1 << 2, + bit_digit = 1 << 3, + bit_graph = 1 << 4, + bit_lower = 1 << 5, + bit_print = 1 << 6, + bit_punct = 1 << 7, + bit_space = 1 << 8, + bit_upper = 1 << 9, + bit_xdigit = 1 << 10 + }; + + int mask = 0; + + if (spec.mod_l) { + +#ifndef _RWSTD_NO_WCHAR_H + + mask |= iswalnum (c) ? bit_alnum : 0; + mask |= iswalpha (c) ? bit_alpha : 0; + mask |= iswcntrl (c) ? bit_cntrl : 0; + mask |= iswdigit (c) ? bit_digit : 0; + mask |= iswgraph (c) ? bit_graph : 0; + mask |= iswlower (c) ? bit_lower : 0; + mask |= iswprint (c) ? bit_print : 0; + mask |= iswpunct (c) ? bit_punct : 0; + mask |= iswspace (c) ? bit_space : 0; + mask |= iswupper (c) ? bit_upper : 0; + mask |= iswxdigit (c) ? bit_xdigit : 0; + +#endif // _RWSTD_NO_WCHAR_H + } + else { + typedef unsigned char UChar; + + const UChar uc = c; + + mask |= isalnum (uc) ? bit_alnum : 0; + mask |= isalpha (uc) ? bit_alpha : 0; + mask |= iscntrl (uc) ? bit_cntrl : 0; + mask |= isdigit (uc) ? bit_digit : 0; + mask |= isgraph (uc) ? bit_graph : 0; + mask |= islower (uc) ? bit_lower : 0; + mask |= isprint (uc) ? bit_print : 0; + mask |= ispunct (uc) ? bit_punct : 0; + mask |= isspace (uc) ? bit_space : 0; + mask |= isupper (uc) ? bit_upper : 0; + mask |= isxdigit (uc) ? bit_xdigit : 0; + } + + char mask_str [80]; + char *str = mask_str; + + str [0] = '\0'; + +#define APPEND(bit) \ + if (mask & bit_ ## bit) \ + strcat (strcat (str, #bit), "|"); \ + else (void)0 + + APPEND (alnum); + APPEND (alpha); + APPEND (cntrl); + APPEND (digit); + APPEND (graph); + APPEND (lower); + APPEND (print); + APPEND (punct); + APPEND (space); + APPEND (upper); + APPEND (xdigit); + + if (str == mask_str) + *str = '\0'; + else + str [-1] = '\0'; + + const size_t len = strlen (str); + if (0 == _rw_bufcat (pbuf, pbufsize, str, len)) + return -1; + + return int (len); +} + +/********************************************************************/ - if (0 > _RW::__rw_memattr (tmb, sizeof *tmb, 0)) { +static int +_rw_fmttm (const FmtSpec &spec, char **pbuf, size_t *pbufsize, const tm *tmb) +{ + if (0 == tmb || 0 > _RW::__rw_memattr (tmb, sizeof *tmb, 0)) { return _rw_fmtbadaddr (spec, pbuf, pbufsize, tmb); } @@ -2486,36 +2596,48 @@ } -template -int rw_quotestr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, - const charT *wstr, size_t nchars, int noesc) +enum { + A_ESC = 1, // use escape sequences + A_CHAR = 1 << 1, // format each element as a char + A_WCHAR = 1 << 2 // format each element as a wchar_t +}; + +template +int rw_fmtarray (const FmtSpec &spec, char **pbuf, size_t *pbufsize, + const elemT *array, // pointer to first element + size_t nelems, // number of elements + int flags) { RW_ASSERT (0 != pbuf); - if (!wstr) { - static const charT null[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' }; - wstr = null; - nchars = sizeof null / sizeof *null - 1; - } - - if (0 > _RW::__rw_memattr (wstr, _RWSTD_SIZE_MAX, 0)) { - return _rw_fmtbadaddr (spec, pbuf, pbufsize, wstr); - } + if (0 == array || 0 > _RW::__rw_memattr (array, _RWSTD_SIZE_MAX, 0)) + return _rw_fmtbadaddr (spec, pbuf, pbufsize, array); - if (_RWSTD_SIZE_MAX == nchars) { + if (_RWSTD_SIZE_MAX == nelems) { // compute the length of the NUL-terminate string - nchars = 0; - for (const charT *pc = wstr; *pc; ++pc, ++nchars); + nelems = 0; + for (const elemT *pc = array; *pc; ++pc, ++nelems); } - char *next = _rw_bufcat (pbuf, pbufsize, 0, (nchars + 1) * 12 + 3); + // separator string to insert between numerical elements + const char* const sep = flags & (A_CHAR | A_WCHAR) ? + "" : spec.strarg ? spec.strarg : ","; + + // length of the separator string + const size_t seplen = strlen (sep); + + // compute the size of the buffer to preallocate + const size_t bufsize = (nelems + 1) * (65 + seplen) + 3; + + // preallocate a buffer large enough for the formatted array + char *next = _rw_bufcat (pbuf, pbufsize, 0, bufsize); const char* const bufend = next; if (0 == next) return -1; - if (0 == nchars) { - if (noesc) { + if (0 == nelems) { + if (!(flags & A_ESC)) { #if 0 // width handling disabled (width used for array formatting) for (int w = 0; w < spec.width; ++w) @@ -2524,7 +2646,7 @@ } else { - if (_RWSTD_WCHAR_T_SIZE == sizeof (charT)) + if (_RWSTD_WCHAR_T_SIZE == sizeof (elemT)) *next++ = 'L'; *next++ = '"'; @@ -2540,84 +2662,150 @@ char *s = next; - const charT *last = wstr; + const elemT *last = array; bool any_repeats = false; - long last_repeat = noesc ? 0L : -1L; + long last_repeat = flags & A_ESC ? -1L : 0L; - char chstr [16]; + // large enough for a 64-bit integer in binary notation + char elemstr [65]; - const ptrdiff_t N = ptrdiff_t (noesc ? 0 : 20); + const ptrdiff_t N = ptrdiff_t (flags & A_ESC ? 20 : 0); - for (const charT *pwc = last + 1; ; ++pwc) { + for (const elemT *pelem = last + 1; ; ++pelem) { - if (*pwc == *last && size_t (pwc - wstr) < nchars) { - // if the last processed character repeats, continue - // until a different character is encountered + if (*pelem == *last && size_t (pelem - array) < nelems) { + // if the last processed element repeats, continue + // until a different element is encountered continue; } - if (N > 1 && pwc - last > N) { + if (N > 1 && pelem - last > N) { - // if the last processed character repeats N or more + // if the last processed element repeats N or more // times, format the repeat count instead of all the - // repeated occurrences of the character to conserve + // repeated occurrences of the element to conserve // space and make the string more readable - const long repeat = pwc - last; + const long repeat = pelem - last; + + if (flags & (A_CHAR | A_WCHAR)) { + // format element into elemstr as a character + rw_quotechar (elemstr, *last, !(flags & A_ESC)); + + s += sprintf (s, "%s'%s' ", + -1 == last_repeat ? "" + : 0 == last_repeat ? "\", " : ", ", + elemstr, repeat); + } + else { + // format element into elemstr as an integer + char *localbuf = elemstr; + size_t localbufsize = sizeof elemstr; - rw_quotechar (chstr, *last, noesc); + *localbuf = '\0'; + const int intlen = + rw_fmtinteger (spec, &localbuf, &localbufsize, *last); - s += sprintf (s, "%s'%s' ", - -1 == last_repeat ? "" - : 0 == last_repeat ? "\", " : ", ", - chstr, repeat); + // no error should happen + RW_ASSERT (0 < intlen); - last = pwc; + localbuf [intlen] = '\0'; + + // verify that rw_fmtinteger didn't try to reallocate + RW_ASSERT (localbuf == elemstr); + + s += sprintf (s, "%s%s %s", + last_repeat < 1 ? "" : sep, elemstr, repeat, sep); + } + + last = pelem; any_repeats = true; last_repeat = repeat; } else { - // otherwise (if the last processed character repeats - // fewer than N times) format the character that many + // otherwise (if the last processed element repeats + // fewer than N times) format the element that many // times if (last_repeat < 0) { - // opening quote - if (_RWSTD_WCHAR_T_SIZE == sizeof (charT)) { - *s++ = 'L'; + if (flags & (A_CHAR | A_WCHAR)) { + // insert an opening quote (preceded by the 'L' + // prefix for wchar_t arrays) + if (_RWSTD_WCHAR_T_SIZE == sizeof (elemT)) { + *s++ = 'L'; + } + *s++ = '\"'; } - *s++ = '\"'; } else if (last_repeat > 0) { - *s++ = ','; - *s++ = ' '; - *s++ = '\"'; + if (flags & (A_CHAR | A_WCHAR)) { + // append a comma after a preceding "" + *s++ = ','; + *s++ = ' '; + // append an opening quote for character arrays + *s++ = '\"'; + } + } + + if (flags & (A_CHAR | A_WCHAR)) { + // format element into elemstr as a character + rw_quotechar (elemstr, *last, !(flags & A_ESC)); } + else { + // format element into elemstr as an integer + char *localbuf = elemstr; + size_t localbufsize = sizeof elemstr; + + *localbuf = '\0'; + const int intlen = + rw_fmtinteger (spec, &localbuf, &localbufsize, *last); + + // no error should happen + RW_ASSERT (0 < intlen); - rw_quotechar (chstr, *last, noesc); + localbuf [intlen] = '\0'; - while (last != pwc) { - s += sprintf (s, "%s", chstr); - ++last; + // verify that rw_fmtinteger didn't try to reallocate + RW_ASSERT (localbuf == elemstr); + } + + const size_t elemlen = strlen (elemstr); + + for ( ; last != pelem; ++last) { + memcpy (s, elemstr, elemlen); + s += elemlen; + memcpy (s, sep, seplen + 1); + s += seplen; } last_repeat = 0; - if (size_t (pwc - wstr) == nchars) { - if (!noesc) + if (size_t (pelem - array) == nelems) { + if (flags & (A_CHAR | A_WCHAR) && flags & A_ESC) *s++ = '\"'; + + // eliminate the last separator + s -= seplen; *s = '\0'; + break; } } - if (size_t (pwc - wstr) == nchars) + if (size_t (pelem - array) == nelems) { + // eliminate the last separator + s -= seplen; + *s = '\0'; + break; + } } if (any_repeats) { + // enclose the whole thing in curly braces if any repeated elements + // have been formatted using the "... " syntax const size_t len = strlen (next); memmove (next + 2, next, len); next [0] = '{'; @@ -2634,6 +2822,79 @@ /********************************************************************/ static int +_rw_fmtarray (FmtSpec *pspec, size_t paramno, + char **pbuf, size_t *pbufsize, va_list *pva) +{ + RW_ASSERT (0 != pspec); + + FmtSpec &spec = pspec [paramno]; + + // save width and set to unspecified (i.e., 1) + const int width = spec.width; + spec.width = -1; + + const int flags = 'c' == spec.cvtspec ? + A_CHAR | A_ESC : spec.fl_pound ? A_ESC : 0; + + // to format an array of integers using the 0 or 0x/0X prefix + // both the pound and the zero flags must be set; clear the pound + // flag unless zero is also set + const unsigned pound = spec.fl_pound; + if (0 == spec.fl_zero) + spec.fl_pound = 0; + + const size_t nelems = spec.prec; + spec.prec = -1; + + int len = -1; + + // array formatting: width determines the width of each array element, + // precision the number of elements (when negative the array is taken + // to extend up to but not including the first 0 element) + if (-1 == width || 1 == width) { + spec.param.ptr = PARAM (_RWSTD_UINT8_T*, ptr); + const _RWSTD_UINT8_T* const array = (_RWSTD_UINT8_T*)spec.param.ptr; + // note that when no precision is specified in the format string + // (e.g., "%{Ac}") its value will be -1 and the function will format + // all elements up to but excluding the terminating 0 + len = rw_fmtarray (spec, pbuf, pbufsize, array, nelems, flags); + } + else if (2 == width) { + spec.param.ptr = PARAM (_RWSTD_UINT16_T*, ptr); + const _RWSTD_UINT16_T* const array = (_RWSTD_UINT16_T*)spec.param.ptr; + len = rw_fmtarray (spec, pbuf, pbufsize, array, nelems, flags); + } + else if (4 == width) { + spec.param.ptr = PARAM (_RWSTD_UINT32_T*, ptr); + const _RWSTD_UINT32_T* const array = (_RWSTD_UINT32_T*)spec.param.ptr; + len = rw_fmtarray (spec, pbuf, pbufsize, array, nelems, flags); + } + +#ifdef _RWSTD_UINT64_T + + else if (8 == width) { + spec.param.ptr = PARAM (_RWSTD_UINT64_T*, ptr); + const _RWSTD_UINT64_T* const array = (_RWSTD_UINT64_T*)spec.param.ptr; + len = rw_fmtarray (spec, pbuf, pbufsize, array, nelems, flags); + } + +#endif // _RWSTD_UINT64_T + + else { + RW_ASSERT (!"%{Ac} not implemented for this character size"); + } + + // restore modified members + spec.fl_pound = pound; + spec.prec = int (nelems); + spec.width = width; + + return len; +} + +/********************************************************************/ + +static int _rw_fmtchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val) { typedef unsigned char UChar; @@ -2680,14 +2941,10 @@ char **pbuf, size_t *pbufsize, const char *str, size_t len) { if (spec.fl_pound) - return rw_quotestr (spec, pbuf, pbufsize, str, len, 0); - - if (0 == str) - str = "(null)"; + return rw_fmtarray (spec, pbuf, pbufsize, str, len, A_CHAR | A_ESC); - if (0 > _RW::__rw_memattr (str, _RWSTD_SIZE_MAX, 0)) { + if (0 == str || 0 > _RW::__rw_memattr (str, _RWSTD_SIZE_MAX, 0)) return _rw_fmtbadaddr (spec, pbuf, pbufsize, str); - } if (_RWSTD_SIZE_MAX == len) len = strlen (str); @@ -2740,7 +2997,7 @@ _rw_fmtwstr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, const wchar_t *wstr, size_t len) { - return rw_quotestr (spec, pbuf, pbufsize, wstr, len, 1); + return rw_fmtarray (spec, pbuf, pbufsize, wstr, len, A_WCHAR | A_ESC); } /********************************************************************/ @@ -3114,7 +3371,7 @@ else { // misplaced "%{:}"? static const char str[] = "%{:}"; - len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0); + len = _rw_fmtstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX); } break; @@ -3126,57 +3383,13 @@ else { // misplaced "%{;}"? static const char str[] = "%{;}"; - len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0); + len = _rw_fmtstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX); } break; case 'c': // %{c}, %{Ac}, %{Lc}, %{lc} - if (spec.mod_A) { - // array formatting: width determines the width of each - // array element, precision the number of elements (when - // negative the array is taken to extend up to but not - // including the first NUL (0) element - if (-1 == spec.width || 1 == spec.width) { - spec.param.ptr = PARAM (_RWSTD_UINT8_T*, ptr); - const _RWSTD_UINT8_T* const array = - (_RWSTD_UINT8_T*)spec.param.ptr; - // note that when no precision is specified in the format - // string (e.g., "%{Ac}") its value will be -1 and the - // function will format all characters up to but excluding - // the terminating NUL - len = rw_quotestr (spec, pbuf, pbufsize, array, - spec.prec, 0); - } - else if (2 == spec.width) { - spec.param.ptr = PARAM (_RWSTD_UINT16_T*, ptr); - const _RWSTD_UINT16_T* const array = - (_RWSTD_UINT16_T*)spec.param.ptr; - len = rw_quotestr (spec, pbuf, pbufsize, array, - spec.prec, 0); - } - else if (4 == spec.width) { - spec.param.ptr = PARAM (_RWSTD_UINT32_T*, ptr); - const _RWSTD_UINT32_T* const array = - (_RWSTD_UINT32_T*)spec.param.ptr; - len = rw_quotestr (spec, pbuf, pbufsize, array, - spec.prec, 0); - } - -#ifdef _RWSTD_UINT64_T - - else if (8 == spec.width) { - spec.param.ptr = PARAM (_RWSTD_UINT64_T*, ptr); - const _RWSTD_UINT64_T* const array = - (_RWSTD_UINT64_T*)spec.param.ptr; - len = rw_quotestr (spec, pbuf, pbufsize, array, - spec.prec, 0); - } - -#endif // _RWSTD_UINT64_T - - else { - RW_ASSERT (!"%{Ac} not implemented for this character size"); - } + if (spec.mod_A) { // array of characters + len = _rw_fmtarray (pspec, paramno, pbuf, pbufsize, pva); } else if (spec.mod_L) { // locale category or LC_XXX constant spec.param.i = PARAM (int, i); @@ -3226,19 +3439,41 @@ else { RW_ASSERT (!"%{g} not implemented"); } + break; case 'd': // %{Id} case 'i': // %{Ii} + if (-1 == spec.base) + spec.base = 10; + // fall through + case 'o': // %{Io} if (spec.mod_I) { // ios::openmode spec.param.i = PARAM (int, i); len = _rw_fmtopenmode (spec, pbuf, pbufsize, spec.param.i); break; } - case 'x': // %{x} - case 'X': // %{X} - case 'u': // %{u} - len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva); + if (-1 == spec.base) + spec.base = 8; + // fall through + + case 'x': // %{x}, %{Ax} + case 'X': // %{X}, %{AX} + if (-1 == spec.base) + spec.base = 16; + // fall through + + case 'u': // %{u}, %{Au} + if (spec.mod_A) { // array + if (-1 == spec.base) + spec.base = 10; + len = _rw_fmtarray (pspec, paramno, pbuf, pbufsize, pva); + } + else { + // reset base set above + spec.base = -1; + len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva); + } break; case 'K': // %{K} -- signal @@ -3336,12 +3571,14 @@ else if (spec.mod_l) { // wchar_t* spec.param.ptr = PARAM (wchar_t*, ptr); const wchar_t* const wstr = (wchar_t*)spec.param.ptr; - len = rw_quotestr (spec, pbuf, pbufsize, wstr, _RWSTD_SIZE_MAX, 0); + len = rw_fmtarray (spec, pbuf, pbufsize, wstr, _RWSTD_SIZE_MAX, + A_WCHAR | A_ESC); } else { // char* spec.param.ptr = PARAM (char*, ptr); const char* const str = (char*)spec.param.ptr; - len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0); + len = rw_fmtarray (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, + A_CHAR | A_ESC); } break;