Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 1999
      3  * Silicon Graphics Computer Systems, Inc.
      4  *
      5  * Copyright (c) 1999
      6  * Boris Fomitchev
      7  *
      8  * This material is provided "as is", with absolutely no warranty expressed
      9  * or implied. Any use is at your own risk.
     10  *
     11  * Permission to use or copy this software for any purpose is hereby granted
     12  * without fee, provided the above notices are retained on all copies.
     13  * Permission to modify the code and to distribute modified code is granted,
     14  * provided the above notices are retained, and a notice that the code was
     15  * modified is included with the above copyright notice.
     16  *
     17  */
     18 
     19 #include "stlport_prefix.h"
     20 
     21 #include <locale>
     22 #include <stdexcept>
     23 
     24 #include "c_locale.h"
     25 #include "locale_impl.h"
     26 
     27 _STLP_BEGIN_NAMESPACE
     28 
     29 #define _NAMELESS   "*"
     30 static const char _Nameless[] = _NAMELESS;
     31 
     32 static inline bool is_C_locale_name (const char* name)
     33 { return ((name[0] == 'C') && (name[1] == 0)); }
     34 
     35 locale* _Stl_get_classic_locale();
     36 locale* _Stl_get_global_locale();
     37 
     38 #if defined (_STLP_USE_MSVC6_MEM_T_BUG_WORKAROUND) || \
     39     defined (_STLP_SIGNAL_RUNTIME_COMPATIBILITY) || defined (_STLP_CHECK_RUNTIME_COMPATIBILITY)
     40 #  define locale _STLP_NO_MEM_T_NAME(loc)
     41 #endif
     42 
     43 locale::facet::~facet() {}
     44 
     45 #if !defined (_STLP_MEMBER_TEMPLATES) || defined (_STLP_INLINE_MEMBER_TEMPLATES)
     46 // members that fail to be templates
     47 bool locale::operator()(const string& __x,
     48                         const string& __y) const
     49 { return __locale_do_operator_call(*this, __x, __y); }
     50 
     51 #  if !defined (_STLP_NO_WCHAR_T)
     52 bool locale::operator()(const wstring& __x,
     53                         const wstring& __y) const
     54 { return __locale_do_operator_call(*this, __x, __y); }
     55 #  endif
     56 #endif
     57 
     58 void _STLP_CALL locale::_M_throw_on_null_name()
     59 { _STLP_THROW(runtime_error("Invalid null locale name")); }
     60 
     61 void _STLP_CALL locale::_M_throw_on_combine_error(const string& name) {
     62   string what = "Unable to find facet";
     63   what += " in ";
     64   what += name.empty() ? "system" : name.c_str();
     65   what += " locale";
     66   _STLP_THROW(runtime_error(what.c_str()));
     67 }
     68 
     69 void _STLP_CALL locale::_M_throw_on_creation_failure(int __err_code,
     70                                                      const char* name, const char* facet) {
     71   string what;
     72   switch (__err_code) {
     73     case _STLP_LOC_UNSUPPORTED_FACET_CATEGORY:
     74       what = "No platform localization support for ";
     75       what += facet;
     76       what += " facet category, unable to create facet for ";
     77       what += name[0] == 0 ? "system" : name;
     78       what += " locale";
     79       break;
     80     case _STLP_LOC_NO_PLATFORM_SUPPORT:
     81       what = "No platform localization support, unable to create ";
     82       what += name[0] == 0 ? "system" : name;
     83       what += " locale";
     84       break;
     85     default:
     86     case _STLP_LOC_UNKNOWN_NAME:
     87       what = "Unable to create facet ";
     88       what += facet;
     89       what += " from name '";
     90       what += name;
     91       what += "'";
     92       break;
     93     case _STLP_LOC_NO_MEMORY:
     94       _STLP_THROW_BAD_ALLOC;
     95       break;
     96   }
     97 
     98   _STLP_THROW(runtime_error(what.c_str()));
     99 }
    100 
    101 // Takes a reference to a locale::id, assign a numeric index if not already
    102 // affected and returns it. The returned index is always positive.
    103 static const locale::id& _Stl_loc_get_index(locale::id& id) {
    104   if (id._M_index == 0) {
    105 #if defined (_STLP_ATOMIC_INCREMENT) && !defined (_STLP_WIN95_LIKE)
    106     static _STLP_VOLATILE __stl_atomic_t _S_index = __STATIC_CAST(__stl_atomic_t, locale::id::_S_max);
    107     id._M_index = _STLP_ATOMIC_INCREMENT(&_S_index);
    108 #else
    109     static _STLP_STATIC_MUTEX _Index_lock _STLP_MUTEX_INITIALIZER;
    110     _STLP_auto_lock sentry(_Index_lock);
    111     size_t new_index = locale::id::_S_max++;
    112     id._M_index = new_index;
    113 #endif
    114   }
    115   return id;
    116 }
    117 
    118 // Default constructor: create a copy of the global locale.
    119 locale::locale() _STLP_NOTHROW
    120   : _M_impl(_get_Locale_impl(_Stl_get_global_locale()->_M_impl))
    121 {}
    122 
    123 // Copy constructor
    124 locale::locale(const locale& L) _STLP_NOTHROW
    125   : _M_impl( _get_Locale_impl( L._M_impl ) )
    126 {}
    127 
    128 void locale::_M_insert(facet* f, locale::id& n) {
    129   if (f)
    130     _M_impl->insert(f, _Stl_loc_get_index(n));
    131 }
    132 
    133 locale::locale( _Locale_impl* impl ) :
    134   _M_impl( _get_Locale_impl( impl ) )
    135 {}
    136 
    137 // Create a locale from a name.
    138 locale::locale(const char* name)
    139   : _M_impl(0) {
    140   if (!name)
    141     _M_throw_on_null_name();
    142 
    143   if (is_C_locale_name(name)) {
    144     _M_impl = _get_Locale_impl( locale::classic()._M_impl );
    145     return;
    146   }
    147 
    148   _Locale_impl* impl = 0;
    149   _STLP_TRY {
    150     impl = new _Locale_impl(locale::id::_S_max, name);
    151 
    152     // Insert categories one at a time.
    153     _Locale_name_hint *hint = 0;
    154     const char* ctype_name = name;
    155     char ctype_buf[_Locale_MAX_SIMPLE_NAME];
    156     const char* numeric_name = name;
    157     char numeric_buf[_Locale_MAX_SIMPLE_NAME];
    158     const char* time_name = name;
    159     char time_buf[_Locale_MAX_SIMPLE_NAME];
    160     const char* collate_name = name;
    161     char collate_buf[_Locale_MAX_SIMPLE_NAME];
    162     const char* monetary_name = name;
    163     char monetary_buf[_Locale_MAX_SIMPLE_NAME];
    164     const char* messages_name = name;
    165     char messages_buf[_Locale_MAX_SIMPLE_NAME];
    166     hint = impl->insert_ctype_facets(ctype_name, ctype_buf, hint);
    167     hint = impl->insert_numeric_facets(numeric_name, numeric_buf, hint);
    168     hint = impl->insert_time_facets(time_name, time_buf, hint);
    169     hint = impl->insert_collate_facets(collate_name, collate_buf, hint);
    170     hint = impl->insert_monetary_facets(monetary_name, monetary_buf, hint);
    171     impl->insert_messages_facets(messages_name, messages_buf, hint);
    172 
    173     // Try to use a normalize locale name in order to have the == operator
    174     // to behave correctly:
    175     if (strcmp(ctype_name, numeric_name) == 0 &&
    176         strcmp(ctype_name, time_name) == 0 &&
    177         strcmp(ctype_name, collate_name) == 0 &&
    178         strcmp(ctype_name, monetary_name) == 0 &&
    179         strcmp(ctype_name, messages_name) == 0) {
    180       impl->name = ctype_name;
    181     }
    182     // else we keep current name.
    183 
    184     // reassign impl
    185     _M_impl = _get_Locale_impl( impl );
    186   }
    187   _STLP_UNWIND(delete impl);
    188 }
    189 
    190 static void _Stl_loc_combine_names_aux(_Locale_impl* L,
    191                                        const char* name,
    192                                        const char* ctype_name, const char* time_name, const char* numeric_name,
    193                                        const char* collate_name, const char* monetary_name, const char* messages_name,
    194                                        locale::category c) {
    195   // This function is only called when names has been validated so using _Locale_extract_*_name
    196   // can't fail.
    197   int __err_code;
    198   char buf[_Locale_MAX_SIMPLE_NAME];
    199   L->name = string("LC_CTYPE=") + _Locale_extract_ctype_name((c & locale::ctype) ? ctype_name : name, buf, 0, &__err_code) + ";";
    200   L->name += string("LC_TIME=") + _Locale_extract_time_name((c & locale::time) ? time_name : name, buf, 0, &__err_code) + ";";
    201   L->name += string("LC_NUMERIC=") + _Locale_extract_numeric_name((c & locale::numeric) ? numeric_name : name, buf, 0, &__err_code) + ";";
    202   L->name += string("LC_COLLATE=") + _Locale_extract_collate_name((c & locale::collate) ? collate_name : name, buf, 0, &__err_code) + ";";
    203   L->name += string("LC_MONETARY=") + _Locale_extract_monetary_name((c & locale::monetary) ? monetary_name : name, buf, 0, &__err_code) + ";";
    204   L->name += string("LC_MESSAGES=") + _Locale_extract_messages_name((c & locale::messages) ? messages_name : name, buf, 0, &__err_code);
    205 }
    206 
    207 // Give L a name where all facets except those in category c
    208 // are taken from name1, and those in category c are taken from name2.
    209 static void _Stl_loc_combine_names(_Locale_impl* L,
    210                                    const char* name1, const char* name2,
    211                                    locale::category c) {
    212   if ((c & locale::all) == 0 || strcmp(name1, name1) == 0)
    213     L->name = name1;
    214   else if ((c & locale::all) == locale::all)
    215     L->name = name2;
    216   else {
    217     _Stl_loc_combine_names_aux(L, name1, name2, name2, name2, name2, name2, name2, c);
    218   }
    219 }
    220 
    221 static void _Stl_loc_combine_names(_Locale_impl* L,
    222                                    const char* name,
    223                                    const char* ctype_name, const char* time_name, const char* numeric_name,
    224                                    const char* collate_name, const char* monetary_name, const char* messages_name,
    225                                    locale::category c) {
    226   if ((c & locale::all) == 0 || (strcmp(name, ctype_name) == 0 &&
    227                                  strcmp(name, time_name) == 0 &&
    228                                  strcmp(name, numeric_name) == 0 &&
    229                                  strcmp(name, collate_name) == 0 &&
    230                                  strcmp(name, monetary_name) == 0 &&
    231                                  strcmp(name, messages_name) == 0))
    232     L->name = name;
    233   else if ((c & locale::all) == locale::all && strcmp(ctype_name, time_name) == 0 &&
    234                                                strcmp(ctype_name, numeric_name) == 0 &&
    235                                                strcmp(ctype_name, collate_name) == 0 &&
    236                                                strcmp(ctype_name, monetary_name) == 0 &&
    237                                                strcmp(ctype_name, messages_name) == 0)
    238     L->name = ctype_name;
    239   else {
    240     _Stl_loc_combine_names_aux(L, name, ctype_name, time_name, numeric_name, collate_name, monetary_name, messages_name, c);
    241   }
    242 }
    243 
    244 
    245 // Create a locale that's a copy of L, except that all of the facets
    246 // in category c are instead constructed by name.
    247 locale::locale(const locale& L, const char* name, locale::category c)
    248   : _M_impl(0) {
    249   if (!name)
    250     _M_throw_on_null_name();
    251 
    252   if (!::strcmp(_Nameless, name)) {
    253     _STLP_THROW(runtime_error("Invalid locale name '" _NAMELESS "'"));
    254   }
    255 
    256   _Locale_impl* impl = 0;
    257 
    258   _STLP_TRY {
    259     impl = new _Locale_impl(*L._M_impl);
    260 
    261     _Locale_name_hint *hint = 0;
    262     const char* ctype_name = name;
    263     char ctype_buf[_Locale_MAX_SIMPLE_NAME];
    264     const char* numeric_name = name;
    265     char numeric_buf[_Locale_MAX_SIMPLE_NAME];
    266     const char* time_name = name;
    267     char time_buf[_Locale_MAX_SIMPLE_NAME];
    268     const char* collate_name = name;
    269     char collate_buf[_Locale_MAX_SIMPLE_NAME];
    270     const char* monetary_name = name;
    271     char monetary_buf[_Locale_MAX_SIMPLE_NAME];
    272     const char* messages_name = name;
    273     char messages_buf[_Locale_MAX_SIMPLE_NAME];
    274     if (c & locale::ctype)
    275       hint = impl->insert_ctype_facets(ctype_name, ctype_buf, hint);
    276     if (c & locale::numeric)
    277       hint = impl->insert_numeric_facets(numeric_name, numeric_buf, hint);
    278     if (c & locale::time)
    279       hint = impl->insert_time_facets(time_name, time_buf, hint);
    280     if (c & locale::collate)
    281       hint = impl->insert_collate_facets(collate_name, collate_buf, hint);
    282     if (c & locale::monetary)
    283       hint = impl->insert_monetary_facets(monetary_name, monetary_buf,hint);
    284     if (c & locale::messages)
    285       impl->insert_messages_facets(messages_name, messages_buf, hint);
    286 
    287     _Stl_loc_combine_names(impl, L._M_impl->name.c_str(),
    288                            ctype_name, time_name, numeric_name,
    289                            collate_name, monetary_name, messages_name, c);
    290     _M_impl = _get_Locale_impl( impl );
    291   }
    292   _STLP_UNWIND(delete impl)
    293 }
    294 
    295 // Contruct a new locale where all facets that aren't in category c
    296 // come from L1, and all those that are in category c come from L2.
    297 locale::locale(const locale& L1, const locale& L2, category c)
    298   : _M_impl(0) {
    299   _Locale_impl* impl = new _Locale_impl(*L1._M_impl);
    300 
    301   _Locale_impl* i2 = L2._M_impl;
    302 
    303   if (L1.name() != _Nameless && L2.name() != _Nameless)
    304     _Stl_loc_combine_names(impl, L1._M_impl->name.c_str(), L2._M_impl->name.c_str(), c);
    305   else {
    306     impl->name = _Nameless;
    307   }
    308 
    309   if (c & collate) {
    310     impl->insert( i2, _STLP_STD::collate<char>::id);
    311 # ifndef _STLP_NO_WCHAR_T
    312     impl->insert( i2, _STLP_STD::collate<wchar_t>::id);
    313 # endif
    314   }
    315   if (c & ctype) {
    316     impl->insert( i2, _STLP_STD::ctype<char>::id);
    317     impl->insert( i2, _STLP_STD::codecvt<char, char, mbstate_t>::id);
    318 # ifndef _STLP_NO_WCHAR_T
    319     impl->insert( i2, _STLP_STD::ctype<wchar_t>::id);
    320     impl->insert( i2, _STLP_STD::codecvt<wchar_t, char, mbstate_t>::id);
    321 # endif
    322   }
    323   if (c & monetary) {
    324     impl->insert( i2, _STLP_STD::moneypunct<char, true>::id);
    325     impl->insert( i2, _STLP_STD::moneypunct<char, false>::id);
    326     impl->insert( i2, _STLP_STD::money_get<char, istreambuf_iterator<char, char_traits<char> > >::id);
    327     impl->insert( i2, _STLP_STD::money_put<char, ostreambuf_iterator<char, char_traits<char> > >::id);
    328 # ifndef _STLP_NO_WCHAR_T
    329     impl->insert( i2, _STLP_STD::moneypunct<wchar_t, true>::id);
    330     impl->insert( i2, _STLP_STD::moneypunct<wchar_t, false>::id);
    331     impl->insert( i2, _STLP_STD::money_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    332     impl->insert( i2, _STLP_STD::money_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    333 # endif
    334   }
    335   if (c & numeric) {
    336     impl->insert( i2, _STLP_STD::numpunct<char>::id);
    337     impl->insert( i2, _STLP_STD::num_get<char, istreambuf_iterator<char, char_traits<char> > >::id);
    338     impl->insert( i2, _STLP_STD::num_put<char, ostreambuf_iterator<char, char_traits<char> > >::id);
    339 # ifndef _STLP_NO_WCHAR_T
    340     impl->insert( i2, _STLP_STD::numpunct<wchar_t>::id);
    341     impl->insert( i2, _STLP_STD::num_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    342     impl->insert( i2, _STLP_STD::num_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    343 # endif
    344   }
    345   if (c & time) {
    346     impl->insert( i2, _STLP_STD::time_get<char, istreambuf_iterator<char, char_traits<char> > >::id);
    347     impl->insert( i2, _STLP_STD::time_put<char, ostreambuf_iterator<char, char_traits<char> > >::id);
    348 # ifndef _STLP_NO_WCHAR_T
    349     impl->insert( i2, _STLP_STD::time_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    350     impl->insert( i2, _STLP_STD::time_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    351 # endif
    352   }
    353   if (c & messages) {
    354     impl->insert( i2, _STLP_STD::messages<char>::id);
    355 # ifndef _STLP_NO_WCHAR_T
    356     impl->insert( i2, _STLP_STD::messages<wchar_t>::id);
    357 # endif
    358   }
    359   _M_impl = _get_Locale_impl( impl );
    360 }
    361 
    362 // Destructor.
    363 locale::~locale() _STLP_NOTHROW {
    364   if (_M_impl)
    365     _release_Locale_impl(_M_impl);
    366 }
    367 
    368 // Assignment operator.  Much like the copy constructor: just a bit of
    369 // pointer twiddling.
    370 const locale& locale::operator=(const locale& L) _STLP_NOTHROW {
    371   if (this->_M_impl != L._M_impl) {
    372     if (this->_M_impl)
    373       _release_Locale_impl(this->_M_impl);
    374     this->_M_impl = _get_Locale_impl(L._M_impl);
    375   }
    376   return *this;
    377 }
    378 
    379 locale::facet* locale::_M_get_facet(const locale::id& n) const {
    380   return n._M_index < _M_impl->size() ? _M_impl->facets_vec[n._M_index] : 0;
    381 }
    382 
    383 locale::facet* locale::_M_use_facet(const locale::id& n) const {
    384   locale::facet* f = (n._M_index < _M_impl->size() ? _M_impl->facets_vec[n._M_index] : 0);
    385   if (!f)
    386     _M_impl->_M_throw_bad_cast();
    387   return f;
    388 }
    389 
    390 string locale::name() const {
    391   return _M_impl->name;
    392 }
    393 
    394 // Compare two locales for equality.
    395 bool locale::operator==(const locale& L) const {
    396   return this->_M_impl == L._M_impl ||
    397          (this->name() == L.name() && this->name() != _Nameless);
    398 }
    399 
    400 bool locale::operator!=(const locale& L) const {
    401   return !(*this == L);
    402 }
    403 
    404 // static data members.
    405 
    406 const locale& _STLP_CALL locale::classic() {
    407   return *_Stl_get_classic_locale();
    408 }
    409 
    410 #if !defined (_STLP_USE_MSVC6_MEM_T_BUG_WORKAROUND)
    411 locale _STLP_CALL locale::global(const locale& L) {
    412 #else
    413 _Locale_impl* _STLP_CALL locale::global(const locale& L) {
    414 #endif
    415   locale old(_Stl_get_global_locale()->_M_impl);
    416   if (_Stl_get_global_locale()->_M_impl != L._M_impl) {
    417     _release_Locale_impl(_Stl_get_global_locale()->_M_impl);
    418     // this assign should be atomic, should be fixed here:
    419     _Stl_get_global_locale()->_M_impl = _get_Locale_impl(L._M_impl);
    420 
    421     // Set the global C locale, if appropriate.
    422 #if !defined(_STLP_NO_LOCALE_SUPPORT)
    423     if (L.name() != _Nameless)
    424       setlocale(LC_ALL, L.name().c_str());
    425 #endif
    426   }
    427 
    428 #if !defined (_STLP_USE_MSVC6_MEM_T_BUG_WORKAROUND)
    429   return old;
    430 #else
    431   return old._M_impl;
    432 #endif
    433 }
    434 
    435 #if !defined (_STLP_STATIC_CONST_INIT_BUG) && !defined (_STLP_NO_STATIC_CONST_DEFINITION)
    436 const locale::category locale::none;
    437 const locale::category locale::collate;
    438 const locale::category locale::ctype;
    439 const locale::category locale::monetary;
    440 const locale::category locale::numeric;
    441 const locale::category locale::time;
    442 const locale::category locale::messages;
    443 const locale::category locale::all;
    444 #endif
    445 
    446 _STLP_END_NAMESPACE
    447 
    448