1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
4 Copyright (C) 2001-2007, 2009-2010 Free Software Foundation, Inc.
5 Written by Bruno Haible and Simon Josefsson.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
32 /* Get MB_LEN_MAX, CHAR_BIT. */
36 #include "c-strcase.h"
39 # define SIZE_MAX ((size_t) -1)
46 mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
47 char **resultp, size_t *lengthp)
49 # define tmpbufsize 4096
53 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
54 # if defined _LIBICONV_VERSION \
55 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
56 /* Set to the initial state. */
57 iconv (cd, NULL, NULL, NULL, NULL);
60 /* Determine the length we need. */
63 /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
64 libiconv's UCS-4-INTERNAL encoding. */
65 union { unsigned int align; char buf[tmpbufsize]; } tmp;
66 # define tmpbuf tmp.buf
67 const char *inptr = src;
68 size_t insize = srclen;
72 char *outptr = tmpbuf;
73 size_t outsize = tmpbufsize;
74 size_t res = iconv (cd,
75 (ICONV_CONST char **) &inptr, &insize,
78 if (res == (size_t)(-1))
82 else if (errno == EINVAL)
87 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
88 /* Irix iconv() inserts a NUL byte if it cannot convert.
89 NetBSD iconv() inserts a question mark if it cannot convert.
90 Only GNU libiconv and GNU libc are known to prefer to fail rather
91 than doing a lossy conversion. */
98 count += outptr - tmpbuf;
100 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
101 # if defined _LIBICONV_VERSION \
102 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
104 char *outptr = tmpbuf;
105 size_t outsize = tmpbufsize;
106 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
108 if (res == (size_t)(-1))
110 count += outptr - tmpbuf;
122 if (*resultp != NULL && *lengthp >= length)
126 result = (char *) malloc (length);
134 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
135 # if defined _LIBICONV_VERSION \
136 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
137 /* Return to the initial state. */
138 iconv (cd, NULL, NULL, NULL, NULL);
141 /* Do the conversion for real. */
143 const char *inptr = src;
144 size_t insize = srclen;
145 char *outptr = result;
146 size_t outsize = length;
150 size_t res = iconv (cd,
151 (ICONV_CONST char **) &inptr, &insize,
154 if (res == (size_t)(-1))
161 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
162 /* Irix iconv() inserts a NUL byte if it cannot convert.
163 NetBSD iconv() inserts a question mark if it cannot convert.
164 Only GNU libiconv and GNU libc are known to prefer to fail rather
165 than doing a lossy conversion. */
173 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
174 # if defined _LIBICONV_VERSION \
175 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
177 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
179 if (res == (size_t)(-1))
194 if (result != *resultp)
196 int saved_errno = errno;
206 str_cd_iconv (const char *src, iconv_t cd)
208 /* For most encodings, a trailing NUL byte in the input will be converted
209 to a trailing NUL byte in the output. But not for UTF-7. So that this
210 function is usable for UTF-7, we have to exclude the NUL byte from the
211 conversion and add it by hand afterwards. */
212 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
213 /* Irix iconv() inserts a NUL byte if it cannot convert.
214 NetBSD iconv() inserts a question mark if it cannot convert.
215 Only GNU libiconv and GNU libc are known to prefer to fail rather
216 than doing a lossy conversion. For other iconv() implementations,
217 we have to look at the number of irreversible conversions returned;
218 but this information is lost when iconv() returns for an E2BIG reason.
219 Therefore we cannot use the second, faster algorithm. */
223 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
233 /* Add the terminating NUL byte. */
235 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
236 if (final_result == NULL)
242 final_result[length] = '\0';
247 /* This algorithm is likely faster than the one above. But it may produce
248 iconv() returns for an E2BIG reason, when the output size guess is too
249 small. Therefore it can only be used when we don't need the number of
250 irreversible conversions performed. */
254 const char *inptr = src;
255 size_t inbytes_remaining = strlen (src);
257 /* Make a guess for the worst-case output size, in order to avoid a
258 realloc. It's OK if the guess is wrong as long as it is not zero and
259 doesn't lead to an integer overflow. */
260 result_size = inbytes_remaining;
262 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
263 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
264 result_size *= MB_LEN_MAX;
266 result_size += 1; /* for the terminating NUL */
268 result = (char *) malloc (result_size);
275 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
276 # if defined _LIBICONV_VERSION \
277 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
278 /* Set to the initial state. */
279 iconv (cd, NULL, NULL, NULL, NULL);
282 /* Do the conversion. */
284 char *outptr = result;
285 size_t outbytes_remaining = result_size - 1;
289 /* Here inptr + inbytes_remaining = src + strlen (src),
290 outptr + outbytes_remaining = result + result_size - 1. */
291 size_t res = iconv (cd,
292 (ICONV_CONST char **) &inptr, &inbytes_remaining,
293 &outptr, &outbytes_remaining);
295 if (res == (size_t)(-1))
299 else if (errno == E2BIG)
301 size_t used = outptr - result;
302 size_t newsize = result_size * 2;
305 if (!(newsize > result_size))
310 newresult = (char *) realloc (result, newsize);
311 if (newresult == NULL)
317 result_size = newsize;
318 outptr = result + used;
319 outbytes_remaining = result_size - 1 - used;
327 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
328 # if defined _LIBICONV_VERSION \
329 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
332 /* Here outptr + outbytes_remaining = result + result_size - 1. */
333 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
335 if (res == (size_t)(-1))
339 size_t used = outptr - result;
340 size_t newsize = result_size * 2;
343 if (!(newsize > result_size))
348 newresult = (char *) realloc (result, newsize);
349 if (newresult == NULL)
355 result_size = newsize;
356 outptr = result + used;
357 outbytes_remaining = result_size - 1 - used;
367 /* Add the terminating NUL byte. */
370 length = outptr - result;
373 /* Give away unused memory. */
374 if (length < result_size)
376 char *smaller_result = (char *) realloc (result, length);
378 if (smaller_result != NULL)
379 result = smaller_result;
386 int saved_errno = errno;
398 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
400 if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0)
402 char *result = strdup (src);
414 /* Avoid glibc-2.1 bug with EUC-KR. */
415 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
416 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
417 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
423 cd = iconv_open (to_codeset, from_codeset);
424 if (cd == (iconv_t) -1)
427 result = str_cd_iconv (src, cd);
431 /* Close cd, but preserve the errno from str_cd_iconv. */
432 int saved_errno = errno;
438 if (iconv_close (cd) < 0)
440 /* Return NULL, but free the allocated memory, and while doing
441 that, preserve the errno from iconv_close. */
442 int saved_errno = errno;
450 /* This is a different error code than if iconv_open existed but didn't
451 support from_codeset and to_codeset, so that the caller can emit
452 an error message such as
453 "iconv() is not supported. Installing GNU libiconv and
454 then reinstalling this package would fix this." */