/*  Metrowerks Standard Library  Version 4.0  1998 August 10  */

/*  $Date:: 6/18/98 12:29 PM                                 $ 
 *  $Revision:: 12                                           $ 
 *  $NoKeywords: $ 
 *
 *		Portions Copyright © 1995-1998 Metrowerks, Inc.
 *		All rights reserved.
 */

/**
 **  locale.cpp
 **
 **  Lib++  : The Modena C++ Standard Library,
 **           Version 2.5, April 1998
 **
 **  Copyright (c) 1995-1997 Modena Software Inc.
 **/

#include <ios>
#include <streambuf>
#include <locale>
#include <stdexcept>
#include <typeinfo>

#ifdef _MSL_USING_NAMESPACE
	namespace std {
#endif

size_t locale::id::id_count_s = 0;

_RefCountedPtr<locale::imp> locale::global_s;

locale::locale() throw()
	: imp_(global_s)
{
	if (imp_ == 0)
		imp_ = classic().imp_;
}

locale::locale(const locale& other) throw()
	: imp_(other.imp_)
{
}

locale::locale(const char* std_name)
{
	imp_ = classic().imp_;
	if (std_name == 0)
		throw runtime_error(string("locale constructed with null name"));
	string name(std_name);
	if (name != "" && name != "C")
		throw runtime_error(string("locale constructed with unsupported name: ") + name);
	if (name != "C")
	{
		make_unique();
		imp_->name() = name;
	}
}

locale::locale(const locale& other, const char* std_name, category cat)
{
	imp_ = locale(other, locale(std_name), cat).imp_;
}

#ifndef MSIPL_MEMBER_TEMPLATE
	#define MAKE_LOCALE(MyFacet)                              \
		locale::locale(const locale& other, MyFacet* f)       \
		{                                                     \
			if (f == 0)                                       \
				imp_ = other.imp_;                            \
			else {                                            \
				imp_ = new imp(*other.imp_);                  \
				imp_->replace(*f);                            \
				imp_->name() = "*";                           \
			}                                                 \
		}

	MAKE_LOCALE(_STD::collate<char>)
	MAKE_LOCALE(_STD::ctype<char>)
	typedef _STD::codecvt<char, char, mbstate_t> __codecvt1;
	MAKE_LOCALE(__codecvt1)
	MAKE_LOCALE(_STD::numpunct<char>)
	MAKE_LOCALE(_STD::num_get<char>)
	MAKE_LOCALE(_STD::num_put<char>)
	MAKE_LOCALE(_STD::timepunct<char>)
	MAKE_LOCALE(_STD::time_get<char>)
	MAKE_LOCALE(_STD::time_put<char>)
	MAKE_LOCALE(_STD::moneypunct<char>)
	typedef _STD::moneypunct<char, true> __moneypunct1;
	MAKE_LOCALE(__moneypunct1)
	MAKE_LOCALE(_STD::money_get<char>)
	MAKE_LOCALE(_STD::money_put<char>)
	#ifdef MSIPL_WCHART
		MAKE_LOCALE(_STD::collate<wchar_t>)
		MAKE_LOCALE(_STD::ctype<wchar_t>)
		typedef _STD::codecvt<wchar_t, char, mbstate_t> __codecvt2;
		MAKE_LOCALE(__codecvt2)
		MAKE_LOCALE(_STD::numpunct<wchar_t>)
		MAKE_LOCALE(_STD::num_get<wchar_t>)
		MAKE_LOCALE(_STD::num_put<wchar_t>)
		MAKE_LOCALE(_STD::timepunct<wchar_t>)
		MAKE_LOCALE(_STD::time_get<wchar_t>)
		MAKE_LOCALE(_STD::time_put<wchar_t>)
		MAKE_LOCALE(_STD::moneypunct<wchar_t>)
		typedef _STD::moneypunct<wchar_t, true> __moneypunct2;
		MAKE_LOCALE(__moneypunct2)
		MAKE_LOCALE(_STD::money_get<wchar_t>)
		MAKE_LOCALE(_STD::money_put<wchar_t>)
	#endif

	#undef MAKE_LOCALE
#endif

locale::locale(const locale& other, const locale& one, category cat)
{
	imp_ = new imp(*other.imp_);
	if (cat & collate)
	{
		imp_->replace(use_facet<_STD::collate<char> >(one));
		#ifdef MSIPL_WCHART
			imp_->replace(use_facet<_STD::collate<wchar_t> >(one));
		#endif
	}
	if (cat & ctype)
	{
		imp_->replace(use_facet<_STD::ctype<char> >(one));
		imp_->replace(use_facet<_STD::codecvt<char, char, mbstate_t> >(one));
		#ifdef MSIPL_WCHART
			imp_->replace(use_facet<_STD::ctype<wchar_t> >(one));
			imp_->replace(use_facet<_STD::codecvt<wchar_t, char, mbstate_t> >(one));
		#endif
	}
	if (cat & monetary)
	{
		imp_->replace(use_facet<_STD::moneypunct<char> >(one));
		imp_->replace(use_facet<_STD::moneypunct<char, true> >(one));
		imp_->replace(use_facet<_STD::money_get<char> >(one));
		imp_->replace(use_facet<_STD::money_put<char> >(one));
		#ifdef MSIPL_WCHART
			imp_->replace(use_facet<_STD::moneypunct<wchar_t> >(one));
			imp_->replace(use_facet<_STD::moneypunct<wchar_t, true> >(one));
			imp_->replace(use_facet<_STD::money_get<wchar_t> >(one));
			imp_->replace(use_facet<_STD::money_put<wchar_t> >(one));
		#endif
	}
	if (cat & numeric)
	{
		imp_->replace(use_facet<_STD::numpunct<char> >(one));
		imp_->replace(use_facet<_STD::num_get<char> >(one));
		imp_->replace(use_facet<_STD::num_put<char> >(one));
		#ifdef MSIPL_WCHART
			imp_->replace(use_facet<_STD::numpunct<wchar_t> >(one));
			imp_->replace(use_facet<_STD::num_get<wchar_t> >(one));
			imp_->replace(use_facet<_STD::num_put<wchar_t> >(one));
		#endif
	}
	if (cat & time)
	{
		imp_->replace(use_facet<_STD::timepunct<char> >(one));
		imp_->replace(use_facet<_STD::time_get<char> >(one));
		imp_->replace(use_facet<_STD::time_put<char> >(one));
		#ifdef MSIPL_WCHART
			imp_->replace(use_facet<_STD::timepunct<wchar_t> >(one));
			imp_->replace(use_facet<_STD::time_get<wchar_t> >(one));
			imp_->replace(use_facet<_STD::time_put<wchar_t> >(one));
		#endif
	}
	if (other.name() != "*")
		imp_->name() = other.name();
	else
		imp_->name() = one.name();
}

locale::~locale() throw()
{
}

const locale&
locale::operator=(const locale& other) throw()
{
	imp_ = other.imp_;
	return *this;
}

basic_string<char>
locale::name() const
{
	return imp_->name();
}

#ifndef MSIPL_MEMBER_TEMPLATE
	bool
	locale::operator()(const basic_string<char>& s1,
	                   const basic_string<char>& s2) const
	{
		return use_facet<_STD::collate<char> >(*this).compare(
			s1.data(), s1.data()+s1.size(), s2.data(), s2.data()+s2.size()
		) < 0;
	}

	#ifdef MSIPL_WCHART
		bool
		locale::operator()(const basic_string<wchar_t>& s1,
		                   const basic_string<wchar_t>& s2) const
		{
			return use_facet<_STD::collate<wchar_t> >(*this).compare(
				s1.data(), s1.data()+s1.size(), s2.data(), s2.data()+s2.size()
			) < 0;
		}
	#endif
#endif

locale
locale::global(const locale& loc)
{
	_RefCountedPtr<imp> result = global_s;
	if (result == 0)
		result = classic().imp_;
	global_s = loc.imp_;
	if (loc.name() != "*")
		setlocale(LC_ALL, loc.name().c_str());
	return locale(result);
}

const locale&
locale::classic()
{
	static locale C = make_classic();
	return C;
}

locale::locale(const _RefCountedPtr<imp>& i)
	: imp_(i)
{
}

locale
locale::make_classic()
{
	_RefCountedPtr<imp> result = new imp(26);
	result->replace(*(new _STD::collate<char>()));
	result->replace(*(new _STD::ctype<char>()));
	result->replace(*(new _STD::codecvt<char, char, mbstate_t>()));
	result->replace(*(new _STD::numpunct<char>()));
	result->replace(*(new _STD::num_get<char>()));
	result->replace(*(new _STD::num_put<char>()));
	result->replace(*(new _STD::timepunct<char>()));
	result->replace(*(new _STD::time_get<char>()));
	result->replace(*(new _STD::time_put<char>()));
	result->replace(*(new _STD::moneypunct<char>()));
	result->replace(*(new _STD::moneypunct<char, true>()));
	result->replace(*(new _STD::money_get<char>()));
	result->replace(*(new _STD::money_put<char>()));
	#ifdef MSIPL_WCHART
		result->replace(*(new _STD::collate<wchar_t>()));
		result->replace(*(new _STD::ctype<wchar_t>()));
		result->replace(*(new _STD::codecvt<wchar_t, char, mbstate_t>()));
		result->replace(*(new _STD::numpunct<wchar_t>()));
		result->replace(*(new _STD::num_get<wchar_t>()));
		result->replace(*(new _STD::num_put<wchar_t>()));
		result->replace(*(new _STD::timepunct<wchar_t>()));
		result->replace(*(new _STD::time_get<wchar_t>()));
		result->replace(*(new _STD::time_put<wchar_t>()));
		result->replace(*(new _STD::moneypunct<wchar_t>()));
		result->replace(*(new _STD::moneypunct<wchar_t, true>()));
		result->replace(*(new _STD::money_get<wchar_t>()));
		result->replace(*(new _STD::money_put<wchar_t>()));
	#endif
	result->name() = "C";
	return locale(result);
}

// locale::imp

locale::imp::imp(size_t size)
	: facets_(size),
	name_("*")
{
}

locale::imp::imp(const imp& rhs)
	: facets_(rhs.facets_),
	name_(rhs.name_)
{
	size_t end = facets_.size();
	for (size_t i = 0; i < end; ++i)
	{
		facet* p = facets_[i];
		if (p != 0)
			p->add_ref();
	}
}

locale::imp::~imp()
{
	size_t end = facets_.size();
	for (size_t i = 0; i < end; ++i)
	{
		facet* p = facets_[i];
		if (p != 0)
			delete static_cast<locale::facet*>(p->rem_ref());
	}
}

locale::imp&
locale::imp::operator =(const imp& rhs)
{
	if (this != &rhs)
	{
		size_t end = facets_.size();
		for (size_t i = 0; i < end; ++i)
		{
			facet* p = facets_[i];
			if (p != 0)
				delete static_cast<locale::facet*>(p->rem_ref());
		}
		facets_ = rhs.facets_;
		end = facets_.size();
		{  // hh 980816 ARM/Standard neutral for-scoping
		for (size_t i = 0; i < end; ++i)
		{
			facet* p = facets_[i];
			if (p != 0)
				p->add_ref();
		}
		}
		name_ = rhs.name_;
	}
	return *this;
}

#ifndef MSIPL_MEMBER_TEMPLATE
	#define MAKE_REPLACE(MyFacet)                                      \
		void                                                           \
		locale::imp::replace(const MyFacet& f)                         \
		{                                                              \
			size_t id = f.id.get();                                    \
			if (id >= facets_.size())                                  \
				facets_.resize(id+1);                                  \
			facet*& p = facets_[id];                                   \
			if (p != 0)                                                \
				delete static_cast<locale::facet*>(p->rem_ref());      \
			p = f.add_ref();                                           \
		}

	MAKE_REPLACE(_STD::collate<char>)
	MAKE_REPLACE(_STD::ctype<char>)
	typedef _STD::codecvt<char, char, mbstate_t> __codecvt1;
	MAKE_REPLACE(__codecvt1)
	MAKE_REPLACE(_STD::numpunct<char>)
	MAKE_REPLACE(_STD::num_get<char>)
	MAKE_REPLACE(_STD::num_put<char>)
	MAKE_REPLACE(_STD::timepunct<char>)
	MAKE_REPLACE(_STD::time_get<char>)
	MAKE_REPLACE(_STD::time_put<char>)
	MAKE_REPLACE(_STD::moneypunct<char>)
	typedef _STD::moneypunct<char, true> __moneypunct1;
	MAKE_REPLACE(__moneypunct1)
	MAKE_REPLACE(_STD::money_get<char>)
	MAKE_REPLACE(_STD::money_put<char>)
	#ifdef MSIPL_WCHART
		MAKE_REPLACE(_STD::collate<wchar_t>)
		MAKE_REPLACE(_STD::ctype<wchar_t>)
		typedef _STD::codecvt<wchar_t, char, mbstate_t> __codecvt2;
		MAKE_REPLACE(__codecvt2)
		MAKE_REPLACE(_STD::numpunct<wchar_t>)
		MAKE_REPLACE(_STD::num_get<wchar_t>)
		MAKE_REPLACE(_STD::num_put<wchar_t>)
		MAKE_REPLACE(_STD::timepunct<wchar_t>)
		MAKE_REPLACE(_STD::time_get<wchar_t>)
		MAKE_REPLACE(_STD::time_put<wchar_t>)
		MAKE_REPLACE(_STD::moneypunct<wchar_t>)
		typedef _STD::moneypunct<wchar_t, true> __moneypunct2;
		MAKE_REPLACE(__moneypunct2)
		MAKE_REPLACE(_STD::money_get<wchar_t>)
		MAKE_REPLACE(_STD::money_put<wchar_t>)
	#endif

	#undef MAKE_REPLACE
#endif

#ifdef MSIPL_WCHART

	// ctype<wchar_t>

	template<>
	locale::id ctype<wchar_t>::id;

	// hh 980803 added.  non-standard
	template<>
	basic_string<wchar_t>
	ctype<wchar_t>::widen(const basic_string<char>& s) const
	{
		basic_string<wchar_t> result;
		result.resize(s.size());
		const char* s0 = s.c_str();
		widen(s0, s0 + s.size(), &result[0]);
		return result;
	}

	template<>
	const wchar_t*
	ctype<wchar_t>::do_is(const wchar_t* low, const wchar_t* high, mask* vec) const
	{
		const wchar_t* p;
		for (p = low; p < high; ++p)
			vec[p-low] = classify(*p);
		return high;
	}

	template<>
	const wchar_t*
	ctype<wchar_t>::do_scan_is(mask m, const wchar_t* low, const wchar_t* high) const
	{
		const wchar_t* p;
		for (p = low; p < high; ++p)
			if (classify(*p) & m)
				break;
		return p;
	}

	template<>
	const wchar_t*
	ctype<wchar_t>::do_scan_not(mask m, const wchar_t* low, const wchar_t* high) const
	{
		const wchar_t* p;
		for (p = low; p < high; ++p)
			if (!(classify(*p) & m))
				break;
		return p;
	}

	template<>
	const wchar_t*
	ctype<wchar_t>::do_toupper(wchar_t* low, const wchar_t* high) const
	{
		for (;low < high; ++low)
			*low = towupper(*low);
		return high;
	}

	template<>
	const wchar_t*
	ctype<wchar_t>::do_tolower(wchar_t* low, const wchar_t* high) const
	{
		for (;low < high; ++low)
			*low = towlower(*low);
		return high;
	}

	template<>
	const char*
	ctype<wchar_t>::do_widen(const char* low, const char* high, wchar_t* dest) const
	{
		while (low < high)
			*dest++ = wchar_t(*low++);
		return high;
	}

	template<>
	const wchar_t*
	ctype<wchar_t>::do_narrow(const wchar_t* low, const wchar_t* high, char dfault, char* dest) const
	{
		while (low < high)
			*dest++ = do_narrow(*low++, dfault);
		return high;
	}

	template<>
	ctype_base::mask
	ctype<wchar_t>::classify(wchar_t c) const
	{
		mask m = mask(0);
		if (iswspace(c))
			m |= space;
		if (iswprint(c))
			m |= print;
		if (iswcntrl(c))
			m |= cntrl;
		if (iswupper(c))
			m |= upper;
		if (iswlower(c))
			m |= lower;
		if (iswalpha(c))
			m |= alpha;
		if (iswdigit(c))
			m |= digit;
		if (iswpunct(c))
			m |= punct;
		if (iswxdigit(c))
			m |= xdigit;
		return m;
	}

#endif

// ctype<char>

#define ctrl	ctype_base::mask(__control_char)
#define motn	ctype_base::mask(__motion_char)
#define spac	ctype_base::mask(__space_char)
#define punc	ctype_base::mask(__punctuation)
#define digi	ctype_base::mask(__digit)
#define hexd	ctype_base::mask(__hex_digit)
#define lowc	ctype_base::mask(__lower_case)
#define uppc	ctype_base::mask(__upper_case)
#define dhex    ctype_base::mask(__hex_digit | __digit)  // hh 980811
#define uhex    ctype_base::mask(__hex_digit | __upper_case)
#define lhex    ctype_base::mask(__hex_digit | __lower_case)

ctype_base::mask __mask_map[ctype<char>::table_size] = {
	ctrl, ctrl, ctrl, ctrl, ctrl, ctrl, ctrl, ctrl,
	ctrl, motn, motn, motn, motn, motn, ctrl, ctrl,
	ctrl, ctrl, ctrl, ctrl, ctrl, ctrl, ctrl, ctrl,
	ctrl, ctrl, ctrl, ctrl, ctrl, ctrl, ctrl, ctrl,
	spac, punc, punc, punc, punc, punc, punc, punc,
	punc, punc, punc, punc, punc, punc, punc, punc,
	dhex, dhex, dhex, dhex, dhex, dhex, dhex, dhex,
	dhex, dhex, punc, punc, punc, punc, punc, punc,
	punc, uhex, uhex, uhex, uhex, uhex, uhex, uppc,
	uppc, uppc, uppc, uppc, uppc, uppc, uppc, uppc,
	uppc, uppc, uppc, uppc, uppc, uppc, uppc, uppc,
	uppc, uppc, uppc, punc, punc, punc, punc, punc,
	punc, lhex, lhex, lhex, lhex, lhex, lhex, lowc,
	lowc, lowc, lowc, lowc, lowc, lowc, lowc, lowc,
	lowc, lowc, lowc, lowc, lowc, lowc, lowc, lowc,
	lowc, lowc, lowc, punc, punc, punc, punc, ctrl
};

template <>
ctype<char>::ctype(const mask* tab, bool del, size_t refs)
	: locale::facet(refs),
	table_(tab),
	owns_(del)
{
	if (table_ == 0)
	{
		table_ = classic_table();
		owns_ = false;
	}
}

template <>
inline
ctype<char>::~ctype()
{
	if (owns_)
		delete [] table_;
}

template<>
const char*
ctype<char>::is(const char* low, const char* high, mask* vec) const
{
	for (const char* p = low; p < high; ++low)
		vec[p-low] = table_[(unsigned char)*p];
	return high;
}

template<>
const char*
ctype<char>::scan_is(mask m, const char* low, const char* high) const
{
	const char* p;
	for (p = low; p < high; ++p)
		if (table_[(unsigned char)*p] & m)
			break;
	return p;
}

template<>
const char*
ctype<char>::scan_not(mask m, const char* low, const char* high) const
{
	const char* p;
	for (p = low; p < high; ++p)
		if (!(table_[(unsigned char)*p] & m))
			break;
	return p;
}

template<>
locale::id ctype<char>::id;

template<>
const char*
ctype<char>::do_toupper(char* low, const char* high) const
{
	for (;low < high; ++low)
		*low = char(_STD::toupper(*low));
	return high;
}

template<>
const char*
ctype<char>::do_tolower(char* low, const char* high) const
{
	for (;low < high; ++low)
		*low = char(_STD::tolower(*low));
	return high;
}

// ctype_byname<char>

template<>
ctype_byname<char>::ctype_byname(const char* name, size_t refs)
	: ctype(0, false, refs),
	loc_(name),
	facet_(use_facet<ctype<char> >(loc_))
{
}

// codecvt<char, char, mbstate_t>

template <>
codecvt<char, char, mbstate_t>::codecvt(size_t refs)
	: _Generic_codecvt(refs)
{
}

template <>
locale::id codecvt<char, char, mbstate_t>::id;

template <>
codecvt_base::result
codecvt<char, char, mbstate_t>::do_nothing(
	const char* from, const char* from_end, const char*& from_next,
	char* to, char* to_limit, char*& to_next) const
{
	size_t len = size_t(from_end - from);
	size_t temp = size_t(to_limit - to);
	result r = noconv;
	if (len > temp)
		len = temp;
	from_next = from;
	to_next = to;
	memcpy(to, from, len);
	return r;
}

#ifdef MSIPL_WCHART

	// codecvt<wchar_t, char, mbstate_t>

	template <>
	codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
		: _Generic_codecvt(refs)
	{
	}

	template <>
	locale::id codecvt<wchar_t, char, mbstate_t>::id;

	// hh 980416 unimplemented prototypes
	size_t 	wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps);
	size_t 	mbsrtowcs(wchar_t *dst, const char **src, size_t len, mbstate_t *ps);

	template <>
	codecvt_base::result
	codecvt<wchar_t, char, mbstate_t>::do_out(mbstate_t& state,
		const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
		char* to, char* to_limit, char*& to_next) const
	{
		size_t len = size_t(from_end - from);
		size_t temp = size_t(to_limit - to);
		result r = ok;
		if (len != temp)
		{
			r = partial;
			if (len > temp)
				len = temp;
		}
		from_next = from;
		to_next = to;
	//	size_t e = wcsrtombs(to_next, &from_next, len, &state); ???
		state;
		size_t e = size_t(-1);
		if (e == -1)
			r = error;
		if (from_next == 0)
			from_next = from_end;
		to_next += from_next - from;
		return r;
	}

	template <>
	codecvt_base::result
	codecvt<wchar_t, char, mbstate_t>::do_in(mbstate_t& state,
		const char* from, const char* from_end, const char*& from_next,
		wchar_t* to, wchar_t* to_limit, wchar_t*& to_next) const
	{
		size_t len = size_t(from_end - from);
		size_t temp = size_t(to_limit - to);
		result r = ok;
		if (len != temp)
		{
			r = partial;
			if (len > temp)
				len = temp;
		}
		from_next = from;
		to_next = to;
	//	size_t e = mbsrtowcs(to_next, &from_next, len, &state); ???
		state;
		size_t e = size_t(-1);
		if (e == -1)
			r = error;
		if (from_next == 0)
			from_next = from_end;
		to_next += from_next - from;
		return r;
	}

#endif

// numpunct<char>

template <>
numpunct<char>::numpunct(size_t refs)
	: _Generic_numpunct(refs)
{
}

template <>
locale::id numpunct<char>::id;

#ifdef MSIPL_WCHART

	// numpunct<wchar_t>

	template <>
	numpunct<wchar_t>::numpunct(size_t refs)
		: _Generic_numpunct(refs)
	{
	}

	template <>
	locale::id numpunct<wchar_t>::id;

#endif

// timepunct<char>

template <>
timepunct<char>::timepunct(size_t refs)
	: _Generic_timepunct(refs)
{
}

template <>
locale::id timepunct<char>::id;

template <>
const char*
timepunct<char>::do_weekday_name(size_t d) const
{
	static const char* name[] = {
		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", ""
	};
	if (d < 7)
		return name[d];
	return name[7];
}

template <>
const char*
timepunct<char>::do_month_name(size_t m) const
{
	static const char* name[] = {
		"January", "February", "March", "April", "May", "June",
		"July", "August", "September", "October", "November", "December", ""
	};
	if (m < 12)
		return name[m];
	return name[12];
}

template <>
const char*
timepunct<char>::do_am_pm(int hour) const
{
	static const char* name[] = {"am", "pm"};
	return name[hour/12];
}

#ifdef MSIPL_WCHART

	// timepunct<wchar_t>

	template <>
	timepunct<wchar_t>::timepunct(size_t refs)
		: _Generic_timepunct(refs)
	{
	}

	template <>
	locale::id timepunct<wchar_t>::id;

	template <>
	const wchar_t*
	timepunct<wchar_t>::do_weekday_name(size_t d) const
	{
		static const wchar_t* name[] = {
			L"Sunday", L"Monday", L"Tuesday", L"Wednesday", L"Thursday", L"Friday", L"Saturday", L""
		};
		if (d < 7)
			return name[d];
		return name[7];
	}

	template <>
	const wchar_t*
	timepunct<wchar_t>::do_month_name(size_t m) const
	{
		static const wchar_t* name[] = {
			L"January", L"February", L"March", L"April", L"May", L"June",
			L"July", L"August", L"September", L"October", L"November", L"December", L""
		};
		if (m < 12)
			return name[m];
		return name[12];
	}

	template <>
	const wchar_t*
	timepunct<wchar_t>::do_am_pm(int hour) const
	{
		static const wchar_t* name[] = {L"am", L"pm"};
		return name[hour/12];
	}

#endif

// moneypunct<char, false>

template <>
moneypunct<char, false>::moneypunct(size_t refs)
	: _Generic_moneypunct(refs)
{
}

template <>
locale::id moneypunct<char, false>::id;

// moneypunct<char, true>

template <>
moneypunct<char, true>::moneypunct(size_t refs)
	: _Generic_moneypunct(refs)
{
}

template <>
locale::id moneypunct<char, true>::id;

#ifdef MSIPL_WCHART

	// moneypunct<wchar_t, false>

	template <>
	moneypunct<wchar_t, false>::moneypunct(size_t refs)
		: _Generic_moneypunct(refs)
	{
	}

	template <>
	locale::id moneypunct<wchar_t, false>::id;

	// moneypunct<wchar_t, true>

	template <>
	moneypunct<wchar_t, true>::moneypunct(size_t refs)
		: _Generic_moneypunct(refs)
	{
	}

	template <>
	locale::id moneypunct<wchar_t, true>::id;

#endif

// Binary Coded Decimal class
// hh 980802 Added to assist in the printing of floating point values

_BCD::_BCD(long double x, int limit)
	: exp_(0)
{
	if (limit <= DECIMAL_DIG)
	{
		if (limit < 2)  // hh 980903
			limit = 2;
		char buff[512];
		sprintf(buff, "%#.*Le", limit-1,  x);
		mantissa_ = buff;
		// Get exponent
		string::iterator i = mantissa_.begin() + limit + 3;
		while (i != mantissa_.end())
		{
			exp_ *= 10;
			exp_ += *i - '0';
			++i;
		}
		i = mantissa_.begin() + limit + 2;
		if (*i == '-')
			exp_ = short(-exp_);
		--i;
		// Remove exponent and decimal point
		mantissa_.erase(i, mantissa_.end());
		mantissa_.erase(mantissa_.begin() + 1);
		for (i = mantissa_.begin(); i != mantissa_.end(); ++i)
			*i -= '0';
	}
	else
	{
		static const _BCD one_half("5", -1);
		if (x > 0)
		{
			int exp;
			long double frac = frexpl(x, &exp);
			_BCD bit = __two_exp(short(exp));
			while (frac != 0)
			{
				long double integer;
				frac = modfl(2*frac, &integer);
				--exp;
				bit *= one_half;
				if (integer != 0)
					*this += bit;
			}
		}
	}
}

string
_BCD::to_string(int precision, int& exponent) const
{
	string result(mantissa_, 0, size_t(precision+1));
	exponent = exp_;
	string::iterator i = result.end() - 1;
	if (precision < result.size())
	{
		if (*i >= 5)
		{
			--i;
			while (true)
			{
				if (*i < 9)
				{
					(*i)++;
					break;
				}
				*i = char();
				if (i == result.begin())
				{
					result.insert(result.begin(), char(1));
					result.resize(result.size()-1);
					++exponent;
					break;
				}
				--i;
			}
		}
		result.resize(result.size()-1);
	}
	for (i = result.begin(); i != result.end(); ++i)
		*i += '0';
	return result;
}

_BCD::_BCD(const char* mantissa, int exponent)
	: exp_((short)exponent),
	  mantissa_(mantissa)
{
	string::iterator i = mantissa_.begin();
	while (i != mantissa_.end())
		*i++ -= '0';
	trim();
}

_BCD&
_BCD::operator += (_BCD rhs)
{
	if (rhs.mantissa_.size() == 0)
		return *this;
	if (mantissa_.size() == 0)
	{
		*this = rhs;
		return *this;
	}
	if (exp_ > rhs.exp_)
	{
		rhs.mantissa_.insert(rhs.mantissa_.begin(), size_t(exp_ - rhs.exp_), char());
		rhs.exp_ = exp_;
	}
	else if (exp_ < rhs.exp_)
	{
		mantissa_.insert(mantissa_.begin(), size_t(rhs.exp_ - exp_), char());
		exp_ = rhs.exp_;
	}
	if (rhs.mantissa_.size() > mantissa_.size())
		mantissa_.resize(rhs.mantissa_.size(), char());
	else if (rhs.mantissa_.size() < mantissa_.size())
		rhs.mantissa_.resize(mantissa_.size(), char());
	size_t i = mantissa_.size() - 1;
	char carry = char();
	while (i > 0)
	{
		mantissa_[i] += char(rhs.mantissa_[i] + carry);
		if (mantissa_[i] > 9)
		{
			carry = char(mantissa_[i] / 10);
			mantissa_[i] %= char(10);
		}
		else
			carry = char();
		--i;
	}
	mantissa_[0] += char(rhs.mantissa_[0] + carry);
	if (mantissa_[0] > 9)
	{
		carry = char(mantissa_[0] / 10);
		mantissa_[0] %= char(10);
		mantissa_.insert(mantissa_.begin(), carry);
		++exp_;
	}
	trim();
	return *this;
}

_BCD&
_BCD::operator *= (_BCD rhs)
{
	if (mantissa_.size() == 0)
		return *this;
	if (rhs.mantissa_.size() == 0)
	{
		*this = rhs;
		return *this;
	}
	_BCD lhs(*this);
	unsigned long long accumulator = 0;
	mantissa_.clear();
	mantissa_.resize(lhs.mantissa_.size() + rhs.mantissa_.size() - 1, char());
	for (long i = (long)mantissa_.size()-1; i >= 0; --i)
	{
		long k = (long)rhs.mantissa_.size() - 1;
		long j = i - k;
		if (j < 0)
		{
			j = 0;
			k = i;
		}
		while (j < lhs.mantissa_.size() && k >= 0)
		{
			accumulator += (unsigned long)lhs.mantissa_[size_t(j)] * rhs.mantissa_[size_t(k)];
			--k;
			++j;
		}
		mantissa_[size_t(i)] = char(accumulator % 10);
		accumulator /= 10;
	}
	exp_ = short(lhs.exp_ + rhs.exp_);
	while (accumulator > 0)
	{
		mantissa_.insert(mantissa_.begin(), char(accumulator % 10));
		accumulator /= 10;
		++exp_;
	}
	trim();
	return *this;
}

_BCD
__two_exp(short x)
{
	static const _BCD one_sixteenth("625", -2);
	static const _BCD one_eighth("125", -1);
	static const _BCD one_fourth("25", -1);
	static const _BCD one_half("5", -1);
	static const _BCD one("1", 0);
	static const _BCD two("2", 0);
	static const _BCD four("4", 0);
	static const _BCD eight("8", 0);
	static const _BCD sixteen("16", 1);
	switch (x)
	{
	case -4:
		return one_sixteenth;
	case -3:
		return one_eighth;
	case -2:
		return one_fourth;
	case -1:
		return one_half;
	case 0:
		return one;
	case 1:
		return two;
	case 2:
		return four;
	case 3:
		return eight;
	case 4:
		return sixteen;
	}
	_BCD temp = __two_exp(short(x/2));
	temp *= temp;
	if (x % 2)
	{
		if (x > 0)
			temp *= two;
		else
			temp *= one_half;
	}
	return temp;
}

#ifdef _MSL_USING_NAMESPACE
	}
#endif

// hh 980811 reworded dhex, uhex and lhex defines
// hh 980816 ARM/Standard neutral for-scoping
