Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
locale_body.cpp
Go to the documentation of this file.
1
32#define _RWSTD_LIB_SRC
33
34#include <rw/_defs.h>
35
36#include <new> // for placement new
37#include <locale.h>
38#include <stdio.h>
39#include <stdlib.h> // for bsearch(), qsort()
40#include <string.h> // for memxxx() and strxxx() functions
41
42#include <loc/_locale.h>
43
44#include "access.h"
45#include "locale_body.h"
46#include "setlocale.h"
47
48
49#ifdef _RWSTD_NO_LOCALE_NAME_FMAT
50
51// pick an arbitrary order for categories in locale names
52# define _RWSTD_CAT_0(pfx) \
53 { _RWSTD_LC_CTYPE, "LC_CTYPE", pfx::_C_ctype }
54# define _RWSTD_CAT_1(pfx) \
55 { _RWSTD_LC_NUMERIC, "LC_NUMERIC", pfx::_C_numeric }
56# define _RWSTD_CAT_2(pfx) \
57 { _RWSTD_LC_TIME, "LC_TIME", pfx::_C_time }
58# define _RWSTD_CAT_3(pfx) \
59 { _RWSTD_LC_COLLATE, "LC_COLLATE", pfx::_C_collate }
60# define _RWSTD_CAT_4(pfx) \
61 { _RWSTD_LC_MONETARY, "LC_MONETARY", pfx::_C_monetary }
62# define _RWSTD_CAT_5(pfx) \
63 { _RWSTD_LC_MESSAGES, "LC_MESSAGES", pfx::_C_messages }
64
65#endif // _RWSTD_NO_LOCALE_NAME_FMAT
66
67
68#if 6 == _RWSTD_HP_aCC_MAJOR && _RWSTD_HP_aCC_MINOR <= 1600
69 // silence bogus HP aCC 6.16/cadvise warning #20200-D:
70 // Potential null pointer dereference
71# pragma diag_suppress 20200
72#endif
73
74
76
77
78// maps LC_XXX category values to their names
79extern const __rw_cats_t
80__rw_cats [] = {
81
82 // expands to { LC_XXX, "LC_XXX", _RW::__rw_locale::_C_xxx }
83 // the order of these is determined at config time and corresponds to
84 // the order mixed/combined locale categories returned by setlocale()
85 _RWSTD_CAT_0 (_RW::__rw_locale),
86 _RWSTD_CAT_1 (_RW::__rw_locale),
87 _RWSTD_CAT_2 (_RW::__rw_locale),
88 _RWSTD_CAT_3 (_RW::__rw_locale),
89 _RWSTD_CAT_4 (_RW::__rw_locale),
90
91#ifdef _RWSTD_CAT_5
92 _RWSTD_CAT_5 (_RW::__rw_locale)
93#else // if !defined (_RWSTD_CAT_5)
94 // for Windoze (no LC_MESSAGES there)
95 _RWSTD_CAT_0 (_RW::__rw_locale)
96#endif // _RWSTD_CAT_5
97
98};
99
100
101// fills provided buffer (if large anough) with the names of locales
102// for each of the standard LC_XXX categories; if all categories come
103// from the same locale, copies the name of the common locale into
104// the provided buffer
105//
106// names of categories are in the following order:
107// LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES
108//
109// examples of output (assuming ';' as a separator):
110// "C"
111// all facets of all categories come from the "C" locale
112//
113// "C;C;de_DE;C;C;C;"
114// all facets come from the "C" locale except those that belong
115// to the LC_MONETARY category, which all come from "de_DE"
116//
117// "C;en_US;*;*;*;*;"
118// facets the belong to the LC_COLLATE category come from the
119// "C" locale, those belonging to the LC_CTYPE category come
120// from "en_US", all others are from mixed locales within
121// their respective categories
122//
123// "*"
124// facets belonging to each category come from all different
125// locales (e.g., ctype<char> might come from the "C" locale,
126// and ctype<wchar_t> from "ja_JP", etc.)
127
128char* __rw_locale::
129_C_get_cat_names (char *buf, size_t bufsize) const
130{
131 const size_t savesize = bufsize;
132 char *savebuf = buf;
133
134 if (!buf)
135 buf = new char [bufsize ? bufsize : (bufsize = 256)];
136
137 *buf = '\0';
138
139 // will point at the locale name common across all categories
140 // if one such name exists; otherwise at "*" (mixed locale)
141 const char *common_name = 0;
142
143 // iterate over all categories, searching for all facets that belong
144 // to that category and comparing their names. if all such facets come
145 // from the same locale, the name of the category is the name of the
146 // locale; otherwise "*"
147 for (size_t i = 0; i != __rw_n_cats; ++i) {
148
149 const char *cat_name = 0;
150
151 for (size_t j = 0; j != _C_n_std_facets; ++j) {
152
153 // verify that all facet pointers are set
154 _RWSTD_ASSERT (_C_std_facets [j]);
155
156 // ignore the non-localized {money,num}_{get,put} facets
157 // and consider only moneypunct and numpunct for the
158 // monetary category
159 switch (_C_std_facets [j]->_C_type) {
160 case __rw_facet::_C_num_get:
161 case __rw_facet::_C_wnum_get:
162 case __rw_facet::_C_num_put:
163 case __rw_facet::_C_wnum_put:
164 case __rw_facet::_C_money_get:
165 case __rw_facet::_C_wmoney_get:
166 case __rw_facet::_C_money_put:
167 case __rw_facet::_C_wmoney_put:
168 continue;
169 default:
170 break;
171 }
172
173 _RWSTD_ASSERT (0 != _C_std_facets [j]->_C_pid);
174
175 // one category at a time
176 if ( __rw_cats [i].cat
177 != __rw_get_cat (int (*_C_std_facets [j]->_C_pid)))
178 continue;
179
180 // default facet name (if 0) is "C"
181 const char *facet_name = _C_std_facets [j]->_C_name
182 ? _C_std_facets [j]->_C_name : "C";
183
184 if (cat_name && strcmp (cat_name, facet_name))
185 cat_name = "*";
186 else
187 cat_name = facet_name;
188
189 if (common_name) {
190 // if the name of the locale for this category doesn't
191 // match the common locale name so far, assign "*"
192 if (strcmp (common_name, cat_name))
193 common_name = "*";
194 }
195 else
196 common_name = cat_name;
197 }
198
199 // will be 0 iff all facets in a category are 0
200 // (i.e., an internal logic error)
201 _RWSTD_ASSERT (cat_name);
202
203 if ( strlen (buf) + strlen (cat_name) + 2
204 >= bufsize) {
205 // reallocate buffer if necessary
206 char *tmp = 0;
207
208 _TRY {
209 tmp = new char [bufsize *= 2];
210 }
211 _CATCH (...) {
212 if (buf != savebuf)
213 delete[] buf;
214 _RETHROW;
215 }
216
217 strcpy (tmp, buf);
218 if (buf != savebuf)
219 delete[] buf;
220 buf = tmp;
221 }
222
223 strcat (buf, cat_name);
224 strcat (buf, _RWSTD_CAT_SEP);
225 }
226
227 _RWSTD_ASSERT (common_name);
228
229 if (__rw_facet::_C_opts & __rw_facet::_C_condensed_name) {
230 // if all categories come from the same locale, copy the name
231 // of that locale into the buffer
232 if ('*' != common_name [0] || '\0' != common_name [1]) {
233 if ( savebuf && buf != savebuf
234 && savesize >= strlen (common_name)) {
235 // delete allocated memory and repoint at original buffer
236 delete[] buf;
237 buf = savebuf;
238 }
239 strcpy (buf, common_name);
240 }
241 }
242
243 // remove trailing separator
244 const size_t len = strlen (buf);
245 if (len && *_RWSTD_CAT_SEP == buf [len - 1])
246 buf [len - 1] = '\0';
247
248 return buf;
249}
250
251
252// returns a pointer to a character array containing locale names separated
253// by _RWSTD_CAT_SEP corresponding to the named locale (typically all the
254// names will be the same except possibly for the native locale which can
255// consist of facets from different named locales specified by the LC_XXX
256// environment variables)
257static const char*
258__rw_expand_name (__rw_chararray &namebuf, const char *name)
259{
260 const char *sep = strchr (name, *_RWSTD_CAT_SEP);
261
262 if (sep == name) {
263 // skip the first separator if it's at the beginning of `name'
264 // (e.g., SunOS locale names have the format "/en/C/ja/C/it/de")
265 sep = strchr (++name, *_RWSTD_CAT_SEP);
266 }
267
268 // true if all ctaegories are from the same locale, false otherwise
269 bool same_cats = true;
270
271 if (sep) {
272
273 // `name' contains a locale category separator; iterate over
274 // all locale categories to determine the name of the locale
275 // for each one of them
276
277 for (size_t i = 0; ; sep = strchr (name, *_RWSTD_CAT_SEP)) {
278
279 if (!sep)
280 sep = name + strlen (name);
281
282 const size_t catlen = sep - name;
283
284 // copy the read-only substring forming a locale name
285 // into a writeable buffer so that it can be NUL-terminated
286 const __rw_chararray shortname (name, catlen);
287
288 __rw_chararray longname;
289
290 // convert the (possibly abbreviated) name or a locale alias
291 // into the full name uniquely identifying the locale (e.g.,
292 // all of "de," "de_DE," and "german" can expand into the
293 // full canonical name "de_DE.ISO-8869-1"; this is necessary
294 // to guarantee that the internal locale repository doesn't
295 // contain duplicate entries)
296 const char* const fullname =
297 __rw_locale_name (__rw_cats [i].cat, shortname.data (),
298 longname);
299
300 if (!fullname)
301 return 0;
302
303 const size_t namelen = strlen (fullname);
304
305 _RWSTD_ASSERT (0 != namelen);
306
307 // determine if the new category name is the same as the first
308 // one (if it is, it is also the same as all subsequent ones,
309 // otherwise `same_cats' is already set to false)
310 if (same_cats && i)
311 same_cats = !memcmp (namebuf.data (), fullname, namelen)
312 && *_RWSTD_CAT_SEP == namebuf.data () [namelen];
313
314 namebuf.append (fullname, namelen);
315
316 if (++i == __rw_n_cats || !*sep)
317 break;
318
319 namebuf.append (_RWSTD_CAT_SEP, 1);
320
321 name = sep + 1;
322 }
323 }
324 else if ('\0' == *name) {
325
326 // no separator found, set all categories
327 const __rw_setlocale loc (name, _RWSTD_LC_ALL, 1 /* nothrow */);
328
329 if (!loc.name ())
330 return 0;
331
332 // compose a string of category names separated by CAT_SEP
333 for (size_t i = 0; ; ) {
334
335 // retrieve the name of each idividual category
336 const char* const fullname = setlocale (__rw_cats [i].cat, 0);
337
338 // call to setlocale() must succeed if `loc' succeeded
339 _RWSTD_ASSERT (0 != fullname);
340
341 const size_t namelen = strlen (fullname);
342
343 if (same_cats && i)
344 same_cats = !memcmp (namebuf.data (), fullname, namelen)
345 && *_RWSTD_CAT_SEP == namebuf.data () [namelen];
346
347 namebuf.append (fullname, namelen);
348
349 if (++i == __rw_n_cats)
350 break;
351
352 namebuf.append (_RWSTD_CAT_SEP, 1);
353 }
354 }
355
356 if (*namebuf.data ()) {
357
358 if (same_cats && __rw_facet::_C_opts & __rw_facet::_C_condensed_name) {
359
360 // all categories were the same, store just the first one
361
362 char* const data = namebuf.data ();
363 const size_t sepinx = strchr (data, *_RWSTD_CAT_SEP) - data;
364
365 // NUL-terminate at the first separator
366 namebuf.acquire (data, sepinx);
367 namebuf.append ("", 1);
368 }
369 }
370 else {
371
372 const char* const fullname =
373 __rw_locale_name (_RWSTD_LC_ALL, name, namebuf);
374
375 if (!fullname)
376 return 0;
377 }
378
379 return namebuf.data ();
380
381
382#if 0
383
384 // points to the next category name
385 const char *next = strchr (name, *_RWSTD_CAT_SEP);
386
387 if (next && *next) {
388
389 // save the end of the first name to detect combined locale
390 // names composed of categories referring to the same locale
391 char *first_end = bufbeg;
392
393 // name is a string of locale category names; compose
394 // an equivalent string obtained by concatenating the
395 // results of calling setlocale() on each
396 // substring
397
398 const char *ps = name;
399
400 size_t __i = 0;
401 do {
402 if (!next)
403 next = ps + strlen (ps);
404
405 memcpy (pbuf, ps, next - ps);
406 pbuf [next - ps] = '\0';
407
408 if (__i < __rw_n_cats) {
409
410 const int cat = __rw_cats [__i++].cat;
411
412 // get the actual locale name for each category
413 // and append it to the end of the name buffer
414 if (!__rw_locale_name (cat, pbuf, pbuf, pbuf - bufbeg))
415 return 0; // name not recognized
416 }
417
418 const size_t len = strlen (pbuf);
419
420 if (first_end == bufbeg)
421 first_end = pbuf + len;
422 else if ( first_end
423 && ( size_t (first_end - bufbeg) != len
424 || memcmp (bufbeg, pbuf, len))) {
425 // category name differs from the first (i.e., category
426 // names will be cobined) no need to check further
427 first_end = 0;
428 }
429
430 // advance to the next name
431 pbuf += len;
432 *pbuf++ = *_RWSTD_CAT_SEP;
433
434 // reached the end of the (not `sep'-terminated) list
435 if ('\0' == *next)
436 break;
437
438 ps = next + 1;
439 next = strchr (ps, *_RWSTD_CAT_SEP);
440 } while (*ps);
441
442 *pbuf = '\0';
443
444 // assume the native locale for all missing categories
445 while (__i < __rw_n_cats) {
446
447 const int cat = __rw_cats [__i++].cat;
448
449 const __rw_setlocale loc ("", cat, 1 /* nothrow */);
450
451 if (!loc.name ())
452 return 0;
453
454 const char* catname = setlocale (cat, 0);
455
456 _RWSTD_ASSERT (0 != catname);
457
458 strcat (pbuf, catname);
459
460 // compare the category name with the first one and remember
461 // if they differ (to detect all the same category names)
462 if (first_end && memcmp (bufbeg, name, first_end - name))
463 first_end = 0;
464
465 pbuf += strlen (pbuf);
466 *pbuf++ = *_RWSTD_CAT_SEP;
467 }
468
469 // remove the last separator
470 if (pbuf [-1] == *_RWSTD_CAT_SEP)
471 pbuf [-1] = '\0';
472
473 // if non-0, all categories come from the same locale
474 // keep the first name and chop off the rest
475 if ( __rw_facet::_C_opts & __rw_facet::_C_condensed_name
476 && first_end)
477 bufbeg [first_end - bufbeg] = '\0';
478 }
479 else {
480 // all categories have the same name in named locales
481
482 name = __rw_locale_name (_RWSTD_LC_ALL, name, bufbeg, bufsize);
483 if (!name)
484 return 0;
485 }
486 }
487
488 return bufbeg;
489
490#endif
491}
492
493
494size_t __rw_locale::
495_C_get_facet_inx (size_t id) const
496{
497 // verify that facet's id is initialized
498 _RWSTD_ASSERT (id);
499
500 // standard facet's id are one greater than their index
501 if (id <= _C_n_std_facets)
502 return id - 1;
503
504 _RWSTD_ASSERT (!_C_n_usr_facets || _C_usr_facets);
505
506 // linear search through user-defined facets (if any)
507 for (size_t i = 0; i != _C_n_usr_facets; ++i) {
508
509 _RWSTD_ASSERT (_C_usr_facets [i]->_C_pid);
510
511 if (*_C_usr_facets [i]->_C_pid == id)
512 return i + _C_n_std_facets;
513 }
514
515 return _RWSTD_SIZE_MAX;
516}
517
518
519__rw_locale::
520__rw_locale (const char *name)
521 : _C_usr_facets (0), _C_n_usr_facets (0), _C_ref (1),
522 _C_std_facet_bits (0), _C_byname_facet_bits (0)
523{
525
526 // verify that name doesn't refer to an unnamed (combined) locale
527 _RWSTD_ASSERT (!strchr (name, '*'));
528
529 if ('\0' == *name) {
530
531 __rw_chararray fullname;
532 fullname.acquire (_C_namebuf, 0);
533
534 // get the names of locales for all standard categories
535 // avoiding dynamic memory allocation if possible
536 _C_name = __rw_expand_name (fullname, name);
537
538 fullname.release ();
539
540 // caller must guarantee that `name' is valid
541 _RWSTD_ASSERT (0 != _C_name);
542
543 // note that `name' may not be the same as `_C_name' at this point
544 }
545 else {
546 const size_t namelen = strlen (name) + 1;
547
548 // assume name is well-formed and valid (checked by caller)
549 char* const tmp = namelen < sizeof _C_namebuf
550 ? _C_namebuf : new char [namelen];
551
552 memcpy (tmp, name, namelen);
553
554 _C_name = tmp;
555 }
556
557 // all facets are standard
558 _C_std_facet_bits = _C_all;
559
560 // byname facets determined below
561 _C_byname_facet_bits = 0;
562
563 if (strchr (_C_name, *_RWSTD_CAT_SEP)) {
564
565 // name consist of multiple locale names; iterate over them all
566 // setting byname facet bits for each named category
567 size_t inx = 0;
568
569 for (const char *nm = _C_name; *nm && inx != __rw_n_cats; ++nm) {
570
571 if ('C' != nm [0] || *_RWSTD_CAT_SEP != nm [1])
572 _C_byname_facet_bits |= __rw_cats [inx].facet_bits;
573
574 nm = strchr (nm, *_RWSTD_CAT_SEP);
575 if (!nm)
576 break;
577
578 ++inx;
579 }
580 }
581 else {
582 // all facets (except for num_{get,put}) are byname in non-C locales
583 if (!__rw_is_C (_C_name))
584 _C_byname_facet_bits = _C_all;
585 }
586
587#if defined (__i386__) || !defined (__GNUG__) || __GNUG__ < 3
588
589 memset (_C_std_facets, 0, sizeof _C_std_facets);
590
591#else // !i86 || !gcc 3.x
592
593 // Working around a gcc 3.1 optimizer bug on SPARC (and possibly
594 // other RISC architectures) where, when generating PIC, _C_std_facets
595 // ends up being 4-byte aligned and gcc replaces memset() with a series
596 // of std %o1, [_C_std_facets + i] instructions with %o1 being 0 and i
597 // being 0, 8, 16, etc. and std operating on 64-bit double words. The
598 // first such misaligned std operation causes a SIGBUS
599
600 for (size_t i = 0; i != _C_n_std_facets; ++i)
601 _C_std_facets [i] = 0;
602
603#endif // i86/gcc 3.x
604
605}
606
607
608// convert a LC_XXX constant to a locale::category value
609/* static */ int __rw_locale::
610_C_LC2category (int cat)
611{
612 switch (cat) {
613 case _RWSTD_LC_ALL: cat = __rw_cat_all; break;
614 case _RWSTD_LC_COLLATE: cat = __rw_cat_collate; break;
615 case _RWSTD_LC_CTYPE: cat = __rw_cat_ctype; break;
616 case _RWSTD_LC_MONETARY: cat = __rw_cat_monetary; break;
617 case _RWSTD_LC_NUMERIC: cat = __rw_cat_numeric; break;
618 case _RWSTD_LC_TIME: cat = __rw_cat_time; break;
619#ifdef _RWSTD_LC_MESSAGES
620 case _RWSTD_LC_MESSAGES: cat = __rw_cat_messages; break;
621#endif
622
623 default:
624 // assume `cat' is already a locale::category value
625 break;
626 }
627 return cat;
628}
629
630
631// convert a LC_XXX constant to an internal bitset of facets
632/* static */ int __rw_locale::
633_C_LC2facet_bits (int cat)
634{
635 int bits;
636
637 switch (cat) {
638 case _RWSTD_LC_ALL: bits = __rw_locale::_C_all; break;
639 case _RWSTD_LC_COLLATE: bits = __rw_locale::_C_collate; break;
640 case _RWSTD_LC_CTYPE: bits = __rw_locale::_C_ctype; break;
641 case _RWSTD_LC_MONETARY: bits = __rw_locale::_C_monetary; break;
642 case _RWSTD_LC_NUMERIC: bits = __rw_locale::_C_numeric; break;
643 case _RWSTD_LC_TIME: bits = __rw_locale::_C_time; break;
644#ifdef _RWSTD_LC_MESSAGES
645 case _RWSTD_LC_MESSAGES: bits = __rw_locale::_C_messages; break;
646#endif
647
648 default: {
649
650 // assume `cat' is a locale::category value
651 bits = 0;
652
653 if (cat & __rw_cat_collate)
654 bits |= _RW::__rw_locale::_C_collate;
655 if (cat & __rw_cat_ctype)
656 bits |= _RW::__rw_locale::_C_ctype;
657 if (cat & __rw_cat_monetary)
658 bits |= _RW::__rw_locale::_C_monetary;
659 if (cat & __rw_cat_numeric)
660 bits |= _RW::__rw_locale::_C_numeric;
661 if (cat & __rw_cat_time)
662 bits |= _RW::__rw_locale::_C_time;
663 if (cat & __rw_cat_messages)
664 bits |= _RW::__rw_locale::_C_messages;
665 break;
666 }
667
668 }
669 return bits;
670}
671
672
673__rw_locale::
674~__rw_locale ()
675{
676 // verify that object isn't being destroyed prematurely
677 _RWSTD_ASSERT (0 == _C_ref);
678
679 if (_C_name != _C_namebuf)
680 delete[] _RWSTD_CONST_CAST (char*, _C_name);
681
682 // decrement the reference count of each installed facet
683 // and delete each facet whose refcount drops to zero
684 for (size_t i = 0; i != _C_n_std_facets; ++i) {
685
686 if (!_C_std_facets [i])
687 continue;
688
689 _RWSTD_ASSERT (_C_std_facets [i]->_C_type != __rw_facet::_C_invalid);
690
691 if (_C_std_facets [i]->_C_type) {
692
693 // only standard facets (non-zero type) are managed
694 // decrement the facet's reference count and remove
695 // it from the global repository if it is 0
696 const __rw_facet* const pfacet =
697 __rw_facet::_C_manage (_C_std_facets [i],
698 _C_std_facets [i]->_C_type,
699 _C_std_facets [i]->_C_name,
700 0);
701
702 // verify that facet has been disposed of
703 _RWSTD_ASSERT (0 == pfacet);
704 _RWSTD_UNUSED (pfacet);
705 }
706 else {
707 // decrement ref count (must not drop below 0)
708 const size_t ref = _C_remove_ref (*_C_std_facets [i]);
709
710 _RWSTD_ASSERT (ref + 1U != 0);
711
712 if (0 == ref)
713 delete _C_std_facets [i];
714 }
715 }
716
717 // verify that either both are 0 or neither is 0
718 _RWSTD_ASSERT (!_C_n_usr_facets == !_C_usr_facets);
719
720 // decrement ref counts of user-defined facets and delete if necessary
721 for (size_t j = 0; j != _C_n_usr_facets; ++j) {
722
723 _RWSTD_ASSERT (_C_usr_facets [j]);
724
725 _RWSTD_ASSERT (_C_usr_facets [j]->_C_type != __rw_facet::_C_invalid);
726
727 // decrement ref count (must not drop below 0)
728 const size_t ref = _C_remove_ref (*_C_usr_facets [j]);
729
730 _RWSTD_ASSERT (ref + 1U != 0);
731
732 if (0 == ref)
733 delete _C_usr_facets [j];
734 }
735
736 delete[] _C_usr_facets;
737}
738
739
740extern "C" {
741
742// compares two locales, returns 0 if equal, -1 if less, +1 otherwise
743static int
744cmplocales (const void *pv1, const void *pv2)
745{
746 _RWSTD_ASSERT (0 != pv1);
747 _RWSTD_ASSERT (0 != pv2);
748
749 const __rw_locale* const pl1 =
750 *_RWSTD_STATIC_CAST (const __rw_locale* const*, pv1);
751 const __rw_locale* const pl2 =
752 *_RWSTD_STATIC_CAST (const __rw_locale* const*, pv2);
753
754 _RWSTD_ASSERT (0 != pl1->_C_get_name ());
755 _RWSTD_ASSERT (0 != pl1->_C_get_name ());
756
757 return strcmp (pl1->_C_get_name (), pl2->_C_get_name ());
758}
759
760
761// compares a key to a locale, returns 0 if equal, -1 if less, +1 otherwise
762static int
763cmplocale (const void *pv1, const void *pv2)
764{
765 _RWSTD_ASSERT (0 != pv1);
766 _RWSTD_ASSERT (0 != pv2);
767
768 const char* const nm1 = _RWSTD_STATIC_CAST (const char*, pv1);
769
770 const __rw_locale* const plocale =
771 *_RWSTD_STATIC_CAST (const __rw_locale* const*, pv2);
772
773 _RWSTD_ASSERT (0 != nm1);
774 _RWSTD_ASSERT (0 != plocale->_C_get_name ());
775
776 return strcmp (nm1, plocale->_C_get_name ());
777}
778
779} // extern "C"
780
781
782// manages a global, per-process repository of locale bodies according
783// to the following table:
784
785// plocale locname algorithm
786// 0 0 retrieve the global locale
787// 0 non-0 find named locale in repository and increment
788// its ref count if found, or construct it with
789// ref count of 1 and add it otherwise
790// non-0 0 make `plocale' the new global locale and
791// return the previous global locale
792// non-0 non-0 find locale in repository, decrement its ref
793// count, and remove it if the ref count is 0
794
795/* static */ __rw_locale*
796__rw_locale::
797_C_manage (__rw_locale *plocale, const char *locname)
798{
799 // a per-process array of locale body pointers
800 static __rw_locale* locale_buf [8];
801 static __rw_locale** locales = locale_buf;
802 static __rw_locale* classic = 0;
803 static size_t n_locales = 0;
804 static size_t locale_bufsize =
805 sizeof locale_buf / sizeof *locale_buf;
806
807 if (!locname) {
808
809 // manage the global locale
810
811 static __rw_locale* global = 0;
812
813 if (!global) {
814
815 // volatile to prevent optimizers from turning
816 // the while statement below into an infinite loop
817 static volatile int ginit /* = 0 */;
818
819 // cast ginit to int& (STDCXX-792)
820 // casting should be removed after fixing STDCXX-794
821 if (!ginit && 1 == _RWSTD_ATOMIC_PREINCREMENT (
822 _RWSTD_CONST_CAST (int&, ginit), false)) {
823 global = _C_manage (0, "C");
824 ginit += 1000;
825 }
826 else {
827 // ginit must be volatile to prevent optimizers
828 // from turning this into an infinite loop
829 while (ginit < 1000) { /* empty */ }
830 }
831 }
832
833 // re-entrant
834 _RWSTD_MT_STATIC_GUARD (_RW::__rw_locale);
835
836 __rw_locale* const tmp = global;
837
838 _RWSTD_ASSERT (0 != tmp);
839
840 if (plocale) {
841 // replace the global locale with `plocale'
842
843 // increment the future global locale's ref count first
844 _RWSTD_ATOMIC_PREINCREMENT (plocale->_C_ref, false);
845
846 // and then set the global locale
847 global = plocale;
848 }
849 else {
850
851 // retrieve the global locale
852
853 // always increment a ref count, even if `global' is being set
854 // (and its ref count is > 0), to prevent its ref count from
855 // dropping to 0
856 _RWSTD_ATOMIC_PREINCREMENT (tmp->_C_ref, false);
857 }
858
859 return tmp;
860 }
861
862
863 // re-entrant to protect static local data structures
864 // (not the locales themselves)
865 _RWSTD_MT_STATIC_GUARD (_RW::__rw_locale);
866
867 // determine whether `locname' refers to the classic C locale
868 // (e.g., it could be any of "C", "POSIX", "C C C C C C", etc.)
869 bool is_C_locale = __rw_is_C (locname);
870
871 // substitute the fully expanded libc name for the classic C locale,
872 // i.e., the result of calling std::setlocale ("C")
873 if (is_C_locale)
874 locname = __rw_C_locale_name;
875
876 __rw_chararray fullname;
877
878 if (!plocale && !is_C_locale) {
879 // to avoid unnecessary calls to setlocale() only get cat names
880 // when composing a locale name, otherwise the locale name is
881 // assumed to be correct and complete
882 locname = __rw_expand_name (fullname, locname);
883
884 if (!locname)
885 return 0; // program error
886
887 is_C_locale = __rw_is_C (locname);
888
889 if (is_C_locale)
890 locname = __rw_C_locale_name;
891 }
892
893 if (plocale) {
894 // remove locale from the locale repository (if it is found) and
895 // destroy it (the classic C locale is never destroyed)
896
897 _RWSTD_ASSERT (0 != n_locales);
898
899 const void* const pl =
900 bsearch (locname, locales, n_locales, sizeof *locales, &cmplocale);
901 if (pl) {
902
903 const size_t inx =
904 _RWSTD_STATIC_CAST (const __rw_locale* const*, pl)
905 - _RWSTD_CONST_CAST (const __rw_locale* const*, locales);
906
907 plocale = locales [inx];
908
909 const size_t ref =
910 _RWSTD_ATOMIC_PREDECREMENT (plocale->_C_ref, false);
911
912 _RWSTD_ASSERT (_RWSTD_SIZE_MAX != ref);
913
914 if (0 == ref) {
915
916 static const size_t bufsize =
917 sizeof locale_buf / sizeof *locale_buf;
918
919 --n_locales;
920
921 if (n_locales < bufsize / 2 && locales != locale_buf) {
922
923 _RWSTD_ASSERT (inx < bufsize);
924
925 // when the number of locales in the dynamically
926 // allocated repository drops below half the capacity
927 // of the statically allocated buffer, copy locales
928 // from the former into the latter and deallocate the
929 // former
930 memcpy (locale_buf, locales, inx * sizeof (*locales));
931
932 memcpy (locale_buf + inx, locales + inx + 1,
933 (n_locales - inx) * sizeof (*locales));
934
935 delete[] locales;
936
937 // point at the statically allocated buffer and reset
938 // the current capacity to the original capacity
939 locales = locale_buf;
940 locale_bufsize = bufsize;
941 }
942 else {
943 // move facet pointers back
944 memmove (locales + inx, locales + inx + 1,
945 (n_locales - inx) * sizeof (*locales));
946 }
947
948 _RWSTD_ASSERT (0 != plocale->_C_name);
949
950 // only named locales (i.e., other than the C locale)
951 // are deleted
952 if (!__rw_is_C (plocale->_C_name))
953 delete plocale;
954 }
955 }
956 else {
957
958 // object is the classic C locale which is never destroyed
959 _RWSTD_ASSERT (plocale->_C_name);
960 _RWSTD_ASSERT (__rw_is_C (plocale->_C_name));
961
962 const size_t ref =
963 _RWSTD_ATOMIC_PREDECREMENT (plocale->_C_ref, false);
964
965 _RWSTD_ASSERT (ref + 1U != 0);
966 _RWSTD_UNUSED (ref);
967 }
968
969 plocale = 0;
970 }
971 else {
972
973 // find locale in the repository or construct it if not found
974
975 const void* const pcl =
976 bsearch (locname, locales, n_locales, sizeof *locales, &cmplocale);
977
978 if (pcl) {
979 // facet already exists in the repository, bump up its ref count
980
981 void* const pl = _RWSTD_CONST_CAST (void*, pcl);
982
983 plocale = *_RWSTD_STATIC_CAST (__rw_locale**, pl);
984
985 _RWSTD_ASSERT (0 != plocale);
986
987 _RWSTD_ATOMIC_PREINCREMENT (plocale->_C_ref, false);
988 }
989 else {
990
991 if (n_locales == locale_bufsize) {
992
993 // reallocate buffer of facet pointers
994 __rw_locale** const tmp =
995 new __rw_locale* [n_locales * 2];
996
997 memcpy (tmp, locales, n_locales * sizeof *tmp);
998
999 if (locales != locale_buf)
1000 delete[] locales;
1001
1002 locales = tmp;
1003 locale_bufsize *= 2;
1004 }
1005
1006 if (__rw_is_C (locname)) {
1007
1008 if (!classic) {
1009
1010 // the classic C locale is statically allocated
1011 // and not destroyed during the lifetime of the process
1012 static union {
1013 void* _C_align;
1014 char _C_buf [sizeof (__rw_locale)];
1015 } classic_body;
1016
1017 // construct a locale body in place
1018 // with the initial reference count of 1
1019 classic = new (&classic_body) __rw_locale (locname);
1020
1021 _RWSTD_ASSERT (1 == classic->_C_ref);
1022 }
1023 else {
1024 _RWSTD_ASSERT (0 != classic);
1025
1026 _RWSTD_ATOMIC_PREINCREMENT (classic->_C_ref, false);
1027 }
1028
1029 plocale = classic;
1030 }
1031 else {
1032 plocale = new __rw_locale (locname);
1033
1034 _RWSTD_ASSERT (1 == plocale->_C_ref);
1035 }
1036
1037 _RWSTD_ASSERT (plocale);
1038
1039 // add locale body pointer to the end of the repository
1040 locales [n_locales++] = plocale;
1041
1042 // sort pointers for fast access
1043 qsort (locales, n_locales, sizeof *locales, &cmplocales);
1044 }
1045 }
1046
1047 return plocale;
1048}
1049
1050
1051// returns true iff all the facets in the given locale category
1052// installed in `*this' are being globally managed by the library
1053// if (cat == locale::none) holds, returns true iff the entire
1054// locale body is being managed
1055bool __rw_locale::
1056_C_is_managed (int cat) const
1057{
1058 // `cat' must be a valid category
1059 _RWSTD_ASSERT (_C_check_category (_C_LC2category (cat)));
1060
1061 if (cat == __rw_cat_none) {
1062
1063 // locales containing any user-defined facets are not globally managed
1064 if (_C_n_usr_facets) {
1065 _RWSTD_ASSERT (0 != _C_usr_facets);
1066 return false;
1067 }
1068
1069 // unless all facets in the same category come either from
1070 // the C locale or from some named locale the locale object
1071 // containing the facets is not managed (this test doesn't
1072 // detect categores of all byname facets not all of which
1073 // belong to the same named locale)
1074 if ( (_C_std_facet_bits & _C_all) != _C_all
1075 || (_C_byname_facet_bits & _C_collate)
1076 && (_C_byname_facet_bits & _C_collate) != _C_collate
1077 || (_C_byname_facet_bits & _C_ctype)
1078 && (_C_byname_facet_bits & _C_ctype) != _C_ctype
1079 || (_C_byname_facet_bits & _C_monetary)
1080 && (_C_byname_facet_bits & _C_monetary) != _C_monetary
1081 || (_C_byname_facet_bits & _C_numeric)
1082 && (_C_byname_facet_bits & _C_numeric) != _C_numeric
1083 || (_C_byname_facet_bits & _C_time)
1084 && (_C_byname_facet_bits & _C_time) != _C_time
1085 || (_C_byname_facet_bits & _C_messages)
1086 && (_C_byname_facet_bits & _C_messages) != _C_messages)
1087 return false;
1088
1089 // check whether all _byname facets in each category belong
1090 // to the same named locale; facets witout byname forms are
1091 // excluded from this test
1092 // note that the locale may have a combined name such as
1093 // "/de/en/fr/it/ja/ru"
1094 const char* locname = _C_name ? _C_name : "C";
1095
1096 if (*_RWSTD_CAT_SEP == *locname)
1097 ++locname;
1098
1099 // find the first category separator (if any) and compute
1100 // the length of the name of the first category's locale
1101 // (don't bother when combined locales don't exist, i.e.,
1102 // when no locale separator is defined)
1103 const char* next =
1104 *_RWSTD_CAT_SEP ? strchr (locname, *_RWSTD_CAT_SEP) : 0;
1105
1106 size_t loclen = next ? next - locname : strlen (locname);
1107
1108 // iterate over all standard facets, comparing the name of the
1109 // locale each comes from with the name of the category encoded
1110 // in the locale name for equality; a mismatch indicates that
1111 // the locale is not managed
1112 for (size_t i = 0, catinx = 0; i != _C_n_std_facets; ++i) {
1113
1114 if (0 == _C_std_facets [i]) {
1115 // skip facets that are not installed
1116 continue;
1117 }
1118
1119 const __rw_facet::_C_facet_type facet_type =
1120 _C_get_facet_type (*_C_std_facets [i]);
1121
1122 switch (facet_type) {
1123 case __rw_facet::_C_money_get:
1124 case __rw_facet::_C_money_put:
1125 case __rw_facet::_C_num_get:
1126 case __rw_facet::_C_num_put:
1127 case __rw_facet::_C_wmoney_get:
1128 case __rw_facet::_C_wmoney_put:
1129 case __rw_facet::_C_wnum_get:
1130 case __rw_facet::_C_wnum_put:
1131 // skip facets with no _byname forms
1132 continue;
1133 default:
1134 break;
1135 }
1136
1137 // iterate through the names of categories in the combined
1138 // locale name looking for one that the facet belongs to
1139 while (next && !(__rw_cats [catinx].facet_bits & (1 << i))) {
1140
1141 if (*next) {
1142 // advance past the category separator to the name
1143 // of the next category in the (potentially combined)
1144 // locale name
1145 _RWSTD_ASSERT (*next == *_RWSTD_CAT_SEP);
1146
1147 locname = ++next;
1148 ++catinx;
1149 }
1150 else {
1151 // reset to the name of the first category
1152 locname = _C_name ? _C_name : "C";
1153 catinx = 0;
1154 }
1155
1156 // skip over the category separator
1157 if (*_RWSTD_CAT_SEP == *locname)
1158 ++locname;
1159
1160 next = strchr (locname, *_RWSTD_CAT_SEP);
1161 if (next)
1162 loclen = next - locname;
1163 else {
1164 loclen = strlen (locname);
1165 next = "";
1166 }
1167 }
1168
1169 // get the facet name (or "C" if null)
1170 const char* const facet_name =
1171 _C_std_facets [i]->_C_get_name ();
1172
1173 _RWSTD_ASSERT (0 != facet_name);
1174 _RWSTD_ASSERT (0 != locname);
1175
1176 // mismatch indicates a combined category
1177 if ( strlen (facet_name) != loclen
1178 || memcmp (locname, facet_name, loclen)) {
1179 // locales with heterogeneous categories are not managed
1180 return false;
1181 }
1182 }
1183
1184 // locales with all heterogeneous categories are managed
1185 return true;
1186 }
1187
1188 // in order for the entire category to be considered globally managed,
1189 // all its facets must come from the same (named or unnamed) locale
1190 // i.e., if the LC_CTYPE category contains codecvt from "de_DE" and
1191 // ctype from "en_US", the category is not considered globally managed
1192 // because it doesn't have a unambiguous name
1193 const int bits = _C_LC2facet_bits (cat);
1194
1195 const int std_bits = bits & int (_C_std_facet_bits);
1196
1197 if (std_bits ? bits == std_bits
1198 : bits == (bits & int (_C_byname_facet_bits)))
1199 return true;
1200
1201 return false;
1202}
1203
1204
1205} // namespace __rw
1206
1207
1208
1211#include <memory>
1212#include <loc/_locale.h>
1213
1214#include <rw/_defs.h>
1215
1216
1218
1219
1220const locale&
1221locale::
1222operator= (const locale &rhs) _THROWS (())
1223{
1224 // copy body and bump up a ref count in `rhs'
1225 _RW::__rw_locale* const body = rhs._C_body;
1226
1227 _RWSTD_ATOMIC_PREINCREMENT (rhs._C_body->_C_ref, false);
1228
1229
1230 // _C_body is never 0 except in objects still being constructed by
1231 // the combining ctor locale::locale<Facet>(const locale&, Facet*)
1232
1233 if (_C_body) {
1234 // dispose of old body (dtor decrements ref count and possibly deletes)
1235 locale destroy (*_C_body);
1236
1237 _RWSTD_UNUSED (destroy);
1238 }
1239
1240 // assign new body
1241 _C_body = body;
1242
1243 return *this;
1244}
1245
1246
1247} // namespace std
#define i
Definition 17.names.cpp:126
#define rhs
Definition 17.names.cpp:536
#define loc
Definition 17.names.cpp:492
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
#define inx
Definition 17.names.cpp:484
const char *const data[]
#define _THROWS()
#define _RWSTD_ATOMIC_PREINCREMENT(x, ignore)
Definition _defs.h:699
#define _RETHROW
Definition _defs.h:853
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _TRY
Definition _defs.h:850
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_ATOMIC_PREDECREMENT(x, ignore)
Definition _defs.h:700
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _CATCH(ex)
Definition _defs.h:851
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
#define _RWSTD_MT_STATIC_GUARD(name)
Definition _defs.h:696
const struct @19 locales[]
const char * name
Definition codecvt1.cpp:72
#define _RWSTD_CAT_SEP
Definition json.h:5363
#define true
Definition stdbool.h:25