Support for "iconv -l".
[libiconv.git] / lib / loop_wchar.h
blob27d912a76eda77d9f1cf3c846af93990f9ab2a7f
1 /*
2 * Copyright (C) 2000-2001 Free Software Foundation, Inc.
3 * This file is part of the GNU LIBICONV Library.
5 * The GNU LIBICONV Library is free software; you can redistribute it
6 * and/or modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * The GNU LIBICONV Library is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
17 * If not, write to the Free Software Foundation, Inc., 59 Temple Place -
18 * Suite 330, Boston, MA 02111-1307, USA.
21 /* This file defines three conversion loops:
22 - from wchar_t to anything else,
23 - from anything else to wchar_t,
24 - from wchar_t to wchar_t.
27 #if HAVE_WCRTOMB || HAVE_MBRTOWC
28 # include <wchar.h>
29 # define BUF_SIZE 64 /* assume MB_LEN_MAX <= 64 */
30 /* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
31 extern size_t mbrtowc ();
32 # ifdef mbstate_t
33 # define mbrtowc(pwc, s, n, ps) (mbrtowc)(pwc, s, n, 0)
34 # define mbsinit(ps) 1
35 # endif
36 # ifndef mbsinit
37 # if !HAVE_MBSINIT
38 # define mbsinit(ps) 1
39 # endif
40 # endif
41 #else
42 # ifndef mbstate_t
43 typedef int mbstate_t;
44 # endif
45 #endif
48 * The first two conversion loops have an extended conversion descriptor.
50 struct wchar_conv_struct {
51 struct conv_struct parent;
52 mbstate_t state;
56 #if HAVE_WCRTOMB
58 /* From wchar_t to anything else. */
60 static size_t wchar_from_loop_convert (iconv_t icd,
61 const char* * inbuf, size_t *inbytesleft,
62 char* * outbuf, size_t *outbytesleft)
64 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
65 size_t result = 0;
66 while (*inbytesleft >= sizeof(wchar_t)) {
67 const wchar_t * inptr = (const wchar_t *) *inbuf;
68 size_t inleft = *inbytesleft;
69 char buf[BUF_SIZE];
70 mbstate_t state = wcd->state;
71 size_t bufcount = 0;
72 while (inleft >= sizeof(wchar_t)) {
73 /* Convert one wchar_t to multibyte representation. */
74 size_t count = wcrtomb(buf+bufcount,*inptr,&state);
75 if (count == (size_t)(-1)) {
76 /* Invalid input. */
77 errno = EILSEQ;
78 return -1;
80 inptr++;
81 inleft -= sizeof(wchar_t);
82 bufcount += count;
83 if (count == 0) {
84 /* Continue, append next wchar_t. */
85 } else {
86 /* Attempt to convert the accumulated multibyte representations
87 to the target encoding. */
88 const char* bufptr = buf;
89 size_t bufleft = bufcount;
90 char* outptr = *outbuf;
91 size_t outleft = *outbytesleft;
92 size_t res = unicode_loop_convert(&wcd->parent,
93 &bufptr,&bufleft,
94 &outptr,&outleft);
95 if (res == (size_t)(-1)) {
96 if (errno == EILSEQ)
97 /* Invalid input. */
98 return -1;
99 else if (errno == E2BIG)
100 /* Output buffer too small. */
101 return -1;
102 else if (errno == EINVAL) {
103 /* Continue, append next wchar_t, but avoid buffer overrun. */
104 if (bufcount + MB_CUR_MAX > BUF_SIZE)
105 abort();
106 } else
107 abort();
108 } else {
109 /* Successful conversion. */
110 wcd->state = state;
111 *inbuf = (const char *) inptr;
112 *inbytesleft = inleft;
113 *outbuf = outptr;
114 *outbytesleft = outleft;
115 result += res;
116 break;
121 return result;
124 static size_t wchar_from_loop_reset (iconv_t icd,
125 char* * outbuf, size_t *outbytesleft)
127 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
128 if (outbuf == NULL || *outbuf == NULL) {
129 /* Reset the states. */
130 memset(&wcd->state,'\0',sizeof(mbstate_t));
131 return unicode_loop_reset(&wcd->parent,NULL,NULL);
132 } else {
133 if (!mbsinit(&wcd->state)) {
134 mbstate_t state = wcd->state;
135 char buf[BUF_SIZE];
136 size_t bufcount = wcrtomb(buf,(wchar_t)0,&state);
137 if (bufcount == (size_t)(-1) || bufcount == 0 || buf[bufcount-1] != '\0')
138 abort();
139 else {
140 const char* bufptr = buf;
141 size_t bufleft = bufcount-1;
142 char* outptr = *outbuf;
143 size_t outleft = *outbytesleft;
144 size_t res = unicode_loop_convert(&wcd->parent,
145 &bufptr,&bufleft,
146 &outptr,&outleft);
147 if (res == (size_t)(-1)) {
148 if (errno == E2BIG)
149 return -1;
150 else
151 abort();
152 } else {
153 res = unicode_loop_reset(&wcd->parent,&outptr,&outleft);
154 if (res == (size_t)(-1))
155 return res;
156 else {
157 /* Successful. */
158 wcd->state = state;
159 *outbuf = outptr;
160 *outbytesleft = outleft;
161 return 0;
165 } else
166 return unicode_loop_reset(&wcd->parent,outbuf,outbytesleft);
170 #endif
173 #if HAVE_MBRTOWC
175 /* From anything else to wchar_t. */
177 static size_t wchar_to_loop_convert (iconv_t icd,
178 const char* * inbuf, size_t *inbytesleft,
179 char* * outbuf, size_t *outbytesleft)
181 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
182 size_t result = 0;
183 while (*inbytesleft > 0) {
184 size_t incount;
185 for (incount = 1; incount <= *inbytesleft; incount++) {
186 char buf[BUF_SIZE];
187 const char* inptr = *inbuf;
188 size_t inleft = incount;
189 char* bufptr = buf;
190 size_t bufleft = BUF_SIZE;
191 size_t res = unicode_loop_convert(&wcd->parent,
192 &inptr,&inleft,
193 &bufptr,&bufleft);
194 if (res == (size_t)(-1)) {
195 if (errno == EILSEQ)
196 /* Invalid input. */
197 return -1;
198 else if (errno == EINVAL) {
199 /* Incomplete input. Next try with one more input byte. */
200 } else
201 /* E2BIG shouldn't occur. */
202 abort();
203 } else {
204 /* Successful conversion. */
205 size_t bufcount = bufptr-buf; /* = BUF_SIZE-bufleft */
206 mbstate_t state = wcd->state;
207 wchar_t wc;
208 res = mbrtowc(&wc,buf,bufcount,&state);
209 if (res == (size_t)(-2)) {
210 /* Next try with one more input byte. */
211 } else if (res == (size_t)(-1)) {
212 /* Invalid input. */
213 return -1;
214 } else {
215 if (*outbytesleft < sizeof(wchar_t)) {
216 errno = E2BIG;
217 return -1;
219 *(wchar_t*) *outbuf = wc;
220 *outbuf += sizeof(wchar_t);
221 *outbytesleft -= sizeof(wchar_t);
222 *inbuf += incount;
223 *inbytesleft -= incount;
224 result += res;
225 break;
230 return result;
233 static size_t wchar_to_loop_reset (iconv_t icd,
234 char* * outbuf, size_t *outbytesleft)
236 struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) icd;
237 size_t res = unicode_loop_reset(&wcd->parent,outbuf,outbytesleft);
238 if (res == (size_t)(-1))
239 return res;
240 memset(&wcd->state,0,sizeof(mbstate_t));
241 return 0;
244 #endif
247 /* From wchar_t to wchar_t. */
249 static size_t wchar_id_loop_convert (iconv_t icd,
250 const char* * inbuf, size_t *inbytesleft,
251 char* * outbuf, size_t *outbytesleft)
253 const wchar_t* inptr = (const wchar_t*) *inbuf;
254 size_t inleft = *inbytesleft / sizeof(wchar_t);
255 wchar_t* outptr = (wchar_t*) *outbuf;
256 size_t outleft = *outbytesleft / sizeof(wchar_t);
257 size_t count = (inleft <= outleft ? inleft : outleft);
258 if (count > 0) {
259 *inbytesleft -= count * sizeof(wchar_t);
260 *outbytesleft -= count * sizeof(wchar_t);
262 *outptr++ = *inptr++;
263 while (--count > 0);
264 *inbuf = (const char*) inptr;
265 *outbuf = (char*) outptr;
267 return 0;
270 static size_t wchar_id_loop_reset (iconv_t icd,
271 char* * outbuf, size_t *outbytesleft)
273 return 0;