Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
22.locale.numpunct.cpp
Go to the documentation of this file.
1
29#include <rw/_defs.h>
30
31#if defined (__IBMCPP__) && !defined (_RWSTD_NO_IMPLICIT_INCLUSION)
32// Disable implicit inclusion to work around
33// a limitation in IBM's VisualAge 5.0.2.0 (see PR#26959)
34
35# define _RWSTD_NO_IMPLICIT_INCLUSION
36#endif
37
38
39#include <clocale> // for struct lconv, setlocale()
40#include <cstdio> // for sprintf()
41#include <cstdlib> // for getenv()
42#include <cstring> // for strcmp()
43#include <locale>
44
45#include <rw_driver.h>
46#include <rw_environ.h>
47#include <rw_locale.h>
48
49
51template <class charT>
53
54template <class charT>
55void check_decimal_point (charT, const char*, const std::locale*);
56
57template <class charT>
58void check_thousands_sep (charT, const char*, const std::locale*);
59
60template <class charT>
61void check_grouping (charT, const char*, const std::string&, const std::locale*);
62
63template <class charT>
64void check_falsename (const std::basic_string<charT>&,
65 const char*, const std::locale*);
66
67template <class charT>
68void check_truename (const std::basic_string<charT>&,
69 const char*, const std::locale*);
70
71template <class charT>
72bool check_numpunct (charT, const char*, const char*, const std::locale*);
73
74
75
77template <class charT>
78void run_test (charT, const char *tname)
79{
80 rw_info (0, 0, __LINE__, "classic \"C\" locale");
81
82 // create a copy of the classic ("C") locale
83 std::locale *loc = new std::locale (std::locale::classic ());
84
85 // verify (at compile time) that _byname facets can be used
86 // to specialize use_facet() and has_facet()
87 typedef std::numpunct_byname<charT> NumpunctByname;
88
91
92 // verify values as per 7.4 of C89, and 7.11, p2 of C99
93 check_decimal_point (charT ('.'), tname, loc);
94
95 // verify 22.2.3.1.2, p2
96 check_thousands_sep (charT (','), tname, loc);
97 check_grouping (charT (), tname, "", loc);
98
99 const charT fn[] = { 'f', 'a', 'l', 's', 'e', '\0' };
100 const charT tn[] = { 't', 'r', 'u', 'e', '\0' };
101
102 check_falsename (std::basic_string<charT>(fn), tname, loc);
103 check_truename (std::basic_string<charT>(tn), tname, loc);
104
105 delete loc;
106 loc = 0;
107
109 // verify that the facet can be safely used on its own, without
110 // first having to be installed in a locale and retrieved using
111 // use_facet
112
113 check_decimal_point (charT ('.'), tname, loc);
114 check_thousands_sep (charT (','), tname, loc);
115 check_grouping (charT (), tname, "", loc);
116
117 check_falsename (std::basic_string<charT>(fn), tname, loc);
118 check_truename (std::basic_string<charT>(tn), tname, loc);
119
121 // exercise the native locale (affected by the environment
122 // variables LANG, LC_ALL, LC_NUMERIC, etc.)
123 check_numpunct (charT (), tname, "", loc); // native locale
124
125 // the name of the first non-C (and non-POSIX) locale
126 const char *first_non_c = 0;
127
128 // exercise named locales (including "C" and "POSIX")
129 for (const char* s = rw_locales (); *s; s += std::strlen (s) + 1) {
130 if (check_numpunct (charT (), tname, s, loc))
131 if ( !first_non_c
132 && std::strcmp ("C", s)
133 && std::strcmp ("POSIX", s))
134 first_non_c = s;
135 }
136
137 // verify that numpunct behaves correctly when LC_ALL is set
138 // to the name of the (non-C, non-POSIX) locale
139 char envvar [80];
140 std::sprintf (envvar, "LC_ALL=%s", first_non_c);
141 rw_putenv (envvar);
142 check_numpunct (charT (), tname, "", loc);
143}
144
145
147char widen (char, const char *s)
148{
149 return *s;
150}
151
152#ifndef _RWSTD_NO_WCHAR_T
153
154wchar_t widen (wchar_t, const char *s)
155{
156 wchar_t wc = 0;
157
158# ifndef _RWSTD_NO_MBTOWC
159
160 const int n = s && *s ? std::mbtowc (&wc, s, std::strlen (s)) : 0;
161
162# else // if defined (_RWSTD_NO_MBTOWC)
163
164 const int n = 1;
165
166 wc = s ? wchar_t (_RWSTD_STATIC_CAST (unsigned char, *s)) : 0;
167
168# endif // _RWSTD_NO_MBTOWC
169
170 return n > 0 ? wc : n ? -1 : 0;
171}
172
173#endif // _RWSTD_NO_WCHAR_T
174
175
176template <class charT>
178 const char *tname,
179 const char *locname,
180 const std::locale *loc)
181{
182 // (try to) set the global C locale
183 const char *tmploc = std::setlocale (LC_ALL, locname);
184 if (!tmploc)
185 return false;
186
187 // future setlocale() calls may change tmploc's value, so make a copy
188 // (fixed-size char buf is clunky but avoids memory-leak potential)
189 char locnamebuf [1024];
190 RW_ASSERT ((std::strlen (tmploc) + 1) < sizeof locnamebuf);
191 std::strcpy (locnamebuf, tmploc);
192
193 _TRY {
194
195 rw_info (0, 0, __LINE__,
196 "locale (%s) -> \"%s\"; LANG=%s, "
197 "LC_ALL=%s, LC_NUMERIC=%s",
198 locname, loc,
199 std::getenv ("LANG"),
200 std::getenv ("LC_ALL"),
201 std::getenv ("LC_NUMERIC"));
202
203 // get a pointer to lconv
204 const std::lconv *plconv = std::localeconv ();
205
206 if (!plconv)
207 return false;
208
209 // copy important data; the contents of *plconv may
210 // be overwritten by the call sto setlocale() below
211 // note that decimal_point at al may be multbyte character
212 // strings that need to be widened according to the rules
213 // of the same locale
214 const charT decimal_point = widen (charT (), plconv->decimal_point);
215 const charT thousands_sep = widen (charT (), plconv->thousands_sep);
216
217 const std::string grouping =
218 plconv->grouping ? plconv->grouping : "";
219
220 // reset to default locale given by LC_LANG
221 std::setlocale (LC_ALL, "");
222
223 loc = new std::locale (locname);
224
225 // check that newly constructed locale matches
226
227 if ( ('C' == locnamebuf [0] && '\0' == locnamebuf [1])
228 || ('C' == locname [0] && '\0' == locname [1])
229 || *loc == std::locale::classic ()) {
230 // follow requirements in 22.2.3.1.2. p1, 2, and 3
231 check_decimal_point (charT ('.'), tname, loc);
232 check_thousands_sep (charT (','), tname, loc);
233
234 check_grouping (charT (), tname, "", loc);
235 }
236 else {
237 // cast to prevent sign extension between (signed) char and wchar_t
238 // tmp guards against possibly passing along a "(nil)" pointer
239 check_decimal_point (decimal_point, tname, loc);
240 check_thousands_sep (thousands_sep, tname, loc);
241 check_grouping (charT (), tname, grouping.c_str (), loc);
242 }
243
244 // FIXME: exercise falsename() and truename() in named locales
245
246 delete loc;
247 loc = 0;
248 }
249 _CATCH (...) {
250 return false;
251 }
252 return true;
253}
254
255
257template <class charT>
259 const char *tname,
260 const std::locale *loc)
261{
262 typedef std::numpunct<charT> Punct;
263 typedef std::char_traits<charT> Traits;
264
265 const charT c = loc ?
266 _STD_USE_FACET (Punct, *loc).decimal_point ()
267 : Punct ().decimal_point ();
268
269
270 rw_assert (Traits::eq (c, expect), 0, __LINE__,
271 "numpunct<%s>::decimal_point() == %{#lc}, got %{#lc}",
272 tname, expect, c);
273}
274
275
277template <class charT>
279 const char *tname,
280 const std::locale *loc)
281{
282 typedef std::numpunct<charT> Punct;
283 typedef std::char_traits<charT> Traits;
284
285 const charT c = loc ?
286 _STD_USE_FACET (Punct, *loc).thousands_sep ()
287 : Punct ().thousands_sep ();
288
289 rw_assert (Traits::eq (c, expect), 0, __LINE__,
290 "numpunct<%s>::thousands_sep() == %{#lc}, got %{#lc}",
291 tname, expect, c);
292}
293
294
296template <class charT>
298 const char *tname,
299 const std::string &expect,
300 const std::locale *loc)
301{
302 typedef std::numpunct<charT> Punct;
303
304 const std::string s = loc ?
305 _STD_USE_FACET (Punct, *loc).grouping ()
306 : Punct ().grouping ();
307
308 if ( s != expect
309 && s.size () != expect.size () && s.size () && expect.size ()) {
310
311 // if the grouping is not exactly the same as the expected result,
312 // verify that the actual grouping is equivalent to the expected
313 // one, e.g., that "\003\003" is equivalent to "\003"
314
315 const std::string *lng = s.size () > expect.size () ? &expect : &s;
316 const std::string *shrt = s.size () < expect.size () ? &expect : &s;
317
318 std::size_t i = shrt->size () - 1;
319
320 for ( ; i != lng->size (); ++i)
321 if ((*shrt) [shrt->size () - 1] != (*lng)[i])
322 break;
323
324 rw_assert (i == lng->size (), 0, __LINE__,
325 "numpunct<%s>::grouping() equivalent to %{#S}, got %{#S}",
326 tname, &expect, &s);
327 }
328 else
329 rw_assert (s == expect, 0, __LINE__,
330 "numpunct<%s>::grouping() == %{#S}, got %{#S}",
331 tname, &expect, &s);
332}
333
334
336template <class charT>
337void check_falsename (const std::basic_string<charT> &expect,
338 const char *tname,
339 const std::locale *loc)
340{
341 typedef std::numpunct<charT> Punct;
342
343 const std::basic_string<charT> s = loc ?
344 _STD_USE_FACET (Punct, *loc).falsename ()
345 : Punct ().falsename ();
346
347 const int char_size = int (sizeof (charT));
348
349 rw_assert (s == expect, 0, __LINE__,
350 "numpunct<%s>::falsename() == %{#*S}, got %{#*S}",
351 tname, char_size, &expect, char_size, &s);
352}
353
354
356template <class charT>
357void check_truename (const std::basic_string<charT> &expect,
358 const char *tname,
359 const std::locale *loc)
360{
361 typedef std::numpunct<charT> Punct;
362
363 const std::basic_string<charT> s = loc ?
364 _STD_USE_FACET (Punct, *loc).truename ()
365 : Punct ().truename ();
366
367 const int char_size = int (sizeof (charT));
368
369 rw_assert (s == expect, 0, __LINE__,
370 "numpunct<%s>::truename() == %{#*S}, got %{#*S}",
371 tname, char_size, &expect, char_size, &s);
372}
373
374
376static int
377run_test (int, char**)
378{
379 run_test (char (), "char");
380
381#ifndef _RWSTD_WCHAR_T
382
383 run_test (wchar_t (), "wchar_t");
384
385#endif // _RWSTD_WCHAR_T
386
387 return 0;
388}
389
390
392int main (int argc, char *argv[])
393{
394 return rw_test (argc, argv, __FILE__,
395 "lib.locale.numpunct",
396 "", run_test,
397 "",
398 (void*)0);
399}
#define i
Definition 17.names.cpp:126
#define loc
Definition 17.names.cpp:492
#define Traits
Definition 17.names.cpp:556
#define c
Definition 17.names.cpp:111
#define charT
Definition 17.names.cpp:456
#define s
#define n
Definition 17.names.cpp:130
std::numpunct_byname< char > NumpunctByname
void check_decimal_point(charT, const char *, const std::locale *)
void check_falsename(const std::basic_string< charT > &, const char *, const std::locale *)
void check_truename(const std::basic_string< charT > &, const char *, const std::locale *)
void run_test(charT *)
void check_grouping(charT, const char *, const std::string &, const std::locale *)
char widen(char, const char *s)
void check_thousands_sep(charT, const char *, const std::locale *)
bool check_numpunct(charT, const char *, const char *, const std::locale *)
#define main
#define LC_ALL
unsigned short wchar_t
#define _STD_HAS_FACET(type, arg)
Definition _defs.h:917
#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 _CATCH(ex)
Definition _defs.h:851
_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_putenv(const char *, int=-1)
Definition environ.cpp:69
_TEST_EXPORT char * rw_locales(int=_UNUSED_CAT, const char *=0, bool=true)
Definition locale.cpp:368
#define RW_ASSERT(expr)