// xlocinfo internal header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _XLOCINFO_
#define _XLOCINFO_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <cctype>
#include <clocale>
#include <cstdlib>
#include <cstring>
#include <ctime>
#if _DLIB_WIDE_CHARACTERS
#include <cwchar>
#endif
#include <xstring>

#include <xctype.h>

#if _DLIB_FULL_LOCALE_SUPPORT

namespace std {
  struct _Ctypevec;
} // namespace std

extern "C" {
  __ATTRIBUTES int _Strcollx(const char *s1, const char *s2,
                             struct __iar_Locale const *);
  __ATTRIBUTES int _Wcscollx(const wchar_t *s1, const wchar_t *s2);
  __ATTRIBUTES size_t _Strxfrmx(char *s1, const char *s2, size_t n,
                                struct __iar_Locale const *);
  __ATTRIBUTES size_t _Wcsxfrmx(wchar_t *s1, const wchar_t *s2, size_t n);
  __ATTRIBUTES _Sizet __iar_CStrftime(char *, _Sizet, const char *,
                                      const struct tm *, struct _Tinfo const *);
  struct __iar_Locale;
  struct lconv;
}

namespace std {

class _Locinfo;

// CLASS _Collvec
struct _Collvec
{ // locale-specific collation information
  struct __iar_Locale const *_Plocale;
};

// CLASS _Ctypevec
struct _Ctypevec
{ // locale-specific ctype information
  // The ctype isxxx functionality.
private:
  friend class _Locinfo;
  __iar_Locale const *_PInfo;

public:
  _Ctypevec() : _PInfo(0), _Table(0), _Delfl(0) {}

  _Ctypevec(_Ctypevec const &_Right)
    : _PInfo(_Right._PInfo), _Table(_Right._Table), _Delfl(_Right._Delfl)
  {
  }
 	
  _CtypeMask const * LocaleTable() const;

  int tolower(int) const;
  int toupper(int) const;

  _CtypeMask const * _Table;
  int _Delfl;
};

// CLASS _Cvtvec
struct _Cvtvec
{ // locale-specific codecvt information
private:
  friend class _Locinfo;
  __iar_Locale const *_PInfo;

public:
  _Cvtvec() : _PInfo(0)
  {
  }

  _Cvtvec(_Cvtvec const &_Right)
    : _PInfo(_Right._PInfo)
  {
  }

  int mbtowc(_Wchart *pwc, const char *s, _Sizet nin, _Mbstatet *pst) const;
  #if _DLIB_WIDE_CHARACTERS
    int wctomb(char * c, _Wchart wc, _Mbstatet * st) const;
  #endif
  // The multibyte encoding
  _Sizet Mbcurmax() const;
};

// CLASS _Timevec
struct _Timevec
{ // locale-specific time information
  struct _Tinfo const *_Timeinfo;
};

// CLASS _Locinfo
class _Locinfo
{ // summary of all stuff peculiar to a locale used by standard facets
public:
  typedef _Collvec _Collvec;
  typedef _Ctypevec _Ctypevec;
  typedef _Cvtvec _Cvtvec;
  typedef _Timevec _Timevec;

  _Locinfo();                     // construct from global C locale
  _Locinfo(const char *);         // construct from named locale
  _Locinfo(const string&);        // construct from named locale
  _Locinfo(const _Locinfo &);

  ~_Locinfo() _NOEXCEPT;  // destroy the object

  char const *_Getname() const
  { // return the new locale name
    return _Newlocname.c_str();
  }

  _Collvec _Getcoll() const;
  _Ctypevec _Getctype() const;
  _Cvtvec _Getcvt() const;

  const lconv *_Getlconv_for_messages() const;
  const lconv *_Getlconv_for_monetary() const;
  const lconv *_Getlconv_for_numeric() const;
  _Timevec _Gettnames() const;
  const char *_Getdays() const;
  const char *_Getmonths() const;
  const char *_Getfalse() const;
  const char *_Gettrue() const;

  void _CopyLocaleCat(const _Locinfo *_Lobj, int _CatIndex);
  bool _UpdateName();

  void _UpdateCLocale() const;

private:
  void _Init(char const *);

  _Yarn<char> _Newlocname;        // new locale name for this object
  _Locale_Profile_t _Profile;
};

// TEMPLATE FUNCTION _LStrcoll
template<class _Elem> inline
int _LStrcoll(const _Elem *_First1, const _Elem *_Last1,
              const _Elem *_First2, const _Elem *_Last2,
              const _Collvec *)
{ // perform locale-specific comparison of _Elem sequences
  for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, ++_First2)
    if (*_First1 < *_First2)
      return -1;    // [_First1, _Last1) < [_First2, _Last2)
    else if (*_First2 < *_First1)
      return +1;    // [_First1, _Last1) > [_First2, _Last2)
  return _First2 != _Last2 ? -1 : _First1 != _Last1 ? +1 : 0;
}

template<> inline
int _LStrcoll(const char *_First1, const char *_Last1,
              const char *_First2, const char *_Last2,
              const _Collvec *_Pcoll)
{ // perform locale-specific comparison of char sequences
  string _Str1, _Str2;
  size_t _Len1 = _Last1 - _First1;
  size_t _Len2 = _Last2 - _First2;

  if (0 < _Len1 && _Last1[-1] != '\0')
  { // copy first operand to string
    _Str1.assign(_First1, _Last1);
    _First1 = _Str1.c_str();
  }
  if (0 < _Len2 && _Last2[-1] != '\0')
  { // copy second operand to string
    _Str2.assign(_First2, _Last2);
    _First2 = _Str2.c_str();
  }

  int _Ans = 0;
  while (   0 < _Len1 && 0 < _Len2
         && (_Ans = _Strcollx(_First1, _First2, _Pcoll->_Plocale)) == 0)
  { // equal through nul, test for following strings
    size_t _Prefix = ::strlen(_First1) + 1;
    if (_Len1 <= _Prefix || _Len2 <= _Prefix)
      return _Len1 < _Len2 ? -1 : _Len1 == _Len2 ? 0 : +1;

    _Len1 -= _Prefix, _Len2 -= _Prefix;
    _First1 += _Prefix, _First2 += _Prefix;
  }
  return _Ans != 0 || _Len1 == _Len2 ? _Ans
                                     : _Len1 < _Len2 ? -1 : +1;
}

template<> inline
int _LStrcoll(const wchar_t *_First1, const wchar_t *_Last1,
              const wchar_t *_First2, const wchar_t *_Last2,
              const _Collvec *_Pcoll)
{ // perform locale-specific comparison of wchar_t sequences
  wstring _Str1, _Str2;
  size_t _Len1 = _Last1 - _First1;
  size_t _Len2 = _Last2 - _First2;

  if (0 < _Len1 && _Last1[-1] != L'\0')
  { // copy first operand to string
    _Str1.assign(_First1, _Last1);
    _First1 = _Str1.c_str();
  }
  if (0 < _Len2 && _Last2[-1] != L'\0')
  { // copy second operand to string
    _Str2.assign(_First2, _Last2);
    _First2 = _Str2.c_str();
  }

  int _Ans = 0;
  while (   0 < _Len1 && 0 < _Len2
         && (_Ans = _Wcscollx(_First1, _First2)) == 0)
  { // equal through nul, test for following strings
    size_t _Prefix = ::wcslen(_First1) + 1;
    if (_Len1 <= _Prefix || _Len2 <= _Prefix)
      return _Len1 < _Len2 ? -1 : _Len1 == _Len2 ? 0 : +1;

    _Len1 -= _Prefix, _Len2 -= _Prefix;
    _First1 += _Prefix, _First2 += _Prefix;
  }
  return _Ans != 0 || _Len1 == _Len2 ? _Ans
		                     : _Len1 < _Len2 ? -1 : +1;
}

// TEMPLATE FUNCTION _LStrxfrm
template<class _Elem> inline
size_t _LStrxfrm(_Elem *_First1, _Elem *_Last1,
                 const _Elem *_First2, const _Elem *_Last2,
                 const _Locinfo::_Collvec *)
{ // perform locale-specific transform of _Elems to [_First1, _Last1)
  size_t _Count = _Last2 - _First2;

  if (_Count <= (size_t)(_Last1 - _First1))
    ::memcpy(_First1, _First2, _Count * sizeof (_Elem));
  return _Count;
}

template<> inline
size_t _LStrxfrm(char *_First1, char *_Last1,
                 const char *_First2, const char *_Last2,
                 const _Locinfo::_Collvec *_Pcoll)
{ // perform locale-specific transform of chars to [_First1, _Last1)
  string _Str2;
  size_t _Len1 = _Last1 - _First1;
  size_t _Len2 = _Last2 - _First2;

  if (0 < _Len2 && _Last2[-1] != '\0')
  { // copy second operand to string
    _Str2.assign(_First2, _Last2);
    _First2 = _Str2.c_str();
  }

  size_t _Count = 0;
  while (0 < _Len2)
  { // more to translate, try another nul-terminated sequence
    size_t _Num = _Strxfrmx(_First1, _First2, _Len1, _Pcoll->_Plocale);
    _Count += _Num;
    if (_Len1 < _Num)
      break;	// translation too long, give up

    size_t _Prefix = ::strlen(_First2) + 1;
    if (_Len1 <= _Prefix)
      break;	// translation done, quit
    _Len1 -= _Num;
    _First1 += _Num;
    _First2 += _Prefix;
  }
  return _Count;
}

template<> inline
size_t _LStrxfrm(wchar_t *_First1, wchar_t *_Last1,
                 const wchar_t *_First2, const wchar_t *_Last2,
                 const _Locinfo::_Collvec *_Pcoll)
{ // perform locale-specific transform of wchar_ts to [_First1, _Last1)
  wstring _Str2;
  size_t _Len1 = _Last1 - _First1;
  size_t _Len2 = _Last2 - _First2;

  if (0 < _Len2 && _Last2[-1] != L'\0')
  { // copy second operand to string
    _Str2.assign(_First2, _Last2);
    _First2 = _Str2.c_str();
  }

  size_t _Count = 0;
  while (0 < _Len2)
  { // more to translate, try another nul-terminated sequence
    size_t _Num = _Wcsxfrmx(_First1, _First2, _Len1) + 1;
    _Count += _Num;
    if (_Len1 < _Num)
      break;	// translation too long, give up

    size_t _Prefix = ::wcslen(_First2) + 1;
    if (_Len1 <= _Prefix)
      break;	// translation done, quit
    _Len1 -= _Num;
    _First1 += _Num;
    _First2 += _Prefix;
  }
  return _Count;
}

// FUNCTION _Mbrtowc
inline int _Mbrtowc(wchar_t *_Wptr, const char *_Ptr, size_t _Count,
                    mbstate_t *_Pstate, const _Cvtvec *_Pvct)
{ // perform locale-specific mbrtowc
  return _Pvct->mbtowc(_Wptr, _Ptr, _Count, _Pstate);
}

// FUNCTION _Strftime
inline size_t _Strftime(char *_Ptr, size_t _Count, const char *_Format,
                        const struct tm *_Ptime, struct _Tinfo const *_timePtr)
{ // perform locale-specific strftime
  return ::__iar_CStrftime(_Ptr, _Count, _Format, _Ptime, _timePtr);
}

// FUNCTION _Tolower
inline int _Tolower(char _Byte, const _Ctypevec *_Pctype)
{ // perform locale-specific tolower
  return _Pctype->tolower(_Byte);
}

// FUNCTION _Toupper
inline int _Toupper(char _Byte, const _Ctypevec *_Pctype)
{ // perform locale-specific toupper
  return _Pctype->toupper(_Byte);
}

// FUNCTION _Wcrtomb
inline int _Wcrtomb(char *_Ptr, wchar_t _Char,
                    mbstate_t *_Pstate, const _Cvtvec *_Pcvt)
{ // perform locale-specific wcrtomb
  return _Pcvt->wctomb(_Ptr, _Char, _Pstate);
}

} /* namespace std */
#else /* _DLIB_FULL_LOCALE_SUPPORT */
namespace std {

#if _DLIB_WIDE_CHARACTERS
// FUNCTION _Mbrtowc
inline int _Mbrtowc(wchar_t *_Wptr, const char *_Ptr, size_t _Count,
                    mbstate_t *_Pstate)
{ // perform locale-specific mbrtowc
  return ::mbrtowc(_Wptr, _Ptr, _Count, _Pstate);
}

// FUNCTION _Wcrtomb
inline int _Wcrtomb(char *_Ptr, wchar_t _Char, mbstate_t *_Pstate)
{ // perform locale-specific wcrtomb
  return ::wcrtomb(_Ptr, _Char, _Pstate);
}
#endif

} /* namespace std */

#endif /* _DLIB_FULL_LOCALE_SUPPORT */

#endif /* _XLOCINFO_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
