Update.
[glibc.git] / libio / iofwide.c
blobae4f63f454f9fc44794306a906f89ed35bb13867
1 /* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
2 This file is part of the GNU IO Library.
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2, or (at
7 your option) any later version.
9 This library is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this library; see the file COPYING. If not, write to
16 the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
17 MA 02111-1307, USA.
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does
21 not cause the resulting executable to be covered by the GNU General
22 Public License. This exception does not however invalidate any
23 other reasons why the executable file might be covered by the GNU
24 General Public License. */
26 #include <libioP.h>
27 #ifdef _LIBC
28 # include <dlfcn.h>
29 # include <wchar.h>
30 #endif
31 #include <stdlib.h>
32 #include <string.h>
34 #ifdef _LIBC
35 # include <langinfo.h>
36 # include <locale/localeinfo.h>
37 # include <wcsmbs/wcsmbsload.h>
38 # include <iconv/gconv_int.h>
39 #endif
42 /* Prototypes of libio's codecvt functions. */
43 static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
44 __mbstate_t *statep,
45 const wchar_t *from_start,
46 const wchar_t *from_end,
47 const wchar_t **from_stop, char *to_start,
48 char *to_end, char **to_stop);
49 static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
50 __mbstate_t *statep, char *to_start,
51 char *to_end, char **to_stop);
52 static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
53 __mbstate_t *statep,
54 const char *from_start,
55 const char *from_end,
56 const char **from_stop, wchar_t *to_start,
57 wchar_t *to_end, wchar_t **to_stop);
58 static int do_encoding (struct _IO_codecvt *codecvt);
59 static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
60 const char *from_start,
61 const char *from_end, _IO_size_t max);
62 static int do_max_length (struct _IO_codecvt *codecvt);
63 static int do_always_noconv (struct _IO_codecvt *codecvt);
66 /* The functions used in `codecvt' for libio are always the same. */
67 struct _IO_codecvt __libio_codecvt =
69 .__codecvt_destr = NULL, /* Destructor, never used. */
70 .__codecvt_do_out = do_out,
71 .__codecvt_do_unshift = do_unshift,
72 .__codecvt_do_in = do_in,
73 .__codecvt_do_encoding = do_encoding,
74 .__codecvt_do_always_noconv = do_always_noconv,
75 .__codecvt_do_length = do_length,
76 .__codecvt_do_max_length = do_max_length
80 static struct __gconv_trans_data libio_translit =
82 .__trans_fct = __gconv_transliterate
86 /* Return orientation of stream. If mode is nonzero try to change
87 the orientation first. */
88 #undef _IO_fwide
89 int
90 _IO_fwide (fp, mode)
91 _IO_FILE *fp;
92 int mode;
94 /* Normalize the value. */
95 mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
97 if (mode == 0 || fp->_mode != 0)
98 /* The caller simply wants to know about the current orientation
99 or the orientation already has been determined. */
100 return fp->_mode;
102 /* Set the orientation appropriately. */
103 if (mode > 0)
105 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
106 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
108 /* Clear the state. We start all over again. */
109 memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
110 memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
112 /* Get the character conversion functions based on the currently
113 selected locale for LC_CTYPE. */
114 #ifdef _LIBC
116 struct gconv_fcts fcts;
117 struct _IO_codecvt *cc = &fp->_wide_data->_codecvt;
119 __wcsmbs_clone_conv (&fcts);
121 /* The functions are always the same. */
122 *cc = __libio_codecvt;
124 cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed. */
125 cc->__cd_in.__cd.__steps = fcts.towc;
127 cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
128 cc->__cd_in.__cd.__data[0].__internal_use = 1;
129 cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
130 cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
132 /* XXX For now no transliteration. */
133 cc->__cd_in.__cd.__data[0].__trans = NULL;
135 cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed. */
136 cc->__cd_out.__cd.__steps = fcts.tomb;
138 cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
139 cc->__cd_out.__cd.__data[0].__internal_use = 1;
140 cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
141 cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
143 /* XXX For now no transliteration. */
144 cc->__cd_out.__cd.__data[0].__trans = &libio_translit;
146 #else
147 # error "somehow determine this from LC_CTYPE"
148 #endif
150 /* From now on use the wide character callback functions. */
151 ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
154 /* Set the mode now. */
155 fp->_mode = mode;
157 return mode;
160 #ifdef weak_alias
161 weak_alias (_IO_fwide, fwide)
162 #endif
165 static enum __codecvt_result
166 do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
167 const wchar_t *from_start, const wchar_t *from_end,
168 const wchar_t **from_stop, char *to_start, char *to_end,
169 char **to_stop)
171 enum __codecvt_result result;
173 #ifdef _LIBC
174 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
175 int status;
176 size_t dummy;
177 const unsigned char *from_start_copy = (unsigned char *) from_start;
179 codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
180 codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
181 codecvt->__cd_out.__cd.__data[0].__statep = statep;
183 status = DL_CALL_FCT (gs->__fct,
184 (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
185 (const unsigned char *) from_end, NULL,
186 &dummy, 0, 0));
188 *from_stop = (wchar_t *) from_start_copy;
189 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
191 switch (status)
193 case __GCONV_OK:
194 case __GCONV_EMPTY_INPUT:
195 result = __codecvt_ok;
196 break;
198 case __GCONV_FULL_OUTPUT:
199 case __GCONV_INCOMPLETE_INPUT:
200 result = __codecvt_partial;
201 break;
203 default:
204 result = __codecvt_error;
205 break;
207 #else
208 /* Decide what to do. */
209 result = __codecvt_error;
210 #endif
212 return result;
216 static enum __codecvt_result
217 do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
218 char *to_start, char *to_end, char **to_stop)
220 enum __codecvt_result result;
222 #ifdef _LIBC
223 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
224 int status;
225 size_t dummy;
227 codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
228 codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
229 codecvt->__cd_out.__cd.__data[0].__statep = statep;
231 status = DL_CALL_FCT (gs->__fct,
232 (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
233 NULL, &dummy, 1, 0));
235 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
237 switch (status)
239 case __GCONV_OK:
240 case __GCONV_EMPTY_INPUT:
241 result = __codecvt_ok;
242 break;
244 case __GCONV_FULL_OUTPUT:
245 case __GCONV_INCOMPLETE_INPUT:
246 result = __codecvt_partial;
247 break;
249 default:
250 result = __codecvt_error;
251 break;
253 #else
254 /* Decide what to do. */
255 result = __codecvt_error;
256 #endif
258 return result;
262 static enum __codecvt_result
263 do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
264 const char *from_start, const char *from_end, const char **from_stop,
265 wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
267 enum __codecvt_result result;
269 #ifdef _LIBC
270 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
271 int status;
272 size_t dummy;
273 const unsigned char *from_start_copy = (unsigned char *) from_start;
275 codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_start;
276 codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) to_end;
277 codecvt->__cd_in.__cd.__data[0].__statep = statep;
279 status = DL_CALL_FCT (gs->__fct,
280 (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
281 from_end, NULL, &dummy, 0, 0));
283 *from_stop = from_start_copy;
284 *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
286 switch (status)
288 case __GCONV_OK:
289 case __GCONV_EMPTY_INPUT:
290 result = __codecvt_ok;
291 break;
293 case __GCONV_FULL_OUTPUT:
294 case __GCONV_INCOMPLETE_INPUT:
295 result = __codecvt_partial;
296 break;
298 default:
299 result = __codecvt_error;
300 break;
302 #else
303 /* Decide what to do. */
304 result = __codecvt_error;
305 #endif
307 return result;
311 static int
312 do_encoding (struct _IO_codecvt *codecvt)
314 #ifdef _LIBC
315 /* See whether the encoding is stateful. */
316 if (codecvt->__cd_in.__cd.__steps[0].__stateful)
317 return -1;
318 /* Fortunately not. Now determine the input bytes for the conversion
319 necessary for each wide character. */
320 if (codecvt->__cd_in.__cd.__steps[0].__min_needed_from
321 != codecvt->__cd_in.__cd.__steps[0].__max_needed_from)
322 /* Not a constant value. */
323 return 0;
325 return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
326 #else
327 /* Worst case scenario. */
328 return -1;
329 #endif
333 static int
334 do_always_noconv (struct _IO_codecvt *codecvt)
336 return 0;
340 static int
341 do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
342 const char *from_start, const char *from_end, _IO_size_t max)
344 int result;
345 #ifdef _LIBC
346 const unsigned char *cp = (const unsigned char *) from_start;
347 wchar_t to_buf[max];
348 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
349 int status;
350 size_t dummy;
352 codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_buf;
353 codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) &to_buf[max];
354 codecvt->__cd_in.__cd.__data[0].__statep = statep;
356 status = DL_CALL_FCT (gs->__fct,
357 (gs, codecvt->__cd_in.__cd.__data, &cp, from_end,
358 NULL, &dummy, 0, 0));
360 result = cp - (const unsigned char *) from_start;
361 #else
362 /* Decide what to do. */
363 result = 0;
364 #endif
366 return result;
370 static int
371 do_max_length (struct _IO_codecvt *codecvt)
373 #ifdef _LIBC
374 return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
375 #else
376 return MB_CUR_MAX;
377 #endif