locale.cpp 16 KB

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