Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
facet.cpp
Go to the documentation of this file.
1
29#define _RWSTD_LIB_SRC
30
31#include <rw/_defs.h>
32
33#include <locale.h> // for LC_XXX costants
34#include <stdlib.h> // for bsearch(), getenv(), qsort()
35#include <string.h> // for memcpy(), strlen()
36
37#include <iosfwd> // for mbstate_t
38
39#include "access.h"
40#include "mman.h"
41
42#include <loc/_facet.h>
43#include <loc/_locale.h>
44#include <loc/_localedef.h>
45
46#include <rw/_mutex.h>
47
48#include "locale_body.h"
49#include "podarray.h" // for __rw_chararry
50
51
53
54// computes LC_XXX category from a numeric facet id, returns the
55// LC_XXX category for standard facets, LC_ALL for all others
56int __rw_get_cat (int);
57
58// retrieves the literal name for a given category value
59static inline
60const char* __rw_get_cat_name (int category)
61{
62 // FIXME: merge this struct and lookup with __rw_cats in rw_locale.cpp
63 // maps LC_XXX category values to their names
64 static const struct {
65 int cat; // LC_XXX category
66 const char *name; // string corresponding to LC_XXX
67 } cats [] = {
68 { _RWSTD_LC_COLLATE, "LC_COLLATE"},
69 { _RWSTD_LC_CTYPE, "LC_CTYPE"},
70 { _RWSTD_LC_MONETARY, "LC_MONETARY"},
71 { _RWSTD_LC_NUMERIC, "LC_NUMERIC"},
72 { _RWSTD_LC_TIME, "LC_TIME"}
73
74#ifdef _RWSTD_LC_MESSAGES
75 , { _RWSTD_LC_MESSAGES, "LC_MESSAGES" }
76#endif // _RWSTD_LC_MESSAGES
77 };
78
79 // find facet's category name
80 for (_RWSTD_SIZE_T i = 0; i != sizeof cats / sizeof *cats; ++i) {
81 if (category == cats [i].cat)
82 return cats [i].name;
83 }
84
85 return 0;
86}
87
88
89int __rw_facet::_C_opts = 0
90
91#ifndef _RWSTD_NO_INITIAL_CAT_SEP
92 | __rw_facet::_C_prepend_cat_sep
93#endif // _RWSTD_NO_INITIAL_CAT_SEP
94
95#ifndef _RWSTD_NO_CAT_NAMES
96 | __rw_facet::_C_use_cat_names
97#endif // _RWSTD_NO_CAT_NAMES
98
99#ifndef _RWSTD_NO_CONDENSED_NAME
100 | __rw_facet::_C_condensed_name
101#endif // _RWSTD_NO_CONDENSED_NAME
102
103 | 0;
104
105
106
107__rw_facet::__rw_facet (_RWSTD_SIZE_T __ref /* = 0 */)
108 : _C_name (0), _C_buf (0), _C_impdata (0), _C_impsize (0),
109 _C_type (_C_unknown), _C_ref (__ref), _C_pid (0 /* invalid */)
110{
111}
112
113
114__rw_facet::~__rw_facet ()
115{
116 _RWSTD_ASSERT (!_C_name && !_C_buf || _C_name && _C_buf);
117
118 static const char destroyed[] = "*** destroyed facet ***";
119
120 // (try to) detect double deletion
121 _RWSTD_ASSERT (destroyed != _C_name);
122 _RWSTD_ASSERT (_C_invalid != _C_type);
123
124 // mark invalid
125 _C_type = _C_invalid;
126
127 if (_C_name != _C_buf)
128 // MSVC requires that we cast away const before calling delete.
129 delete[] _RWSTD_CONST_CAST (char*, _C_name);
130
131 // mark destroyed
132 _C_name = destroyed;
133
134 // unmap only if both `impadata' and `impsize' are valid
135 // (derived facets may want to set `impdata' to their own,
136 // not necessarily memory mapped, data w/o setting `impsize'
137 // to something meaningful
138 if ((_RWSTD_SIZE_T)(-1) == _C_impsize)
139 ::operator delete (_RWSTD_CONST_CAST (void*, _C_impdata));
140 else if (_C_impdata && _C_impsize)
141 __rw_release_facet_data (_C_impdata, _C_impsize);
142}
143
144
145void __rw_facet::_C_set_name (const char *name, char *buf, _RWSTD_SIZE_T size)
146{
147 _RWSTD_ASSERT (0 != name);
148 _RWSTD_ASSERT (0 != buf || 0 == size);
149
150 // expected to be called only from the ctor
151 _RWSTD_ASSERT (0 == _C_name);
152 _RWSTD_ASSERT (0 == _C_buf);
153
154 _RWSTD_SIZE_T len = ::strlen (name) + 1;
155
156 char *tmp = len <= size ? buf : new char [len];
157
158 ::memcpy (tmp, name, len);
159 _C_name = tmp;
160 _C_buf = buf;
161}
162
163
164const void* __rw_facet::_C_get_data ()
165{
166 // check initialization
167 if (_C_impsize)
168 return _C_impdata;
169
170 // `pid' may be 0 if the facet has not been obtained
171 // by a call to use_facet (but instead constructed
172 // and used directly without having been installed
173 // in a locale object); in that case, locale database
174 // mapping for the facet is not available
175 if (!_C_pid)
176 return _C_impdata;
177
178 // lock the object
179 _RWSTD_MT_GUARD (&_C_mutex);
180
181 // check again for initialization
182 if (_C_impsize)
183 return _C_impdata;
184
185 __rw_chararray locname (_C_name && _C_name [0] ? _C_name : "C");
186
187 // implementation database mapping data
188 const void* pdata = 0;
189 _RWSTD_SIZE_T sz = 0;
190
191 _RWSTD_ASSERT (0 != _C_pid);
192 const int cat = __rw_get_cat (int (*_C_pid));
193
194 // use facet's id and name to determine whether the type of the facet is
195 // codecvt_byname<wchar_t, char, mbstate_t> (_C_type is not sufficiently
196 // reliable since it is set to _C_unknown for all facet objects contructed
197 // outside of the library)
198 const bool is_wcodecvt_byname =
199 _C_wcodecvt_byname == __rw_locale::_C_get_facet_type (*this);
200
201 // map the database; first try with the full name (including
202 // any modifiers) since such a database may actually exist
203 pdata = __rw_get_facet_data (cat, sz, locname.data ());
204 if (!pdata) {
205
206 // the mapping failure can be attributed to the use of a
207 // special name, eg <locale>.<codeset>@UCS-4 which calls
208 // for the stripping of the special suffix
209 _RW::__rw_chararray strip_name;
210
211 const char* pstr = strstr (locname.data (), "@UCS");
212 const size_t plen = size_t (pstr - locname.data ());
213
214 if (pstr && !pstr [4]) {
215
216 // @UCS suffix is recognized irrespective of the size of wchar_t,
217 strip_name.append (locname.data (), plen);
218 pdata = __rw_get_facet_data (cat, sz, strip_name.data ());
219 }
220 else if ( pstr && pstr [4] == '-' && !pstr [6]
221 && ( '4' == pstr [5] && sizeof (wchar_t) == 4
222 || '2' == pstr [5] && sizeof (wchar_t) == 2)) {
223
224 // @UCS-4 is only recognized where sizeof (wchar_t) == 4
225 // @UCS-2 is only recognized where sizeof (wchar_t) == 2
226 // no other modifier is recognized
227 strip_name.append (locname.data (), plen);
228 pdata = __rw_get_facet_data (cat, sz, strip_name.data ());
229 }
230
231 // if the type of the facet is codecvt_byname<wchar_t,char,mbstate_t>
232 // then the name is possibly in the format codeset | codeset@modifier
233 if (!pdata && is_wcodecvt_byname) {
234
235 pstr = pstr ? strip_name.data () : locname.data ();
236 pdata = __rw_get_facet_data (cat, sz, 0, pstr /* codeset */);
237 }
238 else
239 pstr = 0;
240
241 // this is the definitive result for facets other than
242 // codecvt_byname<wchar_t, char, mbstate_t>
243 if (!pdata) {
244 _RWSTD_ASSERT (0 == _C_impdata);
245
246 // set `impsize' to non-zero value to avoid subsequent
247 // attempts at reinitialization
248 _C_impsize = (_RWSTD_SIZE_T)-1;
249 return 0;
250 }
251
252 if (!is_wcodecvt_byname || pstr && pdata) {
253 _C_impdata = pdata;
254 _C_impsize = sz;
255 return _C_impdata;
256 }
257 }
258 else if (!is_wcodecvt_byname) {
259 _C_impdata = pdata;
260 _C_impsize = sz;
261 return _C_impdata;
262 }
263
264 // for codecvt_byname facet map the database indicated by
265 // codeset_name offset in LC_CTYPE database
266 const _RW::__rw_ctype_t* pctype =
267 _RWSTD_STATIC_CAST (const _RW::__rw_ctype_t*, pdata);
268
269 _RWSTD_ASSERT (0 != pctype);
270
271 // the facet name may be an ordinary filename or a (relative
272 // or absolute) pathname; unless it's the former, prepend
273 // the name of the directory containing the facet to the
274 // name of the codeset before trying to map it
275 __rw_chararray codeset_fname;
276 const char* codeset = pctype->codeset_name ();
277
278 const char* const slash = strrchr (locname.data (), _RWSTD_PATH_SEP);
279 if (slash) {
280 const size_t dirlen = size_t (slash - locname.data ()) + 1;
281
282 codeset_fname.assign (locname.data (), dirlen);
283 codeset_fname.append (codeset);
284 codeset = codeset_fname.data ();
285 }
286
287 // map the codecvt database
288 _C_impdata = __rw_get_facet_data (cat, _C_impsize, 0, codeset);
289
290 // unmap the LC_CTYPE database
291 __rw_munmap (pdata, sz);
292
293 return _C_impdata;
294}
295
296
297extern "C" {
298
299// compares two facets, returns 0 if equal, -1 if less, +1 otherwise
300static int cmpfacets (const void *pv1, const void *pv2)
301{
302 _RWSTD_ASSERT (0 != pv1);
303 _RWSTD_ASSERT (0 != pv2);
304
305 const __rw_facet* const pf1 =
306 *_RWSTD_STATIC_CAST (const __rw_facet* const*, pv1);
307 const __rw_facet* const pf2 =
308 *_RWSTD_STATIC_CAST (const __rw_facet* const*, pv2);
309
310 if (__rw_access::_C_get_type(*pf1) == __rw_access::_C_get_type(*pf2)) {
311 return ::strcmp (__rw_access::_C_get_name(*pf1) ?
312 __rw_access::_C_get_name(*pf1) : "C",
313 __rw_access::_C_get_name(*pf2) ?
314 __rw_access::_C_get_name(*pf2) : "C");
315 }
316
317 return __rw_access::_C_get_type(*pf2) - __rw_access::_C_get_type(*pf1);
318}
319
320
321struct __rw_facet_info
322{
323 const char *_C_name;
324 __rw_facet::_C_facet_type _C_type;
325};
326
327// compares a key to a facet, returns 0 if equal, -1 if less, +1 otherwise
328static int cmpfacet (const void *pv1, const void *pv2)
329{
330 _RWSTD_ASSERT (0 != pv1);
331 _RWSTD_ASSERT (0 != pv2);
332
333 const __rw_facet_info* const pinfo =
334 _RWSTD_STATIC_CAST (const __rw_facet_info*, pv1);
335
336 const __rw_facet* const pfacet =
337 *_RWSTD_STATIC_CAST (const __rw_facet* const*, pv2);
338
339 if (pinfo->_C_type == __rw_access::_C_get_type(*pfacet)) {
340 return ::strcmp (pinfo->_C_name ? pinfo->_C_name : "C",
341 __rw_access::_C_get_name(*pfacet) ?
342 __rw_access::_C_get_name(*pfacet) : "C");
343 }
344
345 return __rw_access::_C_get_type(*pfacet) - pinfo->_C_type;
346}
347
348} // extern "C"
349
350
351/* static */ __rw_facet*
352__rw_facet::_C_manage (__rw_facet *pfacet,
353 _C_facet_type type,
354 const char *name,
355 __rw_facet::_C_ctor_t *ctor)
356{
357 // a per-process array of facet pointers sufficiently large
358 // to hold (pointers to) all standard facets for 8 locales
359 static __rw_facet* std_facet_buf [__rw_facet::_C_last_type * 8];
360 static __rw_facet** std_facets = std_facet_buf;
361 static _RWSTD_SIZE_T n_std_facets = 0;
362 static _RWSTD_SIZE_T std_facet_bufsize =
363 sizeof std_facet_buf / sizeof *std_facet_buf;
364
365 // acquire lock
366 _RWSTD_MT_STATIC_GUARD (_RW::__rw_facet);
367
368 if (pfacet) {
369 // remove facet from the facet repository (if it is found) and
370 // destroy it (ordinary unnamed standard facets are never destroyed)
371
372 if (!name) {
373 // find facet by its name
374 name = __rw_locale::_C_get_cat_name (*pfacet);
375 }
376
377 _RWSTD_ASSERT (0 != n_std_facets);
378
379 const void *pf =
380 ::bsearch (&pfacet, std_facets, n_std_facets,
381 sizeof pfacet, &cmpfacets);
382 if (pf) {
383
384 const _RWSTD_SIZE_T inx =
385 _RWSTD_STATIC_CAST (const __rw_facet* const*, pf)
386 - _RWSTD_CONST_CAST (const __rw_facet* const*, std_facets);
387
388 pfacet = std_facets [inx];
389
390 if (0 == __rw_locale::_C_remove_ref (*pfacet)) {
391
392 static const _RWSTD_SIZE_T bufsize =
393 sizeof std_facet_buf / sizeof *std_facet_buf;
394
395 --n_std_facets;
396
397 if (n_std_facets < bufsize / 2 && std_facets != std_facet_buf) {
398
399 _RWSTD_ASSERT (inx < bufsize);
400
401 // when the number of facets in the dynamically allocated
402 // repository drops below half the capacity of the
403 // statically allocated buffer, copy facets from the
404 // former into the latter and deallocate the former
405 ::memcpy (std_facet_buf, std_facets,
406 inx * sizeof (*std_facets));
407
408 ::memcpy (std_facet_buf + inx,
409 std_facets + inx + 1,
410 (n_std_facets - inx)
411 * sizeof (*std_facets));
412
413 delete[] std_facets;
414 std_facets = std_facet_buf;
415 }
416 else {
417
418 // move facet pointers back
419 ::memmove (std_facets + inx,
420 std_facets + inx + 1,
421 (n_std_facets - inx)
422 * sizeof (*std_facets));
423 }
424
425 // delete facet unless it's one of the ordinary (unnamed)
426 // standard factes which are statically allocated
427 if (pfacet->_C_name)
428 delete pfacet;
429 }
430 }
431 else {
432
433 // facet is an ordinary (unnamed) standard facet
434 const _RWSTD_SIZE_T ref = __rw_locale::_C_remove_ref (*pfacet);
435 _RWSTD_ASSERT (ref + 1U != 0);
436 _RWSTD_UNUSED (ref);
437 }
438
439 pfacet = 0;
440 }
441 else {
442
443 // find facet in the repository or construct it if not found
444
445 const __rw_facet_info info = { name, type };
446
447 const void *pcf = ::bsearch (&info, std_facets, n_std_facets,
448 sizeof pfacet, &cmpfacet);
449
450 if (pcf) {
451 // facet already exists in the repository, bump up its ref count
452
453 void *pf = _RWSTD_CONST_CAST (void*, pcf);
454 pfacet = *_RWSTD_STATIC_CAST (__rw_facet**, pf);
455
456 _RWSTD_ASSERT (0 != pfacet);
457
458 __rw_locale::_C_add_ref (*pfacet);
459 }
460 else {
461
462 if (n_std_facets == std_facet_bufsize) {
463
464 // reallocate buffer of facet pointers
465 __rw_facet **tmp = new __rw_facet* [n_std_facets * 2];
466
467 ::memcpy (tmp, std_facets, n_std_facets * sizeof *tmp);
468
469 if (std_facets != std_facet_buf)
470 delete[] std_facets;
471
472 std_facets = tmp;
473 std_facet_bufsize *= 2;
474 }
475
476 // construct a facet with the initial reference count of 1
477 // if no such facet exists yet or bump up the facet's ref
478 // count by 1 if it does
479
480 _RWSTD_ASSERT (0 != ctor);
481
482 pfacet = ctor (1, type & 1 ? 0 : name);
483
484 _RWSTD_ASSERT (0 != pfacet);
485
486 // set the facet's numeric id
487 *__rw_access::_C_get_pid (*pfacet) =
488 _RWSTD_STATIC_CAST (_RWSTD_SIZE_T, (type + 1) / 2);
489
490 if (__rw_access::_C_get_type (*pfacet) != type) {
491 // set the type of the facet if not already set
492 __rw_access::_C_get_type (*pfacet) = type;
493 }
494
495 if (__rw_access::_C_get_ref (*pfacet) != 1) {
496 // set the refcount of the facet if 0
497
498 // the refcount is set during construction which occurs
499 // at most once in a program, but may decrease to 0 if
500 // all locales containing that facet are destroyed
501
502 _RWSTD_ASSERT (0 == __rw_access::_C_get_ref (*pfacet));
503
504 __rw_access::_C_get_ref (*pfacet) = 1;
505 }
506
507 // add facet pointer to the end of the repository
508 std_facets [n_std_facets++] = pfacet;
509
510 // sort facet pointers for fast access
511 ::qsort (std_facets, n_std_facets, sizeof pfacet, &cmpfacets);
512
513 }
514 }
515
516 return pfacet;
517}
518
519
520const void* __rw_get_facet_data (int cat, _RWSTD_SIZE_T &impsize,
521 const char* name, const char* encoding)
522{
523 if (__rw_facet::_C_use_libc == (__rw_facet::_C_opts &
524 (__rw_facet::_C_use_libc |
525 __rw_facet::_C_use_libstd))) {
526 // fail but allow further calls to this function
527 return 0;
528 }
529
530 __rw_chararray pathname;
531 const char *path;
532
533 // null name means C locale
534 const char *locname = name ? name : "C";
535
536 if ('/' == *locname) {
537 // facet name is an absolute pathname to a locale/category database
538 path = locname;
539 }
540 else {
541
542#ifndef _RWSTD_LOCALE_ROOT_ENVVAR
543# define _RWSTD_LOCALE_ROOT_ENVVAR "RWSTD_LOCALE_ROOT"
544#endif
545
546 // look up the value of the environment variable
547 const char *root = getenv (_RWSTD_LOCALE_ROOT_ENVVAR);
548
549 // use the cwd if none given
550 if (!root || !*root)
551 root = "./";
552
553 // compose the pathname of the locale/category database
554 pathname.append (root);
555 if (pathname.data () [pathname.size () - 1] != '/')
556 pathname.append ("/", 1);
557
558 // the database name for the facet will hold either the
559 // name of the category (ie LC_CTYPE, etc.) or the name
560 // of the encoding (codecvt database)
561 const char* db;
562
563 if (encoding)
564 db = encoding;
565 else {
566 // only append the locname if we are not going to be
567 // appending an encoding
568 pathname.append (locname).append ("/", 1);
569 db = __rw_get_cat_name (cat);
570 }
571 if (!db)
572 return 0;
573
574 // append database name to the end of the pathname
575 // to form a complete name of the locale/category database
576 pathname.append (db);
577 path = pathname.data ();
578 }
579
580 // map the database
581 return __rw_mmap (path, &impsize);
582}
583
584// Its counterpart - does the database unmapping
585void __rw_release_facet_data (const void* pv, _RWSTD_SIZE_T sz)
586{
587 __rw_munmap (pv, sz);
588}
589
590
591// standard facet id's (i.e., those instantiated and installed
592// by the library are in the range [1, __rw_facet::_C_last_type]
593// all others (i.e., id's of all user-defined facet types or
594// specializations of standard facets on user-defined types)
595// are in the range (__rw_facet::_C_last_type, ...)
596static _RWSTD_SIZE_T __rw_id_gen = __rw_facet::_C_last_type + 1;
597
598
599_RWSTD_SIZE_T __rw_facet_id::_C_init () const
600{
601 // return immediately if already initialized
602 if (_C_id)
603 return _C_id;
604
605 // atomically increment id generator
606 // the above initialization is already guarded and the initialization
607 // of standard facets has a chance of completing at the step above
608
609 // generate a unique id
610 const _RWSTD_SIZE_T new_id =
611 _RWSTD_ATOMIC_PREINCREMENT (__rw_id_gen, false);
612
613#ifndef _RWSTD_NO_MUTABLE
614
615 _C_id = new_id;
616
617#else // if defined (_RWSTD_NO_MUTABLE)
618
619 _RWSTD_CONST_CAST (__rw_facet_id*, this)->_C_id = new_id;
620
621#endif // _RWSTD_NO_MUTABLE
622
623 return _C_id;
624}
625
626} // namespace __rw
#define i
Definition 17.names.cpp:126
#define pf
Definition 17.names.cpp:516
#define buf
Definition 17.names.cpp:452
#define sz
Definition 17.names.cpp:550
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
#define inx
Definition 17.names.cpp:484
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define _RWSTD_ATOMIC_PREINCREMENT(x, ignore)
Definition _defs.h:699
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_MT_GUARD(ignore)
Definition _defs.h:695
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
#define _RWSTD_MT_STATIC_GUARD(name)
Definition _defs.h:696
A TOML path.
Definition path.hpp:209
const char * name
Definition codecvt1.cpp:72
#define _RWSTD_LOCALE_ROOT_ENVVAR