]> git.ipfire.org Git - thirdparty/glibc.git/blame - libio/iofwide.c
Update.
[thirdparty/glibc.git] / libio / iofwide.c
CommitLineData
4e2e9999 1/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
d64b6ad0
UD
2 This file is part of the GNU IO Library.
3
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.
8
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.
13
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.
18
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. */
25
26#include <libioP.h>
27#ifdef _LIBC
28# include <wchar.h>
29#endif
30#include <stdlib.h>
31#include <string.h>
32
33#ifdef _LIBC
34# include <langinfo.h>
35# include <locale/localeinfo.h>
36# include <wcsmbs/wcsmbsload.h>
37#endif
38
39
40/* Prototypes of libio's codecvt functions. */
41static 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);
47static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
48 __mbstate_t *statep, char *to_start,
49 char *to_end, char **to_stop);
50static 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);
56static int do_encoding (struct _IO_codecvt *codecvt);
57static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
58 const char *from_start,
59 const char *from_end, _IO_size_t max);
60static int do_max_length (struct _IO_codecvt *codecvt);
61static int do_always_noconv (struct _IO_codecvt *codecvt);
62
63
64/* The functions used in `codecvt' for libio are always the same. */
4e2e9999 65struct _IO_codecvt __libio_codecvt =
d64b6ad0
UD
66{
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
75};
76
77
78/* Return orientation of stream. If mode is nonzero try to change
79 the orientation first. */
80#undef _IO_fwide
81int
82_IO_fwide (fp, mode)
83 _IO_FILE *fp;
84 int mode;
85{
86 /* Normalize the value. */
87 mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
88
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;
93
94 _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, fp);
95 _IO_flockfile (fp);
96
97 /* Set the orientation appropriately. */
98 if (mode > 0)
99 {
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;
102
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));
106
107 /* Get the character conversion functions based on the currently
108 selected locale for LC_CTYPE. */
109#ifdef _LIBC
110 {
111 struct gconv_fcts fcts;
112 struct _IO_codecvt *cc = &fp->_wide_data->_codecvt;
113
114 __wcsmbs_clone_conv (&fcts);
115
116 /* The functions are always the same. */
4e2e9999 117 *cc = __libio_codecvt;
d64b6ad0
UD
118
119 cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed. */
120 cc->__cd_in.__cd.__steps = fcts.towc;
121
122 cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
123 cc->__cd_in.__cd.__data[0].__internal_use = 1;
85830c4c 124 cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
d64b6ad0
UD
125 cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
126
127 cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed. */
128 cc->__cd_out.__cd.__steps = fcts.tomb;
129
130 cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
131 cc->__cd_out.__cd.__data[0].__internal_use = 1;
85830c4c 132 cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
d64b6ad0
UD
133 cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
134 }
135#else
136# error "somehow determine this from LC_CTYPE"
137#endif
138
139 /* From now on use the wide character callback functions. */
140 ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
141 }
142
143 /* Set the mode now. */
144 fp->_mode = mode;
145
146 _IO_funlockfile (fp);
147 _IO_cleanup_region_end (0);
148
149 return mode;
150}
151
152#ifdef weak_alias
153weak_alias (_IO_fwide, fwide)
154#endif
155
156
157static enum __codecvt_result
158do_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)
162{
163 enum __codecvt_result result;
164
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;
170
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;
174
175 status = (*gs->__fct) (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
fd1b5c0f 176 (const unsigned char *) from_end, &written, 0, 0);
d64b6ad0
UD
177
178 *from_stop = (wchar_t *) from_start_copy;
179 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
180
181 switch (status)
182 {
183 case __GCONV_OK:
184 case __GCONV_EMPTY_INPUT:
185 result = __codecvt_ok;
186 break;
187
188 case __GCONV_FULL_OUTPUT:
189 case __GCONV_INCOMPLETE_INPUT:
190 result = __codecvt_partial;
191 break;
192
193 default:
194 result = __codecvt_error;
195 break;
196 }
197#else
198 /* Decide what to do. */
199 result = __codecvt_error;
200#endif
201
202 return result;
203}
204
205
206static enum __codecvt_result
207do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
208 char *to_start, char *to_end, char **to_stop)
209{
210 enum __codecvt_result result;
211
212#ifdef _LIBC
213 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
214 int status;
215 size_t written;
216
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;
220
221 status = (*gs->__fct) (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
fd1b5c0f 222 &written, 1, 0);
d64b6ad0
UD
223
224 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
225
226 switch (status)
227 {
228 case __GCONV_OK:
229 case __GCONV_EMPTY_INPUT:
230 result = __codecvt_ok;
231 break;
232
233 case __GCONV_FULL_OUTPUT:
234 case __GCONV_INCOMPLETE_INPUT:
235 result = __codecvt_partial;
236 break;
237
238 default:
239 result = __codecvt_error;
240 break;
241 }
242#else
243 /* Decide what to do. */
244 result = __codecvt_error;
245#endif
246
247 return result;
248}
249
250
251static enum __codecvt_result
252do_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)
255{
256 enum __codecvt_result result;
257
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;
263
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;
267
268 status = (*gs->__fct) (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
fd1b5c0f 269 from_end, &written, 0, 0);
d64b6ad0
UD
270
271 *from_stop = from_start_copy;
272 *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
273
274 switch (status)
275 {
276 case __GCONV_OK:
277 case __GCONV_EMPTY_INPUT:
278 result = __codecvt_ok;
279 break;
280
281 case __GCONV_FULL_OUTPUT:
282 case __GCONV_INCOMPLETE_INPUT:
283 result = __codecvt_partial;
284 break;
285
286 default:
287 result = __codecvt_error;
288 break;
289 }
290#else
291 /* Decide what to do. */
292 result = __codecvt_error;
293#endif
294
295 return result;
296}
297
298
299static int
300do_encoding (struct _IO_codecvt *codecvt)
301{
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;
312
313 return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
314#else
315 /* Worst case scenario. */
316 return -1;
317#endif
318}
319
320
321static int
322do_always_noconv (struct _IO_codecvt *codecvt)
323{
324 return 0;
325}
326
327
328static int
329do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
330 const char *from_start, const char *from_end, _IO_size_t max)
331{
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;
339
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;
343
344 status = (*gs->__fct) (gs, codecvt->__cd_in.__cd.__data, &cp, from_end,
fd1b5c0f 345 &written, 0, 0);
d64b6ad0
UD
346
347 result = cp - (const unsigned char *) from_start;
348#else
349 /* Decide what to do. */
350 result = 0;
351#endif
352
353 return result;
354}
355
356
357static int
358do_max_length (struct _IO_codecvt *codecvt)
359{
360#ifdef _LIBC
361 return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
362#else
363 return MB_CUR_MAX;
364#endif
365}