// xiosbase internal header (from <ios>) -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _XIOSBASE_
#define _XIOSBASE_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <xlocale>
#include <system_error>

#define _OPENPROT      0666

namespace std {

#define _IOSskipws     0x0001
#define _IOSunitbuf    0x0002
#define _IOSuppercase  0x0004
#define _IOSshowbase   0x0008
#define _IOSshowpoint  0x0010
#define _IOSshowpos    0x0020
#define _IOSleft       0x0040
#define _IOSright      0x0080
#define _IOSinternal   0x0100
#define _IOSdec        0x0200
#define _IOSoct        0x0400
#define _IOShex        0x0800
#define _IOSscientific 0x1000
#define _IOSfixed      0x2000

#define _IOShexfloat   0x3000  // added with TR1

#define _IOSboolalpha  0x4000
#define _IOS_Stdio     0x8000

#define _IOS_Nocreate  0x40
#define _IOS_Noreplace 0x80
#define _IOSbinary     0x20

// TEMPLATE CLASS _Iosb
template<class _Dummy>
class _Iosb
{       // define templatized bitmask/enumerated types, instantiate on demand
public:
  enum _Dummy_enum {_Dummy_enum_val = 1}; // don't ask
  enum _Fmtflags : unsigned short
  {       // constants for formatting options
    _Fmtmask = 0xffff, _Fmtzero = 0
  };

  static constexpr _Fmtflags skipws      = (_Fmtflags)_IOSskipws;
  static constexpr _Fmtflags unitbuf     = (_Fmtflags)_IOSunitbuf;
  static constexpr _Fmtflags uppercase   = (_Fmtflags)_IOSuppercase;
  static constexpr _Fmtflags showbase    = (_Fmtflags)_IOSshowbase;
  static constexpr _Fmtflags showpoint   = (_Fmtflags)_IOSshowpoint;
  static constexpr _Fmtflags showpos     = (_Fmtflags)_IOSshowpos;
  static constexpr _Fmtflags left        = (_Fmtflags)_IOSleft;
  static constexpr _Fmtflags right       = (_Fmtflags)_IOSright;
  static constexpr _Fmtflags internal    = (_Fmtflags)_IOSinternal;
  static constexpr _Fmtflags dec         = (_Fmtflags)_IOSdec;
  static constexpr _Fmtflags oct         = (_Fmtflags)_IOSoct;
  static constexpr _Fmtflags hex         = (_Fmtflags)_IOShex;
  static constexpr _Fmtflags scientific  = (_Fmtflags)_IOSscientific;
  static constexpr _Fmtflags fixed       = (_Fmtflags)_IOSfixed;

  static constexpr _Fmtflags hexfloat    = (_Fmtflags)_IOShexfloat;
                                               // added with TR1 (not in C++0X)

  static constexpr _Fmtflags boolalpha   = (_Fmtflags)_IOSboolalpha;
  static constexpr _Fmtflags _Stdio      = (_Fmtflags)_IOS_Stdio;
  static constexpr _Fmtflags adjustfield = (_Fmtflags)(_IOSleft
                                                    | _IOSright | _IOSinternal);
  static constexpr _Fmtflags basefield   = (_Fmtflags)(  _IOSdec
                                                       | _IOSoct | _IOShex);
  static constexpr _Fmtflags floatfield  = (_Fmtflags)(  _IOSscientific
                                                       | _IOSfixed);

  enum _Iostate : unsigned char
  {       // constants for stream states
    _Statmask = 0x17
  };

  static constexpr _Iostate goodbit = (_Iostate)0x0;
  static constexpr _Iostate eofbit  = (_Iostate)0x1;
  static constexpr _Iostate failbit = (_Iostate)0x2;
  static constexpr _Iostate badbit  = (_Iostate)0x4;

  enum _Openmode : unsigned char
  {       // constants for file opening options
    _Openmask = 0xff
  };

  static constexpr _Openmode in         = (_Openmode)0x01;
  static constexpr _Openmode out        = (_Openmode)0x02;
  static constexpr _Openmode ate        = (_Openmode)0x04;
  static constexpr _Openmode app        = (_Openmode)0x08;
  static constexpr _Openmode trunc      = (_Openmode)0x10;
  static constexpr _Openmode _Nocreate  = (_Openmode)_IOS_Nocreate;
  static constexpr _Openmode _Noreplace = (_Openmode)_IOS_Noreplace;
  static constexpr _Openmode binary     = (_Openmode)_IOSbinary;

  enum _Seekdir : unsigned char
  {       // constants for file positioning options
    _Seekbeg,
    _Seekcur,
    _Seekend
  };

  static constexpr _Seekdir beg = _Seekbeg;
  static constexpr _Seekdir cur = _Seekcur;
  static constexpr _Seekdir end = _Seekend;

  enum
  {       // constant for default file opening protection
    _Openprot = _OPENPROT
  };
};

template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::skipws;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::unitbuf;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::uppercase;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::showbase;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::showpoint;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::showpos;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::left;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::right;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::internal;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::dec;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::oct;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::hex;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::scientific;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::fixed;

template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags
_Iosb<_Dummy>::hexfloat;        // added with TR1 (not in C++0X)

template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::boolalpha;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::_Stdio;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::adjustfield;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::basefield;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Fmtflags _Iosb<_Dummy>::floatfield;

template<class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::goodbit;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::eofbit;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::failbit;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Iostate _Iosb<_Dummy>::badbit;

template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::in;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::out;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::ate;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::app;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::trunc;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::_Nocreate;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::_Noreplace;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Openmode _Iosb<_Dummy>::binary;

template<class _Dummy>
const typename _Iosb<_Dummy>::_Seekdir _Iosb<_Dummy>::beg;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Seekdir _Iosb<_Dummy>::cur;
template<class _Dummy>
const typename _Iosb<_Dummy>::_Seekdir _Iosb<_Dummy>::end;

// CLASS ios_base
class ios_base
  : public _Iosb<int>
{       // base class for ios
public:
  #pragma preferred_typedef
  _BITMASK(_Fmtflags, fmtflags);
  #pragma preferred_typedef
  _BITMASK(_Iostate, iostate);
  #pragma preferred_typedef
  _BITMASK(_Openmode, openmode);
  #pragma preferred_typedef
  _BITMASK(_Seekdir, seekdir);

  typedef std::streamoff streamoff;
  typedef std::streampos streampos;

  enum event : unsigned char
  {       // constants for ios events
    erase_event, imbue_event, copyfmt_event
  };

  typedef void (*event_callback)(event, ios_base&, int);
  typedef unsigned int io_state, open_mode, seek_dir;

  // CLASS failure
  class failure
    : public system_error
  {       // base of all iostreams exceptions
  public:
    explicit failure(const string &_Message,
                  const error_code& _Errcode = make_error_code(io_errc::stream))
      : system_error(_Errcode, _Message)
    {       // construct with message
    }

    explicit failure(const char *_Message,
                  const error_code& _Errcode = make_error_code(io_errc::stream))
      : system_error(_Errcode, _Message)
    {       // construct with message
    }
  };

  // CLASS Init
  class Init
  {       // controller for standard-stream initialization
  public:
    Init(); // initialize standard streams on first construction

    ~Init() _NOEXCEPT;      // flush standard streams on last destruction

  private:
    static int _Init_cnt;   // net constructions - destructions
  };

#if 0
  operator void *() const
  {       // test if any stream operation has failed
    return fail() ? 0 : (void *)this;
  }
#endif

  explicit operator bool() const
  {       // test if no stream operation has failed
    return !fail();
  }

  bool operator!() const
  {       // test if any stream operation has failed
    return fail();
  }

  void clear(iostate, bool);    // set state, possibly reraise exception

  void clear(iostate _State = goodbit)
  {       // set state to argument
    clear(_State, false);
  }

  void clear(io_state _State)
  {       // set state to argument, old-style
    clear((iostate)_State);
  }

  iostate rdstate() const
  {       // return stream state
    return _Mystate;
  }

  void setstate(iostate _State, bool _Exreraise)
  {       // merge in state argument, possibly reraise exception
    if (_State != goodbit)
      clear((iostate)((int)rdstate() | (int)_State), _Exreraise);
  }

  void setstate(iostate _State)
  {       // merge in state argument
    if (_State != goodbit)
      clear((iostate)((int)rdstate() | (int)_State), false);
  }

  void setstate(io_state _State)
  {       // merge in state argument, old style
    setstate((iostate)_State);
  }

  bool good() const
  {       // test if no state bits are set
    return rdstate() == goodbit;
  }

  bool eof() const
  {       // test if eofbit is set in stream state
    return (int)rdstate() & (int)eofbit;
  }

  bool fail() const
  {       // test if badbit or failbit is set in stream state
    return ((int)rdstate() & ((int)badbit | (int)failbit)) != 0;
  }

  bool bad() const
  {       // test if badbit is set in stream state
    return ((int)rdstate() & (int)badbit) != 0;
  }

  iostate exceptions() const
  {       // return exception mask
    return _Except;
  }

  void exceptions(iostate _Newexcept)
  {       // set exception mask to argument
    _Except = (iostate)((int)_Newexcept & (int)_Statmask);
    clear(_Mystate);
  }

  void exceptions(io_state _State)
  {       // set exception mask to argument, old style
    exceptions((iostate)_State);
  }

  fmtflags flags() const
  {       // return format flags
    return _Fmtfl;
  }

  fmtflags flags(fmtflags _Newfmtflags)
  {       // set format flags to argument
    fmtflags _Oldfmtflags = _Fmtfl;
    _Fmtfl = (fmtflags)((int)_Newfmtflags & (int)_Fmtmask);
    return _Oldfmtflags;
  }

  fmtflags setf(fmtflags _Newfmtflags)
  {       // merge in format flags argument
    ios_base::fmtflags _Oldfmtflags = _Fmtfl;
    _Fmtfl = (fmtflags)(  (int)_Fmtfl
                        | ((int)_Newfmtflags & (int)_Fmtmask));
    return _Oldfmtflags;
  }

  fmtflags setf(fmtflags _Newfmtflags, fmtflags _Mask)
  {       // merge in format flags argument under mask argument
    ios_base::fmtflags _Oldfmtflags = _Fmtfl;
    _Fmtfl = (fmtflags)(  ((int)_Fmtfl & (int)~_Mask)
                        | ((int)_Newfmtflags & (int)_Mask & (int)_Fmtmask));
    return _Oldfmtflags;
  }

  void unsetf(fmtflags _Mask)
  {       // clear format flags under mask argument
    _Fmtfl = (fmtflags)((int)_Fmtfl & (int)~_Mask);
  }

  streamsize precision() const
  {       // return precision
    return _Prec;
  }

  streamsize precision(streamsize _Newprecision)
  {       // set precision to argument
    streamsize _Oldprecision = _Prec;
    _Prec = _Newprecision;
    return _Oldprecision;
  }

  streamsize width() const
  {       // return width
    return _Wide;
  }

  streamsize width(streamsize _Newwidth)
  {       // set width to argument
    streamsize _Oldwidth = _Wide;
    _Wide = _Newwidth;
    return _Oldwidth;
  }

  #if _DLIB_FULL_LOCALE_SUPPORT
    locale getloc() const
    {       // get locale
      return *_Ploc;
    }

    locale imbue(const locale& _Loc);
  #endif /* _DLIB_FULL_LOCALE_SUPPORT */

  static int xalloc()
  { // allocate new iword/pword index
    // Possibly lock thread to ensure atomicity
    return _Index++;
  }

  long& iword(int _Idx)
  {       // return reference to long element
    return _Findarr(_Idx)._Lo;
  }

  void *& pword(int _Idx)
  {       // return reference to pointer element
    return _Findarr(_Idx)._Vp;
  }

  void register_callback(event_callback _Pfn, int _Idx);

  ios_base& copyfmt(const ios_base& _Other);

  static bool sync_with_stdio(bool _Newsync = true)
  {       // set C/C++ synchronization flag from argument
    // Posibly lock thread to ensure atomicity
    const bool _Oldsync = _Sync;
    _Sync = _Newsync;
    return _Oldsync;
  }

  void swap(ios_base& _Right)
  {       // swap with _Right
    if (this != &_Right)
    {       // different, do the move
      std::swap(_Mystate, _Right._Mystate);
      std::swap(_Except, _Right._Except);
      std::swap(_Fmtfl, _Right._Fmtfl);
      std::swap(_Prec, _Right._Prec);
      std::swap(_Wide, _Right._Wide);

      std::swap(_Arr, _Right._Arr);
      std::swap(_Calls, _Right._Calls);
      #if _DLIB_FULL_LOCALE_SUPPORT
        std::swap(_Ploc, _Right._Ploc);
      #endif
    }
  }

  virtual ~ios_base() _NOEXCEPT;  // destroy the object

  static void _Addstd(ios_base *);        // add standard stream

  size_t _Stdstr; // if > 0 index of standard stream to suppress destruction

protected:
  ios_base()
  {       // default constructor
  }

  void _Init();

private:
  // STRUCT _Iosarray
  struct _Iosarray
  {       // list element for open-ended sparse array of longs/pointers
  public:
    _Iosarray(int _Idx, _Iosarray *_Link)
      : _Next(_Link), _Index(_Idx), _Lo(0), _Vp(0)
    {       // construct node for index _Idx and link it in
    }

    _Iosarray *_Next;       // pointer to next node
    int _Index;     // index of this node
    long _Lo;       // stored long value
    void *_Vp;      // stored pointer value
  };

  // STRUCT _Fnarray
  struct _Fnarray
  {       // list element for open-ended sparse array of event handlers
    _Fnarray(int _Idx, event_callback _Pnew, _Fnarray *_Link)
      : _Next(_Link), _Index(_Idx), _Pfn(_Pnew)
    {       // construct node for index _Idx and link it in
    }

    _Fnarray *_Next;        // pointer to next node
    int _Index;     // index of this node
    event_callback _Pfn;    // pointer to event handler
  };

  void _Callfns(event _Ev);

  _Iosarray& _Findarr(int _Idx);

  void _Tidy();

  iostate _Mystate;       // stream state
  iostate _Except;        // exception mask
  fmtflags _Fmtfl;        // format flags
  streamsize _Prec;       // field precision
  streamsize _Wide;       // field width
  _Iosarray *_Arr;        // pointer to first node of long/pointer array
  _Fnarray *_Calls;       // pointer to first node of call list
  #if _DLIB_FULL_LOCALE_SUPPORT
    locale *_Ploc;  // pointer to locale
  #endif

  static int _Index;      // source of unique indexes for long/pointer array
  static bool _Sync;      // C/C++ synchronization flag (ignored)

public:
  ios_base(const ios_base&) = delete;
  ios_base& operator=(const ios_base&) = delete;
};

_BITMASK_OPS(ios_base::_Fmtflags)
_BITMASK_OPS(ios_base::_Iostate)
_BITMASK_OPS(ios_base::_Openmode)
_BITMASK_OPS(ios_base::_Seekdir)

} /* namespace std */

#endif /* _XIOSBASE_ */

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