]>
git.ipfire.org Git - thirdparty/glibc.git/blob - libio/iofwide.c
80cb2d507420623986ad26b945de9385973cc08b
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 /* Return orientation of stream. If mode is nonzero try to change
43 the orientation first. */
46 _IO_fwide (FILE *fp
, int mode
)
48 /* Normalize the value. */
49 mode
= mode
< 0 ? -1 : (mode
== 0 ? 0 : 1);
51 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
52 if (__glibc_unlikely (&_IO_stdin_used
== NULL
) && _IO_legacy_file (fp
))
53 /* This is for a stream in the glibc 2.0 format. */
57 /* The orientation already has been determined. */
59 /* Or the caller simply wants to know about the current orientation. */
63 /* Set the orientation appropriately. */
66 struct _IO_codecvt
*cc
= fp
->_codecvt
= &fp
->_wide_data
->_codecvt
;
68 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
69 fp
->_wide_data
->_IO_write_ptr
= fp
->_wide_data
->_IO_write_base
;
71 /* Get the character conversion functions based on the currently
72 selected locale for LC_CTYPE. */
74 /* Clear the state. We start all over again. */
75 memset (&fp
->_wide_data
->_IO_state
, '\0', sizeof (__mbstate_t
));
76 memset (&fp
->_wide_data
->_IO_last_state
, '\0', sizeof (__mbstate_t
));
78 struct gconv_fcts fcts
;
79 __wcsmbs_clone_conv (&fcts
);
80 assert (fcts
.towc_nsteps
== 1);
81 assert (fcts
.tomb_nsteps
== 1);
83 cc
->__cd_in
.__cd
.__nsteps
= fcts
.towc_nsteps
;
84 cc
->__cd_in
.__cd
.__steps
= fcts
.towc
;
86 cc
->__cd_in
.__cd
.__data
[0].__invocation_counter
= 0;
87 cc
->__cd_in
.__cd
.__data
[0].__internal_use
= 1;
88 cc
->__cd_in
.__cd
.__data
[0].__flags
= __GCONV_IS_LAST
;
89 cc
->__cd_in
.__cd
.__data
[0].__statep
= &fp
->_wide_data
->_IO_state
;
91 cc
->__cd_out
.__cd
.__nsteps
= fcts
.tomb_nsteps
;
92 cc
->__cd_out
.__cd
.__steps
= fcts
.tomb
;
94 cc
->__cd_out
.__cd
.__data
[0].__invocation_counter
= 0;
95 cc
->__cd_out
.__cd
.__data
[0].__internal_use
= 1;
96 cc
->__cd_out
.__cd
.__data
[0].__flags
97 = __GCONV_IS_LAST
| __GCONV_TRANSLIT
;
98 cc
->__cd_out
.__cd
.__data
[0].__statep
= &fp
->_wide_data
->_IO_state
;
101 /* From now on use the wide character callback functions. */
102 _IO_JUMPS_FILE_plus (fp
) = fp
->_wide_data
->_wide_vtable
;
105 /* Set the mode now. */
112 enum __codecvt_result
113 __libio_codecvt_out (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
114 const wchar_t *from_start
, const wchar_t *from_end
,
115 const wchar_t **from_stop
, char *to_start
, char *to_end
,
118 enum __codecvt_result result
;
120 struct __gconv_step
*gs
= codecvt
->__cd_out
.__cd
.__steps
;
123 const unsigned char *from_start_copy
= (unsigned char *) from_start
;
125 codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
= (unsigned char *) to_start
;
126 codecvt
->__cd_out
.__cd
.__data
[0].__outbufend
= (unsigned char *) to_end
;
127 codecvt
->__cd_out
.__cd
.__data
[0].__statep
= statep
;
129 __gconv_fct fct
= gs
->__fct
;
131 if (gs
->__shlib_handle
!= NULL
)
135 status
= DL_CALL_FCT (fct
,
136 (gs
, codecvt
->__cd_out
.__cd
.__data
, &from_start_copy
,
137 (const unsigned char *) from_end
, NULL
,
140 *from_stop
= (wchar_t *) from_start_copy
;
141 *to_stop
= (char *) codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
;
146 case __GCONV_EMPTY_INPUT
:
147 result
= __codecvt_ok
;
150 case __GCONV_FULL_OUTPUT
:
151 case __GCONV_INCOMPLETE_INPUT
:
152 result
= __codecvt_partial
;
156 result
= __codecvt_error
;
164 enum __codecvt_result
165 __libio_codecvt_in (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
166 const char *from_start
, const char *from_end
,
167 const char **from_stop
,
168 wchar_t *to_start
, wchar_t *to_end
, wchar_t **to_stop
)
170 enum __codecvt_result result
;
172 struct __gconv_step
*gs
= codecvt
->__cd_in
.__cd
.__steps
;
175 const unsigned char *from_start_copy
= (unsigned char *) from_start
;
177 codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
= (unsigned char *) to_start
;
178 codecvt
->__cd_in
.__cd
.__data
[0].__outbufend
= (unsigned char *) to_end
;
179 codecvt
->__cd_in
.__cd
.__data
[0].__statep
= statep
;
181 __gconv_fct fct
= gs
->__fct
;
183 if (gs
->__shlib_handle
!= NULL
)
187 status
= DL_CALL_FCT (fct
,
188 (gs
, codecvt
->__cd_in
.__cd
.__data
, &from_start_copy
,
189 (const unsigned char *) from_end
, NULL
,
192 *from_stop
= (const char *) from_start_copy
;
193 *to_stop
= (wchar_t *) codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
;
198 case __GCONV_EMPTY_INPUT
:
199 result
= __codecvt_ok
;
202 case __GCONV_FULL_OUTPUT
:
203 case __GCONV_INCOMPLETE_INPUT
:
204 result
= __codecvt_partial
;
208 result
= __codecvt_error
;
217 __libio_codecvt_encoding (struct _IO_codecvt
*codecvt
)
219 /* See whether the encoding is stateful. */
220 if (codecvt
->__cd_in
.__cd
.__steps
[0].__stateful
)
222 /* Fortunately not. Now determine the input bytes for the conversion
223 necessary for each wide character. */
224 if (codecvt
->__cd_in
.__cd
.__steps
[0].__min_needed_from
225 != codecvt
->__cd_in
.__cd
.__steps
[0].__max_needed_from
)
226 /* Not a constant value. */
229 return codecvt
->__cd_in
.__cd
.__steps
[0].__min_needed_from
;
234 __libio_codecvt_length (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
235 const char *from_start
, const char *from_end
,
239 const unsigned char *cp
= (const unsigned char *) from_start
;
241 struct __gconv_step
*gs
= codecvt
->__cd_in
.__cd
.__steps
;
244 codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
= (unsigned char *) to_buf
;
245 codecvt
->__cd_in
.__cd
.__data
[0].__outbufend
= (unsigned char *) &to_buf
[max
];
246 codecvt
->__cd_in
.__cd
.__data
[0].__statep
= statep
;
248 __gconv_fct fct
= gs
->__fct
;
250 if (gs
->__shlib_handle
!= NULL
)
255 (gs
, codecvt
->__cd_in
.__cd
.__data
, &cp
,
256 (const unsigned char *) from_end
, NULL
,
259 result
= cp
- (const unsigned char *) from_start
;