1 /* Copyright (C) 1999, 2000 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. */
35 # include <langinfo.h>
36 # include <locale/localeinfo.h>
37 # include <wcsmbs/wcsmbsload.h>
38 # include <iconv/gconv_int.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
, _IO_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 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 static struct __gconv_trans_data libio_translit
=
82 .__trans_fct
= __gconv_transliterate
86 /* Return orientation of stream. If mode is nonzero try to change
87 the orientation first. */
94 /* Normalize the value. */
95 mode
= mode
< 0 ? -1 : (mode
== 0 ? 0 : 1);
97 if (mode
== 0 || fp
->_mode
!= 0)
98 /* The caller simply wants to know about the current orientation
99 or the orientation already has been determined. */
102 /* Set the orientation appropriately. */
105 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
106 fp
->_wide_data
->_IO_write_ptr
= fp
->_wide_data
->_IO_write_base
;
108 /* Clear the state. We start all over again. */
109 memset (&fp
->_wide_data
->_IO_state
, '\0', sizeof (__mbstate_t
));
110 memset (&fp
->_wide_data
->_IO_last_state
, '\0', sizeof (__mbstate_t
));
112 /* Get the character conversion functions based on the currently
113 selected locale for LC_CTYPE. */
116 struct gconv_fcts fcts
;
117 struct _IO_codecvt
*cc
= &fp
->_wide_data
->_codecvt
;
119 __wcsmbs_clone_conv (&fcts
);
121 /* The functions are always the same. */
122 *cc
= __libio_codecvt
;
124 cc
->__cd_in
.__cd
.__nsteps
= 1; /* Only one step allowed. */
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 /* XXX For now no transliteration. */
133 cc
->__cd_in
.__cd
.__data
[0].__trans
= NULL
;
135 cc
->__cd_out
.__cd
.__nsteps
= 1; /* Only one step allowed. */
136 cc
->__cd_out
.__cd
.__steps
= fcts
.tomb
;
138 cc
->__cd_out
.__cd
.__data
[0].__invocation_counter
= 0;
139 cc
->__cd_out
.__cd
.__data
[0].__internal_use
= 1;
140 cc
->__cd_out
.__cd
.__data
[0].__flags
= __GCONV_IS_LAST
;
141 cc
->__cd_out
.__cd
.__data
[0].__statep
= &fp
->_wide_data
->_IO_state
;
143 /* XXX For now no transliteration. */
144 cc
->__cd_out
.__cd
.__data
[0].__trans
= &libio_translit
;
147 # error "somehow determine this from LC_CTYPE"
150 /* From now on use the wide character callback functions. */
151 ((struct _IO_FILE_plus
*) fp
)->vtable
= fp
->_wide_data
->_wide_vtable
;
154 /* Set the mode now. */
161 weak_alias (_IO_fwide
, fwide
)
165 static enum __codecvt_result
166 do_out (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
167 const wchar_t *from_start
, const wchar_t *from_end
,
168 const wchar_t **from_stop
, char *to_start
, char *to_end
,
171 enum __codecvt_result result
;
174 struct __gconv_step
*gs
= codecvt
->__cd_out
.__cd
.__steps
;
177 const unsigned char *from_start_copy
= (unsigned char *) from_start
;
179 codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
= to_start
;
180 codecvt
->__cd_out
.__cd
.__data
[0].__outbufend
= to_end
;
181 codecvt
->__cd_out
.__cd
.__data
[0].__statep
= statep
;
183 status
= DL_CALL_FCT (gs
->__fct
,
184 (gs
, codecvt
->__cd_out
.__cd
.__data
, &from_start_copy
,
185 (const unsigned char *) from_end
, NULL
,
188 *from_stop
= (wchar_t *) from_start_copy
;
189 *to_stop
= codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
;
194 case __GCONV_EMPTY_INPUT
:
195 result
= __codecvt_ok
;
198 case __GCONV_FULL_OUTPUT
:
199 case __GCONV_INCOMPLETE_INPUT
:
200 result
= __codecvt_partial
;
204 result
= __codecvt_error
;
208 /* Decide what to do. */
209 result
= __codecvt_error
;
216 static enum __codecvt_result
217 do_unshift (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
218 char *to_start
, char *to_end
, char **to_stop
)
220 enum __codecvt_result result
;
223 struct __gconv_step
*gs
= codecvt
->__cd_out
.__cd
.__steps
;
227 codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
= to_start
;
228 codecvt
->__cd_out
.__cd
.__data
[0].__outbufend
= to_end
;
229 codecvt
->__cd_out
.__cd
.__data
[0].__statep
= statep
;
231 status
= DL_CALL_FCT (gs
->__fct
,
232 (gs
, codecvt
->__cd_out
.__cd
.__data
, NULL
, NULL
,
233 NULL
, &dummy
, 1, 0));
235 *to_stop
= codecvt
->__cd_out
.__cd
.__data
[0].__outbuf
;
240 case __GCONV_EMPTY_INPUT
:
241 result
= __codecvt_ok
;
244 case __GCONV_FULL_OUTPUT
:
245 case __GCONV_INCOMPLETE_INPUT
:
246 result
= __codecvt_partial
;
250 result
= __codecvt_error
;
254 /* Decide what to do. */
255 result
= __codecvt_error
;
262 static enum __codecvt_result
263 do_in (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
264 const char *from_start
, const char *from_end
, const char **from_stop
,
265 wchar_t *to_start
, wchar_t *to_end
, wchar_t **to_stop
)
267 enum __codecvt_result result
;
270 struct __gconv_step
*gs
= codecvt
->__cd_in
.__cd
.__steps
;
273 const unsigned char *from_start_copy
= (unsigned char *) from_start
;
275 codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
= (char *) to_start
;
276 codecvt
->__cd_in
.__cd
.__data
[0].__outbufend
= (char *) to_end
;
277 codecvt
->__cd_in
.__cd
.__data
[0].__statep
= statep
;
279 status
= DL_CALL_FCT (gs
->__fct
,
280 (gs
, codecvt
->__cd_in
.__cd
.__data
, &from_start_copy
,
281 from_end
, NULL
, &dummy
, 0, 0));
283 *from_stop
= from_start_copy
;
284 *to_stop
= (wchar_t *) codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
;
289 case __GCONV_EMPTY_INPUT
:
290 result
= __codecvt_ok
;
293 case __GCONV_FULL_OUTPUT
:
294 case __GCONV_INCOMPLETE_INPUT
:
295 result
= __codecvt_partial
;
299 result
= __codecvt_error
;
303 /* Decide what to do. */
304 result
= __codecvt_error
;
312 do_encoding (struct _IO_codecvt
*codecvt
)
315 /* See whether the encoding is stateful. */
316 if (codecvt
->__cd_in
.__cd
.__steps
[0].__stateful
)
318 /* Fortunately not. Now determine the input bytes for the conversion
319 necessary for each wide character. */
320 if (codecvt
->__cd_in
.__cd
.__steps
[0].__min_needed_from
321 != codecvt
->__cd_in
.__cd
.__steps
[0].__max_needed_from
)
322 /* Not a constant value. */
325 return codecvt
->__cd_in
.__cd
.__steps
[0].__min_needed_from
;
327 /* Worst case scenario. */
334 do_always_noconv (struct _IO_codecvt
*codecvt
)
341 do_length (struct _IO_codecvt
*codecvt
, __mbstate_t
*statep
,
342 const char *from_start
, const char *from_end
, _IO_size_t max
)
346 const unsigned char *cp
= (const unsigned char *) from_start
;
348 struct __gconv_step
*gs
= codecvt
->__cd_in
.__cd
.__steps
;
352 codecvt
->__cd_in
.__cd
.__data
[0].__outbuf
= (char *) to_buf
;
353 codecvt
->__cd_in
.__cd
.__data
[0].__outbufend
= (char *) &to_buf
[max
];
354 codecvt
->__cd_in
.__cd
.__data
[0].__statep
= statep
;
356 status
= DL_CALL_FCT (gs
->__fct
,
357 (gs
, codecvt
->__cd_in
.__cd
.__data
, &cp
, from_end
,
358 NULL
, &dummy
, 0, 0));
360 result
= cp
- (const unsigned char *) from_start
;
362 /* Decide what to do. */
371 do_max_length (struct _IO_codecvt
*codecvt
)
374 return codecvt
->__cd_in
.__cd
.__steps
[0].__max_needed_from
;