]> git.ipfire.org Git - thirdparty/glibc.git/blob - libio/iofwide.c
Update.
[thirdparty/glibc.git] / libio / iofwide.c
1 /* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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. */
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);
62
63
64 /* The functions used in `codecvt' for libio are always the same. */
65 struct _IO_codecvt __libio_codecvt =
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
81 int
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. */
117 *cc = __libio_codecvt;
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;
124 cc->__cd_in.__cd.__data[0].__is_last = 1;
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;
132 cc->__cd_out.__cd.__data[0].__is_last = 1;
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
153 weak_alias (_IO_fwide, fwide)
154 #endif
155
156
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)
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,
176 (const unsigned char *) from_end, &written, 0);
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
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)
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,
222 &written, 1);
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
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)
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,
269 from_end, &written, 0);
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
299 static int
300 do_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
321 static int
322 do_always_noconv (struct _IO_codecvt *codecvt)
323 {
324 return 0;
325 }
326
327
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)
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,
345 &written, 0);
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
357 static int
358 do_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 }