2 /* Copyright (C) 2002, 2003, 2004 Manuel Novoa III
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
21 * Besides uClibc, I'm using this code in my libc for elks, which is
22 * a 16-bit environment with a fairly limited compiler. It would make
23 * things much easier for me if this file isn't modified unnecessarily.
24 * In particular, please put any new or replacement functions somewhere
25 * else, and modify the makefile to use your version instead.
28 * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
31 /* May 23, 2002 Initial Notes:
33 * I'm still tweaking this stuff, but it passes the tests I've thrown
34 * at it, and Erik needs it for the gcc port. The glibc extension
35 * __wcsnrtombs() hasn't been tested, as I didn't find a test for it
36 * in the glibc source. I also need to fix the behavior of
37 * _wchar_utf8sntowcs() if the max number of wchars to convert is 0.
39 * UTF-8 -> wchar -> UTF-8 conversion tests on Markus Kuhn's UTF-8-demo.txt
40 * file on my platform (x86) show about 5-10% faster conversion speed than
41 * glibc with mbsrtowcs()/wcsrtombs() and almost twice as fast as glibc with
42 * individual mbrtowc()/wcrtomb() calls.
44 * If 'DECODER' is defined, then _wchar_utf8sntowcs() will be compiled
45 * as a fail-safe UTF-8 decoder appropriate for a terminal, etc. which
46 * needs to deal gracefully with whatever is sent to it. In that mode,
47 * it passes Markus Kuhn's UTF-8-test.txt stress test. I plan to add
48 * an arg to force that behavior, so the interface will be changing.
50 * I need to fix the error checking for 16-bit wide chars. This isn't
51 * an issue for uClibc, but may be for ELKS. I'm currently not sure
52 * if I'll use 16-bit, 32-bit, or configureable wchars in ELKS.
56 * Fixed _wchar_utf8sntowcs() for the max number of wchars == 0 case.
57 * Fixed nul-char bug in btowc(), and another in __mbsnrtowcs() for 8-bit
59 * Enabled building of a C/POSIX-locale-only version, so full locale support
60 * no longer needs to be enabled.
64 * Fixed a bug in _wchar_wcsntoutf8s(). Don't store wcs position if dst is NULL.
65 * Also, introduce an awful hack into _wchar_wcsntoutf8s() and wcsrtombs() in
66 * order to support %ls in printf. See comments below for details.
67 * Change behaviour of wc<->mb functions when in the C locale. Now they do
68 * a 1-1 map for the range 0x80-UCHAR_MAX. This is for backwards compatibility
69 * and consistency with the stds requirements that a printf format string by
70 * a valid multibyte string beginning and ending in it's initial shift state.
74 * Forgot to change btowc and wctob when I changed the wc<->mb functions yesterday.
78 * Add wcwidth and wcswidth, based on Markus Kuhn's wcwidth of 2002-05-08.
79 * Added some size/speed optimizations and integrated it into my locale
80 * framework. Minimally tested at the moment, but the stub C-locale
81 * version (which most people would probably be using) should be fine.
85 * Revert the wc<->mb changes from earlier this month involving the C-locale.
86 * Add a couple of ugly hacks to support *wprintf.
87 * Add a mini iconv() and iconv implementation (requires locale support).
90 * Bug fix for mbrtowc.
93 * Bug fix: _wchar_utf8sntowcs and _wchar_wcsntoutf8s now set errno if EILSEQ.
96 * Bug fix: Fix size check for remaining output space in iconv().
102 #define _ISOC99_SOURCE
107 #include <inttypes.h>
113 #include <bits/uClibc_uwchar.h>
115 /**********************************************************************/
116 #ifdef __UCLIBC_HAS_LOCALE__
117 #ifdef __UCLIBC_MJN3_ONLY__
119 /* generates one warning */
120 #warning TODO: Fix Cc2wc* and Cwc2c* defines!
122 #endif /* __UCLIBC_MJN3_ONLY__ */
124 #define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding)
126 #define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
127 #define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
128 #define Cwc2c_DOMAIN_MAX __LOCALE_DATA_Cwc2c_DOMAIN_MAX
129 #define Cwc2c_TI_SHIFT __LOCALE_DATA_Cwc2c_TI_SHIFT
130 #define Cwc2c_TT_SHIFT __LOCALE_DATA_Cwc2c_TT_SHIFT
131 #define Cwc2c_TI_LEN __LOCALE_DATA_Cwc2c_TI_LEN
133 #ifndef __CTYPE_HAS_UTF_8_LOCALES
134 #warning __CTYPE_HAS_UTF_8_LOCALES not set!
137 #else /* __UCLIBC_HAS_LOCALE__ */
139 #ifdef __UCLIBC_MJN3_ONLY__
142 #warning fix preprocessor logic testing locale settings
146 #define ENCODING (__ctype_encoding_7_bit)
147 #ifdef __CTYPE_HAS_8_BIT_LOCALES
148 #error __CTYPE_HAS_8_BIT_LOCALES is defined!
150 #ifdef __CTYPE_HAS_UTF_8_LOCALES
151 #error __CTYPE_HAS_UTF_8_LOCALES is defined!
153 #undef L__wchar_utf8sntowcs
154 #undef L__wchar_wcsntoutf8s
156 #endif /* __UCLIBC_HAS_LOCALE__ */
157 /**********************************************************************/
159 #if WCHAR_MAX > 0xffffUL
160 #define UTF_8_MAX_LEN 6
162 #define UTF_8_MAX_LEN 3
167 /* Implementation-specific work functions. */
169 extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
170 const char **__restrict src, size_t n,
171 mbstate_t *ps, int allow_continuation) attribute_hidden;
173 extern size_t _wchar_wcsntoutf8s(char *__restrict s, size_t n,
174 const wchar_t **__restrict src, size_t wn) attribute_hidden;
176 /**********************************************************************/
179 libc_hidden_proto(mbrtowc)
183 #ifdef __CTYPE_HAS_8_BIT_LOCALES
186 unsigned char buf[1];
190 *buf = (unsigned char) c;
191 mbstate.__mask = 0; /* Initialize the mbstate. */
192 if (mbrtowc(&wc, buf, 1, &mbstate) <= 1) {
198 #else /* __CTYPE_HAS_8_BIT_LOCALES */
200 #ifdef __UCLIBC_HAS_LOCALE__
201 assert((ENCODING == __ctype_encoding_7_bit)
202 || (ENCODING == __ctype_encoding_utf8));
203 #endif /* __UCLIBC_HAS_LOCALE__ */
205 /* If we don't have 8-bit locale support, then this is trivial since
206 * anything outside of 0-0x7f is illegal in C/POSIX and UTF-8 locales. */
207 return (((unsigned int)c) < 0x80) ? c : WEOF;
209 #endif /* __CTYPE_HAS_8_BIT_LOCALES */
211 libc_hidden_proto(btowc)
212 libc_hidden_def(btowc)
215 /**********************************************************************/
218 /* Note: We completely ignore ps in all currently supported conversions. */
220 libc_hidden_proto(wcrtomb)
224 #ifdef __CTYPE_HAS_8_BIT_LOCALES
226 unsigned char buf[MB_LEN_MAX];
228 return (wcrtomb(buf, c, NULL) == 1) ? *buf : EOF;
230 #else /* __CTYPE_HAS_8_BIT_LOCALES */
232 #ifdef __UCLIBC_HAS_LOCALE__
233 assert((ENCODING == __ctype_encoding_7_bit)
234 || (ENCODING == __ctype_encoding_utf8));
235 #endif /* __UCLIBC_HAS_LOCALE__ */
237 /* If we don't have 8-bit locale support, then this is trivial since
238 * anything outside of 0-0x7f is illegal in C/POSIX and UTF-8 locales. */
240 /* TODO: need unsigned version of wint_t... */
241 /* return (((unsigned int)c) < 0x80) ? c : WEOF; */
242 return ((c >= 0) && (c < 0x80)) ? c : EOF;
244 #endif /* __CTYPE_HAS_8_BIT_LOCALES */
248 /**********************************************************************/
251 int mbsinit(const mbstate_t *ps)
253 return !ps || !ps->__mask;
255 libc_hidden_proto(mbsinit)
256 libc_hidden_def(mbsinit)
259 /**********************************************************************/
262 libc_hidden_proto(mbrtowc)
264 size_t mbrlen(const char *__restrict s, size_t n, mbstate_t *__restrict ps)
266 static mbstate_t mbstate; /* Rely on bss 0-init. */
268 return mbrtowc(NULL, s, n, (ps != NULL) ? ps : &mbstate);
270 libc_hidden_proto(mbrlen)
271 libc_hidden_def(mbrlen)
274 /**********************************************************************/
277 libc_hidden_proto(mbsnrtowcs)
279 size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
280 size_t n, mbstate_t *__restrict ps)
282 static mbstate_t mbstate; /* Rely on bss 0-init. */
286 char empty_string[1]; /* Avoid static to be fPIC friendly. */
293 pwc = (wchar_t *) s; /* NULL */
294 empty_string[0] = 0; /* Init the empty string when necessary. */
298 /* TODO: change error code? */
299 return (ps->__mask && (ps->__wc == 0xffffU))
300 ? ((size_t) -1) : ((size_t) -2);
305 #ifdef __CTYPE_HAS_UTF_8_LOCALES
306 /* Need to do this here since mbsrtowcs doesn't allow incompletes. */
307 if (ENCODING == __ctype_encoding_utf8) {
311 r = _wchar_utf8sntowcs(pwc, 1, &p, n, ps, 1);
312 return (r == 1) ? (p-s) : r; /* Need to return 0 if nul char. */
316 #ifdef __UCLIBC_MJN3_ONLY__
317 #warning TODO: This adds a trailing nul!
318 #endif /* __UCLIBC_MJN3_ONLY__ */
320 r = mbsnrtowcs(wcbuf, &p, SIZE_MAX, 1, ps);
322 if (((ssize_t) r) >= 0) {
329 libc_hidden_proto(mbrtowc)
330 libc_hidden_def(mbrtowc)
333 /**********************************************************************/
336 libc_hidden_proto(wcsnrtombs)
338 /* Note: We completely ignore ps in all currently supported conversions. */
339 /* TODO: Check for valid state anyway? */
341 size_t wcrtomb(register char *__restrict s, wchar_t wc,
342 mbstate_t *__restrict ps)
344 #ifdef __UCLIBC_MJN3_ONLY__
345 #warning TODO: Should wcsnrtombs nul-terminate unconditionally? Check glibc.
346 #endif /* __UCLIBC_MJN3_ONLY__ */
350 char buf[MB_LEN_MAX];
360 r = wcsnrtombs(s, &pwc, 1, MB_LEN_MAX, ps);
361 return (r != 0) ? r : 1;
363 libc_hidden_proto(wcrtomb)
364 libc_hidden_def(wcrtomb)
367 /**********************************************************************/
370 libc_hidden_proto(mbsnrtowcs)
372 size_t mbsrtowcs(wchar_t *__restrict dst, const char **__restrict src,
373 size_t len, mbstate_t *__restrict ps)
375 static mbstate_t mbstate; /* Rely on bss 0-init. */
377 return mbsnrtowcs(dst, src, SIZE_MAX, len,
378 ((ps != NULL) ? ps : &mbstate));
380 libc_hidden_proto(mbsrtowcs)
381 libc_hidden_def(mbsrtowcs)
384 /**********************************************************************/
387 /* Note: We completely ignore ps in all currently supported conversions.
389 * TODO: Check for valid state anyway? */
391 libc_hidden_proto(wcsnrtombs)
393 size_t wcsrtombs(char *__restrict dst, const wchar_t **__restrict src,
394 size_t len, mbstate_t *__restrict ps)
396 return wcsnrtombs(dst, src, SIZE_MAX, len, ps);
398 libc_hidden_proto(wcsrtombs)
399 libc_hidden_def(wcsrtombs)
402 /**********************************************************************/
403 #ifdef L__wchar_utf8sntowcs
405 /* Define DECODER to generate a UTF-8 decoder which passes Markus Kuhn's
406 * UTF-8-test.txt strss test.
408 /* #define DECODER */
416 size_t attribute_hidden _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
417 const char **__restrict src, size_t n,
418 mbstate_t *ps, int allow_continuation)
420 register const char *s;
433 /* NOTE: The following is an AWFUL HACK! In order to support %s in
434 * wprintf, we need to be able to compute the number of wchars needed
435 * for the mbs conversion, not to exceed the precision specified.
436 * But if dst is NULL, the return value is the length assuming a
437 * sufficiently sized buffer. So, we allow passing of (wchar_t *) ps
438 * as pwc in order to flag that we really want the length, subject
439 * to the restricted buffer size and no partial conversions.
440 * See mbsnrtowcs() as well. */
441 if (!pwc || (pwc == ((wchar_t *)ps))) {
449 /* This is really here only to support the glibc extension function
450 * __mbsnrtowcs which apparently returns 0 if wn == 0 without any
451 * check on the validity of the mbstate. */
456 if ((mask = (__uwchar_t) ps->__mask) != 0) { /* A continuation... */
458 wc = (__uwchar_t) ps->__wc;
464 if ((wc = (__uwchar_t) ps->__wc) != 0xffffU) {
465 /* TODO: change error code here and below? */
472 return (size_t) -1; /* We're in an error state. */
481 if ((wc = ((unsigned char) *s++)) >= 0x80) { /* Not ASCII... */
483 #ifdef __UCLIBC_MJN3_ONLY__
484 #warning TODO: Fix range for 16 bit wchar_t case.
486 if ( ((unsigned char)(s[-1] - 0xc0)) < (0xfe - 0xc0) ) {
497 return (size_t) -1; /* Illegal start byte! */
503 if ((*s & 0xc0) != 0x80) {
508 wc += (*s & 0x3f); /* keep seperate for bcc (smaller code) */
513 if ((wc & mask) == 0) { /* Character completed. */
514 if ((mask >>= 5) == 0x40) {
517 /* Check for invalid sequences (longer than necessary)
518 * and invalid chars. */
519 if ( (wc < mask) /* Sequence not minimal length. */
521 #if UTF_8_MAX_LEN == 3
522 #error broken since mask can overflow!!
523 /* For plane 0, these are the only defined values.*/
526 /* Note that we don't need to worry about exceeding */
527 /* 31 bits as that is the most that UTF-8 provides. */
528 || ( ((__uwchar_t)(wc - 0xfffeU)) < 2)
530 || ( ((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U) )
538 /* Character potentially valid but incomplete. */
539 if (!allow_continuation) {
543 /* NOTE: The following can fail if you allow and then disallow
545 #if UTF_8_MAX_LEN == 3
546 #error broken since mask can overflow!!
548 /* Need to back up... */
551 } while ((mask >>= 5) >= 0x40);
554 ps->__mask = (wchar_t) mask;
555 ps->__wc = (wchar_t) wc;
566 while (wc && --count);
574 /* ps->__wc is irrelavent here. */
584 /**********************************************************************/
585 #ifdef L__wchar_wcsntoutf8s
587 size_t attribute_hidden _wchar_wcsntoutf8s(char *__restrict s, size_t n,
588 const wchar_t **__restrict src, size_t wn)
593 const __uwchar_t *swc;
595 char buf[MB_LEN_MAX];
599 /* NOTE: The following is an AWFUL HACK! In order to support %ls in
600 * printf, we need to be able to compute the number of bytes needed
601 * for the mbs conversion, not to exceed the precision specified.
602 * But if dst is NULL, the return value is the length assuming a
603 * sufficiently sized buffer. So, we allow passing of (char *) src
604 * as dst in order to flag that we really want the length, subject
605 * to the restricted buffer size and no partial conversions.
606 * See wcsnrtombs() as well. */
607 if (!s || (s == ((char *) src))) {
616 swc = (const __uwchar_t *) *src;
629 #if UTF_8_MAX_LEN == 3
630 /* For plane 0, these are the only defined values.*/
631 /* Note that we don't need to worry about exceeding */
632 /* 31 bits as that is the most that UTF-8 provides. */
635 /* UTF_8_MAX_LEN == 6 */
637 || ( ((__uwchar_t)(wc - 0xfffeU)) < 2)
639 || ( ((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U) )
645 #if UTF_8_MAX_LEN != 3
646 if (wc > 0x7fffffffUL) { /* Value too large. */
659 if ((len = p - s) > t) { /* Not enough space. */
666 *--p = (wc & 0x3f) | 0x80;
670 } else if (wc == 0) { /* End of string. */
684 *src = (const wchar_t *) swc;
692 /**********************************************************************/
695 /* WARNING: We treat len as SIZE_MAX when dst is NULL! */
697 size_t mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
698 size_t NMC, size_t len, mbstate_t *__restrict ps)
700 static mbstate_t mbstate; /* Rely on bss 0-init. */
710 #ifdef __CTYPE_HAS_UTF_8_LOCALES
711 if (ENCODING == __ctype_encoding_utf8) {
713 return ((r = _wchar_utf8sntowcs(dst, len, src, NMC, ps, 1))
714 != (size_t) -2) ? r : 0;
718 /* NOTE: The following is an AWFUL HACK! In order to support %s in
719 * wprintf, we need to be able to compute the number of wchars needed
720 * for the mbs conversion, not to exceed the precision specified.
721 * But if dst is NULL, the return value is the length assuming a
722 * sufficiently sized buffer. So, we allow passing of ((wchar_t *)ps)
723 * as dst in order to flag that we really want the length, subject
724 * to the restricted buffer size and no partial conversions.
725 * See _wchar_utf8sntowcs() as well. */
726 if (!dst || (dst == ((wchar_t *)ps))) {
734 /* Since all the following encodings are single-byte encodings... */
742 #ifdef __CTYPE_HAS_8_BIT_LOCALES
743 if (ENCODING == __ctype_encoding_8_bit) {
746 if ((wc = ((unsigned char)(*s))) >= 0x80) { /* Non-ASCII... */
748 wc = __UCLIBC_CURLOCALE_DATA.tbl8c2wc[
749 (__UCLIBC_CURLOCALE_DATA.idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
750 << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
770 #ifdef __UCLIBC_HAS_LOCALE__
771 assert(ENCODING == __ctype_encoding_7_bit);
775 if ((*dst = (unsigned char) *s) == 0) {
780 #ifdef __CTYPE_HAS_8_BIT_LOCALES
795 libc_hidden_proto(mbsnrtowcs)
796 libc_hidden_def(mbsnrtowcs)
799 /**********************************************************************/
802 /* WARNING: We treat len as SIZE_MAX when dst is NULL! */
804 /* Note: We completely ignore ps in all currently supported conversions.
805 * TODO: Check for valid state anyway? */
807 size_t wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
808 size_t NWC, size_t len, mbstate_t *__restrict ps)
813 char buf[MB_LEN_MAX];
815 #ifdef __CTYPE_HAS_UTF_8_LOCALES
816 if (ENCODING == __ctype_encoding_utf8) {
817 return _wchar_wcsntoutf8s(dst, len, src, NWC);
819 #endif /* __CTYPE_HAS_UTF_8_LOCALES */
822 /* NOTE: The following is an AWFUL HACK! In order to support %ls in
823 * printf, we need to be able to compute the number of bytes needed
824 * for the mbs conversion, not to exceed the precision specified.
825 * But if dst is NULL, the return value is the length assuming a
826 * sufficiently sized buffer. So, we allow passing of (char *) src
827 * as dst in order to flag that we really want the length, subject
828 * to the restricted buffer size and no partial conversions.
829 * See _wchar_wcsntoutf8s() as well. */
830 if (!dst || (dst == ((char *) src))) {
838 /* Since all the following encodings are single-byte encodings... */
844 s = (const __uwchar_t *) *src;
846 #ifdef __CTYPE_HAS_8_BIT_LOCALES
847 if (ENCODING == __ctype_encoding_8_bit) {
851 if ((wc = *s) <= 0x7f) {
852 if (!(*dst = (unsigned char) wc)) {
858 if (wc <= Cwc2c_DOMAIN_MAX) {
859 u = __UCLIBC_CURLOCALE_DATA.idx8wc2c[wc >> (Cwc2c_TI_SHIFT
861 u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[(u << Cwc2c_TI_SHIFT)
862 + ((wc >> Cwc2c_TT_SHIFT)
863 & ((1 << Cwc2c_TI_SHIFT)-1))];
864 u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[Cwc2c_TI_LEN
865 + (u << Cwc2c_TT_SHIFT)
866 + (wc & ((1 << Cwc2c_TT_SHIFT)-1))];
869 #define __WCHAR_REPLACEMENT_CHAR '?'
870 #ifdef __WCHAR_REPLACEMENT_CHAR
871 *dst = (unsigned char) ( u ? u : __WCHAR_REPLACEMENT_CHAR );
872 #else /* __WCHAR_REPLACEMENT_CHAR */
876 *dst = (unsigned char) u;
877 #endif /* __WCHAR_REPLACEMENT_CHAR */
884 *src = (const wchar_t *) s;
888 #endif /* __CTYPE_HAS_8_BIT_LOCALES */
890 #ifdef __UCLIBC_HAS_LOCALE__
891 assert(ENCODING == __ctype_encoding_7_bit);
896 #if defined(__CTYPE_HAS_8_BIT_LOCALES) && !defined(__WCHAR_REPLACEMENT_CHAR)
902 if ((*dst = (unsigned char) *s) == 0) {
911 *src = (const wchar_t *) s;
915 libc_hidden_proto(wcsnrtombs)
916 libc_hidden_def(wcsnrtombs)
919 /**********************************************************************/
922 #ifdef __UCLIBC_MJN3_ONLY__
923 #warning REMINDER: If we start doing translit, wcwidth and wcswidth will need updating.
924 #warning TODO: Update wcwidth to match latest by Kuhn.
927 #if defined(__UCLIBC_HAS_LOCALE__) && \
928 ( defined(__CTYPE_HAS_8_BIT_LOCALES) || defined(__CTYPE_HAS_UTF_8_LOCALES) )
930 static const unsigned char new_idx[] = {
931 0, 5, 5, 6, 10, 15, 28, 39,
932 48, 48, 71, 94, 113, 128, 139, 154,
933 175, 186, 188, 188, 188, 188, 188, 188,
934 203, 208, 208, 208, 208, 208, 208, 208,
935 208, 219, 219, 219, 222, 222, 222, 222,
936 222, 222, 222, 222, 222, 222, 222, 224,
937 224, 231, 231, 231, 231, 231, 231, 231,
938 231, 231, 231, 231, 231, 231, 231, 231,
939 231, 231, 231, 231, 231, 231, 231, 231,
940 231, 231, 231, 231, 231, 231, 231, 231,
941 231, 231, 231, 231, 231, 231, 231, 231,
942 231, 231, 231, 231, 231, 231, 231, 231,
943 231, 231, 231, 231, 231, 231, 231, 231,
944 231, 231, 231, 231, 231, 231, 231, 231,
945 231, 231, 231, 231, 231, 231, 231, 231,
946 231, 231, 231, 231, 231, 231, 231, 231,
947 231, 231, 231, 231, 231, 231, 231, 231,
948 231, 231, 231, 231, 231, 231, 231, 231,
949 231, 231, 231, 231, 231, 231, 231, 231,
950 231, 231, 231, 231, 231, 231, 231, 231,
951 231, 231, 231, 231, 231, 233, 233, 233,
952 233, 233, 233, 233, 234, 234, 234, 234,
953 234, 234, 234, 234, 234, 234, 234, 234,
954 234, 234, 234, 234, 234, 234, 234, 234,
955 234, 234, 234, 234, 234, 234, 234, 234,
956 234, 234, 234, 234, 234, 234, 234, 234,
957 234, 234, 234, 234, 234, 234, 234, 234,
958 236, 236, 236, 236, 236, 236, 236, 236,
959 236, 236, 236, 236, 236, 236, 236, 236,
960 236, 236, 236, 236, 236, 236, 236, 236,
961 236, 236, 236, 236, 236, 236, 236, 236,
962 236, 237, 237, 238, 241, 241, 242, 249,
966 static const unsigned char new_tbl[] = {
967 0x00, 0x01, 0x20, 0x7f, 0xa0, 0x00, 0x00, 0x50,
968 0x60, 0x70, 0x00, 0x83, 0x87, 0x88, 0x8a, 0x00,
969 0x91, 0xa2, 0xa3, 0xba, 0xbb, 0xbe, 0xbf, 0xc0,
970 0xc1, 0xc3, 0xc4, 0xc5, 0x00, 0x4b, 0x56, 0x70,
971 0x71, 0xd6, 0xe5, 0xe7, 0xe9, 0xea, 0xee, 0x00,
972 0x0f, 0x10, 0x11, 0x12, 0x30, 0x4b, 0xa6, 0xb1,
973 0x00, 0x01, 0x03, 0x3c, 0x3d, 0x41, 0x49, 0x4d,
974 0x4e, 0x51, 0x55, 0x62, 0x64, 0x81, 0x82, 0xbc,
975 0xbd, 0xc1, 0xc5, 0xcd, 0xce, 0xe2, 0xe4, 0x00,
976 0x02, 0x03, 0x3c, 0x3d, 0x41, 0x43, 0x47, 0x49,
977 0x4b, 0x4e, 0x70, 0x72, 0x81, 0x83, 0xbc, 0xbd,
978 0xc1, 0xc6, 0xc7, 0xc9, 0xcd, 0xce, 0x00, 0x01,
979 0x02, 0x3c, 0x3d, 0x3f, 0x40, 0x41, 0x44, 0x4d,
980 0x4e, 0x56, 0x57, 0x82, 0x83, 0xc0, 0xc1, 0xcd,
981 0xce, 0x00, 0x3e, 0x41, 0x46, 0x49, 0x4a, 0x4e,
982 0x55, 0x57, 0xbf, 0xc0, 0xc6, 0xc7, 0xcc, 0xce,
983 0x00, 0x41, 0x44, 0x4d, 0x4e, 0xca, 0xcb, 0xd2,
984 0xd5, 0xd6, 0xd7, 0x00, 0x31, 0x32, 0x34, 0x3b,
985 0x47, 0x4f, 0xb1, 0xb2, 0xb4, 0xba, 0xbb, 0xbd,
986 0xc8, 0xce, 0x00, 0x18, 0x1a, 0x35, 0x36, 0x37,
987 0x38, 0x39, 0x3a, 0x71, 0x7f, 0x80, 0x85, 0x86,
988 0x88, 0x90, 0x98, 0x99, 0xbd, 0xc6, 0xc7, 0x00,
989 0x2d, 0x31, 0x32, 0x33, 0x36, 0x38, 0x39, 0x3a,
990 0x58, 0x5a, 0x00, 0x60, 0x00, 0x12, 0x15, 0x32,
991 0x35, 0x52, 0x54, 0x72, 0x74, 0xb7, 0xbe, 0xc6,
992 0xc7, 0xc9, 0xd4, 0x00, 0x0b, 0x0f, 0xa9, 0xaa,
993 0x00, 0x0b, 0x10, 0x2a, 0x2f, 0x60, 0x64, 0x6a,
994 0x70, 0xd0, 0xeb, 0x00, 0x29, 0x2b, 0x00, 0x80,
995 0x00, 0x2a, 0x30, 0x3f, 0x40, 0x99, 0x9b, 0x00,
996 0xd0, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x1e,
997 0x1f, 0x00, 0x00, 0x10, 0x20, 0x24, 0x30, 0x70,
998 0xff, 0x00, 0x61, 0xe0, 0xe7, 0xf9, 0xfc,
1001 static const signed char new_wtbl[] = {
1002 0, -1, 1, -1, 1, 1, 0, 1,
1003 0, 1, 1, 0, 1, 0, 1, 1,
1004 0, 1, 0, 1, 0, 1, 0, 1,
1005 0, 1, 0, 1, 1, 0, 1, 0,
1006 1, 0, 1, 0, 1, 0, 1, 1,
1007 0, 1, 0, 1, 0, 1, 0, 1,
1008 1, 0, 1, 0, 1, 0, 1, 0,
1009 1, 0, 1, 0, 1, 0, 1, 0,
1010 1, 0, 1, 0, 1, 0, 1, 1,
1011 0, 1, 0, 1, 0, 1, 0, 1,
1012 0, 1, 0, 1, 0, 1, 0, 1,
1013 0, 1, 0, 1, 0, 1, 1, 0,
1014 1, 0, 1, 0, 1, 0, 1, 0,
1015 1, 0, 1, 0, 1, 0, 1, 0,
1016 1, 1, 0, 1, 0, 1, 0, 1,
1017 0, 1, 0, 1, 0, 1, 0, 1,
1018 1, 0, 1, 0, 1, 0, 1, 0,
1019 1, 0, 1, 1, 0, 1, 0, 1,
1020 0, 1, 0, 1, 0, 1, 0, 1,
1021 0, 1, 1, 0, 1, 0, 1, 0,
1022 1, 0, 1, 0, 1, 0, 1, 0,
1023 1, 0, 1, 0, 1, 0, 1, 1,
1024 0, 1, 0, 1, 0, 1, 0, 1,
1025 0, 1, 2, 0, 1, 0, 1, 0,
1026 1, 0, 1, 0, 1, 0, 1, 0,
1027 1, 0, 1, 1, 0, 1, 0, 1,
1028 1, 0, 1, 0, 1, 0, 1, 0,
1029 1, 0, 1, 1, 2, 1, 1, 2,
1030 2, 0, 2, 1, 2, 0, 2, 2,
1031 1, 1, 2, 1, 1, 2, 1, 0,
1032 1, 1, 0, 1, 0, 1, 2, 1,
1033 0, 2, 1, 2, 1, 0, 1,
1036 libc_hidden_proto(wcsnrtombs)
1038 int wcswidth(const wchar_t *pwcs, size_t n)
1044 if (ENCODING == __ctype_encoding_7_bit) {
1047 for (i = 0 ; (i < n) && pwcs[i] ; i++) {
1048 if (pwcs[i] != ((unsigned char)(pwcs[i]))) {
1053 #ifdef __CTYPE_HAS_8_BIT_LOCALES
1054 else if (ENCODING == __ctype_encoding_8_bit) {
1057 mbstate.__mask = 0; /* Initialize the mbstate. */
1058 if (wcsnrtombs(NULL, &pwcs, n, SIZE_MAX, &mbstate) == ((size_t) - 1)) {
1062 #endif /* __CTYPE_HAS_8_BIT_LOCALES */
1063 #if defined(__CTYPE_HAS_UTF_8_LOCALES) && defined(KUHN)
1064 /* For stricter handling of allowed unicode values... see comments above. */
1065 else if (ENCODING == __ctype_encoding_utf8) {
1068 for (i = 0 ; (i < n) && pwcs[i] ; i++) {
1069 if ( (((__uwchar_t)((pwcs[i]) - 0xfffeU)) < 2)
1070 || (((__uwchar_t)((pwcs[i]) - 0xd800U)) < (0xe000U - 0xd800U))
1076 #endif /* __CTYPE_HAS_UTF_8_LOCALES */
1078 for (count = 0 ; n && (wc = *pwcs++) ; n--) {
1080 /* If we're here, wc != 0. */
1081 if ((wc < 32) || ((wc >= 0x7f) && (wc < 0xa0))) {
1087 if (((unsigned int) wc) <= 0xffff) {
1092 while ((m = (l+h) >> 1) != l) {
1093 if (b >= new_tbl[m]) {
1095 } else { /* wc < tbl[m] */
1099 count += new_wtbl[l]; /* none should be -1. */
1103 /* Redo this to minimize average number of compares?*/
1104 if (wc >= 0x1d167) {
1105 if (wc <= 0x1d1ad) {
1111 || (wc >= 0x1d1aa))))))
1115 } else if (((wc >= 0xe0020) && (wc <= 0xe007f)) || (wc == 0xe0001)) {
1117 } else if ((wc >= 0x20000) && (wc <= 0x2ffff)) {
1118 ++count; /* need 2.. add one here */
1120 #if (WCHAR_MAX > 0x7fffffffL)
1121 else if (wc > 0x7fffffffL) {
1124 #endif /* (WCHAR_MAX > 0x7fffffffL) */
1133 #else /* __UCLIBC_HAS_LOCALE__ */
1135 int wcswidth(const wchar_t *pwcs, size_t n)
1140 for (count = 0 ; n && (wc = *pwcs++) ; n--) {
1142 /* If we're here, wc != 0. */
1143 if ((wc < 32) || ((wc >= 0x7f) && (wc < 0xa0))) {
1156 #endif /* __UCLIBC_HAS_LOCALE__ */
1158 libc_hidden_proto(wcswidth)
1159 libc_hidden_def(wcswidth)
1162 /**********************************************************************/
1165 libc_hidden_proto(wcswidth)
1167 int wcwidth(wchar_t wc)
1169 return wcswidth(&wc, 1);
1173 /**********************************************************************/
1178 mbstate_t fromstate;
1186 int skip_invalid_input; /* To support iconv -c option. */
1196 #include <byteswap.h>
1198 #if (__BYTE_ORDER != __BIG_ENDIAN) && (__BYTE_ORDER != __LITTLE_ENDIAN)
1199 #error unsupported endianness for iconv
1202 #ifndef __CTYPE_HAS_8_BIT_LOCALES
1203 #error currently iconv requires 8 bit locales
1205 #ifndef __CTYPE_HAS_UTF_8_LOCALES
1206 #error currently iconv requires UTF-8 locales
1212 IC_MULTIBYTE = 0xe0,
1213 #if __BYTE_ORDER == __BIG_ENDIAN
1228 /* For the multibyte
1229 * bit 0 means swap endian
1230 * bit 1 means 2 byte
1231 * bit 2 means 4 byte
1235 const unsigned char __iconv_codesets[] =
1236 "\x0a\xe0""WCHAR_T\x00" /* superset of UCS-4 but platform-endian */
1237 #if __BYTE_ORDER == __BIG_ENDIAN
1238 "\x08\xec""UCS-4\x00" /* always BE */
1239 "\x0a\xec""UCS-4BE\x00"
1240 "\x0a\xed""UCS-4LE\x00"
1241 "\x09\fe4""UTF-32\x00" /* platform endian with BOM */
1242 "\x0b\xe4""UTF-32BE\x00"
1243 "\x0b\xe5""UTF-32LE\x00"
1244 "\x08\xe2""UCS-2\x00" /* always BE */
1245 "\x0a\xe2""UCS-2BE\x00"
1246 "\x0a\xe3""UCS-2LE\x00"
1247 "\x09\xea""UTF-16\x00" /* platform endian with BOM */
1248 "\x0b\xea""UTF-16BE\x00"
1249 "\x0b\xeb""UTF-16LE\x00"
1250 #elif __BYTE_ORDER == __LITTLE_ENDIAN
1251 "\x08\xed""UCS-4\x00" /* always BE */
1252 "\x0a\xed""UCS-4BE\x00"
1253 "\x0a\xec""UCS-4LE\x00"
1254 "\x09\xf4""UTF-32\x00" /* platform endian with BOM */
1255 "\x0b\xe5""UTF-32BE\x00"
1256 "\x0b\xe4""UTF-32LE\x00"
1257 "\x08\xe3""UCS-2\x00" /* always BE */
1258 "\x0a\xe3""UCS-2BE\x00"
1259 "\x0a\xe2""UCS-2LE\x00"
1260 "\x09\xfa""UTF-16\x00" /* platform endian with BOM */
1261 "\x0b\xeb""UTF-16BE\x00"
1262 "\x0b\xea""UTF-16LE\x00"
1264 "\x08\x02""UTF-8\x00"
1265 "\x0b\x01""US-ASCII\x00"
1266 "\x07\x01""ASCII"; /* Must be last! (special case to save a nul) */
1268 libc_hidden_proto(strcasecmp)
1270 static int find_codeset(const char *name)
1272 const unsigned char *s;
1275 for (s = __iconv_codesets ; *s ; s += *s) {
1276 if (!strcasecmp(s+2, name)) {
1281 /* The following is ripped from find_locale in locale.c. */
1283 /* TODO: maybe CODESET_LIST + *s ??? */
1284 /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
1286 s = __LOCALE_DATA_CODESET_LIST;
1288 ++codeset; /* Increment codeset first. */
1289 if (!strcasecmp(__LOCALE_DATA_CODESET_LIST+*s, name)) {
1294 return 0; /* No matching codeset! */
1297 iconv_t weak_function iconv_open(const char *tocode, const char *fromcode)
1299 register _UC_iconv_t *px;
1300 int tocodeset, fromcodeset;
1302 if (((tocodeset = find_codeset(tocode)) != 0)
1303 && ((fromcodeset = find_codeset(fromcode)) != 0)) {
1304 if ((px = malloc(sizeof(_UC_iconv_t))) != NULL) {
1305 px->tocodeset = tocodeset;
1306 px->tobom0 = px->tobom = (tocodeset & 0x10) >> 4;
1307 px->fromcodeset0 = px->fromcodeset = fromcodeset;
1308 px->frombom0 = px->frombom = (fromcodeset & 0x10) >> 4;
1309 px->skip_invalid_input = px->tostate.__mask
1310 = px->fromstate.__mask = 0;
1311 return (iconv_t) px;
1314 __set_errno(EINVAL);
1316 return (iconv_t)(-1);
1319 int weak_function iconv_close(iconv_t cd)
1326 size_t weak_function iconv(iconv_t cd, char **__restrict inbuf,
1327 size_t *__restrict inbytesleft,
1328 char **__restrict outbuf,
1329 size_t *__restrict outbytesleft)
1331 _UC_iconv_t *px = (_UC_iconv_t *) cd;
1336 assert(px != (_UC_iconv_t *)(-1));
1337 assert(sizeof(wchar_t) == 4);
1339 if (!inbuf || !*inbuf) { /* Need to reinitialze conversion state. */
1340 /* Note: For shift-state encodings we possibly need to output the
1341 * shift sequence to return to initial state! */
1342 if ((px->fromcodeset & 0xf0) == 0xe0) {
1344 px->tostate.__mask = px->fromstate.__mask = 0;
1345 px->fromcodeset = px->fromcodeset0;
1346 px->tobom = px->tobom0;
1347 px->frombom = px->frombom0;
1352 while (*inbytesleft) {
1353 if (!*outbytesleft) {
1360 if (px->fromcodeset >= IC_MULTIBYTE) {
1361 inci = (px->fromcodeset == IC_WCHAR_T) ? 4: (px->fromcodeset & 6);
1362 if (*inbytesleft < inci) goto INVALID;
1363 wc = (((unsigned int)((unsigned char)((*inbuf)[0]))) << 8)
1364 + ((unsigned char)((*inbuf)[1]));
1366 wc = (((unsigned int)((unsigned char)((*inbuf)[2]))) << 8)
1367 + ((unsigned char)((*inbuf)[3])) + (wc << 16);
1368 if (!(px->fromcodeset & 1)) wc = bswap_32(wc);
1370 if (!(px->fromcodeset & 1)) wc = bswap_16(wc);
1371 if (((px->fromcodeset & IC_UTF_16) == IC_UTF_16)
1372 && (((__uwchar_t)(wc - 0xd800U)) < (0xdc00U - 0xd800U))
1375 if (*inbytesleft < 4) goto INVALID;
1376 wc2 = (((unsigned int)((unsigned char)((*inbuf)[2]))) << 8)
1377 + ((unsigned char)((*inbuf)[3]));
1378 if (!(px->fromcodeset & 1)) wc = bswap_16(wc2);
1379 if (((__uwchar_t)(wc2 -= 0xdc00U)) < (0xe0000U - 0xdc00U)) {
1382 inci = 4; /* Change inci here in case skipping illegals. */
1383 wc = 0x10000UL + (wc << 10) + wc2;
1390 || (wc == ((inci == 4)
1391 ? (((wchar_t) 0xfffe0000UL))
1392 : ((wchar_t)(0xfffeUL))))
1394 if (wc != 0xfeffU) {
1395 px->fromcodeset ^= 1; /* toggle endianness */
1399 goto BOM_SKIP_OUTPUT;
1405 if (px->fromcodeset != IC_WCHAR_T) {
1406 if (((__uwchar_t) wc) > (((px->fromcodeset & IC_UCS_4) == IC_UCS_4)
1407 ? 0x7fffffffUL : 0x10ffffUL)
1409 || (((__uwchar_t)(wc - 0xfffeU)) < 2)
1410 || (((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U))
1416 } else if (px->fromcodeset == IC_UTF_8) {
1417 const char *p = *inbuf;
1418 r = _wchar_utf8sntowcs(&wc, 1, &p, *inbytesleft, &px->fromstate, 0);
1419 if (((ssize_t) r) <= 0) { /* either EILSEQ or incomplete or nul */
1420 if (((ssize_t) r) < 0) { /* either EILSEQ or incomplete or nul */
1421 assert((r == (size_t)(-1)) || (r == (size_t)(-2)));
1422 if (r == (size_t)(-2)) {
1424 __set_errno(EINVAL);
1426 px->fromstate.__mask = 0;
1429 if (px->skip_invalid_input) {
1430 px->skip_invalid_input = 2; /* flag for iconv utility */
1431 goto BOM_SKIP_OUTPUT;
1433 __set_errno(EILSEQ);
1435 return (size_t)(-1);
1437 #ifdef __UCLIBC_MJN3_ONLY__
1438 #warning TODO: optimize this.
1440 if (p != NULL) { /* incomplete char case */
1443 p = *inbuf + 1; /* nul */
1446 } else if ((wc = ((unsigned char)(**inbuf))) >= 0x80) { /* Non-ASCII... */
1447 if (px->fromcodeset == IC_ASCII) { /* US-ASCII codeset */
1449 } else { /* some other 8-bit ascii-extension codeset */
1450 const __codeset_8_bit_t *c8b
1451 = __locale_mmap->codeset_8_bit + px->fromcodeset - 3;
1453 wc = __UCLIBC_CURLOCALE_DATA.tbl8c2wc[
1454 (c8b->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
1455 << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
1470 if (px->tocodeset >= IC_MULTIBYTE) {
1471 inco = (px->tocodeset == IC_WCHAR_T) ? 4: (px->tocodeset & 6);
1472 if (*outbytesleft < inco) goto TOO_BIG;
1473 if (px->tocodeset != IC_WCHAR_T) {
1474 if (((__uwchar_t) wc) > (((px->tocodeset & IC_UCS_4) == IC_UCS_4)
1475 ? 0x7fffffffUL : 0x10ffffUL)
1477 || (((__uwchar_t)(wc - 0xfffeU)) < 2)
1478 || (((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U))
1487 if (px->tocodeset & 1) wc = bswap_32(wc);
1489 if (((__uwchar_t)wc ) > 0xffffU) {
1490 if ((px->tocodeset & IC_UTF_16) != IC_UTF_16) {
1493 if (*outbytesleft < (inco = 4)) goto TOO_BIG;
1494 wc2 = 0xdc00U + (wc & 0x3ff);
1495 wc = 0xd800U + ((wc >> 10) & 0x3ff);
1496 if (px->tocodeset & 1) {
1498 wc2 = bswap_16(wc2);
1501 } else if (px->tocodeset & 1) wc = bswap_16(wc);
1503 (*outbuf)[0] = (char)((unsigned char)(wc));
1504 (*outbuf)[1] = (char)((unsigned char)(wc >> 8));
1506 (*outbuf)[2] = (char)((unsigned char)(wc >> 16));
1507 (*outbuf)[3] = (char)((unsigned char)(wc >> 24));
1509 } else if (px->tocodeset == IC_UTF_8) {
1510 const wchar_t *pw = &wc;
1512 r = _wchar_wcsntoutf8s(*outbuf, *outbytesleft, &pw, 1);
1513 if (r != (size_t)(-1)) {
1514 #ifdef __UCLIBC_MJN3_ONLY__
1515 #warning TODO: What happens for a nul?
1529 } else if (((__uwchar_t)(wc)) < 0x80) {
1533 if ((px->tocodeset != 0x01) && (wc <= Cwc2c_DOMAIN_MAX)) {
1534 const __codeset_8_bit_t *c8b
1535 = __locale_mmap->codeset_8_bit + px->tocodeset - 3;
1537 u = c8b->idx8wc2c[wc >> (Cwc2c_TI_SHIFT + Cwc2c_TT_SHIFT)];
1538 u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[(u << Cwc2c_TI_SHIFT)
1539 + ((wc >> Cwc2c_TT_SHIFT)
1540 & ((1 << Cwc2c_TI_SHIFT)-1))];
1541 wc = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[Cwc2c_TI_LEN
1542 + (u << Cwc2c_TT_SHIFT)
1543 + (wc & ((1 << Cwc2c_TT_SHIFT)-1))];
1553 *outbytesleft -= inco;
1556 *inbytesleft -= inci;
1562 /**********************************************************************/
1573 extern const unsigned char __iconv_codesets[];
1581 static void error_msg(const char *fmt, ...)
1582 __attribute__ ((noreturn, format (printf, 1, 2)));
1584 static void error_msg(const char *fmt, ...)
1589 fprintf(stderr, "%s: ", progname);
1591 vfprintf(stderr, fmt, arg);
1598 int main(int argc, char **argv)
1601 FILE *ofile = stdout;
1604 static const char opt_chars[] = "tfocsl";
1606 const char *opts[sizeof(opt_chars)]; /* last is infile name */
1612 size_t ni, no, r, pos;
1616 for (s = opt_chars ; *s ; s++) {
1617 opts[ s - opt_chars ] = NULL;
1623 if ((*p != '-') || (*++p == 0)) {
1627 if ((s = strchr(opt_chars,*p)) == NULL) {
1629 s = basename(progname);
1631 "%s [-cs] -f fromcode -t tocode [-o outputfile] [inputfile ...]\n"
1632 " or\n%s -l\n", s, s);
1633 return EXIT_FAILURE;
1635 if ((s - opt_chars) < 3) {
1636 if ((--argc == 0) || opts[s - opt_chars]) {
1639 opts[s - opt_chars] = *++argv;
1641 opts[s - opt_chars] = p;
1646 if (opts[5]) { /* -l */
1647 fprintf(stderr, "Recognized codesets:\n");
1648 for (s = __iconv_codesets ; *s ; s += *s) {
1649 fprintf(stderr," %s\n", s+2);
1651 s = __LOCALE_DATA_CODESET_LIST;
1653 fprintf(stderr," %s\n", __LOCALE_DATA_CODESET_LIST+ (unsigned char)(*s));
1656 return EXIT_SUCCESS;
1663 if (!opts[0] || !opts[1]) {
1666 if ((ic = iconv_open(opts[0],opts[1])) == ((iconv_t)(-1))) {
1667 error_msg( "unsupported codeset in %s -> %s conversion\n", opts[0], opts[1]);
1669 if (opts[3]) { /* -c */
1670 ((_UC_iconv_t *) ic)->skip_invalid_input = 1;
1673 if ((s = opts[2]) != NULL) {
1674 if (!(ofile = fopen(s, "w"))) {
1675 error_msg( "couldn't open %s for writing\n", s);
1681 if (!argc || ((**argv == '-') && !((*argv)[1]))) {
1682 ifile = stdin; /* we don't check for duplicates */
1683 } else if (!(ifile = fopen(*argv, "r"))) {
1684 error_msg( "couldn't open %s for reading\n", *argv);
1687 while ((r = fread(ibuf + ni, 1, IBUF - ni, ifile)) > 0) {
1693 if ((r = iconv(ic, &pi, &ni, &po, &no)) == ((size_t)(-1))) {
1694 if ((errno != EINVAL) && (errno != E2BIG)) {
1695 error_msg( "iconv failed at pos %lu : %m\n", (unsigned long) (pos - ni));
1698 if ((r = OBUF - no) > 0) {
1699 if (fwrite(obuf, 1, OBUF - no, ofile) < r) {
1700 error_msg( "write error\n");
1703 if (ni) { /* still bytes in buffer! */
1704 memmove(ibuf, pi, ni);
1708 if (ferror(ifile)) {
1709 error_msg( "read error\n");
1714 if (ifile != stdin) {
1718 } while (--argc > 0);
1723 error_msg( "incomplete sequence\n");
1726 return (((_UC_iconv_t *) ic)->skip_invalid_input < 2)
1727 ? EXIT_SUCCESS : EXIT_FAILURE;
1731 /**********************************************************************/