summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark H Weaver <mhw@netris.org>2012-04-04 18:58:44 -0400
committerMark H Weaver <mhw@netris.org>2012-04-04 18:58:44 -0400
commitbbb9f000ad52282ee1a0518b65437baf20c3d17c (patch)
tree270f1ab225107ae8cb2a58fe5e8259877d6ab5ea
parent51853eee69ca5811ae0661eb91868121c6ad1d74 (diff)
downloadguile-bbb9f000ad52282ee1a0518b65437baf20c3d17c.tar.gz
Fix scm_to_utf8_stringn once and for all; optimize; add tests
* libguile/strings.c (scm_to_utf8_stringn): Fix another new bug in this recent comedy of errors: pass the size of the preallocated buffer to u32_to_u8. Arrange to call 'scm_i_string_wide_chars' and 'scm_i_string_length' only once each. Rename local variables for improved code clarity. * test-suite/standalone/test-conversion.c (test_to_utf8_stringn): New function to test scm_to_utf8_stringn.
-rw-r--r--libguile/strings.c22
-rw-r--r--test-suite/standalone/test-conversion.c69
2 files changed, 80 insertions, 11 deletions
diff --git a/libguile/strings.c b/libguile/strings.c
index ec55c501b..07356fcaf 100644
--- a/libguile/strings.c
+++ b/libguile/strings.c
@@ -1929,28 +1929,28 @@ scm_to_utf8_stringn (SCM str, size_t *lenp)
NULL, lenp);
else
{
+ scm_t_uint32 *chars = (scm_t_uint32 *) scm_i_string_wide_chars (str);
scm_t_uint8 *buf, *ret;
- size_t predicted_len, actual_len; /* length in bytes */
+ size_t num_chars = scm_i_string_length (str);
+ size_t num_bytes_predicted, num_bytes_actual;
- predicted_len = u32_u8_length_in_bytes
- ((scm_t_uint32 *) scm_i_string_wide_chars (str),
- scm_i_string_length (str));
+ num_bytes_predicted = u32_u8_length_in_bytes (chars, num_chars);
if (lenp)
{
- *lenp = predicted_len;
- buf = scm_malloc (predicted_len);
+ *lenp = num_bytes_predicted;
+ buf = scm_malloc (num_bytes_predicted);
}
else
{
- buf = scm_malloc (predicted_len + 1);
- buf[predicted_len] = 0;
+ buf = scm_malloc (num_bytes_predicted + 1);
+ buf[num_bytes_predicted] = 0;
}
- ret = u32_to_u8 ((scm_t_uint32 *) scm_i_string_wide_chars (str),
- scm_i_string_length (str), buf, &actual_len);
+ num_bytes_actual = num_bytes_predicted;
+ ret = u32_to_u8 (chars, num_chars, buf, &num_bytes_actual);
- if (SCM_LIKELY (ret == buf && actual_len == predicted_len))
+ if (SCM_LIKELY (ret == buf && num_bytes_actual == num_bytes_predicted))
return (char *) ret;
/* An error: a bad codepoint. */
diff --git a/test-suite/standalone/test-conversion.c b/test-suite/standalone/test-conversion.c
index 09b74bf17..700e5b3d4 100644
--- a/test-suite/standalone/test-conversion.c
+++ b/test-suite/standalone/test-conversion.c
@@ -1079,6 +1079,74 @@ test_locale_strings ()
}
static void
+test_to_utf8_stringn ()
+{
+ scm_t_wchar wstr[] = { 0x20, /* 0x20 */
+ 0xDF, /* 0xC3, 0x9F */
+ 0x65E5, /* 0xE6, 0x97, 0xA5 */
+ 0x1D400 }; /* 0xF0, 0x9D, 0x90, 0x80 */
+
+ SCM str0 = scm_from_utf32_stringn (wstr, 1); /* ASCII */
+ SCM str1 = scm_from_utf32_stringn (wstr, 2); /* Narrow */
+ SCM str2 = scm_from_utf32_stringn (wstr, 4); /* Wide */
+
+ char cstr0[] = { 0x20, 0 };
+ char cstr1[] = { 0x20, 0xC3, 0x9F, 0 };
+ char cstr2[] = { 0x20, 0xC3, 0x9F, 0xE6, 0x97, 0xA5,
+ 0xF0, 0x9D, 0x90, 0x80, 0 };
+ char *cstr;
+ size_t len;
+
+ /* Test conversion of ASCII string */
+ cstr = scm_to_utf8_stringn (str0, &len);
+ if (len + 1 != sizeof (cstr0) || memcmp (cstr, cstr0, len))
+ {
+ fprintf (stderr, "fail: scm_to_utf8_stringn (<ASCII>, &len)");
+ exit (EXIT_FAILURE);
+ }
+ free (cstr);
+ cstr = scm_to_utf8_stringn (str0, NULL);
+ if (memcmp (cstr, cstr0, len + 1))
+ {
+ fprintf (stderr, "fail: scm_to_utf8_stringn (<ASCII>, NULL)");
+ exit (EXIT_FAILURE);
+ }
+ free (cstr);
+
+ /* Test conversion of narrow string */
+ cstr = scm_to_utf8_stringn (str1, &len);
+ if (len + 1 != sizeof (cstr1) || memcmp (cstr, cstr1, len))
+ {
+ fprintf (stderr, "fail: scm_to_utf8_stringn (<NARROW>, &len)");
+ exit (EXIT_FAILURE);
+ }
+ free (cstr);
+ cstr = scm_to_utf8_stringn (str1, NULL);
+ if (memcmp (cstr, cstr1, len + 1))
+ {
+ fprintf (stderr, "fail: scm_to_utf8_stringn (<NARROW>, NULL)");
+ exit (EXIT_FAILURE);
+ }
+ free (cstr);
+
+ /* Test conversion of wide string */
+ cstr = scm_to_utf8_stringn (str2, &len);
+ if (len + 1 != sizeof (cstr2) || memcmp (cstr, cstr2, len))
+ {
+ fprintf (stderr, "fail: scm_to_utf8_stringn (<WIDE>, &len)");
+ exit (EXIT_FAILURE);
+ }
+ free (cstr);
+ cstr = scm_to_utf8_stringn (str2, NULL);
+ if (memcmp (cstr, cstr2, len + 1))
+ {
+ fprintf (stderr, "fail: scm_to_utf8_stringn (<WIDE>, NULL)");
+ exit (EXIT_FAILURE);
+ }
+ free (cstr);
+}
+
+static void
test_is_exact ()
{
if (1 != scm_is_exact (scm_c_eval_string ("3")))
@@ -1122,6 +1190,7 @@ tests (void *data, int argc, char **argv)
test_from_double ();
test_to_double ();
test_locale_strings ();
+ test_to_utf8_stringn ();
test_is_exact ();
test_is_inexact ();
}