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   _Locale_impl* impl = 0;
    256 
    257   _STLP_TRY {
    258     impl = new _Locale_impl(*L._M_impl);
    259 
    260     _Locale_name_hint *hint = 0;
    261     const char* ctype_name = name;
    262     char ctype_buf[_Locale_MAX_SIMPLE_NAME];
    263     const char* numeric_name = name;
    264     char numeric_buf[_Locale_MAX_SIMPLE_NAME];
    265     const char* time_name = name;
    266     char time_buf[_Locale_MAX_SIMPLE_NAME];
    267     const char* collate_name = name;
    268     char collate_buf[_Locale_MAX_SIMPLE_NAME];
    269     const char* monetary_name = name;
    270     char monetary_buf[_Locale_MAX_SIMPLE_NAME];
    271     const char* messages_name = name;
    272     char messages_buf[_Locale_MAX_SIMPLE_NAME];
    273     if (c & locale::ctype)
    274       hint = impl->insert_ctype_facets(ctype_name, ctype_buf, hint);
    275     if (c & locale::numeric)
    276       hint = impl->insert_numeric_facets(numeric_name, numeric_buf, hint);
    277     if (c & locale::time)
    278       hint = impl->insert_time_facets(time_name, time_buf, hint);
    279     if (c & locale::collate)
    280       hint = impl->insert_collate_facets(collate_name, collate_buf, hint);
    281     if (c & locale::monetary)
    282       hint = impl->insert_monetary_facets(monetary_name, monetary_buf,hint);
    283     if (c & locale::messages)
    284       impl->insert_messages_facets(messages_name, messages_buf, hint);
    285 
    286     _Stl_loc_combine_names(impl, L._M_impl->name.c_str(),
    287                            ctype_name, time_name, numeric_name,
    288                            collate_name, monetary_name, messages_name, c);
    289     _M_impl = _get_Locale_impl( impl );
    290   }
    291   _STLP_UNWIND(delete impl)
    292 }
    293 
    294 // Contruct a new locale where all facets that aren't in category c
    295 // come from L1, and all those that are in category c come from L2.
    296 locale::locale(const locale& L1, const locale& L2, category c)
    297   : _M_impl(0) {
    298   _Locale_impl* impl = new _Locale_impl(*L1._M_impl);
    299 
    300   _Locale_impl* i2 = L2._M_impl;
    301 
    302   if (L1.name() != _Nameless && L2.name() != _Nameless)
    303     _Stl_loc_combine_names(impl, L1._M_impl->name.c_str(), L2._M_impl->name.c_str(), c);
    304   else {
    305     impl->name = _Nameless;
    306   }
    307 
    308   if (c & collate) {
    309     impl->insert( i2, _STLP_STD::collate<char>::id);
    310 # ifndef _STLP_NO_WCHAR_T
    311     impl->insert( i2, _STLP_STD::collate<wchar_t>::id);
    312 # endif
    313   }
    314   if (c & ctype) {
    315     impl->insert( i2, _STLP_STD::ctype<char>::id);
    316     impl->insert( i2, _STLP_STD::codecvt<char, char, mbstate_t>::id);
    317 # ifndef _STLP_NO_WCHAR_T
    318     impl->insert( i2, _STLP_STD::ctype<wchar_t>::id);
    319     impl->insert( i2, _STLP_STD::codecvt<wchar_t, char, mbstate_t>::id);
    320 # endif
    321   }
    322   if (c & monetary) {
    323     impl->insert( i2, _STLP_STD::moneypunct<char, true>::id);
    324     impl->insert( i2, _STLP_STD::moneypunct<char, false>::id);
    325     impl->insert( i2, _STLP_STD::money_get<char, istreambuf_iterator<char, char_traits<char> > >::id);
    326     impl->insert( i2, _STLP_STD::money_put<char, ostreambuf_iterator<char, char_traits<char> > >::id);
    327 # ifndef _STLP_NO_WCHAR_T
    328     impl->insert( i2, _STLP_STD::moneypunct<wchar_t, true>::id);
    329     impl->insert( i2, _STLP_STD::moneypunct<wchar_t, false>::id);
    330     impl->insert( i2, _STLP_STD::money_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    331     impl->insert( i2, _STLP_STD::money_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    332 # endif
    333   }
    334   if (c & numeric) {
    335     impl->insert( i2, _STLP_STD::numpunct<char>::id);
    336     impl->insert( i2, _STLP_STD::num_get<char, istreambuf_iterator<char, char_traits<char> > >::id);
    337     impl->insert( i2, _STLP_STD::num_put<char, ostreambuf_iterator<char, char_traits<char> > >::id);
    338 # ifndef _STLP_NO_WCHAR_T
    339     impl->insert( i2, _STLP_STD::numpunct<wchar_t>::id);
    340     impl->insert( i2, _STLP_STD::num_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    341     impl->insert( i2, _STLP_STD::num_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    342 # endif
    343   }
    344   if (c & time) {
    345     impl->insert( i2, _STLP_STD::time_get<char, istreambuf_iterator<char, char_traits<char> > >::id);
    346     impl->insert( i2, _STLP_STD::time_put<char, ostreambuf_iterator<char, char_traits<char> > >::id);
    347 # ifndef _STLP_NO_WCHAR_T
    348     impl->insert( i2, _STLP_STD::time_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    349     impl->insert( i2, _STLP_STD::time_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t> > >::id);
    350 # endif
    351   }
    352   if (c & messages) {
    353     impl->insert( i2, _STLP_STD::messages<char>::id);
    354 # ifndef _STLP_NO_WCHAR_T
    355     impl->insert( i2, _STLP_STD::messages<wchar_t>::id);
    356 # endif
    357   }
    358   _M_impl = _get_Locale_impl( impl );
    359 }
    360 
    361 // Destructor.
    362 locale::~locale() _STLP_NOTHROW {
    363   if (_M_impl)
    364     _release_Locale_impl(_M_impl);
    365 }
    366 
    367 // Assignment operator.  Much like the copy constructor: just a bit of
    368 // pointer twiddling.
    369 const locale& locale::operator=(const locale& L) _STLP_NOTHROW {
    370   if (this->_M_impl != L._M_impl) {
    371     if (this->_M_impl)
    372       _release_Locale_impl(this->_M_impl);
    373     this->_M_impl = _get_Locale_impl(L._M_impl);
    374   }
    375   return *this;
    376 }
    377 
    378 locale::facet* locale::_M_get_facet(const locale::id& n) const {
    379   return n._M_index < _M_impl->size() ? _M_impl->facets_vec[n._M_index] : 0;
    380 }
    381 
    382 locale::facet* locale::_M_use_facet(const locale::id& n) const {
    383   locale::facet* f = (n._M_index < _M_impl->size() ? _M_impl->facets_vec[n._M_index] : 0);
    384   if (!f)
    385     _M_impl->_M_throw_bad_cast();
    386   return f;
    387 }
    388 
    389 string locale::name() const {
    390   return _M_impl->name;
    391 }
    392 
    393 // Compare two locales for equality.
    394 bool locale::operator==(const locale& L) const {
    395   return this->_M_impl == L._M_impl ||
    396          (this->name() == L.name() && this->name() != _Nameless);
    397 }
    398 
    399 bool locale::operator!=(const locale& L) const {
    400   return !(*this == L);
    401 }
    402 
    403 // static data members.
    404 
    405 const locale& _STLP_CALL locale::classic() {
    406   return *_Stl_get_classic_locale();
    407 }
    408 
    409 #if !defined (_STLP_USE_MSVC6_MEM_T_BUG_WORKAROUND)
    410 locale _STLP_CALL locale::global(const locale& L) {
    411 #else
    412 _Locale_impl* _STLP_CALL locale::global(const locale& L) {
    413 #endif
    414   locale old(_Stl_get_global_locale()->_M_impl);
    415   if (_Stl_get_global_locale()->_M_impl != L._M_impl) {
    416     _release_Locale_impl(_Stl_get_global_locale()->_M_impl);
    417     // this assign should be atomic, should be fixed here:
    418     _Stl_get_global_locale()->_M_impl = _get_Locale_impl(L._M_impl);
    419 
    420     // Set the global C locale, if appropriate.
    421 #if !defined(_STLP_NO_LOCALE_SUPPORT)
    422     if (L.name() != _Nameless)
    423       setlocale(LC_ALL, L.name().c_str());
    424 #endif
    425   }
    426 
    427 #if !defined (_STLP_USE_MSVC6_MEM_T_BUG_WORKAROUND)
    428   return old;
    429 #else
    430   return old._M_impl;
    431 #endif
    432 }
    433 
    434 #if !defined (_STLP_STATIC_CONST_INIT_BUG) && !defined (_STLP_NO_STATIC_CONST_DEFINITION)
    435 const locale::category locale::none;
    436 const locale::category locale::collate;
    437 const locale::category locale::ctype;
    438 const locale::category locale::monetary;
    439 const locale::category locale::numeric;
    440 const locale::category locale::time;
    441 const locale::category locale::messages;
    442 const locale::category locale::all;
    443 #endif
    444 
    445 _STLP_END_NAMESPACE
    446 
    447