Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
22.locale.codecvt.out.cpp
Go to the documentation of this file.
1
29#ifdef __SUNPRO_CC
30 // working around a SunPro/SunOS bug (PR #26255)
31# include <time.h>
32#endif // __SUNPRO_CC
33
34#include <locale> // for codecvt
35
36#include <climits> // for MB_LEN_MAX
37#include <clocale> // for LC_CTYPE, setlocale()
38#include <cstdlib> // for MB_CUR_MAX, free(), size_t
39#include <cstring> // for strcpy(), strlen()
40#include <cwchar> // for codecvt
41
42#include <rw_driver.h> // for rw_test(), ...
43#include <rw_file.h> // for rw_fwrite()
44#include <rw_locale.h> // for rw_locales(), rw_set_locale_root()
45#include <rw_printf.h> // for rw_sprintf()
46#include <rw_valcmp.h> // for rw_strcmp()
47
48
50// the root of the locale directory (RWSTD_LOCALE_ROOT)
51// set in main() instead of here to avoid Solaris 7 putenv() bug (PR #30017)
52const char* locale_root /* = set in main() */;
53
54
55// creates a table-based multibyte locale
56static const char*
58{
59 char cm_fname [1024];
60 if (rw_snprintf (cm_fname, sizeof cm_fname, "%s%c%s",
61 locale_root, _RWSTD_PATH_SEP, "charmap") < 0)
62 return 0;
63
64 static const char charmap[] = {
65 "<code_set_name> test_charmap \n"
66 "<comment_char> % \n"
67 "<escape_char> / \n"
68 "<mb_cur_min> 1 \n"
69 "<mb_cur_max> 9 \n"
70 "CHARMAP \n"
71 "<U0000> /x30 0 \n"
72 "<U0001> /x31 1 \n"
73 "<U0002> /x32/x32 22 \n"
74 "<U0003> /x33/x33/x33 333 \n"
75 "<U0004> /x34/x34/x34/x34 4444 \n"
76 "<U0005> /x35/x35/x35/x35/x35 55555 \n"
77 "<U0006> /x36/x36/x36/x36/x36/x36 666666 \n"
78 "<U0007> /x37/x37/x37/x37/x37/x37/x37 7777777 \n"
79 "<U0008> /x38/x38/x38/x38/x38/x38/x38/x38 88888888 \n"
80 "<U0009> /x39/x39/x39/x39/x39/x39/x39/x39/x39 999999999 \n"
81 "<U0010> /x41 A \n"
82 "<U0011> /x42 B \n"
83 "<U0012> /x43 C \n"
84 "<U0013> /x44 D \n"
85 "<U0014> /x45 E \n"
86 "<U0015> /x46 F \n"
87 "END CHARMAP \n"
88 };
89
90 if (std::size_t (-1) == rw_fwrite (cm_fname, charmap))
91 return 0;
92
93 char src_fname [1024];
94 if (rw_snprintf (src_fname, sizeof src_fname, "%s%c%s",
95 locale_root, _RWSTD_PATH_SEP, "source") < 0)
96 return 0;
97
98 if (std::size_t (-1) == rw_fwrite (src_fname, "LC_CTYPE\nEND LC_CTYPE\n"))
99 return 0;
100
101 // invoke localedef to create the named locale
102 // silence the following warnings:
103 // 701: no compatible locale found
104 // 702: member of portable character set <x> not found
105 // in the character map
106 // 706: iconv_open() failed
107 const char* const locname =
108 rw_localedef ("-w701 -w702 -w706",
109 src_fname, cm_fname, "mb_cur_max-9");
110
111 return locname;
112}
113
114
116// finds a multibyte character that is `bytes' long if `bytes' is less
117// than or equal to MB_CUR_MAX, or the longest multibyte sequence in
118// the current locale, and sets `wchar' to the wide character that
119// corresponds to it
120// returns `mbchar' on success, 0 on failure to find a multibute
121// character of the specified length
122static const char*
123get_mb_char (wchar_t *wchar, char *mbchar, std::size_t bytes)
124{
125 RW_ASSERT (0 != wchar);
126 RW_ASSERT (0 != mbchar);
127
128 *mbchar = '\0';
129
130 if (0 == bytes)
131 return mbchar;
132
133 const bool exact = bytes <= MB_CUR_MAX;
134
135 if (!exact)
137
138 wchar_t wc;
139
140 // search the first 64K characters sequentially
141 for (wc = wchar_t (1); wc != wchar_t (0xffff); ++wc) {
142
143 if ( int (bytes) == std::wctomb (mbchar, wc)
144 && int (bytes) == std::mblen (mbchar, bytes)) {
145 // NUL-terminate the multibyte character of the requested length
146 mbchar [bytes] = '\0';
147 *wchar = wc;
148 break;
149 }
150
151 *mbchar = '\0';
152 }
153
154#if 2 < _RWSTD_WCHAR_SIZE
155
156 // if a multibyte character of the requested size is not found
157 // in the low 64K range, try to find one using a random search
158 if (wchar_t (0xffff) == wc) {
159
160 // iterate only so many times to prevent an infinite loop
161 // in case when MB_CUR_MAX is greater than the longest
162 // multibyte character
163 for (int i = 0; i != 0x100000; ++i) {
164
165 wc = 0;
166
167 typedef unsigned char UChar;
168
169 // set wc to a random value (rand() returns a value
170 // less than or equal to RAND_MAX so the loop makes
171 // sure all bits are initialized)
172 for (int j = 0; j < int (sizeof wc); ++j) {
173 wc <<= 8;
174 wc |= wchar_t (UChar (std::rand ()));
175 }
176
177 if ( int (bytes) == std::wctomb (mbchar, wc)
178 && int (bytes) == std::mblen (mbchar, bytes)) {
179 // NUL-terminate the multibyte character
180 mbchar [bytes] = '\0';
181 *wchar = wc;
182 break;
183 }
184
185 *mbchar = '\0';
186 }
187 }
188
189#endif // 2 < _RWSTD_WCHAR_SIZE
190
191 // return 0 on failure to find a sequence exactly `bytes' long
192 return !exact || bytes == std::strlen (mbchar) ? mbchar : 0;
193}
194
195
198{
199 wchar_t wchar;
200 char mbchar [MB_LEN_MAX + 1];
201};
202
204
205// fills consecutive elemenets of the `mb_chars' array with wide
206// and multibyte characters between 1 and MB_CUR_MAX bytes long
207// for the given locale returns the number of elements populated
208// (normally, MB_CUR_MAX)
209static std::size_t
210get_mb_chars (mb_char_array_t mb_chars)
211{
212 RW_ASSERT (0 != mb_chars);
213
214 const char* mbc =
215 get_mb_char (&mb_chars [0].wchar,
216 mb_chars [0].mbchar,
217 std::size_t (-1));
218
219 if (!mbc) {
220 rw_fprintf (rw_stderr, "*** unable to find any multibyte characters "
221 "in locale \"%s\" with MB_CUR_MAX = %u\n",
222 std::setlocale (LC_CTYPE, 0),
223 unsigned (MB_CUR_MAX));
224 return 0;
225 }
226
227 std::size_t mb_cur_max = std::strlen (mbc);
228
229 if (MB_LEN_MAX < mb_cur_max)
230 mb_cur_max = MB_LEN_MAX;
231
232 // fill each element of `mb_chars' a multibyte character
233 // of the corresponding length
234 for (std::size_t i = mb_cur_max; i; --i) {
235
236 const std::size_t inx = i - 1;
237
238 // try to generate a multibyte character `i' bytes long
239 mbc = get_mb_char (&mb_chars [inx].wchar, mb_chars [inx].mbchar, i);
240
241 if (0 == mbc) {
242 if (i < mb_cur_max) {
243 rw_fprintf (rw_stderr, "*** unable to find %zu-byte characters"
244 " in locale \"%s\" with MB_CUR_MAX = %u\n",
245 i + 1, std::setlocale (LC_CTYPE, 0),
246 unsigned (MB_CUR_MAX));
247 mb_cur_max = 0;
248 break;
249 }
250 --mb_cur_max;
251 }
252 }
253
254 return mb_cur_max;
255}
256
257
259// finds the multibyte locale with the largest MB_CUR_MAX value and
260// fills consecutive elemenets of the `mb_chars' array with multibyte
261// characters between 1 and MB_CUR_MAX bytes long for such a locale
262static const char*
263find_mb_locale (std::size_t *mb_cur_max, mb_char_array_t mb_chars)
264{
265 RW_ASSERT (0 != mb_cur_max);
266 RW_ASSERT (0 != mb_chars);
267
268 if (2 > MB_LEN_MAX) {
269 rw_fprintf (rw_stderr, "MB_LEN_MAX = %d, giving up\n", MB_LEN_MAX);
270 return 0;
271 }
272
273 static const char *mb_locale_name;
274
275 char saved_locale_name [1024];
276 std::strcpy (saved_locale_name, std::setlocale (LC_CTYPE, 0));
277
278 *mb_cur_max = 0;
279
280 // iterate over all installed locales
281 for (const char *name = rw_locales (); name && *name;
282 name += std::strlen (name) + 1) {
283
284 if (std::setlocale (LC_CTYPE, name)) {
285
286 // try to generate a set of multibyte characters
287 // with lengths from 1 and MB_CUR_MAX (or less)
288 const std::size_t cur_max = get_mb_chars (mb_chars);
289
290 if (*mb_cur_max < cur_max) {
291 *mb_cur_max = cur_max;
292 mb_locale_name = name;
293
294 // break when we've found a multibyte locale
295 // with the longest possible encoding
296 if (MB_LEN_MAX == *mb_cur_max)
297 break;
298 }
299 }
300 }
301
302 if (*mb_cur_max < 2) {
303 rw_fprintf (rw_stderr, "*** unable to find a full set of multibyte "
304 "characters in locale \"%s\" with MB_CUR_MAX = %u "
305 "(computed)", mb_locale_name, *mb_cur_max);
306 mb_locale_name = 0;
307 }
308 else {
309 // (re)generate the multibyte characters for the saved locale
310 // as they may have been overwritten in subsequent iterations
311 // of the loop above (while searching for a locale with greater
312 // value of MB_CUR_MAX)
313 std::setlocale (LC_CTYPE, mb_locale_name);
314 get_mb_chars (mb_chars);
315 }
316
317 std::setlocale (LC_CTYPE, saved_locale_name);
318
319 return mb_locale_name;
320}
321
322
324inline const char* codecvt_result (std::codecvt_base::result res)
325{
326 return std::codecvt_base::error == res ? "error"
327 : std::codecvt_base::ok == res ? "ok"
328 : std::codecvt_base::partial == res ? "partial"
329 : "noconv";
330}
331
332
333template <class internT>
334void test_out (int line,
335 const char* tname,
336 const std::mbstate_t *pstate,
337 const std::codecvt<internT, char, std::mbstate_t> &cvt,
338 const internT *src,
339 std::size_t src_len,
340 std::size_t src_off,
341 const char *res,
342 std::size_t res_len,
343 std::size_t res_off,
344 std::codecvt_base::result result)
345{
346 static const std::mbstate_t initial_state = std::mbstate_t ();
347
348 std::mbstate_t state = pstate ? *pstate : initial_state;
349
350 // create and invalidate a buffer for the destination sequence
351 char buf [1024];
352 std::memset (buf, -1, sizeof buf);
353
354 // set up from, from_end, and from_next arguments
355 const internT* const from = src;
356 const internT* const from_end = from + src_len;
357 const internT* from_next = 0;
358
359 // set up to, to_end, and to_next arguments
360 char* const to = buf;
361 char* const to_end = to + res_len;
362 char* to_next = 0;
363
364 // call codecvt::out () with the arguments above
365 const std::codecvt_base::result cvtres =
366 cvt.out (state,
367 from, from_end, from_next,
368 to, to_end, to_next);
369
370 // format a string describing the function call above
371 static char fcall [4096];
372 std::memset (fcall, 0, sizeof fcall);
373
374 rw_sprintf (fcall,
375 "codecvt<%s, char, mbstate_t>::out(state, "
376 "from = %{*.*Ac}, from + %td, from + %td, "
377 "to = %{#*s}, to + %d, to + %d)",
378 tname, int (sizeof *from), int (src_len), from,
379 from_end - from, from_next - from,
380 int (to_next - to), to, to_end - to, to_next - to);
381
382 RW_ASSERT (std::strlen (fcall) < sizeof fcall);
383
384 // verify the expected result of the conversion
385 rw_assert (cvtres == result, __FILE__, line,
386 "line %d: %s == %s, got %s",
387 __LINE__, fcall,
389 codecvt_result (cvtres));
390
391 // verify that the from_next pointer is set just past the last
392 // successfully converted character in the source sequence
393 rw_assert (from_next == from + src_off, __FILE__, line,
394 "line %d: %s: from_next == from + %d, got from + %d",
395 __LINE__, fcall,
396 src_off, from_next - from);
397
398 // verify that the to_next pointer is set just past the last
399 // external character in the converted (destination) sequence
400 rw_assert (to_next == to + res_off, __FILE__, line,
401 "line %d: %s: to_next == to + %d, got to + %d",
402 __LINE__, fcall,
403 res_off, to_next - to);
404
405 // compare the converted sequence against the expected result
406 rw_assert (0 == rw_strncmp (to, res, res_off), __FILE__, line,
407 "line %d: %s: expected %{#*s}, got %{#*s}",
408 __LINE__, fcall,
409 int (res_off), res, int (to_next - to), to);
410
411 // verify that the function didn't write past the end
412 // of the destination buffer
413 rw_assert (char (-1) == to [res_off], 0, line,
414 "line %d: %s: expected %{#lc}, got %{#lc} "
415 "at end of destination buffer (offset %zu)",
416 __LINE__, fcall,
417 -1, to [res_off], res_off);
418
419 // verify that the conversion state is as expected
420 rw_assert (!pstate || !std::memcmp (pstate, &state, sizeof state),
421 __FILE__, line,
422 "line %d: %s: unexpected conversion state",
423 __LINE__, fcall);
424}
425
426
428typedef std::codecvt<char, char, std::mbstate_t> Codecvt;
429typedef std::codecvt_byname<char, char, std::mbstate_t> CodecvtByname;
430
431
432static void
433test_codecvt (const Codecvt *pcvt = 0)
434{
435 if (0 == pcvt)
436 rw_info (0, 0, __LINE__,
437 "std::codecvt<char, char, mbstate_t>::out("
438 "state_type&, "
439 "const intern_type*, const intern_type*, "
440 "const intern_type*, "
441 "extern_type*, extern_type*, exterm_type*&)");
442
443 const std::locale classic = std::locale::classic ();
444
445 const Codecvt &cvt = pcvt ? *pcvt : std::use_facet<Codecvt>(classic);
446
447#undef TEST
448#define TEST(from, from_end_off, from_next_off, \
449 res, res_end_off, res_next_off, result) \
450 test_out (__LINE__, "char", 0, cvt, \
451 from, from_end_off, from_next_off, \
452 res, res_end_off, res_next_off, \
453 std::codecvt_base::result)
454
455 // +---------------------------- source sequence before conversion
456 // | +--------------------- (from_end - from) before conversion
457 // | | +------------------ (from_next - from) after conversion
458 // | | | +--------------- destination sequence after conversion
459 // | | | | +-------- (to_end - to) before conversion
460 // | | | | | +----- (to_next - to) after conversion
461 // | | | | | | +-- conversion result
462 // | | | | | | |
463 // V V V V V V V
464 TEST ("", 0, 0, "", 0, 0, noconv);
465 TEST ("a", 1, 0, "", 0, 0, noconv);
466 TEST ("b", 1, 0, "", 1, 0, noconv);
467 TEST ("ab", 2, 0, "", 0, 0, noconv);
468 TEST ("bc", 2, 0, "", 1, 0, noconv);
469 TEST ("cd", 2, 0, "", 2, 0, noconv);
470 TEST ("abc", 3, 0, "", 0, 0, noconv);
471 TEST ("\0", 1, 0, "", 0, 0, noconv);
472}
473
474
476static void
477test_codecvt_byname ()
478{
479 rw_info (0, 0, __LINE__,
480 "std::codecvt_byname<char, char, mbstate_t>::out("
481 "state_type&, const intern_type*, const intern_type*, "
482 "const intern_type*, "
483 "extern_type*, extern_type*, exterm_type*&)");
484
485 const CodecvtByname cvt ("");
486
487 test_codecvt (&cvt);
488}
489
490
492#ifndef _RWSTD_NO_WCHAR_T
493
494typedef std::codecvt<wchar_t, char, std::mbstate_t> WCodecvt;
495typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> WCodecvtByname;
496
497
498static void
499test_wcodecvt ()
500{
501 rw_info (0, 0, __LINE__,
502 "std::codecvt<wchar_t, char, mbstate_t>::out("
503 "state_type&, "
504 "const intern_type*, const intern_type*, "
505 "const intern_type*, "
506 "extern_type*, extern_type*, exterm_type*&)");
507
508 const std::locale classic = std::locale::classic ();
509
510 const WCodecvt &cvt = std::use_facet<WCodecvt>(classic);
511
512#undef TEST
513#define TEST(from, from_end_off, from_next_off, \
514 res, res_end_off, res_next_off, result) \
515 test_out (__LINE__, "wchar_t", 0, cvt, \
516 from, from_end_off, from_next_off, \
517 res, res_end_off, res_next_off, \
518 std::codecvt_base::result)
519
520 // +------------------------------- source sequence before conversion
521 // | +---------------------- (from_end - from) before conversion
522 // | | +------------------- (from_next - from) after conversion
523 // | | | +---------------- destination sequence
524 // | | | | +-------- (to_end - to) before conversion
525 // | | | | | +----- (to_next - to) after conversion
526 // | | | | | | +-- conversion result
527 // | | | | | | |
528 // V V V V V V V
529 TEST (L"", 0, 0, "", 0, 0, ok);
530 TEST (L"a", 1, 1, "a", 1, 1, ok);
531 TEST (L"ab", 2, 2, "ab", 2, 2, ok);
532 TEST (L"abc", 3, 3, "abc", 3, 3, ok);
533 TEST (L"\0", 1, 1, "\0", 1, 1, ok);
534 TEST (L"\x80", 1, 1, "\x80", 1, 1, ok);
535 TEST (L"\xff", 1, 1, "\xff", 1, 1, ok);
536 TEST (L"a\0", 2, 2, "a\0", 2, 2, ok);
537 TEST (L"a\0b", 3, 3, "a\0b", 3, 3, ok);
538 TEST (L"\0\0", 2, 2, "\0\0", 2, 2, ok);
539
540 TEST (L"123", 3, 0, "", 0, 0, partial);
541 TEST (L"234", 3, 1, "2", 1, 1, partial);
542 TEST (L"345", 3, 2, "34", 2, 2, partial);
543 TEST (L"456", 3, 3, "456", 3, 3, ok);
544 TEST (L"567", 3, 3, "567", 4, 3, ok);
545 TEST (L"6789", 3, 3, "678", 4, 3, ok);
546}
547
548
550// exercises an algorithmic multibyte encoding
551static void
552test_wcodecvt_byname_algorithmic ()
553{
554 rw_info (0, 0, __LINE__, "locale (\"UTF-8@UCS\") [algorithmic encoding]");
555
556 // lowercase utf ==> relaxed checking (i.e., some, but not all,
557 // invalid UTF-8 sequence are accepted)
558 const WCodecvtByname cvt_relaxd ("utf-8@UCS");
559
560 // capital UTF ==> strict checking
561 const WCodecvtByname cvt_strict ("UTF-8@UCS");
562
563#undef STRICT
564#define STRICT(from, from_end_off, from_next_off, \
565 res, res_end_off, res_next_off, result) \
566 test_out (__LINE__, "wchar_t", 0, cvt_strict, \
567 from, from_end_off, from_next_off, \
568 res, res_end_off, res_next_off, \
569 std::codecvt_base::result)
570
571#undef RELAXD
572#define RELAXD(from, from_end_off, from_next_off, \
573 res, res_end_off, res_next_off, result) \
574 test_out (__LINE__, "wchar_t", 0, cvt_relaxd, \
575 from, from_end_off, from_next_off, \
576 res, res_end_off, res_next_off, \
577 std::codecvt_base::result)
578
579#undef TEST
580#define TEST(from, from_end_off, from_next_off, \
581 res, res_end_off, res_next_off, result) \
582 STRICT (from, from_end_off, from_next_off, \
583 res, res_end_off, res_next_off, result); \
584 RELAXD (from, from_end_off, from_next_off, \
585 res, res_end_off, res_next_off, result)
586
587 // +------------------------------- source sequence before conversion
588 // | +---------------------- (from_end - from) before conversion
589 // | | +------------------- (from_next - from) after conversion
590 // | | | +---------------- destination sequence
591 // | | | | +-------- (to_end - to) before conversion
592 // | | | | | +----- (to_next - to) after conversion
593 // | | | | | | +-- conversion result
594 // | | | | | | |
595 // V V V V V V V
596 TEST (L"", 0, 0, "", 0, 0, ok);
597 TEST (L"a", 1, 1, "a", 1, 1, ok);
598 TEST (L"ab", 2, 2, "ab", 2, 2, ok);
599 TEST (L"abc", 3, 3, "abc", 3, 3, ok);
600 TEST (L"\0", 1, 1, "\0", 1, 1, ok);
601 TEST (L"a\0", 2, 2, "a\0", 2, 2, ok);
602 TEST (L"a\0b", 3, 3, "a\0b", 3, 3, ok);
603
604 TEST (L"123", 3, 0, "", 0, 0, partial);
605 TEST (L"234", 3, 1, "2", 1, 1, partial);
606 TEST (L"345", 3, 2, "34", 2, 2, partial);
607 TEST (L"456", 3, 3, "456", 3, 3, ok);
608 TEST (L"567", 3, 3, "567", 4, 3, ok);
609
610 // exercise multibyte sequences
611 TEST (L"\x100", 1, 0, "\xc4\x80", 0, 0, partial);
612 TEST (L"\x101", 1, 0, "\xc4\x81", 1, 0, partial);
613 TEST (L"\x102", 1, 1, "\xc4\x82", 2, 2, ok);
614
615 TEST (L"\x103x", 2, 0, "\xc4\x83", 0, 0, partial);
616 TEST (L"\x104y", 2, 1, "\xc4\x84", 2, 2, partial);
617 TEST (L"\x105z", 2, 2, "\xc4\x85z", 3, 3, ok);
618 TEST (L"\x106zz", 2, 2, "\xc4\x86z", 4, 3, ok);
619
620 TEST (L"\x0901", 1, 0, "\xe0\xa4\x81", 0, 0, partial);
621 TEST (L"\x0902", 1, 0, "\xe0\xa4\x82", 1, 0, partial);
622 TEST (L"\x0903", 1, 0, "\xe0\xa4\x83", 2, 0, partial);
623 TEST (L"\x0904", 1, 1, "\xe0\xa4\x84", 3, 3, ok);
624
625 TEST (L"\x0905\x0916", 2, 1, "\xe0\xa4\x85\xe0\xa4\x96", 4, 3, partial);
626 TEST (L"\x0906\x0917", 2, 1, "\xe0\xa4\x86\xe0\xa4\x97", 5, 3, partial);
627 TEST (L"\x0907\x0918", 2, 2, "\xe0\xa4\x87\xe0\xa4\x98", 6, 6, ok);
628
629 // U+D800 to U+DFFF (UTF-16 surrogates) as well as U+FFFE and U+FFFF
630 // must not occur in normal UCS-4 data and should be treated like
631 // malformed or overlong sequences.
632
633 STRICT (L"\xd800", 1, 0, "", 6, 0, error);
634 STRICT (L"\xd801", 1, 0, "", 6, 0, error);
635 STRICT (L"A\xd802", 2, 1, "A", 6, 1, error);
636 STRICT (L"AB\xd803", 3, 2, "AB", 6, 2, error);
637 STRICT (L"ABC\xd804", 4, 3, "ABC", 6, 3, error);
638 STRICT (L"\xdffe", 1, 0, "", 6, 0, error);
639 STRICT (L"\xdfff", 1, 0, "", 6, 0, error);
640
641 TEST (L"\xe000", 1, 1, "\xee\x80\x80", 6, 3, ok);
642 TEST (L"\xd7ff", 1, 1, "\xed\x9f\xbf", 6, 3, ok);
643
644 STRICT (L"\xd800", 1, 0, "", 6, 0, error);
645 STRICT (L"\xd801", 1, 0, "", 6, 0, error);
646 STRICT (L"\xdffe", 1, 0, "", 6, 0, error);
647 STRICT (L"\xdfff", 1, 0, "", 6, 0, error);
648
649 TEST (L"\xe000", 1, 1, "\xee\x80\x80", 6, 3, ok);
650
651 // verify that surrogate pairs are accepted in relaxed mode
652 RELAXD (L"\xd800", 1, 1, "\xed\xa0\x80", 6, 3, ok);
653 RELAXD (L"\xd801", 1, 1, "\xed\xa0\x81", 6, 3, ok);
654 RELAXD (L"\xdffe", 1, 1, "\xed\xbf\xbe", 6, 3, ok);
655 RELAXD (L"\xdfff", 1, 1, "\xed\xbf\xbf", 6, 3, ok);
656}
657
658
660// exercises a table-based multibyte encoding
661static void
662test_wcodecvt_byname_table_based ()
663{
664 // create a locale from a generated character set description file
665 // where L'\1' maps to "1", L'\2' to "22", ..., and L'\x10' to "A",
666 // L'\x11' to "B", L'\x12' to "C", etc.
667 const char* const locname = create_locale ();
668
669 if (!locname) {
670 rw_error (0, 0, __LINE__, "failed to create a locale database");
671 return;
672 }
673
674 std::locale loc;
675
676 _TRY {
677 loc = std::locale (locname);
678 }
679 _CATCH (...) {
680 rw_error (0, 0, __LINE__, "locale(\"%s\") unexpectedly threw", locname);
681 return;
682 }
683
684 const WCodecvt &cvt_table = std::use_facet<WCodecvt>(loc);
685
686 rw_info (0, 0, __LINE__, "locale (\"%s\") [table-based encoding]", locname);
687
688#undef TEST
689#define TEST(from, from_end_off, from_next_off, \
690 res, res_end_off, res_next_off, result) \
691 test_out (__LINE__, "wchar_t", 0, cvt_table, \
692 from, from_end_off, from_next_off, \
693 res, res_end_off, res_next_off, \
694 std::codecvt_base::result)
695
696 TEST (L"", 0, 0, "", 0, 0, ok);
697 TEST (L"\x10", 1, 1, "A", 1, 1, ok);
698 TEST (L"\x11\x12", 2, 2, "BC", 2, 2, ok);
699 TEST (L"\x12\x13\x14", 3, 3, "CDE", 3, 3, ok);
700
701 TEST (L"\1\2\3\4\5\6", 1, 1, "1", 21, 1, ok);
702 TEST (L"\1\2\3\4\5\6", 2, 1, "1", 1, 1, partial);
703 TEST (L"\1\2\3\4\5\6", 2, 1, "1", 2, 1, partial);
704 TEST (L"\1\2\3\4\5\6", 2, 2, "122", 3, 3, ok);
705 TEST (L"\1\2\3\4\5\6", 2, 2, "122", 21, 3, ok);
706 TEST (L"\1\2\3\4\5\6", 3, 2, "122", 3, 3, partial);
707 TEST (L"\1\2\3\4\5\6", 3, 2, "122", 4, 3, partial);
708 TEST (L"\1\2\3\4\5\6", 3, 2, "122", 5, 3, partial);
709 TEST (L"\1\2\3\4\5\6", 3, 3, "122333", 6, 6, ok);
710 TEST (L"\1\2\3\4\5\6", 4, 3, "122333", 7, 6, partial);
711 TEST (L"\1\2\3\4\5\6", 3, 3, "122333", 21, 6, ok);
712 TEST (L"\1\2\3\4\5\6", 4, 4, "1223334444", 21, 10, ok);
713 TEST (L"\1\2\3\4\5\6", 5, 5, "122333444455555", 21, 15, ok);
714 TEST (L"\6\5\4\3\2\1", 6, 3, "666666555554444", 15, 15, partial);
715 TEST (L"\6\5\4\3\2\1", 6, 3, "666666555554444", 16, 15, partial);
716
717 // exercise the ability to detect invalid characters (e.g., '*')
718 TEST (L"*\3\4\5\6\7", 6, 0, "", 27, 0, error);
719 TEST (L"\2*\4\5\6\7", 6, 0, "", 1, 0, partial);
720 TEST (L"\2*\4\5\6\7", 6, 1, "22", 2, 2, partial);
721 TEST (L"\2*\4\5\6\7", 6, 1, "22", 27, 2, error);
722 TEST (L"\2*\4\5\6\7", 6, 1, "22", 27, 2, error);
723 TEST (L"\2\3*\5\6\7", 6, 2, "22333", 27, 5, error);
724 TEST (L"\2\3\4*\6\7", 6, 3, "223334444", 27, 9, error);
725}
726
727
729static void
730make_strings (const char *pat, std::size_t patsize,
731 wchar_t *wstr, char *mbstr,
732 const mb_char_array_t mb_chars)
733{
734 RW_ASSERT (0 != pat);
735 RW_ASSERT (0 != wstr);
736 RW_ASSERT (0 != mbstr);
737 RW_ASSERT (0 != mb_chars);
738
739 typedef unsigned char UChar;
740
741 *mbstr = '\0';
742
743 for (const char *s = pat; s != pat + patsize; ++s, ++wstr) {
744
745 if ('%' == *s) {
746
747 ++s;
748
749 RW_ASSERT ('0' <= *s && *s <= char ('0' + MB_LEN_MAX));
750
751 std::size_t char_inx = *s - '0';
752
753 *wstr = mb_chars [char_inx].wchar;
754
755 std::strcpy (mbstr, mb_chars [char_inx].mbchar);
756 mbstr += std::strlen (mbstr);
757 }
758 else {
759 *wstr = UChar (*s);
760 *mbstr++ = *s;
761 *mbstr = '\0';
762 }
763 }
764
765 *wstr = L'\0';
766}
767
768
770// exercises a libc-based multibyte encoding
771static void
772test_wcodecvt_byname_libc_based ()
773{
774 // find `mb_cur_max' multibyte characters in increasing length
775 // from 1 to mb_cur_max bytes long
776
777 // i.e., initialize the first (N + 1) elements of mb_chars as follows:
778 // [0].mbstr = "0"; // where "0" is a single byte character
779 // [1].mbstr = "11"; // where "11" is a two-byte character
780 // [2].mbstr = "222"; // where "222" is a three-byte character
781 // ...
782 // [N].mbstr = "NNN...N"; // where "NNN...N" is an N-byte character
783
784 std::size_t mb_cur_max = 0;
785
786 mb_char_array_t mb_chars;
787
788 const char* const locname = find_mb_locale (&mb_cur_max, mb_chars);
789
790 if (0 == locname) {
791 rw_warn (0, 0, __LINE__, "unable to find a multibyte locale");
792 return;
793 }
794
795 std::locale loc;
796
797 _TRY {
798 loc = std::locale (locname);
799 }
800 _CATCH (...) {
801 rw_error (0, 0, __LINE__, "locale(\"%s\") unexpectedly threw", locname);
802 return;
803 }
804
805 const WCodecvt &cvt_libc = std::use_facet<WCodecvt>(loc);
806
807 rw_info (0, 0, __LINE__, "locale (\"%s\") [libc-based encoding, "
808 "single-byte characters]", locname);
809
811 // exercise sequences containing single-byte characters
812
813#undef TEST
814#define TEST(from, from_end_off, from_next_off, \
815 res, res_end_off, res_next_off, result) \
816 test_out (__LINE__, "wchar_t", 0, cvt_libc, \
817 from, from_end_off, from_next_off, \
818 res, res_end_off, res_next_off, \
819 std::codecvt_base::result)
820
821 // +----------------------------------- source sequence (from)
822 // | +------------------------ from_end offset from from
823 // | | +--------------------- expected from_next offset
824 // | | | +------------------ expected destination sequence
825 // | | | | +-------- to_end offset from to
826 // | | | | | +----- expected to_next offset
827 // | | | | | | +-- expected result (to)
828 // | | | | | | |
829 // V V V V V V V
830 TEST (L"", 0, 0, "", 0, 0, ok);
831 TEST (L"a", 1, 1, "a", 1, 1, ok);
832 TEST (L"b", 1, 1, "b", 2, 1, ok);
833 TEST (L"c", 1, 1, "c", 3, 1, ok);
834 TEST (L"d", 1, 1, "d", 4, 1, ok);
835 TEST (L"e", 1, 1, "e", 5, 1, ok);
836 TEST (L"f", 1, 1, "f", 6, 1, ok);
837 TEST (L"ab", 2, 2, "ab", 6, 2, ok);
838 TEST (L"abc", 3, 3, "abc", 6, 3, ok);
839 TEST (L"abcd", 4, 4, "abcd", 6, 4, ok);
840 TEST (L"abcde", 5, 5, "abcde", 6, 5, ok);
841 TEST (L"abcdef", 6, 6, "abcdef", 6, 6, ok);
842
843 TEST (L"\n", 1, 1, "\n", 1, 1, ok);
844 TEST (L"\n\377", 1, 1, "\n", 1, 1, ok);
845
846 // exercise embedded NULs
847 TEST (L"\0abcdef", 7, 7, "\0abcdef", 7, 7, ok);
848 TEST (L"a\0bcdef", 7, 7, "a\0bcdef", 7, 7, ok);
849 TEST (L"ab\0cdef", 7, 7, "ab\0cdef", 7, 7, ok);
850 TEST (L"abc\0def", 7, 7, "abc\0def", 7, 7, ok);
851 TEST (L"abcd\0ef", 7, 7, "abcd\0ef", 7, 7, ok);
852 TEST (L"abcde\0f", 7, 7, "abcde\0f", 7, 7, ok);
853 TEST (L"abcdef\0", 7, 7, "abcdef\0", 7, 7, ok);
854
855 TEST (L"ab\0cd\0ef", 8, 8, "ab\0cd\0ef", 8, 8, ok);
856
858 // exercise sequences containing 2-byte characters
859
860 if (mb_cur_max < 2) {
861 rw_warn (0, 0, __LINE__, "no multibyte characters found");
862 return;
863 }
864
865 size_t bufsize = 0;
866 char *sequences = 0;
867
868 // verify the length of each character
869 for (std::size_t i = 0; i < mb_cur_max; ++i) {
870 const std::size_t mb_len = std::strlen (mb_chars [i].mbchar);
871
872 if (i + 1 != mb_len) {
873 rw_assert (0, 0, __LINE__,
874 "unexpected multibyte character length: "
875 "%u, expected %u", mb_len, i + 1);
876 return;
877 }
878
879 rw_asnprintf (&sequences, &bufsize,
880 "%{+}%s{ %{#lc}, %{#s} }",
881 i ? ", " : "",
882 mb_chars [i].wchar,
883 mb_chars [i].mbchar);
884 }
885
886 rw_info (0, 0, __LINE__,
887 "locale (\"%s\") [libc-based encoding, "
888 "MB_CUR_MAX = %u, multi-byte characters: %s]",
889 locname, mb_cur_max, (const char*)sequences);
890
891 std::free (sequences);
892
893#ifdef _RWSTD_OS_SUNOS
894
895 if (0 == std::strcmp ("5.7", _RWSTD_OS_RELEASE)) {
896
897 rw_warn (0, 0, __LINE__, "skipping tests due to a SunOS 5.7 libc bug");
898 return;
899 }
900
901#endif // _RWSTD_OS_SUNOS
902
903 wchar_t wstr [256];
904 char mbstr [256];
905
906#undef TEST
907#define TEST(pat, from_end_off, from_next_off, \
908 res_end_off, res_next_off, result) \
909 make_strings (pat, sizeof pat - 1, \
910 wstr, mbstr, mb_chars); \
911 test_out (__LINE__, "wchar_t", 0, cvt_libc, \
912 wstr, from_end_off, from_next_off, \
913 mbstr, res_end_off, res_next_off, \
914 std::codecvt_base::result)
915
916 // %N for N in [0, MB_CUR_MAX) represents a wide character
917 // whose multibyte representation is (N + 1) bytes long
918 // any other (narrow) character, including the NUL, is
919 // widened to a wchar_t as if by an ordinary cast
920
921 // +------------------------------ source sequence (from)
922 // | +-------------- initial (from_end - from)
923 // | | +----------- expected (from_next - from)
924 // | | | +-------- initial (to_limit - to)
925 // | | | | +----- expected (to_next - to)
926 // | | | | | +-- expected conversion result
927 // | | | | | |
928 // V V V V V V
929 TEST ("%0", 0, 0, 0, 0, ok);
930 TEST ("%0", 1, 0, 0, 0, partial);
931 TEST ("%0", 1, 1, 1, 1, ok);
932 TEST ("%1", 1, 0, 0, 0, partial);
933 TEST ("%1", 1, 0, 1, 0, partial);
934 TEST ("%1", 1, 1, 2, 2, ok);
935
936 TEST ("a%1", 2, 1, 2, 1, partial);
937 TEST ("b%1", 2, 2, 3, 3, ok);
938
939 TEST ("%1%1", 2, 0, 1, 0, partial);
940 TEST ("%1%1", 2, 1, 2, 2, partial);
941 TEST ("%1%1", 2, 1, 3, 2, partial);
942 TEST ("%1%1", 2, 2, 4, 4, ok);
943
944 TEST ("%1X%1Y%1Z", 6, 0, 1, 0, partial);
945 TEST ("%1X%1Y%1Z", 6, 1, 2, 2, partial);
946 TEST ("%1X%1Y%1Z", 6, 2, 3, 3, partial);
947 TEST ("%1X%1Y%1Z", 6, 2, 4, 3, partial);
948 TEST ("%1X%1Y%1Z", 6, 3, 5, 5, partial);
949 TEST ("%1X%1Y%1Z", 6, 4, 6, 6, partial);
950 TEST ("%1X%1Y%1Z", 6, 4, 7, 6, partial);
951 TEST ("%1X%1Y%1Z", 6, 5, 8, 8, partial);
952 TEST ("%1X%1Y%1Z", 6, 6, 9, 9, ok);
953
954 // exercise embedded NULs
955 TEST ("\0", 1, 1, 1, 1, ok);
956 TEST ("\0X", 2, 2, 2, 2, ok);
957 TEST ("\0X\0", 3, 3, 3, 3, ok);
958 TEST ("\0X\0Y", 4, 4, 4, 4, ok);
959 TEST ("\0X\0Y\0", 5, 5, 5, 5, ok);
960 TEST ("\0X\0Y\0Z", 6, 6, 6, 6, ok);
961 TEST ("\0XYZ\0", 5, 5, 5, 5, ok);
962
963 TEST ("%1\0", 2, 2, 3, 3, ok);
964 TEST ("\0%1", 2, 2, 3, 3, ok);
965
966 TEST ("%1\0%1", 3, 3, 5, 5, ok);
967 TEST ("\0%1\0", 3, 3, 4, 4, ok);
968
969 TEST ("%1\0%1\0%1\0", 6, 2, 3, 3, partial);
970 TEST ("%1\0%1\0%1\0", 6, 3, 5, 5, partial);
971 TEST ("%1\0%1\0%1\0", 6, 4, 6, 6, partial);
972 TEST ("%1\0%1\0%1\0", 6, 5, 8, 8, partial);
973 TEST ("%1\0%1\0%1\0", 6, 6, 9, 9, ok);
974
975 // exercise consecutive embedded NULs
976 TEST ("\0\0%1\0\0%1\0\0", 8, 8, 10, 10, ok);
977 TEST ("\0\0\0\0\0\0\0XY", 9, 9, 9, 9, ok);
978
980 // exercise sequences containing 3-byte characters
981
982 if (mb_cur_max < 3)
983 return;
984
985 TEST ("%2", 1, 0, 0, 0, partial);
986 TEST ("%2", 1, 0, 1, 0, partial);
987 TEST ("%2", 1, 0, 2, 0, partial);
988 TEST ("%2", 1, 1, 3, 3, ok);
989
990 TEST ("%2%1", 2, 0, 0, 0, partial);
991 TEST ("%2%1", 2, 0, 1, 0, partial);
992 TEST ("%2%1", 2, 0, 2, 0, partial);
993 TEST ("%2%1", 2, 1, 3, 3, partial);
994 TEST ("%2%1", 2, 1, 4, 3, partial);
995 TEST ("%2%1", 2, 2, 5, 5, ok);
996
997 TEST ("%2%2", 2, 0, 0, 0, partial);
998 TEST ("%2%2", 2, 0, 1, 0, partial);
999 TEST ("%2%2", 2, 0, 2, 0, partial);
1000 TEST ("%2%2", 2, 1, 3, 3, partial);
1001 TEST ("%2%2", 2, 1, 4, 3, partial);
1002 TEST ("%2%2", 2, 1, 5, 3, partial);
1003 TEST ("%2%2", 2, 2, 6, 6, ok);
1004
1005 TEST ("%2%1%2", 3, 0, 0, 0, partial);
1006 TEST ("%2%1%2", 3, 0, 1, 0, partial);
1007 TEST ("%2%1%2", 3, 0, 2, 0, partial);
1008 TEST ("%2%1%2", 3, 1, 3, 3, partial);
1009 TEST ("%2%1%2", 3, 1, 4, 3, partial);
1010 TEST ("%2%1%2", 3, 2, 5, 5, partial);
1011 TEST ("%2%1%2", 3, 2, 6, 5, partial);
1012 TEST ("%2%1%2", 3, 2, 7, 5, partial);
1013 TEST ("%2%1%2", 3, 3, 8, 8, ok);
1014
1015 TEST ("%2%1%2%0%1%2$", 6, 6, 14, 14, ok);
1016
1017 // exercise embedded NULs
1018 TEST ("\0%2$", 2, 2, 4, 4, ok);
1019 TEST ("%2\0$", 2, 2, 4, 4, ok);
1020 TEST ("\0\0%2$", 3, 3, 5, 5, ok);
1021 TEST ("%2\0\0$", 3, 3, 5, 5, ok);
1022 TEST ("\0\0%2\0%2$", 5, 5, 9, 9, ok);
1023 TEST ("\0%2\0\0%2$", 5, 5, 9, 9, ok);
1024 TEST ("\0%2\0%2\0$", 5, 5, 9, 9, ok);
1025 TEST ("%2\0\0%2\0$", 5, 5, 9, 9, ok);
1026 TEST ("%2\0%2\0\0$", 5, 5, 9, 9, ok);
1027
1029 // exercise sequences containing 4-byte characters
1030
1031 if (mb_cur_max < 4)
1032 return;
1033
1034 TEST ("%3", 1, 0, 0, 0, partial);
1035 TEST ("%3", 1, 0, 1, 0, partial);
1036 TEST ("%3", 1, 0, 2, 0, partial);
1037 TEST ("%3", 1, 0, 3, 0, partial);
1038 TEST ("%3", 1, 1, 4, 4, ok);
1039
1040 TEST ("%3%3", 2, 0, 3, 0, partial);
1041 TEST ("%3%3", 2, 1, 4, 4, partial);
1042 TEST ("%3%3", 2, 1, 5, 4, partial);
1043 TEST ("%3%3", 2, 1, 6, 4, partial);
1044 TEST ("%3%3", 2, 1, 7, 4, partial);
1045 TEST ("%3%3", 2, 2, 8, 8, ok);
1046
1047 TEST ("%3G%3", 3, 2, 8, 5, partial);
1048 TEST ("%3G%3", 3, 3, 9, 9, ok);
1049
1050 TEST ("%3%1%3", 3, 2, 9, 6, partial);
1051 TEST ("%3%1%3", 3, 3, 10, 10, ok);
1052
1053 TEST ("%3%2%1%0%1%2%3", 7, 7, 19, 19, ok);
1054
1055 // 4+1+3+1+2+1+1+1+2+1+3+1+4 = 25 bytes (13 wchar_t)
1056 TEST ("%3\0%2\0%1\0%0\0%1\0%2\0%3$", 13, 13, 25, 25, ok);
1057 // 4+1+1+3+2+1+1+1+2+1+3+4+1 = 25 bytes (13 wchar_t)
1058 TEST ("%3\0\0%2%1\0%0\0%1\0%2%3\0$", 13, 13, 25, 25, ok);
1059 // 1+4+3+1+2+1+1+1+2+1+3+4+1 = 25 bytes (13 wchar_t)
1060 TEST ("\0%3%2\0%1\0\0%0%1\0%2%3\0$", 13, 13, 25, 25, ok);
1061 // 1+4+3+1+2+1+2+1+3+4+1+1+1 = 25 bytes (13 wchar_t)
1062 TEST ("\0%3%2\0%1%0%1\0%2%3\0\0\0$", 13, 13, 25, 25, ok);
1063 // 1+1+1+1+1+1+4+3+2+1+2+3+4 = 25 bytes (13 wchar_t)
1064 TEST ("\0\0\0\0\0\0%3%2%1%0%1%2%3$", 13, 13, 25, 25, ok);
1065}
1066
1067
1069static void
1070test_wcodecvt_byname ()
1071{
1072 rw_info (0, 0, __LINE__,
1073 "std::codecvt_byname<wchar_t, char, mbstate_t>::out("
1074 "state_type&, "
1075 "const intern_type*, const intern_type*, "
1076 "const intern_type*, "
1077 "extern_type*, extern_type*, exterm_type*&)");
1078
1079 test_wcodecvt_byname_algorithmic ();
1080 test_wcodecvt_byname_table_based ();
1081 test_wcodecvt_byname_libc_based ();
1082}
1083
1084#endif // _RWSTD_NO_WCHAR_T
1085
1086
1088static int
1089run_test (int, char**)
1090{
1091 // set up RWSTD_LOCALE_ROOT and other environment variables
1092 // here as opposed to at program startup to work around a
1093 // SunOS 5.7 bug in putenv() (PR #30017)
1095
1096 test_codecvt ();
1097 test_codecvt_byname ();
1098
1099#ifndef _RWSTD_NO_WCHAR_T
1100
1101 // exercise wchar_t specializations
1102 test_wcodecvt ();
1103 test_wcodecvt_byname ();
1104
1105#else // if defined (_RWSTD_NO_WCHAR_T)
1106
1107 rw_warn (0, 0, __LINE__, "_RWSTD_NO_WCHAR_T #defined, cannot test");
1108
1109#endif // _RWSTD_NO_WCHAR_T
1110
1111 return 0;
1112}
1113
1114
1116int main (int argc, char *argv[])
1117{
1118 return rw_test (argc, argv, __FILE__,
1119 "lib.locale.codecvt.virtuals",
1120 0 /* no comment */,
1121 run_test,
1122 "",
1123 (void*)0 /* sentinel */);
1124}
#define i
Definition 17.names.cpp:126
#define line
Definition 17.names.cpp:490
#define res
Definition 17.names.cpp:531
#define loc
Definition 17.names.cpp:492
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define s
#define inx
Definition 17.names.cpp:484
volatile int result
std::codecvt< char, char, std::mbstate_t > Codecvt
std::codecvt< wchar_t, char, std::mbstate_t > WCodecvt
std::codecvt_byname< wchar_t, char, std::mbstate_t > WCodecvtByname
const char * create_locale()
std::codecvt_byname< char, char, std::mbstate_t > CodecvtByname
void test_codecvt(const Codecvt *pcvt=0)
std::codecvt< char, char, std::mbstate_t > Codecvt
std::codecvt< wchar_t, char, std::mbstate_t > WCodecvt
std::codecvt_byname< wchar_t, char, std::mbstate_t > WCodecvtByname
const char * codecvt_result(std::codecvt_base::result res)
void test_out(int line, const char *tname, const std::mbstate_t *pstate, const std::codecvt< internT, char, std::mbstate_t > &cvt, const internT *src, std::size_t src_len, std::size_t src_off, const char *res, std::size_t res_len, std::size_t res_off, std::codecvt_base::result result)
#define STRICT(from, from_end_off, from_next_off, res, res_end_off, res_next_off, result)
WideCode mb_char_array_t[MB_LEN_MAX]
std::codecvt_byname< char, char, std::mbstate_t > CodecvtByname
#define RELAXD(from, from_end_off, from_next_off, res, res_end_off, res_next_off, result)
const char * locale_root
#define TEST(from, from_end_off, from_next_off, res, res_end_off, res_next_off, result)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
#define main
#define LC_CTYPE
unsigned short wchar_t
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define MB_CUR_MAX
#define _TRY
Definition _defs.h:850
#define _CATCH(ex)
Definition _defs.h:851
const char * name
Definition codecvt1.cpp:72
#define MB_LEN_MAX
Definition limits.h:100
UChar bytes[sizeof(int)]
Definition printf.cpp:83
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
Definition driver.cpp:1613
_TEST_EXPORT int rw_warn(int, const char *, int, const char *,...)
Definition driver.cpp:1647
_TEST_EXPORT _RWSTD_SIZE_T rw_fwrite(const char *, const void *, _RWSTD_SIZE_T=~0, const char *="w")
_TEST_EXPORT const char * rw_set_locale_root()
Definition locale.cpp:324
_TEST_EXPORT char * rw_locales(int=_UNUSED_CAT, const char *=0, bool=true)
Definition locale.cpp:368
_TEST_EXPORT const char * rw_localedef(const char *, const char *, const char *, const char *)
Definition locale.cpp:154
_TEST_EXPORT rw_file *const rw_stderr
Definition printf.cpp:3348
_TEST_EXPORT int rw_snprintf(char *, _RWSTD_SIZE_T, const char *,...)
_TEST_EXPORT int rw_sprintf(char *, const char *,...)
Definition printf.cpp:3284
_TEST_EXPORT int rw_fprintf(rw_file *, const char *,...)
Definition printf.cpp:3397
_TEST_EXPORT int rw_asnprintf(char **pbuf, _RWSTD_SIZE_T *pbufsize, const char *fmt,...)
#define RW_ASSERT(expr)
_TEST_EXPORT int rw_strncmp(const char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX, int=CMP_NULTERM)
unsigned char UChar
Definition collate.cpp:122
char mbchar[MB_LEN_MAX+1]