1 /* Copyright (C) 1999 Free Software Foundation, Inc.
2 This file is part of the GNU IO Library.
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.
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.
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,
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. */
34 # include <langinfo.h>
35 # include <locale/localeinfo.h>
36 # include <wcsmbs/wcsmbsload.h>
40 /* Prototypes of libio's codecvt functions. */
41 static enum __codecvt_result
do_out (struct _IO_codecvt
*codecvt
,
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
,
52 const char *from_start
,
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
);
64 /* The functions used in `codecvt' for libio are always the same. */
65 static struct _IO_codecvt libio_codecvt
=
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
78 /* Return orientation of stream. If mode is nonzero try to change
79 the orientation first. */
86 /* Normalize the value. */
87 mode
= mode
< 0 ? -1 : (mode
== 0 ? 0 : 1);
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. */
94 _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile
, fp
);
97 /* Set the orientation appropriately. */
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
;
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
));
107 /* Get the character conversion functions based on the currently
108 selected locale for LC_CTYPE. */
111 struct gconv_fcts fcts
;
112 struct _IO_codecvt
*cc
= &fp
->_wide_data
->_codecvt
;
114 __wcsmbs_clone_conv (&fcts
);
116 /* The functions are always the same. */
119 cc
->__cd_in
.__cd
.__nsteps
= 1; /* Only one step allowed. */
120 cc
->__cd_in
.__cd
.__steps
= fcts
.towc
;
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
;
127 cc
->__cd_out
.__cd
.__nsteps
= 1; /* Only one step allowed. */
128 cc
->__cd_out
.__cd
.__steps
= fcts
.tomb
;
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
;
136 # error "somehow determine this from LC_CTYPE"
139 /* From now on use the wide character callback functions. */
140 ((struct _IO_FILE_plus
*) fp
)->vtable
= fp
->_wide_data
->_wide_vtable
;
143 /* Set the mode now. */
146 _IO_funlockfile (fp
);
147 _IO_cleanup_region_end (0);
153 weak_alias (_IO_fwide
, fwide
)
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
,
163 enum __codecvt_result result
;
166 struct __gconv_step
*gs
= codecvt
->__cd_out
.__cd
.__steps
;
169 const unsigned char *from_start_copy
= (unsigned char *) from_start
;
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
;
175 status
= (*gs
->__fct
) (gs
, codecvt
->__cd_out
.__cd
.__data
, &from_start_copy
,
176 (const unsigned char *) from_end
, &written
, 0);
178 *from_stop
= (wchar_t *) from_start_copy
;
179 *to_stop
= codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
;
184 case __GCONV_EMPTY_INPUT
:
185 result
= __codecvt_ok
;
188 case __GCONV_FULL_OUTPUT
:
189 case __GCONV_INCOMPLETE_INPUT
:
190 result
= __codecvt_partial
;
194 result
= __codecvt_error
;
198 /* Decide what to do. */
199 result
= __codecvt_error
;
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
)
210 enum __codecvt_result result
;
213 struct __gconv_step
*gs
= codecvt
->__cd_out
.__cd
.__steps
;
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
;
221 status
= (*gs
->__fct
) (gs
, codecvt
->__cd_out
.__cd
.__data
, NULL
, NULL
,
224 *to_stop
= codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
;
229 case __GCONV_EMPTY_INPUT
:
230 result
= __codecvt_ok
;
233 case __GCONV_FULL_OUTPUT
:
234 case __GCONV_INCOMPLETE_INPUT
:
235 result
= __codecvt_partial
;
239 result
= __codecvt_error
;
243 /* Decide what to do. */
244 result
= __codecvt_error
;
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
)
256 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
= (char *) to_start
;
265 codecvt
->__cd_in
.__cd
.__data
[0].__outbufend
= (char *) to_end
;
266 codecvt
->__cd_in
.__cd
.__data
[0].__statep
= statep
;
268 status
= (*gs
->__fct
) (gs
, codecvt
->__cd_in
.__cd
.__data
, &from_start_copy
,
269 from_end
, &written
, 0);
271 *from_stop
= from_start_copy
;
272 *to_stop
= (wchar_t *) codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
;
277 case __GCONV_EMPTY_INPUT
:
278 result
= __codecvt_ok
;
281 case __GCONV_FULL_OUTPUT
:
282 case __GCONV_INCOMPLETE_INPUT
:
283 result
= __codecvt_partial
;
287 result
= __codecvt_error
;
291 /* Decide what to do. */
292 result
= __codecvt_error
;
300 do_encoding (struct _IO_codecvt
*codecvt
)
303 /* See whether the encoding is stateful. */
304 if (codecvt
->__cd_in
.__cd
.__steps
[0].__stateful
)
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. */
313 return codecvt
->__cd_in
.__cd
.__steps
[0].__min_needed_from
;
315 /* Worst case scenario. */
322 do_always_noconv (struct _IO_codecvt
*codecvt
)
329 do_length (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
330 const char *from_start
, const char *from_end
, _IO_size_t max
)
334 const unsigned char *cp
= (const unsigned char *) from_start
;
336 struct __gconv_step
*gs
= codecvt
->__cd_in
.__cd
.__steps
;
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
;
344 status
= (*gs
->__fct
) (gs
, codecvt
->__cd_in
.__cd
.__data
, &cp
, from_end
,
347 result
= cp
- (const unsigned char *) from_start
;
349 /* Decide what to do. */
358 do_max_length (struct _IO_codecvt
*codecvt
)
361 return codecvt
->__cd_in
.__cd
.__steps
[0].__max_needed_from
;