1 /* Character set conversion with error handling.
2 Copyright (C) 2001-2008 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "striconveh.h"
33 #include "c-strcase.h"
34 #include "c-strcaseeq.h"
37 # define SIZE_MAX ((size_t) -1)
43 /* The caller must provide CD, CD1, CD2, not just CD, because when a conversion
44 error occurs, we may have to determine the Unicode representation of the
45 inconvertible character. */
47 /* iconv_carefully is like iconv, except that it stops as soon as it encounters
48 a conversion error, and it returns in *INCREMENTED a boolean telling whether
49 it has incremented the input pointers past the error location. */
50 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
51 /* Irix iconv() inserts a NUL byte if it cannot convert.
52 NetBSD iconv() inserts a question mark if it cannot convert.
53 Only GNU libiconv and GNU libc are known to prefer to fail rather
54 than doing a lossy conversion. */
56 iconv_carefully (iconv_t cd
,
57 const char **inbuf
, size_t *inbytesleft
,
58 char **outbuf
, size_t *outbytesleft
,
61 const char *inptr
= *inbuf
;
62 const char *inptr_end
= inptr
+ *inbytesleft
;
63 char *outptr
= *outbuf
;
64 size_t outsize
= *outbytesleft
;
65 const char *inptr_before
;
75 for (insize
= 1; inptr
+ insize
<= inptr_end
; insize
++)
78 (ICONV_CONST
char **) &inptr
, &insize
,
80 if (!(res
== (size_t)(-1) && errno
== EINVAL
))
82 /* iconv can eat up a shift sequence but give EINVAL while attempting
83 to convert the first character. E.g. libiconv does this. */
84 if (inptr
> inptr_before
)
94 *outbytesleft
= outsize
;
97 while (res
== 0 && inptr
< inptr_end
);
100 *inbytesleft
= inptr_end
- inptr
;
101 if (res
!= (size_t)(-1) && res
> 0)
103 /* iconv() has already incremented INPTR. We cannot go back to a
104 previous INPTR, otherwise the state inside CD would become invalid,
105 if FROM_CODESET is a stateful encoding. So, tell the caller that
106 *INBUF has already been incremented. */
107 *incremented
= (inptr
> inptr_before
);
113 *incremented
= false;
118 # define iconv_carefully(cd, inbuf, inbytesleft, outbuf, outbytesleft, incremented) \
119 (*(incremented) = false, \
120 iconv (cd, (ICONV_CONST char **) (inbuf), inbytesleft, outbuf, outbytesleft))
123 /* iconv_carefully_1 is like iconv_carefully, except that it stops after
124 converting one character or one shift sequence. */
126 iconv_carefully_1 (iconv_t cd
,
127 const char **inbuf
, size_t *inbytesleft
,
128 char **outbuf
, size_t *outbytesleft
,
131 const char *inptr_before
= *inbuf
;
132 const char *inptr
= inptr_before
;
133 const char *inptr_end
= inptr_before
+ *inbytesleft
;
134 char *outptr
= *outbuf
;
135 size_t outsize
= *outbytesleft
;
136 size_t res
= (size_t)(-1);
139 for (insize
= 1; inptr_before
+ insize
<= inptr_end
; insize
++)
141 inptr
= inptr_before
;
143 (ICONV_CONST
char **) &inptr
, &insize
,
145 if (!(res
== (size_t)(-1) && errno
== EINVAL
))
147 /* iconv can eat up a shift sequence but give EINVAL while attempting
148 to convert the first character. E.g. libiconv does this. */
149 if (inptr
> inptr_before
)
157 *inbytesleft
= inptr_end
- inptr
;
158 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
159 /* Irix iconv() inserts a NUL byte if it cannot convert.
160 NetBSD iconv() inserts a question mark if it cannot convert.
161 Only GNU libiconv and GNU libc are known to prefer to fail rather
162 than doing a lossy conversion. */
163 if (res
!= (size_t)(-1) && res
> 0)
165 /* iconv() has already incremented INPTR. We cannot go back to a
166 previous INPTR, otherwise the state inside CD would become invalid,
167 if FROM_CODESET is a stateful encoding. So, tell the caller that
168 *INBUF has already been incremented. */
169 *incremented
= (inptr
> inptr_before
);
175 if (res
!= (size_t)(-1))
178 *outbytesleft
= outsize
;
180 *incremented
= false;
184 /* utf8conv_carefully is like iconv, except that
185 - it converts from UTF-8 to UTF-8,
186 - it stops as soon as it encounters a conversion error, and it returns
187 in *INCREMENTED a boolean telling whether it has incremented the input
188 pointers past the error location,
189 - if one_character_only is true, it stops after converting one
192 utf8conv_carefully (bool one_character_only
,
193 const char **inbuf
, size_t *inbytesleft
,
194 char **outbuf
, size_t *outbytesleft
,
197 const char *inptr
= *inbuf
;
198 size_t insize
= *inbytesleft
;
199 char *outptr
= *outbuf
;
200 size_t outsize
= *outbytesleft
;
210 n
= u8_mbtoucr (&uc
, (const uint8_t *) inptr
, insize
);
213 errno
= (n
== -2 ? EINVAL
: EILSEQ
);
214 n
= u8_mbtouc (&uc
, (const uint8_t *) inptr
, insize
);
225 *incremented
= false;
228 m
= u8_uctomb ((uint8_t *) outptr
, uc
, outsize
);
233 *incremented
= false;
248 while (!one_character_only
&& insize
> 0);
251 *inbytesleft
= insize
;
253 *outbytesleft
= outsize
;
258 mem_cd_iconveh_internal (const char *src
, size_t srclen
,
259 iconv_t cd
, iconv_t cd1
, iconv_t cd2
,
260 enum iconv_ilseq_handler handler
,
263 char **resultp
, size_t *lengthp
)
265 /* When a conversion error occurs, we cannot start using CD1 and CD2 at
266 this point: FROM_CODESET may be a stateful encoding like ISO-2022-KR.
267 Instead, we have to start afresh from the beginning of SRC. */
268 /* Use a temporary buffer, so that for small strings, a single malloc()
269 call will be sufficient. */
270 # define tmpbufsize 4096
271 /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
272 libiconv's UCS-4-INTERNAL encoding. */
273 union { unsigned int align
; char buf
[tmpbufsize
]; } tmp
;
274 # define tmpbuf tmp.buf
276 char *initial_result
;
280 size_t last_length
= (size_t)(-1); /* only needed if offsets != NULL */
282 if (*resultp
!= NULL
&& *lengthp
>= sizeof (tmpbuf
))
284 initial_result
= *resultp
;
285 allocated
= *lengthp
;
289 initial_result
= tmpbuf
;
290 allocated
= sizeof (tmpbuf
);
292 result
= initial_result
;
294 /* Test whether a direct conversion is possible at all. */
295 if (cd
== (iconv_t
)(-1))
302 for (i
= 0; i
< srclen
; i
++)
303 offsets
[i
] = (size_t)(-1);
305 last_length
= (size_t)(-1);
309 /* First, try a direct conversion, and see whether a conversion error
312 const char *inptr
= src
;
313 size_t insize
= srclen
;
315 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
316 # if defined _LIBICONV_VERSION \
317 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
318 /* Set to the initial state. */
319 iconv (cd
, NULL
, NULL
, NULL
, NULL
);
324 char *outptr
= result
+ length
;
325 size_t outsize
= allocated
- extra_alloc
- length
;
332 if (length
!= last_length
) /* ensure that offset[] be increasing */
334 offsets
[inptr
- src
] = length
;
335 last_length
= length
;
337 res
= iconv_carefully_1 (cd
,
343 /* Use iconv_carefully instead of iconv here, because:
344 - If TO_CODESET is UTF-8, we can do the error handling in this
345 loop, no need for a second loop,
346 - With iconv() implementations other than GNU libiconv and GNU
347 libc, if we use iconv() in a big swoop, checking for an E2BIG
348 return, we lose the number of irreversible conversions. */
349 res
= iconv_carefully (cd
,
354 length
= outptr
- result
;
355 grow
= (length
+ extra_alloc
> allocated
/ 2);
356 if (res
== (size_t)(-1))
360 else if (errno
== EINVAL
)
362 else if (errno
== EILSEQ
&& handler
!= iconveh_error
)
364 if (cd2
== (iconv_t
)(-1))
366 /* TO_CODESET is UTF-8. */
367 /* Error handling can produce up to 1 byte of output. */
368 if (length
+ 1 + extra_alloc
> allocated
)
372 allocated
= 2 * allocated
;
373 if (length
+ 1 + extra_alloc
> allocated
)
375 if (result
== initial_result
)
376 memory
= (char *) malloc (allocated
);
378 memory
= (char *) realloc (result
, allocated
);
381 if (result
!= initial_result
)
386 if (result
== initial_result
)
387 memcpy (memory
, initial_result
, length
);
391 /* The input is invalid in FROM_CODESET. Eat up one byte
392 and emit a question mark. */
400 result
[length
] = '?';
408 if (result
!= initial_result
)
410 int saved_errno
= errno
;
423 allocated
= 2 * allocated
;
424 if (result
== initial_result
)
425 memory
= (char *) malloc (allocated
);
427 memory
= (char *) realloc (result
, allocated
);
430 if (result
!= initial_result
)
435 if (result
== initial_result
)
436 memcpy (memory
, initial_result
, length
);
442 /* Now get the conversion state back to the initial state.
443 But avoid glibc-2.1 bug and Solaris 2.7 bug. */
444 #if defined _LIBICONV_VERSION \
445 || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
448 char *outptr
= result
+ length
;
449 size_t outsize
= allocated
- extra_alloc
- length
;
452 res
= iconv (cd
, NULL
, NULL
, &outptr
, &outsize
);
453 length
= outptr
- result
;
454 if (res
== (size_t)(-1))
460 allocated
= 2 * allocated
;
461 if (result
== initial_result
)
462 memory
= (char *) malloc (allocated
);
464 memory
= (char *) realloc (result
, allocated
);
467 if (result
!= initial_result
)
472 if (result
== initial_result
)
473 memcpy (memory
, initial_result
, length
);
478 if (result
!= initial_result
)
480 int saved_errno
= errno
;
492 /* The direct conversion succeeded. */
496 /* The direct conversion failed.
497 Use a conversion through UTF-8. */
502 for (i
= 0; i
< srclen
; i
++)
503 offsets
[i
] = (size_t)(-1);
505 last_length
= (size_t)(-1);
509 const bool slowly
= (offsets
!= NULL
|| handler
== iconveh_error
);
510 # define utf8bufsize 4096 /* may also be smaller or larger than tmpbufsize */
511 char utf8buf
[utf8bufsize
+ 1];
513 const char *in1ptr
= src
;
514 size_t in1size
= srclen
;
515 bool do_final_flush1
= true;
516 bool do_final_flush2
= true;
518 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
519 # if defined _LIBICONV_VERSION \
520 || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
521 /* Set to the initial state. */
522 if (cd1
!= (iconv_t
)(-1))
523 iconv (cd1
, NULL
, NULL
, NULL
, NULL
);
524 if (cd2
!= (iconv_t
)(-1))
525 iconv (cd2
, NULL
, NULL
, NULL
, NULL
);
528 while (in1size
> 0 || do_final_flush1
|| utf8len
> 0 || do_final_flush2
)
530 char *out1ptr
= utf8buf
+ utf8len
;
531 size_t out1size
= utf8bufsize
- utf8len
;
536 /* Conversion step 1: from FROM_CODESET to UTF-8. */
540 && length
!= last_length
) /* ensure that offset[] be increasing */
542 offsets
[in1ptr
- src
] = length
;
543 last_length
= length
;
545 if (cd1
!= (iconv_t
)(-1))
548 res1
= iconv_carefully_1 (cd1
,
553 res1
= iconv_carefully (cd1
,
560 /* FROM_CODESET is UTF-8. */
561 res1
= utf8conv_carefully (slowly
,
567 else if (do_final_flush1
)
569 /* Now get the conversion state of CD1 back to the initial state.
570 But avoid glibc-2.1 bug and Solaris 2.7 bug. */
571 # if defined _LIBICONV_VERSION \
572 || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
573 if (cd1
!= (iconv_t
)(-1))
574 res1
= iconv (cd1
, NULL
, NULL
, &out1ptr
, &out1size
);
578 do_final_flush1
= false;
586 if (res1
== (size_t)(-1)
587 && !(errno
== E2BIG
|| errno
== EINVAL
|| errno
== EILSEQ
))
589 if (result
!= initial_result
)
591 int saved_errno
= errno
;
597 if (res1
== (size_t)(-1)
598 && errno
== EILSEQ
&& handler
!= iconveh_error
)
600 /* The input is invalid in FROM_CODESET. Eat up one byte and
601 emit a question mark. Room for the question mark was allocated
602 at the end of utf8buf. */
610 utf8buf
[utf8len
++] = '?';
613 utf8len
= out1ptr
- utf8buf
;
617 || utf8len
> utf8bufsize
/ 2
618 || (res1
== (size_t)(-1) && errno1
== E2BIG
))
620 /* Conversion step 2: from UTF-8 to TO_CODESET. */
621 const char *in2ptr
= utf8buf
;
622 size_t in2size
= utf8len
;
625 || (in1size
== 0 && !do_final_flush1
&& do_final_flush2
))
627 char *out2ptr
= result
+ length
;
628 size_t out2size
= allocated
- extra_alloc
- length
;
635 if (cd2
!= (iconv_t
)(-1))
636 res2
= iconv_carefully (cd2
,
641 /* TO_CODESET is UTF-8. */
642 res2
= utf8conv_carefully (false,
647 else /* in1size == 0 && !do_final_flush1
648 && in2size == 0 && do_final_flush2 */
650 /* Now get the conversion state of CD1 back to the initial
651 state. But avoid glibc-2.1 bug and Solaris 2.7 bug. */
652 # if defined _LIBICONV_VERSION \
653 || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
654 if (cd2
!= (iconv_t
)(-1))
655 res2
= iconv (cd2
, NULL
, NULL
, &out2ptr
, &out2size
);
659 do_final_flush2
= false;
663 length
= out2ptr
- result
;
664 grow
= (length
+ extra_alloc
> allocated
/ 2);
665 if (res2
== (size_t)(-1))
669 else if (errno
== EINVAL
)
671 else if (errno
== EILSEQ
&& handler
!= iconveh_error
)
673 /* Error handling can produce up to 10 bytes of ASCII
674 output. But TO_CODESET may be UCS-2, UTF-16 or
675 UCS-4, so use CD2 here as well. */
685 if (u8_prev (&uc
, (const uint8_t *) in2ptr
,
686 (const uint8_t *) utf8buf
)
695 n
= u8_mbtouc_unsafe (&uc
, (const uint8_t *) in2ptr
,
701 if (handler
== iconveh_escape_sequence
)
703 static char hex
[16] = "0123456789ABCDEF";
705 scratchbuf
[scratchlen
++] = '\\';
707 scratchbuf
[scratchlen
++] = 'u';
710 scratchbuf
[scratchlen
++] = 'U';
711 scratchbuf
[scratchlen
++] = hex
[(uc
>>28) & 15];
712 scratchbuf
[scratchlen
++] = hex
[(uc
>>24) & 15];
713 scratchbuf
[scratchlen
++] = hex
[(uc
>>20) & 15];
714 scratchbuf
[scratchlen
++] = hex
[(uc
>>16) & 15];
716 scratchbuf
[scratchlen
++] = hex
[(uc
>>12) & 15];
717 scratchbuf
[scratchlen
++] = hex
[(uc
>>8) & 15];
718 scratchbuf
[scratchlen
++] = hex
[(uc
>>4) & 15];
719 scratchbuf
[scratchlen
++] = hex
[uc
& 15];
729 if (cd2
!= (iconv_t
)(-1))
731 (ICONV_CONST
char **) &inptr
, &insize
,
732 &out2ptr
, &out2size
);
735 /* TO_CODESET is UTF-8. */
736 if (out2size
>= insize
)
738 memcpy (out2ptr
, inptr
, insize
);
751 length
= out2ptr
- result
;
752 if (res
== (size_t)(-1) && errno
== E2BIG
)
756 allocated
= 2 * allocated
;
757 if (length
+ 1 + extra_alloc
> allocated
)
759 if (result
== initial_result
)
760 memory
= (char *) malloc (allocated
);
762 memory
= (char *) realloc (result
, allocated
);
765 if (result
!= initial_result
)
770 if (result
== initial_result
)
771 memcpy (memory
, initial_result
, length
);
775 out2ptr
= result
+ length
;
776 out2size
= allocated
- extra_alloc
- length
;
777 if (cd2
!= (iconv_t
)(-1))
779 (ICONV_CONST
char **) &inptr
,
781 &out2ptr
, &out2size
);
784 /* TO_CODESET is UTF-8. */
785 if (!(out2size
>= insize
))
787 memcpy (out2ptr
, inptr
, insize
);
794 length
= out2ptr
- result
;
796 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
797 /* Irix iconv() inserts a NUL byte if it cannot convert.
798 NetBSD iconv() inserts a question mark if it cannot
800 Only GNU libiconv and GNU libc are known to prefer
801 to fail rather than doing a lossy conversion. */
802 if (res
!= (size_t)(-1) && res
> 0)
808 if (res
== (size_t)(-1))
810 /* Failure converting the ASCII replacement. */
811 if (result
!= initial_result
)
813 int saved_errno
= errno
;
822 if (result
!= initial_result
)
824 int saved_errno
= errno
;
832 || (in1size
== 0 && !do_final_flush1
&& do_final_flush2
)))
838 allocated
= 2 * allocated
;
839 if (result
== initial_result
)
840 memory
= (char *) malloc (allocated
);
842 memory
= (char *) realloc (result
, allocated
);
845 if (result
!= initial_result
)
850 if (result
== initial_result
)
851 memcpy (memory
, initial_result
, length
);
856 /* Move the remaining bytes to the beginning of utf8buf. */
858 memmove (utf8buf
, in2ptr
, in2size
);
862 if (res1
== (size_t)(-1))
864 if (errno1
== EINVAL
)
866 else if (errno1
== EILSEQ
)
868 if (result
!= initial_result
)
879 /* Now the final memory allocation. */
880 if (result
== tmpbuf
)
882 size_t memsize
= length
+ extra_alloc
;
885 memory
= (char *) malloc (memsize
> 0 ? memsize
: 1);
888 memcpy (memory
, tmpbuf
, length
);
897 else if (result
!= *resultp
&& length
+ extra_alloc
< allocated
)
899 /* Shrink the allocated memory if possible. */
900 size_t memsize
= length
+ extra_alloc
;
903 memory
= (char *) realloc (result
, memsize
> 0 ? memsize
: 1);
915 mem_cd_iconveh (const char *src
, size_t srclen
,
916 iconv_t cd
, iconv_t cd1
, iconv_t cd2
,
917 enum iconv_ilseq_handler handler
,
919 char **resultp
, size_t *lengthp
)
921 return mem_cd_iconveh_internal (src
, srclen
, cd
, cd1
, cd2
, handler
, 0,
922 offsets
, resultp
, lengthp
);
926 str_cd_iconveh (const char *src
,
927 iconv_t cd
, iconv_t cd1
, iconv_t cd2
,
928 enum iconv_ilseq_handler handler
)
930 /* For most encodings, a trailing NUL byte in the input will be converted
931 to a trailing NUL byte in the output. But not for UTF-7. So that this
932 function is usable for UTF-7, we have to exclude the NUL byte from the
933 conversion and add it by hand afterwards. */
936 int retval
= mem_cd_iconveh_internal (src
, strlen (src
),
937 cd
, cd1
, cd2
, handler
, 1, NULL
,
944 int saved_errno
= errno
;
951 /* Add the terminating NUL byte. */
952 result
[length
] = '\0';
960 mem_iconveh (const char *src
, size_t srclen
,
961 const char *from_codeset
, const char *to_codeset
,
962 enum iconv_ilseq_handler handler
,
964 char **resultp
, size_t *lengthp
)
968 /* Nothing to convert. */
972 else if (offsets
== NULL
&& c_strcasecmp (from_codeset
, to_codeset
) == 0)
976 if (*resultp
!= NULL
&& *lengthp
>= srclen
)
980 result
= (char *) malloc (srclen
);
987 memcpy (result
, src
, srclen
);
1002 /* Avoid glibc-2.1 bug with EUC-KR. */
1003 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
1004 if (c_strcasecmp (from_codeset
, "EUC-KR") == 0
1005 || c_strcasecmp (to_codeset
, "EUC-KR") == 0)
1012 cd
= iconv_open (to_codeset
, from_codeset
);
1014 if (STRCASEEQ (from_codeset
, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1015 cd1
= (iconv_t
)(-1);
1018 cd1
= iconv_open ("UTF-8", from_codeset
);
1019 if (cd1
== (iconv_t
)(-1))
1021 int saved_errno
= errno
;
1022 if (cd
!= (iconv_t
)(-1))
1024 errno
= saved_errno
;
1029 if (STRCASEEQ (to_codeset
, "UTF-8", 'U','T','F','-','8',0,0,0,0)
1030 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105
1031 || c_strcasecmp (to_codeset
, "UTF-8//TRANSLIT") == 0
1034 cd2
= (iconv_t
)(-1);
1037 cd2
= iconv_open (to_codeset
, "UTF-8");
1038 if (cd2
== (iconv_t
)(-1))
1040 int saved_errno
= errno
;
1041 if (cd1
!= (iconv_t
)(-1))
1043 if (cd
!= (iconv_t
)(-1))
1045 errno
= saved_errno
;
1052 retval
= mem_cd_iconveh (src
, srclen
, cd
, cd1
, cd2
, handler
, offsets
,
1057 /* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv. */
1058 int saved_errno
= errno
;
1059 if (cd2
!= (iconv_t
)(-1))
1061 if (cd1
!= (iconv_t
)(-1))
1063 if (cd
!= (iconv_t
)(-1))
1065 errno
= saved_errno
;
1069 if (cd2
!= (iconv_t
)(-1) && iconv_close (cd2
) < 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 (cd1
!= (iconv_t
)(-1))
1076 if (cd
!= (iconv_t
)(-1))
1078 if (result
!= *resultp
&& result
!= NULL
)
1080 errno
= saved_errno
;
1083 if (cd1
!= (iconv_t
)(-1) && iconv_close (cd1
) < 0)
1085 /* Return -1, but free the allocated memory, and while doing
1086 that, preserve the errno from iconv_close. */
1087 int saved_errno
= errno
;
1088 if (cd
!= (iconv_t
)(-1))
1090 if (result
!= *resultp
&& result
!= NULL
)
1092 errno
= saved_errno
;
1095 if (cd
!= (iconv_t
)(-1) && iconv_close (cd
) < 0)
1097 /* Return -1, but free the allocated memory, and while doing
1098 that, preserve the errno from iconv_close. */
1099 int saved_errno
= errno
;
1100 if (result
!= *resultp
&& result
!= NULL
)
1102 errno
= saved_errno
;
1110 /* This is a different error code than if iconv_open existed but didn't
1111 support from_codeset and to_codeset, so that the caller can emit
1112 an error message such as
1113 "iconv() is not supported. Installing GNU libiconv and
1114 then reinstalling this package would fix this." */
1122 str_iconveh (const char *src
,
1123 const char *from_codeset
, const char *to_codeset
,
1124 enum iconv_ilseq_handler handler
)
1126 if (*src
== '\0' || c_strcasecmp (from_codeset
, to_codeset
) == 0)
1128 char *result
= strdup (src
);
1142 /* Avoid glibc-2.1 bug with EUC-KR. */
1143 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
1144 if (c_strcasecmp (from_codeset
, "EUC-KR") == 0
1145 || c_strcasecmp (to_codeset
, "EUC-KR") == 0)
1152 cd
= iconv_open (to_codeset
, from_codeset
);
1154 if (STRCASEEQ (from_codeset
, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1155 cd1
= (iconv_t
)(-1);
1158 cd1
= iconv_open ("UTF-8", from_codeset
);
1159 if (cd1
== (iconv_t
)(-1))
1161 int saved_errno
= errno
;
1162 if (cd
!= (iconv_t
)(-1))
1164 errno
= saved_errno
;
1169 if (STRCASEEQ (to_codeset
, "UTF-8", 'U','T','F','-','8',0,0,0,0)
1170 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105
1171 || c_strcasecmp (to_codeset
, "UTF-8//TRANSLIT") == 0
1174 cd2
= (iconv_t
)(-1);
1177 cd2
= iconv_open (to_codeset
, "UTF-8");
1178 if (cd2
== (iconv_t
)(-1))
1180 int saved_errno
= errno
;
1181 if (cd1
!= (iconv_t
)(-1))
1183 if (cd
!= (iconv_t
)(-1))
1185 errno
= saved_errno
;
1190 result
= str_cd_iconveh (src
, cd
, cd1
, cd2
, handler
);
1194 /* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv. */
1195 int saved_errno
= errno
;
1196 if (cd2
!= (iconv_t
)(-1))
1198 if (cd1
!= (iconv_t
)(-1))
1200 if (cd
!= (iconv_t
)(-1))
1202 errno
= saved_errno
;
1206 if (cd2
!= (iconv_t
)(-1) && iconv_close (cd2
) < 0)
1208 /* Return NULL, but free the allocated memory, and while doing
1209 that, preserve the errno from iconv_close. */
1210 int saved_errno
= errno
;
1211 if (cd1
!= (iconv_t
)(-1))
1213 if (cd
!= (iconv_t
)(-1))
1216 errno
= saved_errno
;
1219 if (cd1
!= (iconv_t
)(-1) && iconv_close (cd1
) < 0)
1221 /* Return NULL, but free the allocated memory, and while doing
1222 that, preserve the errno from iconv_close. */
1223 int saved_errno
= errno
;
1224 if (cd
!= (iconv_t
)(-1))
1227 errno
= saved_errno
;
1230 if (cd
!= (iconv_t
)(-1) && iconv_close (cd
) < 0)
1232 /* Return NULL, but free the allocated memory, and while doing
1233 that, preserve the errno from iconv_close. */
1234 int saved_errno
= errno
;
1236 errno
= saved_errno
;
1242 /* This is a different error code than if iconv_open existed but didn't
1243 support from_codeset and to_codeset, so that the caller can emit
1244 an error message such as
1245 "iconv() is not supported. Installing GNU libiconv and
1246 then reinstalling this package would fix this." */