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 <[EMAIL PROTECTED]>
* src/printf.cpp (<ctype.h>): Included for isalpha, et al.
(<wchar.h>, <wctype.h>): 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 <repeats 32 times> }");
+
+ TEST ("%{2Ao}", array16, 0, 0, array_str);
+ TEST ("%{#2Ao}", array16, 0, 0, "{ 1 <repeats 32 times> }");
+
+ TEST ("%{4Ao}", array32, 0, 0, array_str);
+ TEST ("%{#4Ao}", array32, 0, 0, "{ 1 <repeats 32 times> }");
+
+ SET_ELEM (1, 2);
+
+ TEST ("%{2Ao}", array16, 0, 0, array_str);
+ TEST ("%{#2Ao}", array16, 0, 0, "{ 1,2,1 <repeats 30 times> }");
+
+ SET_ELEM ( 1, 1);
+ SET_ELEM (30, 2);
+
+ TEST ("%{2Ao}", array16, 0, 0, array_str);
+ TEST ("%{#2Ao}", array16, 0, 0, "{ 1 <repeats 30 times>,2,1 }");
+
+ SET_ELEM (30, 1);
+ SET_ELEM (31, 2);
+
+ TEST ("%{2Ao}", array16, 0, 0, array_str);
+ TEST ("%{#2Ao}", array16, 0, 0, "{ 1 <repeats 31 times>,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 <testdefs.h>
#include <printf.h>
+#include <ctype.h> // for isalpha(), ...
#include <errno.h> // for errno, errno constants
#include <float.h> // for floating point macros
#include <locale.h>
@@ -33,7 +34,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <wchar.h>
+
+#ifndef _RWSTD_NO_WCHAR_H
+# include <wchar.h>
+#endif // _RWSTD_NO_WCHAR_H
+
+#ifndef _RWSTD_NO_WCTYPE_H
+# include <wctype.h> // for iswalpha(), ...
+#endif // _RWSTD_NO_WCTYPE_H
#if defined (_WIN32) || defined (_WIN64)
// define macros to enable Win98 + WinNT support in <windows.h>
@@ -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) {
+ // %{$<string>}: 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 <class IntT>
+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 <class charT>
-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 <class elemT>
+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' <repeats %ld times>",
+ -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' <repeats %ld times>",
- -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 <repeats %ld times>%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 "<repeats N times>"
+ *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 "... <repeats N times>" 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;