Update.
[glibc.git] / libio / iofwide.c
blob853920a001576603c1a79dd50070c13899a4006d
1 /* Copyright (C) 1999 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 <wchar.h>
29 #endif
30 #include <stdlib.h>
31 #include <string.h>
33 #ifdef _LIBC
34 # include <langinfo.h>
35 # include <locale/localeinfo.h>
36 # include <wcsmbs/wcsmbsload.h>
37 #endif
40 /* Prototypes of libio's codecvt functions. */
41 static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
42 __mbstate_t *statep,
43 const wchar_t *from_start,
44 const wchar_t *from_end,
45 const wchar_t **from_stop, char *to_start,
46 char *to_end, char **to_stop);
47 static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
48 __mbstate_t *statep, char *to_start,
49 char *to_end, char **to_stop);
50 static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
51 __mbstate_t *statep,
52 const char *from_start,
53 const char *from_end,
54 const char **from_stop, wchar_t *to_start,
55 wchar_t *to_end, wchar_t **to_stop);
56 static int do_encoding (struct _IO_codecvt *codecvt);
57 static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
58 const char *from_start,
59 const char *from_end, _IO_size_t max);
60 static int do_max_length (struct _IO_codecvt *codecvt);
61 static int do_always_noconv (struct _IO_codecvt *codecvt);
64 /* The functions used in `codecvt' for libio are always the same. */
65 static struct _IO_codecvt libio_codecvt =
67 .__codecvt_destr = NULL, /* Destructor, never used. */
68 .__codecvt_do_out = do_out,
69 .__codecvt_do_unshift = do_unshift,
70 .__codecvt_do_in = do_in,
71 .__codecvt_do_encoding = do_encoding,
72 .__codecvt_do_always_noconv = do_always_noconv,
73 .__codecvt_do_length = do_length,
74 .__codecvt_do_max_length = do_max_length
78 /* Return orientation of stream. If mode is nonzero try to change
79 the orientation first. */
80 #undef _IO_fwide
81 int
82 _IO_fwide (fp, mode)
83 _IO_FILE *fp;
84 int mode;
86 /* Normalize the value. */
87 mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
89 if (mode == 0 || fp->_mode != 0)
90 /* The caller simply wants to know about the current orientation
91 or the orientation already has been determined. */
92 return fp->_mode;
94 _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
95 _IO_flockfile (fp);
97 /* Set the orientation appropriately. */
98 if (mode > 0)
100 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
101 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
103 /* Clear the state. We start all over again. */
104 memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
105 memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
107 /* Get the character conversion functions based on the currently
108 selected locale for LC_CTYPE. */
109 #ifdef _LIBC
111 struct gconv_fcts fcts;
112 struct _IO_codecvt *cc = &fp->_wide_data->_codecvt;
114 __wcsmbs_clone_conv (&fcts);
116 /* The functions are always the same. */
117 *cc = libio_codecvt;
119 cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed. */
120 cc->__cd_in.__cd.__steps = fcts.towc;
122 cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
123 cc->__cd_in.__cd.__data[0].__internal_use = 1;
124 cc->__cd_in.__cd.__data[0].__is_last = 1;
125 cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
127 cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed. */
128 cc->__cd_out.__cd.__steps = fcts.tomb;
130 cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
131 cc->__cd_out.__cd.__data[0].__internal_use = 1;
132 cc->__cd_out.__cd.__data[0].__is_last = 1;
133 cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
135 #else
136 # error "somehow determine this from LC_CTYPE"
137 #endif
139 /* From now on use the wide character callback functions. */
140 ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
143 /* Set the mode now. */
144 fp->_mode = mode;
146 _IO_funlockfile (fp);
147 _IO_cleanup_region_end (0);
149 return mode;
152 #ifdef weak_alias
153 weak_alias (_IO_fwide, fwide)
154 #endif
157 static enum __codecvt_result
158 do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
159 const wchar_t *from_start, const wchar_t *from_end,
160 const wchar_t **from_stop, char *to_start, char *to_end,
161 char **to_stop)
163 enum __codecvt_result result;
165 #ifdef _LIBC
166 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
167 int status;
168 size_t written;
169 const unsigned char *from_start_copy = (unsigned char *) from_start;
171 codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
172 codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
173 codecvt->__cd_out.__cd.__data[0].__statep = statep;
175 status = (*gs->__fct) (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
176 (const unsigned char *) from_end, &written, 0);
178 *from_stop = (wchar_t *) from_start_copy;
179 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
181 switch (status)
183 case __GCONV_OK:
184 case __GCONV_EMPTY_INPUT:
185 result = __codecvt_ok;
186 break;
188 case __GCONV_FULL_OUTPUT:
189 case __GCONV_INCOMPLETE_INPUT:
190 result = __codecvt_partial;
191 break;
193 default:
194 result = __codecvt_error;
195 break;
197 #else
198 /* Decide what to do. */
199 result = __codecvt_error;
200 #endif
202 return result;
206 static enum __codecvt_result
207 do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
208 char *to_start, char *to_end, char **to_stop)
210 enum __codecvt_result result;
212 #ifdef _LIBC
213 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
214 int status;
215 size_t written;
217 codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
218 codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
219 codecvt->__cd_out.__cd.__data[0].__statep = statep;
221 status = (*gs->__fct) (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
222 &written, 1);
224 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
226 switch (status)
228 case __GCONV_OK:
229 case __GCONV_EMPTY_INPUT:
230 result = __codecvt_ok;
231 break;
233 case __GCONV_FULL_OUTPUT:
234 case __GCONV_INCOMPLETE_INPUT:
235 result = __codecvt_partial;
236 break;
238 default:
239 result = __codecvt_error;
240 break;
242 #else
243 /* Decide what to do. */
244 result = __codecvt_error;
245 #endif
247 return result;
251 static enum __codecvt_result
252 do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
253 const char *from_start, const char *from_end, const char **from_stop,
254 wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
256 enum __codecvt_result result;
258 #ifdef _LIBC
259 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
260 int status;
261 size_t written;
262 const unsigned char *from_start_copy = (unsigned char *) from_start;
264 codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_start;
265 codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) to_end;
266 codecvt->__cd_in.__cd.__data[0].__statep = statep;
268 status = (*gs->__fct) (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
269 from_end, &written, 0);
271 *from_stop = from_start_copy;
272 *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
274 switch (status)
276 case __GCONV_OK:
277 case __GCONV_EMPTY_INPUT:
278 result = __codecvt_ok;
279 break;
281 case __GCONV_FULL_OUTPUT:
282 case __GCONV_INCOMPLETE_INPUT:
283 result = __codecvt_partial;
284 break;
286 default:
287 result = __codecvt_error;
288 break;
290 #else
291 /* Decide what to do. */
292 result = __codecvt_error;
293 #endif
295 return result;
299 static int
300 do_encoding (struct _IO_codecvt *codecvt)
302 #ifdef _LIBC
303 /* See whether the encoding is stateful. */
304 if (codecvt->__cd_in.__cd.__steps[0].__stateful)
305 return -1;
306 /* Fortunately not. Now determine the input bytes for the conversion
307 necessary for each wide character. */
308 if (codecvt->__cd_in.__cd.__steps[0].__min_needed_from
309 != codecvt->__cd_in.__cd.__steps[0].__max_needed_from)
310 /* Not a constant value. */
311 return 0;
313 return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
314 #else
315 /* Worst case scenario. */
316 return -1;
317 #endif
321 static int
322 do_always_noconv (struct _IO_codecvt *codecvt)
324 return 0;
328 static int
329 do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
330 const char *from_start, const char *from_end, _IO_size_t max)
332 int result;
333 #ifdef _LIBC
334 const unsigned char *cp = (const unsigned char *) from_start;
335 wchar_t to_buf[max];
336 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
337 int status;
338 size_t written;
340 codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_buf;
341 codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) &to_buf[max];
342 codecvt->__cd_in.__cd.__data[0].__statep = statep;
344 status = (*gs->__fct) (gs, codecvt->__cd_in.__cd.__data, &cp, from_end,
345 &written, 0);
347 result = cp - (const unsigned char *) from_start;
348 #else
349 /* Decide what to do. */
350 result = 0;
351 #endif
353 return result;
357 static int
358 do_max_length (struct _IO_codecvt *codecvt)
360 #ifdef _LIBC
361 return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
362 #else
363 return MB_CUR_MAX;
364 #endif