Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
22.locale.codecvt.cpp
Go to the documentation of this file.
1
29#ifdef __SUNPRO_CC
30 // working around a SunPro/SunOS 5.8 bug (PR #26255)
31# include <time.h>
32#endif // __SUNPRO_CC
33
34#include <locale>
35
36#include <cassert>
37#include <climits>
38#include <clocale>
39#include <csetjmp> // for longjmp(), setjmp(), ...
40#include <csignal> // for SIGABRT, signal()
41#include <cstdlib>
42#include <cstring>
43#include <cstdio>
44#include <cwchar> // for mbstate_t
45
46#include <sys/types.h>
47#include <sys/stat.h>
48
49#ifndef _WIN32
50# include <iconv.h> // for iconv(), iconv_open(), iconv_close()
51# include <langinfo.h> // for CODESET, nl_langinfo()
52# include <unistd.h>
53#else
54# include <direct.h>
55#endif
56
57#define DEFINE_REPLACEMENT_NEW_AND_DELETE
58#include <rw_driver.h>
59#include <rw_file.h>
60#include <rw_locale.h>
61
62#ifndef PATH_MAX
63# define PATH_MAX 1024
64#endif
65
66// No dependency on C library min/max
67#undef min
68#define min(a, b) ((a) < (b) ? (a) : (b))
69
70
72// mbs/wcs helper functions
73#if !defined _RWSTD_NO_WCHAR_T
74
75template <class T>
76/*static*/ std::size_t
77rwtest_mbstowcs (std::mbstate_t& state, T* pi,
78 const char* pe, std::size_t srclen)
79{
80# ifndef _RWSTD_NO_MBSRTOWCS
81
82 return std::mbsrtowcs (pi, &pe, srclen, &state);
83
84# else // if defined _RWSTD_NO_MBSRTOWCS
85
86 _RWSTD_UNUSED (state);
87 return std::mbstowcs (pi, pe, srclen);
88
89# endif // _RWSTD_NO_MBSRTOWCS
90}
91
92
94/*static*/ std::size_t
95rwtest_mbstowcs<char> (std::mbstate_t& /*unused*/, char* /*unused*/,
96 const char* /*unused*/, std::size_t /*unused*/)
97{
98 return 0;
99}
100
101template <class charT>
102inline std::size_t
103rwtest_wcstombs (std::mbstate_t& state, const charT* pi,
104 char* pe, std::size_t srclen)
105{
106# ifndef _RWSTD_NO_WCSRTOMBS
107
108 return std::wcsrtombs (pe, &pi, srclen, &state);
109
110# else // if defined _RWSTD_NO_WCSRTOMBS)
111
112 _RWSTD_UNUSED (state);
113 return std::wcstombs (pe, pi, srclen);
114
115# endif // _RWSTD_NO_WCSRTOMBS
116}
117
119inline std::size_t
120rwtest_wcstombs<char>(std::mbstate_t& /*unused*/, const char* /*unused*/,
121 char* /*unused*/, std::size_t /*unused*/)
122{
123 return 0;
124}
125
126#endif // !defined _RWSTD_NO_WCHAR_T
127
128
129static std::size_t
130rwtest_mbslen (std::mbstate_t& state,
131 const char* pe,
132 const char* limit,
133 std::size_t cmax)
134{
135 std::size_t total = 0;
136 std::size_t ret = 0;
137
138 while (total < cmax && pe < limit)
139 {
140#ifndef _RWSTD_NO_MBRLEN
141
142 ret = std::mbrlen (pe, min (_RWSTD_MB_LEN_MAX, limit - pe), &state);
143
144#else // if defined _RWSTD_NO_MBRLEN
145
146 _RWSTD_UNUSED (state);
147 ret = std::mblen (pe, min (_RWSTD_MB_LEN_MAX, limit - pe));
148
149#endif // _RWSTD_NO_MBRLEN
150
151 if (ret >= std::size_t (-2))
152 break;
153
154 pe += ret;
155 ++total;
156 }
157
158 return total;
159}
160
161
163// The codecvt facets and their required specializations
164typedef std::codecvt_base::result CodecvtResult;
165typedef std::codecvt<char,char,std::mbstate_t> Codecvt;
166typedef std::codecvt_byname<char,char,std::mbstate_t> CodecvtBn;
167
168#ifndef _RWSTD_NO_WCHAR_T
169typedef std::codecvt<wchar_t,char,std::mbstate_t> CodecvtW;
170typedef std::codecvt_byname<wchar_t,char,std::mbstate_t> CodecvtBnW;
171#endif // _RWSTD_NO_WCHAR_T
172
173
174// Type names used in assertion messages
175template <class T>
177{
178 static const char* name;
179};
180
181_RWSTD_SPECIALIZED_CLASS const char*
182TypeName<char>::name = "char";
183
184_RWSTD_SPECIALIZED_CLASS const char*
185TypeName<Codecvt>::name = "std::codecvt<char, char, std::mbstate_t>";
186
187_RWSTD_SPECIALIZED_CLASS const char*
188TypeName<CodecvtBn>::name = "std::codecvt_byname<char, char, std::mbstate_t>";
189
190#ifndef _RWSTD_NO_WCHAR_T
191
192_RWSTD_SPECIALIZED_CLASS const char*
193TypeName<wchar_t>::name = "wchar_t";
194
195_RWSTD_SPECIALIZED_CLASS const char*
196TypeName<CodecvtW>::name = "std::codecvt<wchar_t, char, std::mbstate_t>";
197
198_RWSTD_SPECIALIZED_CLASS const char*
200 "std::codecvt_byname<wchar_t, char, std::mbstate_t>";
201
202#endif // _RWSTD_NO_WCHAR_T
203
204
206// bitmasks for calls to virtual functions
207enum {
208 dtor = 1 << 0,
209 do_out = 1 << 1,
210 do_in = 1 << 2,
211 do_unshift = 1 << 3,
212 do_encoding = 1 << 4,
214 do_length = 1 << 6,
215 do_max_length = 1 << 7
217
218// bitset for all virtual function calls
219int call = 0;
220
221// template class for testing virtual calls
222template <class Base>
224{
226 typedef typename base_type::intern_type itype;
227 typedef typename base_type::extern_type etype;
228 typedef typename base_type::state_type stype;
229 typedef typename std::codecvt_base::result result;
230
231 CodecvtDerived (const char*);
232
233 virtual ~CodecvtDerived () {
234 call |= ::dtor;
235 }
236
237 result
238 do_out (stype&, const itype*, const itype*, const itype*&,
239 etype*, etype*, etype*&) const {
240 call |= ::do_out;
241 return result ();
242 }
243
244 result
245 do_in (stype&, const etype*, const etype*, const etype*&,
246 itype*, itype*, itype*&) const {
247 call |= ::do_in;
248 return result ();
249 }
250
251 result
252 do_unshift (stype&, etype*, etype*, etype*&) const {
254 return result ();
255 }
256
257 int do_encoding () const _THROWS (()) {
259 return 0;
260 }
261
262 bool do_always_noconv () const _THROWS (()) {
264 return false;
265 }
266
267 int do_length (stype&, const etype*, const etype*,
268 std::size_t) const {
269 call |= ::do_length;
270 return 0;
271 }
272
273 int do_max_length () const _THROWS (()) {
275 return 0;
276 }
277};
278
279
280// specialization for the class constructor in CodecvtDerived
283 : Codecvt () { }
284
287 : CodecvtBn (name) { }
288
289#ifndef _RWSTD_NO_WCHAR_T
290
292CodecvtDerived<CodecvtW>::CodecvtDerived (const char* /*unused*/)
293 : CodecvtW () { }
294
297 : CodecvtBnW (name) { }
298
299#endif // _RWSTD_NO_WCHAR_T
300
301
302// Tests the call of virtual member functions in codecvt facets
303template <class CodeCvtT>
304static void
305test_virtuals (const char* locale_name)
306{
307 rw_info (0, __FILE__, __LINE__,
308 "%s virtual functions", TypeName<CodeCvtT>::name);
309
310 CodecvtDerived<CodeCvtT> pccvt (locale_name);
311 CodeCvtT& cc = pccvt;
312
313 typedef typename CodeCvtT::intern_type intern_type;
314 typedef typename CodeCvtT::extern_type extern_type;
315
316 const extern_type* pce = 0;
317 extern_type* pe = 0;
318 const intern_type* pci = 0;
319 intern_type* pi = 0;
320
321 std::mbstate_t st = std::mbstate_t ();
322
323 // verify 22.2.1.5.1, p1
324 cc.out (st, pci, pci, pci, pe, pe, pe );
325 rw_assert ((call & do_out) != 0, __FILE__, __LINE__,
326 "%s::do_out call failed.", TypeName<CodeCvtT>::name);
327
328 // verify 22.2.1.5.1, p2
329 cc.in (st, pce, pce, pce, pi, pi, pi );
330 rw_assert ((call & do_in) != 0, __FILE__, __LINE__,
331 "%s::do_in call failed.", TypeName<CodeCvtT>::name);
332
333 // verify 22.2.1.5.1, p3
334 cc.unshift (st, pe, pe, pe);
335 rw_assert ((call & do_unshift) != 0, __FILE__, __LINE__,
336 "%s::do_unshift call failed.", TypeName<CodeCvtT>::name);
337
338 // verify 22.2.1.5.1, p4
339 cc.encoding ();
340 rw_assert ((call & do_encoding) != 0, __FILE__, __LINE__,
341 "%s::do_encoding call failed.", TypeName<CodeCvtT>::name);
342
343 // verify 22.2.1.5.1, p5
344 cc.always_noconv ();
345 rw_assert ((call & do_always_noconv) != 0, __FILE__, __LINE__,
346 "%s::do_always_noconv call failed.", TypeName<CodeCvtT>::name);
347
348 // verify 22.2.1.5.1, p6
349 cc.length (st, pce, pce, 0);
350 rw_assert ((call & do_length) != 0, __FILE__, __LINE__,
351 "%s::do_length call failed.", TypeName<CodeCvtT>::name);
352
353 // verify 22.2.1.5.1, p7
354 cc.max_length ();
355 rw_assert ((call & do_max_length) != 0, __FILE__, __LINE__,
356 "%s::do_max_length call failed.", TypeName<CodeCvtT>::name);
357}
358
359
361const Codecvt& create_Codecvt (const std::locale&)
362{
363 static Codecvt cc;
364 return cc;
365}
366
367const CodecvtBn& create_CodecvtBn (const std::locale& loc)
368{
369 return _STD_USE_FACET (CodecvtBn, loc);
370}
371
372#ifndef _RWSTD_NO_WCHAR_T
373
374const CodecvtW& create_CodecvtW (const std::locale&)
375{
376 static CodecvtW cc;
377 return cc;
378}
379
380const CodecvtBnW& create_CodecvtBnW (const std::locale& loc)
381{
382 return _STD_USE_FACET (CodecvtBnW, loc);
383}
384
385#endif // !defined _RWSTD_NO_WCHAR_T
386
387
388// facet operations results
389static const char*
390rwtest_codecvt_result (int res)
391{
392 // allow the function to be called up to 8 times in the same expression
393 // without overwriting the static buffer (each call will return a pointer
394 // to a new array)
395 static char buf [8][16];
396
397 static std::size_t index;
398
399 std::size_t inx = index;
400
401 index = (index + 1) % sizeof buf / sizeof *buf;
402
403 std::sprintf (buf [inx], "%#x", res);
404
405 return buf [inx];
406}
407
408static const char*
409rwtest_codecvt_result (CodecvtResult res)
410{
411 static const struct {
413 const char* str;
414 } results [] = {
415 { std::codecvt_base::ok, "std::codecvt_base::ok" },
416 { std::codecvt_base::partial, "std::codecvt_base::partial" },
417 { std::codecvt_base::noconv, "std::codecvt_base::noconv" },
418 { std::codecvt_base::error, "std::codecvt_base::error" }
419 };
420
421 for (unsigned i = 0; i != sizeof results / sizeof *results; ++i)
422 if (res == results [i].res)
423 return results [i].str;
424
425 return rwtest_codecvt_result (int (res));
426}
427
428
430static bool
431rwtest_is_C_locale (const char* s)
432{
433 const char* old = std::setlocale (LC_ALL, s);
434 if (old == 0)
435 return false;
436
437 std::setlocale (LC_ALL, old);
438 return true;
439}
440
441
443// Test custom locales, built on the fly
444template <class CodeCvtT>
445static void
446test_libstd_do_in (const char* locale_name, const CodeCvtT& cc,
447 const typename CodeCvtT::extern_type* buffe,
448 typename CodeCvtT::intern_type*& buffi,
449 std::size_t sze, std::size_t& szi,
450 bool skip_C,
451 CodecvtResult& res, std::size_t& sz)
452{
453 // buffers types
454 typedef typename CodeCvtT::intern_type intern_t;
455 typedef typename CodeCvtT::extern_type extern_t;
456
457 const extern_t* pe = buffe;
458 const extern_t* pen = buffe;
459 const extern_t* pe_limit = buffe + sze;
460
461 szi = sze;
462 buffi = new intern_t [szi];
463 std::memset (buffi, 0, szi * sizeof (intern_t));
464
465 intern_t* pi = buffi;
466 intern_t* pin = pi;
467 intern_t* pi_limit = pi + sze;
468
469 // the state
470 std::mbstate_t state = std::mbstate_t ();
471
472 // do the conversion and store results
473 res = cc.in ( state, pe, pe_limit, pen, pi, pi_limit, pin );
474 szi = sz = pin - pi;
475
476 // if C library locale is available, then perform conversion and
477 // compare the results
478 if (skip_C || std::setlocale (LC_CTYPE, locale_name) == 0)
479 return;
480
481 intern_t* C_buffer = new intern_t [sze];
482 std::memset (C_buffer, 0, sze * sizeof (intern_t));
483
484 intern_t* C_pi = C_buffer;
485
486 std::mbstate_t C_state = std::mbstate_t ();
487
488 pen = pe;
489 std::size_t C_res =
490 rwtest_mbstowcs<intern_t> (C_state, C_pi, pen, sze);
491 if (res != std::codecvt_base::ok || C_res == std::size_t(-1)) {
492 delete [] C_buffer;
493 return;
494 }
495
496 // test against C library results - length and content
497 rw_assert (C_res == std::size_t(pin - pi), __FILE__, __LINE__,
498 "(%s) %s::do_in Clib length check:\n"
499 " C library conversion size : %d\n"
500 " std library conversion size : %d\n",
501 locale_name, TypeName<CodeCvtT>::name, C_res, pin - pi);
502
503 rw_assert (0 == std::memcmp (pi, C_pi, C_res), __FILE__, __LINE__,
504 "(%s) %s::do_in data check failed against C library conversion",
505 locale_name, TypeName<CodeCvtT>::name);
506
507 // clean up the allocations
508 delete [] C_buffer;
509}
510
511#define CCVT_MAX_LOCALE 5 // Max. number of locale to test
512#define CCVT_MB_CUR_MIN 1 // Minimum and maximum no. of
513#define CCVT_MB_CUR_MAX 6 // bytes per character
514
515template <class CodeCvtT>
516static void
517test_libstd_do_out (const char* locale_name, const CodeCvtT& cc,
518 typename CodeCvtT::extern_type*& buffe,
519 const typename CodeCvtT::intern_type* buffi,
520 std::size_t& sze, std::size_t szi,
521 bool skip_C,
522 CodecvtResult& res, std::size_t& sz)
523{
524 // buffers types
525 typedef typename CodeCvtT::intern_type intern_t;
526 typedef typename CodeCvtT::extern_type extern_t;
527
528 // the state
529 std::mbstate_t state = std::mbstate_t ();
530
531 buffe = new extern_t [CCVT_MB_CUR_MAX * szi];
532 std::memset (buffe, 0, CCVT_MB_CUR_MAX * szi);
533 extern_t* pe = buffe;
534 extern_t* pen = pe;
535 extern_t* pe_limit = pe + CCVT_MB_CUR_MAX * szi;
536
537 const intern_t* pi = buffi;
538 const intern_t* pin = buffi;
539 const intern_t* pi_limit = pi + szi;
540
541 // perform the conversion
542 res = cc.out ( state, pi, pi_limit, pin, pe, pe_limit, pen );
543 sze = sz = pen - pe;
544
545 if (skip_C || std::setlocale (LC_CTYPE, locale_name) == 0) {
546 return;
547 }
548
549 extern_t* C_buffer = new extern_t [CCVT_MB_CUR_MAX * szi];
550 std::memset (C_buffer, 0, CCVT_MB_CUR_MAX * szi);
551 extern_t* C_pe = C_buffer;
552
553 std::mbstate_t C_state = std::mbstate_t ();
554
555 std::size_t C_res =
556 rwtest_wcstombs<intern_t> (C_state, pi, C_pe, CCVT_MB_CUR_MAX * szi);
557 if (C_res == std::size_t(-1)) {
558 delete [] C_buffer;
559 return;
560 }
561
562 // test results against C library
563 rw_assert (C_res == std::size_t(pen - pe), __FILE__, __LINE__,
564 "(%s) %s::do_out Clib length check\n"
565 " C library conversion size : %d\n"
566 " std library conversion size : %d\n",
567 locale_name, TypeName<CodecvtBnW>::name,
568 C_res, (pen - pe));
569
570 rw_assert (0 == std::memcmp (pe, C_pe, C_res), __FILE__, __LINE__,
571 "(%s) %s::do_out Clib data check failed "
572 "against C library conversion",
573 locale_name, TypeName<CodecvtBnW>::name);
574
575 delete [] C_buffer;
576}
577
578template <class CodeCvtT>
579static void
580test_libstd_do_unshift (const CodeCvtT& cc,
581 std::mbstate_t& state,
582 typename CodeCvtT::extern_type* buffe,
583 std::size_t& sze,
585{
586 // buffers types
587 typedef typename CodeCvtT::intern_type intern_t;
588 typedef typename CodeCvtT::extern_type extern_t;
589
590 extern_t* pe = buffe;
591 extern_t* pen = buffe;
592 extern_t* pe_limit = buffe + sze;
593
594 res = cc.unshift (state, pe, pe_limit, pen);
595 sze = pen - pe;
596}
597
598template <class CodeCvtT>
599static void
600test_libstd_do_always_noconv (const CodeCvtT& cc, bool& res)
601{
602 res = cc.always_noconv ();
603}
604
605// check do_max_length operation in facet
606template <class CodeCvtT>
607static void
608test_libstd_do_max_length (const CodeCvtT& cc, std::size_t& res )
609{
610 res = cc.max_length ();
611}
612
613// check do_length operation in facet
614template <class CodeCvtT>
615static void
616test_libstd_do_length (const char* locale_name, const CodeCvtT& cc,
617 const typename CodeCvtT::extern_type* buffe,
618 std::size_t& sze, bool skip_C)
619{
620 // buffers types
621 typedef CodecvtBnW::intern_type intern_t;
622 typedef CodecvtBnW::extern_type extern_t;
623
624 // the state
625 std::mbstate_t state = std::mbstate_t ();
626
627 extern_t* pe = _RWSTD_CONST_CAST(extern_t*, buffe);
628 extern_t* pe_limit = _RWSTD_CONST_CAST(extern_t*, buffe + sze);
629
630 sze = cc.length ( state, pe, pe_limit, sze );
631
632 if (skip_C)
633 return;
634
635 std::mbstate_t C_state = std::mbstate_t ();
636
637 std::size_t C_res =
638 rwtest_mbslen ( C_state, pe, pe_limit, sze );
639 // test the result against C library
640 rw_assert (sze == C_res, __FILE__, __LINE__,
641 "(%s) %s::do_length; "
642 "check against C library result failed :\n"
643 " C library result : %d\n"
644 " std library result : %d",
645 locale_name, TypeName<CodeCvtT>::name,
646 C_res, sze);
647}
648
649template <class CodeCvtT>
650static void
651test_libstd_do_encoding (const CodeCvtT& cc, std::size_t& sze)
652{
653 sze = cc.encoding ();
654}
655
656
658// Primary template for checking libstd locale codecvt facets
659template <class CodeCvtT>
660static void
661test_libstd_codecvt (const char* locale_name, const CodeCvtT& cc,
662 const char* fname, bool skip_C,
663 CodecvtResult in_res, std::size_t in_res_sz,
664 CodecvtResult out_res, std::size_t out_res_sz,
665 CodecvtResult unshift_res,
666 bool always_noconv_res,
667 std::size_t encoding_res,
668 std::size_t length_res,
669 std::size_t max_length_res)
670{
671 // buffers types
672 typedef typename CodeCvtT::intern_type intern_t;
673 typedef typename CodeCvtT::extern_type extern_t;
674
675 // create a state object
676 std::mbstate_t state = std::mbstate_t ();
677
678 // pointers to buffers
679 extern_t* ebuffer = 0;
680 intern_t* ibuffer = 0;
681 extern_t* eebuffer = 0;
682
683 std::size_t elength = 0;
684 std::size_t ilength = 0;
685 std::size_t eelength = 0;
686
687 // read source file
688 ebuffer = _RWSTD_STATIC_CAST (extern_t*, rw_fread (fname, &elength, "rb"));
689
690 if (!ebuffer || !elength) {
691 rw_assert (false, __FILE__, __LINE__,
692 "failed to read from %s", fname);
693 return;
694 }
695
696 // operations results
698 bool bres;
699 std::size_t ires;
700 std::size_t res_sz;
701
702 char fcall [256];
703 std::sprintf (fcall, "%s::in(..., %p, %p, 0, %p, %p, 0)",
705 (const void*)ebuffer, (const void*)(ebuffer + elength),
706 (const void*)ibuffer, (const void*)(ibuffer + ilength));
707
708 // Test do_in conversion result and size
709 test_libstd_do_in<CodeCvtT> (locale_name, cc,
710 ebuffer, ibuffer, elength, ilength,
711 skip_C, res, res_sz);
712
713 // 22.2.1.5 p3, 22.2.1.5.2 p2 - test operation result
714 rw_assert (res == in_res, __FILE__, __LINE__,
715 "%s == %s, got %s in locale(\"%s\")",
716 fcall,
717 rwtest_codecvt_result (in_res),
718 rwtest_codecvt_result (res),
719 locale_name);
720
721 // test the length of the internal buffer is correct; noconv does not do
722 // any copying of the data
723 if (res == std::codecvt_base::noconv) {
724 rw_assert (res_sz == 0, __FILE__, __LINE__,
725 "%s expected size 0 for %s, got %d instead "
726 "in locale(\"%s\")", fcall,
727 rwtest_codecvt_result (res), res_sz, locale_name);
728
729 // so copy all content from external buffer to internal buffer
730 ilength = elength;
731 for (std::size_t i = 0; i < elength; i++)
732 ibuffer [i] = intern_t (ebuffer [i]);
733
734 }
735 else {
736 rw_assert (ilength == in_res_sz && ilength == res_sz,
737 __FILE__, __LINE__,
738 "%s: conversion size: expected %d, got %d in locale(\"%s\")",
739 fcall, in_res_sz, ilength, locale_name);
740 }
741
742 // Test do_out conversion result and size
743 test_libstd_do_out<CodeCvtT> (locale_name, cc,
744 eebuffer, ibuffer, eelength, ilength,
745 skip_C, res, res_sz);
746
747 // 22.2.1.5 p3, 22.2.1.5.2 p2 - test operation result
748 rw_assert (res == out_res, __FILE__, __LINE__,
749 "(%s) %s::do_out() == %s, got %s",
750 locale_name, TypeName<CodecvtBnW>::name,
751 rwtest_codecvt_result (out_res), rwtest_codecvt_result (res));
752
753 if (res == std::codecvt_base::noconv) {
754 rw_assert (res_sz == 0, __FILE__, __LINE__,
755 "(%s) %s::do_out expected size 0 for %s, got %d instead",
756 locale_name, TypeName<CodeCvtT>::name,
757 rwtest_codecvt_result (res), res_sz);
758
759 // so copy all content from internal buffer to external buffer
760 eelength = ilength;
761 for (std::size_t i = 0; i < eelength; i++)
762 eebuffer [i] = extern_t (ibuffer [i]);
763
764 } else {
765 rw_assert (eelength == out_res_sz && eelength == res_sz,
766 __FILE__, __LINE__,
767 "(%s) %s::do_out conversion size: expected %d, got %d",
768 locale_name, TypeName<CodeCvtT>::name,
769 in_res_sz, ilength);
770 }
771
772 // Test the roundtrip conversion content and size
773 std::size_t cmp = 0;
774 if (std::memcmp (ebuffer, eebuffer, min (elength, eelength))) {
775 for (cmp = 0; cmp < min (elength, eelength); cmp++)
776 if (ebuffer [cmp] != eebuffer [cmp])
777 break;
778 }
779
780 rw_assert (elength == eelength, __FILE__, __LINE__,
781 "(%s) %s round-trip check size mismatch : "
782 " expected size %d , got size %d",
783 locale_name, TypeName<CodeCvtT>::name,
784 elength, eelength);
785
786 rw_assert (0 == std::memcmp (ebuffer, eebuffer,
787 min (elength, eelength)),
788 __FILE__, __LINE__,
789 "(%s) %s round-trip check content mismatch : at index %d",
790 locale_name, TypeName<CodeCvtT>::name, cmp);
791
792 // Test unshift operation
793 extern_t tmp [16];
794 std::size_t tmp_len = 16;
795 state = std::mbstate_t ();
796
797 test_libstd_do_unshift<CodeCvtT> (cc, state, tmp, tmp_len, res);
798
799 // 22.2.1.5.2 p5-6
800 rw_assert (res == unshift_res, __FILE__, __LINE__,
801 "(%s) %s::do_unshift; expected %s, got %s",
802 locale_name, TypeName<CodeCvtT>::name,
803 rwtest_codecvt_result (unshift_res),
804 rwtest_codecvt_result (res));
805
806 rw_assert (tmp_len == 0, __FILE__, __LINE__,
807 "(%s) %s::do_unshift; expected 0 length unshift sequence, "
808 "got %d", locale_name, TypeName<CodeCvtT>::name, tmp_len);
809
810 // Test do_always_noconv operation
811 test_libstd_do_always_noconv<CodeCvtT> (cc, bres);
812 rw_assert (bres == always_noconv_res, __FILE__, __LINE__,
813 "(%s) %s::do_always_noconv expected %s, got %s",
814 locale_name, TypeName<CodeCvtT>::name,
815 always_noconv_res?"true":"false", bres?"true":"false");
816
817 // Test do_max_length operation
818 test_libstd_do_max_length<CodeCvtT> (cc, ires);
819 // 22.2.1.5.2 p11
820 rw_assert (ires == max_length_res, __FILE__, __LINE__,
821 "(%s) %s::do_max_length expected %d, got %d",
822 locale_name, TypeName<CodeCvtT>::name,
823 max_length_res, ires);
824
825 // Test do_length operation
826 ires = elength;
827 test_libstd_do_length<CodeCvtT> (locale_name, cc,
828 ebuffer, ires, skip_C);
829 // 22.2.1.5.2 p10
830 rw_assert (ires == length_res, __FILE__, __LINE__,
831 "(%s) %s::do_length expected %d, got %d",
832 locale_name, TypeName<CodeCvtT>::name,
833 length_res, ires);
834
835 ires = 0;
836 test_libstd_do_encoding<CodeCvtT> (cc, ires);
837 // 22.2.1.5.2 p6
838 rw_assert (ires == encoding_res, __FILE__, __LINE__,
839 "(%s) %s::do_encoding expected %d, got %d",
840 locale_name, TypeName<CodeCvtT>::name,
841 encoding_res, ires);
842
843 delete [] ibuffer;
844 delete [] eebuffer;
845 // delete [] ebuffer;
846}
847
848
850#if !defined _WIN32
851
852static unsigned int endian_test = 1;
853static bool big_endian = *(unsigned char*)&endian_test == 0;
854
855static iconv_t
856rwtest_iconv_open (bool ucs4, const char* enc)
857{
858 static const char* const ucs4_aliases [] = {
859 "UCS-4LE", "UCS-4", "UCS4", "ucs4", 0
860 };
861
862 static const char* const ucs2_aliases [] = {
863 "UCS-2LE", "UCS-2", "UCS2", "ucs2", 0
864 };
865
866 const char* const* pucs = ucs4 ? ucs4_aliases : ucs2_aliases;
867
868 // that accomodates Linux with its extra modifiers LE and BE
869 // (UCS-4 is synonym with UCS-4BE)
870 if (big_endian)
871 pucs++;
872
873 iconv_t id = iconv_t (-1);
874
875 for (; id == iconv_t (-1) && *pucs && **pucs; pucs++)
876 id = iconv_open (*pucs, enc);
877
878 return id;
879}
880
881
882static void
883rwtest_iconv_convert (iconv_t fd,
884 const char* in, std::size_t in_sz,
885 wchar_t* out, std::size_t& out_sz)
886{
887 out_sz *= sizeof (wchar_t);
888
889 // Two issues:
890 // - iconv shipped with the C library on RedHat 6.2 if reaches the end of
891 // the input buffer (out_sz == 0) reports E2BIG as if it has had not
892 // enuff space to store the result of the conversion
893 // - iconv shipped with C library on RedHat 6.2 apparently uses UCS-4 big
894 // endian on little endian machines too
895 std::size_t tmp = out_sz++ + 1;
896
897# if defined _RWSTD_NO_ICONV_CONST_CHAR
898 char* par1 = _RWSTD_CONST_CAST (char*, in);
899# else
900 const char* par1 = in;
901# endif // defined _RWSTD_NO_ICONV_CONST_CHAR
902 char* par2 = _RWSTD_REINTERPRET_CAST (char*, out);
903
904 std::size_t res = iconv (fd, &par1, &in_sz, &par2, &out_sz);
905 if (res == std::size_t (-1))
906 out_sz = 0;
907 else
908 out_sz = (tmp + 1 - out_sz) / sizeof (wchar_t);
909}
910
911#endif // defined _WIN32
912
913
915 use_libc, // use libc's native internal wchar_t encoding
916 use_UCS4, // use UCS-4 as the internal wchar_t encoding
917 use_UCS2 // use UCS-2 as the internal wchar_t encoding
919
920
921static bool
922rwtest_convert_to_internal (InternalEncoding conv,
923 const char* native_locname,
924 const char* ebuffer, std::size_t elength,
925 wchar_t* ibuffer, std::size_t& ilength)
926{
927 ilength = 0;
928
929 if (!native_locname)
930 return false;
931
932 const char* const old_locale = std::setlocale (LC_CTYPE, native_locname);
933
934 if (!old_locale)
935 return false;
936
937 switch (conv) {
938
939#ifdef _WIN32
940
941 case use_UCS2:
942 // fall through...
943
944#endif // _WIN32
945
946 case use_libc: {
947
948 std::mbstate_t state = std::mbstate_t ();
949
950 ilength = rwtest_mbstowcs (state, ibuffer, ebuffer, elength);
951
952 break;
953 }
954
955#ifndef _WIN32
956
957 case use_UCS2:
958 case use_UCS4: {
959 // use iconv
960
961 const char* const codeset = nl_langinfo (CODESET);
962 if (!codeset) {
963 ilength = std::size_t (-1);
964 break;
965 }
966
967 const iconv_t id = rwtest_iconv_open (true, codeset);
968
969 if (iconv_t (-1) == id)
970 ilength = std::size_t (-1);
971 else {
972 rwtest_iconv_convert (id, ebuffer, elength, ibuffer, ilength);
973
974 iconv_close (id);
975 }
976
977 break;
978 }
979
980#endif // _WIN32
981
982 }
983
984 // restore the previous locale
985 std::setlocale (LC_CTYPE, old_locale);
986
987 if (std::size_t (-1) == ilength) {
988 ilength = 0;
989 return false;
990 }
991
992 return true;
993}
994
995
996static const char*
997rwtest_internal_type (InternalEncoding enc)
998{
999 static const char* const encs [] = {
1000 "native", "UCS-4", "UCS-2", "invalid"
1001 };
1002
1003 switch (enc) {
1004 case use_libc:
1005 return encs [0];
1006 case use_UCS4:
1007 return encs [1];
1008 case use_UCS2:
1009 return encs [2];
1010 default:
1011 return encs [3];
1012 }
1013}
1014
1015
1016static std::size_t
1017bmatch (const char* mem1, const char* mem2, std::size_t nchars)
1018{
1019 if (std::memcmp (mem1, mem2, nchars)) {
1020
1021 for (std::size_t i = 0; i != nchars; ++i)
1022 if (mem1 [i] != mem2 [i])
1023 return i;
1024 }
1025 return nchars;
1026}
1027
1028
1029static std::size_t
1030bmatch (const wchar_t* mem1, const wchar_t* mem2, std::size_t nchars)
1031{
1032 if (std::size_t (-1) == nchars) {
1033 // avoid warnings about unused overload above
1034 return bmatch ((char*)0, (char*)0, 0);
1035 }
1036
1037 if (std::memcmp (mem1, mem2, nchars * sizeof *mem1)) {
1038
1039 for (std::size_t i = 0; i != nchars; ++i)
1040 if (mem1 [i] != mem2 [i])
1041 return i;
1042 }
1043 return nchars;
1044}
1045
1046
1047static void
1048test_ucs_modifier (const char* locale_name,
1049 InternalEncoding conv,
1050 const char* native_locname,
1051 const CodecvtBnW& cc,
1052 const char* fname,
1053 CodecvtResult in_res,
1054 std::size_t in_res_sz)
1055{
1056 // pointers to buffers
1057 char* ebuf = 0;
1058 wchar_t* ibuf = 0;
1059 wchar_t* ibuf_native = 0;
1060
1061 // buffer sizes
1062 std::size_t elen = 0;
1063 std::size_t ilen = 0;
1064 std::size_t ilen_native = 0;
1065
1066 // read source file
1067 ebuf = _RWSTD_STATIC_CAST (char*, rw_fread (fname, &elen, "rb"));
1068 if (!ebuf || !elen)
1069 return;
1070
1071 // allocate and zero the internal buffer
1072 ilen = elen;
1073 ibuf = new wchar_t [ilen];
1074 std::memset (ibuf, 0, ilen * sizeof *ibuf);
1075
1076 ilen_native = elen;
1077
1078 // to accommodate iconv shipped with RedHat 6.2, allocate one more wchar_t
1079 ibuf_native = new wchar_t [ilen_native + 1];
1080 std::memset (ibuf_native, 0, (ilen_native + 1) * sizeof *ibuf_native);
1081
1082 const char* from = ebuf;
1083 const char* from_next = ebuf;
1084 const char* from_limit = ebuf + elen;
1085 wchar_t* to = ibuf;
1086 wchar_t* to_next = ibuf;
1087 wchar_t* to_limit = ibuf + elen;
1088
1089 // create a state object
1090 std::mbstate_t state = std::mbstate_t ();
1091
1092 rw_info (0, __FILE__, __LINE__, "locale(\"%s\")", locale_name);
1093
1094 const std::codecvt_base::result res =
1095 cc.in (state, from, from_limit, from_next, to, to_limit, to_next);
1096
1097 ilen = to_next - to;
1098
1099 if (res != in_res || in_res_sz != std::size_t (to_next - to)) {
1100 rw_assert (false, __FILE__, __LINE__,
1101 "(%s) EXT -> INT conversion using codecvt failed:\n"
1102 " result : %s\n expected size %d, got %d",
1103 locale_name, rwtest_codecvt_result (res),
1104 in_res_sz, to_next - to);
1105
1106 delete [] ibuf_native;
1107 delete [] ibuf;
1108 return;
1109
1110 }
1111
1112 // test against the libc mbstowcs() or iconv() conversion
1113 if (!rwtest_convert_to_internal (conv, native_locname, ebuf, elen,
1114 ibuf_native, ilen_native)) {
1115 delete [] ibuf_native;
1116 delete [] ibuf;
1117 return;
1118 }
1119
1120 if (!ilen_native) {
1121 rw_assert (false, __FILE__, __LINE__,
1122 "(%s) EXT -> INT conversion using %s "
1123 "(%s internally) failed",
1124 locale_name,
1125 (conv == use_libc) ? "mbstowcs()" : "iconv()",
1126 rwtest_internal_type (conv));
1127
1128 delete [] ibuf_native;
1129 delete [] ibuf;
1130 return;
1131 }
1132
1133 // Conversion and check against mbstowcs / iconv
1134 rw_assert (ilen_native == ilen, __FILE__, __LINE__,
1135 "(%s) EXT -> INT length check (%s internally):\n"
1136 " size of native encoding: %d\n"
1137 " size of codecvt encoding: %d\n",
1138 locale_name, rwtest_internal_type (conv),
1139 ilen, ilen_native);
1140
1141 if (ilen_native == ilen) {
1142 const std::size_t diff = bmatch (to, ibuf_native, ilen);
1143
1144 rw_assert (diff >= ilen, __FILE__, __LINE__,
1145 "codecvt<wchar_t, char, mbstate_t>::in() mismatch "
1146 "at character %u of %u: '%s' != '%s'; in locale(\"%s\")",
1147 diff, ilen, ibuf_native [diff],
1148 to [diff], locale_name);
1149 }
1150
1151 delete [] ibuf_native;
1152 delete [] ibuf;
1153}
1154
1155
1157std::jmp_buf jmp_env;
1158
1159// called in response to abort() or failed assertions
1160extern "C"
1161void SIGABRT_handler (int /*unused*/)
1162{
1163 std::longjmp (jmp_env, 1);
1164}
1165
1166
1167// exercise the facets' treatment of an invalid mbstate_t argument
1168template <class CodeCvtT>
1169static void
1170test_mbstate_t (const CodeCvtT*, const char* name)
1171{
1172 const std::locale loc (name);
1173
1174 const CodeCvtT &cvt = _STD_USE_FACET (CodeCvtT, loc);
1175
1176 typedef typename CodeCvtT::intern_type intern_type;
1177 typedef typename CodeCvtT::extern_type extern_type;
1178 typedef typename CodeCvtT::state_type state_type;
1179
1180 state_type state;
1181
1182 // initialize `state' to an invalid value
1183 std::memset (&state, -1, sizeof state);
1184
1185 intern_type in = intern_type ();
1186 intern_type* in_0 = &in;
1187 intern_type* in_1 = &in + 1;
1188 intern_type* in_2 = 0;
1189 const intern_type* const_in_2 = 0;
1190
1191 extern_type ext = extern_type ();
1192 extern_type* ext_0 = &ext;
1193 extern_type* ext_1 = &ext + 1;
1194 extern_type* ext_2 = 0;
1195 const extern_type* const_ext_2 = 0;
1196
1197#ifndef _RWSTDDEBUG
1198 // when debugging is disabled, expect member functions to
1199 // detect and indicate an invalid argument by setting the
1200 // return value to codecvt_base::error
1201 const bool expect_abort = false;
1202#else
1203 // when debugging is enabled, expect member functions to
1204 // detect and indicate an invalid argument by calling abort()
1205 const bool expect_abort = true;
1206#endif
1207
1208#undef TEST
1209#define TEST(resultT, result, fname, args) \
1210 if (0 == setjmp (jmp_env)) { \
1211 std::signal (SIGABRT, SIGABRT_handler); \
1212 const resultT res = cvt.fname args; \
1213 rw_assert (!expect_abort && result == res, __FILE__, __LINE__, \
1214 "%s::%s (state_type&, ...) failed to " \
1215 "detect an invalid state argument", \
1216 TypeName<CodeCvtT>::name, #fname); \
1217 } else \
1218 rw_assert (expect_abort, __FILE__, __LINE__, \
1219 "%s::%s (state_type&, ...) called abort() instead " \
1220 "of gracefully indicating an invalid state argument", \
1221 TypeName<CodeCvtT>::name, #fname)
1222
1223 const std::codecvt_base::result error = std::codecvt_base::error;
1224
1225 TEST (std::codecvt_base::result, error,
1226 in, (state, ext_0, ext_1, const_ext_2, in_0, in_1, in_2));
1227
1228 TEST (std::codecvt_base::result, error,
1229 out, (state, in_0, in_1, const_in_2, ext_0, ext_1, ext_2));
1230
1231 TEST (std::codecvt_base::result, error,
1232 unshift, (state, ext_0, ext_1, ext_2));
1233
1234 TEST (int, 0,
1235 length, (state, ext_0, ext_1, 0));
1236
1237 // verify that functions gracefully handle null pointers
1238#undef TEST
1239#define TEST(resultT, result, fname, args) \
1240 if (0 == setjmp (jmp_env)) { \
1241 std::signal (SIGABRT, SIGABRT_handler); \
1242 const resultT res = cvt.fname args; \
1243 rw_assert (result == res, __FILE__, __LINE__, \
1244 "%s::%s (state_type&, (char_type*)0, ...) == %s, " \
1245 "got %s (NULL pointer test)", \
1246 TypeName<CodeCvtT>::name, #fname, \
1247 rwtest_codecvt_result (result), \
1248 rwtest_codecvt_result (res)); \
1249 } else \
1250 rw_assert (expect_abort, __FILE__, __LINE__, \
1251 "%s::%s (state_type&, (char_type*)0, ...) " \
1252 "unexpectedly called abort() (NULL pointer test)", \
1253 TypeName<CodeCvtT>::name, #fname)
1254
1255 // initialize `state' to a valid value
1256 std::memset (&state, 0, sizeof state);
1257
1258 // const below commented out to work around an HP aCC bug (PR #29666)
1259 /* const */ std::codecvt_base::result result =
1260 sizeof (intern_type) == sizeof (char)
1261 ? std::codecvt_base::noconv : std::codecvt_base::ok;
1262
1263 TEST (std::codecvt_base::result, result,
1264 in, (state, 0, 0, const_ext_2, 0, 0, in_2));
1265
1266 TEST (std::codecvt_base::result, result,
1267 out, (state, 0, 0, const_in_2, 0, 0, ext_2));
1268
1269 TEST (std::codecvt_base::result, std::codecvt_base::noconv,
1270 unshift, (state, 0, 0, ext_2));
1271
1272 TEST (int, 0,
1273 length, (state, 0, 0, 0));
1274}
1275
1276
1278static void
1279test_invalid_args (const char* locname)
1280{
1281 // exercise the behavior of the base facets
1282 rw_info (0, __FILE__, __LINE__,
1283 "Testing %s with invalid arguments", TypeName<Codecvt>::name);
1284 test_mbstate_t ((Codecvt*)0, "C");
1285
1286 rw_info (0, __FILE__, __LINE__,
1287 "Testing %s with invalid arguments", TypeName<CodecvtW>::name);
1288 test_mbstate_t ((CodecvtW*)0, "C");
1289
1290 char non_c_locname [256];
1291 *non_c_locname = '\0';
1292
1293 for (const char *loc = rw_locale_query (); *loc;
1294 loc += std::strlen (loc) + 1) {
1295 if ( std::strcmp ("C", loc) && std::strcmp ("POSIX", loc)
1296 && std::setlocale (LC_ALL, loc)) {
1297 std::setlocale (LC_ALL, "C");
1298 std::strcpy (non_c_locname, loc);
1299 break;
1300 }
1301 }
1302
1303 if (*non_c_locname) {
1304 // exercise the behavior of the derived facets when using
1305 // libc locale names other than "C" or "POSIX"
1306
1307 rw_info (0, __FILE__, __LINE__,
1308 "Testing libc based %s with invalid arguments "
1309 "in locale(\"%s\")",
1310 TypeName<CodecvtBn>::name, non_c_locname);
1311
1312 test_mbstate_t ((CodecvtBn*)0, non_c_locname);
1313
1314 rw_info (0, __FILE__, __LINE__,
1315 "Testing libc based %s with invalid arguments "
1316 "in locale(\"%s\")",
1317 TypeName<CodecvtBnW>::name, non_c_locname);
1318 test_mbstate_t ((CodecvtBnW*)0, non_c_locname);
1319 }
1320
1321 if (locname) {
1322
1323 // exercise the behavior of the byname facets when using own
1324 // locale databases and when passed an invalid mbstate_t object
1325 rw_info (0, __FILE__, __LINE__,
1326 "Testing libstd %s with invalid arguments",
1328
1329 test_mbstate_t ((CodecvtBn*)0, locname);
1330
1331 rw_info (0, __FILE__, __LINE__,
1332 "Testing libstd %s with invalid arguments",
1334
1335 test_mbstate_t ((CodecvtBnW*)0, locname);
1336 }
1337}
1338
1339
1341template <class internT>
1342static void
1343test_inout (int which, int line, const char* name,
1344 const char* sext, std::size_t ext_len, std::size_t ext_num,
1345 const internT* sint, std::size_t int_len, std::size_t int_num,
1346 std::codecvt_base::result expect)
1347{
1349
1350 char namebuf [256];
1351 assert (255 >= std::strlen (name));
1352 std::strcpy (namebuf, name);
1353
1354 // when non-0, the name the locale object is constructed with
1355 const char* locale_name = 0;
1356
1357 // when non-0, the name the codevt_byname facet is constructed
1358 // with before being installed in the locale object
1359 const char* codecvt_name = 0;
1360
1361 // look for a locale name modifier
1362 const char* const mod = std::strrchr (name, '@');
1363
1364 if (mod && 'U' == mod [1] && 'C' == mod [2] && 'S' == mod [3]) {
1365
1366 namebuf [mod - name] = '\0';
1367 locale_name = namebuf;
1368 codecvt_name = namebuf + (mod - name) + 1;
1369 }
1370
1371 // check for the special names "UTF-8" and "utf-8" indicating
1372 // a codecvt_byname facet with UTF-8 as the external encoding
1373 // and UCS (either UCS-4 or UCS-2, depending on the width of
1374 // wchar_t) as the internal encoding (i.e., synonyms for
1375 // "UTF-8@UCS" and "utf-8@UCS" respectively)
1376 if ( !std::strcmp (namebuf, "UTF-8")
1377 || !std::strcmp (namebuf, "utf-8")) {
1378 codecvt_name = namebuf;
1379 locale_name = 0;
1380 }
1381 else
1382 locale_name = namebuf;
1383
1384 typedef std::codecvt<internT, char, std::mbstate_t> Cvt;
1385 typedef std::codecvt_byname<internT, char, std::mbstate_t> CvtByname;
1386
1387 std::locale loc;
1388
1389 // try to construct a locale with the given name
1390 if (locale_name) {
1391 _TRY {
1392 loc = std::locale (locale_name);
1393 }
1394 _CATCH (...) {
1395 const char* const envvar = std::getenv (LOCALE_ROOT_ENVAR);
1396
1397 rw_assert (false, __FILE__, __LINE__,
1398 "locale(\"%s\") unexpectedly threw an exception; "
1399 LOCALE_ROOT_ENVAR "=%s", locale_name,
1400 envvar ? envvar : "(null)");
1401
1402 return;
1403 }
1404 }
1405
1406 // if `codecvt_name' is non-0, try to construct a codecvt_byname
1407 // facet with that name and install it in the locale object
1408 // constructed above
1409 if (codecvt_name) {
1410
1411 const Cvt* pcvt = 0;
1412
1413 _TRY {
1414 // first try to construct the facet
1415 pcvt = new CvtByname (codecvt_name);
1416 }
1417 _CATCH (...) {
1418 const char* const envvar = std::getenv (LOCALE_ROOT_ENVAR);
1419
1420 rw_assert (false, __FILE__, __LINE__,
1421 "codecvt_byname<%s, char, mbstate_t>(\"%s\") "
1422 "unexpectedly threw an exception; "
1424 codecvt_name, envvar ? envvar : "(null)");
1425
1426 return;
1427 }
1428 _TRY {
1429 // next try to install the facet in the locale object
1430 loc = std::locale (loc, pcvt);
1431 }
1432 _CATCH (...) {
1433 rw_assert (false, __FILE__, __LINE__,
1434 "locale combining ctor unexpectedly threw "
1435 "an exception; ");
1436 delete pcvt;
1437 return;
1438 }
1439 }
1440
1441 // compute the length of the source sequence if it isn't specified
1442 if (std::size_t (-1) == ext_len)
1443 ext_len = sext ? std::strlen (sext) : 0;
1444
1445 // compute the length of the destination sequence if it isn't specified
1446 if (std::size_t (-1) == int_len)
1447 int_len = sint ? std::char_traits<internT>::length (sint) : 0;
1448
1449 // retrieve the codecvt or codecvt_byname facet from the locale object
1450 const Cvt &cvt = std::use_facet<Cvt>(loc);
1451
1452 std::mbstate_t state;
1453 std::memset (&state, 0, sizeof state);
1454
1455 // for convenience: fully qualified name of the function,
1456 // including the values of function arguments
1457 static char fcall [4096];
1458
1459 if ( ('I' == which || 'i' == which
1460 || 'o' == which) && std::codecvt_base::ok == expect) {
1461 // exercise do_in():
1462 // * the type of `sext' is char
1463 // * ext_len is the number of bytes in the external sequence
1464 // * the type of `sint' is internT (i.e., char or wchar_t)
1465 // * int_len is the number of internT characters
1466 // in the expected internal sequence
1467
1468 const char* ext_lo = sext;
1469 const char* ext_hi = sext + ext_len;
1470 const char* ext_nxt = 0;
1471
1472 internT* int_lo = new internT [int_len + 1];
1473 internT* int_hi = int_lo + int_len;
1474 internT* int_nxt = 0;
1475
1476 std::memset (int_lo, 0, (int_len + 1) * sizeof *int_lo);
1477
1478 // is the `sext' array is not NUL-terminated, create a copy
1479 // and NUL-terminate it
1480 const char* pextstr = sext;
1481 if (sext [ext_len]) {
1482 char* const tmp = new char [ext_len + 1];
1483 std::memcpy (tmp, sext, ext_len);
1484 tmp [ext_len] = '\0';
1485 pextstr = tmp;
1486 }
1487
1488 std::sprintf (fcall, "codecvt<%s, char, mbstate_t>::in"
1489 "(..., %p = %s, %p, %p, %p, %p, %p)",
1491 (const void*)ext_lo, pextstr,
1492 (const void*)ext_hi, (const void*)ext_nxt,
1493 (const void*)int_lo, (const void*)int_hi,
1494 (const void*)int_nxt);
1495
1496 if (pextstr != sext) {
1497 // const_cast works around an MSVC 6.0 bug (PR #30092)
1498 delete[] _RWSTD_CONST_CAST (char*, pextstr);
1499 }
1500
1501 std::codecvt_base::result res;
1502
1503 _TRY {
1504 res = cvt.in (state,
1505 ext_lo, ext_hi, ext_nxt,
1506 int_lo, int_hi, int_nxt);
1507 }
1508 _CATCH (...) {
1509 rw_assert (false, __FILE__, __LINE__,
1510 "%d. %s unexpectedly threw an exception",
1511 __LINE__, fcall);
1512 }
1513
1514 // verify the value returned from the function
1515 if (expect != res) {
1516 rw_assert (false, __FILE__, __LINE__,
1517 "%d. %s == %s, got %s", __LINE__, fcall,
1518 rwtest_codecvt_result (expect),
1519 rwtest_codecvt_result (res));
1520 }
1521
1522 // verify the value of the from_next pointer modified by the function
1523 if (ext_nxt != ext_lo + ext_num) {
1524
1525 rw_assert (false, __FILE__, __LINE__,
1526 "%d. %s; from_next == %p, got %p (at offset %d)",
1527 __LINE__, fcall, ext_lo + ext_num, ext_nxt,
1528 ext_nxt - ext_lo);
1529 }
1530
1531 // verify the value of the to_next pointer modified by the function
1532 if (int_nxt != int_lo + int_num) {
1533
1534 rw_assert (false, __FILE__, __LINE__,
1535 "%d. %s; to_next == %p, got %p (at offset %d)",
1536 __LINE__, fcall, int_lo + int_num, int_nxt,
1537 int_nxt - int_lo);
1538 }
1539
1540 if (std::codecvt_base::error != res) {
1541
1542 // verify that the contents of the destination sequence
1543 // matches the expected sequence
1544 const int cmp = std::memcmp (int_lo, sint, int_len);
1545
1546 if (cmp) {
1547 rw_assert (false, __FILE__, __LINE__,
1548 "%d. %s -> %s, expected %s", __LINE__, fcall,
1549 int_lo, sint);
1550 }
1551 }
1552
1553 delete[] int_lo;
1554 }
1555
1556 if ( ('O' == which || 'o' == which
1557 || 'i' == which) && std::codecvt_base::ok == expect) {
1558 // exercise do_out():
1559 // * the type of `sint' is internT (i.e., either char or wchar_t)
1560 // * int_len is the number of internT characters
1561 // * the type of `ext' is char
1562 // * ext_len is the number of bytes in the expected sequence
1563 // of external characters
1564
1565 char* ext_lo = new char [ext_len + 1];
1566 char* ext_hi = ext_lo + ext_len;
1567 char* ext_nxt = 0;
1568
1569 std::memset (ext_lo, 0, ext_len + 1);
1570
1571 const internT* int_lo = sint;
1572 const internT* int_hi = int_lo + int_len;
1573 const internT* int_nxt = 0;
1574
1575 const char* fmt;
1576 if (sizeof (internT) == sizeof (char))
1577 fmt = "codecvt<char, char, mbstate_t>::out"
1578 "(..., %p = %s, %p, %p, %p, %p, %p)";
1579 else if (sizeof (internT) == sizeof (wchar_t))
1580 fmt = "codecvt<wchar_t, char, mbstate_t>::out"
1581 "(..., %p = L%ls, %p, %p, %p, %p, %p)";
1582
1583 std::sprintf (fcall, fmt, (const void*)int_lo,
1584 int_lo, (const void*)int_hi,
1585 (const void*)int_nxt, (const void*)ext_lo,
1586 (const void*)ext_hi, (const void*)ext_nxt);
1587
1588 std::codecvt_base::result res;
1589
1590 _TRY {
1591 res = cvt.out (state,
1592 int_lo, int_hi, int_nxt,
1593 ext_lo, ext_hi, ext_nxt);
1594 }
1595 _CATCH (...) {
1596 rw_assert (false, __FILE__, __LINE__,
1597 "%d. %s unexpectedly threw an exception",
1598 __LINE__, fcall);
1599 }
1600
1601 // verify the value returned from the function
1602 if (expect != res) {
1603 rw_assert (false, __FILE__, __LINE__,
1604 "%d. %s == %s, got %s", __LINE__, fcall,
1605 rwtest_codecvt_result (expect),
1606 rwtest_codecvt_result (res));
1607 }
1608
1609 // verify the value of the from_next pointer modified by the function
1610 if (int_nxt != int_lo + int_num) {
1611
1612 rw_assert (false, __FILE__, __LINE__,
1613 "%d. %s; from_next == %p, got %p (at offset %d)",
1614 __LINE__, fcall, int_lo + int_num, int_nxt,
1615 int_nxt - int_lo);
1616 }
1617
1618 // verify the value of the to_next pointer modified by the function
1619 if (ext_nxt != ext_lo + ext_num) {
1620
1621 rw_assert (false, __FILE__, __LINE__,
1622 "%d. %s; to_next == %p, got %p (at offset %d)",
1623 __LINE__, fcall, ext_lo + ext_num, ext_nxt,
1624 ext_nxt - ext_lo);
1625 }
1626
1627 if (std::codecvt_base::error != res) {
1628
1629 // verify that the contents of the destination sequence
1630 // matches the expected sequence
1631 const int cmp = std::memcmp (ext_lo, sext, ext_len);
1632
1633 if (cmp) {
1634
1635 rw_assert (false, __FILE__, __LINE__,
1636 "%d. %s -> %s, expected %s", __LINE__, fcall,
1637 ext_lo, sext);
1638 }
1639 }
1640
1641 delete[] ext_lo;
1642 }
1643}
1644
1645
1646// the root of the locale directory (RWSTD_LOCALE_ROOT)
1647// set in main() instead of here to avoid Solaris 7 putenv() bug (PR #30017)
1648const char* locale_root;
1649
1650
1651// creates a codecvt database from `charmap'
1652static const char*
1653create_codecvt (unsigned mb_min,
1654 unsigned mb_max,
1655 const char* charmap,
1656 const char* charset_name = 0)
1657{
1658 // keeps track of successful calls and generates a unique
1659 // name for each codeset conversion database and locale
1660 static int call_no;
1661
1662 // construct the absolute pathname of a charmap file
1663 char cm_pathname [PATH_MAX];
1664
1665 if (charset_name)
1666 std::sprintf (cm_pathname, "%s" SLASH "%s.cm",
1667 locale_root, charset_name);
1668 else
1669 std::sprintf (cm_pathname,
1670 "%s" SLASH "codecvt-%u-%u.%d.cm",
1671 locale_root, mb_min, mb_max, call_no);
1672
1673 // create the charmap file
1674 std::FILE* pf = std::fopen (cm_pathname, "w");
1675 if (!pf)
1676 return 0;
1677
1678 if (charset_name)
1679 std::fprintf (pf, "<code_set_name> %s\n", charset_name);
1680 else
1681 std::fprintf (pf, "<code_set_name> codecvt-%u-%u.%d\n",
1682 mb_min, mb_max, call_no);
1683
1684 std::fprintf (pf, "<escape_char> /\n");
1685
1686 std::fprintf (pf, "<mb_cur_min> %u\n", mb_min);
1687 std::fprintf (pf, "<mb_cur_max> %u\n\n\n", mb_max);
1688 std::fprintf (pf, "CHARMAP\n");
1689 std::fprintf (pf, charmap);
1690 std::fprintf (pf, "\nEND CHARMAP\n");
1691
1692 std::fclose (pf);
1693
1694 // construct the absolute pathname of a dummy locale definition file
1695 char src_pathname [PATH_MAX];
1696 std::strcpy (src_pathname, locale_root);
1697 std::strcat (src_pathname, SLASH "dummy.src");
1698
1699 // create the locale definition file
1700 if (!(pf = std::fopen (src_pathname, "w")))
1701 return 0;
1702
1703 // dummy source file must contain the LC_CTYPE section
1704 // in order for localedef to generate the codecvt database
1705 std::fprintf (pf, "LC_CTYPE\nEND LC_CTYPE\n");
1706
1707 std::fclose (pf);
1708
1709 // construct the filename of the locale
1710 char locale_fname[32];
1711 std::sprintf (locale_fname,
1712 "locale-%u.%u-%d",
1713 mb_min, mb_max, call_no);
1714
1715 // invoke localedef to create the named locale from the dummy
1716 // locale definition file and the character set description file
1717 // silence the following warnings:
1718 // 701: no compatible locale found
1719 // 702: member of portable character set <x> not found
1720 // in the character map
1721 // 706: iconv_open() failed
1722 // : unknown symbol found in LC_COLLATE definition
1723 // : some characters in the codeset were not explicitly
1724 // given a collation value
1725 const char* const locname =
1726 rw_localedef ("-w701 -w702 -w706",
1727 src_pathname, cm_pathname, locale_fname);
1728
1729 call_no += !!locname;
1730
1731 return locname;
1732}
1733
1734
1735// given a canonical locale name, `locname', tries to find a platform
1736// specific locale name that corresponds to the name; when `codeset'
1737// is non-0, also checks to see that the platform-specific locale's
1738// codeset is the same as that specified by the argument
1739// on success, returns the name of the platform-specific locale,
1740// otherwise 0
1741static const char*
1742find_locale (const char* locname, const char* codeset)
1743{
1744 static const struct {
1745 const char* locnames [16];
1746 const char* codesets [16];
1747 } aliases [] = {
1748 { {
1749 // canonical locale name, followed by its common aliases
1750 "de_DE.ISO-8859-1",
1751 "de_DE.iso88591", "de_DE.ISO8859-1", "de_DE", "DEU", "de", 0
1752 }, {
1753 // well-known codeset name, followed by its common aliases
1754 "ISO-8859-1",
1755 "ISO-88591", "ISO_8859-1", "ISO8859-1", "iso88591", "iso1", 0
1756 // Windows Codepage 1252 (Latin I)
1757 // http://www.microsoft.com/globaldev/reference/sbcs/1252.htm
1758 } },
1759 { {
1760 "fr_FR.ISO-8859-1",
1761 "fr_FR.iso88591", "fr_FR.ISO8859-1", "fr_FR", "FRA", "fr", 0
1762 }, {
1763 "ISO-8859-1",
1764 "ISO-88591", "ISO_8859-1", "ISO8859-1", "iso88591", "iso1", 0
1765 } },
1766 { {
1767 "ja_JP.Shift_JIS",
1768 "ja_JP.SJIS", "japanese.sjis", "JPN", 0
1769 }, {
1770 "Shift_JIS",
1771 "Shift-JIS", "SJIS", "SHIFT-JIS", "SHIFT_JIS", "shift-jis",
1772 "sjis", 0
1773 // Windows Codepage 932 (Japanese Shift-JIS)
1774 // http://www.microsoft.com/globaldev/reference/dbcs/932.htm
1775 } },
1776 { {
1777 "ja_JP.EUC-JP",
1778 "ja_JP.eucJP", "ja_JP.EUC", "ja_JP.eucjp", 0
1779 }, {
1780 "EUC-JP",
1781 "eucjp", "eucJP", "euc_jp", "euc", "ujis", 0
1782 } },
1783 { { 0 }, { 0 } }
1784 };
1785
1786 const char* name = std::setlocale (LC_ALL, locname);
1787
1788 std::size_t inx = std::size_t (-1);
1789
1790 if (!name) {
1791
1792 // find the index, `inx', of `locname' in the table
1793 for (std::size_t i = 0; i != sizeof aliases / sizeof *aliases; ++i) {
1794 if (!aliases [i].locnames [0])
1795 break;
1796
1797 if (!std::strcmp (locname, aliases [i].locnames [0])) {
1798 inx = i;
1799 break;
1800 }
1801 }
1802
1803 if (std::size_t (-1) != inx) {
1804
1805 // go through the locale name's aliases until one
1806 // that's a valid argument to setlocale() is found
1807 for (std::size_t j = 1; aliases [inx].locnames [j]; ++j) {
1808 if (!aliases [inx].locnames [j])
1809 break;
1810
1811 if (std::setlocale (LC_ALL, aliases [inx].locnames [j])) {
1812 name = aliases [inx].locnames [j];
1813 break;
1814 }
1815 }
1816 }
1817 }
1818
1819#ifndef _RWSTD_NO_NL_LANGINFO
1820
1821 if (name) {
1822 const char* const cset = nl_langinfo (CODESET);
1823
1824 if (codeset && std::strcmp (codeset, cset)) {
1825
1826 // if `codeset' is specified, verify that it matches
1827 // the codeset used to encode the libc locale found
1828 // and set above
1829
1830 for (std::size_t j = 0; aliases [inx].codesets [j]; ++j) {
1831
1832 if (!std::strcmp (aliases [inx].codesets [j], cset)) {
1833 std::setlocale (LC_ALL, "C");
1834 return name;
1835 }
1836 }
1837 name = 0;
1838 }
1839
1840 std::setlocale (LC_ALL, "C");
1841 }
1842
1843#endif // _RWSTD_NO_NL_LANGINFO
1844
1845 return name;
1846}
1847
1848
1849const char ext_ascii[] = {
1850 // basic ASCII
1851 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
1852 "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
1853 "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
1854 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
1855 "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
1856 "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
1857 "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
1858 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
1859 // extended ASCII
1860 "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
1861 "\x90\x91\x92\x93\x94\x95\x96\x97\x89\x99\x9a\x9b\x9c\x9d\x9e\x9f"
1862 "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
1863 "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
1864 "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
1865 "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
1866 "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
1867 "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
1868};
1869
1870
1871// tries to find a locale whose internal (wchar_t) representation
1872// of the Extended ASCII character set does not match the ASCII
1873// character values; if such locale is found, fills up to `bufsize'
1874// elements of the `buf' array with such characters and returns
1875// the name of the locale
1876static const char*
1877find_interesting_locale (char* buf, std::size_t bufsize)
1878{
1879 std::memset (buf, 0, bufsize);
1880
1881 const char* name = 0;
1882
1883 const char* const buf_save = buf;
1884
1885 for (name = rw_locale_query (); *name; name += std::strlen (name) + 1) {
1886
1887 if (!std::setlocale (LC_ALL, name))
1888 continue;
1889
1890 wchar_t wide_ascii [sizeof ext_ascii] = { 0 };
1891
1892 // convert the array of narrow Extended ASCII characters
1893 // to their corresponding wchar_t values using mbstowcs()
1894 const std::size_t nchars =
1895 std::mbstowcs (wide_ascii + 1, ext_ascii + 1, sizeof ext_ascii - 2);
1896
1897 // continue on error
1898 if (!nchars || nchars > sizeof ext_ascii - 2)
1899 continue;
1900
1901 // look for a wide character with value different
1902 // from the narrow single-byte character
1903 for (std::size_t i = 0; i != nchars; ++i) {
1904
1905 typedef unsigned char UChar;
1906
1907 // convert to unsigned char before comparing
1908 const UChar uc = UChar (ext_ascii [i]);
1909
1910 if (unsigned (uc) != unsigned (wide_ascii [i])) {
1911 if (bufsize) {
1912 *buf++ = ext_ascii [i];
1913 --bufsize;
1914 }
1915 }
1916 }
1917
1918 if (buf != buf_save)
1919 break;
1920 }
1921
1922 return name;
1923}
1924
1925
1926template <class internT>
1927static void
1928test_inout (const char* tname)
1929{
1930 // for convenience
1931 const std::codecvt_base::result error = std::codecvt_base::error;
1932 const std::codecvt_base::result noconv = std::codecvt_base::noconv;
1933 const std::codecvt_base::result ok = std::codecvt_base::ok;
1934 const std::codecvt_base::result partial = std::codecvt_base::partial;
1935
1936 _RWSTD_UNUSED (noconv);
1937
1938 const char* locname = 0;
1939
1941 // exercise both codecvt::in() and codecvt::out()
1942
1943 rw_info (0, __FILE__, __LINE__,
1944 "std::codecvt<%s, char, mbstate_t>::in() "
1945 "in a generated locale", tname);
1946
1947 rw_info (0, __FILE__, __LINE__,
1948 "std::codecvt<%s, char, mbstate_t>::out() "
1949 "in a generated locale", tname);
1950
1951 // exercise a single-byte external encoding
1952
1953 rw_info (0, __FILE__, __LINE__, "<mb_cur_max> 1");
1954
1955 locname = create_codecvt (1, 1, // MB_CUR_MAX = 1 (min = 1)
1956 // internal external (single-byte)
1957 /* NUL */ "<U0000> /x30\n" // L"\0" <-> "0"
1958 /* <A> */ "<U0041> /x31\n" // L"A" <-> "1"
1959 /* <B> */ "<U0042> /x32\n" // L"B" <-> "2"
1960 /* <C> */ "<U0043> /x33\n" // L"C" <-> "3"
1961 /* <D> */ "<U0044> /x34\n" // L"D" <-> "4"
1962 /* <E> */ "<U0045> /x35\n" // L"E" <-> "5"
1963 /* <F> */ "<U0046> /x36\n" // L"F" <-> "6"
1964 /* <Z> */ "<U005A> /x00\n" // L"Z" <-> "\0"
1965
1966#if _RWSTD_WCHAR_T_MAX > 0xffffU
1967 "<U12345678> /x78\n" // 0x12345678 <-> "x"
1968 "<U0DEDBEEF> /x79\n" // 0x0dedbeef <-> "y"
1969#else // if (WCHAR_T_MAX <= 0xffffU)
1970 "<U1234> /x78\n" // 0x1234 <-> "x"
1971 "<UBEEF> /x79\n" // 0xbeef <-> "y"
1972#endif // _RWSTD_WCHAR_T_MAX > 0xffffU
1973 );
1974
1975 if (!locname) {
1976 rw_assert (false, __FILE__, __LINE__,
1977 "failed to generate locale");
1978 return;
1979 }
1980
1981#define DO_TEST(io, src, ext_len, ext_num, dst, int_len, int_num, res) \
1982 test_inout (io, __LINE__, locname, src, ext_len, ext_num, \
1983 dst, int_len, int_num, res)
1984
1985// TEST_IN: tests only codecvt::in()
1986#define TEST_IN(src, ext_len, ext_num, dst, int_len, int_num, res) \
1987 DO_TEST ('I', src, ext_len, ext_num, dst, int_len, int_num, res)
1988
1989// TEST_OUT: tests only codecvt::out()
1990#define TEST_OUT(src, ext_len, ext_num, dst, int_len, int_num, res) \
1991 DO_TEST ('O', src, ext_len, ext_num, dst, int_len, int_num, res)
1992
1993// TEST_IN_OUT: tests codecvt::in() and codecvt::out() only
1994// if the expected result is codecvt_base::ok
1995#define TEST_IN_OUT(src, ext_len, ext_num, dst, int_len, int_num, res) \
1996 DO_TEST ('i', src, ext_len, ext_num, dst, int_len, int_num, res)
1997
1998// TEST_OUT_IN: tests codecvt::out() and codecvt::in() only
1999// if the expected result is codecvt_base::ok
2000#define TEST_OUT_IN(src, ext_len, ext_num, dst, int_len, int_num, res) \
2001 DO_TEST ('o', src, ext_len, ext_num, dst, int_len, int_num, res)
2002
2003 // +------------------------- contents of external (source) buffer
2004 // | +-------------------- size of external (source) sequence
2005 // | | +----------------- expected size of consumed input
2006 // | | | +-------------- expected contents of internal buffer
2007 // | | | | +-------- size of dest. buffer (in chars)
2008 // | | | | | +----- expected size of output (in chars)
2009 // | | | | | | +-- expected result
2010 // V V V V V V V
2011 TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
2012 TEST_IN_OUT ("0", 1, 1, L"", 1, 1, ok); // "0" maps to wchar_t (0)
2013 TEST_IN_OUT ("1", 1, 1, L"A", 1, 1, ok);
2014 TEST_IN_OUT ("2", 1, 1, L"B", 1, 1, ok);
2015 TEST_IN_OUT ("3", 1, 1, L"C", 1, 1, ok);
2016 TEST_IN_OUT ("4", 1, 1, L"D", 1, 1, ok);
2017 TEST_IN_OUT ("5", 1, 1, L"E", 1, 1, ok);
2018 TEST_IN_OUT ("6", 1, 1, L"F", 1, 1, ok);
2019 TEST_IN_OUT ("7", 1, 0, L"", 1, 0, error);
2020 TEST_IN_OUT ("0", 1, 0, L"", 0, 0, partial); // not enough space
2021
2022 TEST_IN_OUT ("12", 2, 2, L"AB", 2, 2, ok);
2023 TEST_IN_OUT ("123", 3, 3, L"ABC", 3, 3, ok);
2024 TEST_IN_OUT ("0123", 4, 4, L"\0ABC", 4, 4, ok);
2025 TEST_IN_OUT ("0123Z", 5, 4, L"\0ABC", 5, 4, error);
2026 TEST_IN_OUT ("01234", 5, 4, L"\0ABC", 4, 4, partial);
2027
2028#if _RWSTD_WCHAR_T_MAX > 0xffffU
2029
2030 TEST_IN_OUT ("x", 1, 1, L"\x12345678", 1, 1, ok);
2031 TEST_IN_OUT ("y", 1, 1, L"\x0dedbeef", 1, 1, ok);
2032
2033 TEST_IN_OUT ("0123x", 5, 5, L"\0ABC\x12345678", 5, 5, ok);
2034 TEST_IN_OUT ("123y", 4, 4, L"ABC\x0dedbeef", 4, 4, ok);
2035
2036#else
2037
2038 TEST_IN_OUT ("x", 1, 1, L"\x1234", 1, 1, ok);
2039 TEST_IN_OUT ("y", 1, 1, L"\xbeef", 1, 1, ok);
2040
2041 TEST_IN_OUT ("0123x", 5, 5, L"\0ABC\x1234", 5, 5, ok);
2042 TEST_IN_OUT ("123y", 4, 4, L"ABC\xbeef", 4, 4, ok);
2043
2044#endif // _RWSTD_WCHAR_T_MAX > 0xffffU
2045
2046
2047 // exercise multi-byte external encodings
2048
2049 rw_info (0, __FILE__, __LINE__, "<mb_cur_max> 2");
2050
2051 locname = create_codecvt (1, 2, // MB_CUR_MAX = 2 (min = 1)
2052 // internal external (multi-byte)
2053 /* NUL */ "<U0000> /x30\n" // '\0' <-> "0"
2054 /* <A> */ "<U0041> /x31/x61\n" // "A" <--> "1a"
2055 /* <B> */ "<U0042> /x32\n" // "B" <--> "2"
2056 /* <C> */ "<U0043> /x33/x62\n" // "C" <--> "3b"
2057 /* <D> */ "<U0044> /x34\n" // "D" <--> "4"
2058 /* <E> */ "<U0045> /x35/x63\n" // "E" <--> "3c"
2059 /* <F> */ "<U0046> /x36\n" // "F" <--> "4"
2060 /* <Z> */ "<U005A> /x00/x00"); // "Z" <--> "\0\0"
2061
2062 if (!locname) {
2063 rw_assert (false, __FILE__, __LINE__,
2064 "failed to generate locale");
2065 return;
2066 }
2067
2068 TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
2069 TEST_IN_OUT ("0", 1, 1, L"", 1, 1, ok); // "0" maps to wchar_t (0)
2070 TEST_IN_OUT ("1a", 2, 2, L"A", 1, 1, ok);
2071 TEST_IN_OUT ("2", 1, 1, L"B", 1, 1, ok);
2072 TEST_IN_OUT ("3b", 2, 2, L"C", 1, 1, ok);
2073 TEST_IN_OUT ("4", 1, 1, L"D", 1, 1, ok);
2074 TEST_IN_OUT ("5c", 2, 2, L"E", 1, 1, ok);
2075 TEST_IN_OUT ("6", 1, 1, L"F", 1, 1, ok);
2076 TEST_IN_OUT ("7", 1, 0, L"", 1, 0, error);
2077 TEST_IN_OUT ("1", 1, 0, L"", 0, 0, partial); // not enough space
2078
2079 // exercise only in()
2080 // result is partial due to the incomplete multibyte character
2081 TEST_IN ("3", 1, 0, L"", 1, 0, partial);
2082
2083 TEST_IN_OUT ("01a23b", 6, 6, L"\0ABC", 4, 4, ok);
2084 TEST_IN_OUT ("01a23b4", 7, 7, L"\0ABCD", 5, 5, ok);
2085 TEST_IN_OUT ("01a23b45", 8, 7, L"\0ABCD", 5, 5, partial);
2086 TEST_IN_OUT ("01a23b45c", 9, 9, L"\0ABCDE", 6, 6, ok);
2087 TEST_IN_OUT ("01a23c45c", 9, 4, L"\0ABCDE", 6, 3, error);
2088
2089
2090 rw_info (0, __FILE__, __LINE__, "<mb_cur_max> 6");
2091
2092 locname = create_codecvt (1, 6, // MB_CUR_MAX = 6 (min = 1)
2093 // internal external (multi-byte)
2094 /* NUL */ "<U0000> /x35\n" // "\0" <-> "5"
2095 /* <A> */ "<U0041> /x30/x31\n" // "A" <--> "01"
2096 /* <B> */ "<U0042> /x31/x32/x33\n" // "B" <--> "123"
2097 /* <C> */ "<U0043> /x32/x33/x34/x35\n" // "C" <--> "2345"
2098 /* <D> */ "<U0044> /x33/x34/x35/x36/x37\n" // "D" <--> "34567"
2099 /* <E> */ "<U0045> /x34/x35/x36/x37/x38/x39\n" // "E" <--> "456789"
2100 /* <Z> */ "<U005A> /x00/x00/x00"); // "Z" <--> "\0\0\0"
2101
2102 if (!locname) {
2103 rw_assert (false, __FILE__, __LINE__, "failed to generate locale");
2104 return;
2105 }
2106
2107 TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
2108 TEST_IN_OUT ("01", 2, 2, L"A", 1, 1, ok);
2109 TEST_IN_OUT ("012", 3, 2, L"A", 1, 1, partial);
2110 TEST_IN_OUT ("0123", 4, 2, L"A", 1, 1, partial);
2111 TEST_IN_OUT ("01234", 5, 2, L"A", 1, 1, partial);
2112 TEST_IN_OUT ("012345", 6, 6, L"AC", 2, 2, ok);
2113 TEST_IN_OUT ("123456789", 9, 9, L"BE", 3, 2, ok);
2114 TEST_IN_OUT ("456789012345", 12, 12, L"EAC", 3, 3, ok);
2115
2116 // the first one below is partial even though the external sequence
2117 // ends in the invalid byte '6' since there is no room in the dest.
2118 // buffer (this could be either partial or error, the latter if the
2119 // function verifies the validity of the character before checking
2120 // whether there is sufficient room in the destination buffer)
2121 TEST_IN_OUT ("0123456", 7, 6, L"AC", 2, 2, partial /* or error */);
2122 TEST_IN_OUT ("0123456", 7, 6, L"AC", 3, 2, error);
2123
2124#ifndef _RWSTD_NO_NL_LANGINFO
2125
2126 char chars [256];
2127 const char* const interesting_locale_name =
2128 find_interesting_locale (chars, sizeof chars);
2129
2130 if (interesting_locale_name) {
2131
2132 std::setlocale (LC_ALL, interesting_locale_name);
2133 const char* const codeset = nl_langinfo (CODESET);
2134
2135 rw_info (0, __FILE__, __LINE__,
2136 "<code_set_name> %s (locale(\"%s\"))",
2137 codeset, interesting_locale_name);
2138
2139 typedef unsigned char UChar;
2140
2141 char charmap [sizeof chars * 40];
2142
2143 charmap [0] = '\0';
2144
2145 for (const char* pc = chars; *pc; ++pc) {
2146 std::sprintf (charmap + std::strlen (charmap),
2147 "<U%04X> /x%02x\n", UChar (*pc), UChar (*pc));
2148 }
2149
2150 locname = create_codecvt (1, 1, charmap, codeset);
2151
2152 if (!locname) {
2153 rw_assert (false, __FILE__, __LINE__,
2154 "failed to generate locale");
2155 return;
2156 }
2157
2158 wchar_t wchars [sizeof chars];
2159 std::mbstowcs (wchars, chars, std::strlen (chars));
2160
2161 std::setlocale (LC_ALL, "C");
2162
2163 for (std::size_t i = 0; chars [i]; ++i) {
2164
2165 const char cs [] = { chars [i], '\0' };
2166 const wchar_t ws [] = { wchars [i], 0 };
2167
2168 TEST_IN_OUT (cs, 1, 1, ws, 1, 1, ok);
2169 }
2170 }
2171
2172#endif // _RWSTD_NO_NL_LANGINFO
2173
2174 // exercise codecvt_byname constructed with the special names below
2175 const char* const names[] = {
2176 // "UTF" prefix in all caps causes strict checking of UTF
2177 // sequences at some loss in performance; "utf" prefix (all
2178 // lowercase) allows for a faster implementation but accepts
2179 // some sequences that are strictly speaking invalid (see
2180 // below)
2181
2182 "UTF-8", "UTF-8@UCS",
2183
2184#if _RWSTD_WCHAR_T_MAX > 0xffffU
2185 "UTF-8@UCS-4",
2186#else // if _RWSTD_WCHAR_T_MAX <= 0xffffU
2187 "UTF-8@UCS-2",
2188#endif // WCHAR_T_MAX > 0xffffU
2189
2190 "utf-8", "utf-8@UCS",
2191
2192#if _RWSTD_WCHAR_T_MAX > 0xffffU
2193 "utf-8@UCS-4",
2194#else // if _RWSTD_WCHAR_T_MAX <= 0xffffU
2195 "utf-8@UCS-2",
2196#endif // WCHAR_T_MAX > 0xffffU
2197 };
2198
2199 for (std::size_t i = 0; i != sizeof names / sizeof *names; ++i) {
2200 locname = names [i];
2201
2202 rw_info (0, __FILE__, __LINE__,
2203 "codecvt_byname<wchar_t, char, mbstate_t>"
2204 "(\"%s\")", locname);
2205
2206 // strict conformance mode
2207 const bool strict_mode = 'U' == *locname;
2208
2209 TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
2210 TEST_IN_OUT ("\0", 1, 1, L"\0", 1, 1, ok);
2211 TEST_IN_OUT ("a", 1, 1, L"a", 1, 1, ok);
2212 TEST_IN_OUT ("b", 1, 1, L"b", 1, 1, ok);
2213 TEST_IN_OUT ("z", 1, 1, L"z", 1, 1, ok);
2214 TEST_IN_OUT ("\x7f", 1, 1, L"\x7f", 1, 1, ok);
2215
2216 TEST_IN ("\x80", 1, 0, L"", 1, 0, error);
2217 TEST_IN ("\x81", 1, 0, L"", 1, 0, error);
2218 TEST_IN ("\x82", 1, 0, L"", 1, 0, error);
2219 TEST_IN ("\xc1", 1, 0, L"", 1, 0, error);
2220
2221 TEST_IN_OUT ("\xc2\x80", 2, 2, L"\x80", 1, 1, ok);
2222 TEST_IN_OUT ("\xc2\x81", 2, 2, L"\x81", 1, 1, ok);
2223 TEST_IN_OUT ("\xc2\x82", 2, 2, L"\x82", 1, 1, ok);
2224 TEST_IN_OUT ("\xc2\xbf", 2, 2, L"\xbf", 1, 1, ok);
2225
2226 TEST_IN_OUT ("\xc3\x80", 2, 2, L"\xc0", 1, 1, ok);
2227 TEST_IN_OUT ("\xc3\x81", 2, 2, L"\xc1", 1, 1, ok);
2228
2229 TEST_IN_OUT ("\xde\xb0", 2, 2, L"\x07b0", 1, 1, ok);
2230
2231 TEST_IN_OUT ("\xe0\xa4\x81", 3, 3, L"\x0901", 1, 1, ok);
2232 TEST_IN_OUT ("\xe3\x8f\xbe", 3, 3, L"\x33fe", 1, 1, ok);
2233 TEST_IN_OUT ("\xe3\x90\x80", 3, 3, L"\x3400", 1, 1, ok);
2234 TEST_IN_OUT ("\xe3\x91\x80", 3, 3, L"\x3440", 1, 1, ok);
2235
2236 if (strict_mode) {
2237 // otherwise benign invalid patterns detected only in strict mode
2238
2239 // test the ability to detect and diagnose overlong sequences
2240
2241 // exercise, e.g., alternative encodings of U+0000 (i.e., <NUL>)
2242 TEST_IN ("\xc0\x80", 2, 0, L"", 1, 0, error);
2243 TEST_IN ("\xe0\x80\x80", 3, 0, L"", 1, 0, error);
2244 TEST_IN ("\xf0\x80\x80\x80", 4, 0, L"", 1, 0, error);
2245 TEST_IN ("\xf8\x80\x80\x80\x80", 5, 0, L"", 1, 0, error);
2246 TEST_IN ("\xfc\x80\x80\x80\x80\x80", 6, 0, L"", 1, 0, error);
2247
2248 // exercise, e.g., alternative encodings of U+000A (i.e., <LF>)
2249 TEST_IN ("\xc0\x8a", 2, 0, L"", 1, 0, error);
2250 TEST_IN ("\xe0\x80\x8a", 3, 0, L"", 1, 0, error);
2251 TEST_IN ("\xf0\x80\x80\x8a", 4, 0, L"", 1, 0, error);
2252 TEST_IN ("\xf8\x80\x80\x80\x8a", 5, 0, L"", 1, 0, error);
2253 TEST_IN ("\xfc\x80\x80\x80\x80\x8a", 6, 0, L"", 1, 0, error);
2254
2255 // test the ability to detect and diagnose UTF-16 surrogate
2256 // pairs and the special code points U+FFFE and U+FFFF
2257
2258 TEST_OUT ("", 8, 0, L"\xd800", 1, 0, error);
2259 TEST_OUT ("", 8, 0, L"\xd801", 1, 0, error);
2260 TEST_OUT ("", 8, 0, L"\xdffe", 1, 0, error);
2261 TEST_OUT ("", 8, 0, L"\xdfff", 1, 0, error);
2262 TEST_OUT ("", 8, 0, L"\xfffe", 1, 0, error);
2263 TEST_OUT ("", 8, 0, L"\xffff", 1, 0, error);
2264
2265 // the second and subsequent bytes of a multibyte UTF-8
2266 // sequence must have the following bit pattern: 10xxxxxx
2267 TEST_IN ("\xc2\x01", 2, 0, L"", 1, 0, error);
2268 TEST_IN ("\xc2\xff", 2, 0, L"", 1, 0, error);
2269
2270 }
2271 else {
2272 // in relaxed mode the UTF-8 sequences below convert
2273 // into the UCS characters U+3081 and U+30BF even
2274 // though the UCS characters convert into 3-byte
2275 // UTF-8 characters each (see below)
2276 TEST_IN ("\xc2\x01", 2, 2, L"\x3081", 1, 1, ok);
2277 TEST_IN ("\xc2\xff", 2, 2, L"\x30bf", 1, 1, ok);
2278 }
2279
2280 TEST_OUT ("\xe3\x82\x81", 3, 3, L"\x3081", 1, 1, ok);
2281 TEST_OUT ("\xe3\x82\xbf", 3, 3, L"\x30bf", 1, 1, ok);
2282
2283 TEST_IN_OUT ("\x00", 1, 1, L"\x00000000", 1, 1, ok);
2284 TEST_IN_OUT ("\x7f", 1, 1, L"\x0000007f", 1, 1, ok);
2285
2286 TEST_IN_OUT ("\xc2\x80", 2, 2, L"\x00000080", 1, 1, ok);
2287 TEST_IN_OUT ("\xdf\xbf", 2, 2, L"\x000007ff", 1, 1, ok);
2288
2289 TEST_IN_OUT ("\xe0\xa0\x80", 3, 3, L"\x00000800", 1, 1, ok);
2290
2291#if _RWSTD_WCHAR_T_MAX > 0xffffU
2292
2293 TEST_IN_OUT ("\xf0\x90\x8c\x80", 4, 4, L"\x00010300", 1, 1, ok);
2294 TEST_IN_OUT ("\xf0\x90\x8c\x81", 4, 4, L"\x00010301", 1, 1, ok);
2295 TEST_IN_OUT ("\xf4\x8f\xbf\x80", 4, 4, L"\x0010ffc0", 1, 1, ok);
2296
2297 TEST_IN_OUT ("\xf0\x90\x80\x80", 4, 4, L"\x0010000", 1, 1, ok);
2298 TEST_IN_OUT ("\xf8\x88\x80\x80\x80", 5, 5, L"\x0200000", 1, 1, ok);
2299 TEST_IN_OUT ("\xfc\x84\x80\x80\x80\x80", 6, 6, L"\x4000000", 1, 1, ok);
2300
2301#endif // _RWSTD_WCHAR_T_MAX > 0xffffU
2302 }
2303}
2304
2305
2307static void
2308test_ascii (const char *locname, const char* native_locname)
2309{
2310 _RWSTD_ASSERT (0 != locname);
2311 _RWSTD_ASSERT (0 != native_locname);
2312
2313 rw_info (0, __FILE__, __LINE__,
2314 "Testing conversion of Extended ASCII range in "
2315 "locale(\"%s\") against the native locale \"%s\"",
2316 locname, native_locname);
2317
2318 wchar_t wascii [sizeof ext_ascii];
2319
2320 const std::size_t ext_num = sizeof ext_ascii - 2;
2321 std::size_t int_num = ext_num;
2322
2323 // try to convert the whole extended ascii range
2324 if (rwtest_convert_to_internal (use_libc, native_locname,
2325 ext_ascii + 1, ext_num,
2326 wascii, int_num)) {
2327
2328 wascii [int_num] = L'\0';
2329
2330 test_inout ('i', __LINE__, locname,
2331 ext_ascii + 1, ext_num, ext_num, wascii, int_num, int_num,
2332 std::codecvt_base::ok);
2333
2334 return;
2335 }
2336
2337 // conversion of the whole range failed,
2338 // convert one character at a time
2339
2340 for (std::size_t i = 1; i != UCHAR_MAX + 1; ++i) {
2341
2342 if (rwtest_convert_to_internal (use_libc, native_locname,
2343 ext_ascii + i, 1,
2344 wascii, int_num)) {
2345 wascii [int_num] = L'\0';
2346
2347 test_inout ('i', __LINE__, locname,
2348 ext_ascii + i, 1, 1,
2349 wascii, int_num, int_num,
2350 std::codecvt_base::ok);
2351 }
2352 }
2353}
2354
2355
2357// - checks the conversion for each the locales in the locales array
2358static int
2359run_test (int /*unused*/, char* /*unused*/ [])
2360{
2361 // set up RWSTD_LOCALE_ROOT and other environment variables
2362 // here as opposed to at program startup to work around a
2363 // SunOS 5.7 bug in putenv() (PR ##30017)
2365
2366#if 0 // FIXME
2367
2368 // codecvt_byname<char, char, mbstate_t> behaves just like
2369 // the base, codecvt<char, char, mbstate_t>, i.e., it does
2370 // no conversion
2371 test_inout (*this, char ());
2372
2373#endif // 0/1
2374
2375 test_inout<wchar_t> ("wchar_t");
2376
2377 test_virtuals<Codecvt> (0);
2378 test_virtuals<CodecvtW> ("C");
2379
2380#ifndef _RWSTD_NO_WCHAR_T
2381
2382 test_virtuals<CodecvtBn> ("C");
2383 test_virtuals<CodecvtBnW> ("C");
2384
2385#endif // _RWSTD_NO_WCHAR_T
2386
2387#define TEST_UCS_MODIFIER(T, mod, enc, locname, f, i, is) \
2388 do { \
2389 char locname_mod [256]; /* <locale-name>@<modifier>*/ \
2390 if (*(mod)) \
2391 std::sprintf (locname_mod, "%s@%s", locname, (mod)); \
2392 else \
2393 std::sprintf (locname_mod, "%s", locname); \
2394 \
2395 _TRY { \
2396 const CodecvtBnW cc (locname_mod, 1); \
2397 std::locale loc = std::locale (std::locale::classic (), &cc); \
2398 \
2399 cc._C_opts |= cc._C_use_libstd; \
2400 cc._C_opts &= ~cc._C_use_libc; \
2401 test_ucs_modifier (locname_mod, enc, s, cc, f, i, is); \
2402 \
2403 } _CATCH (...) { \
2404 rw_assert (false, __FILE__, __LINE__, \
2405 "unexpected exception in locale test %s", \
2406 locname_mod); \
2407 } \
2408 } while (0)
2409
2410#define TEST_LIBSTD(L,T,C,c,f,s,i,is,o,os,ur,ar,er,lr,mr) \
2411 _TRY { \
2412 test_libstd_codecvt<T>(L,c,f,s,i,is,o,os,ur,ar,er,lr,mr); \
2413 } _CATCH (...) { \
2414 rw_assert (false, __FILE__, __LINE__, \
2415 "unexpected exception in conversion using %s " \
2416 "(locale %s)", C ? "C library" : "std library", L); \
2417 }
2418
2419#define TEST_CONVERSION(T,L,C,f,s,i,is,o,os,ur,er,ar,lr,mr) \
2420 do { \
2421 std::locale loc; \
2422 _TRY { \
2423 loc = std::locale (L); \
2424 } _CATCH (...) { \
2425 rw_assert (false, __FILE__, __LINE__, \
2426 "locale(\"%s\") unexpectedly threw an " \
2427 "exception; " LOCALE_ROOT_ENVAR " = %s", L, \
2428 locale_root); \
2429 break; \
2430 } \
2431 _TRY { \
2432 const T &cc = create_##T (loc); \
2433 \
2434 cc._C_opts |= cc._C_use_libstd; \
2435 cc._C_opts &= ~cc._C_use_libc; \
2436 TEST_LIBSTD (L,T,C,cc,f,s,i,is,o,os,ur,ar,er,lr,mr); \
2437 \
2438 if (C == true && rwtest_is_C_locale (f)) { \
2439 cc._C_opts &= ~cc._C_use_libstd; \
2440 cc._C_opts |= cc._C_use_libc; \
2441 TEST_LIBSTD(L,T,C,cc,f,s,i,is,o,os,ur,ar,er,lr,mr); \
2442 } \
2443 } _CATCH (...) { \
2444 rw_assert (false, __FILE__, __LINE__, \
2445 "unexpected exception in locale test %s", L); \
2446 } \
2447 } while (0)
2448
2449
2450 static const struct {
2451 const char* src_name; // locale definition file name
2452 const char* charmap_name; // charset description file name
2453 const char* locale_name; // name of the locale database
2454 std::size_t nbytes; // size of test buffer
2455 std::size_t nchars; // number of characters in buffer
2456 std::size_t encoding; // result of codecvt::encoding()
2457 std::size_t max_length; // result of codecvt::max_length()
2458 } locales [] = {
2459 // single-width encodings where the number of characters
2460 // equals the number of bytes (and max_length == 1)
2461 { "de_DE", "ISO-8859-1", "de_DE.ISO-8859-1", 6826, 6826, 1, 1 },
2462 { "fr_FR", "ISO-8859-1", "fr_FR.ISO-8859-1", 3920, 3920, 1, 1 },
2463 // multi-byte encodings (variable width, and max_length > 1)
2464 { "ja_JP", "Shift_JIS" , "ja_JP.Shift_JIS", 25115, 13001, 0, 2 },
2465#if !defined _WIN32
2466 { "ja_JP", "EUC-JP" , "ja_JP.EUC-JP", 20801, 14299, 0, 3 },
2467 { "ja_JP", "UTF-8" , "ja_JP.UTF-8", 25056, 12000, 0, 6 },
2468#endif // !defined _WIN32
2469
2470 // terminate the array
2471 { 0, 0, 0, 0, 0, 0, 0 }
2472 };
2473
2474
2475 // Testing actual locale databases with input files
2476 rw_info (0, __FILE__, __LINE__,
2477 "Testing locale databases - file conversions.");
2478
2479 // index of the first successfully built locale database
2480 int first_good_locale = -1;
2481
2482 const char* const topdir = std::getenv ("TOPDIR");
2483 if (!topdir || !*topdir) {
2484 rw_assert (false, __FILE__, __LINE__,
2485 "environment variable TOPDIR not set or empty");
2486 }
2487
2488 for (std::size_t i = 0; locales [i].src_name; i++) {
2489
2490 // Testing actual locale databases with input files
2491
2492 // try to build a locale database and get its name
2493 const char* const locname =
2494 rw_localedef ("-w",
2495 locales [i].src_name,
2496 locales [i].charmap_name,
2497 locales [i].locale_name);
2498
2499 if (!locname)
2500 continue;
2501
2502 // find the native locale name correspomding to the canonical
2503 // locale name hardcoded in the table above
2504 const char* const native_locname =
2505 find_locale (locales [i].locale_name, locales [i].charmap_name);
2506
2507 if (native_locname)
2508 test_ascii (locales [i].locale_name, native_locname);
2509 else {
2510 std::fprintf (stderr, "*** failed to find a native locale to match"
2511 " locale(\"%s\"), skipping Extended ASCII conversion"
2512 " test\n", locales [i].locale_name);
2513 }
2514
2515#define TESTS_ETC_PATH "tests" SLASH "etc"
2516
2517 // determine the full pathname of test files in the source tree
2518 char pathname [PATH_MAX];
2519 std::strcpy (pathname, topdir);
2520 std::strcat (pathname, SLASH TESTS_ETC_PATH SLASH "codecvt.");
2521 std::strcat (pathname, locales [i].locale_name);
2522 std::strcat (pathname, ".in");
2523
2524 const char* const s = pathname;
2525
2526 // exercise the behavior of codecvt<char, char, mbstate_t>
2527 TEST_CONVERSION (Codecvt, locales [i].locale_name, true, s, true,
2528 std::codecvt_base::noconv, locales [i].nbytes,
2529 std::codecvt_base::noconv, locales [i].nbytes,
2530 std::codecvt_base::noconv, 1,
2531 true, locales [i].nbytes, 1);
2532
2533 // exercise the behavior of codecvt_byname<char, char, mbstate_t>
2534 TEST_CONVERSION (CodecvtBn, locales [i].locale_name, true, s, true,
2535 std::codecvt_base::noconv, locales [i].nbytes,
2536 std::codecvt_base::noconv, locales [i].nbytes,
2537 std::codecvt_base::noconv, 1,
2538 true, locales [i].nbytes, 1);
2539
2540#ifndef _RWSTD_NO_WCHAR_T
2541
2542 // exercise the behavior of codecvt<wchar_t, char, mbstate_t>
2543 TEST_CONVERSION (CodecvtW, locales [i].locale_name, true, s, true,
2544 std::codecvt_base::ok, locales [i].nbytes,
2545 std::codecvt_base::ok, locales [i].nbytes,
2546 std::codecvt_base::noconv, 1,
2547 false, locales [i].nbytes, 1);
2548
2549 // exercise the behavior of codecvt_byname<wchar_t, char, mbstate_t>
2550 TEST_CONVERSION (CodecvtBnW, locales [i].locale_name, true, s, false,
2551 std::codecvt_base::ok, locales [i].nchars,
2552 std::codecvt_base::ok, locales [i].nbytes,
2553 std::codecvt_base::noconv, locales [i].encoding,
2554 false, locales [i].nchars, locales [i].max_length);
2555
2556
2557
2558 // save the index of the first locale database successfully built
2559 if (-1 == first_good_locale)
2560 first_good_locale = _RWSTD_STATIC_CAST (int, i);
2561
2562 // FIXME: Until the LE (little endian) and BE (big endian) extra
2563 // modifiers are implemented, the test is skipped for Linux distros
2564 // such as Red Hat 6.2 that ship with glibc 2.1.1-6
2565
2566# if !defined __GLIBC__ \
2567 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 1 \
2568 || __GLIBC__ > 2
2569
2570 // exercise the behavior of codecvt_byname<wchar_t, char, mbstate_t>
2571 // in constructed with one of the additional @UCS name modifiers
2573 locales [i].locale_name, s, std::codecvt_base::ok,
2574 locales [i].nchars);
2575
2576 const InternalEncoding which_ucs =
2577 sizeof (wchar_t) == 4 ? use_UCS4 : use_UCS2;
2578
2580 use_UCS4 == which_ucs ? "UCS-4" : "UCS-2", which_ucs,
2581 locales [i].locale_name, s, std::codecvt_base::ok,
2582 locales [i].nchars);
2583
2584 TEST_UCS_MODIFIER (CodecvtBnW, "UCS", which_ucs,
2585 locales [i].locale_name, s, std::codecvt_base::ok,
2586 locales [i].nchars);
2587
2588# endif // GLIBC version > 2.1
2589#endif // _RWSTD_NO_WCHAR_T
2590
2591 }
2592
2593 // exercise the behavior of the facets when passed
2594 // an uninitialized or corrupt mbstate_t object
2595 test_invalid_args (-1 == first_good_locale ?
2596 (char*)0 : locales [first_good_locale].locale_name);
2597
2598 return 0;
2599}
2600
2601
2602/*extern*/ int
2603main (int argc, char* argv [])
2604{
2605 return rw_test (argc, argv, __FILE__,
2606 "[lib.locale.codecvt]",
2607 "", // no comment
2608 run_test, "", 0);
2609}
2610
2611
#define i
Definition 17.names.cpp:126
#define T
Definition 17.names.cpp:163
#define cmp
Definition 17.names.cpp:458
#define nchars
Definition 17.names.cpp:502
#define line
Definition 17.names.cpp:490
#define res
Definition 17.names.cpp:531
#define loc
Definition 17.names.cpp:492
#define which
Definition 17.names.cpp:575
#define pf
Definition 17.names.cpp:516
#define index
Definition 17.names.cpp:482
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define sz
Definition 17.names.cpp:550
#define charT
Definition 17.names.cpp:456
#define tmp
Definition 17.names.cpp:553
#define s
#define inx
Definition 17.names.cpp:484
#define old
Definition 17.names.cpp:509
int expect_abort
volatile int result
std::Nested::test_mbstate_t test_mbstate_t
@ do_always_noconv
@ do_encoding
@ do_max_length
#define CCVT_MB_CUR_MAX
const CodecvtBn & create_CodecvtBn(const std::locale &loc)
#define TEST_CONVERSION(T, L, C, f, s, i, is, o, os, ur, er, ar, lr, mr)
#define TEST(resultT, result, fname, args)
#define TEST_UCS_MODIFIER(T, mod, enc, locname, f, i, is)
_RWSTD_SPECIALIZED_FUNCTION std::size_t rwtest_mbstowcs< char >(std::mbstate_t &, char *, const char *, std::size_t)
#define TEST_IN(src, ext_len, ext_num, dst, int_len, int_num, res)
std::codecvt< char, char, std::mbstate_t > Codecvt
const Codecvt & create_Codecvt(const std::locale &)
std::jmp_buf jmp_env
std::size_t rwtest_wcstombs(std::mbstate_t &state, const charT *pi, char *pe, std::size_t srclen)
const char ext_ascii[]
_RWSTD_SPECIALIZED_FUNCTION std::size_t rwtest_wcstombs< char >(std::mbstate_t &, const char *, char *, std::size_t)
#define TESTS_ETC_PATH
std::codecvt_base::result CodecvtResult
const CodecvtW & create_CodecvtW(const std::locale &)
#define min(a, b)
void SIGABRT_handler(int)
std::codecvt_byname< char, char, std::mbstate_t > CodecvtBn
const char * locale_root
const CodecvtBnW & create_CodecvtBnW(const std::locale &loc)
#define TEST_IN_OUT(src, ext_len, ext_num, dst, int_len, int_num, res)
std::size_t rwtest_mbstowcs(std::mbstate_t &state, T *pi, const char *pe, std::size_t srclen)
std::codecvt_byname< wchar_t, char, std::mbstate_t > CodecvtBnW
#define PATH_MAX
std::codecvt< wchar_t, char, std::mbstate_t > CodecvtW
#define TEST_OUT(src, ext_len, ext_num, dst, int_len, int_num, res)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
const int out
const int in
#define main
#define _RWSTD_SPECIALIZED_CLASS
@ big_endian
Definition INFINITY.cpp:70
#define _THROWS()
int dtor
#define assert(expr)
Definition _cassert.h:40
#define LC_CTYPE
#define LC_ALL
unsigned short wchar_t
#define stderr
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _TRY
Definition _defs.h:850
#define _STD_USE_FACET(type, arg)
Definition _defs.h:920
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _CATCH(ex)
Definition _defs.h:851
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
#define _RWSTD_SPECIALIZED_FUNCTION
Definition _defs.h:556
const struct @19 locales[]
const char * name
Definition codecvt1.cpp:72
const char * str
Definition exec.cpp:170
#define UCHAR_MAX
Definition limits.h:60
@ error
throw a parse_error exception in case of a tag
Definition json.h:5363
_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
#define SLASH
Definition rw_file.h:55
_TEST_EXPORT void * rw_fread(const char *, _RWSTD_SIZE_T *=0, const char *="r")
#define LOCALE_ROOT_ENVAR
Definition rw_locale.h:57
_TEST_EXPORT const char * rw_set_locale_root()
Definition locale.cpp:324
_TEST_EXPORT const char * rw_localedef(const char *, const char *, const char *, const char *)
Definition locale.cpp:154
_TEST_EXPORT char * rw_locale_query(int=_UNUSED_CAT, const char *=0, _RWSTD_SIZE_T=0)
unsigned char UChar
Definition collate.cpp:122
result do_out(stype &, const itype *, const itype *, const itype *&, etype *, etype *, etype *&) const
result do_unshift(stype &, etype *, etype *, etype *&) const
int do_encoding() const _THROWS(())
std::codecvt_base::result result
result do_in(stype &, const etype *, const etype *, const etype *&, itype *, itype *, itype *&) const
base_type::state_type stype
base_type::extern_type etype
base_type::intern_type itype
std::codecvt< charT, char, std::mbstate_t > Codecvt
int do_max_length() const _THROWS(())
CodecvtDerived(const char *)
bool do_always_noconv() const _THROWS(())
int do_length(stype &, const etype *, const etype *, std::size_t) const
static const char * name