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. */
35 #include <locale/localeinfo.h>
36 #include <wcsmbs/wcsmbsload.h>
37 #include <iconv/gconv_int.h>
38 #include <shlib-compat.h>
42 /* Prototypes of libio's codecvt functions. */
43 static enum __codecvt_result
do_out (struct _IO_codecvt
*codecvt
,
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
,
54 const char *from_start
,
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. */
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. */
95 /* The orientation already has been determined. */
97 /* Or the caller simply wants to know about the current orientation. */
101 /* Set the orientation appropriately. */
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. */
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
,
159 enum __codecvt_result result
;
161 struct __gconv_step
*gs
= codecvt
->__cd_out
.__cd
.__steps
;
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
;
172 if (gs
->__shlib_handle
!= NULL
)
176 status
= DL_CALL_FCT (fct
,
177 (gs
, codecvt
->__cd_out
.__cd
.__data
, &from_start_copy
,
178 (const unsigned char *) from_end
, NULL
,
181 *from_stop
= (wchar_t *) from_start_copy
;
182 *to_stop
= (char *) codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
;
187 case __GCONV_EMPTY_INPUT
:
188 result
= __codecvt_ok
;
191 case __GCONV_FULL_OUTPUT
:
192 case __GCONV_INCOMPLETE_INPUT
:
193 result
= __codecvt_partial
;
197 result
= __codecvt_error
;
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
;
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
;
221 if (gs
->__shlib_handle
!= NULL
)
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
;
234 case __GCONV_EMPTY_INPUT
:
235 result
= __codecvt_ok
;
238 case __GCONV_FULL_OUTPUT
:
239 case __GCONV_INCOMPLETE_INPUT
:
240 result
= __codecvt_partial
;
244 result
= __codecvt_error
;
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
;
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
;
270 if (gs
->__shlib_handle
!= NULL
)
274 status
= DL_CALL_FCT (fct
,
275 (gs
, codecvt
->__cd_in
.__cd
.__data
, &from_start_copy
,
276 (const unsigned char *) from_end
, NULL
,
279 *from_stop
= (const char *) from_start_copy
;
280 *to_stop
= (wchar_t *) codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
;
285 case __GCONV_EMPTY_INPUT
:
286 result
= __codecvt_ok
;
289 case __GCONV_FULL_OUTPUT
:
290 case __GCONV_INCOMPLETE_INPUT
:
291 result
= __codecvt_partial
;
295 result
= __codecvt_error
;
304 do_encoding (struct _IO_codecvt
*codecvt
)
306 /* See whether the encoding is stateful. */
307 if (codecvt
->__cd_in
.__cd
.__steps
[0].__stateful
)
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. */
316 return codecvt
->__cd_in
.__cd
.__steps
[0].__min_needed_from
;
321 do_always_noconv (struct _IO_codecvt
*codecvt
)
328 do_length (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
329 const char *from_start
, const char *from_end
, size_t max
)
332 const unsigned char *cp
= (const unsigned char *) from_start
;
334 struct __gconv_step
*gs
= codecvt
->__cd_in
.__cd
.__steps
;
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
;
343 if (gs
->__shlib_handle
!= NULL
)
348 (gs
, codecvt
->__cd_in
.__cd
.__data
, &cp
,
349 (const unsigned char *) from_end
, NULL
,
352 result
= cp
- (const unsigned char *) from_start
;
359 do_max_length (struct _IO_codecvt
*codecvt
)
361 return codecvt
->__cd_in
.__cd
.__steps
[0].__max_needed_from
;