// iomanip standard header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _IOMANIP_
#define _IOMANIP_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <istream>
#include <type_traits>

#include <xlocmon>
#include <xloctime>

namespace std {

// TEMPLATE STRUCT _Fillobj
template<class _Elem>
struct _Fillobj
{       // store fill character
  _Fillobj(_Elem _Ch)
    : _Fill(_Ch)
  {       // construct from fill character
  }

  _Elem _Fill;    // the fill character
};

// TEMPLATE FUNCTION setfill
template<class _Elem> inline
_Fillobj<_Elem> setfill(_Elem _Ch)
{       // return a _Fillobj manipulator
  return _Fillobj<_Elem>(_Ch);
}

template<class _Elem,
         class _Traits,
         class _Elem2> inline
basic_istream<_Elem, _Traits>&
operator>>(basic_istream<_Elem, _Traits>& _Istr,
           const _Fillobj<_Elem2>& _Manip)
{       // set fill character in input stream
  _STATIC_ASSERT2((is_same<_Elem, _Elem2>::value),
                  "wrong character type for setfill");

  _Istr.fill(_Manip._Fill);
  return _Istr;
}

template<class _Elem,
         class _Traits,
         class _Elem2> inline
basic_ostream<_Elem, _Traits>&
operator<<(basic_ostream<_Elem, _Traits>& _Ostr,
           const _Fillobj<_Elem2>& _Manip)
{       // set fill character in output stream
  _STATIC_ASSERT2((is_same<_Elem, _Elem2>::value),
                  "wrong character type for setfill");

  _Ostr.fill(_Manip._Fill);
  return _Ostr;
}

// TEMPLATE STRUCT _Monobj
template<class _Money>
struct _Monobj
{       // store reference to monetary amount
  _Monobj(_Money& _Val_arg, bool _Intl_arg)
    : _Val(_Val_arg), _Intl(_Intl_arg)
  {       // construct from monetary amount reference and int'l flag
  }

  _Money& _Val;   // the monetary amount reference
  bool _Intl;             // international flag

private:
  _Monobj& operator=(const _Monobj&);
};

// TEMPLATE FUNCTION get_money
template<class _Money> inline
_Monobj<_Money> get_money(_Money& _Val_arg,
                          bool _Intl_arg = false)
{       // return a _Monobj manipulator
  return _Monobj<_Money>(_Val_arg, _Intl_arg);
}

#if _DLIB_FULL_LOCALE_SUPPORT
  template<class _Elem,
           class _Traits,
           class _Money> inline
  basic_istream<_Elem, _Traits>&
  operator>>(basic_istream<_Elem, _Traits>& _Istr,
             const _Monobj<_Money>& _Manip)
  {       // get monetary amount from input stream
    typedef basic_istream<_Elem, _Traits> _Myis;
    typedef istreambuf_iterator<_Elem, _Traits> _Iter;
    typedef money_get<_Elem, _Iter> _Mymget;

    ios_base::iostate _State = ios_base::goodbit;
    const typename _Myis::sentry _Ok(_Istr);

    if (_Ok)
    {       // state okay, extract monetary amount
      const _Mymget& _Mget_fac = use_facet< _Mymget >(_Istr.getloc());
      _TRY_IO_BEGIN
      _Mget_fac.get(_Iter(_Istr.rdbuf()), _Iter(0), _Manip._Intl,
                    _Istr, _State, _Manip._Val);
      _CATCH_IO_(_Istr)
    }

    _Istr.setstate(_State);
    return _Istr;
  }

  // TEMPLATE FUNCTION put_money
  template<class _Money> inline
  _Monobj<const _Money>
  put_money(const _Money& _Val_arg,
            bool _Intl_arg = false)
  {       // return a _Monobj manipulator
    return _Monobj<const _Money>(_Val_arg, _Intl_arg);
  }

  template<class _Elem,
           class _Traits,
           class _Money> inline
  basic_ostream<_Elem, _Traits>&
  operator<<(basic_ostream<_Elem, _Traits>& _Ostr,
             const _Monobj<_Money>& _Manip)
  {       // put monetary amount to output stream
    typedef basic_ostream<_Elem, _Traits> _Myos;
    typedef ostreambuf_iterator<_Elem, _Traits> _Iter;
    typedef money_put<_Elem, _Iter> _Mymput;

    ios_base::iostate _State = ios_base::goodbit;
    const typename _Myos::sentry _Ok(_Ostr);

    if (_Ok)
    {       // state okay, insert monetary amount
      const _Mymput& _Mput_fac = use_facet< _Mymput >(_Ostr.getloc());
      _TRY_IO_BEGIN
      if (_Mput_fac.put(_Iter(_Ostr.rdbuf()), _Manip._Intl,
                        _Ostr, _Ostr.fill(), _Manip._Val).failed())
        _State |= ios_base::badbit;
      _CATCH_IO_(_Ostr)
    }

    _Ostr.setstate(_State);
    return _Ostr;
  }

  // TEMPLATE STRUCT _Timeobj
  template<class _Elem,
           class _Ptr>
  struct _Timeobj
  {       // store reference to tm object and format
    _Timeobj(_Ptr _Tptr_arg, const _Elem *_Fmt_arg)
      : _Tptr(_Tptr_arg), _Fmtfirst(_Fmt_arg)
    {       // construct from tm pointer and format pointer
      for (_Fmtlast = _Fmtfirst; *_Fmtlast != 0; ++_Fmtlast)
        ;       // find end of format string
    }

    _Ptr _Tptr;     // the tm struct pointer
    const _Elem *_Fmtfirst; // format string start
    const _Elem *_Fmtlast;  // format string end
  };

  // TEMPLATE FUNCTION get_time
  template<class _Elem> inline
  _Timeobj<_Elem, struct tm *>
  get_time(struct tm *_Tptr_arg, const _Elem *_Fmt_arg)
  {       // return a _Timeobj manipulator
    return _Timeobj<_Elem, struct tm *>(_Tptr_arg, _Fmt_arg);
  }

  template<class _Elem,
           class _Traits,
           class _Elem2> inline
  basic_istream<_Elem, _Traits>&
  operator>>(basic_istream<_Elem, _Traits>& _Istr,
             const _Timeobj<_Elem2, struct tm *>& _Manip)
  {       // get time information from input stream
    typedef basic_istream<_Elem, _Traits> _Myis;
    typedef istreambuf_iterator<_Elem, _Traits> _Iter;
    typedef time_get<_Elem2, _Iter> _Mytget;

    _STATIC_ASSERT2((is_same<_Elem, _Elem2>::value),
                    "wrong character type for get_time");

    ios_base::iostate _State = ios_base::goodbit;
    const typename _Myis::sentry _Ok(_Istr);

    if (_Ok)
    {       // state okay, extract time amounts
      const _Mytget& _Tget_fac = use_facet< _Mytget >(_Istr.getloc());
      _TRY_IO_BEGIN
      _Tget_fac.get(_Iter(_Istr.rdbuf()), _Iter(0), _Istr, _State,
                    _Manip._Tptr, _Manip._Fmtfirst, _Manip._Fmtlast);
      _CATCH_IO_(_Istr)
    }

    _Istr.setstate(_State);
    return _Istr;
  }

  // TEMPLATE FUNCTION put_time
  template<class _Elem> inline
  _Timeobj<_Elem, const struct tm *>
  put_time(const struct tm *_Tptr_arg, const _Elem *_Fmt_arg)
  {       // return a _Timeobj manipulator
    return _Timeobj<_Elem, const struct tm *>(_Tptr_arg, _Fmt_arg);
  }

  template<class _Elem,
           class _Traits,
           class _Elem2> inline
  basic_ostream<_Elem, _Traits>&
  operator<<(basic_ostream<_Elem, _Traits>& _Ostr,
             const _Timeobj<_Elem2, const struct tm *>& _Manip)
  {       // put time information to output stream
    typedef basic_ostream<_Elem, _Traits> _Myos;
    typedef ostreambuf_iterator<_Elem, _Traits> _Iter;
    typedef time_put<_Elem2, _Iter> _Mytput;

    _STATIC_ASSERT2((is_same<_Elem, _Elem2>::value),
                    "wrong character type for put_time");

    ios_base::iostate _State = ios_base::goodbit;
    const typename _Myos::sentry _Ok(_Ostr);

    if (_Ok)
    {       // state okay, insert monetary amount
      const _Mytput& _Tput_fac = use_facet< _Mytput >(_Ostr.getloc());
      _TRY_IO_BEGIN
      if (_Tput_fac.put(_Iter(_Ostr.rdbuf()), _Ostr, _Ostr.fill(),
                        _Manip._Tptr, _Manip._Fmtfirst,
                        _Manip._Fmtlast).failed())
        _State |= ios_base::badbit;
      _CATCH_IO_(_Ostr)
    }

    _Ostr.setstate(_State);
    return _Ostr;
  }
#endif // _DLIB_FULL_LOCALE_SUPPORT

// TEMPLATE STRUCT _Quote_in
template<class _Elem,
         class _Traits,
         class _Alloc>
struct _Quote_in
{       // store reference to string
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;

  _Quote_in(_Mystr& _Str_obj,
            _Elem _Delim_obj, _Elem _Escape_obj)
    : _Str(_Str_obj), _Delim(_Delim_obj), _Escape(_Escape_obj)
  {       // construct from string, delimiter, and escape
  }

  _Mystr& _Str;   // reference to string
  _Elem _Delim;   // delimiter element
  _Elem _Escape;  // escape element

  _Quote_in& operator=(const _Quote_in&) = delete;
};

// TEMPLATE STRUCT _Quote_out
template<class _Elem, class _Traits, class _Sizet>
struct _Quote_out
{       // store pointer/length for string
  _Quote_out(const _Elem *_Ptr_obj, _Sizet _Size_obj,
             _Elem _Delim_obj, _Elem _Escape_obj)
    : _Ptr(_Ptr_obj), _Size(_Size_obj),
      _Delim(_Delim_obj), _Escape(_Escape_obj)
  {       // construct from string, delimiter, and escape
  }

  const _Elem *_Ptr;      // pointer to string
  _Sizet _Size;   // length of string
  _Elem _Delim;   // delimiter element
  _Elem _Escape;  // escape element

  _Quote_out& operator=(const _Quote_out&) = delete;
};

// TEMPLATE FUNCTION quoted
template<class _Elem> inline
_Quote_out<_Elem, void, size_t>
quoted(const _Elem *_Ptr,
       _Elem _Delim = _Elem('"'),
       _Elem _Escape = _Elem('\\'))
{       // return a _Quote_out manipulator for pointer/length
  size_t _Size = 0;
  for (; _Ptr[_Size] != _Elem(0); ++_Size)
    ;
  return _Quote_out<_Elem, void, size_t>(_Ptr, _Size, _Delim, _Escape);
}

template<class _Elem,
         class _Traits,
         class _Alloc> inline
_Quote_out<_Elem, _Traits,
           typename basic_string<_Elem, _Traits, _Alloc>::size_type>
quoted(const basic_string<_Elem, _Traits, _Alloc>& _Str,
       _Elem _Delim = _Elem('"'),
       _Elem _Escape = _Elem('\\'))
{       // return a _Quote_out manipulator for string
  typedef _Quote_out<_Elem, _Traits,
    typename basic_string<_Elem, _Traits, _Alloc>::size_type> _Qobj;
  return _Qobj(_Str.c_str(), _Str.size(), _Delim, _Escape);
}

template<class _Elem,
         class _Traits,
         class _Alloc> inline
_Quote_in<_Elem, _Traits, _Alloc>
quoted(basic_string<_Elem, _Traits, _Alloc>& _Str,
       _Elem _Delim = _Elem('"'),
       _Elem _Escape = _Elem('\\'))
{       // return a _Quote_in manipulator
  return _Quote_in<_Elem, _Traits, _Alloc>(_Str, _Delim, _Escape);
}

// quoted INSERTER
template<class _Elem,
         class _Traits,
         class _QuTraits,
         class _Sizet> inline
basic_ostream<_Elem, _Traits>&
operator<<(basic_ostream<_Elem, _Traits>& _Ostr,
           const _Quote_out<_Elem, _QuTraits, _Sizet>& _Manip)
{       // put quoted string to output stream
  _STATIC_ASSERT2((   is_void<_QuTraits>::value
                   || is_same<_QuTraits, _Traits>::value),
                  "quoted() traits must match basic_ostream traits");

  typedef basic_ostream<_Elem, _Traits> _Myos;

  const _Elem *const _Last = _Manip._Ptr + _Manip._Size;

  _Sizet _Size = _Manip._Size + 2;        // allow for delimiters
  for (const _Elem *_Ptr = _Manip._Ptr; _Ptr != _Last; ++_Ptr)
    if (_Traits::eq(*_Ptr, _Manip._Delim) || _Traits::eq(*_Ptr, _Manip._Escape))
      ++_Size;        // count escapes

  ios_base::iostate _State = ios_base::goodbit;
  _Sizet _Pad = _Ostr.width() <= 0 || (_Sizet)_Ostr.width() <= _Size
                ? 0 : (_Sizet)_Ostr.width() - _Size;
  const typename _Myos::sentry _Ok(_Ostr);

  if (!_Ok)
    _State |= ios_base::badbit;
  else
  {       // state okay, insert characters
    _TRY_IO_BEGIN
    if ((_Ostr.flags() & ios_base::adjustfield) != ios_base::left)
      for (; 0 < _Pad; --_Pad)        // pad on left
        if (_Traits::eq_int_type(_Traits::eof(),
                                 _Ostr.rdbuf()->sputc(_Ostr.fill())))
        {       // insertion failed, quit
          _State |= ios_base::badbit;
          break;
        }

    if (   _State == ios_base::goodbit
        && _Traits::eq_int_type(_Traits::eof(),
                         _Ostr.rdbuf()->sputc(_Manip._Delim))) // put delimiter
      _State |= ios_base::badbit;

    for (const _Elem *_Ptr = _Manip._Ptr; _Ptr != _Last; ++_Ptr)
    {       // put (possibly escaped) element
      if (   (   _Traits::eq(*_Ptr, _Manip._Delim)
              || _Traits::eq(*_Ptr, _Manip._Escape))
          && _State == ios_base::goodbit
          && _Traits::eq_int_type(_Traits::eof(),
                           _Ostr.rdbuf()->sputc(_Manip._Escape))) // put escape
      {       // insertion failed, quit
        _State |= ios_base::badbit;
        break;
      }
      if (_State == ios_base::goodbit
          && _Traits::eq_int_type(_Traits::eof(),
                                  _Ostr.rdbuf()->sputc(*_Ptr))) // put element
      {       // insertion failed, quit
        _State |= ios_base::badbit;
        break;
      }
    }
    if (_State == ios_base::goodbit
        && _Traits::eq_int_type(_Traits::eof(),
                         _Ostr.rdbuf()->sputc(_Manip._Delim))) // put delimiter
      _State |= ios_base::badbit;

    if (_State == ios_base::goodbit)
      for (; 0 < _Pad; --_Pad)        // pad on right
        if (_Traits::eq_int_type(_Traits::eof(),
                                 _Ostr.rdbuf()->sputc(_Ostr.fill())))
        {       // insertion failed, quit
          _State |= ios_base::badbit;
          break;
        }
    _Ostr.width(0);
    _CATCH_IO_(_Ostr)
  }

  _Ostr.setstate(_State);
  return _Ostr;
}

template<class _Elem,
         class _Traits,
         class _Alloc> inline
basic_ostream<_Elem, _Traits>&
operator<<(basic_ostream<_Elem, _Traits>& _Ostr,
           const _Quote_in<_Elem, _Traits, _Alloc>& _Manip)
{       // put quoted string to output stream
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;
  const _Mystr& _Ref = _Manip._Str;
  return _Ostr << std::quoted(_Ref, _Manip._Delim, _Manip._Escape);
}

// quoted EXTRACTOR
template<class _Elem,
         class _Traits,
         class _Alloc> inline
basic_istream<_Elem, _Traits>& operator>>(
  basic_istream<_Elem, _Traits>& _Istr,
  const _Quote_in<_Elem, _Traits, _Alloc>& _Manip)
{       // get quoted string from input stream
  typedef basic_istream<_Elem, _Traits> _Myis;
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;
  typedef typename _Mystr::size_type _Sizet;

  ios_base::iostate _State = ios_base::goodbit;
  bool _Changed = false;
  const typename _Myis::sentry _Ok(_Istr);

  while (_Ok)
  {       // state okay, extract characters
    _TRY_IO_BEGIN
    _Sizet _Size =    0 < _Istr.width()
                   && (_Sizet)_Istr.width() < _Manip._Str.max_size()
                   ? (_Sizet)_Istr.width() : _Manip._Str.max_size();
    typename _Traits::int_type _Meta = _Istr.rdbuf()->sgetc();
    typename _Traits::int_type _Delim = _Traits::to_int_type(_Manip._Delim);
    typename _Traits::int_type _Escape = _Traits::to_int_type(_Manip._Escape);

    if (!_Traits::eq_int_type(_Meta, _Delim))       // no leading delimiter
      return _Istr >> _Manip._Str;
    _Manip._Str.clear();
    _Meta = _Istr.rdbuf()->snextc();        // discard leading delimiter

    for (; !_Traits::eq_int_type(_Meta, _Delim) && 0 < _Size;
         _Meta = _Istr.rdbuf()->snextc(), --_Size)
      if (_Traits::eq_int_type(_Traits::eof(), _Meta))
      {       // end of file, quit
        _State |= ios_base::eofbit;
        break;
      }
      else if (!_Traits::eq_int_type(_Meta, _Escape))
        _Manip._Str.append(1,
                           _Traits::to_char_type(_Meta));  // add element
      else if (_Traits::eq_int_type(_Traits::eof(),
                                    _Meta = _Istr.rdbuf()->snextc()))
      {       // escaped end of file, quit
        _State |= ios_base::eofbit;
        break;
      }
      else
        _Manip._Str.append(1,
                           _Traits::to_char_type(_Meta)); // add escaped element

    if (!_Traits::eq_int_type(_Meta, _Delim))
      _State |= ios_base::failbit;    // no trailing delimiter, fail
    else
    {       // discard trailing delimiter
      _Changed = true;
      _Istr.rdbuf()->snextc();
    }
    _CATCH_IO_(_Istr)
    break;
  }

  _Istr.width(0);
  if (!_Changed)
    _State |= ios_base::failbit;
  _Istr.setstate(_State);
  return _Istr;
}

// TEMPLATE STRUCT _Smanip
template<class _Arg>
struct _Smanip
{       // store function pointer and argument value
  _Smanip(void (*_Left)(ios_base&, _Arg), _Arg _Val)
    : _Pfun(_Left), _Manarg(_Val)
  {       // construct from function pointer and argument value
  }

  void (*_Pfun)(ios_base&, _Arg); // the function pointer
  _Arg _Manarg;   // the argument value
};

template<class _Elem,
         class _Traits,
         class _Arg> inline
basic_istream<_Elem, _Traits>& operator>>(
  basic_istream<_Elem, _Traits>& _Istr, const _Smanip<_Arg>& _Manip)
{       // extract by calling function with input stream and argument
  (*_Manip._Pfun)(_Istr, _Manip._Manarg);
  return _Istr;
}

template<class _Elem,
         class _Traits,
         class _Arg> inline
basic_ostream<_Elem, _Traits>& operator<<(
  basic_ostream<_Elem, _Traits>& _Ostr, const _Smanip<_Arg>& _Manip)
{       // insert by calling function with output stream and argument
  (*_Manip._Pfun)(_Ostr, _Manip._Manarg);
  return _Ostr;
}

// INSTANTIATIONS
_Smanip<ios_base::fmtflags> resetiosflags(ios_base::fmtflags);
_Smanip<ios_base::fmtflags> setiosflags(ios_base::fmtflags);
_Smanip<int> setbase(int);
_Smanip<streamsize> setprecision(streamsize);
_Smanip<streamsize> setw(streamsize);

} /* namespace std */

#endif /* _IOMANIP_ */

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