2305
|
1 /* Unicode character output to streams with locale dependent encoding. |
|
2 |
|
3 Copyright (C) 2000 Free Software Foundation, Inc. |
|
4 |
|
5 This program is free software; you can redistribute it and/or modify it |
|
6 under the terms of the GNU Library General Public License as published |
|
7 by the Free Software Foundation; either version 2, or (at your option) |
|
8 any later version. |
|
9 |
|
10 This program is distributed in the hope that it will be useful, |
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 Library General Public License for more details. |
|
14 |
|
15 You should have received a copy of the GNU Library General Public |
|
16 License along with this program; if not, write to the Free Software |
|
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
|
18 USA. */ |
|
19 |
|
20 /* Written by Bruno Haible <haible@clisp.cons.org>. */ |
|
21 |
|
22 #ifdef HAVE_CONFIG_H |
|
23 # include <config.h> |
|
24 #endif |
|
25 |
|
26 #if HAVE_STDDEF_H |
|
27 # include <stddef.h> |
|
28 #endif |
|
29 |
|
30 #include <stdio.h> |
|
31 |
|
32 #if HAVE_ICONV |
|
33 # include <iconv.h> |
|
34 /* Name of UCS-4 encoding with machine dependent endianness and alignment. */ |
|
35 # ifdef _LIBICONV_VERSION |
|
36 # define UCS4_NAME "UCS-4-INTERNAL" |
|
37 # else |
|
38 # define UCS4_NAME "INTERNAL" |
|
39 # endif |
|
40 #endif |
|
41 |
|
42 #include <error.h> |
|
43 |
|
44 #if ENABLE_NLS |
|
45 # include <libintl.h> |
|
46 # define _(Text) gettext (Text) |
|
47 #else |
|
48 # define _(Text) Text |
|
49 #endif |
|
50 |
|
51 #include "unicodeio.h" |
|
52 |
|
53 /* Use md5.h for its nice detection of unsigned 32-bit type. */ |
|
54 #include "md5.h" |
|
55 #undef uint32_t |
|
56 #define uint32_t md5_uint32 |
|
57 |
|
58 /* Outputs the Unicode character CODE to the output stream STREAM. |
|
59 Assumes that the locale doesn't change between two calls. */ |
|
60 void |
|
61 print_unicode_char (FILE *stream, unsigned int code) |
|
62 { |
|
63 #if HAVE_ICONV |
|
64 static int initialized; |
|
65 static iconv_t ucs4_to_local; |
|
66 |
|
67 uint32_t in; |
|
68 char outbuf[25]; |
|
69 const char *inptr; |
|
70 size_t inbytesleft; |
|
71 char *outptr; |
|
72 size_t outbytesleft; |
|
73 size_t res; |
|
74 |
|
75 if (!initialized) |
|
76 { |
|
77 extern const char *locale_charset (void); |
|
78 const char *charset = locale_charset (); |
|
79 |
|
80 ucs4_to_local = (charset != NULL |
|
81 ? iconv_open (charset, UCS4_NAME) |
|
82 : (iconv_t)(-1)); |
|
83 if (ucs4_to_local == (iconv_t)(-1)) |
|
84 { |
|
85 /* For an unknown encoding, assume ASCII. */ |
|
86 ucs4_to_local = iconv_open ("ASCII", UCS4_NAME); |
|
87 if (ucs4_to_local == (iconv_t)(-1)) |
|
88 error (1, 0, _("cannot output U+%04X: iconv function not usable"), |
|
89 code); |
|
90 } |
|
91 initialized = 1; |
|
92 } |
|
93 |
|
94 in = code; |
|
95 inptr = (char *) ∈ |
|
96 inbytesleft = sizeof (in); |
|
97 outptr = outbuf; |
|
98 outbytesleft = sizeof (outbuf); |
|
99 |
|
100 /* Convert the character. */ |
|
101 res = iconv (ucs4_to_local, &inptr, &inbytesleft, &outptr, &outbytesleft); |
|
102 if (inbytesleft > 0 || res == (size_t)(-1)) |
|
103 error (1, res == (size_t)(-1) ? errno : 0, |
|
104 _("cannot convert U+%04X to local character set"), code); |
|
105 |
|
106 /* Avoid glibc-2.1 bug. */ |
|
107 # if defined _LIBICONV_VERSION || !(__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) |
|
108 |
|
109 /* Get back to the initial shift state. */ |
|
110 res = iconv (ucs4_to_local, NULL, NULL, &outptr, &outbytesleft); |
|
111 if (res == (size_t)(-1)) |
|
112 error (1, errno, _("cannot convert U+%04X to local character set"), code); |
|
113 |
|
114 # endif |
|
115 |
|
116 fwrite (outbuf, 1, outptr - outbuf, stream); |
|
117 |
|
118 #else |
|
119 error (1, 0, _("cannot output U+%04X: iconv function not available"), code); |
|
120 #endif |
|
121 } |