You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stdcxx.apache.org by se...@apache.org on 2007/06/28 00:19:31 UTC

svn commit: r551354 - /incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp

Author: sebor
Date: Wed Jun 27 15:19:30 2007
New Revision: 551354

URL: http://svn.apache.org/viewvc?view=rev&rev=551354
Log:
2007-06-27  Martin Sebor  <se...@roguewave.com>

	* 22.locale.moneypunct.mt.cpp: Rewrote so as not to rely on localeconv
	but retrieve the "master" data from the C++ locale instead instead.
	(thread_loop_body): Factored out the body of thread_func here.
	(get_format): Removed.
	(rw_opt_nloops): Reduced from 2000000 to 10000 and set to the number
	of tested locales in non-reentrant configurations to speed things up.
	(rw_opt_setlocales): Callback function to process --locales option.
	(main): Set rw_opt_nthreads to rw_get_cpus() in thread-safe configs.
	(--locale=<arg>): New command line option to specify the names of
	locales to test.

Modified:
    incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp

Modified: incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp?view=diff&rev=551354&r1=551353&r2=551354
==============================================================================
--- incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp (original)
+++ incubator/stdcxx/trunk/tests/localization/22.locale.moneypunct.mt.cpp Wed Jun 27 15:19:30 2007
@@ -29,9 +29,8 @@
 #include <ios>        // for ios
 #include <locale>     // for locale, moneypunct
 
-#include <clocale>    // for lconv, localeconv()
-#include <cstdlib>    // for mbstowcs()
-#include <cstring>    // for size_t, strcpy()
+#include <cstdlib>    // for mbstowcs(), size_t
+#include <cstring>    // for strcpy()
 
 #include <rw_locale.h>
 #include <rw_thread.h>
@@ -42,17 +41,16 @@
 // maximum number of threads allowed by the command line interface
 #define MAX_THREADS   32
 
-
-#ifdef _RWSTD_REENTRANT
-int rw_opt_nthreads = 4;
-#else   // if !defined (_RWSTD_REENTRANT)
-// in non-threaded builds use just one thread
+// default number of threads (will be adjusted to the number
+// of processors/cores later)
 int rw_opt_nthreads = 1;
-#endif   // _RWSTD_REENTRANT
 
-// the number of times each thread should iterate (unless specified
-// otherwise on the command line)
-int rw_opt_nloops = 200000;
+// the default number of times for each thread to iterate
+#define DFLT_LOOPS   10000
+
+// the number of times each thread should iterate (will be set to
+// DFLT_LOOPS unless explicitly specified on the command line)
+int rw_opt_nloops = -1;
 
 /**************************************************************************/
 
@@ -97,147 +95,154 @@
 
 } punct_data [MAX_THREADS];
 
-
-extern "C" {
+/**************************************************************************/
 
 bool test_char;    // exercise num_put<char>
 bool test_wchar;   // exercise num_put<wchar_t>
 
-
-static void*
-thread_func (void*)
+static void
+thread_loop_body (std::size_t i)
 {
-    for (int i = 0; i != rw_opt_nloops; ++i) {
+    const std::size_t inx = std::size_t (i) % (nlocales ? nlocales : 1);
 
-        const std::size_t inx = std::size_t (i) % nlocales;
+    const MoneypunctData* const data = punct_data + inx;
 
-        const MoneypunctData* const data = punct_data + inx;
+    // construct a named locale
+    const std::locale loc (data->locale_name_);
 
-        // construct a named locale
-        const std::locale loc (data->locale_name_);
+    if (test_char) {
+        // exercise the narrow char, local specialization of the facet
+
+        typedef std::moneypunct<char, false> Punct;
+
+        const Punct &mp = std::use_facet<Punct>(loc);
+
+        const char           dp  = mp.decimal_point ();
+        const char           ts  = mp.thousands_sep ();
+        const std::string    grp = mp.grouping ();
+        const std::string    cur = mp.curr_symbol ();
+        const std::string    pos = mp.positive_sign ();
+        const std::string    neg = mp.negative_sign ();
+        const int            fd  = mp.frac_digits ();
+        const Punct::pattern pfm = mp.pos_format ();
+        const Punct::pattern nfm = mp.neg_format ();
+
+        RW_ASSERT (dp == data->decimal_point_);
+        RW_ASSERT (ts == data->thousands_sep_);
+        RW_ASSERT (fd == data->frac_digits_);
+        RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
+        RW_ASSERT (!rw_strncmp (cur.c_str (), data->curr_symbol_));
+        RW_ASSERT (!rw_strncmp (pos.c_str (), data->positive_sign_));
+        RW_ASSERT (!rw_strncmp (neg.c_str (), data->negative_sign_));
 
-        if (test_char) {
-            // exercise the narrow char, local specialization of the facet
-
-            typedef std::moneypunct<char, false> Punct;
-
-            const Punct &mp = std::use_facet<Punct>(loc);
-
-            const char           dp  = mp.decimal_point ();
-            const char           ts  = mp.thousands_sep ();
-            const std::string    grp = mp.grouping ();
-            const std::string    cur = mp.curr_symbol ();
-            const std::string    pos = mp.positive_sign ();
-            const std::string    neg = mp.negative_sign ();
-            const int            fd  = mp.frac_digits ();
-            const Punct::pattern pfm = mp.pos_format ();
-            const Punct::pattern nfm = mp.neg_format ();
-
-            RW_ASSERT (dp == data->decimal_point_);
-            RW_ASSERT (ts == data->thousands_sep_);
-            RW_ASSERT (fd == data->frac_digits_);
-            RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
-            RW_ASSERT (!rw_strncmp (cur.c_str (), data->curr_symbol_));
-            RW_ASSERT (!rw_strncmp (pos.c_str (), data->positive_sign_));
-            RW_ASSERT (!rw_strncmp (neg.c_str (), data->negative_sign_));
+        RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4));
+        RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4));
+    }
 
-            RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4));
-            RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4));
-        }
+    if (test_char) {
+        // exercise the narrow char, international specialization
 
-        if (test_char) {
-            // exercise the narrow char, international specialization
+        typedef std::moneypunct<char, true> Punct;
 
-            typedef std::moneypunct<char, true> Punct;
+        const Punct &mp = std::use_facet<Punct>(loc);
 
-            const Punct &mp = std::use_facet<Punct>(loc);
+        const char           dp  = mp.decimal_point ();
+        const char           ts  = mp.thousands_sep ();
+        const std::string    grp = mp.grouping ();
+        const std::string    cur = mp.curr_symbol ();
+        const std::string    pos = mp.positive_sign ();
+        const std::string    neg = mp.negative_sign ();
+        const int            fd  = mp.frac_digits ();
+        const Punct::pattern pfm = mp.pos_format ();
+        const Punct::pattern nfm = mp.neg_format ();
+
+        RW_ASSERT (dp == data->decimal_point_);
+        RW_ASSERT (ts == data->thousands_sep_);
+        RW_ASSERT (fd == data->frac_digits_);
+        RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
+        RW_ASSERT (!rw_strncmp (cur.c_str (), data->int_curr_symbol_));
+        RW_ASSERT (!rw_strncmp (pos.c_str (), data->positive_sign_));
+        RW_ASSERT (!rw_strncmp (neg.c_str (), data->negative_sign_));
 
-            const char           dp  = mp.decimal_point ();
-            const char           ts  = mp.thousands_sep ();
-            const std::string    grp = mp.grouping ();
-            const std::string    cur = mp.curr_symbol ();
-            const std::string    pos = mp.positive_sign ();
-            const std::string    neg = mp.negative_sign ();
-            const int            fd  = mp.frac_digits ();
-            const Punct::pattern pfm = mp.pos_format ();
-            const Punct::pattern nfm = mp.neg_format ();
+        RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4));
+        RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4));
+    }
 
-            RW_ASSERT (dp == data->decimal_point_);
-            RW_ASSERT (ts == data->thousands_sep_);
-            RW_ASSERT (fd == data->frac_digits_);
-            RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
-            RW_ASSERT (!rw_strncmp (cur.c_str (), data->int_curr_symbol_));
-            RW_ASSERT (!rw_strncmp (pos.c_str (), data->positive_sign_));
-            RW_ASSERT (!rw_strncmp (neg.c_str (), data->negative_sign_));
+    // both specializations may be tested at the same time
 
-            RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4));
-            RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4));
-        }
+#ifndef _RWSTD_NO_WCHAR_T
 
-        // both specializations may be tested at the same time
+    if (test_wchar) {
+        // exercise the wide char, local specialization of the facet
 
-#ifndef _RWSTD_NO_WCHAR_T
+        typedef std::moneypunct<wchar_t, false> Punct;
 
-        if (test_wchar) {
-            // exercise the wide char, local specialization of the facet
+        const Punct &mp = std::use_facet<Punct>(loc);
 
-            typedef std::moneypunct<wchar_t, false> Punct;
+        const char           dp  = mp.decimal_point ();
+        const char           ts  = mp.thousands_sep ();
+        const std::string    grp = mp.grouping ();
+        const std::wstring   cur = mp.curr_symbol ();
+        const std::wstring   pos = mp.positive_sign ();
+        const std::wstring   neg = mp.negative_sign ();
+        const int            fd  = mp.frac_digits ();
+        const Punct::pattern pfm = mp.pos_format ();
+        const Punct::pattern nfm = mp.neg_format ();
+
+        RW_ASSERT (dp == data->wdecimal_point_);
+        RW_ASSERT (ts == data->wthousands_sep_);
+        RW_ASSERT (fd == data->frac_digits_);
+        RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
+        RW_ASSERT (!rw_strncmp (cur.c_str (), data->wcurr_symbol_));
+        RW_ASSERT (!rw_strncmp (pos.c_str (), data->wpositive_sign_));
+        RW_ASSERT (!rw_strncmp (neg.c_str (), data->wnegative_sign_));
 
-            const Punct &mp = std::use_facet<Punct>(loc);
+        RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4));
+        RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4));
+    }
 
-            const char           dp  = mp.decimal_point ();
-            const char           ts  = mp.thousands_sep ();
-            const std::string    grp = mp.grouping ();
-            const std::wstring   cur = mp.curr_symbol ();
-            const std::wstring   pos = mp.positive_sign ();
-            const std::wstring   neg = mp.negative_sign ();
-            const int            fd  = mp.frac_digits ();
-            const Punct::pattern pfm = mp.pos_format ();
-            const Punct::pattern nfm = mp.neg_format ();
+    if (test_wchar) {
+        // exercise the wide char, international specialization
 
-            RW_ASSERT (dp == data->wdecimal_point_);
-            RW_ASSERT (ts == data->wthousands_sep_);
-            RW_ASSERT (fd == data->frac_digits_);
-            RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
-            RW_ASSERT (!rw_strncmp (cur.c_str (), data->wcurr_symbol_));
-            RW_ASSERT (!rw_strncmp (pos.c_str (), data->wpositive_sign_));
-            RW_ASSERT (!rw_strncmp (neg.c_str (), data->wnegative_sign_));
+        typedef std::moneypunct<wchar_t, true> Punct;
 
-            RW_ASSERT (!std::memcmp (&pfm, data->pos_format_, 4));
-            RW_ASSERT (!std::memcmp (&nfm, data->neg_format_, 4));
-        }
+        const Punct &mp = std::use_facet<Punct>(loc);
 
-        if (test_wchar) {
-            // exercise the wide char, international specialization
+        const char           dp  = mp.decimal_point ();
+        const char           ts  = mp.thousands_sep ();
+        const std::string    grp = mp.grouping ();
+        const std::wstring   cur = mp.curr_symbol ();
+        const std::wstring   pos = mp.positive_sign ();
+        const std::wstring   neg = mp.negative_sign ();
+        const int            fd  = mp.frac_digits ();
+        const Punct::pattern pfm = mp.pos_format ();
+        const Punct::pattern nfm = mp.neg_format ();
+
+        RW_ASSERT (dp == data->wdecimal_point_);
+        RW_ASSERT (ts == data->wthousands_sep_);
+        RW_ASSERT (fd == data->frac_digits_);
+        RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
+        RW_ASSERT (!rw_strncmp (cur.c_str (), data->wint_curr_symbol_));
+        RW_ASSERT (!rw_strncmp (pos.c_str (), data->wpositive_sign_));
+        RW_ASSERT (!rw_strncmp (neg.c_str (), data->wnegative_sign_));
 
-            typedef std::moneypunct<wchar_t, true> Punct;
+        RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4));
+        RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4));
+    }
 
-            const Punct &mp = std::use_facet<Punct>(loc);
+#endif   // _RWSTD_NO_WCHAR_T
 
-            const char           dp  = mp.decimal_point ();
-            const char           ts  = mp.thousands_sep ();
-            const std::string    grp = mp.grouping ();
-            const std::wstring   cur = mp.curr_symbol ();
-            const std::wstring   pos = mp.positive_sign ();
-            const std::wstring   neg = mp.negative_sign ();
-            const int            fd  = mp.frac_digits ();
-            const Punct::pattern pfm = mp.pos_format ();
-            const Punct::pattern nfm = mp.neg_format ();
+}
 
-            RW_ASSERT (dp == data->wdecimal_point_);
-            RW_ASSERT (ts == data->wthousands_sep_);
-            RW_ASSERT (fd == data->frac_digits_);
-            RW_ASSERT (!rw_strncmp (grp.c_str (), data->grouping_));
-            RW_ASSERT (!rw_strncmp (cur.c_str (), data->wint_curr_symbol_));
-            RW_ASSERT (!rw_strncmp (pos.c_str (), data->wpositive_sign_));
-            RW_ASSERT (!rw_strncmp (neg.c_str (), data->wnegative_sign_));
 
-            RW_ASSERT (!std::memcmp (&pfm, data->int_pos_format_, 4));
-            RW_ASSERT (!std::memcmp (&nfm, data->int_neg_format_, 4));
-        }
+extern "C" {
 
-#endif   // _RWSTD_NO_WCHAR_T
+static void*
+thread_func (void*)
+{
+    for (int i = 0; i != rw_opt_nloops; ++i) {
 
+        thread_loop_body (std::size_t (i));
     }
 
     return 0;
@@ -247,154 +252,16 @@
 
 /**************************************************************************/
 
-static void
-get_format (MoneypunctData *pdata, const std::lconv *pconv)
-{
-    // code copied from src/punct.cpp
-
-    enum {
-        // for syntactic convenience
-        none   = std::money_base::none,
-        space  = std::money_base::space,
-        symbol = std::money_base::symbol,
-        sign   = std::money_base::sign,
-        value  = std::money_base::value
-    };
-
-    static const std::money_base::pattern pat[] = {
-
-        // cs_precedes [0..1]:
-        //
-        // An integer set to 1 if the currency_symbol precedes the value
-        // for a monetary value, and set to 0 if the symbol succeeds
-        // the value.
-
-        // sep_by_space [0..2]:
-        //
-        // 0  No space separates the currency_symbol from the value for
-        //    a monetary value.
-        // 1  If the currency symbol and sign string are adjacent, a space
-        //    separates them from the value; otherwise, a space separates
-        //    the currency symbol from the value.
-        // 2  If the currency symbol and sign string are adjacent, a space
-        //    separates them; otherwise, a space separates the sign string
-        //    from the value.
-
-        // sign_posn [0..4]:
-        //
-        // An integer set to a value indicating the positioning of the
-        // positive_sign for a monetary value. The following integer
-        // values shall be recognized:
-        //
-        // 0  Parentheses enclose the value and the currency_symbol.
-        // 1  The sign string precedes the value and the currency_symbol.
-        // 2  The sign string succeeds the value and the currency_symbol.
-        // 3  The sign string immediately precedes the currency_symbol.
-        // 4  The sign string immediately succeeds the currency_symbol.
-
-        // +-------- cs_precedes
-        // |+----- sep_by_space
-        // ||+-- sign_posn
-        // |||
-        // VVV  ....        -     1      $       .           // pattern
-        /* 000: -1$. */ { { sign, value, symbol, none } },   // "\3\4\2\0"
-        /* 001: -1$. */ { { sign, value, symbol, none } },   // "\3\4\2\0"
-        /* 002: 1$-. */ { { value, symbol, sign, none } },   // "\4\2\3\0"
-        /* 003: 1-$. */ { { value, sign, symbol, none } },   // "\4\3\2\0"
-        /* 004: 1$-. */ { { value, symbol, sign, none } },   // "\4\2\3\0"
-
-        /* 010: -1 $ */ { { sign, value, space, symbol } },  // "\3\4\1\2"
-        /* 011: -1 $ */ { { sign, value, space, symbol } },  // "\3\4\1\2"
-        /* 012: 1 $- */ { { value, space, symbol, sign } },  // "\4\1\2\3"
-        /* 013: 1 -$ */ { { value, space, sign, symbol } },  // "\4\3\3\2"
-        /* 014: 1 $- */ { { value, space, symbol, sign } },  // "\4\1\2\3"
-
-        /* 020: - 1$ */ { { sign, space, value, symbol } },  // "\3\1\4\2"
-        /* 021: - 1$ */ { { sign, space, value, symbol } },  // "\3\1\4\2"
-        /* 022: 1$ - */ { { value, symbol, space, sign } },  // "\4\2\1\3"
-        /* 023: 1- $ */ { { value, sign, space, symbol } },  // "\4\3\1\2"
-        /* 024: 1$ - */ { { value, symbol, space, sign } },  // "\4\2\1\3"
-
-        /* 100: -$1. */ { { sign, symbol, value, none } },   // "\3\2\4\0"
-        /* 101: -$1. */ { { sign, symbol, value, none } },   // "\3\2\4\0"
-        /* 102: $1-. */ { { symbol, value, sign, none } },   // "\2\4\3\0"
-        /* 103: -$1. */ { { sign, symbol, value, none } },   // "\3\2\4\0"
-        /* 104: $-1. */ { { symbol, sign, value, none } },   // "\2\3\4\0"
-
-        /* 110: -$ 1 */ { { sign, symbol, space, value } },  // "\3\2\1\4"
-        /* 111: -$ 1 */ { { sign, symbol, space, value } },  // "\3\2\1\4"
-        /* 112: $ 1- */ { { symbol, space, value, sign } },  // "\2\1\4\3"
-        /* 113: -$ 1 */ { { sign, symbol, space, value } },  // "\3\2\1\4"
-        /* 114: $- 1 */ { { symbol, sign, space, value } },  // "\2\3\1\4"
-
-        /* 120: - $1 */ { { sign, space, symbol, value } },  // "\3\1\2\4"
-        /* 121: - $1 */ { { sign, space, symbol, value } },  // "\3\1\2\4"
-        /* 122: $1 - */ { { symbol, value, space, sign } },  // "\2\4\1\3"
-        /* 123: - $1 */ { { sign, space, symbol, value } },  // "\3\1\2\4"
-        /* 124: $ -1 */ { { symbol, space, sign, value } }   // "\2\1\3\4"
-    };
-
-    std::size_t inx;
-
-    inx =   std::size_t (pconv->p_cs_precedes) * (3U * 5U)
-          + std::size_t (pconv->p_sep_by_space) * 5U
-          + std::size_t (pconv->p_sign_posn);
-
-    if (inx < sizeof pat / sizeof *pat)
-        std::memcpy (pdata->pos_format_, pat + inx, sizeof *pat);
-    else
-        std::memset (pdata->pos_format_, none, sizeof *pat);
-
-    inx =   std::size_t (pconv->n_cs_precedes) * (3U * 5U)
-          + std::size_t (pconv->n_sep_by_space) * 5U
-          + std::size_t (pconv->n_sign_posn);
-
-    if (inx < sizeof pat / sizeof *pat)
-        std::memcpy (pdata->neg_format_, pat + inx, sizeof *pat);
-    else
-        std::memset (pdata->neg_format_, none, sizeof *pat);
-
-
-#ifndef _RWSTD_NO_LCONV_INT_FMAT
-
-    inx =   std::size_t (pconv->int_p_cs_precedes) * (3U * 5U)
-          + std::size_t (pconv->int_p_sep_by_space) * 5U
-          + std::size_t (pconv->int_p_sign_posn);
-
-    if (inx < sizeof pat / sizeof *pat)
-        std::memcpy (pdata->int_pos_format_, pat + inx, sizeof *pat);
-    else
-        std::memset (pdata->int_pos_format_, none, sizeof *pat);
-
-    inx =   std::size_t (pconv->int_n_cs_precedes) * (3U * 5U)
-          + std::size_t (pconv->int_n_sep_by_space) * 5U
-          + std::size_t (pconv->int_n_sign_posn);
-
-    if (inx < sizeof pat / sizeof *pat)
-        memcpy (pdata->int_neg_format_, pat + inx, sizeof *pat);
-    else
-        memset (pdata->int_neg_format_, none, sizeof *pat);
-
-    std::strcpy (pdata->int_curr_symbol_, pconv->int_curr_symbol);
-
-    pdata->int_frac_digits_ = pconv->int_frac_digits;
-
-#else   // if defined (_RWSTD_NO_LCONV_INT_FMAT)
-
-    std::strcpy (pdata->int_curr_symbol_, pconv->curr_symbol);
-
-    pdata->int_frac_digits_ = pconv->frac_digits;
-
-#endif   // _RWSTD_NO_LCONV_INT_FMAT
-
-}
+static char*
+rw_opt_locales;
 
 
 static int
 run_test (int, char**)
 {
-    // get a NUL-separated list of names of installed locales
-    char* const locale_list = rw_locales ();
+    // find all installed locales for which setlocale(LC_ALL) succeeds
+    char* const locale_list =
+        rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
 
     // array of locale names to use for testing
     const char* locales [sizeof punct_data / sizeof *punct_data];
@@ -404,76 +271,144 @@
     // iterate over locales, initializing a global punct_data array
     for (char *name = locale_list; *name; name += std::strlen (name) + 1) {
 
-        const std::size_t inx = nlocales;
+        std::locale loc;
 
-        // set LC_NUMERIC and LC_CTYPE to be able to use mbstowcs()
-        if (std::setlocale (LC_ALL, name)) {
+        MoneypunctData* const pdata = punct_data + nlocales;
 
-            const std::lconv* const pconv = std::localeconv ();
-            MoneypunctData* const pdata = punct_data + inx;
+        pdata->locale_name_ = name;
+        locales [nlocales]  = name;
 
-            locales [inx] = pdata->locale_name_ = name;
+        try {
+            loc = std::locale (name);
 
-            // assign just the first character of the (potentially)
-            // multibyte decimal_point and thousands_sep (C++ locale
-            // can't deal with more)
-            pdata->decimal_point_ = *pconv->mon_decimal_point;
-            pdata->thousands_sep_ = *pconv->mon_thousands_sep;
+            typedef std::moneypunct<char, false> Punct;
+
+            const Punct &mp = std::use_facet<Punct>(loc);
 
-            pdata->frac_digits_   = pconv->frac_digits;
+            const char           dp  = mp.decimal_point ();
+            const char           ts  = mp.thousands_sep ();
+            const std::string    grp = mp.grouping ();
+            const std::string    cur = mp.curr_symbol ();
+            const std::string    pos = mp.positive_sign ();
+            const std::string    neg = mp.negative_sign ();
+            const int            fd  = mp.frac_digits ();
+            const Punct::pattern pfm = mp.pos_format ();
+            const Punct::pattern nfm = mp.neg_format ();
+
+            pdata->decimal_point_ = dp;
+            pdata->thousands_sep_ = ts;
+            pdata->frac_digits_   = fd;
+
+            std::strcpy (pdata->grouping_, grp.c_str ());
+            std::strcpy (pdata->curr_symbol_, cur.c_str ());
+            std::strcpy (pdata->positive_sign_, pos.c_str ());
+            std::strcpy (pdata->negative_sign_, neg.c_str ());
+            std::memcpy (pdata->pos_format_, &pfm, sizeof pfm);
+            std::memcpy (pdata->neg_format_, &nfm, sizeof nfm);
+        }
+        catch (...) {
+            rw_warn (0, 0, __LINE__,
+                     "std::locale(%#s) threw an exception, skipping", name);
+            continue;
+        }
+
+        try {
+            typedef std::moneypunct<char, true> Punct;
+
+            const Punct &mp = std::use_facet<Punct>(loc);
+
+            const std::string    cur = mp.curr_symbol ();
+            const int            fd  = mp.frac_digits ();
+            const Punct::pattern pfm = mp.pos_format ();
+            const Punct::pattern nfm = mp.neg_format ();
 
-            // simply copy the narrow grouping, currency symbols,
-            // and signs
-            std::strcpy (pdata->grouping_,      pconv->mon_grouping);
-            std::strcpy (pdata->curr_symbol_,   pconv->currency_symbol);
-            std::strcpy (pdata->negative_sign_, pconv->negative_sign);
-            std::strcpy (pdata->positive_sign_, pconv->positive_sign);
-            std::strcpy (pdata->grouping_,      pconv->mon_grouping);
+            pdata->int_frac_digits_ = fd;
 
-            get_format (pdata, pconv);
+            std::strcpy (pdata->int_curr_symbol_, cur.c_str ());
+            std::memcpy (pdata->int_pos_format_, &pfm, sizeof pfm);
+            std::memcpy (pdata->int_neg_format_, &nfm, sizeof nfm);
+        }
+        catch (...) {
+            rw_warn (0, 0, __LINE__,
+                     "std::locale(%#s) threw an exception, skipping", name);
+            continue;
+        }
 
-#ifndef _RWSTD_WCHAR_T
+#ifndef _RWSTD_NO_WCHAR_T
 
-            wchar_t tmp [2];
+        try {
+            typedef std::moneypunct<wchar_t, false> Punct;
 
-            // convert multibyte decimal point and thousands separator
-            // to wide characters (assumes they are single character
-            // each -- C++ locale can't handle more)
-            std::mbstowcs (tmp, pconv->mon_decimal_point, 2);
-            pdata->wdecimal_point_ = tmp [0];
+            const Punct &mp = std::use_facet<Punct>(loc);
 
-            std::mbstowcs (tmp, pconv->mon_thousands_sep, 2);
-            pdata->wthousands_sep_ = tmp [0];
+            const wchar_t      dp  = mp.decimal_point ();
+            const wchar_t      ts  = mp.thousands_sep ();
+            const std::wstring cur = mp.curr_symbol ();
+            const std::wstring pos = mp.positive_sign ();
+            const std::wstring neg = mp.negative_sign ();
+
+            pdata->wdecimal_point_ = dp;
+            pdata->wthousands_sep_ = ts;
+
+            typedef std::wstring::traits_type Traits;
+
+            Traits::copy (pdata->wcurr_symbol_,   cur.data (), cur.size ());
+            Traits::copy (pdata->wpositive_sign_, pos.data (), pos.size ());
+            Traits::copy (pdata->wnegative_sign_, neg.data (), neg.size ());
+        }
+        catch (...) {
+            rw_warn (0, 0, __LINE__,
+                     "std::locale(%#s) threw an exception, skipping", name);
+            continue;
+        }
 
-            const std::size_t n =
-                sizeof pdata->wcurr_symbol_ / sizeof (wchar_t);
+        try {
+            typedef std::moneypunct<wchar_t, true> Punct;
 
-            std::mbstowcs (pdata->wcurr_symbol_,   pdata->curr_symbol_,   n);
-            std::mbstowcs (pdata->wnegative_sign_, pdata->negative_sign_, n);
-            std::mbstowcs (pdata->wpositive_sign_, pdata->positive_sign_, n);
+            const Punct &mp = std::use_facet<Punct>(loc);
 
-            std::mbstowcs (pdata->wint_curr_symbol_,
-                           pdata->int_curr_symbol_,
-                           n);
+            const std::wstring cur = mp.curr_symbol ();
+            const std::wstring pos = mp.positive_sign ();
+            const std::wstring neg = mp.negative_sign ();
 
-#endif   // _RWSTD_WCHAR_T
+            typedef std::wstring::traits_type Traits;
 
-            ++nlocales;
+            Traits::copy (pdata->wint_curr_symbol_, cur.data (), cur.size ());
         }
+        catch (...) {
+            rw_warn (0, 0, __LINE__,
+                     "std::locale(%#s) threw an exception, skipping", name);
+            continue;
+        }
+
+#endif   // _RWSTD_NO_WCHAR_T
+
+        ++nlocales;
 
         if (nlocales == maxinx)
             break;
     }
 
-    // reset the global locale
-    std::setlocale (LC_ALL, "C");
+    // unless the number of iterations was explicitly specified
+    // on the command line, decrease the number to equal the number
+    // of excericsed locales when only one thread is being tested
+    if (1 == rw_opt_nthreads && rw_opt_nloops < 0)
+        rw_opt_nloops = int (nlocales);
+
+    // when the number of iterations wasn't explicitly specified
+    // on the command line set it to the default value
+    if (rw_opt_nloops < 0)
+        rw_opt_nloops = DFLT_LOOPS;
+
+    rw_fatal (0 < nlocales, 0, __LINE__,
+              "must have at least one valid locale to test");
 
     rw_info (0, 0, 0,
              "testing std::moneypunct<charT> with %d thread%{?}s%{;}, "
-             "%zu iteration%{?}s%{;} each, in locales { %{ .*A@} }",
+             "%zu iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
              rw_opt_nthreads, 1 != rw_opt_nthreads,
              rw_opt_nloops, 1 != rw_opt_nloops,
-             int (nlocales), "%#s", locales);
+             nlocales, int (nlocales), "%#s", locales);
 
     rw_info (0, 0, 0, "exercising std::moneypunct<char>");
 
@@ -529,14 +464,54 @@
 
 /**************************************************************************/
 
+static int
+rw_opt_setlocales (int argc, char* argv[])
+{
+    RW_ASSERT (0 < argc && argv [0]);
+
+    rw_opt_locales = std::strchr (argv [0], '=');
+
+    if (rw_opt_locales) {
+
+        const std::size_t len = std::strlen (++rw_opt_locales);
+        char* const locale_names = new char [len + 2];
+
+        locale_names [len + 1] = '\0';
+
+        std::memcpy (locale_names, rw_opt_locales, len);
+
+        rw_opt_locales = locale_names;
+
+        for (char *next = rw_opt_locales; ; ) {
+            next = std::strpbrk (next, ", ");
+            if (next)
+                *next++ = '\0';
+            else
+                break;
+        }
+    }
+
+    return 0;
+}
+
+
 int main (int argc, char *argv[])
 {
+#ifdef _RWSTD_REENTRANT
+
+    // set nthreads to the number of processors by default
+    rw_opt_nthreads = rw_get_cpus ();
+
+#endif   // _RWSTD_REENTRANT
+
     return rw_test (argc, argv, __FILE__,
                     "lib.locale.moneypunct",
                     "thread safety", run_test,
                     "|-nloops#0 "       // must be non-negative
-                    "|-nthreads#0-*",   // must be in [0, MAX_THREADS]
+                    "|-nthreads#0-*"    // must be in [0, MAX_THREADS]
+                    "|-locales=",       // must be provided
                     &rw_opt_nloops,
                     int (MAX_THREADS),
-                    &rw_opt_nthreads);
+                    &rw_opt_nthreads,
+                    &rw_opt_setlocales);
 }