[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[i18n 5/6] i18n: Refactor for simplicity.
From: |
Ben Pfaff |
Subject: |
[i18n 5/6] i18n: Refactor for simplicity. |
Date: |
Mon, 20 Sep 2010 22:50:25 -0700 |
It seems to me that recode_string_pool() is better implemented as a retry
loop around a simpler core. This commit implements that.
---
src/libpspp/i18n.c | 127 ++++++++++++++++++++++------------------------------
1 files changed, 53 insertions(+), 74 deletions(-)
diff --git a/src/libpspp/i18n.c b/src/libpspp/i18n.c
index fa9f29c..d9b42cb 100644
--- a/src/libpspp/i18n.c
+++ b/src/libpspp/i18n.c
@@ -98,6 +98,54 @@ recode_string (const char *to, const char *from,
}
+/* Uses CONV to convert the INBYTES starting at IP into the OUTBYTES starting
+ at OP, and appends a null terminator to the output.
+
+ Returns true if successful, false if the output buffer is too small. */
+static bool
+try_recode (iconv_t conv,
+ const char *ip, size_t inbytes,
+ char *op, size_t outbytes)
+{
+ /* FIXME: Need to ensure that this char is valid in the target encoding */
+ const char fallbackchar = '?';
+
+ /* Put the converter into the initial shift state, in case there was any
+ state information left over from its last usage. */
+ iconv (conv, NULL, 0, NULL, 0);
+
+ while (iconv (conv, (ICONV_CONST char **) &ip, &inbytes,
+ &op, &outbytes) == -1)
+ switch (errno)
+ {
+ case EILSEQ:
+ case EINVAL:
+ if (outbytes == 0)
+ return false;
+
+ *op++ = fallbackchar;
+ outbytes--;
+ ip++;
+ inbytes--;
+ break;
+
+ case E2BIG:
+ return false;
+
+ default:
+ /* should never happen */
+ fprintf (stderr, "Character conversion error: %s\n", strerror (errno));
+ NOT_REACHED ();
+ break;
+ }
+
+ if (outbytes == 0)
+ return false;
+
+ *op = '\0';
+ return true;
+}
+
/* Converts the string TEXT, which should be encoded in FROM-encoding, to a
dynamically allocated string in TO-encoding. Any characters which cannot be
converted will be represented by '?'.
@@ -114,18 +162,9 @@ char *
recode_string_pool (const char *to, const char *from,
const char *text, int length, struct pool *pool)
{
- char *outbuf = 0;
size_t outbufferlength;
- size_t result;
- char *ip;
- char *op ;
- size_t inbytes = 0;
- size_t outbytes ;
iconv_t conv ;
- /* FIXME: Need to ensure that this char is valid in the target encoding */
- const char fallbackchar = '?';
-
if ( text == NULL )
return NULL;
@@ -143,78 +182,18 @@ recode_string_pool (const char *to, const char *from,
if ( (iconv_t) -1 == conv )
return xstrdup (text);
- /* Put the converter into the initial shift state, in case there was any
- state information left over from its last usage. */
- iconv (conv, NULL, 0, NULL, 0);
-
for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
if ( outbufferlength > length)
- break;
-
- ip = text;
-
- outbuf = pool_malloc (pool, outbufferlength);
- op = outbuf;
-
- outbytes = outbufferlength;
- inbytes = length;
-
-
- do {
- result = iconv (conv, (ICONV_CONST char **) &ip, &inbytes,
- &op, &outbytes);
-
- if ( -1 == result )
{
- int the_error = errno;
-
- switch (the_error)
- {
- case EILSEQ:
- case EINVAL:
- if ( outbytes > 0 )
- {
- *op++ = fallbackchar;
- outbytes--;
- text++;
- inbytes--;
- break;
- }
- /* Fall through */
- case E2BIG:
- iconv (conv, NULL, 0, NULL, 0);
- pool_free (pool, outbuf);
- outbufferlength <<= 1;
- outbuf = pool_malloc (pool, outbufferlength);
- op = outbuf;
- outbytes = outbufferlength;
- inbytes = length;
- ip = text;
- break;
- default:
- /* should never happen */
- fprintf (stderr, "Character conversion error: %s\n",
- strerror (the_error));
- NOT_REACHED ();
- break;
- }
+ char *output = pool_malloc (pool, outbufferlength);
+ if (try_recode (conv, text, length, output, outbufferlength))
+ return output;
+ pool_free (pool, output);
}
- } while ( -1 == result );
- if (outbytes == 0 )
- {
- char *const oldaddr = outbuf;
- outbuf = pool_realloc (pool, outbuf, outbufferlength + 1);
-
- op += (outbuf - oldaddr) ;
- }
-
- *op = '\0';
-
- return outbuf;
+ NOT_REACHED ();
}
-
void
i18n_init (void)
{
--
1.7.1
- [i18n 0/6] Fixes for recode_string()., Ben Pfaff, 2010/09/21
- [i18n 3/6] i18n: Ensure that every recoding starts from the initial shift state., Ben Pfaff, 2010/09/21
- [i18n 4/6] i18n: Properly restart conversion when output buffer overflows., Ben Pfaff, 2010/09/21
- [i18n 5/6] i18n: Refactor for simplicity.,
Ben Pfaff <=
- [i18n 1/6] i18n: Lightly reformat comments to better resemble other files., Ben Pfaff, 2010/09/21
- [i18n 6/6] i18n: Handle EINVAL more gracefully., Ben Pfaff, 2010/09/21
- [i18n 2/6] i18n: Avoid memory leak when create_iconv() fails., Ben Pfaff, 2010/09/21
- Re: [i18n 0/6] Fixes for recode_string()., John Darrington, 2010/09/21