// xloctime internal header (from <locale>) -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _XLOCTIME_
#define _XLOCTIME_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <ctime>
#include <xlocnum>

#if _DLIB_FULL_LOCALE_SUPPORT

namespace std {

// STRUCT time_base
struct time_base
  : public locale::facet
{       // base class for time_get
  enum dateorder : unsigned char
  {       // constants for different orders of date components
    no_order, dmy, mdy, ymd, ydm};

  time_base(size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // default constructor
  }

  ~time_base() _NOEXCEPT
  {       // destroy the object
  }
};

// TEMPLATE CLASS time_get
template<class _Elem,
         class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem> > >
class time_get
  : public time_base
{       // facet for converting text to encoded times
public:
  typedef _Elem char_type;
  typedef _InIt iter_type;
  typedef ctype<_Elem> _Ctype;

  static locale::id id;   // unique facet id

  dateorder date_order() const
  {       // return date order code
    return do_date_order();
  }

  _InIt get_time(_InIt _First, _InIt _Last,
                 ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt) const
  {       // get time of day from [_First, _Last) into _Pt
    return do_get_time(_First, _Last, _Iosbase, _State, _Pt);
  }

  _InIt get_date(_InIt _First, _InIt _Last,
                 ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt) const
  {       // get date from [_First, _Last) into _Pt
    return do_get_date(_First, _Last, _Iosbase, _State, _Pt);
  }

  _InIt get_weekday(_InIt _First, _InIt _Last,
                   ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt) const
  {       // get weekday from [_First, _Last) into _Pt
    return do_get_weekday(_First, _Last, _Iosbase, _State, _Pt);
  }

  _InIt get_monthname(_InIt _First, _InIt _Last,
                   ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt) const
  {       // get month from [_First, _Last) into _Pt
    return do_get_monthname(_First, _Last, _Iosbase, _State, _Pt);
  }

  _InIt get_year(_InIt _First, _InIt _Last,
                 ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt) const
  {       // get year from [_First, _Last) into _Pt
    return do_get_year(_First, _Last, _Iosbase, _State, _Pt);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt,
            char _Specifier, char _Modifier = '\0') const
  {       // get formatted time for _Specifier/_Modifier
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    return do_get(_First, _Last, _Iosbase, _State, _Pt, _Specifier, _Modifier);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt,
            const _Elem *_Fmtfirst, const _Elem *_Fmtlast) const
  {       // get formatted time for format string
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    _DEBUG_RANGE(_Fmtfirst, _Fmtlast);
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    _State = ios_base::goodbit;

    for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst)
      if (_Ctype_fac.narrow(*_Fmtfirst) != '%')
      {       // match literal element
        if (_Ctype_fac.is(_Ctype::space, *_Fmtfirst))
          for (;
               _First != _Last && _Ctype_fac.is(_Ctype::space, *_First);
               ++_First)
            ;
        else if (*_First != *_Fmtfirst)
        {       // bad literal match
          _State |= ios_base::failbit;
          break;
        }
        else
          ++_First;
      }
      else if (++_Fmtfirst == _Fmtlast)
      {       // treat trailing % as literal match
        if (*_First != _Fmtfirst[-1])
          _State |= ios_base::failbit;
        else
          ++_First;
        break;
      }
      else
      {       // get specifier after %
        char _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
        char _Modifier = '\0';
        _Elem _Percent = _Fmtfirst[-1];

        if (   _Specifier != 'E'
            && _Specifier != 'O'
            && _Specifier != 'Q'
            && _Specifier != '#')
          ;       // not [E0Q#] modifier, treat as specifier
        else if (++_Fmtfirst == _Fmtlast)
        {       // no specifier, treat %[E0Q#] as literal match
          if (   *_First != _Percent
              || ++_First == _Last
              || _Ctype_fac.narrow(*_First) != _Specifier)
            _State |= ios_base::failbit;
          else
            ++_First;
          break;
        }
        else
        {       // save both qualifier and specifier
          _Modifier = _Specifier;
          _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
        }

        _First = do_get(_First, _Last, _Iosbase, _State, _Pt,
                        _Specifier, _Modifier); // convert a single field
      }
    if (_First == _Last)
      _State |= ios_base::eofbit;
    return _First;
  }

  explicit time_get(size_t _Refs = 0)
    : time_base(_Refs)
  {       // construct from current locale
    // Possibly lock thread
    _Locinfo _Lobj;
    _Init(_Lobj);
  }

  time_get(const _Locinfo& _Lobj, size_t _Refs = 0)
    : time_base(_Refs)
  {       // construct from specified locale
    _Init(_Lobj);
  }

  static size_t _Getcat(const locale::facet **_Ppf = 0,
                        const locale *_Ploc = 0)
  {       // return locale category mask and construct standard facet
    if (_Ppf != 0 && *_Ppf == 0)
      *_Ppf = new time_get<_Elem, _InIt>(
        _Locinfo(_Ploc->c_str()));
    return _X_TIME;
  }

protected:
  virtual ~time_get() _NOEXCEPT
  {       // destroy the object
    _Tidy();
  }

  time_get(const char *_Locname, size_t _Refs = 0)
    : time_base(_Refs)
  {       // construct from specified locale
    // Possibly lock thread
    _Locinfo _Lobj(_Locname);
    _Init(_Lobj);
  }

  template<class _Elem2>
  void _Getvals(_Elem2, const _Locinfo& _Lobj)
  {       // get values
    _Cvt = _Lobj._Getcvt();
    _Days = _MAKLOCSTR(_Elem, _Lobj._Getdays(), _Cvt);
    _Months = _MAKLOCSTR(_Elem, _Lobj._Getmonths(), _Cvt);
    _Ampm = _MAKLOCSTR(_Elem, ":AM:am:PM:pm", _Cvt);
  }

  void _Init(const _Locinfo& _Lobj)
  {       // initialize from _Lobj
    _Days = 0;
    _Months = 0;
    _Ampm = 0;

    _TRY_BEGIN
      _Getvals((_Elem)0, _Lobj);
      _Dateorder = mdy;       // default is month, day, year
    _CATCH_ALL
      _Tidy();
      _RERAISE;
    _CATCH_END
  }

  virtual dateorder do_date_order() const
  {       // return date order code
    return _Dateorder;
  }

  virtual _InIt do_get_time(_InIt _First, _InIt _Last, ios_base& _Iosbase,
                            ios_base::iostate& _State, tm *_Pt) const
  {       // get time of day from [_First, _Last) into _Pt
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    _State |= _Getint(_First, _Last, 0, 23,
                      _Pt->tm_hour, _Ctype_fac);

    if (_State != ios_base::goodbit || _Ctype_fac.narrow(*_First) != ':')
      _State |= ios_base::failbit;    // hour field is bad
    else
      _State |= _Getint(++_First, _Last, 0, 59,
                        _Pt->tm_min, _Ctype_fac);

    if (_State != ios_base::goodbit || _Ctype_fac.narrow(*_First) != ':')
      _State |= ios_base::failbit;    // min field is bad
    else
      _State |= _Getint(++_First, _Last, 0, 59,
                        _Pt->tm_sec, _Ctype_fac);
    return _First;
  }

  virtual _InIt do_get_date(_InIt _First, _InIt _Last, ios_base& _Iosbase,
                            ios_base::iostate& _State, tm *_Pt) const
  {       // get date from [_First, _Last) into _Pt
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    dateorder _Dorder = date_order();
    if (_Dorder == no_order)
      _Dorder = mdy;

    if (_First == _Last)
      ;
    else if (!_Ctype_fac.is(_Ctype::digit, *_First))
    {       // begins with month name, assume mdy
      _First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
      _Dorder = mdy;
    }
    else if (_Dorder == mdy)
    {       // get month number
      _State |= _Getint(_First, _Last, 1, 12,
                        _Pt->tm_mon, _Ctype_fac);
      --_Pt->tm_mon;
    }
    else if (_Dorder == dmy)
      _State |= _Getint(_First, _Last, 1, 31,
                        _Pt->tm_mday, _Ctype_fac);
    else    // ymd or ydm
      _First = get_year(_First, _Last, _Iosbase, _State, _Pt);

    while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First))
      ++_First;       // skip spaces

    if (_First != _Last)
    {       // skip [:,/]
      char _Ch = _Ctype_fac.narrow(*_First);
      if (_Ch == ':' || _Ch == ',' || _Ch == '/')
        ++_First;
    }
    while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First))
      ++_First;       // skip spaces

    if (_First == _Last)
      ;
    else if (!_Ctype_fac.is(_Ctype::digit, *_First))
      if (_Dorder == mdy)
        _State |= ios_base::failbit;    // error, month already seen
      else
      {       // month name is second, like it or not
        _First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
        if (_Dorder == ydm)
          _Dorder = ymd;
      }
    else if (_Dorder == dmy || _Dorder == ymd)
    {       // get month number
      _State |= _Getint(_First, _Last, 1, 12,
                        _Pt->tm_mon, _Ctype_fac);
      --_Pt->tm_mon;
    }
    else
      _State |= _Getint(_First, _Last, 1, 31,
                        _Pt->tm_mday, _Ctype_fac);

    while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First))
      ++_First;       // skip spaces
    if (_First != _Last)
    {       // skip [:,/]
      char _Ch = _Ctype_fac.narrow(*_First);
      if (_Ch == ':' || _Ch == ',' || _Ch == '/')
        ++_First;
    }
    while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First))
      ++_First;       // skip spaces

    if (_First == _Last)
      _State |= ios_base::failbit;    // error, missing component(s)
    else if (!_Ctype_fac.is(_Ctype::digit, *_First))
      if (_Dorder != ydm)
        _State |= ios_base::failbit;    // error, month out of place
      else
        _First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
    else if (_Dorder == ydm)
    {       // get month number
      _State |= _Getint(_First, _Last, 1, 12,
                        _Pt->tm_mon, _Ctype_fac);
      --_Pt->tm_mon;
    }
    else if (_Dorder == ymd)
      _State |= _Getint(_First, _Last, 1, 31,
                        _Pt->tm_mday, _Ctype_fac);
    else    // mdy or dmy
      _First = get_year(_First, _Last, _Iosbase, _State, _Pt);

    if (_First == _Last)
      _State |= ios_base::eofbit;
    return _First;
  }

  virtual _InIt do_get_weekday(_InIt _First, _InIt _Last, ios_base&,
                               ios_base::iostate& _State, tm *_Pt) const
  {       // get weekday from [_First, _Last) into _Pt
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    int _Num = _Getloctxt(_First, _Last, (size_t)0, _Days);

    if (_Num < 0)
      _State |= ios_base::failbit;
    else
      _Pt->tm_wday = _Num >> 1;       // set wday
    return _First;
  }

  virtual _InIt do_get_monthname(_InIt _First, _InIt _Last, ios_base&,
                                 ios_base::iostate& _State, tm *_Pt) const
  {       // get month from [_First, _Last) into _Pt
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    int _Num = _Getloctxt(_First, _Last, (size_t)0, _Months);

    if (_Num < 0)
      _State |= ios_base::failbit;
    else
      _Pt->tm_mon = _Num >> 1;        // set mon
    return _First;
  }

  virtual _InIt do_get_year(_InIt _First, _InIt _Last, ios_base& _Iosbase,
                            ios_base::iostate& _State, tm *_Pt) const
  {       // get year from [_First, _Last) into _Pt
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pt);
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    int _Ans = 0;
    ios_base::iostate _Res = _Getint(_First, _Last, 0, 9999,
                                     _Ans, _Ctype_fac);

    _State |= _Res;	// pass on eofbit and failbit
    if (_Res & ios_base::failbit)
      ;	// invalid input
    else if (_Ans < 69)
      _Pt->tm_year = _Ans + 100;	// [0, 68] parsed as [2000, 2068]
    else if (_Ans < 100)
      _Pt->tm_year = _Ans;		// [69, 99] parsed as [1969, 1999]
    else
      _Pt->tm_year = _Ans - 1900;	// [100, 9999] parsed literally
    return _First;
  }

  virtual _InIt do_get(_InIt _First, _InIt _Last,
                       ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt,
                       char _Specifier, char = 0) const
  {       // get formatted time for _Specifier (_Modifier ignored)
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());
    int _Ans = 0;

    _State = ios_base::goodbit;

    switch (_Specifier)
    {       // process format specifier
    case 'a':
    case 'A':
      _First = get_weekday(_First, _Last, _Iosbase, _State, _Pt);
      break;

    case 'b':
    case 'B':
    case 'h':
      _First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
      break;

    case 'c':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       "%a %b %d %H : %M : %S %Y");
      break;

    case 'C':
      _State |= _Getint(_First, _Last, 0, 99,
                        _Ans, _Ctype_fac);
      if (!(_State & ios_base::failbit))
        _Pt->tm_year = _Ans * 100 - 1900;       // convert to century
      break;

    case 'd':
    case 'e':
      _State |= _Getint(_First, _Last, 1, 31,
                        _Pt->tm_mday, _Ctype_fac);
      break;

    case 'D':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       "%m / %d / %y");
      break;

    case 'H':
      _State |= _Getint(_First, _Last, 0, 23,
                        _Pt->tm_hour, _Ctype_fac);
      break;

    case 'I':
      _State |= _Getint(_First, _Last, 1, 12,
                        _Ans, _Ctype_fac);
      if (!(_State & ios_base::failbit))
        _Pt->tm_hour = _Ans == 12 ? 0 : _Ans;
      break;

    case 'j':
      _State |= _Getint(_First, _Last, 1, 366,
                        _Pt->tm_yday, _Ctype_fac);
      break;

    case 'm':
      _State |= _Getint(_First, _Last, 1, 12,
                        _Ans, _Ctype_fac);
      if (!(_State & ios_base::failbit))
        _Pt->tm_mon = _Ans - 1;
      break;

    case 'M':
      _State |= _Getint(_First, _Last, 0, 59,
                        _Pt->tm_min, _Ctype_fac);
      break;

    case 'n':
    case 't':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       " ");
      break;

    case 'p':
      _Ans = _Getloctxt(_First, _Last, (size_t)0, ":AM:am:PM:pm");
      if (_Ans < 0)
        _State |= ios_base::failbit;
      else if (1 < _Ans)
        _Pt->tm_hour += 12;
      break;

    case 'r':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       "%I : %M : %S %p");
      break;

    case 'R':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       "%H : %M");
      break;

    case 'S':
      _State |= _Getint(_First, _Last, 0, 60,
                        _Pt->tm_sec, _Ctype_fac);
      break;

    case 'T':
    case 'X':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       "%H : %M : %S");
      break;

    case 'U':
      _State |= _Getint(_First, _Last, 0, 53,
                        _Pt->tm_yday, _Ctype_fac);
      break;

    case 'w':
      _State |= _Getint(_First, _Last, 0, 6,
                        _Pt->tm_wday, _Ctype_fac);
      break;

    case 'W':
      _State |= _Getint(_First, _Last, 0, 53,
                        _Pt->tm_yday, _Ctype_fac);
      break;

    case 'x':
      _First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt,
                       "%d / %m / %y");
      break;

    case 'y':
      _State |= _Getint(_First, _Last, 0, 99,
                        _Ans, _Ctype_fac);
      if (!(_State & ios_base::failbit))
        _Pt->tm_year = _Ans < 69 ? _Ans + 100 : _Ans;
      break;

    case 'Y':
      _First = get_year(_First, _Last, _Iosbase, _State, _Pt);
      break;

    default:
      _State |= ios_base::failbit;    // unknown specifier
    }

    if (_First == _Last)
      _State |= ios_base::eofbit;
    return _First;
  }

  _InIt _Getfmt(_InIt _First, _InIt _Last,
                ios_base& _Iosbase, ios_base::iostate& _State, tm *_Pt,
                const char *_Fmtfirst) const
  {       // get formatted time for format NTBS
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    for (; *_Fmtfirst != '\0' && _State == ios_base::goodbit; ++_Fmtfirst)
      if (*_Fmtfirst == '%')
        _First = do_get(_First, _Last, _Iosbase, _State, _Pt,
                        *++_Fmtfirst);  // convert a single field
      else if (*_Fmtfirst == ' ')
        for (; _First != _Last
               && _Ctype_fac.is(_Ctype::space, *_First); ++_First)
          ;
      else if (_Ctype_fac.narrow(*_First) != *_Fmtfirst)
      {       // bad literal match
        _State |= ios_base::failbit;
        break;
      }
      else
        ++_First;
    if (_First == _Last)
      _State |= ios_base::eofbit;
    return _First;
  }

private:
  ios_base::iostate _Getint(_InIt& _First, _InIt& _Last, int _Lo, int _Hi,
                            int& _Val, const _Ctype& _Ctype_fac) const
  {       // get integer in range [_Lo, _Hi] from [_First, _Last)
    char _Ac[_MAX_INT_DIG], *_Ep;
    char *_Ptr = _Ac;
    char _Ch;

    if (_First == _Last)
      ;
    else if ((_Ch = _Ctype_fac.narrow(*_First)) == '+')
      *_Ptr++ = '+', ++_First;        // copy plus sign
    else if (_Ch == '-')
      *_Ptr++ = '-', ++_First;        // copy minus sign

    bool _Seendigit = false;
    while (_First != _Last && _Ctype_fac.narrow(*_First) == '0')
      _Seendigit = true, ++_First;    // strip leading zeros
    if (_Seendigit)
      *_Ptr++ = '0';  // replace one or more with single zero

    for (char *const _Pe = &_Ac[_MAX_INT_DIG - 1];
            _First != _Last
         && '0' <= (_Ch = _Ctype_fac.narrow(*_First))
         && _Ch <= '9';
         _Seendigit = true, ++_First)
    {       // copy digits
      *_Ptr = _Ch;
      if (_Ptr < _Pe)
        ++_Ptr; // drop trailing digits if already too large
    }

    if (!_Seendigit)
      _Ptr = _Ac;
    *_Ptr = '\0';
    int _Errno = 0;
    const long _Ans = ::__iar_Stolx(_Ac, &_Ep, 10, &_Errno);
    ios_base::iostate _State = ios_base::goodbit;

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0 || _Ans < _Lo || _Hi < _Ans)
      _State |= ios_base::failbit;    // bad conversion
    else
      _Val = _Ans;    // store valid result
    return _State;
  }

  void _Tidy()
  {       // free all storage
    ::free((void *)_Days);
    ::free((void *)_Months);
    ::free((void *)_Ampm);
  }

  const _Elem *_Days;     // ":Sun:Sunday:Mon:Monday..." for example
  const _Elem *_Months;   // "Jan:January:Feb:February..." for example
  const _Elem *_Ampm;     // ":AM:am:PM:pm"
  dateorder _Dateorder;
  _Locinfo::_Cvtvec _Cvt;         // conversion information
};

// STATIC time_get::id OBJECT
template<class _Elem,
         class _InIt>
locale::id time_get<_Elem, _InIt>::id;

// TEMPLATE CLASS time_get_byname
template<class _Elem,
         class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem> > >
class time_get_byname
  : public time_get<_Elem, _InIt>
{       // time_get for named locale
public:
  explicit time_get_byname(const char *_Locname, size_t _Refs = 0)
    : time_get<_Elem, _InIt>(_Locname, _Refs)
  {       // construct for named locale
  }

  explicit time_get_byname(const string& _Str, size_t _Refs = 0)
    : time_get<_Elem, _InIt>(_Locinfo(_Str.c_str()), _Refs)
  {       // construct for named locale
  }

protected:
  virtual ~time_get_byname() _NOEXCEPT
  {       // destroy the object
  }
};

// TEMPLATE CLASS time_put
template<class _Elem,
         class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem> > >
class time_put
  : public locale::facet
{       // facet for converting encoded times to text
public:
  typedef _Elem char_type;
  typedef _OutIt iter_type;
  typedef ctype<_Elem> _Ctype;

  _OutIt put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm *_Pt,
             const _Elem *_Fmtfirst, const _Elem *_Fmtlast) const
  {       // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Pt);
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst)
      if (_Ctype_fac.narrow(*_Fmtfirst) != '%')
        *_Dest++ = *_Fmtfirst;  // copy literal element
      else if (++_Fmtfirst == _Fmtlast)
      {       // treat trailing % as %%
        *_Dest++ = _Fmtfirst[-1];
        break;
      }
      else
      {       // get specifier after %
        char _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
        char _Modifier = '\0';
        _Elem _Percent = _Fmtfirst[-1];

        if (   _Specifier != 'E'
            && _Specifier != 'O'
            && _Specifier != 'Q'
            && _Specifier != '#')
          ;       // not [E0Q#] qualifier, treat as specifier
        else if (++_Fmtfirst == _Fmtlast)
        {       // no specifier, copy %[E0Q#] as literal elements
          *_Dest++ = _Percent;
          *_Dest++ = _Specifier;
          break;
        }
        else
        {       // save both qualifier and specifier
          _Modifier = _Specifier;
          _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
        }

        _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt,
                       _Specifier, _Modifier); // convert a single field
      }
    return _Dest;
  }

  _OutIt put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm *_Pt,
             char _Specifier, char _Modifier = '\0') const
  {       // put formatted time from _Pt to _Dest for _Specifier/_Modifier
    return do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier);
  }

  static locale::id id;   // unique facet id

  explicit time_put(size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from current locale
    // Possibly lock thread
    _Locinfo _Lobj;
    _Init(_Lobj);
  }

  time_put(const _Locinfo& _Lobj, size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from specified locale
    _Init(_Lobj);
  }

  static size_t _Getcat(const locale::facet **_Ppf = 0,
                        const locale *_Ploc = 0)
  {       // return locale category mask and construct standard facet
    if (_Ppf != 0 && *_Ppf == 0)
      *_Ppf = new time_put<_Elem, _OutIt>(
          _Ploc->_GetLocinfo());
    return _X_TIME;
  }

protected:
  virtual ~time_put() _NOEXCEPT
  {       // destroy the object
  }

  void _Init(const _Locinfo& _Lobj)
  {       // initialize from _Lobj
    _Tnames = _Lobj._Gettnames();
  }

  virtual _OutIt do_put(_OutIt _Dest,
                        ios_base&, _Elem, const tm *_Pt,
                        char _Specifier, char _Modifier = '\0') const
  {       // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Pt);

    char _Fmt[5] = "!%x\0"; // '!' for nonzero count, null for modifier
    size_t _Count, _Num;
    string _Str;

    if (_Modifier == '\0')
      _Fmt[2] = _Specifier;
    else
    {       // add both modifier and specifier
      _Fmt[2] = _Modifier;
      _Fmt[3] = _Specifier;
    }

    for (_Num = 16; ; _Num *= 2)
    {       // convert into ever larger string buffer until success
      _Str.append(_Num, '\0');
      if (0 < (_Count = _Strftime(&*_Str.begin(), _Str.size(),
                                  _Fmt, _Pt, _Tnames._Timeinfo)))
        break;
    }
    return std::copy(&_Str[1], &_Str[_Count], _Dest);
  }

private:
  _Locinfo::_Timevec _Tnames;     // locale-specific stuff for _Strftime
};

// STATIC time_put::id OBJECT
template<class _Elem,
         class _OutIt>
locale::id time_put<_Elem, _OutIt>::id;

// CLASS time_put<wchar_t>
template<class _OutIt>
class time_put<wchar_t, _OutIt>
  : public locale::facet
{       // facet for converting encoded times to wchar_t text
public:
  typedef wchar_t _Elem;
  typedef _Elem char_type;
  typedef _OutIt iter_type;
  typedef ctype<_Elem> _Ctype;

  _OutIt put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm *_Pt,
             const _Elem *_Fmtfirst, const _Elem *_Fmtlast) const
  {       // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Pt);
    const _Ctype& _Ctype_fac = use_facet< _Ctype >(_Iosbase.getloc());

    for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst)
      if (_Ctype_fac.narrow(*_Fmtfirst) != '%')
        *_Dest++ = *_Fmtfirst;  // copy literal element
      else if (++_Fmtfirst == _Fmtlast)
      {       // treat trailing % as %%
        *_Dest++ = _Fmtfirst[-1];
        break;
      }
      else
      {       // get specifier after %
        char _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
        char _Modifier = '\0';
        _Elem _Percent = _Fmtfirst[-1];

        if (   _Specifier != 'E'
            && _Specifier != 'O'
            && _Specifier != 'Q'
            && _Specifier != '#')
          ;       // not [E0Q#] qualifier, treat as specifier
        else if (++_Fmtfirst == _Fmtlast)
        {       // no specifier, copy %[E0Q#] as literal elements
          *_Dest++ = _Percent;
          *_Dest++ = _Specifier;
          break;
        }
        else
        {       // save both qualifier and specifier
          _Modifier = _Specifier;
          _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
        }

        _Dest = do_put(_Dest, _Iosbase, _Fill, _Pt,
                       _Specifier, _Modifier); // convert a single field
      }
    return _Dest;
  }

  _OutIt put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm *_Pt,
             char _Specifier, char _Modifier = '\0') const
  {       // put formatted time from _Pt to _Dest for _Specifier/_Modifier
    return do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier);
  }

  static locale::id id;   // unique facet id

  explicit time_put(size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from current locale
    // Possibly lock thread
    _Locinfo _Lobj;
    _Init(_Lobj);
  }

  time_put(const _Locinfo& _Lobj, size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from specified locale
    _Init(_Lobj);
  }

  static size_t _Getcat(const locale::facet **_Ppf = 0,
                        const locale *_Ploc = 0)
  {       // return locale category mask and construct standard facet
    if (_Ppf != 0 && *_Ppf == 0)
      *_Ppf = new time_put<_Elem, _OutIt>(
        _Locinfo(_Ploc->c_str()));
    return _X_TIME;
  }

protected:
  virtual ~time_put() _NOEXCEPT
  {       // destroy the object
  }

  time_put(const char *_Locname, size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from specified locale
    // Possibly lock thread
    _Locinfo _Lobj(_Locname);
    _Init(_Lobj);
  }

  void _Init(const _Locinfo& _Lobj)
  {       // initialize from _Lobj
    _Cvt = _Lobj._Getcvt();
    _Tnames = _Lobj._Gettnames();
  }

  virtual _OutIt do_put(_OutIt _Dest,
                        ios_base&, _Elem, const tm *_Pt,
                        char _Specifier, char _Modifier = '\0') const
  {       // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Pt);
    char _Fmt[5] = "!%x\0"; // ! for nonzero count, null for modifier
    size_t _Count, _Num;
    string _Str;

    if (_Modifier == '\0')
      _Fmt[2] = _Specifier;
    else
    {       // add both modifier and specifier
      _Fmt[2] = _Modifier;
      _Fmt[3] = _Specifier;
    }

    for (_Num = 16; ; _Num *= 2)
    {       // convert into ever larger string buffer until success
      _Str.append(_Num, '\0');
      if (0 < (_Count = _Strftime(&*_Str.begin(), _Str.size(),
                                  _Fmt, _Pt, _Tnames._Timeinfo)))
        break;
    }

    int _Bytes;
    _Mbstinit(_Mbst);
    wchar_t _Wc;
    --_Count;       // skip '!'
    for (string::const_iterator _Snext = _Str.begin() + 1;
         0 < _Count;
         _Count -= _Bytes, _Snext += _Bytes, *_Dest++ = _Wc)
      switch (_Bytes = _Mbrtowc(&_Wc, &*_Snext, _Count, &_Mbst, &_Cvt))
      {       // convert a wchar_t
      case -2:        // partial conversion
      case -1:        // failed conversion
        return (_Dest);

      case 0: // may have converted null character
        if (_Wc == L'\0')
          _Bytes = (int)::strlen(&*_Snext) + 1;
        break;

      case -3:
        _Bytes = 0;     // wchar_t generated from state info
        break;

      default:         // C-RUN wants this
        break;
      }
    return _Dest;
  }

private:
  _Locinfo::_Timevec _Tnames;     // locale-specific stuff for __iar_Wcsftime
  _Locinfo::_Cvtvec _Cvt;         // conversion information
};

// STATIC time_put::id OBJECT
template<class _OutIt>
locale::id time_put<wchar_t, _OutIt>::id;

// TEMPLATE CLASS time_put_byname
template<class _Elem,
         class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem> > >
class time_put_byname
  : public time_put<_Elem, _OutIt>
{       // time_put for named locale
public:
  explicit time_put_byname(const char *_Locname, size_t _Refs = 0)
    : time_put<_Elem, _OutIt>(_Locname, _Refs)
  {       // construct for named locale
  }

  explicit time_put_byname(const string& _Str, size_t _Refs = 0)
    : time_put<_Elem, _OutIt>(_Str.c_str(), _Refs)
  {       // construct for named locale
  }

protected:
  virtual ~time_put_byname() _NOEXCEPT
  {       // destroy the object
  }
};

} /* namespace std */

#endif /* _DLIB_FULL_LOCALE_SUPPORT */

#endif /* _XLOCTIME_ */

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