Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
22.locale.ctype.cpp
Go to the documentation of this file.
1
29// DESCRIPTION: test iterates over the locales installed on a machine,
30// calling the C character classification functions and
31// their C++ counterpart(s), comparing the results of
32// the calls against one another.
33
34
35#include <rw/_defs.h>
36
37#if defined __linux__
38 // on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
39# define _XOPEN_SOURCE 500 /* Single Unix conformance */
40 // bring __int32_t into scope (otherwise <wctype.h> fails to compile)
41# include <sys/types.h>
42#endif // __linux__
43
44// see Onyx PR #28150
45#if defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
46# include <wchar.h>
47#endif // defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540
48
49#include <locale>
50
51#include <climits>
52#include <clocale>
53#include <cstring>
54#include <cctype>
55#include <cstdio>
56#include <cstdlib>
57#include <cwchar> // for WEOF, btowc(), wctob()
58#include <cwctype> // for iswxxx()
59
60
61#if !defined (_WIN32)
62# if !defined (LC_MESSAGES)
63# define LC_MESSAGES _RWSTD_LC_MESSAGES
64# endif // LC_MESSAGES
65# include <langinfo.h>
66#endif // _WIN32
67
68#include <rw_driver.h>
69#include <rw_file.h> // for SLASH
70#include <rw_locale.h> // for rw_locale_query()
71
72
74// the root of the locale directory (RWSTD_LOCALE_ROOT)
75// not set here to avoid Solaris 7 putenv() bug (PR #30017)
76const char* locale_root;
77
78#define NLOOPS 25
79#define MAX_STR_SIZE 16
80
81#define LOCALES "{{en-US,de-DE,fr-FR,es-ES}-*-{ISO-8859-*,UTF-8,CP125?}," \
82 "{ja-JP-*-{EUC-JP,SHIFT_JIS,UTF-8,CP125?}}," \
83 "{zh-CN-*-{GB*,UTF-8,CP125?}}," \
84 "{ru-RU-*-{KOI*,UTF-8,CP125?}}}"
85
86const char* locale_list = 0;
87
88#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl) \
89 if (!locale_list) locale_list = rw_locale_query (LC_CTYPE, LOCALES); \
90 for (const char* locname = locale_list; \
91 locname && *locname; locname += std::strlen (locname) + 1) { \
92 _TRY { \
93 const std::locale loc (locname); \
94 const std::ctype<char> &ctc = \
95 _STD_USE_FACET (std::ctype<char>, loc); \
96 _RWSTD_UNUSED (ctc); \
97 const std::ctype<charT> &ctp = \
98 _STD_USE_FACET (std::ctype<charT>, loc); \
99 for (int loop_cntrl = 0; loop_cntrl < int (num); loop_cntrl++)
100
101#define END_LOCALE_LOOP(locname) \
102 } \
103 _CATCH (...) { \
104 rw_assert (0, 0, __LINE__, \
105 "locale (\"%s\") threw an exception", locname); \
106 } \
107 }
108
109
110// for notational convenience
111typedef unsigned char UChar;
112
113#define ALPHA std::ctype_base::alpha
114#define UPPER std::ctype_base::upper
115#define LOWER std::ctype_base::lower
116#define DIGIT std::ctype_base::digit
117#define SPACE std::ctype_base::space
118#define CNTRL std::ctype_base::cntrl
119#define PUNCT std::ctype_base::punct
120#define XDIGIT std::ctype_base::xdigit
121#define GRAPH std::ctype_base::graph
122#define PRINT std::ctype_base::print
123
124
125// wrapper functions for the c library char and wchar_t functions
126int libc_isalpha (char ch)
127{
128 return (std::isalpha)(UChar (ch));
129}
130
131int libc_isspace (char ch)
132{
133 return (std::isspace)(UChar (ch));
134}
135
136int libc_isprint (char ch)
137{
138 return (std::isprint)(UChar (ch));
139}
140
141int libc_iscntrl (char ch)
142{
143 return (std::iscntrl)(UChar (ch));
144}
145
146int libc_isupper (char ch)
147{
148 return (std::isupper)(UChar (ch));
149}
150
151int libc_islower (char ch)
152{
153 return (std::islower)(UChar (ch));
154}
155
156int libc_isdigit (char ch)
157{
158 return (std::isdigit)(UChar (ch));
159}
160
161int libc_ispunct (char ch)
162{
163 return (std::ispunct)(UChar (ch));
164}
165
166int libc_isxdigit (char ch)
167{
168 return (std::isxdigit)(UChar (ch));
169}
170
171int libc_isalnum (char ch)
172{
173 return (std::isalnum)(UChar (ch));
174}
175
176int libc_isgraph (char ch)
177{
178 return (std::isgraph)(UChar (ch));
179}
180
181char libc_tolower (char ch)
182{
183 return std::tolower (UChar (ch));
184}
185
186char libc_toupper (char ch)
187{
188 return (std::toupper)(UChar (ch));
189}
190
191std::ctype_base::mask libc_mask (int mask, char ch, const char *locname)
192{
193 char curlocname [256];
194
195 if (locname) {
196 std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
197
198 if (0 == std::setlocale (LC_CTYPE, locname))
199 return std::ctype_base::mask ();
200 }
201
202 const int c = UChar (ch);
203
204 int result = 0;
205
206 if (mask & ALPHA && (std::isalpha)(c))
207 result |= ALPHA;
208 if (mask & CNTRL && (std::iscntrl)(c))
209 result |= CNTRL;
210 if (mask & DIGIT && (std::isdigit)(c))
211 result |= DIGIT;
212 if (mask & GRAPH && (std::isgraph)(c))
213 result |= GRAPH;
214 if (mask & LOWER && (std::islower)(c))
215 result |= LOWER;
216 if (mask & PRINT && (std::isprint)(c))
217 result |= PRINT;
218 if (mask & PUNCT && (std::ispunct)(c))
219 result |= PUNCT;
220 if (mask & SPACE && (std::isspace)(c))
221 result |= SPACE;
222 if (mask & UPPER && (std::isupper)(c))
223 result |= UPPER;
224 if (mask & XDIGIT && (std::isxdigit)(c))
225 result |= XDIGIT;
226
227 if (locname)
228 std::setlocale (LC_CTYPE, curlocname);
229
230 return std::ctype_base::mask (result);
231}
232
233inline bool libc_is (std::ctype_base::mask mask, char ch, const char *locname)
234{
235 const std::ctype_base::mask m = libc_mask (mask, ch, locname);
236
237 return 0 != (m & mask);
238}
239
240std::size_t c_strlen (const char *s1)
241{
242 return std::strlen (s1);
243}
244
245int c_strcmp (const char *s1, const char *s2)
246{
247 int ret = std::strcoll (s1, s2);
248 return ret ? ret > 0 ? 1 : -1 : 0;
249}
250
251const char* narrow (char *dst, const char *src)
252{
253 if (src == dst || !src || !dst)
254 return src;
255
256 std::memcpy (dst, src, std::strlen (src) + 1);
257 return dst;
258}
259
260
261const char* widen (char *dst, const char *src)
262{
263 if (src == dst || !src || !dst)
264 return src;
265
266 std::memcpy (dst, src, std::strlen (src) + 1);
267 return dst;
268}
269
270
271char widen (char, char ch, const char*)
272{
273 return ch;
274}
275
276char narrow (char ch, const char*)
277{
278 return ch;
279}
280
281// cond1() verifies condition [1] in Test::test_narrow_widen()
282// below using libc functions
283bool cond1 (std::ctype_base::mask mask, char ch, const char *locname)
284{
285 char curlocname [256];
286 std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
287
288 if (0 == std::setlocale (LC_CTYPE, locname))
289 return false;
290
291#ifdef __SUNPRO_CC
292
293 // working around a SunPro bug (PR #28150)
294 using std::wint_t;
295
296#endif // __SUNPRO_CC
297
298#ifndef _RWSTD_NO_BTOWC
299
300 const std::wint_t wc = std::btowc (UChar (ch));
301
302#elif !defined (_RWSTD_NO_MBSTOWCS)
303
304 wchar_t tmp;
305 const std::wint_t wc = 1 == std::mbstowcs (&tmp, &ch, 1) ? tmp : WEOF;
306
307#else
308
309 const std::wint_t wc = WEOF;
310
311#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBSTOWCS
312
313 const bool result =
314 WEOF == wc || libc_is (mask, ch, 0) || !libc_is (mask, wchar_t (wc), 0);
315
316 std::setlocale (LC_CTYPE, curlocname);
317
318 return result;
319}
320
321
322// cond3() overloads verify condition [3] in Test::test_narrow_widen()
323// below using libc functions
324bool cond3 (std::ctype_base::mask, char, const char*)
325{
326 return true;
327}
328
329
330#ifndef _RWSTD_NO_WCHAR_T
331
332int libc_isalpha (wchar_t ch)
333{
334 return (std::iswalpha)(ch);
335}
336
337int libc_isspace (wchar_t ch)
338{
339 return (std::iswspace)(ch);
340}
341
342int libc_isprint (wchar_t ch)
343{
344 return (std::iswprint)(ch);
345}
346
347int libc_iscntrl (wchar_t ch)
348{
349 return (std::iswcntrl)(ch);
350}
351
352int libc_isupper (wchar_t ch)
353{
354 return (std::iswupper)(ch);
355}
356
357int libc_islower (wchar_t ch)
358{
359 return (std::iswlower)(ch);
360}
361
362int libc_isdigit (wchar_t ch)
363{
364 return (std::iswdigit)(ch);
365}
366
367int libc_ispunct (wchar_t ch)
368{
369 return (std::iswpunct)(ch);
370}
371
372int libc_isxdigit (wchar_t ch)
373{
374 return (std::iswxdigit)(ch);
375}
376
377int libc_isalnum (wchar_t ch)
378{
379 return (std::iswalnum)(ch);
380}
381
382int libc_isgraph (wchar_t ch)
383{
384 return (std::iswgraph)(ch);
385}
386
387wchar_t libc_tolower (wchar_t ch)
388{
389 return (std::towlower)(ch);
390}
391
392wchar_t libc_toupper (wchar_t ch)
393{
394 return (std::towupper)(ch);
395}
396
397std::size_t c_strlen (const wchar_t *s1)
398{
399 return std::wcslen (s1);
400}
401
402int c_strcmp (const wchar_t *s1, const wchar_t *s2)
403{
404 int ret = std::wcscmp (s1, s2);
405 return ret ? ret > 0 ? 1 : -1 : 0;
406}
407
408
409const char* narrow (char *dst, const wchar_t *src)
410{
411 static char buf [4096];
412
413 if (!src)
414 return 0;
415
416 if (!dst)
417 dst = buf;
418
419 std::size_t len = std::wcslen (src);
420
421 _RWSTD_ASSERT (len < sizeof buf);
422
423 len = std::wcstombs (dst, src, sizeof buf / sizeof *buf);
424
425 if (std::size_t (-1) == len)
426 *dst = 0;
427
428 return dst;
429}
430
431
432const wchar_t* widen (wchar_t *dst, const char *src)
433{
434 static wchar_t buf [4096];
435
436 if (!src)
437 return 0;
438
439 if (!dst)
440 dst = buf;
441
442 std::size_t len = std::strlen (src);
443
444 _RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
445
446 len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
447
448 if (std::size_t (-1) == len)
449 *dst = 0;
450
451 return dst;
452}
453
454std::ctype_base::mask libc_mask (int mask, wchar_t ch, const char *locname)
455{
456 char curlocname [256];
457
458 if (locname) {
459 std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
460
461 if (0 == std::setlocale (LC_CTYPE, locname))
462 return std::ctype_base::mask ();
463 }
464
465 int result = 0;
466
467 if (mask & ALPHA && (std::iswalpha)(ch))
468 result |= ALPHA;
469 if (mask & CNTRL && (std::iswcntrl)(ch))
470 result |= CNTRL;
471 if (mask & DIGIT && (std::iswdigit)(ch))
472 result |= DIGIT;
473 if (mask & GRAPH && (std::iswgraph)(ch))
474 result |= GRAPH;
475 if (mask & LOWER && (std::iswlower)(ch))
476 result |= LOWER;
477 if (mask & PRINT && (std::iswprint)(ch))
478 result |= PRINT;
479 if (mask & PUNCT && (std::iswpunct)(ch))
480 result |= PUNCT;
481 if (mask & SPACE && (std::iswspace)(ch))
482 result |= SPACE;
483 if (mask & UPPER && (std::iswupper)(ch))
484 result |= UPPER;
485 if (mask & XDIGIT && (std::iswxdigit)(ch))
486 result |= XDIGIT;
487
488 if (locname)
489 std::setlocale (LC_CTYPE, curlocname);
490
491 return std::ctype_base::mask (result);
492}
493
494bool libc_is (std::ctype_base::mask mask, wchar_t ch, const char *locname)
495{
496 const std::ctype_base::mask m = libc_mask (mask, ch, locname);
497
498 return 0 != (m & mask);
499}
500
501wchar_t widen (wchar_t, char ch, const char *locname)
502{
503 char curlocname [256];
504 std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
505
506 if (0 == std::setlocale (LC_CTYPE, locname))
507 return UChar (ch);
508
509 wchar_t result;
510
511#ifndef _RWSTD_NO_BTOWC
512
513 result = std::btowc (UChar (ch));
514
515#elif !defined (_RWSTD_NO_MBTOWC)
516
517 if (1 != std::mbtowc (&result, &ch, 1))
518 result = wchar_t (WEOF);
519
520#else
521
522 result = UChar (ch);
523
524#endif // _RWSTD_NO_BTOWC, _RWSTD_NO_MBTOWC
525
526 if (locname)
527 std::setlocale (LC_CTYPE, curlocname);
528
529 return result;
530}
531
532char narrow (wchar_t ch, const char *locname)
533{
534 char curlocname [256];
535 std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
536
537 if (0 == std::setlocale (LC_CTYPE, locname))
538 return UChar (ch);
539
540 char result [MB_LEN_MAX];
541
542#ifndef _RWSTD_NO_WCTOB
543
544 result [0] = std::wctob (ch);
545
546#elif !defined (_RWSTD_NO_WCTOMB)
547
548 if (1 != std::wctomb (result, ch))
549 result [0] = '\377';
550
551#else
552
553 result [0] = char (ch);
554
555#endif // _RWSTD_NO_WCTOB, _RWSTD_NO_WCTOMB
556
557 if (locname)
558 std::setlocale (LC_CTYPE, curlocname);
559
560 return result [0];
561}
562
563bool cond3 (std::ctype_base::mask mask, wchar_t ch, const char *locname)
564{
565 char curlocname [256];
566 std::strcpy (curlocname, std::setlocale (LC_CTYPE, 0));
567
568 if (0 == std::setlocale (LC_CTYPE, locname))
569 return false;
570
571#ifndef _RWSTD_NO_WCTOB
572
573 const int byte = std::wctob (ch);
574
575#elif !defined (_RWSTD_NO_WCTOMB)
576
577 char buf [MB_LEN_MAX];
578 const int byte = 1 == std::wctomb (buf, ch) ? buf [0] : EOF;
579
580#else
581
582 const int byte = EOF;
583
584#endif // _RWSTD_NO_WCTOB, _RWSTD_NO_WCTOMB
585
586 const bool result =
587 EOF == byte || !libc_is (mask, char (byte), 0) || libc_is (mask, ch, 0);
588
589 std::setlocale (LC_CTYPE, curlocname);
590
591 return result;
592}
593
594#endif // _RWSTD_NO_WCHAR_T
595
596
597template <class charT>
598void gen_str (charT *str, std::size_t size)
599{
600 // generate a random string with the given size
601 // we do not attempt to check that the size is within the
602 // valid range for the string.
603
604 for (std::size_t i = 0; i < size; i++){
605 str [i] = UChar (std::rand () % UCHAR_MAX);
606 // only increment if we are not going to roll over
607 if (str [i] != charT (UCHAR_MAX - 1U))
608 ++str [i];
609 }
610
611 str [size] = charT ();
612
614}
615
616
618template <class charT>
619void test_is (charT, const char *cname)
620{
621 charT str [MAX_STR_SIZE + 1];
622
623 BEGIN_LOCALE_LOOP (NLOOPS, locname, j) {
624
625 std::size_t size = std::size_t (j % MAX_STR_SIZE);
626
627 gen_str (str, size);
628
629 // create a mask for each character in the string using the c library
630 // to make sure that it is the same as the mask returned by is
631 std::ctype_base::mask vec [MAX_STR_SIZE + 1];
632
633 // set the global C locale to default to make sure
634 // the C++ library does not asume a set value
635 std::setlocale (LC_CTYPE, "");
636
637 ctp.is (str, str + size, vec);
638
639 // set the global C locale to the current locale for calls to the
640 // C library
641 std::setlocale (LC_CTYPE, locname);
642
643 for (std::size_t i = 0; i < size ; i++) {
644
645 int libc_result = 0;
646
647 if (libc_isalpha (str [i]))
648 libc_result |= ALPHA;
649 if (libc_isprint (str [i]))
650 libc_result |= PRINT;
651 if (libc_isspace (str [i]))
652 libc_result |= SPACE;
653 if (libc_iscntrl (str [i]))
654 libc_result |= CNTRL;
655 if (libc_isupper (str [i]))
656 libc_result |= UPPER;
657 if (libc_islower (str [i]))
658 libc_result |= LOWER;
659 if (libc_isdigit (str [i]))
660 libc_result |= DIGIT;
661 if (libc_ispunct (str [i]))
662 libc_result |= PUNCT;
663 if (libc_isxdigit (str [i]))
664 libc_result |= XDIGIT;
665 if (libc_isgraph (str [i]))
666 libc_result |= GRAPH;
667
668 rw_assert (vec [i] == libc_result, 0, __LINE__,
669 "ctype<%s>::is(%{*Ac}, ..., v) in locale(%#s) "
670 "at offset %zu; got %{LC} expected %{LC}\n",
671 cname, int (sizeof *str), str,
672 locname, i, vec [i], libc_result);
673 }
674 } END_LOCALE_LOOP (locname);
675}
676
677
679template <class charT>
680void test_toupper_tolower (charT, const char *cname)
681{
682 rw_info (0, 0, __LINE__, "std::ctype<%s>::tolower(%1$s)", cname);
683
684 BEGIN_LOCALE_LOOP (UCHAR_MAX, locname, i) {
685
686 const charT ch = charT (i);
687
688 // set the global C locale to locname for the C library call
689 std::setlocale (LC_CTYPE, locname);
690
691 const charT lch = libc_tolower (ch);
692
693 // set the global C locale to default to make sure
694 // the C++ library does not asume a set value
695 std::setlocale (LC_CTYPE, "");
696
697 // exercise tolower using ctype<>::tolower ()
698 rw_assert (lch == (ctp.tolower)(ch), 0, __LINE__,
699 "ctype<%s>::tolower(%{#lc}) == %{#lc}, got %{#lc} "
700 "in locale(%#s)",
701 cname, ch, lch, (ctp.tolower)(ch), locname);
702
703 // exercise tolower using tolower (char, locale)
704 rw_assert (lch == (charT)(std::tolower)(ch, loc), 0, __LINE__,
705 "tolower<%s>(%{#lc}, locale(%#s)) == %{#lc}, got %{#lc}",
706 cname, ch, locname, lch, (std::tolower)(ch, loc));
707 } END_LOCALE_LOOP (locname);
708
709 rw_info (0, 0, __LINE__, "std::ctype<%s>::toupper(%1$s)", cname);
710
711 BEGIN_LOCALE_LOOP (UCHAR_MAX, locname2, i) {
712
713 const charT ch = charT (i);
714
715 // set the global C locale to the locale name for the C library call
716 std::setlocale (LC_CTYPE, locname2);
717
718 const charT uch = libc_toupper (ch);
719
720 // set the global C locale to default to make sure
721 // the C++ library does not asume a set value
722 std::setlocale (LC_CTYPE, "");
723
724 // exercise toupper using ctype<>::toupper ()
725 rw_assert (uch == (ctp.toupper)(ch), 0, __LINE__,
726 "ctype<%s>::toupper(%{#lc}) == %{#lc}, got %{#lc} "
727 "in locale(%#s)",
728 cname, ch, uch, (ctp.toupper)(ch), locname2);
729
730 // exercise toupper using toupper (char, locale)
731 rw_assert (uch == (charT)(std::toupper)(ch, loc), 0, __LINE__,
732 "toupper<%s>(%{#lc}, locale(%#s)) == %{#lc}, got %{#lc}",
733 cname, ch, locname2, uch, (std::toupper)(ch, loc));
734 } END_LOCALE_LOOP (locname2);
735}
736
737
739template <class charT>
740void test_scan (charT, const char *cname)
741{
742 rw_info (0, 0, __LINE__, "std::ctype<%s>::scan_is(), scan_not()", cname);
743
744 charT str [MAX_STR_SIZE + 1];
745
746 BEGIN_LOCALE_LOOP (NLOOPS, locname, j) {
747
748 const std::size_t size = std::size_t (j % MAX_STR_SIZE);
749
750 // generate a random string
751 gen_str (str, size);
752
753 // set the global C locale to default to make sure
754 // the C++ library does not asume a set value
755 std::setlocale (LC_CTYPE, "");
756
757 // call scan_is and scan_not using each mask and compare it to
758 // the results found when using the c library
759
760 const charT* alpha_is = ctp.scan_is (ALPHA, str, str + size);
761 const charT* alpha_not = ctp.scan_not (ALPHA, str, str + size);
762 const charT* space_is = ctp.scan_is (SPACE, str, str + size);
763 const charT* space_not = ctp.scan_not (SPACE, str, str + size);
764 const charT* print_is = ctp.scan_is (PRINT, str, str + size);
765 const charT* print_not = ctp.scan_not (PRINT, str, str + size);
766 const charT* cntrl_is = ctp.scan_is (CNTRL, str, str + size);
767 const charT* cntrl_not = ctp.scan_not (CNTRL, str, str + size);
768 const charT* upper_is = ctp.scan_is (UPPER, str, str + size);
769 const charT* upper_not = ctp.scan_not (UPPER, str, str + size);
770 const charT* lower_is = ctp.scan_is (LOWER, str, str + size);
771 const charT* lower_not = ctp.scan_not (LOWER, str, str + size);
772 const charT* digit_is = ctp.scan_is (DIGIT, str, str + size);
773 const charT* digit_not = ctp.scan_not (DIGIT, str, str + size);
774 const charT* punct_is = ctp.scan_is (PUNCT, str, str + size);
775 const charT* punct_not = ctp.scan_not (PUNCT, str, str + size);
776 const charT* xdigit_is = ctp.scan_is (XDIGIT, str, str + size);
777 const charT* xdigit_not = ctp.scan_not (XDIGIT, str, str + size);
778
779 // set the global C locale to locname for the C library call
780 std::setlocale (LC_CTYPE, locname);
781
782 // find the first character in the string that is of the specified
783 // type
784 charT first = 0;
785 charT first_not = 0;
786 _RWSTD_SIZE_T i;
787 int success;
788
789#define SCAN(what) \
790 for (i = 0; i < size; i++) { \
791 if (libc_is##what (str [i])) { \
792 first = (str [i]); \
793 break; \
794 } \
795 } \
796 success = what##_is != (str + size) || 0 == first \
797 || *what##_is != first; \
798 rw_assert (success, 0, __LINE__, \
799 "ctype<%s>::scan_is(" #what ", %{#lc}) " \
800 "== %{*Ac}, got %{*Ac} in locale (%#s)", \
801 cname, int (sizeof *str), first, \
802 int (sizeof *what##_is), what##_is, \
803 locname); \
804 \
805 first = 0; \
806 for (i = 0; i < size; i++) { \
807 if (!libc_is##what (str[i])) { \
808 first_not = (str[i]); \
809 break; \
810 } \
811 } \
812 success = what##_not != (str + size) || 0 == first_not \
813 || *what##_not == first_not; \
814 rw_assert (success, 0, __LINE__, \
815 "ctype<%s>::scan_not(" #what ", %{#lc}) " \
816 "== %{*Ac}, got %{*Ac} in locale (%#s)", \
817 cname, int (sizeof *str), first, \
818 int (sizeof *what##_not), what##_not, \
819 locname); \
820 \
821 first_not = 0
822
823 // test all classes of characters
824 SCAN (alpha);
825 SCAN (space);
826 SCAN (print);
827 SCAN (cntrl);
828 SCAN (upper);
829 SCAN (lower);
830 SCAN (digit);
831 SCAN (punct);
832 SCAN (xdigit);
833
834 } END_LOCALE_LOOP (locname);
835}
836
837
839template <class charT>
840void test_narrow_widen (charT, const char *cname)
841{
842 // 22.2.1.1.2, p11 requires that the conditions below hold for all
843 // facets ctc and ct whose types are ctype<char> and ctype<charT>,
844 // respectively:
845
846 // [1] (ctc.is (M, c) || !ct.is (M, ctc.do_widen (c))) holds for
847 // all narrow characters c
848 // i.e., narrow characters that are NOT members of a certain
849 // category may not belong to the same category when widened
850 // Note: this implies that some sort of code conversion may
851 // be necessary in order to implement a conforming do_widen()
852
853 // 22.2.1.1.2, p13 requires that:
854 // [2] (ct.do_widen (ct.do_narrow (c, dfault)) == c) holds unless
855 // (ct.do_narrow (c, dfault) == dfault) holds
856 // [3] (ct.is (M, c) || !ctc.is (M, ct.do_narrow (c, dfault))) holds
857 // unless (ct.do_narrow(c, dfault) == dfault) holds
858 //
859 // C99: each of the iswxxx() functions returns true for each
860 // wide character that corresponds (as if by a call to the
861 // wctob() function) to a single-byte character for which the
862 // corresponding character classification function from 7.4.1
863 // returns true, except that the iswgraph() and iswpunct()
864 // functions may differ with respect to wide characters other
865 // than L' ' that are both printing and white-space wide
866 // characters.
867 //
868 // [4] (ct.do_narrow (c, default) - '0') evaluates to the digit
869 // value of the character for all c for which ct.is(digit, c)
870 // returns true
871
872 rw_info (0, 0, __LINE__,
873 "std::ctype<%s>::narrow(%1$s), widen(char)",
874 cname);
875
876 rw_info (0, 0, __LINE__,
877 "std::ctype<%s>::narrow(const %1$s*, const %1$s*, char*), "
878 "widen(const char*, const char*, %1$s*)", cname);
879
880#define STR(x) #x
881
882 // verify condition [1] above; if it fails, verify that
883 // the same condition also fails to hold when using the
884 // corresponding libc functions
885#define COND1(what) \
886 if (!(ctc.is (what, c) || !ctp.is (what, ctp.widen (c)))) { \
887 rw_assert (!cond1 (what, c, locname), 0, __LINE__, \
888 "ctype<char>::is (" STR (what) ", %{#lc})" \
889 " || !ctype<%1$s>::is (" STR (what) ", " \
890 "ctype<%s>::widen (%{#lc}) = %{#lc})" \
891 " returned false in locale(%#s)", \
892 c, cname, c, ctp.widen (c), locname); \
893 } else (void)0
894
895 // verify condition [3] above; if it fails, verify that
896 // the same condition also fails to hold when using the
897 // corresponding libc functions
898#define COND3(what) \
899 if ( ctp.narrow (ch, dfault) != dfault \
900 && !(ctp.is (what, ch) || !ctc.is (what, ctp.narrow (ch, dfault)))) { \
901 rw_assert (!cond3 (what, ch, locname), 0, __LINE__, \
902 "ctype<%s>::is (" STR (what) ", %{#lc})" \
903 " || !ctype<char>::is (" STR (what) ", " \
904 "ctype<%1$s>::narrow (%{#lc}, %{#c}) = %{#lc})" \
905 " returned false in locale(%#s)", cname, \
906 ch, cname, ch, dfault, ctp.narrow (ch, '\0'), \
907 locname); \
908 } else (void)0
909
910
911 char c_locname [256];
912 std::strcpy (c_locname, std::setlocale (LC_ALL, 0));
913
914 BEGIN_LOCALE_LOOP (UCHAR_MAX, locname, i) {
915
916#if defined (_RWSTD_OS_SUNOS) && _RWSTD_OS_MAJOR == 5 && _RWSTD_OS_MINOR <= 10
917
918 // avoid a libc SIGSEGV in mbtowc() in zh_HK and zh_TW
919 // locales encoded using the BIG5 codeset (see bug #603)
920 if ( 0 == std::strncmp ("zh_HK.BIG5", locname, 10)
921 || 0 == std::strncmp ("zh_TW.BIG5", locname, 10))
922 continue;
923
924#endif // SunOS < 5.10
925
926 {
927 // verify that the global C locale stays unchanged
928 const char* const curlocname = std::setlocale (LC_ALL, 0);
929
930 rw_assert (!std::strcmp (c_locname, curlocname), 0, __LINE__,
931 "setlocale(LC_ALL, 0) == \"%s\", got \"%s\"",
932 c_locname, curlocname);
933 }
934
935 const char c = char (i);
936 const charT ch = charT (i);
937
938 // verify that condition [1] holds
939 COND1 (ALPHA);
940 COND1 (CNTRL);
941 COND1 (DIGIT);
942 COND1 (GRAPH);
943 COND1 (LOWER);
944 COND1 (PRINT);
945 COND1 (PUNCT);
946 COND1 (SPACE);
947 COND1 (UPPER);
948 COND1 (XDIGIT);
949
950 // verify that condition [2] holds
951 char dfault = c ? '\0' : '\1';
952 const charT ret = ctp.widen (ctp.narrow (ch, dfault));
953
954 if (ret != charT (dfault) && ret != ch) {
955 rw_assert (ch != widen (ch, narrow (ch, locname), locname),
956 0, __LINE__,
957 "ctype<%s>::widen (ctype<%1$s>::narrow "
958 "(%{#lc}, %{#c})) == %{#c}; got %{#c} "
959 "in locale (%#s)",
960 cname, ch, dfault, ch, ret, locname);
961 }
962
963 // finally verify that condition [3] holds
964 COND3 (ALPHA);
965 COND3 (CNTRL);
966 COND3 (DIGIT);
967 COND3 (GRAPH);
968 COND3 (LOWER);
969 COND3 (PRINT);
970 COND3 (PUNCT);
971 COND3 (SPACE);
972 COND3 (UPPER);
973 COND3 (XDIGIT);
974
975 // now perform a relitively simple sanity check on the 3-argument
976 // overloads of narrow() and widen(). Make sure that the 3-argument
977 // overloads return the same value that the other overload produces
978 // Only do this the first time through the locale list.
979
980 if (i == 0) {
981 // arrays of all tested narrow and wide characters
982 charT wide_chars [UCHAR_MAX + 1];
983 char narrow_chars [UCHAR_MAX + 1];
984 charT narrow_in [UCHAR_MAX + 1];
985 char widen_in [UCHAR_MAX + 1];
986
987 // zero out the last element to allow printing
988 wide_chars [UCHAR_MAX] = charT ();
989 narrow_chars [UCHAR_MAX] = char ();
990 narrow_in [UCHAR_MAX] = charT ();
991 widen_in [UCHAR_MAX] = char ();
992
993 // set the `dfault' character to something unlikely
994 // but other than '\0'
995 dfault = '\377';
996
997 for (unsigned j = 0; j <= UCHAR_MAX; j++) {
998 wide_chars [j] = ctp.widen (char (j));
999 narrow_chars [j] = ctp.narrow (wide_chars [j], dfault);
1000 narrow_in [j] = ctp.widen (char (j));
1001 widen_in [j] = char (j);
1002 }
1003
1004 charT widen_out [UCHAR_MAX + 1];
1005 char narrow_out [UCHAR_MAX + 1];
1006
1007 widen_out [UCHAR_MAX] = charT ();
1008 narrow_out [UCHAR_MAX] = char ();
1009
1010 // narrow source buffer into the destination
1011 // and compare with expected values
1012 ctp.narrow (narrow_in,
1013 narrow_in + UCHAR_MAX + 1,
1014 dfault,
1015 narrow_out);
1016
1017 bool success =
1018 !std::memcmp (narrow_chars, narrow_out, sizeof narrow_chars);
1019
1020 rw_assert (success, 0, __LINE__,
1021 "ctype<%s>::narrow (%{*.*Ac}\", ... , %#c) "
1022 "== %{.*Ac}, got %{.Ac} in locale (%#s)", cname,
1023 int (sizeof *narrow_in), UCHAR_MAX, narrow_in, dfault,
1024 UCHAR_MAX, narrow_chars, UCHAR_MAX, narrow_out,
1025 locname);
1026
1027 // widen source buffer into the destination
1028 // and compare with expected values
1029 ctp.widen (widen_in,
1030 widen_in + UCHAR_MAX + 1,
1031 widen_out);
1032
1033 success = !std::memcmp (wide_chars, widen_out, sizeof wide_chars);
1034
1035 rw_assert (success, 0, __LINE__,
1036 "ctype<%s>::widen (%{.*Ac}, ...) == "
1037 "%{*.*Ac}, got %{*.*Ac} in locale (%#s)",
1038 cname, UCHAR_MAX, widen_in,
1039 int (sizeof *wide_chars), UCHAR_MAX, wide_chars,
1040 int (sizeof *wide_chars), UCHAR_MAX, widen_out,
1041 locname);
1042 }
1043
1044 } END_LOCALE_LOOP (locname);
1045}
1046
1047
1049template <class charT>
1050void test_is_ch (charT, const char *cname)
1051{
1052 // buffers to hold the character classification
1053 // e.g., for `a' in the "C" locale the string will be
1054 // "print lower alpha xdigit alnum graph "
1055
1056 static char is_C [80]; // C character classification
1057 static char is_CXX [80]; // C++ classification using ctype<char> facet
1058 static char is_CXX2 [80]; // C++ classification using convenience funcs
1059
1060 rw_info (0, 0, __LINE__, "std::ctype<%s>::is(mask, %1$s)", cname);
1061
1062 BEGIN_LOCALE_LOOP (UCHAR_MAX, locname, i) {
1063
1064 const charT ch = charT (i);
1065 const UChar uch = ch;
1066
1067 *is_C =
1068 *is_CXX =
1069 *is_CXX2 = '\0';
1070
1071 // set the global C locale to locname for the C library calls
1072 std::setlocale (LC_CTYPE, locname);
1073
1074#define IS(what) \
1075 libc_is##what (ch) \
1076 ? (void)std::strcat (is_C, #what" ") : (void)0;
1077
1078 // test all classes of characters
1079 IS (space); IS (print); IS (cntrl); IS (upper); IS (lower);
1080 IS (alpha); IS (digit); IS (punct); IS (xdigit); IS (alnum);
1081 IS (graph);
1082
1083 // set the global C locale to default to make sure
1084 // the C++ library does not asume a set value
1085 std::setlocale (LC_CTYPE, "");
1086
1087#undef IS
1088// convenience macro
1089#define IS(what) \
1090 ctp.is (std::ctype_base::what, ch) \
1091 ? (void)std::strcat (is_CXX, #what" ") : (void)0; \
1092 (std::is##what)(ch, loc) \
1093 ? (void)std::strcat (is_CXX2, #what" ") : (void)0;
1094
1095 // test all classes of characters
1096 // (must be in the same order as the IS() calls above)
1097 IS (space); IS (print); IS (cntrl); IS (upper); IS (lower);
1098 IS (alpha); IS (digit); IS (punct); IS (xdigit); IS (alnum);
1099 IS (graph);
1100
1101 // compare the two strings (should match)
1102
1103 rw_assert (0 == std::strcmp (is_C, is_CXX), 0, __LINE__,
1104 "ctype<%s>::is(..., %{#lc}) in locale(%#s) "
1105 "expected to hold for { %s}, got { %s}",
1106 cname, uch, locname, is_C, is_CXX);
1107
1108 // convenience functions must produce the same results
1109 rw_assert (0 == std::strcmp (is_C, is_CXX2), 0, __LINE__,
1110 "is* (%{#lc}, locale (%#s)) expected to hold for "
1111 "{ %s}, got { %s}",
1112 uch, locname, is_C, is_CXX2);
1113
1114#ifndef _WIN32
1115
1116 // exercise POSIX requirements only on POSIX platforms
1117
1118 static const std::ctype_base::mask masks[] = {
1119 ALPHA, std::ctype_base::mask (), CNTRL, DIGIT,
1122 };
1123
1124 // see the POSIX description of LC_CTYPE in Locale for a table
1125 // of required and allowed combinations of character classes
1126
1127 // a character in a given /* class */ below is also required
1128 // to be included in the following set of classes
1129 static const int required [sizeof masks / sizeof *masks] = {
1130 /* alpha */ ALPHA | GRAPH | PRINT,
1131 /* blank */ SPACE,
1132 /* cntrl */ CNTRL,
1133 /* digit */ DIGIT | GRAPH | PRINT | XDIGIT,
1134 /* graph */ GRAPH | PRINT,
1135 /* lower */ ALPHA | GRAPH | LOWER | PRINT,
1136 /* print */ PRINT,
1137 /* punct */ GRAPH | PRINT | PUNCT,
1138 /* space */ SPACE,
1139 /* upper */ ALPHA | GRAPH | PRINT | UPPER,
1140 /* xdigit */ GRAPH | PRINT | XDIGIT
1141 };
1142
1143 // a character in a given /* class */ below may also
1144 // be included in the following set of classes
1145 static const int allowed [sizeof masks / sizeof *masks] = {
1146 /* alpha */ UPPER | LOWER | XDIGIT,
1147 /* blank */ CNTRL,
1148 /* cntrl */ SPACE,
1149 /* digit */ 0,
1150 /* graph */ UPPER | LOWER | ALPHA | DIGIT | SPACE | PUNCT |XDIGIT,
1151 /* lower */ UPPER | XDIGIT,
1152 /* print */ UPPER | LOWER | ALPHA | DIGIT | SPACE | PUNCT |XDIGIT,
1153 /* punct */ SPACE,
1154 /* space */ CNTRL,
1155 /* upper */ LOWER | XDIGIT,
1156 /* xdigit */ UPPER | LOWER | ALPHA | DIGIT
1157 };
1158
1159 // a character in a given /* class */ below is explicitly
1160 // disallowed to be included in the following set of classes
1161 static const int disallowed [sizeof masks / sizeof *masks] = {
1162 /* alpha */ DIGIT | SPACE | CNTRL | PUNCT,
1163 /* blank */ UPPER | LOWER | ALPHA | DIGIT,
1164 /* cntrl */ UPPER | LOWER | ALPHA | DIGIT | PUNCT | GRAPH | PRINT,
1165 /* digit */ UPPER | LOWER | ALPHA | SPACE | SPACE | CNTRL,
1166 /* graph */ CNTRL,
1167 /* lower */ DIGIT | SPACE | CNTRL | PUNCT,
1168 /* print */ CNTRL,
1169 /* punct */ UPPER | LOWER | ALPHA | DIGIT | CNTRL | XDIGIT,
1170 /* space */ UPPER | LOWER | ALPHA | DIGIT | XDIGIT,
1171 /* upper */ DIGIT | SPACE | CNTRL | PUNCT,
1172 /* xdigit */ SPACE | CNTRL | PUNCT
1173 };
1174
1175 // obtain the mask of a single character
1176 std::ctype_base::mask m;
1177 ctp.is (&ch, &ch + 1, &m);
1178
1179 int missing = 0; // required bits missing in ch's mask
1180 int all_allowed = 0; // all bits allowed to be set in ch's mask
1181 int all_disallowed = 0; // all bits disallowed to be set in the mask
1182
1183 for (std::size_t k = 0; k != sizeof masks / sizeof *masks; ++k) {
1184
1185 // assumes masks [k] has a single bit set
1186 const int bit = m & masks [k];
1187 if (!bit)
1188 continue;
1189
1190 if ((bit & required [k]) && (m & required [k]) != required [k]) {
1191 // character in a class given by masks[k] is required
1192 // to also belong to all classes in required[k]
1193
1194 missing |= ~(m & required [k]) & required [k];
1195 }
1196
1197 // character in a class given by masks[k] is only allowed
1198 // to belong to classes in (allowed[k] | required[k]) and
1199 // is not allowed to belong to those in disallowed[k]
1200 all_allowed |= required [k] | allowed [k];
1201 all_disallowed |= disallowed [k];
1202 }
1203
1204 // the space character automatically belongs to the print class
1205 // but cannot belong to the punct or graph classes; other characters
1206 // that belong to the space class can belong to the punct and graph
1207 // classes
1208 if (' ' == ch) {
1209 all_disallowed |= PUNCT | GRAPH;
1210 if (!(m & PRINT))
1211 missing |= PRINT;
1212 }
1213
1214 int cmask = -1;
1215
1216 if (missing) {
1217
1218 if (-1 == cmask)
1219 cmask = libc_mask (-1, ch, locname);
1220
1221 rw_assert (m == cmask, 0, __LINE__,
1222 "mask of %{#lc} in locale(%#s) "
1223 "is missing bits %{LC}: %{LC}",
1224 ch, locname, missing, m);
1225 }
1226
1227 if (m & ~all_allowed) {
1228
1229 if (-1 == cmask)
1230 cmask = libc_mask (-1, ch, locname);
1231
1232 rw_assert (m == cmask, 0, __LINE__,
1233 "mask of %{#lc} in locale (%#s) "
1234 "contains extra bits %{LC}: %{LC}",
1235 ch, locname, m & ~all_allowed, m);
1236 }
1237
1238 if (m & all_disallowed) {
1239
1240 if (-1 == cmask)
1241 cmask = libc_mask (-1, ch, locname);
1242
1243 rw_assert (m == cmask, 0, __LINE__,
1244 "mask of %{#lc} in locale (%s#) "
1245 "contains disallowed bits { %s }: { %s }",
1246 ch, locname, m & all_disallowed, m);
1247 }
1248
1249#endif // !WIN32 && !WIN64
1250
1251 } END_LOCALE_LOOP (locname);
1252}
1253
1254
1256template <class charT>
1257void test_libc (charT, const char *cname)
1258{
1259 test_is_ch (charT (), cname);
1260 test_toupper_tolower (charT (), cname);
1261 test_narrow_widen (charT (), cname);
1262 test_is (charT (), cname);
1263 test_scan (charT (), cname);
1264}
1265
1266
1268template <class charT>
1269void test_libstd_scan_is (charT, const char *cname,
1270 const std::ctype<charT> &ct,
1271 const char* str, std::ctype_base::mask mask,
1272 int expected_idx, int fwiden = 0)
1273{
1274 // convert narrow string to a (possibly) wide representation
1275 charT wstrbuf [256];
1276 charT* wstr = wstrbuf;
1277
1278 // If instructed to use the facet widen method, do so, otherwise
1279 // use widen helper function that in turn uses C lib mbstowcs
1280 if (fwiden == 0)
1281 widen (wstrbuf, str);
1282 else
1283 ct.widen (str, str + std::strlen (str), wstrbuf);
1284
1285 const int success =
1286 &wstr [expected_idx] == ct.scan_is (mask, wstr, wstr + c_strlen (wstr));
1287
1288 rw_assert (success, 0, __LINE__,
1289 "ctype<%s>::scan_is() returned an unexpected value",
1290 cname);
1291
1292}
1293
1294
1296template <class charT>
1297void test_libstd_scan_not (charT, const char *cname,
1298 const std::ctype<charT> &ct,
1299 const char* str, std::ctype_base::mask mask,
1300 int expected_idx, int fwiden = 0)
1301{
1302 // convert narrow string to a (possibly) wide representation
1303 charT wstrbuf [256];
1304 charT* wstr = wstrbuf;
1305
1306 // If instructed to use the facet widen method, do so, otherwise
1307 // use widen helper function that in turn uses C lib mbstowcs
1308 if (fwiden == 0)
1309 widen (wstrbuf, str);
1310 else
1311 ct.widen (str, str + std::strlen (str), wstrbuf);
1312
1313 const int success =
1314 &wstr[expected_idx] == ct.scan_not (mask, wstr, wstr + c_strlen (wstr));
1315
1316 rw_assert (success, 0, __LINE__,
1317 "ctype<%s>::scan_not() returned an unexpected value",
1318 cname);
1319
1320}
1321
1322
1324template <class charT>
1325void test_libstd_toupper_tolower (charT, const char *cname,
1326 const std::ctype<charT> &ct,
1327 const char *locname)
1328{
1329 rw_info (0, 0, __LINE__,
1330 "std::ctype<%s>::tolower(%1$s) toupper(%1$s) in locale(%#s)",
1331 cname, locname);
1332
1333 int success;
1334
1335#undef TEST
1336#define TEST(lower, upper) \
1337 success = ct.widen (upper) == ct.toupper (ct.widen (lower)); \
1338 rw_assert (success, 0, __LINE__, \
1339 "ctype<%s>::toupper(%d) == %d, got %d", cname, \
1340 lower, upper, ct.toupper((charT)lower)); \
1341 success = ct.widen (lower) == ct.tolower (ct.widen (upper)); \
1342 rw_assert (success, 0, __LINE__, \
1343 "ctype<%s>::tolower(%d) == %d, got %d", \
1344 cname, upper, lower, ct.tolower((charT)upper))
1345
1346 TEST ('a', 'A');
1347 TEST ('b', 'B');
1348 TEST ('c', 'C');
1349
1350 if (sizeof(charT) > 1) {
1351 TEST ('\xa0', '\xa1');
1352 }
1353
1354#undef TEST
1355}
1356
1357
1359template <class charT>
1360void test_libstd_mask (charT, const char *cname,
1361 const std::ctype<charT> &ct, const char *locname)
1362{
1363
1364 rw_info (0, 0, __LINE__, "std::ctype<%s>::is(mask, %1$s) in locale(%#s)",
1365 cname, locname);
1366
1367#undef TEST
1368#define TEST(ch, m) \
1369 rw_assert (ct.is (m, ch), 0, __LINE__, \
1370 "ctype<%s>::is(%d, %d) failed", cname, m, ch)
1371
1372 // make sure the characters have the correct masks
1373 TEST (charT ('a'), ALPHA);
1374 TEST (charT ('a'), LOWER);
1375 TEST (charT ('a'), XDIGIT);
1376 TEST (charT ('a'), GRAPH);
1377 TEST (charT ('a'), PRINT);
1378 TEST (charT ('a'), ALPHA | LOWER | XDIGIT | PRINT);
1379
1380 TEST (charT ('b'), ALPHA);
1381 TEST (charT ('b'), LOWER);
1382 TEST (charT ('b'), XDIGIT);
1383 TEST (charT ('b'), GRAPH);
1384 TEST (charT ('b'), PRINT);
1385 TEST (charT ('b'), ALPHA | LOWER | XDIGIT | PRINT);
1386
1387 TEST (charT ('c'), ALPHA);
1388 TEST (charT ('c'), LOWER);
1389 TEST (charT ('c'), XDIGIT);
1390 TEST (charT ('c'), GRAPH);
1391 TEST (charT ('c'), PRINT);
1392 TEST (charT ('c'), ALPHA | LOWER | XDIGIT | PRINT);
1393
1394 TEST (charT ('A'), ALPHA);
1395 TEST (charT ('A'), UPPER);
1396 TEST (charT ('A'), XDIGIT);
1397 TEST (charT ('A'), GRAPH);
1398 TEST (charT ('A'), PRINT);
1399 TEST (charT ('A'), ALPHA | UPPER | XDIGIT | PRINT);
1400
1401 TEST (charT ('B'), ALPHA);
1402 TEST (charT ('B'), UPPER);
1403 TEST (charT ('B'), XDIGIT);
1404 TEST (charT ('B'), GRAPH);
1405 TEST (charT ('B'), PRINT);
1406 TEST (charT ('B'), ALPHA | UPPER | XDIGIT | PRINT);
1407
1408 TEST (charT ('C'), ALPHA);
1409 TEST (charT ('C'), UPPER);
1410 TEST (charT ('C'), XDIGIT);
1411 TEST (charT ('C'), GRAPH);
1412 TEST (charT ('C'), PRINT);
1413 TEST (charT ('C'), ALPHA | UPPER | XDIGIT | PRINT);
1414
1415 TEST (charT ('1'), DIGIT);
1416 TEST (charT ('1'), XDIGIT);
1417 TEST (charT ('1'), GRAPH);
1418 TEST (charT ('1'), PRINT);
1419 TEST (charT ('1'), DIGIT | XDIGIT | GRAPH | PRINT);
1420
1421 TEST (charT ('2'), DIGIT);
1422 TEST (charT ('2'), XDIGIT);
1423 TEST (charT ('2'), GRAPH);
1424 TEST (charT ('2'), PRINT);
1425 TEST (charT ('2'), DIGIT | XDIGIT | GRAPH | PRINT);
1426
1427 TEST (charT ('3'), DIGIT);
1428 TEST (charT ('3'), XDIGIT);
1429 TEST (charT ('3'), GRAPH);
1430 TEST (charT ('3'), PRINT);
1431 TEST (charT ('3'), DIGIT | XDIGIT | GRAPH | PRINT);
1432
1433 TEST (charT (' '), SPACE);
1434 TEST (charT (' '), GRAPH);
1435 TEST (charT (' '), PRINT);
1436 TEST (charT (' '), SPACE | GRAPH | PRINT);
1437
1438 if (sizeof (charT) > 1) {
1439 TEST (ct.widen ('\xa0'), ALPHA);
1440 TEST (ct.widen ('\xa0'), LOWER);
1441 TEST (ct.widen ('\xa0'), GRAPH);
1442 TEST (ct.widen ('\xa0'), PRINT);
1443 TEST (ct.widen ('\xa0'), ALPHA | LOWER | GRAPH | PRINT);
1444
1445 TEST (ct.widen ('\xa1'), ALPHA);
1446 TEST (ct.widen ('\xa1'), UPPER);
1447 TEST (ct.widen ('\xa1'), GRAPH);
1448 TEST (ct.widen ('\xa1'), PRINT);
1449 TEST (ct.widen ('\xa1'), ALPHA | UPPER | GRAPH | PRINT);
1450
1451 TEST (ct.widen ('\xa2'), DIGIT);
1452 TEST (ct.widen ('\xa2'), GRAPH);
1453 TEST (ct.widen ('\xa2'), PRINT);
1454 TEST (ct.widen ('\xa2'), DIGIT | GRAPH | PRINT);
1455 }
1456}
1457
1458
1460template <class charT>
1461void test_libstd (charT, const char *cname)
1462{
1463 if (0) {
1464 // do a compile time only test on use_facet and has_facet
1465 _STD_HAS_FACET (std::ctype_byname<charT>, std::locale ());
1466 _STD_USE_FACET (std::ctype_byname<charT>, std::locale ());
1467 }
1468
1469 const char cmap_1[] = {
1470 "<code_set_name> \"ANSI_X3.4-1968\"\n"
1471 "<mb_cur_max> 1\n"
1472 "<mb_cur_min> 1\n"
1473 "CHARMAP\n"
1474 "<U0000> \\x00\n"
1475 "<U0001> \\x01\n"
1476 "<U0002> \\x02\n"
1477 "<U0003> \\x03\n"
1478 "<U0004> \\x04\n"
1479 "<U0005> \\x05\n"
1480 "<U0006> \\x06\n"
1481 "<U0007> \\x07\n"
1482 "<U0008> \\x08\n"
1483 "<U0009> \\x09\n"
1484 "<U000a> \\x0a\n"
1485 "<U000b> \\x0b\n"
1486 "<U000c> \\x0c\n"
1487 "<U000d> \\x0d\n"
1488 "<U000e> \\x0e\n"
1489 "<U000f> \\x0f\n"
1490 "<U0010> \\x10\n"
1491 "<U0011> \\x11\n"
1492 "<U0012> \\x12\n"
1493 "<U0013> \\x13\n"
1494 "<U0014> \\x14\n"
1495 "<U0015> \\x15\n"
1496 "<U0016> \\x16\n"
1497 "<U0017> \\x17\n"
1498 "<U0018> \\x18\n"
1499 "<U0019> \\x19\n"
1500 "<U001a> \\x1a\n"
1501 "<U001b> \\x1b\n"
1502 "<U001c> \\x1c\n"
1503 "<U001d> \\x1d\n"
1504 "<U001e> \\x1e\n"
1505 "<U001f> \\x1f\n"
1506 "<U0020> \\x20\n"
1507 "<U0021> \\x21\n"
1508 "<U0022> \\x22\n"
1509 "<U0023> \\x23\n"
1510 "<U0024> \\x24\n"
1511 "<U0025> \\x25\n"
1512 "<U0026> \\x26\n"
1513 "<U0027> \\x27\n"
1514 "<U0028> \\x28\n"
1515 "<U0029> \\x29\n"
1516 "<U002a> \\x2a\n"
1517 "<U002b> \\x2b\n"
1518 "<U002c> \\x2c\n"
1519 "<U002d> \\x2d\n"
1520 "<U002e> \\x2e\n"
1521 "<U002f> \\x2f\n"
1522 "<U0030> \\x30\n"
1523 "<U0031> \\x31\n"
1524 "<U0032> \\x32\n"
1525 "<U0033> \\x33\n"
1526 "<U0034> \\x34\n"
1527 "<U0035> \\x35\n"
1528 "<U0036> \\x36\n"
1529 "<U0037> \\x37\n"
1530 "<U0038> \\x38\n"
1531 "<U0039> \\x39\n"
1532 "<U003a> \\x3a\n"
1533 "<U003b> \\x3b\n"
1534 "<U003c> \\x3c\n"
1535 "<U003d> \\x3d\n"
1536 "<U003e> \\x3e\n"
1537 "<U003f> \\x3f\n"
1538 "<U0040> \\x40\n"
1539 "<U0041> \\x41\n"
1540 "<U0042> \\x42\n"
1541 "<U0043> \\x43\n"
1542 "<U0044> \\x44\n"
1543 "<U0045> \\x45\n"
1544 "<U0046> \\x46\n"
1545 "<U0047> \\x47\n"
1546 "<U0048> \\x48\n"
1547 "<U0049> \\x49\n"
1548 "<U004a> \\x4a\n"
1549 "<U004b> \\x4b\n"
1550 "<U004c> \\x4c\n"
1551 "<U004d> \\x4d\n"
1552 "<U004e> \\x4e\n"
1553 "<U004f> \\x4f\n"
1554 "<U0050> \\x50\n"
1555 "<U0051> \\x51\n"
1556 "<U0052> \\x52\n"
1557 "<U0053> \\x53\n"
1558 "<U0054> \\x54\n"
1559 "<U0055> \\x55\n"
1560 "<U0056> \\x56\n"
1561 "<U0057> \\x57\n"
1562 "<U0058> \\x58\n"
1563 "<U0059> \\x59\n"
1564 "<U005a> \\x5a\n"
1565 "<U005b> \\x5b\n"
1566 "<U005c> \\x5c\n"
1567 "<U005d> \\x5d\n"
1568 "<U005e> \\x5e\n"
1569 "<U005f> \\x5f\n"
1570 "<U0060> \\x60\n"
1571 "<U0061> \\x61\n"
1572 "<U0062> \\x62\n"
1573 "<U0063> \\x63\n"
1574 "<U0064> \\x64\n"
1575 "<U0065> \\x65\n"
1576 "<U0066> \\x66\n"
1577 "<U0067> \\x67\n"
1578 "<U0068> \\x68\n"
1579 "<U0069> \\x69\n"
1580 "<U006a> \\x6a\n"
1581 "<U006b> \\x6b\n"
1582 "<U006c> \\x6c\n"
1583 "<U006d> \\x6d\n"
1584 "<U006e> \\x6e\n"
1585 "<U006f> \\x6f\n"
1586 "<U0070> \\x70\n"
1587 "<U0071> \\x71\n"
1588 "<U0072> \\x72\n"
1589 "<U0073> \\x73\n"
1590 "<U0074> \\x74\n"
1591 "<U0075> \\x75\n"
1592 "<U0076> \\x76\n"
1593 "<U0077> \\x77\n"
1594 "<U0078> \\x78\n"
1595 "<U0079> \\x79\n"
1596 "<U007a> \\x7a\n"
1597 "<U007b> \\x7b\n"
1598 "<U007c> \\x7c\n"
1599 "<U007d> \\x7d\n"
1600 "<U007e> \\x7e\n"
1601 "<U007f> \\x7f\n"
1602 "<U1000> \\xa0\n"
1603 "<U1001> \\xa1\n"
1604 "<U1002> \\xa2\n"
1605 "END CHARMAP\n"
1606 };
1607
1608 const char loc_1[] = {
1609 "escape_char /\n"
1610 "LC_CTYPE\n"
1611 "# <A> <B> <C> MYANMAR LETTER KHA\n"
1612 "upper <U0041>;<U0042>;<U0043>;<U1001>\n"
1613 " <a> <b> <c> MYANMAR LETTER KA\n"
1614 "lower <U0061>;<U0062>;<U0063>;<U1000>\n"
1615 "alpha <U0061>;<U0062>;<U0063>;<U0041>;"
1616 "<U0042>;<U0043>;<U1000>;<U1001>\n"
1617 "digit <U0031>;<U0032>;<U0033>;<U1002>\n"
1618 "space <U0020>\n"
1619 "cntrl <U0000>\n"
1620 " <!> <\">\n"
1621 "punct <U0021>; <U0022>\n"
1622 "graph <U0041>;<U0042>;<U0043>;<U0061>;<U0062>;<U0063>;"
1623 "<U1000>;<U1001>;<U1002>;<U1003>;<U1004>;<U1005>;"
1624 "<U0031>;<U0032>;<U0033>;<U0020>;<U0021>;<U0022>\n"
1625 "print <U0041>;<U0042>;<U0043>;"
1626 "<U0061>;<U0062>;<U0063>;"
1627 "<U1000>;<U1001>;<U1002>;<U1003>;<U1004>;<U1005>;"
1628 "<U0031>;<U0032>;<U0033>;<U0020>;<U0021>;<U0022>\n"
1629 "xdigit <U0041>;<U0042>;<U0043>;<U0061>;<U0062>;"
1630 "<U0063>;<U0031>;<U0032>;<U0033>\n"
1631 "toupper (<U0061>,<U0041>);(<U0062>,<U0042>);"
1632 "(<U0063>,<U0043>);(<U1000>,<U1001>)\n"
1633 "tolower (<U0041>,<U0061>);(<U0042>,<U0062>);"
1634 "(<U0043>,<U0063>);(<U1001>,<U1000>)\n"
1635 "END LC_CTYPE\n"
1636 };
1637
1638 //invoke rw_create_locale to build a locale to test with
1639 const char* const locname = rw_create_locale (cmap_1, loc_1);
1640
1641 if (!rw_error (0 != locname, 0, __LINE__,
1642 "failed to create a locale in %s", locale_root))
1643 return;
1644
1645 const std::locale loc (locname);
1646
1647 const std::ctype<charT> &ct =
1648 _STD_USE_FACET (std::ctype<charT>, loc);
1649
1650 ct._C_opts |= ct._C_use_libstd;
1651 ct._C_opts &= ~ct._C_use_libc;
1652
1653 test_libstd_mask (charT (), cname, ct, locname);
1654 test_libstd_toupper_tolower (charT (), cname, ct, locname);
1655
1656 // now check the scan functions
1657 rw_info (0, 0, __LINE__,
1658 "std::ctype<%s>::scan_is(const %1$s*, const %1$s, mask*) "
1659 "in locale(%#s)", cname, locname);
1660
1661 test_libstd_scan_is (charT (), cname, ct, "abc1BC", DIGIT, 3);
1662 test_libstd_scan_is (charT (), cname, ct, "abc123B ", SPACE, 7);
1663 test_libstd_scan_is (charT (), cname, ct, "abc123", LOWER, 0);
1664 test_libstd_scan_is (charT (), cname, ct, "abc123", UPPER, 6);
1665 test_libstd_scan_is (charT (), cname, ct, "abc1ABC", DIGIT | UPPER, 3);
1666 test_libstd_scan_is (charT (), cname, ct, "abcA2BC", DIGIT | UPPER, 3);
1667
1668 if (sizeof(charT) > 1) {
1669 test_libstd_scan_is (charT (), cname, ct, "ABC\xa0xyz", LOWER, 3, 1);
1670 test_libstd_scan_is (charT (), cname, ct, "abcx\xa1yz", UPPER, 4, 1);
1671 }
1672
1673 rw_info (0, 0, __LINE__,
1674 "std::ctype<%s>::scan_not(const %1$s*, const %1$s, mask*) "
1675 "in locale(%#s)", cname, locname);
1676
1677 test_libstd_scan_not (charT (), cname, ct, "abc1BC", ALPHA, 3);
1678 test_libstd_scan_not (charT (), cname, ct, "aaBBcc", LOWER, 2);
1679 test_libstd_scan_not (charT (), cname, ct, "abc1BC", DIGIT, 0);
1680 test_libstd_scan_not (charT (), cname, ct, "abc1BC", PRINT, 6);
1681
1682 if (sizeof(charT) > 1) {
1683 test_libstd_scan_not (charT (), cname, ct, "abc\xa2xyz", ALPHA, 3, 1);
1684 test_libstd_scan_not (charT (), cname, ct, "123\xa1yz ", DIGIT, 3, 1);
1685 }
1686}
1687
1688
1690static int
1691run_test (int, char**)
1692{
1693 test_libc (char (), "char");
1694
1695#ifndef _RWSTD_NO_WCHAR_T
1696 test_libc (wchar_t (), "wchar_t");
1697#endif // _RWSTD_NO_WCHAR_T
1698
1699 test_libstd (char (), "char");
1700
1701#ifndef _RWSTD_NO_WCHAR_T
1702 test_libstd (wchar_t (), "wchar_t");
1703#endif // _RWSTD_NO_WCHAR_T
1704
1705 return 0;
1706}
1707
1708
1710int main (int argc, char *argv[])
1711{
1712 return rw_test (argc, argv, __FILE__,
1713 "lib.category.ctype",
1714 0 /* no comment */,
1715 run_test,
1716 "",
1717 (void*)0 /* sentinel */);
1718}
const char lower[]
const char graph[]
const char upper[]
const char cntrl[]
const char print[]
const char punct[]
#define m
Definition 17.names.cpp:129
#define i
Definition 17.names.cpp:126
#define s1
Definition 17.names.cpp:242
#define k
Definition 17.names.cpp:128
#define s2
Definition 17.names.cpp:268
#define loc
Definition 17.names.cpp:492
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define c
Definition 17.names.cpp:111
#define charT
Definition 17.names.cpp:456
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
volatile int result
#define SCAN(what)
int libc_iscntrl(char ch)
#define END_LOCALE_LOOP(locname)
char libc_tolower(char ch)
char libc_toupper(char ch)
int libc_isgraph(char ch)
int libc_islower(char ch)
int libc_ispunct(char ch)
void test_libstd_scan_not(charT, const char *cname, const std::ctype< charT > &ct, const char *str, std::ctype_base::mask mask, int expected_idx, int fwiden=0)
#define COND3(what)
void test_is(charT, const char *cname)
#define IS(what)
int libc_isdigit(char ch)
unsigned char UChar
#define SPACE
#define TEST(lower, upper)
const char * widen(char *dst, const char *src)
const char * locale_list
bool libc_is(std::ctype_base::mask mask, char ch, const char *locname)
int libc_isupper(char ch)
#define DIGIT
void test_libstd_scan_is(charT, const char *cname, const std::ctype< charT > &ct, const char *str, std::ctype_base::mask mask, int expected_idx, int fwiden=0)
int libc_isalpha(char ch)
#define PRINT
int libc_isxdigit(char ch)
void test_toupper_tolower(charT, const char *cname)
#define CNTRL
void test_scan(charT, const char *cname)
#define MAX_STR_SIZE
int libc_isalnum(char ch)
bool cond3(std::ctype_base::mask, char, const char *)
const char * narrow(char *dst, const char *src)
#define PUNCT
#define BEGIN_LOCALE_LOOP(num, locname, loop_cntrl)
std::size_t c_strlen(const char *s1)
#define LOWER
void test_libstd(charT, const char *cname)
#define XDIGIT
#define UPPER
int libc_isspace(char ch)
void test_libstd_mask(charT, const char *cname, const std::ctype< charT > &ct, const char *locname)
#define NLOOPS
std::ctype_base::mask libc_mask(int mask, char ch, const char *locname)
const char * locale_root
void test_libc(charT, const char *cname)
void test_is_ch(charT, const char *cname)
void gen_str(charT *str, std::size_t size)
int libc_isprint(char ch)
void test_libstd_toupper_tolower(charT, const char *cname, const std::ctype< charT > &ct, const char *locname)
void test_narrow_widen(charT, const char *cname)
bool cond1(std::ctype_base::mask mask, char ch, const char *locname)
#define ALPHA
#define COND1(what)
int c_strcmp(const char *s1, const char *s2)
#define GRAPH
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
#define main
#define LC_CTYPE
#define LC_ALL
unsigned short wchar_t
#define EOF
#define WEOF
#define _STD_HAS_FACET(type, arg)
Definition _defs.h:917
#define _STD_USE_FACET(type, arg)
Definition _defs.h:920
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
const char * str
Definition exec.cpp:170
#define UCHAR_MAX
Definition limits.h:60
#define MB_LEN_MAX
Definition limits.h:100
_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 const char * rw_create_locale(const char *, const char *)
Definition locale.cpp:792
unsigned char UChar
Definition collate.cpp:122