Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
mbsrtowcs.cpp
Go to the documentation of this file.
1
31#include <cassert> // for assert()
32#include <cerrno> // for EILSEQ, errno
33#include <cstring> // for strlen()
34#include <cwchar> // for mbstate_t
35#include <ios> // for hex
36#include <iostream> // for cout
37#include <locale> // for codecvt, locale
38
39#include <examples.h>
40
41
42// my_mbsrtowcs() behaves
43std::size_t
44my_mbsrtowcs (std::mbstate_t *pstate,
45 wchar_t *dst,
46 const char *src,
47 std::size_t size)
48{
49 const std::locale global;
50
51 typedef std::codecvt<wchar_t, char, std::mbstate_t> CodeCvt;
52
53 // retrieve the codecvt facet from the global locale
54 const CodeCvt &cvt = std::use_facet<CodeCvt>(global);
55
56 // use a small local buffer when dst is null and ignore size
57 wchar_t buf [4];
58 if (0 == dst) {
59 dst = buf;
60 size = sizeof buf / sizeof *buf;
61 }
62
63 // set up pointers into the source sequence
64 const char* from = src;
65 const char* const from_end = from + std::strlen (from);
66 const char* from_next = from;
67
68 // set up pointers into the destination sequence
69 wchar_t* to = dst;
70 wchar_t* const to_end = to + size;
71 wchar_t* to_next;
72
73 // number of non-NUL wide characters stored in destination buffer
74 std::size_t nconv = 0;
75
76 // use a local state when pstate is null (i.e., emulate mbstowcs)
77 std::mbstate_t state = std::mbstate_t ();
78 if (0 == pstate)
79 pstate = &state;
80
81 for ( ; from_next != from_end && to != to_end;
82 from = from_next, to = dst == buf ? dst : to_next) {
83
84 // convert a (sub)sequence of the source buffer into
85 // the destination buffer
86 const std::codecvt_base::result res =
87 cvt.in (*pstate,
88 from, from_end, from_next,
89 to, to_end, to_next);
90
91 // verify the consistency of the xxx_next pointers
92 assert (from <= from_next && from_next <= from_end);
93 assert (to <= to_next && to_next <= to_end);
94
95 // process conversion result
96 switch (res) {
97
98 case std::codecvt_base::error:
99 // conversion error
100 errno = EILSEQ;
101 return std::size_t (-1);
102
103 case std::codecvt_base::noconv:
104 // only codecvt<T, T> (i.e., facets where intern_type and
105 // extern_type are identical) is allowed to return noconv
106 // treat this case as an error even though it indicates
107 // a bad (incorrectly implemented) codecvt facet
108 return std::size_t (-1);
109
110 case std::codecvt_base::partial:
111 // partial conversion (incomplete character or not enough
112 // room in destination buffer to convert the entire source
113 // sequence)
114 if (dst != buf || std::size_t (to_next - to) < size) {
115 errno = EILSEQ;
116 return std::size_t (-1);
117 }
118
119 nconv += to_next - to;
120 break;
121
122 case std::codecvt_base::ok:
123 // complete conversion of an initial subsequence (but not
124 // necessarily all) of the source buffer
125 nconv += to_next - to;
126
127 if (dst == buf && from_next == from_end)
128 return nconv;
129
130 break;
131 }
132 }
133
134 return nconv;
135}
136
137
138int main ()
139{
140 static const char* const mbs [] = {
141 "a", "abc",
142 // <U0391>: Greek letter Alpha
143 "\xce\x91",
144 // <U0391><U0392>: Greek letters Alpha Beta
145 "\xce\x91\xce\x92",
146 // <U0391><U0392><U0393>: Greek letters Alpha Beta Gamma
147 "\xce\x91\xce\x92\xce\x93",
148 // <U0966>: Devangari digit 0
149 "\xe0\xa5\xa6",
150 // <U0967><U0966>: Devangari digits 10
151 "\xe0\xa5\xa7\xe0\xa5\xa6",
152 // <U0968><U0967><U0966>: Devangari digits 210
153 "\xe0\xa5\xa8\xe0\xa5\xa7\xe0\xa5\xa6"
154 };
155
156 typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> CodeCvt;
157
158 // create a UCS/UTF-8 codecvt facet and install it in a locale
159 const std::locale utf (std::locale (""), new CodeCvt ("UTF-8@UCS"));
160
161 // set the global locale to use the UCS/UTF-8 codecvt facet
162 std::locale::global (utf);
163
164 // iterate over examples of UTF-8 sequences and output the wide
165 // character sequence each converts to
166 for (std::size_t i = 0; i != sizeof mbs / sizeof *mbs; ++i) {
167
168 wchar_t *dst = 0;
169
170 // initialize state to the initial shift state
171 std::mbstate_t state = std::mbstate_t ();
172
173 // obtain the length of the wide character sequence
174 // corresponding to the multibyte source sequence,
175 // not including the terminating NUL
176 const std::size_t length =
177 my_mbsrtowcs (&state, 0, mbs [i], std::size_t (-1));
178
179 if (std::size_t (-1) == length) {
180 std::cerr << "Error computing length of destination sequence.\n";
181 continue;
182 }
183
184 // allocate a wide character buffer large enough to hold
185 // the converted sequence including the terminating NUL
186 dst = new wchar_t [length + 1];
187
188 // reset state to the initial shift state
189 state = std::mbstate_t ();
190
191 // convert the narrow character source sequence into
192 // the wide character buffer
193 const std::size_t nconv =
194 my_mbsrtowcs (&state, dst, mbs [i], length + 1);
195
196 if (length != nconv) {
197 std::cerr << "Error converting source sequence.\n";
198 continue;
199 }
200
201 // NUL-terminate the converted string
202 dst [nconv] = L'\0';
203
204 // write out the wide and the narrow sequences
205 std::cout << "UCS-2 (" << std::dec << length << "): " << std::hex;
206
207 for (const wchar_t *pwc = dst; *pwc != L'\0'; ++pwc)
208 std::cout << "U+" << unsigned (*pwc) << ' ';
209
210 std::cout << " ==> UTF-8: ";
211
212 typedef unsigned char UChar;
213
214 for (const char *pc = mbs [i]; *pc; ++pc)
215 std::cout << "\\x" << int (UChar (*pc));
216
217 std::cout << "\"\n";
218
219 delete[] dst;
220 }
221
222 return 0;
223}
#define i
Definition 17.names.cpp:126
#define res
Definition 17.names.cpp:531
#define buf
Definition 17.names.cpp:452
#define EILSEQ
#define assert(expr)
Definition _cassert.h:40
int main()
std::size_t my_mbsrtowcs(std::mbstate_t *pstate, wchar_t *dst, const char *src, std::size_t size)
Definition mbsrtowcs.cpp:44
unsigned char UChar
Definition collate.cpp:122