1 /* Recode strings between character sets, using iconv.
2 Copyright (C) 2002, 2003, 2004, 2005 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. */
44 /* Get MB_LEN_MAX, CHAR_BIT. */
49 # define SIZE_MAX ((size_t) -1)
52 /* Convert a zero-terminated string STR from the FROM_CODSET code set
53 to the TO_CODESET code set. The returned string is allocated using
54 malloc, and must be dellocated by the caller using free. On
55 failure, NULL is returned and errno holds the error reason. Note
56 that if TO_CODESET uses \0 for anything but to terminate the
57 string, the caller of this function may have difficulties finding
58 out the length of the output string. */
60 iconv_string (const char *str
, const char *from_codeset
,
61 const char *to_codeset
)
68 if (strcmp (to_codeset
, from_codeset
) == 0)
72 cd
= iconv_open (to_codeset
, from_codeset
);
73 if (cd
== (iconv_t
) -1)
76 dest
= iconv_alloc (cd
, str
);
79 int save_errno
= errno
;
81 if (iconv_close (cd
) < 0 && dest
)
83 int save_errno2
= errno
;
84 /* If we didn't have a real error before, make sure we restore
85 the iconv_close error below. */
100 /* Convert a zero-terminated string STR using iconv descriptor CD.
101 The returned string is allocated using malloc, and must be
102 dellocated by the caller using free. On failure, NULL is returned
103 and errno holds the error reason. Note that if the target
104 character set uses \0 for anything but to terminate the string,
105 the caller of this function may have difficulties finding
106 out the length of the output string. */
109 iconv_alloc (iconv_t cd
, const char *str
)
112 char *p
= (char *) str
;
114 size_t inbytes_remaining
= strlen (p
);
115 /* Guess the maximum length the output string can have. */
116 size_t outbuf_size
= inbytes_remaining
+ 1;
117 size_t outbytes_remaining
;
121 /* Use a worst-case output size guess, so long as that wouldn't be
122 too large for comfort. It's OK if the guess is wrong so long as
124 size_t approx_sqrt_SIZE_MAX
= SIZE_MAX
>> (sizeof (size_t) * CHAR_BIT
/ 2);
125 if (outbuf_size
<= approx_sqrt_SIZE_MAX
/ MB_LEN_MAX
)
126 outbuf_size
*= MB_LEN_MAX
;
127 outbytes_remaining
= outbuf_size
- 1;
129 outp
= dest
= (char *) malloc (outbuf_size
);
134 err
= iconv (cd
, &p
, &inbytes_remaining
, &outp
, &outbytes_remaining
);
136 if (err
== (size_t) -1)
141 /* Incomplete text, do not report an error */
146 size_t used
= outp
- dest
;
147 size_t newsize
= outbuf_size
* 2;
150 if (newsize
<= outbuf_size
)
156 newdest
= (char *) realloc (dest
, newsize
);
163 outbuf_size
= newsize
;
166 outbytes_remaining
= outbuf_size
- used
- 1; /* -1 for NUL */
185 if (have_error
&& dest
)
187 int save_errno
= errno
;