Fix strptime era handling, add more strftime tests [BZ #24394]
[glibc.git] / libio / iofwide.c
blob247cfde3d0a293fc1de4f79ea6e4d504b9ddc849
1 /* Copyright (C) 1999-2019 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>.
18 As a special exception, if you link the code in this file with
19 files compiled with a GNU compiler to produce an executable,
20 that does not cause the resulting executable to be covered by
21 the GNU Lesser General Public License. This exception does not
22 however invalidate any other reasons why the executable file
23 might be covered by the GNU Lesser General Public License.
24 This exception applies to code released by its copyright holders
25 in files containing the exception. */
27 #include <libioP.h>
28 #include <dlfcn.h>
29 #include <wchar.h>
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include <langinfo.h>
35 #include <locale/localeinfo.h>
36 #include <wcsmbs/wcsmbsload.h>
37 #include <iconv/gconv_int.h>
38 #include <shlib-compat.h>
39 #include <sysdep.h>
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, 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 const 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 /* Return orientation of stream. If mode is nonzero try to change
81 the orientation first. */
82 #undef _IO_fwide
83 int
84 _IO_fwide (FILE *fp, int mode)
86 /* Normalize the value. */
87 mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
89 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
90 if (__glibc_unlikely (&_IO_stdin_used == NULL) && _IO_legacy_file (fp))
91 /* This is for a stream in the glibc 2.0 format. */
92 return -1;
93 #endif
95 /* The orientation already has been determined. */
96 if (fp->_mode != 0
97 /* Or the caller simply wants to know about the current orientation. */
98 || mode == 0)
99 return fp->_mode;
101 /* Set the orientation appropriately. */
102 if (mode > 0)
104 struct _IO_codecvt *cc = fp->_codecvt = &fp->_wide_data->_codecvt;
106 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
107 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
109 /* Get the character conversion functions based on the currently
110 selected locale for LC_CTYPE. */
112 /* Clear the state. We start all over again. */
113 memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
114 memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
116 struct gconv_fcts fcts;
117 __wcsmbs_clone_conv (&fcts);
118 assert (fcts.towc_nsteps == 1);
119 assert (fcts.tomb_nsteps == 1);
121 /* The functions are always the same. */
122 *cc = __libio_codecvt;
124 cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
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 cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
133 cc->__cd_out.__cd.__steps = fcts.tomb;
135 cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
136 cc->__cd_out.__cd.__data[0].__internal_use = 1;
137 cc->__cd_out.__cd.__data[0].__flags
138 = __GCONV_IS_LAST | __GCONV_TRANSLIT;
139 cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
142 /* From now on use the wide character callback functions. */
143 _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
146 /* Set the mode now. */
147 fp->_mode = mode;
149 return mode;
153 static enum __codecvt_result
154 do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
155 const wchar_t *from_start, const wchar_t *from_end,
156 const wchar_t **from_stop, char *to_start, char *to_end,
157 char **to_stop)
159 enum __codecvt_result result;
161 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
162 int status;
163 size_t dummy;
164 const unsigned char *from_start_copy = (unsigned char *) from_start;
166 codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
167 codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
168 codecvt->__cd_out.__cd.__data[0].__statep = statep;
170 __gconv_fct fct = gs->__fct;
171 #ifdef PTR_DEMANGLE
172 if (gs->__shlib_handle != NULL)
173 PTR_DEMANGLE (fct);
174 #endif
176 status = DL_CALL_FCT (fct,
177 (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
178 (const unsigned char *) from_end, NULL,
179 &dummy, 0, 0));
181 *from_stop = (wchar_t *) from_start_copy;
182 *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
184 switch (status)
186 case __GCONV_OK:
187 case __GCONV_EMPTY_INPUT:
188 result = __codecvt_ok;
189 break;
191 case __GCONV_FULL_OUTPUT:
192 case __GCONV_INCOMPLETE_INPUT:
193 result = __codecvt_partial;
194 break;
196 default:
197 result = __codecvt_error;
198 break;
201 return result;
205 static enum __codecvt_result
206 do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
207 char *to_start, char *to_end, char **to_stop)
209 enum __codecvt_result result;
211 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
212 int status;
213 size_t dummy;
215 codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
216 codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
217 codecvt->__cd_out.__cd.__data[0].__statep = statep;
219 __gconv_fct fct = gs->__fct;
220 #ifdef PTR_DEMANGLE
221 if (gs->__shlib_handle != NULL)
222 PTR_DEMANGLE (fct);
223 #endif
225 status = DL_CALL_FCT (fct,
226 (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
227 NULL, &dummy, 1, 0));
229 *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
231 switch (status)
233 case __GCONV_OK:
234 case __GCONV_EMPTY_INPUT:
235 result = __codecvt_ok;
236 break;
238 case __GCONV_FULL_OUTPUT:
239 case __GCONV_INCOMPLETE_INPUT:
240 result = __codecvt_partial;
241 break;
243 default:
244 result = __codecvt_error;
245 break;
248 return result;
252 static enum __codecvt_result
253 do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
254 const char *from_start, const char *from_end, const char **from_stop,
255 wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
257 enum __codecvt_result result;
259 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
260 int status;
261 size_t dummy;
262 const unsigned char *from_start_copy = (unsigned char *) from_start;
264 codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_start;
265 codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) to_end;
266 codecvt->__cd_in.__cd.__data[0].__statep = statep;
268 __gconv_fct fct = gs->__fct;
269 #ifdef PTR_DEMANGLE
270 if (gs->__shlib_handle != NULL)
271 PTR_DEMANGLE (fct);
272 #endif
274 status = DL_CALL_FCT (fct,
275 (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
276 (const unsigned char *) from_end, NULL,
277 &dummy, 0, 0));
279 *from_stop = (const char *) from_start_copy;
280 *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
282 switch (status)
284 case __GCONV_OK:
285 case __GCONV_EMPTY_INPUT:
286 result = __codecvt_ok;
287 break;
289 case __GCONV_FULL_OUTPUT:
290 case __GCONV_INCOMPLETE_INPUT:
291 result = __codecvt_partial;
292 break;
294 default:
295 result = __codecvt_error;
296 break;
299 return result;
303 static int
304 do_encoding (struct _IO_codecvt *codecvt)
306 /* See whether the encoding is stateful. */
307 if (codecvt->__cd_in.__cd.__steps[0].__stateful)
308 return -1;
309 /* Fortunately not. Now determine the input bytes for the conversion
310 necessary for each wide character. */
311 if (codecvt->__cd_in.__cd.__steps[0].__min_needed_from
312 != codecvt->__cd_in.__cd.__steps[0].__max_needed_from)
313 /* Not a constant value. */
314 return 0;
316 return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
320 static int
321 do_always_noconv (struct _IO_codecvt *codecvt)
323 return 0;
327 static int
328 do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
329 const char *from_start, const char *from_end, size_t max)
331 int result;
332 const unsigned char *cp = (const unsigned char *) from_start;
333 wchar_t to_buf[max];
334 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
335 size_t dummy;
337 codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_buf;
338 codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) &to_buf[max];
339 codecvt->__cd_in.__cd.__data[0].__statep = statep;
341 __gconv_fct fct = gs->__fct;
342 #ifdef PTR_DEMANGLE
343 if (gs->__shlib_handle != NULL)
344 PTR_DEMANGLE (fct);
345 #endif
347 DL_CALL_FCT (fct,
348 (gs, codecvt->__cd_in.__cd.__data, &cp,
349 (const unsigned char *) from_end, NULL,
350 &dummy, 0, 0));
352 result = cp - (const unsigned char *) from_start;
354 return result;
358 static int
359 do_max_length (struct _IO_codecvt *codecvt)
361 return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;