-
-// Copyright (C) 1997-1999 Free Software Foundation, Inc.
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
+#include <clocale>
+#include <cstring>
+#include <locale>
-#include <bits/std_clocale.h>
-#include <bits/std_locale.h>
-#include <bits/std_cstring.h>
-#include <bits/std_cassert.h>
-#include <bits/std_vector.h>
-
-namespace std {
-
-/////////////////////////////
-// locale::_Impl constructors
-/////////////////////////////
-
- // construct specific categories, leaving unselected ones alone
- //////////
- locale::_Impl::_Impl(const _Impl& other,const string& name, category cats,
- size_t refs)
- : _M_num_references(refs)
- // , _M_facets(other._M_facets)
- // , _M_category_names(other._M_category_names)
- , _M_has_name(other._M_has_name), _M_cached_name_ok(false)
- {
-#if 1
- typedef vector<facet*, allocator<facet*> > __vec_facet;
- typedef vector<string, allocator<string> > __vec_string;
- try {
- _M_facets = new __vec_facet(*(other._M_facets));
- }
- catch (...) {
- delete _M_facets;
- throw;
- }
- try {
- _M_category_names = new __vec_string(*(other._M_category_names));
- }
- catch (...) {
- delete _M_category_names;
- throw;
- }
-#endif
- // XXX Nathan what are you doing here? Is this supposed to be const?
- // static void(_Impl::* const ctors[]) (const char*) =
- static void(_Impl::* ctors[]) (const char*) =
- {
- // NB: order must match the decl order in class locale.
- &locale::_Impl::_M_construct_collate,
- &locale::_Impl::_M_construct_ctype,
- &locale::_Impl::_M_construct_monetary,
- &locale::_Impl::_M_construct_numeric,
- &locale::_Impl::_M_construct_time,
- &locale::_Impl::_M_construct_messages,
- 0
- };
-
- _S_initialize();
- std::vector<facet*>::iterator it = _M_facets->begin();
- for (; it != _M_facets->end(); ++it)
- (*it)->_M_add_reference();
-
- try {
- category classix = _S_normalize_category(cats); // might throw
- _M_normalize_category_names(name, classix);
-
- unsigned mask = (locale::all & -(unsigned)locale::all);
- for (unsigned ix = 0; (-mask & cats) != 0; ++ix, (mask <<= 1))
- {
- if (!(mask & cats))
- continue;
-
- if (mask & classix)
- _M_replace_category(_S_classic, _S_facet_categories[ix]);
- else
- (this->*ctors[ix]) (name.c_str());
- }
- }
- catch (...) {
- it = _M_facets->begin();
- for (; it != _M_facets->end(); ++it)
- (*it)->_M_remove_reference();
- throw;
- }
- }
+namespace std
+{
+ using namespace __gnu_cxx;
- //////////
- locale::category
- locale::_Impl::_M_normalize_category_names(const string&,
- locale::category cats)
+
+ locale::locale(const char* __s)
{
-
- // The problem to be solved here is that locale names
- // generally have one of two forms: they might have
- // only one component, such as "en_US"; or they might
- // have six, such as "en_US fr_FR en_US C C C", where
- // each component names a category. Each vendor has
- // a different order of categories. Each vendor uses
- // a different format:
- // AIX uses "C C C C C C"
- // Sun uses "/C/C/C/C/C/C"
- // HP uses "/0:C;1:C;2:C;3:C;4:C;5:C;6:C;/"
- // (where the 0th element is for LC_ALL.)
- // Most systems (except AIX) permit the long form only for
- // setlocale(LC_ALL,...), and require the short form for
- // other calls. All this matters because locale names are
- // supposed to be compatible between locale("") and
- // setlocale(..., "") constructors.
-
- return cats;
-#if 0 /* XXX not done */
- unsigned mask = (locale::all & -(unsigned)locale::all);
- for (unsigned ix = 0; (-mask & cats) != 0; ++ix, (mask <<= 1))
+ if (__s)
{
+ _S_initialize();
+ if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0)
+ (_M_impl = _S_classic)->_M_add_reference();
+ else if (std::strcmp(__s, "") != 0)
+ _M_impl = new _Impl(__s, 1);
+ else
+ {
+ // Get it from the environment.
+ char* __env = std::getenv("LC_ALL");
+ // If LC_ALL is set we are done.
+ if (__env && std::strcmp(__env, "") != 0)
+ {
+ if (std::strcmp(__env, "C") == 0
+ || std::strcmp(__env, "POSIX") == 0)
+ (_M_impl = _S_classic)->_M_add_reference();
+ else
+ _M_impl = new _Impl(__env, 1);
+ }
+ else
+ {
+ // LANG may set a default different from "C".
+ string __res;
+ char* __env = std::getenv("LANG");
+ if (!__env || std::strcmp(__env, "") == 0
+ || std::strcmp(__env, "C") == 0
+ || std::strcmp(__env, "POSIX") == 0)
+ __res = "C";
+ else
+ __res = __env;
+
+ // Scan the categories looking for the first one
+ // different from LANG.
+ size_t __i = 0;
+ if (__res == "C")
+ for (; __i < _S_categories_size; ++__i)
+ {
+ __env = std::getenv(_S_categories[__i]);
+ if (__env && std::strcmp(__env, "") != 0
+ && std::strcmp(__env, "C") != 0
+ && std::strcmp(__env, "POSIX") != 0)
+ break;
+ }
+ else
+ for (; __i < _S_categories_size; ++__i)
+ {
+ __env = std::getenv(_S_categories[__i]);
+ if (__env && std::strcmp(__env, "") != 0
+ && __res != __env)
+ break;
+ }
+ // If one is found, build the complete string of
+ // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on...
+ if (__i < _S_categories_size)
+ {
+ string __str;
+ for (size_t __j = 0; __j < __i; ++__j)
+ {
+ __str += _S_categories[__j];
+ __str += '=';
+ __str += __res;
+ __str += ';';
+ }
+ __str += _S_categories[__i];
+ __str += '=';
+ __str += __env;
+ __str += ';';
+ __i++;
+ for (; __i < _S_categories_size; ++__i)
+ {
+ __env = std::getenv(_S_categories[__i]);
+ if (!__env || std::strcmp(__env, "") == 0)
+ {
+ __str += _S_categories[__i];
+ __str += '=';
+ __str += __res;
+ __str += ';';
+ }
+ else if (std::strcmp(__env, "C") == 0
+ || std::strcmp(__env, "POSIX") == 0)
+ {
+ __str += _S_categories[__i];
+ __str += "=C;";
+ }
+ else
+ {
+ __str += _S_categories[__i];
+ __str += '=';
+ __str += __env;
+ __str += ';';
+ }
+ }
+ __str.erase(__str.end() - 1);
+ _M_impl = new _Impl(__str.c_str(), 1);
+ }
+ // ... otherwise either an additional instance of
+ // the "C" locale or LANG.
+ else if (__res == "C")
+ (_M_impl = _S_classic)->_M_add_reference();
+ else
+ _M_impl = new _Impl(__res.c_str(), 1);
+ }
+ }
}
-#endif
+ else
+ __throw_runtime_error(__N("locale::locale NULL not valid"));
}
- //////////
- void
- locale::_Impl::_M_construct_collate(const char* /*name*/)
- {
-#if 0
- _M_init_facet(new std::collate_byname<char>(name));
- _M_init_facet(new std::collate_byname<wchar_t>(name));
-#endif
+ locale::locale(const locale& __base, const char* __s, category __cat)
+ {
+ // NB: There are complicated, yet more efficient ways to do
+ // this. Building up locales on a per-category way is tedious, so
+ // let's do it this way until people complain.
+ locale __add(__s);
+ _M_coalesce(__base, __add, __cat);
}
- void
- locale::_Impl::_M_construct_ctype(const char* /*name*/)
- {
-#if 0
- _M_init_facet(new std::ctype_byname<char>(name));
- _M_init_facet(new std::ctype_byname<wchar_t>(name));
- _M_init_facet(new std::codecvt_byname<char,char,mbstate_t>(name));
- _M_init_facet(new std::codecvt_byname<wchar_t,char,mbstate_t>(name));
-#endif
- }
-
- void
- locale::_Impl::_M_construct_monetary(const char* /*name*/)
- {
-#if 0
- _M_init_facet(new std::moneypunct_byname<char,false>(name));
- _M_init_facet(new std::moneypunct_byname<wchar_t,false>(name));
- _M_init_facet(new std::moneypunct_byname<char,true >(name));
- _M_init_facet(new std::moneypunct_byname<wchar_t,true >(name));
+ locale::locale(const locale& __base, const locale& __add, category __cat)
+ { _M_coalesce(__base, __add, __cat); }
- locale::_M_initialize();
- _M_replace_facet(locale::_S_classic, &std::money_get<char>(name)::id);
- _M_replace_facet(locale::_S_classic, &std::money_get<wchar_t>(name)::id);
- _M_replace_facet(locale::_S_classic, &std::money_put<char>(name)::id);
- _M_replace_facet(locale::_S_classic, &std::money_put<wchar_t>(name)::id);
-#endif
- }
-
- void
- locale::_Impl::_M_construct_numeric(const char* /*name*/)
+ void
+ locale::_M_coalesce(const locale& __base, const locale& __add,
+ category __cat)
{
-#if 0
- _M_init_facet(new std::numpunct_byname<char>(name));
- _M_init_facet(new std::numpunct_byname<wchar_t>(name));
+ __cat = _S_normalize_category(__cat);
+ _M_impl = new _Impl(*__base._M_impl, 1);
- locale::_M_initialize();
- _M_replace_facet(locale::_S_classic, &std::num_get<char>::id);
- _M_replace_facet(locale::_S_classic, &std::num_get<wchar_t>::id);
- _M_replace_facet(locale::_S_classic, &std::num_put<char>::id);
- _M_replace_facet(locale::_S_classic, &std::num_put<wchar_t>::id);
-#endif
- }
-
- void
- locale::_Impl::_M_construct_time(const char* /*name*/)
- {
-#if 0
- _M_init_facet(new std::time_get_byname<char>(name));
- _M_init_facet(new std::time_get_byname<wchar_t>(name));
- _M_init_facet(new std::time_put_byname<char>(name));
- _M_init_facet(new std::time_put_byname<wchar_t>(name));
-#endif
- }
-
- void
- locale::_Impl::_M_construct_messages(const char* /*name*/)
- {
-#if 0
- _M_init_facet(new std::messages_byname<char>(name));
- _M_init_facet(new std::messages_byname<wchar_t>(name));
-#endif
+ try
+ { _M_impl->_M_replace_categories(__add._M_impl, __cat); }
+ catch (...)
+ {
+ _M_impl->_M_remove_reference();
+ __throw_exception_again;
+ }
}
- //////////////////////
- // locale constructors
- //////////////////////
-
- ////////
- locale::locale(const char* std_name)
+ // Construct named _Impl.
+ locale::_Impl::
+ _Impl(const char* __s, size_t __refs)
+ : _M_refcount(__refs), _M_facets_size(_GLIBCXX_NUM_FACETS)
{
- _S_initialize();
- if (strcmp(std_name, "C") == 0 || strcmp(std_name, "POSIX"))
- (_M_impl = _S_classic)->_M_add_reference();
- else
+ // Initialize the underlying locale model, which also checks to
+ // see if the given name is valid.
+ __c_locale __cloc;
+ locale::facet::_S_create_c_locale(__cloc, __s);
+
+ _M_facets = _M_caches = 0;
+ _M_names = 0;
+ try
{
- // might throw:
- _M_impl = new _Impl(*_S_classic, string(std_name), all, 1);
- _M_impl->_M_has_name = true;
+ _M_facets = new const facet*[_M_facets_size];
+ for (size_t __i = 0; __i < _M_facets_size; ++__i)
+ _M_facets[__i] = 0;
+ _M_caches = new const facet*[_M_facets_size];
+ for (size_t __i = 0; __i < _M_facets_size; ++__i)
+ _M_caches[__i] = 0;
+ _M_names = new char*[_S_categories_size];
+ for (size_t __i = 0; __i < _S_categories_size; ++__i)
+ _M_names[__i] = 0;
+
+ // Name all the categories.
+ const size_t __len = std::strlen(__s);
+ if (!std::strchr(__s, ';'))
+ {
+ for (size_t __i = 0; __i < _S_categories_size; ++__i)
+ {
+ _M_names[__i] = new char[__len + 1];
+ std::strcpy(_M_names[__i], __s);
+ }
+ }
+ else
+ {
+ const char* __beg = __s;
+ for (size_t __i = 0; __i < _S_categories_size; ++__i)
+ {
+ __beg = std::strchr(__beg, '=') + 1;
+ const char* __end = std::strchr(__beg, ';');
+ if (!__end)
+ __end = __s + __len;
+ char* __new = new char[__end - __beg + 1];
+ std::memcpy(__new, __beg, __end - __beg);
+ __new[__end - __beg] = '\0';
+ _M_names[__i] = __new;
+ }
+ }
+
+ // Construct all standard facets and add them to _M_facets.
+ _M_init_facet(new std::ctype<char>(__cloc, 0, false));
+ _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc));
+ _M_init_facet(new numpunct<char>(__cloc));
+ _M_init_facet(new num_get<char>);
+ _M_init_facet(new num_put<char>);
+ _M_init_facet(new std::collate<char>(__cloc));
+ _M_init_facet(new moneypunct<char, false>(__cloc, __s));
+ _M_init_facet(new moneypunct<char, true>(__cloc, __s));
+ _M_init_facet(new money_get<char>);
+ _M_init_facet(new money_put<char>);
+ _M_init_facet(new __timepunct<char>(__cloc, __s));
+ _M_init_facet(new time_get<char>);
+ _M_init_facet(new time_put<char>);
+ _M_init_facet(new std::messages<char>(__cloc, __s));
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ _M_init_facet(new std::ctype<wchar_t>(__cloc));
+ _M_init_facet(new codecvt<wchar_t, char, mbstate_t>(__cloc));
+ _M_init_facet(new numpunct<wchar_t>(__cloc));
+ _M_init_facet(new num_get<wchar_t>);
+ _M_init_facet(new num_put<wchar_t>);
+ _M_init_facet(new std::collate<wchar_t>(__cloc));
+ _M_init_facet(new moneypunct<wchar_t, false>(__cloc, __s));
+ _M_init_facet(new moneypunct<wchar_t, true>(__cloc, __s));
+ _M_init_facet(new money_get<wchar_t>);
+ _M_init_facet(new money_put<wchar_t>);
+ _M_init_facet(new __timepunct<wchar_t>(__cloc, __s));
+ _M_init_facet(new time_get<wchar_t>);
+ _M_init_facet(new time_put<wchar_t>);
+ _M_init_facet(new std::messages<wchar_t>(__cloc, __s));
+#endif
+ locale::facet::_S_destroy_c_locale(__cloc);
}
+ catch(...)
+ {
+ locale::facet::_S_destroy_c_locale(__cloc);
+ this->~_Impl();
+ __throw_exception_again;
+ }
}
- /////////
- locale::locale(const locale& other, const char* std_name, category cats)
- : _M_impl(new _Impl(*other._M_impl, string(std_name),
- _S_normalize_category(cats), 1)) // might throw
- { }
-
- ///////
- bool
- locale::operator==(const locale& __rhs) const throw()
+ void
+ locale::_Impl::
+ _M_replace_categories(const _Impl* __imp, category __cat)
{
- return(_M_impl == __rhs._M_impl
- || (this->name() != "*" && this->name() == __rhs.name()));
+ for (size_t __ix = 0; __ix < _S_categories_size; ++__ix)
+ {
+ const category __mask = 1 << __ix;
+ if (__mask & __cat)
+ {
+ // Need to replace entry in _M_facets with other locale's info.
+ _M_replace_category(__imp, _S_facet_categories[__ix]);
+ // If both have names, go ahead and mangle.
+ if (std::strcmp(_M_names[__ix], "*") != 0
+ && std::strcmp(__imp->_M_names[__ix], "*") != 0)
+ {
+ char* __new = new char[std::strlen(__imp->_M_names[__ix]) + 1];
+ std::strcpy(__new, __imp->_M_names[__ix]);
+ delete [] _M_names[__ix];
+ _M_names[__ix] = __new;
+ }
+ }
+ }
}
-
-}
+} // namespace std