Author: sebor
Date: Tue Mar 21 17:58:27 2006
New Revision: 387687
URL: http://svn.apache.org/viewcvs?rev=387687&view=rev
Log:
2006-03-21 Martin Sebor <[EMAIL PROTECTED]>
* rw_char.h (UserCharFmatInit, _rw_user_char_fmat_init): Initializer
type and object to install a "user-defined" formatting callback for
arrays of generic characters including UserChar.
* src/char.cpp (_rw_fmtstring, _rw_fmtstringv): "User-defined"
formatting callback for arrays of generic characters including
UserChar.
* test/0.char.cpp (test_formatting): Exercised the above.
Modified:
incubator/stdcxx/trunk/tests/include/rw_char.h
incubator/stdcxx/trunk/tests/self/0.char.cpp
incubator/stdcxx/trunk/tests/src/char.cpp
Modified: incubator/stdcxx/trunk/tests/include/rw_char.h
URL:
http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/rw_char.h?rev=387687&r1=387686&r2=387687&view=diff
==============================================================================
--- incubator/stdcxx/trunk/tests/include/rw_char.h (original)
+++ incubator/stdcxx/trunk/tests/include/rw_char.h Tue Mar 21 17:58:27 2006
@@ -316,4 +316,8 @@
_RWSTD_SIZE_T rw_match (const char*, const UserChar*,
_RWSTD_SIZE_T = _RWSTD_SIZE_MAX);
+static const struct UserCharFmatInit {
+ UserCharFmatInit ();
+} _rw_user_char_fmat_init;
+
#endif // RW_CHAR_INCLUDED
Modified: incubator/stdcxx/trunk/tests/self/0.char.cpp
URL:
http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/self/0.char.cpp?rev=387687&r1=387686&r2=387687&view=diff
==============================================================================
--- incubator/stdcxx/trunk/tests/self/0.char.cpp (original)
+++ incubator/stdcxx/trunk/tests/self/0.char.cpp Tue Mar 21 17:58:27 2006
@@ -27,8 +27,10 @@
**************************************************************************/
#include <rw_char.h>
+#include <rw_printf.h>
#include <driver.h>
+#include <stdlib.h>
#include <string.h> // for memset, size_t
/***********************************************************************/
@@ -604,7 +606,7 @@
static size_t
length (const char *s)
{
- return strlen (s);
+ return s ? strlen (s) : 0;
}
@@ -658,15 +660,17 @@
const size_t size_max = _RWSTD_SIZE_MAX;
size_t result;
+#define LEN(T, s, len) \
+ int (size_max == size_t (len) ? length ((const T*)s) : size_t (len))
+
#undef TEST
-#define TEST(s1, s2, len, expect) \
- result = rw_match ((const char*)s1, (const char*)s2, size_t (len)); \
- rw_assert (expect == result, \
- 0, __LINE__, \
- "rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu", \
- int (size_max == len ? length ((const char*)s1) : len), s1, \
- int (size_max == len ? length ((const char*)s2) : len), s2, \
- len, expect, result)
+#define TEST(s1, s2, len, expect) \
+ result = rw_match ((const char*)s1, (const char*)s2, size_t (len)); \
+ rw_assert (expect == result, \
+ 0, __LINE__, \
+ "rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu", \
+ LEN (char, s1, len), s1, LEN (char, s2, len), \
+ s2, len, expect, result)
TEST (0, 0, -1, 0);
TEST ("", 0, -1, 0);
@@ -706,8 +710,7 @@
rw_assert (expect == result, \
0, __LINE__, \
"rw_match(%{#*s}, L%{#*ls}, %zu) == %zu, got %zu", \
- int (size_max == len ? length ((const char*)s1) : len), s1, \
- int (size_max == len ? length ((const wchar_t*)s2) : len), s2, \
+ LEN (char, s1, len), s1, LEN (wchar_t, s2, len), s2, \
len, expect, result)
TEST (0, 0, -1, 0);
@@ -750,9 +753,8 @@
rw_assert (expect == result, \
0, __LINE__, \
"rw_match(%{#*s}, %{#*s}, %zu) == %zu, got %zu", \
- int (size_max == len ? length ((const char*)s1) : len), s1, \
- int (size_max == len ? length ((const char*)s2) : len), s2, \
- len, expect, result)
+ LEN (char, s1, len), s1, LEN (UserChar, s2, len), \
+ s2, len, expect, result)
TEST (0, 0, -1, 0);
TEST ("", 0, -1, 0);
@@ -781,6 +783,61 @@
/***********************************************************************/
+static void
+test_formatting ()
+{
+ //////////////////////////////////////////////////////////////////
+ rw_info (0, 0, 0, "\"%s\": formatting directive", "%{/Gs}");
+
+ const int wchsize = int (sizeof (wchar_t));
+ const int usrsize = int (sizeof (UserChar));
+
+ char *str;
+
+#undef TEST
+#define TEST(fmt, arg0, arg1, arg2, expect_str) \
+ str = rw_sprintfa (fmt, arg0, arg1, arg2); \
+ rw_assert (str && 0 == strcmp (str, expect_str), \
+ 0, __LINE__, \
+ "rw_printf(%#s, ...) == %#s; got %#s", \
+ fmt, expect_str, str); \
+ free (str)
+
+ TEST (">%{/Gs}<", (char*)0, 0, 0, ">(null)<");
+ TEST (">%{/Gs}<", "", 0, 0, ">\"\"<");
+ TEST (">%{/Gs}<", "a", 0, 0, ">\"a\"<");
+ TEST (">%{/Gs}<", "ab", 0, 0, ">\"ab\"<");
+ TEST (">%{/Gs}<", "abc", 0, 0, ">\"abc\"<");
+ TEST (">%{/Gs}<", "x\0z", 0, 0, ">\"x\"<");
+
+ TEST (">%{/*Gs}<", 1, "abc", 0, ">\"abc\"<");
+ TEST (">%{/*.*Gs}<", 1, 2, "abc", ">\"ab\"<");
+ TEST (">%{/.*Gs}<", 2, "abc", 0, ">\"ab\"<");
+ TEST (">%{/.*Gs}<", 3, "x\0z", 0, ">\"x\\0z\"<");
+
+ TEST (">%{/*Gs}<", wchsize, (wchar_t*)0, 0, ">(null)<");
+ TEST (">%{/*Gs}<", wchsize, L"", 0, ">\"\"<");
+ TEST (">%{/*Gs}<", wchsize, L"a", 0, ">\"a\"<");
+ TEST (">%{/*Gs}<", wchsize, L"ab", 0, ">\"ab\"<");
+ TEST (">%{/*Gs}<", wchsize, L"abc", 0, ">\"abc\"<");
+ TEST (">%{/*Gs}<", wchsize, L"x\0z", 0, ">\"x\"<");
+ TEST (">%{/*.*Gs}<", wchsize, 2, L"abc", ">\"ab\"<");
+ TEST (">%{/*.*Gs}<", wchsize, 3, L"x\0z",">\"x\\0z\"<");
+
+#define US(s) make_user_string (s, sizeof (s))
+
+ TEST (">%{/*Gs}<", usrsize, (UserChar*)0, 0, ">(null)<");
+ TEST (">%{/*Gs}<", usrsize, US (""), 0, ">\"\"<");
+ TEST (">%{/*Gs}<", usrsize, US ("a"), 0, ">\"a\"<");
+ TEST (">%{/*Gs}<", usrsize, US ("ab"), 0, ">\"ab\"<");
+ TEST (">%{/*Gs}<", usrsize, US ("abc"), 0, ">\"abc\"<");
+ TEST (">%{/*Gs}<", usrsize, US ("x\0z"), 0, ">\"x\"<");
+ TEST (">%{/*.*Gs}<", usrsize, 2, US ("abc"), ">\"ab\"<");
+ TEST (">%{/*.*Gs}<", usrsize, 3, US ("x\0z"), ">\"x\\0z\"<");
+}
+
+/***********************************************************************/
+
static int no_user_traits;
static int no_user_traits_char;
static int no_user_traits_wchar_t;
@@ -788,6 +845,7 @@
static int no_rw_widen;
static int no_rw_narrow;
static int no_rw_match;
+static int no_formatting;
static int
@@ -829,6 +887,7 @@
TEST (rw_widen);
TEST (rw_narrow);
TEST (rw_match);
+ TEST (formatting);
return 0;
}
@@ -847,7 +906,8 @@
"|-no-UserTraits<UserChar># "
"|-no-rw_widen# "
"|-no-rw_narrow# "
- "|-no-rw_macth#",
+ "|-no-rw_macth# "
+ "|-no-formatting#",
&no_user_traits,
&no_user_traits_char,
&no_user_traits_wchar_t,
@@ -855,5 +915,6 @@
&no_rw_widen,
&no_rw_narrow,
&no_rw_match,
+ &no_formatting,
0);
}
Modified: incubator/stdcxx/trunk/tests/src/char.cpp
URL:
http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/src/char.cpp?rev=387687&r1=387686&r2=387687&view=diff
==============================================================================
--- incubator/stdcxx/trunk/tests/src/char.cpp (original)
+++ incubator/stdcxx/trunk/tests/src/char.cpp Tue Mar 21 17:58:27 2006
@@ -29,7 +29,12 @@
#define _RWSTD_TEST_SRC
#include <rw_char.h>
-#include <string.h> // for memcpy()
+#include <rw_printf.h> // for rw_snprintfa()
+
+#include <ctype.h> // for isdigit()
+#include <stdarg.h> // for va_arg(), va_list, ...
+#include <stdlib.h> // for strtol()
+#include <string.h> // for memcpy(), strlen(), ...
size_t
@@ -226,6 +231,7 @@
return int_type::eof ();
}
+/**************************************************************************/
_TEST_EXPORT
char*
@@ -497,4 +503,222 @@
}
return n;
+}
+
+/**************************************************************************/
+
+static int
+_rw_fmtstringv (char **pbuf, size_t *pbufsize, const char *fmt, va_list va)
+{
+ RW_ASSERT (0 != pbuf);
+ RW_ASSERT (0 != pbufsize);
+ RW_ASSERT (0 != fmt);
+
+ // directive syntax:
+ // '/' [ '#' ] { '*' | <n> } [ '.' '*' | <n> ] "Gs"
+
+ // NOTE:
+ // leading slash (or any other violation of the "standard" directive
+ // syntax) prevents the caller from extracting width and precision
+ // (etc.) from its variable argument list and allows us to do so
+
+ static int nested_call;
+
+ if (nested_call || '/' != fmt [0])
+ return _RWSTD_INT_MIN;
+
+ ++nested_call;
+ ++fmt;
+
+ va_list* pva = 0;
+ bool fl_pound = false;
+ int nelems = -1;
+ int paramno = -1;
+ int elemsize = -1;
+
+ union UPtr {
+ const char *pc;
+ const wchar_t *pwc;
+ const UserChar *puc;
+ };
+
+ if ('#' == *fmt) {
+ fl_pound = true;
+ ++fmt;
+ }
+
+ // saved caller's va_list in case it needs to be restored
+ // to its orginal state after extracting argument from it
+ va_list va_save;
+
+ if ('*' == *fmt) {
+ // process element width (i.e., sizeof(charT))
+ pva = va_arg (va, va_list*);
+
+ RW_ASSERT (0 != pva);
+ va_save = *pva;
+
+ // extract the width from rw_snprintfa's variable argument
+ // list pass through to us by the caller
+ elemsize = va_arg (*pva, int);
+ ++fmt;
+ }
+ else if (isdigit (*fmt)) {
+ // process positional parameter or width
+ char* end = 0;
+ const int arg = strtol (fmt, &end, 10);
+ if ('$' == *end)
+ paramno = arg;
+ else
+ elemsize = arg;
+
+ fmt = end;
+ }
+
+ if ('.' == *fmt) {
+ // process precision (the length of the array in elements)
+ if ('*' == *++fmt) {
+ if (0 == pva) {
+ pva = va_arg (va, va_list*);
+
+ RW_ASSERT (0 != pva);
+
+ va_save = *pva;
+ }
+
+ // extract the width from rw_snprintfa's variable argument
+ // list passed through to us by the caller
+ nelems = va_arg (*pva, int);
+ ++fmt;
+ }
+ else if (isdigit (*fmt)) {
+ char* end = 0;
+ nelems = int (strtol (fmt, &end, 10));
+ fmt = end;
+ }
+ }
+
+ // extract the address of the caller's variable argument list
+ if (0 == pva) {
+ pva = va_arg (va, va_list*);
+
+ RW_ASSERT (0 != pva);
+
+ va_save = *pva;
+ }
+
+ if ('G' != fmt [0] || 's' != fmt [1] || '\0' != fmt [2]) {
+
+ // restore caller's (potentially modified) va_list
+ *pva = va_save;
+
+ --nested_call;
+
+ // uknown directive, let caller process
+ return _RWSTD_INT_MIN;
+ }
+
+ // extract a pointer to the first character from rw_snprintfa's
+ // variable argument list pass through to us by the caller
+ const UPtr beg = { va_arg (*pva, char*) };
+
+ {
+ // extract the address where to store the extracted argument
+ // for use by any subsequent positional paramaters
+ const char** const pparam = va_arg (va, const char**);
+
+ RW_ASSERT (0 != pparam);
+
+ // store the extracted argument
+ *pparam = beg.pc;
+ }
+
+ // compute the length of the buffer formatted so far
+ const size_t buflen_0 = *pbuf ? strlen (*pbuf) : 0;
+
+ int nbytes = 0;
+
+ //////////////////////////////////////////////////////////////////
+ // invoke rw_asnprintf() recursively to format our arguments
+ // and append the result to the end of the buffer; pass the
+ // value returned from rw_asnprintf() (i.e., the number of
+ // bytes appended) back to the caller
+
+ if (-1 == elemsize || 1 == elemsize) {
+ if (nelems < 0)
+ nelems = beg.pc ? strlen (beg.pc) : 0;
+
+ nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#*s}", nelems, beg.pc);
+ }
+ else if (_RWSTD_WCHAR_T_SIZE == elemsize) {
+ if (nelems < 0)
+ nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#ls}", beg.pwc);
+ else
+ nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#*ls}",
+ nelems, beg.pwc);
+ }
+ else if (sizeof (UserChar) == size_t (elemsize)) {
+
+ // narrow the argument into a local buffer of sufficient size
+ // (dynamically allocating memory only when the length of the
+ // string exceeds the size of the buffer for efficiency) and formt
+ // the resulting narrow string
+ char smallbuf [256];
+ const size_t len = nelems < 0 ? rw_match (0, beg.puc) : size_t
(nelems);
+ char* const pb = len < sizeof smallbuf ? smallbuf : new char [len + 1];
+ rw_narrow (pb, beg.puc, len);
+
+ if (nelems < 0)
+ nelems = int (len);
+
+ nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#*s}",
+ nelems, beg.pc ? pb : beg.pc);
+
+ if (pb != smallbuf)
+ delete[] pb;
+ }
+ else {
+ nbytes = rw_asnprintf (pbuf, pbufsize,
+ "*** %%{/Gs}: bad element size: %d ***",
+ elemsize);
+ }
+
+ //////////////////////////////////////////////////////////////////
+
+ // compute the new length of the buffer
+ const size_t buflen_1 = *pbuf ? strlen (*pbuf) : 0;
+
+ // assert that the function really appended as many characters
+ // as it said it did (assumes no NULs embedded in the output)
+ // and that it didn't write past the end of the buffer
+ RW_ASSERT (buflen_1 == buflen_0 + nbytes);
+ RW_ASSERT (buflen_1 < *pbufsize);
+
+ --nested_call;
+
+ return nbytes;
+}
+
+
+static int
+_rw_fmtstring (char **pbuf, size_t *pbufsize, const char *fmt, ...)
+{
+ va_list va;
+ va_start (va, fmt);
+
+ const int nbytes = _rw_fmtstringv (pbuf, pbufsize, fmt, va);
+
+ va_end (va);
+
+ return nbytes;
+}
+
+
+UserCharFmatInit::
+UserCharFmatInit ()
+{
+ // install the formatting callback function
+ static int format_init = rw_printf ("%{+!}", _rw_fmtstring);
+
+ _RWSTD_UNUSED (format_init);
}