// locale -- class locale member functions
#include <cstdlib>
#include <istream>
#include <locale>
_STD_BEGIN

typedef char_traits<char> _Traits;
typedef istreambuf_iterator<char, _Traits> _Initer;
typedef ostreambuf_iterator<char, _Traits> _Outiter;

locale::locale(const locale& _X, const locale& _Y, category _C)
        : _Ptr(new _Locimp(*_X._Ptr))
        {       // construct a locale by copying named facets
        _Locinfo _Lobj(_X._Ptr->_Cat, _X._Ptr->_Name.c_str());
        _Locimp::_Makeloc(_Lobj._Addcats(_C & _Y._Ptr->_Cat,
                _Y._Ptr->_Name.c_str()), _C, _Ptr, &_Y);
        }

locale::locale(const char *_S, category _C)
        : _Ptr(new _Locimp)
        {       // construct a locale with named facets
        _Init();
        _Locinfo _Lobj(_C, _S);
        if (_Lobj._Getname().compare("*") == 0)
                _THROW(runtime_error, "bad locale name");
        _Locimp::_Makeloc(_Lobj, _C, _Ptr, 0);
        }

locale::locale(const locale& _X, const char *_S, category _C)
        : _Ptr(new _Locimp(*_X._Ptr))
        {       // construct a locale by copying, replacing named facets
        _Locinfo _Lobj(_C, _S);
        if (_Lobj._Getname().compare("*") == 0)
                _THROW(runtime_error, "bad locale name");
        _Locimp::_Makeloc(_Lobj._Addcats(_Ptr->_Cat,
                _Ptr->_Name.c_str()), _C, _Ptr, 0);
        }

locale& locale::_Addfac(facet *_Fac, size_t _Id, size_t _Cat)
        {       // add a facet, copying on write
        if (1 < _Ptr->_Refs)
                {_Ptr->_Decref();
                _Ptr = new _Locimp(*_Ptr); }
        _Ptr->_Addfac(_Fac, _Id);
        if (_Cat != 0)
                _Ptr->_Name = "*";
        return (*this); }

locale __cdecl locale::global(const locale& _X)
        {       // change global locale
        locale _L;
        _Lockit _Lk;
        if (_Locimp::_Global != _X._Ptr)
                {       // set new global locale
                delete _Locimp::_Global->_Decref();
                _Locimp::_Global = new _Locimp(*_X._Ptr);
                category _Cmask = _Locimp::_Global->_Cat & all;
                if (_Cmask == all)
                        setlocale(LC_ALL, _Locimp::_Global->_Name.c_str());
                else
                        for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat)
                                if ((_CATMASK(_Cat) & _Cmask) != 0)
                                        setlocale(_Cat,
                                                _Locimp::_Global->_Name.c_str());
                }
        return (_L);
        }

        // facets associated with C categories
#define ADDFAC(T, cat, pi, pl) \
        if ((_CATMASK(T::_Getcat()) & cat) == 0) \
                ; \
        else if (pl == 0) \
                pi->_Addfac(new T(_Lobj), T::id); \
        else \
                pi->_Addfac((locale::facet *)&_USE(*pl, T), T::id);

typedef ctype<char> _T1;
typedef num_get<char, _Initer> _T2;
typedef num_put<char, _Outiter> _T3;
typedef numpunct<char> _T4;

typedef codecvt<char, char, mbstate_t> _Tc1;

template<> locale::id ctype<char>::id;
template<> locale::id codecvt<char,char,int>::id;
template<> locale::id num_get<char, _Initer>::id;
template<> locale::id num_put<char, _Outiter>::id;
template<> locale::id numpunct<char>::id;

locale::_Locimp *__cdecl locale::_Locimp::_Makeloc(
        const _Locinfo& _Lobj, locale::category _C,
                _Locimp *_Pi, const locale *_Pl)
        {       // setup a new locale
        _Lockit _Lk;
        ADDFAC(_T1, _C, _Pi, _Pl);
        ADDFAC(_T2, _C, _Pi, _Pl);
        ADDFAC(_T3, _C, _Pi, _Pl);
        ADDFAC(_T4, _C, _Pi, _Pl);
        //...
        ADDFAC(_Tc1, _C, _Pi, _Pl);
        _Locimp::_Makexloc(_Lobj, _C, _Pi, _Pl);
        _Locimp::_Makewloc(_Lobj, _C, _Pi, _Pl);
        _Pi->_Cat |= _C;
        _Pi->_Name = _Lobj._Getname();
        return (_Pi);
        }

locale::_Locimp::_Locimp(const locale::_Locimp& _X)
        : locale::facet(1), _Fv(0), _Nfv(_X._Nfv),
                _Cat(_X._Cat), _Xpar(_X._Xpar), _Name(_X._Name)
        {       // construct a _Locimp from a copy
        _Lockit Lk;
        if (&_X == _Clocptr)
                _Makeloc(_Locinfo(), locale::all, this, 0);
        else
                {_Lockit _Lk;
                if (0 < _Nfv)
                        {       // copy over nonempty facet vector
                        if ((_Fv = (locale::facet **)malloc(
                                _Nfv * sizeof (locale::facet *))) == 0)
                                _Nomemory();
                        for (size_t _N = _Nfv; 0 < _N; )
                                {       // copy over facet pointers
                                locale::facet *_Pf = _X._Fv[--_N];
                                if ((_Fv[_N] = _Pf) != 0)
                                        _Pf->_Incref();
                                }
                        }
                }
        }

void locale::_Locimp::_Addfac(locale::facet *_Pf, size_t _Id)
        {       // add a facet to a locale
        _Lockit _Lk;
        const size_t _MINCAT = 32;
        if (_Nfv <= _Id)
                {       // make facet vector larger
                size_t _N = _Id + 1;
                if (_N < _MINCAT)
                        _N = _MINCAT;
                locale::facet **_Pvn = (locale::facet **)realloc(_Fv,
                        _N * sizeof (locale::facet **));
                if (_Pvn == 0)
                        _Nomemory();
                _Fv = _Pvn;
                for (; _Nfv < _N; ++_Nfv)
                        _Fv[_Nfv] = 0;
                }
        _Pf->_Incref();
        if (_Fv[_Id] != 0)
                delete _Fv[_Id]->_Decref();
        _Fv[_Id] = _Pf;
        }

_CRTIMP2 _Locinfo::_Locinfo(const char *_Name)
        {       // switch to a named locale
        _Oname = setlocale(LC_ALL, 0);
        _Nname = _Name == 0
                || (_Name = setlocale(LC_ALL, _Name)) == 0
                        ? "*" : _Name; }

_CRTIMP2 _Locinfo::_Locinfo(int _C, const char *_Name)
        {_Addcats(_C, _Name); }


_CRTIMP2 _Locinfo::~_Locinfo()
        {       // destroy a _Locinfo object, revert locale
        if (0 < _Oname.size())
                setlocale(LC_ALL, _Oname.c_str()); }

_CRTIMP2 _Locinfo& _Locinfo::_Addcats(int _C, const char *_Name)
        {       // merge in another named locale
        const char *_Lname = 0;
        if (_C == 0)
                _Lname = setlocale(LC_ALL, 0);
        else if (_C == _M_ALL)
                _Lname = setlocale(LC_ALL, _Name);
        else
                for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat)
                        if ((_CATMASK(_Cat) & _C) != 0)
                                _Lname = setlocale(_Cat, _Name);
        _Nname = _Lname != 0 ? _Lname : "*";
        return (*this); }

_STD_END

/*
 * Copyright (c) 1995 by P.J. Plauger.  ALL RIGHTS RESERVED. 
 * Consult your license regarding permissions and restrictions.
 */
