Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
insert_wchar.cpp
Go to the documentation of this file.
1
31#include <cassert> // for assert()
32#include <cwchar> // for mbstate_t, size_t
33#include <ios> // for hex
34#include <iostream> // for cout
35#include <locale> // for codecvt, isalnum(), locale
36#include <ostream> // for basic_ostream
37#include <sstream> // for ostringstream
38
39
40// inserts a wide character string into a stream buffer performing
41// codeset conversion if necessary
42template <class charT, class Traits>
43void
44streambuf_insert (std::basic_ostream<charT, Traits> &strm,
45 const wchar_t *s)
46{
47 typedef typename Traits::state_type StateT;
48 typedef std::codecvt<wchar_t, charT, StateT> Codecvt;
49
50 const Codecvt &cvt = std::use_facet<Codecvt>(strm.getloc ());
51
52 const std::size_t slen = std::char_traits<wchar_t>::length (s);
53
54 // perform codeset conversion in chunks to avoid dynamic
55 // memory allocation
56
57 const std::size_t xbufsize = 32;
58
59 charT xbuf [xbufsize];
60 charT* xbuf_end = xbuf + xbufsize;
61 charT* to_next = 0;
62 const wchar_t* from_next = 0;
63 const wchar_t* const end = s + slen;
64
65 StateT state = StateT ();
66
67 for (const wchar_t* base = s; from_next != end; base = from_next) {
68
69 const std::codecvt_base::result res =
70 cvt.out (state, base, end, from_next,
71 xbuf, xbuf_end, to_next);
72
73 std::streamsize nbytes = to_next - xbuf;
74
75 switch (res) {
76 case Codecvt::error:
77 // write out the sequence successfully converted up
78 // to the point of the error in the internal sequence
79 // and fail
80 strm.rdbuf ()->sputn (xbuf, nbytes);
81 strm.setstate (strm.badbit);
82
83 case Codecvt::noconv:
84 // write the entire sequence
85 if (nbytes != strm.rdbuf ()->sputn (xbuf, nbytes)) {
86 strm.setstate (strm.badbit);
87 return;
88 }
89
90 from_next = end; // effectively break
91 break;
92
93 default:
94 assert (cvt.ok == res || cvt.partial == res);
95
96 // partial conversion will result if there isn't enough
97 // space in the conversion buffer to hold the converted
98 // sequence, but we're O.K. since we'll be passing any
99 // remaining unconverted characters (starting at
100 // from_next) in the next iteration
101
102 nbytes = to_next - xbuf;
103
104 if (nbytes != strm.rdbuf ()->sputn (xbuf, nbytes)) {
105 strm.setstate (strm.badbit);
106 return;
107 }
108 }
109 }
110}
111
112
113// stream insertion operator overloaded for arrays of wchar_t characters
114template <class charT, class Traits>
115std::basic_ostream<charT, Traits>&
116operator<< (std::basic_ostream<charT, Traits> &strm,
117 const wchar_t *s)
118{
119 const typename std::basic_ostream<charT, Traits>::sentry opfx (strm);
120
121 if (opfx) {
122
123 try {
124 // try to insert character array into stream buffer
126 }
127 catch (...) {
128 bool threw;
129 try {
130 // set badbit on exception without throwing ios::failure
131 strm.setstate (strm.badbit);
132 threw = false;
133 }
134 catch (std::ios_base::failure&) {
135 // make a note of the exception thrown from setstate()...
136 threw = true;
137 }
138 if (threw) {
139 // ...and rethrow the original exception
140 throw;
141 }
142 }
143 }
144
145 return strm;
146}
147
148
149// examples of wide character strings
150static const wchar_t* const wcs [] = {
151 L"a", L"abc",
152 // Greek letter Alpha:
153 L"\x0391", // "\xce\x91"
154 // Greek letters Alpha Beta:
155 L"\x0391\x0392", // "\xce\x91\xce\x91\xce\x92"
156 // Greek letters Alpha Beta Gamma:
157 L"\x0391\x0392\x0393", // "\xce\x91\xce\x92\xce\x93"
158 // Tibetan digit zero:
159 L"\x0f20", // "\xe0\xbc\xa0"
160 // Tibetan digits one, zero:
161 L"\x0f21\x0f20", // "\xe0\xbc\xa1\xe0\xbc\xa0"
162 // Tibetan digits two, one, zero:
163 L"\x0f22\x0f21\x0f20" // "\xe0\xbc\xa2\xe0\xbc\xa1\xe0\xbc\xa0"
164};
165
166
167int main ()
168{
169 typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> Codecvt;
170
171 // create a UCS/UTF-8 codecvt facet and install it in a locale
172 const std::locale utf (std::cout.getloc (), new Codecvt ("UTF-8@UCS"));
173
174 for (std::size_t i = 0; i != sizeof wcs / sizeof *wcs; ++i) {
175
176 std::ostringstream strm;
177
178 // imbue the UTF-8/UCS capable locale in a stringstream
179 strm.imbue (utf);
180
181 // insert each wide character string into the narrow stream
182 // object relying on the inserter to convert each wide string
183 // into the corresponding multibyte character string
184 strm << wcs [i];
185
186 // write out the wide character string in Unicode notation
187 std::cout << "UCS-2: " << std::hex;
188
189 for (const wchar_t *pwc = wcs [i]; *pwc != L'\0'; ++pwc)
190 std::cout << "U+" << unsigned (*pwc) << ' ';
191
192 const std::string str = strm.str ();
193
194 std::cout << " ==> UTF-8: \"";
195
196 typedef unsigned char UChar;
197
198 // write out the the multibyte character sequence using
199 // ordinary aphanumeric symbols or hex escape sequences
200 // where necessary
201 for (const char *pc = str.c_str (); *pc != '\0'; ++pc) {
202
203 // parenthesize isalnum to prevent macro expension
204 // in case the function happens to be (illegally)
205 // shadowed by a macro
206 if ((std::isalnum)(*pc, std::cout.getloc ()))
207 std::cout << *pc;
208 else
209 std::cout << "\\x" << int (UChar (*pc));
210 }
211
212 std::cout << "\"\n";
213 }
214}
#define i
Definition 17.names.cpp:126
#define opfx
Definition 17.names.cpp:510
#define res
Definition 17.names.cpp:531
#define slen
Definition 17.names.cpp:545
#define charT
Definition 17.names.cpp:456
#define s
#define strm
Definition 17.names.cpp:549
std::codecvt< char, char, std::mbstate_t > Codecvt
const int end
#define assert(expr)
Definition _cassert.h:40
const char * str
Definition exec.cpp:170
void streambuf_insert(std::basic_ostream< charT, Traits > &strm, const wchar_t *s)
std::basic_ostream< charT, Traits > & operator<<(std::basic_ostream< charT, Traits > &strm, const wchar_t *s)
int main()
_RWSTD_MBSTATE_T StateT
Definition codecvt.cpp:68
unsigned char UChar
Definition collate.cpp:122