1 /* Character set conversion with error handling.
2 Copyright (C) 2001-2007 Free Software Foundation, Inc.
3 Written by Bruno Haible and Simon Josefsson.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 #include "striconveh.h"
34 #include "c-strcase.h"
35 #include "c-strcaseeq.h"
38 # define SIZE_MAX ((size_t) -1)
44 /* The caller must provide CD, CD1, CD2, not just CD, because when a conversion
45 error occurs, we may have to determine the Unicode representation of the
46 inconvertible character. */
48 /* iconv_carefully is like iconv, except that it stops as soon as it encounters
49 a conversion error, and it returns in *INCREMENTED a boolean telling whether
50 it has incremented the input pointers past the error location. */
51 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
52 /* Irix iconv() inserts a NUL byte if it cannot convert.
53 NetBSD iconv() inserts a question mark if it cannot convert.
54 Only GNU libiconv and GNU libc are known to prefer to fail rather
55 than doing a lossy conversion. */
57 iconv_carefully (iconv_t cd,
58 const char **inbuf, size_t *inbytesleft,
59 char **outbuf, size_t *outbytesleft,
62 const char *inptr = *inbuf;
63 const char *inptr_end = inptr + *inbytesleft;
64 char *outptr = *outbuf;
65 size_t outsize = *outbytesleft;
66 const char *inptr_before;
76 for (insize = 1; inptr + insize <= inptr_end; insize++)
79 (ICONV_CONST char **) &inptr, &insize,
81 if (!(res == (size_t)(-1) && errno == EINVAL))
83 /* We expect that no input bytes have been consumed so far. */
84 if (inptr != inptr_before)
91 *outbytesleft = outsize;
94 while (res == 0 && inptr < inptr_end);
97 *inbytesleft = inptr_end - inptr;
98 if (res != (size_t)(-1) && res > 0)
100 /* iconv() has already incremented INPTR. We cannot go back to a
101 previous INPTR, otherwise the state inside CD would become invalid,
102 if FROM_CODESET is a stateful encoding. So, tell the caller that
103 *INBUF has already been incremented. */
104 *incremented = (inptr > inptr_before);
110 *incremented = false;
115 # define iconv_carefully(cd, inbuf, inbytesleft, outbuf, outbytesleft, incremented) \
116 (*(incremented) = false, \
117 iconv (cd, (ICONV_CONST char **) (inbuf), inbytesleft, outbuf, outbytesleft))
120 /* iconv_carefully_1 is like iconv_carefully, except that it stops after
121 converting one character. */
123 iconv_carefully_1 (iconv_t cd,
124 const char **inbuf, size_t *inbytesleft,
125 char **outbuf, size_t *outbytesleft,
128 const char *inptr = *inbuf;
129 const char *inptr_end = inptr + *inbytesleft;
130 char *outptr = *outbuf;
131 size_t outsize = *outbytesleft;
132 const char *inptr_before = inptr;
133 size_t res = (size_t)(-1);
136 for (insize = 1; inptr + insize <= inptr_end; insize++)
139 (ICONV_CONST char **) &inptr, &insize,
141 if (!(res == (size_t)(-1) && errno == EINVAL))
143 /* We expect that no input bytes have been consumed so far. */
144 if (inptr != inptr_before)
149 *inbytesleft = inptr_end - inptr;
150 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
151 /* Irix iconv() inserts a NUL byte if it cannot convert.
152 NetBSD iconv() inserts a question mark if it cannot convert.
153 Only GNU libiconv and GNU libc are known to prefer to fail rather
154 than doing a lossy conversion. */
155 if (res != (size_t)(-1) && res > 0)
157 /* iconv() has already incremented INPTR. We cannot go back to a
158 previous INPTR, otherwise the state inside CD would become invalid,
159 if FROM_CODESET is a stateful encoding. So, tell the caller that
160 *INBUF has already been incremented. */
161 *incremented = (inptr > inptr_before);
167 if (res != (size_t)(-1))
170 *outbytesleft = outsize;
172 *incremented = false;
176 /* utf8conv_carefully is like iconv, except that
177 - it converts from UTF-8 to UTF-8,
178 - it stops as soon as it encounters a conversion error, and it returns
179 in *INCREMENTED a boolean telling whether it has incremented the input
180 pointers past the error location,
181 - if one_character_only is true, it stops after converting one
184 utf8conv_carefully (bool one_character_only,
185 const char **inbuf, size_t *inbytesleft,
186 char **outbuf, size_t *outbytesleft,
189 const char *inptr = *inbuf;
190 size_t insize = *inbytesleft;
191 char *outptr = *outbuf;
192 size_t outsize = *outbytesleft;
202 n = u8_mbtoucr (&uc, (const uint8_t *) inptr, insize);
205 errno = (n == -2 ? EINVAL : EILSEQ);
206 n = u8_mbtouc (&uc, (const uint8_t *) inptr, insize);
217 *incremented = false;
220 m = u8_uctomb ((uint8_t *) outptr, uc, outsize);
225 *incremented = false;
240 while (!one_character_only && insize > 0);
243 *inbytesleft = insize;
245 *outbytesleft = outsize;
250 mem_cd_iconveh_internal (const char *src, size_t srclen,
251 iconv_t cd, iconv_t cd1, iconv_t cd2,
252 enum iconv_ilseq_handler handler,
255 char **resultp, size_t *lengthp)
257 /* When a conversion error occurs, we cannot start using CD1 and CD2 at
258 this point: FROM_CODESET may be a stateful encoding like ISO-2022-KR.
259 Instead, we have to start afresh from the beginning of SRC. */
260 /* Use a temporary buffer, so that for small strings, a single malloc()
261 call will be sufficient. */
262 # define tmpbufsize 4096
263 /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
264 libiconv's UCS-4-INTERNAL encoding. */
265 union { unsigned int align; char buf[tmpbufsize]; } tmp;
266 # define tmpbuf tmp.buf
268 char *initial_result;
272 size_t last_length = (size_t)(-1); /* only needed if offsets != NULL */
274 if (*resultp != NULL && *lengthp >= sizeof (tmpbuf))
276 initial_result = *resultp;
277 allocated = *lengthp;
281 initial_result = tmpbuf;
282 allocated = sizeof (tmpbuf);
284 result = initial_result;
286 /* Test whether a direct conversion is possible at all. */
287 if (cd == (iconv_t)(-1))
294 for (i = 0; i < srclen; i++)
295 offsets[i] = (size_t)(-1);
297 last_length = (size_t)(-1);
301 /* First, try a direct conversion, and see whether a conversion error
304 const char *inptr = src;
305 size_t insize = srclen;
307 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
308 # if defined _LIBICONV_VERSION \
309 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
310 /* Set to the initial state. */
311 iconv (cd, NULL, NULL, NULL, NULL);
316 char *outptr = result + length;
317 size_t outsize = allocated - extra_alloc - length;
324 if (length != last_length) /* ensure that offset[] be increasing */
326 offsets[inptr - src] = length;
327 last_length = length;
329 res = iconv_carefully_1 (cd,
335 /* Use iconv_carefully instead of iconv here, because:
336 - If TO_CODESET is UTF-8, we can do the error handling in this
337 loop, no need for a second loop,
338 - With iconv() implementations other than GNU libiconv and GNU
339 libc, if we use iconv() in a big swoop, checking for an E2BIG
340 return, we lose the number of irreversible conversions. */
341 res = iconv_carefully (cd,
346 length = outptr - result;
347 grow = (length + extra_alloc > allocated / 2);
348 if (res == (size_t)(-1))
352 else if (errno == EINVAL)
354 else if (errno == EILSEQ && handler != iconveh_error)
356 if (cd2 == (iconv_t)(-1))
358 /* TO_CODESET is UTF-8. */
359 /* Error handling can produce up to 1 byte of output. */
360 if (length + 1 + extra_alloc > allocated)
364 allocated = 2 * allocated;
365 if (length + 1 + extra_alloc > allocated)
367 if (result == initial_result)
368 memory = (char *) malloc (allocated);
370 memory = (char *) realloc (result, allocated);
373 if (result != initial_result)
378 if (result == initial_result)
379 memcpy (memory, initial_result, length);
383 /* The input is invalid in FROM_CODESET. Eat up one byte
384 and emit a question mark. */
392 result[length] = '?';
400 if (result != initial_result)
402 int saved_errno = errno;
415 allocated = 2 * allocated;
416 if (result == initial_result)
417 memory = (char *) malloc (allocated);
419 memory = (char *) realloc (result, allocated);
422 if (result != initial_result)
427 if (result == initial_result)
428 memcpy (memory, initial_result, length);
434 /* Now get the conversion state back to the initial state.
435 But avoid glibc-2.1 bug and Solaris 2.7 bug. */
436 #if defined _LIBICONV_VERSION \
437 || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
440 char *outptr = result + length;
441 size_t outsize = allocated - extra_alloc - length;
444 res = iconv (cd, NULL, NULL, &outptr, &outsize);
445 length = outptr - result;
446 if (res == (size_t)(-1))
452 allocated = 2 * allocated;
453 if (result == initial_result)
454 memory = (char *) malloc (allocated);
456 memory = (char *) realloc (result, allocated);
459 if (result != initial_result)
464 if (result == initial_result)
465 memcpy (memory, initial_result, length);
470 if (result != initial_result)
472 int saved_errno = errno;
484 /* The direct conversion succeeded. */
488 /* The direct conversion failed.
489 Use a conversion through UTF-8. */
494 for (i = 0; i < srclen; i++)
495 offsets[i] = (size_t)(-1);
497 last_length = (size_t)(-1);
501 const bool slowly = (offsets != NULL || handler == iconveh_error);
502 # define utf8bufsize 4096 /* may also be smaller or larger than tmpbufsize */
503 char utf8buf[utf8bufsize + 1];
505 const char *in1ptr = src;
506 size_t in1size = srclen;
507 bool do_final_flush1 = true;
508 bool do_final_flush2 = true;
510 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
511 # if defined _LIBICONV_VERSION \
512 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
513 /* Set to the initial state. */
514 if (cd1 != (iconv_t)(-1))
515 iconv (cd1, NULL, NULL, NULL, NULL);
516 if (cd2 != (iconv_t)(-1))
517 iconv (cd2, NULL, NULL, NULL, NULL);
520 while (in1size > 0 || do_final_flush1 || utf8len > 0 || do_final_flush2)
522 char *out1ptr = utf8buf + utf8len;
523 size_t out1size = utf8bufsize - utf8len;
528 /* Conversion step 1: from FROM_CODESET to UTF-8. */
532 && length != last_length) /* ensure that offset[] be increasing */
534 offsets[in1ptr - src] = length;
535 last_length = length;
537 if (cd1 != (iconv_t)(-1))
540 res1 = iconv_carefully_1 (cd1,
545 res1 = iconv_carefully (cd1,
552 /* FROM_CODESET is UTF-8. */
553 res1 = utf8conv_carefully (slowly,
559 else if (do_final_flush1)
561 /* Now get the conversion state of CD1 back to the initial state.
562 But avoid glibc-2.1 bug and Solaris 2.7 bug. */
563 # if defined _LIBICONV_VERSION \
564 || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
565 if (cd1 != (iconv_t)(-1))
566 res1 = iconv (cd1, NULL, NULL, &out1ptr, &out1size);
570 do_final_flush1 = false;
578 if (res1 == (size_t)(-1)
579 && !(errno == E2BIG || errno == EINVAL || errno == EILSEQ))
581 if (result != initial_result)
583 int saved_errno = errno;
589 if (res1 == (size_t)(-1)
590 && errno == EILSEQ && handler != iconveh_error)
592 /* The input is invalid in FROM_CODESET. Eat up one byte and
593 emit a question mark. Room for the question mark was allocated
594 at the end of utf8buf. */
602 utf8buf[utf8len++] = '?';
605 utf8len = out1ptr - utf8buf;
609 || utf8len > utf8bufsize / 2
610 || (res1 == (size_t)(-1) && errno1 == E2BIG))
612 /* Conversion step 2: from UTF-8 to TO_CODESET. */
613 const char *in2ptr = utf8buf;
614 size_t in2size = utf8len;
617 || (in1size == 0 && !do_final_flush1 && do_final_flush2))
619 char *out2ptr = result + length;
620 size_t out2size = allocated - extra_alloc - length;
627 if (cd2 != (iconv_t)(-1))
628 res2 = iconv_carefully (cd2,
633 /* TO_CODESET is UTF-8. */
634 res2 = utf8conv_carefully (false,
639 else /* in1size == 0 && !do_final_flush1
640 && in2size == 0 && do_final_flush2 */
642 /* Now get the conversion state of CD1 back to the initial
643 state. But avoid glibc-2.1 bug and Solaris 2.7 bug. */
644 # if defined _LIBICONV_VERSION \
645 || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
646 if (cd2 != (iconv_t)(-1))
647 res2 = iconv (cd2, NULL, NULL, &out2ptr, &out2size);
651 do_final_flush2 = false;
655 length = out2ptr - result;
656 grow = (length + extra_alloc > allocated / 2);
657 if (res2 == (size_t)(-1))
661 else if (errno == EINVAL)
663 else if (errno == EILSEQ && handler != iconveh_error)
665 /* Error handling can produce up to 10 bytes of ASCII
666 output. But TO_CODESET may be UCS-2, UTF-16 or
667 UCS-4, so use CD2 here as well. */
677 if (u8_prev (&uc, (const uint8_t *) in2ptr,
678 (const uint8_t *) utf8buf)
687 n = u8_mbtouc_unsafe (&uc, (const uint8_t *) in2ptr,
693 if (handler == iconveh_escape_sequence)
695 static char hex[16] = "0123456789ABCDEF";
697 scratchbuf[scratchlen++] = '\\';
699 scratchbuf[scratchlen++] = 'u';
702 scratchbuf[scratchlen++] = 'U';
703 scratchbuf[scratchlen++] = hex[(uc>>28) & 15];
704 scratchbuf[scratchlen++] = hex[(uc>>24) & 15];
705 scratchbuf[scratchlen++] = hex[(uc>>20) & 15];
706 scratchbuf[scratchlen++] = hex[(uc>>16) & 15];
708 scratchbuf[scratchlen++] = hex[(uc>>12) & 15];
709 scratchbuf[scratchlen++] = hex[(uc>>8) & 15];
710 scratchbuf[scratchlen++] = hex[(uc>>4) & 15];
711 scratchbuf[scratchlen++] = hex[uc & 15];
721 if (cd2 != (iconv_t)(-1))
723 (ICONV_CONST char **) &inptr, &insize,
724 &out2ptr, &out2size);
727 /* TO_CODESET is UTF-8. */
728 if (out2size >= insize)
730 memcpy (out2ptr, inptr, insize);
743 length = out2ptr - result;
744 if (res == (size_t)(-1) && errno == E2BIG)
748 allocated = 2 * allocated;
749 if (length + 1 + extra_alloc > allocated)
751 if (result == initial_result)
752 memory = (char *) malloc (allocated);
754 memory = (char *) realloc (result, allocated);
757 if (result != initial_result)
762 if (result == initial_result)
763 memcpy (memory, initial_result, length);
767 out2ptr = result + length;
768 out2size = allocated - extra_alloc - length;
769 if (cd2 != (iconv_t)(-1))
771 (ICONV_CONST char **) &inptr,
773 &out2ptr, &out2size);
776 /* TO_CODESET is UTF-8. */
777 if (!(out2size >= insize))
779 memcpy (out2ptr, inptr, insize);
786 length = out2ptr - result;
788 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
789 /* Irix iconv() inserts a NUL byte if it cannot convert.
790 NetBSD iconv() inserts a question mark if it cannot
792 Only GNU libiconv and GNU libc are known to prefer
793 to fail rather than doing a lossy conversion. */
794 if (res != (size_t)(-1) && res > 0)
800 if (res == (size_t)(-1))
802 /* Failure converting the ASCII replacement. */
803 if (result != initial_result)
805 int saved_errno = errno;
814 if (result != initial_result)
816 int saved_errno = errno;
824 || (in1size == 0 && !do_final_flush1 && do_final_flush2)))
830 allocated = 2 * allocated;
831 if (result == initial_result)
832 memory = (char *) malloc (allocated);
834 memory = (char *) realloc (result, allocated);
837 if (result != initial_result)
842 if (result == initial_result)
843 memcpy (memory, initial_result, length);
848 /* Move the remaining bytes to the beginning of utf8buf. */
850 memmove (utf8buf, in2ptr, in2size);
854 if (res1 == (size_t)(-1))
856 if (errno1 == EINVAL)
858 else if (errno1 == EILSEQ)
860 if (result != initial_result)
871 /* Now the final memory allocation. */
872 if (result == tmpbuf)
876 memory = (char *) malloc (length + extra_alloc);
879 memcpy (memory, tmpbuf, length);
888 else if (result != *resultp && length + extra_alloc < allocated)
890 /* Shrink the allocated memory if possible. */
893 memory = (char *) realloc (result, length + extra_alloc);
905 mem_cd_iconveh (const char *src, size_t srclen,
906 iconv_t cd, iconv_t cd1, iconv_t cd2,
907 enum iconv_ilseq_handler handler,
909 char **resultp, size_t *lengthp)
911 return mem_cd_iconveh_internal (src, srclen, cd, cd1, cd2, handler, 0,
912 offsets, resultp, lengthp);
916 str_cd_iconveh (const char *src,
917 iconv_t cd, iconv_t cd1, iconv_t cd2,
918 enum iconv_ilseq_handler handler)
920 /* For most encodings, a trailing NUL byte in the input will be converted
921 to a trailing NUL byte in the output. But not for UTF-7. So that this
922 function is usable for UTF-7, we have to exclude the NUL byte from the
923 conversion and add it by hand afterwards. */
926 int retval = mem_cd_iconveh_internal (src, strlen (src),
927 cd, cd1, cd2, handler, 1, NULL,
934 int saved_errno = errno;
941 /* Add the terminating NUL byte. */
942 result[length] = '\0';
950 mem_iconveh (const char *src, size_t srclen,
951 const char *from_codeset, const char *to_codeset,
952 enum iconv_ilseq_handler handler,
954 char **resultp, size_t *lengthp)
958 /* Nothing to convert. */
962 else if (offsets == NULL && c_strcasecmp (from_codeset, to_codeset) == 0)
966 if (*resultp != NULL && *lengthp >= srclen)
970 result = (char *) malloc (srclen);
977 memcpy (result, src, srclen);
992 /* Avoid glibc-2.1 bug with EUC-KR. */
993 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
994 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
995 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
1002 cd = iconv_open (to_codeset, from_codeset);
1004 if (STRCASEEQ (from_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1005 cd1 = (iconv_t)(-1);
1008 cd1 = iconv_open ("UTF-8", from_codeset);
1009 if (cd1 == (iconv_t)(-1))
1011 int saved_errno = errno;
1012 if (cd != (iconv_t)(-1))
1014 errno = saved_errno;
1019 if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1020 cd2 = (iconv_t)(-1);
1023 cd2 = iconv_open (to_codeset, "UTF-8");
1024 if (cd2 == (iconv_t)(-1))
1026 int saved_errno = errno;
1027 if (cd1 != (iconv_t)(-1))
1029 if (cd != (iconv_t)(-1))
1031 errno = saved_errno;
1038 retval = mem_cd_iconveh (src, srclen, cd, cd1, cd2, handler, offsets,
1043 /* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv. */
1044 int saved_errno = errno;
1045 if (cd2 != (iconv_t)(-1))
1047 if (cd1 != (iconv_t)(-1))
1049 if (cd != (iconv_t)(-1))
1051 errno = saved_errno;
1055 if (cd2 != (iconv_t)(-1) && iconv_close (cd2) < 0)
1057 /* Return -1, but free the allocated memory, and while doing
1058 that, preserve the errno from iconv_close. */
1059 int saved_errno = errno;
1060 if (cd1 != (iconv_t)(-1))
1062 if (cd != (iconv_t)(-1))
1064 if (result != *resultp && result != NULL)
1066 errno = saved_errno;
1069 if (cd1 != (iconv_t)(-1) && iconv_close (cd1) < 0)
1071 /* Return -1, but free the allocated memory, and while doing
1072 that, preserve the errno from iconv_close. */
1073 int saved_errno = errno;
1074 if (cd != (iconv_t)(-1))
1076 if (result != *resultp && result != NULL)
1078 errno = saved_errno;
1081 if (cd != (iconv_t)(-1) && iconv_close (cd) < 0)
1083 /* Return -1, but free the allocated memory, and while doing
1084 that, preserve the errno from iconv_close. */
1085 int saved_errno = errno;
1086 if (result != *resultp && result != NULL)
1088 errno = saved_errno;
1096 /* This is a different error code than if iconv_open existed but didn't
1097 support from_codeset and to_codeset, so that the caller can emit
1098 an error message such as
1099 "iconv() is not supported. Installing GNU libiconv and
1100 then reinstalling this package would fix this." */
1108 str_iconveh (const char *src,
1109 const char *from_codeset, const char *to_codeset,
1110 enum iconv_ilseq_handler handler)
1112 if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0)
1114 char *result = strdup (src);
1128 /* Avoid glibc-2.1 bug with EUC-KR. */
1129 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
1130 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
1131 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
1138 cd = iconv_open (to_codeset, from_codeset);
1140 if (STRCASEEQ (from_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1141 cd1 = (iconv_t)(-1);
1144 cd1 = iconv_open ("UTF-8", from_codeset);
1145 if (cd1 == (iconv_t)(-1))
1147 int saved_errno = errno;
1148 if (cd != (iconv_t)(-1))
1150 errno = saved_errno;
1155 if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1156 cd2 = (iconv_t)(-1);
1159 cd2 = iconv_open (to_codeset, "UTF-8");
1160 if (cd2 == (iconv_t)(-1))
1162 int saved_errno = errno;
1163 if (cd1 != (iconv_t)(-1))
1165 if (cd != (iconv_t)(-1))
1167 errno = saved_errno;
1172 result = str_cd_iconveh (src, cd, cd1, cd2, handler);
1176 /* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv. */
1177 int saved_errno = errno;
1178 if (cd2 != (iconv_t)(-1))
1180 if (cd1 != (iconv_t)(-1))
1182 if (cd != (iconv_t)(-1))
1184 errno = saved_errno;
1188 if (cd2 != (iconv_t)(-1) && iconv_close (cd2) < 0)
1190 /* Return NULL, but free the allocated memory, and while doing
1191 that, preserve the errno from iconv_close. */
1192 int saved_errno = errno;
1193 if (cd1 != (iconv_t)(-1))
1195 if (cd != (iconv_t)(-1))
1198 errno = saved_errno;
1201 if (cd1 != (iconv_t)(-1) && iconv_close (cd1) < 0)
1203 /* Return NULL, but free the allocated memory, and while doing
1204 that, preserve the errno from iconv_close. */
1205 int saved_errno = errno;
1206 if (cd != (iconv_t)(-1))
1209 errno = saved_errno;
1212 if (cd != (iconv_t)(-1) && iconv_close (cd) < 0)
1214 /* Return NULL, but free the allocated memory, and while doing
1215 that, preserve the errno from iconv_close. */
1216 int saved_errno = errno;
1218 errno = saved_errno;
1224 /* This is a different error code than if iconv_open existed but didn't
1225 support from_codeset and to_codeset, so that the caller can emit
1226 an error message such as
1227 "iconv() is not supported. Installing GNU libiconv and
1228 then reinstalling this package would fix this." */