stdcxx-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From se...@apache.org
Subject svn commit: r369862 - in /incubator/stdcxx/trunk/tests: self/0.printf.cpp src/printf.cpp
Date Tue, 17 Jan 2006 18:48:20 GMT
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  <sebor@roguewave.com>

	* 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;
 



Mime
View raw message