1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28: #include <libioP.h>
29: #ifdef _LIBC
30: # include <dlfcn.h>
31: # include <wchar.h>
32: #endif
33: #include <assert.h>
34: #include <stdlib.h>
35: #include <string.h>
36:
37: #ifdef _LIBC
38: # include <langinfo.h>
39: # include <locale/localeinfo.h>
40: # include <wcsmbs/wcsmbsload.h>
41: # include <iconv/gconv_int.h>
42: # include <shlib-compat.h>
43: # include <sysdep.h>
44: #endif
45:
46:
47:
48: static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
49: __mbstate_t *statep,
50: const wchar_t *from_start,
51: const wchar_t *from_end,
52: const wchar_t **from_stop, char *to_start,
53: char *to_end, char **to_stop);
54: static enum __codecvt_result do_unshift (struct _IO_codecvt *codecvt,
55: __mbstate_t *statep, char *to_start,
56: char *to_end, char **to_stop);
57: static enum __codecvt_result do_in (struct _IO_codecvt *codecvt,
58: __mbstate_t *statep,
59: const char *from_start,
60: const char *from_end,
61: const char **from_stop, wchar_t *to_start,
62: wchar_t *to_end, wchar_t **to_stop);
63: static int do_encoding (struct _IO_codecvt *codecvt);
64: static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
65: const char *from_start,
66: const char *from_end, _IO_size_t max);
67: static int do_max_length (struct _IO_codecvt *codecvt);
68: static int do_always_noconv (struct _IO_codecvt *codecvt);
69:
70:
71:
72: const struct _IO_codecvt __libio_codecvt =
73: {
74: .__codecvt_destr = NULL,
75: .__codecvt_do_out = do_out,
76: .__codecvt_do_unshift = do_unshift,
77: .__codecvt_do_in = do_in,
78: .__codecvt_do_encoding = do_encoding,
79: .__codecvt_do_always_noconv = do_always_noconv,
80: .__codecvt_do_length = do_length,
81: .__codecvt_do_max_length = do_max_length
82: };
83:
84:
85: #ifdef _LIBC
86: const struct __gconv_trans_data __libio_translit attribute_hidden =
87: {
88: .__trans_fct = __gconv_transliterate
89: };
90: #endif
91:
92:
93:
94:
95: #undef _IO_fwide
96: int
97: _IO_fwide (fp, mode)
98: _IO_FILE *fp;
99: int mode;
100: {
101:
102: mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
103:
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:
109: return -1;
110: #endif
111:
112:
113: if (fp->_mode != 0
114:
115: || mode == 0)
116: return fp->_mode;
117:
118:
119: if (mode > 0)
120: {
121: struct _IO_codecvt *cc = fp->_codecvt = &fp->_wide_data->_codecvt;
122:
123: fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
124: fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
125:
126:
127:
128: #ifdef _LIBC
129: {
130:
131: memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
132: memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
133:
134: struct gconv_fcts fcts;
135: __wcsmbs_clone_conv (&fcts);
136: assert (fcts.towc_nsteps == 1);
137: assert (fcts.tomb_nsteps == 1);
138:
139:
140: *cc = __libio_codecvt;
141:
142: cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
143: cc->__cd_in.__cd.__steps = fcts.towc;
144:
145: cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
146: cc->__cd_in.__cd.__data[0].__internal_use = 1;
147: cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
148: cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
149:
150:
151: cc->__cd_in.__cd.__data[0].__trans = NULL;
152:
153: cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
154: cc->__cd_out.__cd.__steps = fcts.tomb;
155:
156: cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
157: cc->__cd_out.__cd.__data[0].__internal_use = 1;
158: cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
159: cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
160:
161:
162: cc->__cd_out.__cd.__data[0].__trans
163: = (struct __gconv_trans_data *) &__libio_translit;
164: }
165: #else
166: # ifdef _GLIBCPP_USE_WCHAR_T
167: {
168:
169:
170:
171:
172:
173:
174:
175: const char *internal_ccs = _G_INTERNAL_CCS;
176: const char *external_ccs = NULL;
177:
178: # ifdef HAVE_NL_LANGINFO
179: external_ccs = nl_langinfo (CODESET);
180: # endif
181: if (external_ccs == NULL)
182: external_ccs = "ISO-8859-1";
183:
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);
187:
188: if (cc->__cd_in == (iconv_t) -1 || cc->__cd_out == (iconv_t) -1)
189: {
190: if (cc->__cd_in != (iconv_t) -1)
191: iconv_close (cc->__cd_in);
192:
193: abort ();
194: }
195: }
196: # else
197: # error "somehow determine this from LC_CTYPE"
198: # endif
199: #endif
200:
201:
202: ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
203:
204:
205:
206:
207:
208: fp->_offset = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
209: }
210:
211:
212: fp->_mode = mode;
213:
214: return mode;
215: }
216:
217:
218: static enum __codecvt_result
219: do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
220: const wchar_t *from_start, const wchar_t *from_end,
221: const wchar_t **from_stop, char *to_start, char *to_end,
222: char **to_stop)
223: {
224: enum __codecvt_result result;
225:
226: #ifdef _LIBC
227: struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
228: int status;
229: size_t dummy;
230: const unsigned char *from_start_copy = (unsigned char *) from_start;
231:
232: codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
233: codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
234: codecvt->__cd_out.__cd.__data[0].__statep = statep;
235:
236: __gconv_fct fct = gs->__fct;
237: #ifdef PTR_DEMANGLE
238: if (gs->__shlib_handle != NULL)
239: PTR_DEMANGLE (fct);
240: #endif
241:
242: status = DL_CALL_FCT (fct,
243: (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
244: (const unsigned char *) from_end, NULL,
245: &dummy, 0, 0));
246:
247: *from_stop = (wchar_t *) from_start_copy;
248: *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
249:
250: switch (status)
251: {
252: case __GCONV_OK:
253: case __GCONV_EMPTY_INPUT:
254: result = __codecvt_ok;
255: break;
256:
257: case __GCONV_FULL_OUTPUT:
258: case __GCONV_INCOMPLETE_INPUT:
259: result = __codecvt_partial;
260: break;
261:
262: default:
263: result = __codecvt_error;
264: break;
265: }
266: #else
267: # ifdef _GLIBCPP_USE_WCHAR_T
268: size_t res;
269: const char *from_start_copy = (const char *) from_start;
270: size_t from_len = from_end - from_start;
271: char *to_start_copy = to_start;
272: size_t to_len = to_end - to_start;
273: res = iconv (codecvt->__cd_out, &from_start_copy, &from_len,
274: &to_start_copy, &to_len);
275:
276: if (res == 0 || from_len == 0)
277: result = __codecvt_ok;
278: else if (to_len < codecvt->__codecvt_do_max_length (codecvt))
279: result = __codecvt_partial;
280: else
281: result = __codecvt_error;
282:
283: # else
284:
285: result = __codecvt_error;
286: # endif
287: #endif
288:
289: return result;
290: }
291:
292:
293: static enum __codecvt_result
294: do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
295: char *to_start, char *to_end, char **to_stop)
296: {
297: enum __codecvt_result result;
298:
299: #ifdef _LIBC
300: struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
301: int status;
302: size_t dummy;
303:
304: codecvt->__cd_out.__cd.__data[0].__outbuf = (unsigned char *) to_start;
305: codecvt->__cd_out.__cd.__data[0].__outbufend = (unsigned char *) to_end;
306: codecvt->__cd_out.__cd.__data[0].__statep = statep;
307:
308: __gconv_fct fct = gs->__fct;
309: #ifdef PTR_DEMANGLE
310: if (gs->__shlib_handle != NULL)
311: PTR_DEMANGLE (fct);
312: #endif
313:
314: status = DL_CALL_FCT (fct,
315: (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
316: NULL, &dummy, 1, 0));
317:
318: *to_stop = (char *) codecvt->__cd_out.__cd.__data[0].__outbuf;
319:
320: switch (status)
321: {
322: case __GCONV_OK:
323: case __GCONV_EMPTY_INPUT:
324: result = __codecvt_ok;
325: break;
326:
327: case __GCONV_FULL_OUTPUT:
328: case __GCONV_INCOMPLETE_INPUT:
329: result = __codecvt_partial;
330: break;
331:
332: default:
333: result = __codecvt_error;
334: break;
335: }
336: #else
337: # ifdef _GLIBCPP_USE_WCHAR_T
338: size_t res;
339: char *to_start_copy = (char *) to_start;
340: size_t to_len = to_end - to_start;
341:
342: res = iconv (codecvt->__cd_out, NULL, NULL, &to_start_copy, &to_len);
343:
344: if (res == 0)
345: result = __codecvt_ok;
346: else if (to_len < codecvt->__codecvt_do_max_length (codecvt))
347: result = __codecvt_partial;
348: else
349: result = __codecvt_error;
350: # else
351:
352: result = __codecvt_error;
353: # endif
354: #endif
355:
356: return result;
357: }
358:
359:
360: static enum __codecvt_result
361: do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
362: const char *from_start, const char *from_end, const char **from_stop,
363: wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
364: {
365: enum __codecvt_result result;
366:
367: #ifdef _LIBC
368: struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
369: int status;
370: size_t dummy;
371: const unsigned char *from_start_copy = (unsigned char *) from_start;
372:
373: codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_start;
374: codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) to_end;
375: codecvt->__cd_in.__cd.__data[0].__statep = statep;
376:
377: __gconv_fct fct = gs->__fct;
378: #ifdef PTR_DEMANGLE
379: if (gs->__shlib_handle != NULL)
380: PTR_DEMANGLE (fct);
381: #endif
382:
383: status = DL_CALL_FCT (fct,
384: (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
385: (const unsigned char *) from_end, NULL,
386: &dummy, 0, 0));
387:
388: *from_stop = (const char *) from_start_copy;
389: *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
390:
391: switch (status)
392: {
393: case __GCONV_OK:
394: case __GCONV_EMPTY_INPUT:
395: result = __codecvt_ok;
396: break;
397:
398: case __GCONV_FULL_OUTPUT:
399: case __GCONV_INCOMPLETE_INPUT:
400: result = __codecvt_partial;
401: break;
402:
403: default:
404: result = __codecvt_error;
405: break;
406: }
407: #else
408: # ifdef _GLIBCPP_USE_WCHAR_T
409: size_t res;
410: const char *from_start_copy = (const char *) from_start;
411: size_t from_len = from_end - from_start;
412: char *to_start_copy = (char *) from_start;
413: size_t to_len = to_end - to_start;
414:
415: res = iconv (codecvt->__cd_in, &from_start_copy, &from_len,
416: &to_start_copy, &to_len);
417:
418: if (res == 0)
419: result = __codecvt_ok;
420: else if (to_len == 0)
421: result = __codecvt_partial;
422: else if (from_len < codecvt->__codecvt_do_max_length (codecvt))
423: result = __codecvt_partial;
424: else
425: result = __codecvt_error;
426: # else
427:
428: result = __codecvt_error;
429: # endif
430: #endif
431:
432: return result;
433: }
434:
435:
436: static int
437: do_encoding (struct _IO_codecvt *codecvt)
438: {
439: #ifdef _LIBC
440:
441: if (codecvt->__cd_in.__cd.__steps[0].__stateful)
442: return -1;
443:
444:
445: if (codecvt->__cd_in.__cd.__steps[0].__min_needed_from
446: != codecvt->__cd_in.__cd.__steps[0].__max_needed_from)
447:
448: return 0;
449:
450: return codecvt->__cd_in.__cd.__steps[0].__min_needed_from;
451: #else
452:
453: return -1;
454: #endif
455: }
456:
457:
458: static int
459: do_always_noconv (struct _IO_codecvt *codecvt)
460: {
461: return 0;
462: }
463:
464:
465: static int
466: do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
467: const char *from_start, const char *from_end, _IO_size_t max)
468: {
469: int result;
470: #ifdef _LIBC
471: const unsigned char *cp = (const unsigned char *) from_start;
472: wchar_t to_buf[max];
473: struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
474: int status;
475: size_t dummy;
476:
477: codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_buf;
478: codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) &to_buf[max];
479: codecvt->__cd_in.__cd.__data[0].__statep = statep;
480:
481: __gconv_fct fct = gs->__fct;
482: #ifdef PTR_DEMANGLE
483: if (gs->__shlib_handle != NULL)
484: PTR_DEMANGLE (fct);
485: #endif
486:
487: status = DL_CALL_FCT (fct,
488: (gs, codecvt->__cd_in.__cd.__data, &cp,
489: (const unsigned char *) from_end, NULL,
490: &dummy, 0, 0));
491:
492: result = cp - (const unsigned char *) from_start;
493: #else
494: # ifdef _GLIBCPP_USE_WCHAR_T
495: const char *from_start_copy = (const char *) from_start;
496: size_t from_len = from_end - from_start;
497: wchar_t to_buf[max];
498: size_t res;
499: char *to_start = (char *) to_buf;
500:
501: res = iconv (codecvt->__cd_in, &from_start_copy, &from_len,
502: &to_start, &max);
503:
504: result = from_start_copy - (char *) from_start;
505: # else
506:
507: result = 0;
508: # endif
509: #endif
510:
511: return result;
512: }
513:
514:
515: static int
516: do_max_length (struct _IO_codecvt *codecvt)
517: {
518: #ifdef _LIBC
519: return codecvt->__cd_in.__cd.__steps[0].__max_needed_from;
520: #else
521: return MB_CUR_MAX;
522: #endif
523: }