1 /* Recode strings between character sets, using iconv.
2 Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
42 /* Get MB_LEN_MAX, CHAR_BIT. */
47 # define SIZE_MAX ((size_t) -1)
50 /* Convert a zero-terminated string STR from the FROM_CODSET code set
51 to the TO_CODESET code set. The returned string is allocated using
52 malloc, and must be dellocated by the caller using free. On
53 failure, NULL is returned and errno holds the error reason. Note
54 that if TO_CODESET uses \0 for anything but to terminate the
55 string, the caller of this function may have difficulties finding
56 out the length of the output string. */
58 iconv_string (const char *str, const char *from_codeset,
59 const char *to_codeset)
66 if (strcmp (to_codeset, from_codeset) == 0)
70 cd = iconv_open (to_codeset, from_codeset);
71 if (cd == (iconv_t) -1)
74 dest = iconv_alloc (cd, str);
78 int saved_errno = errno;
84 if (iconv_close (cd) < 0)
86 int saved_errno2 = errno;
87 /* If we didn't have a real error before, make sure we restore
88 the iconv_close error below. */
101 /* Convert a zero-terminated string STR using iconv descriptor CD.
102 The returned string is allocated using malloc, and must be
103 dellocated by the caller using free. On failure, NULL is returned
104 and errno holds the error reason. Note that if the target
105 character set uses \0 for anything but to terminate the string,
106 the caller of this function may have difficulties finding
107 out the length of the output string. */
110 iconv_alloc (iconv_t cd, const char *str)
113 char *p = (char *) str;
115 size_t inbytes_remaining = strlen (p);
116 /* Guess the maximum length the output string can have. */
117 size_t outbuf_size = inbytes_remaining + 1;
118 size_t outbytes_remaining;
122 /* Use a worst-case output size guess, so long as that wouldn't be
123 too large for comfort. It's OK if the guess is wrong so long as
125 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
126 if (outbuf_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
127 outbuf_size *= MB_LEN_MAX;
128 outbytes_remaining = outbuf_size - 1;
130 outp = dest = (char *) malloc (outbuf_size);
137 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
138 # if defined _LIBICONV_VERSION \
139 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
140 /* Set to the initial state. */
141 iconv (cd, NULL, NULL, NULL, NULL);
145 err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining);
147 if (err == (size_t) -1)
152 /* Incomplete text, do not report an error */
157 size_t used = outp - dest;
158 size_t newsize = outbuf_size * 2;
161 if (newsize <= outbuf_size)
167 newdest = (char *) realloc (dest, newsize);
175 outbuf_size = newsize;
178 outbytes_remaining = outbuf_size - used - 1; /* -1 for NUL */
193 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
194 /* Irix iconv() inserts a NUL byte if it cannot convert. */
204 err = iconv (cd, NULL, NULL, &outp, &outbytes_remaining);
206 if (err == (size_t) -1)
212 size_t used = outp - dest;
213 size_t newsize = outbuf_size * 2;
216 if (newsize <= outbuf_size)
222 newdest = (char *) realloc (dest, newsize);
230 outbuf_size = newsize;
233 outbytes_remaining = outbuf_size - used - 1; /* -1 for NUL */
244 # if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
245 /* Irix iconv() inserts a NUL byte if it cannot convert. */
256 /* Give away unused memory. */
257 if (outp - dest < outbuf_size)
259 char *newdest = (char *) realloc (dest, outp - dest);
268 int save_errno = errno;