Fix typos.
[platform/upstream/glibc.git] / libio / iofwide.c
1 /* Copyright (C) 1999-2013 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
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/>.
17
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.  */
26
27 #include <libioP.h>
28 #ifdef _LIBC
29 # include <dlfcn.h>
30 # include <wchar.h>
31 #endif
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #ifdef _LIBC
37 # include <langinfo.h>
38 # include <locale/localeinfo.h>
39 # include <wcsmbs/wcsmbsload.h>
40 # include <iconv/gconv_int.h>
41 # include <shlib-compat.h>
42 # include <sysdep.h>
43 #endif
44
45
46 /* Prototypes of libio's codecvt functions.  */
47 static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
48                                      __mbstate_t *statep,
49                                      const wchar_t *from_start,
50                                      const wchar_t *from_end,
51                                      const wchar_t **from_stop, char *to_start,
52                                      char *to_end, char **to_stop);
53 static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
54                                          __mbstate_t *statep, char *to_start,
55                                          char *to_end, char **to_stop);
56 static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
57                                     __mbstate_t *statep,
58                                     const char *from_start,
59                                     const char *from_end,
60                                     const char **from_stop, wchar_t *to_start,
61                                     wchar_t *to_end, wchar_t **to_stop);
62 static int do_encoding (struct _IO_codecvt *codecvt);
63 static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
64                       const char *from_start,
65                       const char *from_end, _IO_size_t max);
66 static int do_max_length (struct _IO_codecvt *codecvt);
67 static int do_always_noconv (struct _IO_codecvt *codecvt);
68
69
70 /* The functions used in `codecvt' for libio are always the same.  */
71 const struct _IO_codecvt __libio_codecvt =
72 {
73   .__codecvt_destr = NULL,              /* Destructor, never used.  */
74   .__codecvt_do_out = do_out,
75   .__codecvt_do_unshift = do_unshift,
76   .__codecvt_do_in = do_in,
77   .__codecvt_do_encoding = do_encoding,
78   .__codecvt_do_always_noconv = do_always_noconv,
79   .__codecvt_do_length = do_length,
80   .__codecvt_do_max_length = do_max_length
81 };
82
83
84 #ifdef _LIBC
85 const struct __gconv_trans_data __libio_translit attribute_hidden =
86 {
87   .__trans_fct = __gconv_transliterate
88 };
89 #endif
90
91
92 /* Return orientation of stream.  If mode is nonzero try to change
93    the orientation first.  */
94 #undef _IO_fwide
95 int
96 _IO_fwide (fp, mode)
97      _IO_FILE *fp;
98      int mode;
99 {
100   /* Normalize the value.  */
101   mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
102
103 #if defined SHARED && defined _LIBC \
104     && SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
105   if (__builtin_expect (&_IO_stdin_used == NULL, 0)
106       && (fp == _IO_stdin || fp == _IO_stdout || fp == _IO_stderr))
107     /* This is for a stream in the glibc 2.0 format.  */
108     return -1;
109 #endif
110
111   /* The orientation already has been determined.  */
112   if (fp->_mode != 0
113       /* Or the caller simply wants to know about the current orientation.  */
114       || mode == 0)
115     return fp->_mode;
116
117   /* Set the orientation appropriately.  */
118   if (mode > 0)
119     {
120       struct _IO_codecvt *cc = fp->_codecvt = &fp->_wide_data->_codecvt;
121
122       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
123       fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
124
125       /* Get the character conversion functions based on the currently
126          selected locale for LC_CTYPE.  */
127 #ifdef _LIBC
128       {
129         /* Clear the state.  We start all over again.  */
130         memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
131         memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
132
133         struct gconv_fcts fcts;
134         __wcsmbs_clone_conv (&fcts);
135         assert (fcts.towc_nsteps == 1);
136         assert (fcts.tomb_nsteps == 1);
137
138         /* The functions are always the same.  */
139         *cc = __libio_codecvt;
140
141         cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
142         cc->__cd_in.__cd.__steps = fcts.towc;
143
144         cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
145         cc->__cd_in.__cd.__data[0].__internal_use = 1;
146         cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
147         cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
148
149         /* XXX For now no transliteration.  */
150         cc->__cd_in.__cd.__data[0].__trans = NULL;
151
152         cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
153         cc->__cd_out.__cd.__steps = fcts.tomb;
154
155         cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
156         cc->__cd_out.__cd.__data[0].__internal_use = 1;
157         cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
158         cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
159
160         /* And now the transliteration.  */
161         cc->__cd_out.__cd.__data[0].__trans
162           = (struct __gconv_trans_data  *) &__libio_translit;
163       }
164 #else
165 # ifdef _GLIBCPP_USE_WCHAR_T
166       {
167         /* Determine internal and external character sets.
168
169            XXX For now we make our life easy: we assume a fixed internal
170            encoding (as most sane systems have; hi HP/UX!).  If somebody
171            cares about systems which changing internal charsets they
172            should come up with a solution for the determination of the
173            currently used internal character set.  */
174         const char *internal_ccs = _G_INTERNAL_CCS;
175         const char *external_ccs = NULL;
176
177 #  ifdef HAVE_NL_LANGINFO
178         external_ccs = nl_langinfo (CODESET);
179 #  endif
180         if (external_ccs == NULL)
181           external_ccs = "ISO-8859-1";
182
183         cc->__cd_in = iconv_open (internal_ccs, external_ccs);
184         if (cc->__cd_in != (iconv_t) -1)
185           cc->__cd_out = iconv_open (external_ccs, internal_ccs);
186
187         if (cc->__cd_in == (iconv_t) -1 || cc->__cd_out == (iconv_t) -1)
188           {
189             if (cc->__cd_in != (iconv_t) -1)
190               iconv_close (cc->__cd_in);
191             /* XXX */
192             abort ();
193           }
194       }
195 # else
196 #  error "somehow determine this from LC_CTYPE"
197 # endif
198 #endif
199
200       /* From now on use the wide character callback functions.  */
201       ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
202
203       /* One last twist: we get the current stream position.  The wide
204          char streams have much more problems with not knowing the
205          current position and so we should disable the optimization
206          which allows the functions without knowing the position.  */
207       fp->_offset = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
208     }
209
210   /* Set the mode now.  */
211   fp->_mode = mode;
212
213   return mode;
214 }
215
216
217 static enum __codecvt_result
218 do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
219         const wchar_t *from_start, const wchar_t *from_end,
220         const wchar_t **from_stop, char *to_start, char *to_end,
221         char **to_stop)
222 {
223   enum __codecvt_result result;
224
225 #ifdef _LIBC
226   struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
227   int status;
228   size_t dummy;
229   const unsigned char *from_start_copy = (unsigned char *) from_start;
230
231   codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
232   codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
233   codecvt->__cd_out.__cd.__data[0].__statep = statep;
234
235   __gconv_fct fct = gs->__fct;
236 #ifdef PTR_DEMANGLE
237   if (gs->__shlib_handle != NULL)
238     PTR_DEMANGLE (fct);
239 #endif
240
241   status = DL_CALL_FCT (fct,
242                         (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
243                          (const unsigned char *) from_end, NULL,
244                          &dummy, 0, 0));
245
246   *from_stop = (wchar_t *) from_start_copy;
247   *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
248
249   switch (status)
250     {
251     case __GCONV_OK:
252     case __GCONV_EMPTY_INPUT:
253       result = __codecvt_ok;
254       break;
255
256     case __GCONV_FULL_OUTPUT:
257     case __GCONV_INCOMPLETE_INPUT:
258       result = __codecvt_partial;
259       break;
260
261     default:
262       result = __codecvt_error;
263       break;
264     }
265 #else
266 # ifdef _GLIBCPP_USE_WCHAR_T
267   size_t res;
268   const char *from_start_copy = (const char *) from_start;
269   size_t from_len = from_end - from_start;
270   char *to_start_copy = to_start;
271   size_t to_len = to_end - to_start;
272   res = iconv (codecvt->__cd_out, &from_start_copy, &from_len,
273                &to_start_copy, &to_len);
274
275   if (res == 0 || from_len == 0)
276     result = __codecvt_ok;
277   else if (to_len < codecvt->__codecvt_do_max_length (codecvt))
278     result = __codecvt_partial;
279   else
280     result = __codecvt_error;
281
282 # else
283   /* Decide what to do.  */
284   result = __codecvt_error;
285 # endif
286 #endif
287
288   return result;
289 }
290
291
292 static enum __codecvt_result
293 do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
294             char *to_start, char *to_end, char **to_stop)
295 {
296   enum __codecvt_result result;
297
298 #ifdef _LIBC
299   struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
300   int status;
301   size_t dummy;
302
303   codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
304   codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
305   codecvt->__cd_out.__cd.__data[0].__statep = statep;
306
307   __gconv_fct fct = gs->__fct;
308 #ifdef PTR_DEMANGLE
309   if (gs->__shlib_handle != NULL)
310     PTR_DEMANGLE (fct);
311 #endif
312
313   status = DL_CALL_FCT (fct,
314                         (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
315                          NULL, &dummy, 1, 0));
316
317   *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
318
319   switch (status)
320     {
321     case __GCONV_OK:
322     case __GCONV_EMPTY_INPUT:
323       result = __codecvt_ok;
324       break;
325
326     case __GCONV_FULL_OUTPUT:
327     case __GCONV_INCOMPLETE_INPUT:
328       result = __codecvt_partial;
329       break;
330
331     default:
332       result = __codecvt_error;
333       break;
334     }
335 #else
336 # ifdef _GLIBCPP_USE_WCHAR_T
337   size_t res;
338   char *to_start_copy = (char *) to_start;
339   size_t to_len = to_end - to_start;
340
341   res = iconv (codecvt->__cd_out, NULL, NULL, &to_start_copy, &to_len);
342
343   if (res == 0)
344     result = __codecvt_ok;
345   else if (to_len < codecvt->__codecvt_do_max_length (codecvt))
346     result = __codecvt_partial;
347   else
348     result = __codecvt_error;
349 # else
350   /* Decide what to do.  */
351   result = __codecvt_error;
352 # endif
353 #endif
354
355   return result;
356 }
357
358
359 static enum __codecvt_result
360 do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
361        const char *from_start, const char *from_end, const char **from_stop,
362        wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
363 {
364   enum __codecvt_result result;
365
366 #ifdef _LIBC
367   struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
368   int status;
369   size_t dummy;
370   const unsigned char *from_start_copy = (unsigned char *) from_start;
371
372   codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_start;
373   codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) to_end;
374   codecvt->__cd_in.__cd.__data[0].__statep = statep;
375
376   __gconv_fct fct = gs->__fct;
377 #ifdef PTR_DEMANGLE
378   if (gs->__shlib_handle != NULL)
379     PTR_DEMANGLE (fct);
380 #endif
381
382   status = DL_CALL_FCT (fct,
383                         (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
384                          (const unsigned char *) from_end, NULL,
385                          &dummy, 0, 0));
386
387   *from_stop = (const char *) from_start_copy;
388   *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
389
390   switch (status)
391     {
392     case __GCONV_OK:
393     case __GCONV_EMPTY_INPUT:
394       result = __codecvt_ok;
395       break;
396
397     case __GCONV_FULL_OUTPUT:
398     case __GCONV_INCOMPLETE_INPUT:
399       result = __codecvt_partial;
400       break;
401
402     default:
403       result = __codecvt_error;
404       break;
405     }
406 #else
407 # ifdef _GLIBCPP_USE_WCHAR_T
408   size_t res;
409   const char *from_start_copy = (const char *) from_start;
410   size_t from_len = from_end - from_start;
411   char *to_start_copy = (char *) from_start;
412   size_t to_len = to_end - to_start;
413
414   res = iconv (codecvt->__cd_in, &from_start_copy, &from_len,
415                &to_start_copy, &to_len);
416
417   if (res == 0)
418     result = __codecvt_ok;
419   else if (to_len == 0)
420     result = __codecvt_partial;
421   else if (from_len < codecvt->__codecvt_do_max_length (codecvt))
422     result = __codecvt_partial;
423   else
424     result = __codecvt_error;
425 # else
426   /* Decide what to do.  */
427   result = __codecvt_error;
428 # endif
429 #endif
430
431   return result;
432 }
433
434
435 static int
436 do_encoding (struct _IO_codecvt *codecvt)
437 {
438 #ifdef _LIBC
439   /* See whether the encoding is stateful.  */
440   if (codecvt->__cd_in.__cd.__steps[0].__stateful)
441     return -1;
442   /* Fortunately not.  Now determine the input bytes for the conversion
443      necessary for each wide character.  */
444   if (codecvt->__cd_in.__cd.__steps[0].__min_needed_from
445       != codecvt->__cd_in.__cd.__steps[0].__max_needed_from)
446     /* Not a constant value.  */
447     return 0;
448
449   return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
450 #else
451   /* Worst case scenario.  */
452   return -1;
453 #endif
454 }
455
456
457 static int
458 do_always_noconv (struct _IO_codecvt *codecvt)
459 {
460   return 0;
461 }
462
463
464 static int
465 do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
466            const char *from_start, const char *from_end, _IO_size_t max)
467 {
468   int result;
469 #ifdef _LIBC
470   const unsigned char *cp = (const unsigned char *) from_start;
471   wchar_t to_buf[max];
472   struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
473   size_t dummy;
474
475   codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_buf;
476   codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) &to_buf[max];
477   codecvt->__cd_in.__cd.__data[0].__statep = statep;
478
479   __gconv_fct fct = gs->__fct;
480 #ifdef PTR_DEMANGLE
481   if (gs->__shlib_handle != NULL)
482     PTR_DEMANGLE (fct);
483 #endif
484
485   DL_CALL_FCT (fct,
486                (gs, codecvt->__cd_in.__cd.__data, &cp,
487                 (const unsigned char *) from_end, NULL,
488                 &dummy, 0, 0));
489
490   result = cp - (const unsigned char *) from_start;
491 #else
492 # ifdef _GLIBCPP_USE_WCHAR_T
493   const char *from_start_copy = (const char *) from_start;
494   size_t from_len = from_end - from_start;
495   wchar_t to_buf[max];
496   size_t res;
497   char *to_start = (char *) to_buf;
498
499   res = iconv (codecvt->__cd_in, &from_start_copy, &from_len,
500                &to_start, &max);
501
502   result = from_start_copy - (char *) from_start;
503 # else
504   /* Decide what to do.  */
505   result = 0;
506 # endif
507 #endif
508
509   return result;
510 }
511
512
513 static int
514 do_max_length (struct _IO_codecvt *codecvt)
515 {
516 #ifdef _LIBC
517   return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
518 #else
519   return MB_CUR_MAX;
520 #endif
521 }