Allow SO* symbols.
[glibc.git] / libio / iofwide.c
blob72a7489ad1dfe6d5d05b5d195d2f703345be76a3
1 /* Copyright (C) 1999, 2000, 2001 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,
17 MA 02111-1307, USA.
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. */
26 #include <libioP.h>
27 #ifdef _LIBC
28 # include <dlfcn.h>
29 # include <wchar.h>
30 #endif
31 #include <stdlib.h>
32 #include <string.h>
34 #ifdef _LIBC
35 # include <langinfo.h>
36 # include <locale/localeinfo.h>
37 # include <wcsmbs/wcsmbsload.h>
38 # include <iconv/gconv_int.h>
39 # include <shlib-compat.h>
40 #endif
43 /* Prototypes of libio's codecvt functions. */
44 static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
45 __mbstate_t *statep,
46 const wchar_t *from_start,
47 const wchar_t *from_end,
48 const wchar_t **from_stop, char *to_start,
49 char *to_end, char **to_stop);
50 static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
51 __mbstate_t *statep, char *to_start,
52 char *to_end, char **to_stop);
53 static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
54 __mbstate_t *statep,
55 const char *from_start,
56 const char *from_end,
57 const char **from_stop, wchar_t *to_start,
58 wchar_t *to_end, wchar_t **to_stop);
59 static int do_encoding (struct _IO_codecvt *codecvt);
60 static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
61 const char *from_start,
62 const char *from_end, _IO_size_t max);
63 static int do_max_length (struct _IO_codecvt *codecvt);
64 static int do_always_noconv (struct _IO_codecvt *codecvt);
67 /* The functions used in `codecvt' for libio are always the same. */
68 struct _IO_codecvt __libio_codecvt =
70 .__codecvt_destr = NULL, /* Destructor, never used. */
71 .__codecvt_do_out = do_out,
72 .__codecvt_do_unshift = do_unshift,
73 .__codecvt_do_in = do_in,
74 .__codecvt_do_encoding = do_encoding,
75 .__codecvt_do_always_noconv = do_always_noconv,
76 .__codecvt_do_length = do_length,
77 .__codecvt_do_max_length = do_max_length
81 #ifdef _LIBC
82 static struct __gconv_trans_data libio_translit =
84 .__trans_fct = __gconv_transliterate
86 #endif
89 /* Return orientation of stream. If mode is nonzero try to change
90 the orientation first. */
91 #undef _IO_fwide
92 int
93 _IO_fwide (fp, mode)
94 _IO_FILE *fp;
95 int mode;
97 /* Normalize the value. */
98 mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
100 if (mode == 0)
101 /* The caller simply wants to know about the current orientation. */
102 return fp->_mode;
104 #if defined SHARED && defined _LIBC \
105 && SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
106 if (__builtin_expect (&_IO_stdin_used == NULL, 0)
107 && (fp == _IO_stdin || fp == _IO_stdout || fp == _IO_stderr))
108 /* This is for a stream in the glibc 2.0 format. */
109 return -1;
110 #endif
112 if (fp->_mode != 0)
113 /* The orientation already has been determined. */
114 return fp->_mode;
116 /* Set the orientation appropriately. */
117 if (mode > 0)
119 struct _IO_codecvt *cc = fp->_codecvt = &fp->_wide_data->_codecvt;
121 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
122 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
124 /* Get the character conversion functions based on the currently
125 selected locale for LC_CTYPE. */
126 #ifdef _LIBC
128 struct gconv_fcts fcts;
130 /* Clear the state. We start all over again. */
131 memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
132 memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
134 __wcsmbs_clone_conv (&fcts);
136 /* The functions are always the same. */
137 *cc = __libio_codecvt;
139 cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed. */
140 cc->__cd_in.__cd.__steps = fcts.towc;
142 cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
143 cc->__cd_in.__cd.__data[0].__internal_use = 1;
144 cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
145 cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
147 /* XXX For now no transliteration. */
148 cc->__cd_in.__cd.__data[0].__trans = NULL;
150 cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed. */
151 cc->__cd_out.__cd.__steps = fcts.tomb;
153 cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
154 cc->__cd_out.__cd.__data[0].__internal_use = 1;
155 cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
156 cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
158 /* And now the transliteration. */
159 #ifdef _LIBC
160 cc->__cd_out.__cd.__data[0].__trans = &libio_translit;
161 #else
162 cc->__cd_out.__cd.__data[0].__trans = NULL;
163 #endif
165 #else
166 # ifdef _GLIBCPP_USE_WCHAR_T
168 /* Determine internal and external character sets.
170 XXX For now we make our life easy: we assume a fixed internal
171 encoding (as most sane systems have; hi HP/UX!). If somebody
172 cares about systems which changing internal charsets they
173 should come up with a solution for the determination of the
174 currently used internal character set. */
175 const char *internal_ccs = _G_INTERNAL_CCS;
176 const char *external_ccs = NULL;
178 # ifdef HAVE_NL_LANGINFO
179 external_ccs = nl_langinfo (CODESET);
180 # endif
181 if (external_ccs == NULL)
182 external_ccs = "ISO-8859-1";
184 cc->__cd_in = iconv_open (internal_ccs, external_ccs);
185 if (cc->__cd_in != (iconv_t) -1)
186 cc->__cd_out = iconv_open (external_ccs, internal_ccs);
188 if (cc->__cd_in == (iconv_t) -1 || cc->__cd_out == (iconv_t) -1)
189 /* XXX */
190 abort ();
192 # else
193 # error "somehow determine this from LC_CTYPE"
194 # endif
195 #endif
197 /* From now on use the wide character callback functions. */
198 ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
201 /* Set the mode now. */
202 fp->_mode = mode;
204 return mode;
208 static enum __codecvt_result
209 do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
210 const wchar_t *from_start, const wchar_t *from_end,
211 const wchar_t **from_stop, char *to_start, char *to_end,
212 char **to_stop)
214 enum __codecvt_result result;
216 #ifdef _LIBC
217 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
218 int status;
219 size_t dummy;
220 const unsigned char *from_start_copy = (unsigned char *) from_start;
222 codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
223 codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
224 codecvt->__cd_out.__cd.__data[0].__statep = statep;
226 status = DL_CALL_FCT (gs->__fct,
227 (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
228 (const unsigned char *) from_end, NULL,
229 &dummy, 0, 0));
231 *from_stop = (wchar_t *) from_start_copy;
232 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
234 switch (status)
236 case __GCONV_OK:
237 case __GCONV_EMPTY_INPUT:
238 result = __codecvt_ok;
239 break;
241 case __GCONV_FULL_OUTPUT:
242 case __GCONV_INCOMPLETE_INPUT:
243 result = __codecvt_partial;
244 break;
246 default:
247 result = __codecvt_error;
248 break;
250 #else
251 # ifdef _GLIBCPP_USE_WCHAR_T
252 size_t res;
253 const char *from_start_copy = (const char *) from_start;
254 size_t from_len = from_end - from_start;
255 char *to_start_copy = to_start;
256 size_t to_len = to_end - to_start;
257 res = iconv (codecvt->__cd_out, &from_start_copy, &from_len,
258 &to_start_copy, &to_len);
260 if (res == 0 || from_len == 0)
261 result = __codecvt_ok;
262 else if (to_len < codecvt->__codecvt_do_max_length (codecvt))
263 result = __codecvt_partial;
264 else
265 result = __codecvt_error;
267 # else
268 /* Decide what to do. */
269 result = __codecvt_error;
270 # endif
271 #endif
273 return result;
277 static enum __codecvt_result
278 do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
279 char *to_start, char *to_end, char **to_stop)
281 enum __codecvt_result result;
283 #ifdef _LIBC
284 struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
285 int status;
286 size_t dummy;
288 codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
289 codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
290 codecvt->__cd_out.__cd.__data[0].__statep = statep;
292 status = DL_CALL_FCT (gs->__fct,
293 (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
294 NULL, &dummy, 1, 0));
296 *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
298 switch (status)
300 case __GCONV_OK:
301 case __GCONV_EMPTY_INPUT:
302 result = __codecvt_ok;
303 break;
305 case __GCONV_FULL_OUTPUT:
306 case __GCONV_INCOMPLETE_INPUT:
307 result = __codecvt_partial;
308 break;
310 default:
311 result = __codecvt_error;
312 break;
314 #else
315 # ifdef _GLIBCPP_USE_WCHAR_T
316 size_t res;
317 char *to_start_copy = (char *) to_start;
318 size_t to_len = to_end - to_start;
320 res = iconv (codecvt->__cd_out, NULL, NULL, &to_start_copy, &to_len);
322 if (res == 0)
323 result = __codecvt_ok;
324 else if (to_len < codecvt->__codecvt_do_max_length (codecvt))
325 result = __codecvt_partial;
326 else
327 result = __codecvt_error;
328 # else
329 /* Decide what to do. */
330 result = __codecvt_error;
331 # endif
332 #endif
334 return result;
338 static enum __codecvt_result
339 do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
340 const char *from_start, const char *from_end, const char **from_stop,
341 wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
343 enum __codecvt_result result;
345 #ifdef _LIBC
346 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
347 int status;
348 size_t dummy;
349 const unsigned char *from_start_copy = (unsigned char *) from_start;
351 codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_start;
352 codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) to_end;
353 codecvt->__cd_in.__cd.__data[0].__statep = statep;
355 status = DL_CALL_FCT (gs->__fct,
356 (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
357 from_end, NULL, &dummy, 0, 0));
359 *from_stop = from_start_copy;
360 *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
362 switch (status)
364 case __GCONV_OK:
365 case __GCONV_EMPTY_INPUT:
366 result = __codecvt_ok;
367 break;
369 case __GCONV_FULL_OUTPUT:
370 case __GCONV_INCOMPLETE_INPUT:
371 result = __codecvt_partial;
372 break;
374 default:
375 result = __codecvt_error;
376 break;
378 #else
379 # ifdef _GLIBCPP_USE_WCHAR_T
380 size_t res;
381 const char *from_start_copy = (const char *) from_start;
382 size_t from_len = from_end - from_start;
383 char *to_start_copy = (char *) from_start;
384 size_t to_len = to_end - to_start;
386 res = iconv (codecvt->__cd_in, &from_start_copy, &from_len,
387 &to_start_copy, &to_len);
389 if (res == 0)
390 result = __codecvt_ok;
391 else if (to_len == 0)
392 result = __codecvt_partial;
393 else if (from_len < codecvt->__codecvt_do_max_length (codecvt))
394 result = __codecvt_partial;
395 else
396 result = __codecvt_error;
397 # else
398 /* Decide what to do. */
399 result = __codecvt_error;
400 # endif
401 #endif
403 return result;
407 static int
408 do_encoding (struct _IO_codecvt *codecvt)
410 #ifdef _LIBC
411 /* See whether the encoding is stateful. */
412 if (codecvt->__cd_in.__cd.__steps[0].__stateful)
413 return -1;
414 /* Fortunately not. Now determine the input bytes for the conversion
415 necessary for each wide character. */
416 if (codecvt->__cd_in.__cd.__steps[0].__min_needed_from
417 != codecvt->__cd_in.__cd.__steps[0].__max_needed_from)
418 /* Not a constant value. */
419 return 0;
421 return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
422 #else
423 /* Worst case scenario. */
424 return -1;
425 #endif
429 static int
430 do_always_noconv (struct _IO_codecvt *codecvt)
432 return 0;
436 static int
437 do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
438 const char *from_start, const char *from_end, _IO_size_t max)
440 int result;
441 #ifdef _LIBC
442 const unsigned char *cp = (const unsigned char *) from_start;
443 wchar_t to_buf[max];
444 struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
445 int status;
446 size_t dummy;
448 codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_buf;
449 codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) &to_buf[max];
450 codecvt->__cd_in.__cd.__data[0].__statep = statep;
452 status = DL_CALL_FCT (gs->__fct,
453 (gs, codecvt->__cd_in.__cd.__data, &cp, from_end,
454 NULL, &dummy, 0, 0));
456 result = cp - (const unsigned char *) from_start;
457 #else
458 # ifdef _GLIBCPP_USE_WCHAR_T
459 const char *from_start_copy = (const char *) from_start;
460 size_t from_len = from_end - from_start;
461 wchar_t to_buf[max];
462 size_t res;
463 char *to_start = (char *) to_buf;
465 res = iconv (codecvt->__cd_in, &from_start_copy, &from_len,
466 &to_start, &max);
468 result = from_start_copy - (char *) from_start;
469 # else
470 /* Decide what to do. */
471 result = 0;
472 # endif
473 #endif
475 return result;
479 static int
480 do_max_length (struct _IO_codecvt *codecvt)
482 #ifdef _LIBC
483 return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
484 #else
485 return MB_CUR_MAX;
486 #endif