/* Copyright (C) 2001, 2004 and 2009 to 2013 Chris Vine

 The following code declares classes to read from and write to
 Unix file descriptors.

 The whole work comprised in files fdstream.h and fdstream.tpp is
 distributed by Chris Vine under the GNU Lesser General Public License
 as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the c++-gtk-utils
   sub-directory); if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

However, it is not intended that the object code of a program whose
source code instantiates a template from this file or uses macros or
inline functions (of any length) should by reason only of that
instantiation or use be subject to the restrictions of use in the GNU
Lesser General Public License.  With that in mind, the words "and
macros, inline functions and instantiations of templates (of any
length)" shall be treated as substituted for the words "and small
macros and small inline functions (ten lines or less in length)" in
the fourth paragraph of section 5 of that licence.  This does not
affect any other reason why object code may be subject to the
restrictions in that licence (nor for the avoidance of doubt does it
affect the application of section 2 of that licence to modifications
of the source code in this file).

The attach(), close() and xsputn() methods added by Chris Vine, 2001.
All the classes were rewritten, and also provided in template form for
wide characters, by Chris Vine 2004.
*/

/**
 * @defgroup fdstreams fdstreams
 *
 * \#include <c++-gtk-utils/fdstream.h>
 *
 * The c++-gtk-utils library contains classes providing streambuffers
 * and stream objects for unix file descriptors.
 *
 * By default, like the fstream::fstream(int fd) and
 * fstream::attach(int fd) extensions in libstdc++-v2, the destructors
 * of these classes close the file descriptors concerned, which helps
 * exception safety (the attach() method will also close any previous
 * file descriptor).  If this behaviour is not wanted, pass 'false' as
 * the second argument of fdostream/fdistream constructor or of the
 * attach() method.  This will enable the same file descriptor to be
 * used successively for, say, reading and writing, or to be shared
 * between fdistream and fdostream objects (but if the file descriptor
 * represents a device providing random access, such as a local file
 * on the filesystem, which has been opened for both reading and
 * writing, the special precautions described under @ref
 * FdRandomAccessAnchor "fdstreams and random access" are required).
 *
 * Here are some examples of use:
 *
 * @code
 *   // the safe creation of a temporary file with standard iostreams
 *   char filename[] = "/tmp/myprog-XXXXXX";
 *   Cgu::fdostream ostrm;
 *   int fd = mkstemp(filename);
 *   if (fd != -1) {
 *     ostrm.attach(fd); // take ownership of the file descriptor
 *     ostrm << "Temporary file text" << std::endl;
 *   }
 *   else {
 *     std::cerr << "Can't open temporary file " << filename
 *               << ", please check permissions" << std::endl;
 *   }
 *
 *   --------------------------------------------------------------------
 *
 *   // mimic std::cout but explicitly use UNIX stdout
 *   Cgu::fdostream out(1, false); // don't take ownership of the file descriptor
 *   out << "Hello" << std::endl;
 *
 *   --------------------------------------------------------------------
 *
 *   // read line delimited text from a pipe until it is closed by the
 *   // writer: assume 'fd' is the read file descriptor of the pipe
 *   Cgu::fdistream istrm(fd); // take ownership of the read file descriptor
 *   std::string line;
 *   while (std::getline(istrm, line)) {
 *     [ ... do something with the read text ... ]
 *   }
 * @endcode
 *
 *
 * @note 1. Users cannot (except by derivation) use the virtual
 * protected methods of the streambuffer classes, including xsgetn()
 * and xsputn().  Instead, if they want direct access to the
 * streambuffer other than through the fdostreamfdistream methods (or
 * their wide stream equivalents), they should use the public
 * forwarding functions provided by std::streambuf base class.
 * @note 2. These streambuffers and stream objects are not copiable.
 *
 * Buffering
 * ---------
 *
 * The streambuffer classes provide buffering for both input and
 * output, although output buffering can be switched off using the
 * set_buffered() method.
 *
 * The streambuf classes provide a block read and write in xsgetn()
 * and xsputn(), which will be called by the read() and write()
 * methods (and some other output operators) inherited by (w)fdistream
 * and (w)fdostream from std::basic_istream and std::basic_ostream.
 * They operate (after appropriately vacating and resetting the
 * buffers) by doing a block read and write by calling Unix read() and
 * write() and are very efficient for large block reads (those
 * significantly exceeding the buffer size).  If users want all reads
 * and writes to go through the buffers, by using
 * std::basic_streambuf<>::xsputn() and
 * std::basic_streambuf<>::xsgetn() then the symbol
 * FDSTREAM_USE_STD_N_READ_WRITE can be defined.  (libstdc++-3
 * provides efficient inbuilt versions of these std::basic_streambuf
 * functions for block reads not significantly larger than the buffer
 * size, provided output buffering has not been turned off by the
 * set_buffered() method of the output streambuffer or stream object.)
 *
 * @b Note @b however that if FDSTREAM_USE_STD_N_READ_WRITE is to be
 * defined, it is best to do this by textually amending the installed
 * fdstream.h header file rather than by defining the symbol in user
 * code before that file is included.  This will ensure that all
 * source files in a program which include the fdstream.h header are
 * guaranteed to see the same definitions so that the C++ standard's
 * one-definition-rule is complied with.
 *
 * One possible case for defining that symbol is where the user wants
 * to use the tie() method of (w)fdistream (inherited from
 * std::basic_ios) to procure flushing of an output stream before
 * extraction from an input stream is made by (w)fdistream::read().
 * Such flushing might not occur where a call to (w)fdistream::read()
 * is made unless FDSTREAM_USE_STD_N_READ_WRITE is defined, because an
 * implementation is permitted to defer such flushing until
 * underflow() occurs, and the block read by (w)fdistream::read(), as
 * forwarded to xsgetn(), will never invoke underflow() if that symbol
 * is not defined.  (Having said that, any basic_istream
 * implementation which does defer output flushing until underflow()
 * is called makes tie() unusable anyway for a number of purposes,
 * because the time of flushing would become dependent on whether a
 * read request can be satisfied by what is already in the buffers.)
 *
 * 4 characters are stored and available for putback.  However, if the
 * symbol FDSTREAM_USE_STD_N_READ_WRITE is not defined, then a call to
 * fdinbuf::xsgetn() via (w)fdistream::read() with a request for less
 * than 4 characters will result in less than 4 characters available
 * for putback (if these block read methods obtain some characters but
 * less than 4, only the number of characters obtained by them is
 * guaranteed to be available for putback).
 *
 * @anchor FdRandomAccessAnchor
 * fdstreams and random access
 * ---------------------------
 *
 * For file descriptors representing files which offer random access,
 * the classes in this c++-gtk-utils library implement the tellg(),
 * tellp(), seekg() and seekp() random access methods.
 *
 * The presence of buffering does not impede this where a file
 * descriptor is only opened for reading or only opened for writing.
 * However, it presents complications if a fdistream object and a
 * fdostream object (or their wide stream equivalents) reference the
 * same file descriptor on a file which offers random access and which
 * is opened for both reading and writing.  To prevent the file
 * pointer getting out of sync with the buffers maintained by the
 * fdistream and fdostream objects, if the last operation carried out
 * on the fdostream/fdistream pair was a write then, if the output
 * stream is set as buffered (the default), before the first read
 * operation thereafter is made on the pair or a call to seekg() is
 * made, the fdostream object must be flushed by calling
 * std::ostream::flush() or by using the std::flush manipulator (or
 * setting the std::ios_base::unitbuf flag).  If the last operation on
 * the pair (having, say, the names 'ostr' and 'istr') was a read,
 * then before the first write operation thereafter is made on the
 * pair, or a call to seekp() is made, the user must call
 * istr.seekg(istr.tellg()) in order to synchronise the logical and
 * actual file positions, or if the user does not want to maintain the
 * current logical file position, make some other call to seekg() on
 * 'istr' which does not comprise only seekg(0, std::ios_base::cur).
 * This requirement to call seekg() when moving from reading to
 * writing applies whether or not the output stream is buffered.  It
 * similarly applies to the wide stream classes.
 *
 * Note that the tie() method of (w)fdistream (inherited from
 * std::basic_ios) cannot reliably to used to procure output flushing
 * of a (w)fdostream object before a read is made, unless
 * FDSTREAM_USE_STD_N_READ_WRITE is defined before fdstream.h is
 * \#include'd, for the reason mentioned under "Buffering" above.
 *
 * Where a file is to be opened for both reading and writing and more
 * automatic tying of input and output is wanted, the Cgu::giostream
 * classes or their wide stream equivalents can be used in conjunction
 * with GIO streams.
 *
 * None of these restrictions applies to file descriptors opened for
 * reading and writing which represent devices for which the operating
 * system does not maintain file pointers, such as sockets.  They can
 * be attached to a fdostream and fdistream object without any special
 * precautions being taken, other than the normal step of calling
 * fdostream::flush() (or using the std::flush manipulator) to flush
 * the output buffer to the socket if the user needs to know that that
 * has happened (or setting output buffering off with the
 * set_buffered() method).  In summary, on a socket, a read does not
 * automatically flush the output buffer: it is for the user to do
 * that.  Note also that only one of the stream objects should be set
 * to manage the file descriptor, and this should normally be the
 * output stream as it may have characters to flush when closing.
 *
 * A (w)fdostream and (w)fdistream object should not reference the
 * same file descriptor on any file on a file system which permits
 * read-write opening of files and reports itself as not supporting
 * random access, but which in fact maintains a file position pointer
 * which is shared for reading and writing.  This might apply to some
 * network file systems.  The best rule to apply is not to reference
 * the same file descriptor on a (w)fdostream and (w)fdistream object
 * if the device is not a socket, unless can_seek() returns true.
 *
 * Wide streams and endianness
 * ---------------------------
 *
 * This library provides typedef'ed instances of the template classes
 * for wchar_t, char16_t and char32_t characters.  With the wide
 * stream ostream classes and wide character output streambuffer
 * classes, wide characters are written out in the native endian
 * format of the writing machine.  Special steps need to be taken if
 * the text which is sent for output might be read by machines with a
 * different endianness.
 *
 * No such special steps are required where the wide character classes
 * are used with temporary files, pipes, fifos, unix domain sockets
 * and network sockets on localhost, because in those cases they will
 * be read by the same machine that writes; but they are required
 * where sockets communicate with other computers over a network or
 * when writing to files which may be distributed to and read by other
 * computers with different endianness.
 *
 * Where wide characters are to be exported to other machines, one
 * useful approach is to convert to and from UTF-8 with
 * Utf8::uniwide_from_utf8(), Utf8::uniwide_to_utf8(),
 * Utf8::wide_from_utf8() or Utf8::wide_to_utf8(), and to use
 * fdostream/fdistream with the converted text.  Alternatively, the
 * wgostream, wgistream and wgiostream classes (and their char16_t and
 * char32_t equivalents) can be used for the purposes of attaching a
 * UTF-8 converter directly to a GIO stream.  (Those classes also
 * enable a UTF-32LE to UTF-32BE converter, and vice versa, to be
 * attached to an output stream for the purpose of writing out UTF-32
 * in other than native endianness, and similarly as regards UTF-16.)
 *
 * Instead of converting exported text to UTF-8, another approach is
 * to use a byte order marker (BOM) as the first character of the wide
 * stream output.  UCS permits a BOM character to be inserted,
 * comprising static_cast<wchar_t>(0xfeff),
 * static_cast<char16_t>(0xfeff) or static_cast<char32_t>(0xfeff), at
 * the beginning of the output to the wide character stream.  At the
 * receiving end, this will appear as 0xfffe (UTF-16) or 0xfffe0000
 * (UTF-32) to a big endian machine with 8 bit char type if the text
 * is little endian, or to a little endian machine with big endian
 * text, so signaling a need to undertake byte swapping of text read
 * from the stream.  Another alternative is to label the physical
 * medium conveying the file as UTF-16LE, UTF-16BE, UTF-32LE or
 * UTF-32BE, as the case may be, in which case a BOM character should
 * not be prepended.
 *
 * Where it is established by either means that the input stream
 * requires byte swapping, the wide character input stream and wide
 * character input streambuffer classes have a set_byteswap() member
 * function which should be called on opening the input stream as soon
 * as it has been established that byte swapping is required.  Once
 * this function has been called with an argument of 'true', all
 * further calls to stream functions which provide characters will
 * provide those characters with the correct native endianness.
 * Calling set_byteswap() on the narrow stream fdistream or fdinbuf
 * objects has no effect (byte order is irrelevant to narrow streams).
 *
 * Here is an example of such use in a case where sizeof(wchar_t) is
 * 4:
 *
 * @code
 *   int fd = open("filename", O_RDONLY);
 *   Cgu::wfdistream input;
 *   if (fd != -1)
 *     input.attach(fd); // take ownership of the file descriptor
 *   else {
 *     std::cerr << "Can't open file 'filename', "
 *               << "please check permissions" << std::endl;
 *     return;
 *   }
 *   wchar_t item;
 *   input.get(item);
 *   if (!input) {
 *     std::cerr << "File 'filename' is empty" << std::endl;
 *     return;
 *   }
 *   if (item == static_cast<wchar_t>(0xfffe0000))
 *     input.set_byteswap(true);
 *   else if (item != static_cast<wchar_t>(0xfeff)) {
 *     // calling set_byteswap() will manipulate the buffers, so
 *     // either call putback() before we call set_byteswap(), or
 *     // call unget() instead
 *     input.putback(item);
 *     // the first character is not a BOM character so assume big endian
 *     // format, and byte swap if the local machine is little endian
 *  #if G_BYTE_ORDER == G_LITTLE_ENDIAN
 *     input.set_byteswap(true);
 *  #endif
 *   }
 *   [ ... do something with the input file ... ]
 * @endcode
 *
 * Other wide stream issues
 * ------------------------
 *
 * basic_fdostream, basic_fdoutbuf, basic_fdistream and basic_fdinbuf
 * objects can be instantiated for any integer type which has an
 * appropriate traits class provided for it which has the copy(),
 * eof(), eq_int_type(), move(), not_eof() and to_int_type() static
 * member functions.  The integer type could in fact have any size,
 * but the set_byteswap() methods for basic_fdistream and
 * basic_fdinbuf will only have an effect if its size is either 2 or 4.
 * Typedef'ed instances of the classes are provided by the library
 * for characters of type wchar_t, char16_t and char32_t.
 *
 * Memory slices
 * -------------
 *
 * If the library is compiled with the
 * \--with-glib-memory-slices-compat or
 * \--with-glib-memory-slices-no-compat configuration option,
 * basic_fdoutbuf constructs its output buffer using glib memory
 * slices.  In such a case, although it is safe in a multi-threaded
 * program if glib < 2.32 is installed to construct a static
 * basic_fdoutbuf/basic_fdostream object in global namespace (that is,
 * prior to g_thread_init() being called) by means of the default
 * constructor and/or a file descriptor argument of -1, it is not safe
 * if it is constructed with a valid file descriptor.  If glib >= 2.32
 * is installed, global objects with memory slices are safe in all
 * circumstances.  (Having said that, it would be highly unusual to
 * have global output stream objects.)  This issue does not affect
 * basic_fdinbuf/basic_fdistream objects, which do not construct their
 * buffers dynamically.
 */

#ifndef CGU_FDSTREAM_H
#define CGU_FDSTREAM_H

// see above for what this does
//#define FDSTREAM_USE_STD_N_READ_WRITE 1

#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <istream>
#include <ostream>
#include <streambuf>
#include <algorithm>
#include <string>
#include <cstddef>

#include <c++-gtk-utils/shared_handle.h>
#include <c++-gtk-utils/cgu_config.h>

namespace Cgu {

/*
The following convenience typedefs appear at the end of this file:
typedef basic_fdinbuf<char> fdinbuf;
typedef basic_fdoutbuf<char> fdoutbuf;
typedef basic_fdistream<char> fdistream;
typedef basic_fdostream<char> fdostream;
typedef basic_fdinbuf<wchar_t> wfdinbuf;
typedef basic_fdoutbuf<wchar_t> wfdoutbuf;
typedef basic_fdistream<wchar_t> wfdistream;
typedef basic_fdostream<wchar_t> wfdostream;
typedef basic_fdinbut<char16_t> u16fdinbuf;
typedef basic_fdoutbuf<char16_t> u16fdoutbuf;
typedef basic_fdistream<char16_t> u16fdistream;
typedef basic_fdostream<char16_t> u16fdostream;
typedef basic_fdinbut<char32_t> u32fdinbuf;
typedef basic_fdoutbuf<char32_t> u32fdoutbuf;
typedef basic_fdistream<char32_t> u32fdistream;
typedef basic_fdostream<char32_t> u32fdostream;
*/


/**
 * @headerfile fdstream.h c++-gtk-utils/fdstream.h
 * @brief Output stream buffer for unix file descriptors
 * @sa fdstreams
 * @ingroup fdstreams
 *
 * This class provides an output stream buffer for unix file
 * descriptors.  It does the buffering for the basic_fdostream stream
 * class.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_fdoutbuf: public std::basic_streambuf<charT, Traits> {

public:
  typedef charT char_type;
  typedef Traits traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;

private:
  int fd;    // file descriptor
  bool manage;

  static const int buf_size = 1024;   // size of the data write buffer
#if defined(CGU_USE_GLIB_MEMORY_SLICES_COMPAT) || defined(CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT)
  ScopedHandle<char_type*,
               GSliceFreeSize<buf_size * sizeof(char_type)>> buffer;
#else
  ScopedHandle<char_type*> buffer;
#endif
  int flush_buffer();

protected:
/**
 * This method will not throw.  fdstreams do not offer concurrent
 * access from multiple threads to the same stream object, and if that
 * is required users should provide their own synchronisation.
 */
  virtual int sync();

/**
 * This method will not throw unless std::basic_streambuf<>::sputc()
 * throws, which it would not do on any sane implementation.  This
 * means that the output functions of stream objects which have this
 * streambuffer as a member will not throw unless the underlying
 * functions of the std::basic_ostream class throw, which they would
 * not normally do unless they have been required to do so on failbit,
 * badbit or eofbit being set by an explicit call to the exceptions()
 * method of that class.  fdstreams do not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 */
  virtual int_type overflow(int_type);

#ifndef FDSTREAM_USE_STD_N_READ_WRITE
/**
 * This method will not throw.  This means that the output functions
 * of stream objects which have this streambuffer as a member will not
 * throw unless the underlying functions of the std::basic_ostream
 * class throw, which they would not normally do unless they have been
 * required to do so on failbit, badbit or eofbit being set by an
 * explicit call to the exceptions() method of that class.  fdstreams
 * do not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 */
  virtual std::streamsize xsputn(const char_type*, std::streamsize);
#endif

/**
 * This method provides random access on output devices that support
 * it, so supporting the tellp() and seekp() methods of the
 * basic_fdostream class.  Any output buffer will be flushed.  This
 * method does not throw, but if it returns pos_type(off_type(-1)) to
 * indicate failure, it will cause the seekp() or tellp() methods of
 * the relevant stream class to throw std::ios_base::failure if such
 * an exception has been required by an explicit call to the
 * exceptions() method of that class (but not otherwise).  fdstreams
 * do not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 *
 * @param off The offset to be applied to the 'way' argument when
 * seeking.  It is a signed integer type, and on wide character
 * streams is dimensioned as the number of wchar_t units not the
 * number of bytes (that is, it is bytes/sizeof(char_type)).
 *
 * @param way The file position to which the 'off' argument is to be
 * applied (either std::ios_base::beg, std::ios_base::cur or
 * std::ios_base::end).
 *
 * @param m The required read/write status of the file descriptor
 * attached to this streambuffer for this method to attempt a seek.
 * As this is an output streambuffer, the argument should have the
 * std::ios_base::out bit set.  Provided that bit is set, it doesn't
 * matter if others are also set.
 *
 * @return If the seek succeeds, a std::char_traits<T>::pos_type
 * object representing the new stream position of the streambuffer
 * after the seek.  (This type is std::streampos for narrow character
 * (char) streams, std::wstreampos for wide character (wchar_t)
 * streams, std::u16streampos for the char16_t type and
 * std::u32streampos for the char32_t type.)  If the seek failed,
 * pos_type(off_type(-1)) is returned.
 */
  virtual pos_type seekoff(off_type off,
			   std::ios_base::seekdir way,
			   std::ios_base::openmode m = std::ios_base::in | std::ios_base::out);

/**
 * This method provides random access on output devices that support
 * it, so supporting the seekp() method of the basic_fdostream class.
 * It is equivalent to seekoff(off_type(p), std::ios_base::beg, m).
 * Any output buffer will be flushed.  This method does not throw, but
 * if it returns pos_type(off_type(-1)) to indicate failure, it will
 * cause the seekp() method of the relevant stream class to throw
 * std::ios_base::failure if such an exception has been required by an
 * explicit call to the exceptions() method of that class (but not
 * otherwise).  fdstreams do not offer concurrent access from multiple
 * threads to the same stream object, and if that is required users
 * should provide their own synchronisation.
 *
 * @param p The absolute position to which the seek is to be made,
 * obtained by a previous call to seekoff() or to this method.
 *
 * @param m The required read/write status of the file descriptor
 * attached to this streambuffer for this method to attempt a seek.
 * As this is an output stream buffer, the argument should have the
 * std::ios_base::out bit set.  Provided that bit is set, it doesn't
 * matter if others are also set.
 *
 * @return If the seek succeeds, a std::char_traits<T>::pos_type
 * object representing the new stream position of the streambuffer
 * after the seek.  (This type is std::streampos for narrow character
 * (char) streams, std::wstreampos for wide character (wchar_t)
 * streams, std::u16streampos for the char16_t type and
 * std::u32streampos for the char32_t type.)  If the seek failed,
 * pos_type(off_type(-1)) is returned.
 */
  virtual pos_type seekpos(pos_type p,
			   std::ios_base::openmode m = std::ios_base::in | std::ios_base::out);
public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_fdoutbuf(const basic_fdoutbuf&) = delete;

/**
 * This class cannot be copied.  The assignment operator is deleted.
 */
  basic_fdoutbuf& operator=(const basic_fdoutbuf&) = delete;

 /**
  * As this constructor has default argument values, it is also a
  * default constructor.  fdstreams do not offer concurrent access
  * from multiple threads to the same stream object, and if that is
  * required users should provide their own synchronisation.
  *
  * @param fd_ The file descriptor to be attached to the streambuffer,
  * or -1 to attach it latter with the attach_fd() method.
  *
  * @param manage_ Whether the streambuffer should manage the file
  * descriptor (that is, close it in its destructor or when a new file
  * descriptor is attached).
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if fd_ >= 0, memory is exhausted and the system
  * throws on such exhaustion (unless the library has been installed
  * using the \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf throws.
  */
  basic_fdoutbuf(int fd_ = -1, bool manage_ = true);

/**
 * The destructor does not throw.
 */
  virtual ~basic_fdoutbuf();

 /**
  * Attach a new file descriptor to the streambuffer (and close any
  * file descriptor at present managed by it).  If output buffering
  * was previously switched off, it is switched back on again.
  * fdstreams do not offer concurrent access from multiple threads to
  * the same stream object, and if that is required users should
  * provide their own synchronisation.
  *
  * @param fd_ The new file descriptor to be attached to the
  * streambuffer.
  *
  * @param manage_ Whether the streambuffer should manage the new file
  * descriptor (that is, close it in its destructor or when a further
  * file descriptor is attached).
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * fd_ >= 0, output buffering had previously been switched off,
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  */
  void attach_fd(int fd_, bool manage_ = true);

 /**
  * Close the file descriptor at present attached to the streambuffer
  * (if any).  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return From version 1.2.6, 'true' if the close succeeded, 'false'
  * if an error arose (including in a case where no descriptor has
  * been attached or it has already been closed).  Prior to version
  * 1.2.6, this method had void return type.
  */
  bool close_fd();

 /**
  * Get the file descriptor at present attached to the streambuffer
  * (if any).  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The file descriptor at present attached to the
  * streambuffer, or -1 if none has been attached
  */
  int get_fd() const {return fd;}

/**
 * Stops output buffering if 'buffered' is false, or reverts to
 * buffering if buffering has previously been switched off and
 * 'buffered' is true.  Buffering is on by default for any newly
 * created fdoutbuf object and any newly attached file descriptor.  If
 * buffering is turned off, all characters at present in the buffers
 * which are stored for output are flushed.  This method has no effect
 * if no file descriptor has yet been attached to this streambuffer.
 * Switching output buffering off is similar in effect to setting the
 * std::ios_base::unitbuf flag in the relevant fdostream object, but
 * is slightly more efficient.  fdstreams do not offer concurrent
 * access from multiple threads to the same stream object, and if that
 * is required users should provide their own synchronisation.
 *
 * @param buffered 'false' if buffering is to be turned off, 'true' if
 * it is to be turned back on.
 *
 * @exception std::bad_alloc This method will throw std::bad_alloc if
 * 'buffered' is true, output buffering had previously been switched
 * off, memory is exhausted and the system throws on such exhaustion
 * (unless the library has been installed using the
 * \--with-glib-memory-slices-compat or
 * \--with-glib-memory-slices-no-compat configuration option, in which
 * case glib will terminate the program if it is unable to obtain
 * memory from the operating system).
 */
  void set_buffered(bool buffered);

/**
 * This method indicates whether the output device concerned supports
 * random access, so that a call to seekoff() or seekpos() can
 * succeed.  This method does not throw.  fdstreams do not offer
 * concurrent access from multiple threads to the same stream object,
 * and if that is required users should provide their own
 * synchronisation.
 *
 * @return true if random access is supported, otherwise false.  The
 * result is only meaningful if a file descriptor has been attached to
 * this streambuffer.
 */
  bool can_seek() const;

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};

/**
 * @headerfile fdstream.h c++-gtk-utils/fdstream.h
 * @brief Output stream for unix file descriptors
 * @sa fdstreams
 * @ingroup fdstreams
 *
 * This class provides standard ostream services for unix file
 * descriptors.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_fdostream: public std::basic_ostream<charT, Traits> {

  basic_fdoutbuf<charT, Traits> buf;

public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_fdostream(const basic_fdostream&);

/**
 * This class cannot be copied.  The assignment operator is deleted.
 */
  basic_fdostream& operator=(const basic_fdostream&);

 /**
  * This is the constructor which passes a file descriptor.  fdstreams
  * do not offer concurrent access from multiple threads to the same
  * stream object, and if that is required users should provide their
  * own synchronisation.
  *
  * @param fd The file descriptor to be attached to the stream object.
  *
  * @param manage Whether the stream should manage the file descriptor
  * (that is, close it in its destructor or when a new file descriptor
  * is attached).
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if fd >= 0, memory is exhausted and the system
  * throws on such exhaustion (unless the library has been installed
  * using the \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf or
  * std::basic_ostream throws.
  */
  // using uniform initializer syntax here confuses doxygen
  basic_fdostream(int fd, bool manage = true): std::basic_ostream<charT, Traits>(0),
                                               buf(fd, manage) { // pass the descriptor at construction
    this->rdbuf(&buf);
  }

 /**
  * With this constructor, the file descriptor must be attached later
  * with the attach() method.  It will not throw unless the
  * constructor of std::basic_streambuf or std::basic_ostream throws.
  * fdstreams do not offer concurrent access from multiple threads to
  * the same stream object, and if that is required users should
  * provide their own synchronisation.
 */
  // using uniform initializer syntax here confuses doxygen
  basic_fdostream(): std::basic_ostream<charT, Traits>(0) {      // attach the descriptor later
    this->rdbuf(&buf);
  }

 /**
  * Attach a new file descriptor to the stream object (and close any
  * file descriptor at present managed by it).  From version 1.2.6, if
  * output buffering was previously switched off, it is switched back
  * on again.  Also from version 1.2.6, if any stream state flags were
  * set (eofbit, failbit or badbit), they will be cleared by a call to
  * clear() (prior to that version, the user had to call clear()
  * explicitly to do so).  If this method closes a file descriptor at
  * present managed by it and the close fails, failbit is not set and
  * no exception will be thrown.  Accordingly, if the user needs to
  * know whether there was an error in this method closing any
  * descriptor, she should call close() explicitly before calling this
  * method.  fdstreams do not offer concurrent access from multiple
  * threads to the same stream object, and if that is required users
  * should provide their own synchronisation.
  *
  * @param fd The new file descriptor to be attached to the stream
  * object.
  *
  * @param manage Whether the stream object should manage the new file
  * descriptor (that is, close it in its destructor or when a further
  * file descriptor is attached).
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * fd >= 0, output buffering had previously been switched off, memory
  * is exhausted and the system throws on such exhaustion (unless the
  * library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  */
  void attach(int fd, bool manage = true) {buf.attach_fd(fd, manage); this->clear();}

 /**
  * Close the file descriptor at present attached to the stream object
  * (if any).  From version 1.2.6, if the close fails, the failbit
  * will be set with setstate(std::ios_base::failbit).  fdstreams do
  * not offer concurrent access from multiple threads to the same
  * stream object, and if that is required users should provide their
  * own synchronisation.
  *
  * @exception std::ios_base::failure From version 1.2.6, this
  * exception will be thrown if an error arises on closing the
  * descriptor and such an exception has been required by a call to
  * the exceptions() method of this class (inherited from
  * std::basic_ios<>).  No exception will be thrown if exceptions()
  * has not been called.
  */
  void close() {if (!buf.close_fd()) this->setstate(std::ios_base::failbit);}

 /**
  * Get the file descriptor at present attached to the stream object
  * (if any).  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The file descriptor at present attached to the
  * stream object, or -1 if none has been attached
  */
  int filedesc() const {return buf.get_fd();}

/**
 * Stops output buffering if 'buffered' is false, or reverts to
 * buffering if buffering has previously been switched off and
 * 'buffered' is true.  Buffering is on by default for any newly
 * created fdostream object and any newly attached file descriptor.
 * If buffering is turned off, all characters at present in the
 * buffers which are stored for output are flushed.  This method has
 * no effect if no file descriptor has yet been attached.  Switching
 * output buffering off is similar in effect to setting the
 * std::ios_base::unitbuf flag, but is slightly more efficient.
 * fdstreams do not offer concurrent access from multiple threads to
 * the same stream object, and if that is required users should
 * provide their own synchronisation.
 *
 * @param buffered 'false' if buffering is to be turned off, 'true' if
 * it is to be turned back on.
 *
 * @exception std::bad_alloc This method will throw std::bad_alloc if
 * 'buffered' is true, output buffering had previously been switched
 * off, memory is exhausted and the system throws on such exhaustion
 * (unless the library has been installed using the
 * \--with-glib-memory-slices-compat or
 * \--with-glib-memory-slices-no-compat configuration option, in which
 * case glib will terminate the program if it is unable to obtain
 * memory from the operating system).
 */
  void set_buffered(bool buffered) {buf.set_buffered(buffered);}

/**
 * This method indicates whether the output device concerned supports
 * random access, so that a call to tellp() or seekp() can succeed.
 * Note that in the seekp(off_type off, ios_base::seekdir dir)
 * variant, on wide character streams the 'off' argument is
 * dimensioned as the number of wchar_t units not the number of bytes
 * (that is, it is bytes/sizeof(char_type)).  This method does not
 * throw.  fdstreams do not offer concurrent access from multiple
 * threads to the same stream object, and if that is required users
 * should provide their own synchronisation.
 *
 * @return true if random access is supported, otherwise false.  The
 * result is only meaningful if a file descriptor has been attached to
 * this stream.
 */
  bool can_seek() const {return buf.can_seek();}

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};


/**
 * @headerfile fdstream.h c++-gtk-utils/fdstream.h
 * @brief Input stream buffer for unix file descriptors
 * @sa fdstreams
 * @ingroup fdstreams
 *
 * This class provides an input stream buffer for unix file
 * descriptors.  It does the buffering for the basic_fdistream stream
 * class.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_fdinbuf : public std::basic_streambuf<charT, Traits> {

public:
  typedef charT char_type;
  typedef Traits traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;

private:
  int fd;    // file descriptor
  bool manage;
  bool byteswap;

  static const int putback_size = 4;     // size of putback area
  static const int buf_size = 1024;      // size of the data buffer
  char_type buffer[buf_size + putback_size];  // data buffer
  void reset();
  static void swap_element(char_type&);

protected:
/**
 * This method will not throw.  This means that the input functions of
 * stream objects which have this streambuffer as a member will not
 * throw unless the underlying functions of the std::basic_istream
 * class throw, which they would not normally do unless they have been
 * required to do so on failbit, badbit or eofbit being set by an
 * explicit call to the exceptions() method of that class.  fdstreams
 * do not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 */
  virtual int_type underflow();

#ifndef FDSTREAM_USE_STD_N_READ_WRITE
/**
 * This method will not throw.  This means that the input functions of
 * stream objects which have this streambuffer as a member will not
 * throw unless the underlying functions of the std::basic_istream
 * class throw, which they would not normally do unless they have been
 * required to do so on failbit, badbit or eofbit being set by an
 * explicit call to the exceptions() method of that class.  fdstreams
 * do not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 */
  virtual std::streamsize xsgetn(char_type*, std::streamsize);
#endif
/**
 * This method provides random access on input devices that support
 * it, so supporting the tellg() and seekg() methods of the
 * basic_fdistream class.  This method does not throw, but if it
 * returns pos_type(off_type(-1)) to indicate failure, it will cause
 * the seekg() or tellg() methods of the relevant stream class to
 * throw std::ios_base::failure if such an exception has been required
 * by an explicit call to the exceptions() method of that class (but
 * not otherwise).  fdstreams do not offer concurrent access from
 * multiple threads to the same stream object, and if that is required
 * users should provide their own synchronisation.
 *
 * @param off The offset to be applied to the 'way' argument when
 * seeking.  It is a signed integer type, and on wide character
 * streams is dimensioned as the number of wchar_t units not the
 * number of bytes (that is, it is bytes/sizeof(char_type)).
 *
 * @param way The file position to which the 'off' argument is to be
 * applied (either std::ios_base::beg, std::ios_base::cur or
 * std::ios_base::end).
 *
 * @param m The required read/write status of the file descriptor
 * attached to this streambuffer for this method to attempt a seek.
 * As this is an input streambuffer, the argument should have the
 * std::ios_base::in bit set.  Provided that bit is set, it doesn't
 * matter if others are also set.
 *
 * @return If the seek succeeds, a std::char_traits<T>::pos_type
 * object representing the new stream position of the streambuffer
 * after the seek.  (This type is std::streampos for narrow character
 * (char) streams, std::wstreampos for wide character (wchar_t)
 * streams, std::u16streampos for the char16_t type and
 * std::u32streampos for the char32_t type.)  If the seek failed,
 * pos_type(off_type(-1)) is returned.
 */
  virtual pos_type seekoff(off_type off,
			   std::ios_base::seekdir way,
			   std::ios_base::openmode m = std::ios_base::in | std::ios_base::out);

/**
 * This method provides random access on input devices that support
 * it, so supporting the seekg() method of the basic_fdistream class.
 * It is equivalent to seekoff(off_type(p), std::ios_base::beg, m).
 * This method does not throw, but if it returns
 * pos_type(off_type(-1)) to indicate failure, it will cause the
 * seekg() method of the relevant stream class to throw
 * std::ios_base::failure if such an exception has been required by an
 * explicit call to the exceptions() method of that class (but not
 * otherwise).  fdstreams do not offer concurrent access from multiple
 * threads to the same stream object, and if that is required users
 * should provide their own synchronisation.
 *
 * @param p The absolute position to which the seek is to be made,
 * obtained by a previous call to seekoff() or to this method.
 *
 * @param m The required read/write status of the file descriptor
 * attached to this streambuffer for this method to attempt a seek.
 * As this is an input streambuffer, the argument should have the
 * std::ios_base::in bit set.  Provided that bit is set, it doesn't
 * matter if others are also set.
 *
 * @return If the seek succeeds, a std::char_traits<T>::pos_type
 * object representing the new stream position of the streambuffer
 * after the seek.  (This type is std::streampos for narrow character
 * (char) streams, std::wstreampos for wide character (wchar_t)
 * streams, std::u16streampos for the char16_t type and
 * std::u32streampos for the char32_t type.)  If the seek failed,
 * pos_type(off_type(-1)) is returned.
 */
  virtual pos_type seekpos(pos_type p,
			   std::ios_base::openmode m = std::ios_base::in | std::ios_base::out);
public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_fdinbuf(const basic_fdinbuf&) = delete;

/**
 * This class cannot be copied.  The assignment operator is deleted.
 */
  basic_fdinbuf& operator=(const basic_fdinbuf&) = delete;

 /**
  * As this constructor has default argument values, it is also a
  * default constructor.  It does not throw unless the constructor of
  * std::basic_streambuf throws.  fdstreams do not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @param fd_ The file descriptor to be attached to the streambuffer,
  * or -1 to attach it latter with the attach() method.
  *
  * @param manage_ Whether the streambuffer should manage the file
  * descriptor (that is, close it in its destructor or when a new file
  * descriptor is attached).
  */
  basic_fdinbuf(int fd_ = -1, bool manage_ = true);

/**
 * The destructor does not throw.
 */
  virtual ~basic_fdinbuf();

 /**
  * Attach a new file descriptor to the streambuffer (and close any
  * file descriptor at present managed by it).  In the case of a wide
  * character streambuffer, it also switches off byte swapping, if it
  * was previously on.  This method does not throw.  fdstreams do not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @param fd_ The new file descriptor to be attached to the
  * streambuffer.
  *
  * @param manage_ Whether the streambuffer should manage the new file
  * descriptor (that is, close it in its destructor or when a further
  * file descriptor is attached).
  */
  void attach_fd(int fd_, bool manage_ = true);

 /**
  * Close the file descriptor at present attached to the streambuffer
  * (if any).  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return From version 1.2.6, 'true' if the close succeeded, 'false'
  * if an error arose (including in a case where no descriptor has
  * been attached or it has already been closed).  Prior to version
  * 1.2.6, this method had void return type.
  */
  bool close_fd();

 /**
  * Get the file descriptor at present attached to the streambuffer
  * (if any).  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The file descriptor at present attached to the
  * streambuffer, or -1 if none has been attached
  */
  int get_fd() const {return fd;}

 /**
  * Causes the streambuffer to swap bytes in the incoming text, so as
  * to convert big endian text to little endian text, or little endian
  * text to big endian text.  It is called by the user in response to
  * finding a byte order marker (BOM) 0xfffe (UTF-16) or 0xfffe0000
  * (UTF-32) as the first character of a newly opened file/stream, or
  * if the user knows by some other means that the native endianness
  * of the machine doing the reading differs from the endianness of
  * the file/stream being read.  This only has effect on wide
  * character input streambuffers (for example, wfdinbuf), and not the
  * fdinbuf narrow character stream buffer.  This method does not
  * throw.  fdstreams do not offer concurrent access from multiple
  * threads to the same stream object, and if that is required users
  * should provide their own synchronisation.
  *
  * @param swap 'true' if byte swapping is to be turned on, 'false' if
  * it is to be turned off.  This will affect all characters extracted
  * from the streambuffer after this call is made.  If any previously
  * extracted character is to be putback(), it must be put back before
  * this function is called (or unget() should be called instead) to
  * avoid a putback mismatch, because this call will byte-swap
  * anything already in the buffers.  (Characters extracted after the
  * call to this method may be putback normally.)
  */
  void set_byteswap(bool swap);

/**
 * This method indicates whether the input device concerned supports
 * random access, so that a call to seekoff() or seekpos() can
 * succeed.  This method does not throw.  fdstreams do not offer
 * concurrent access from multiple threads to the same stream object,
 * and if that is required users should provide their own
 * synchronisation.
 *
 * @return true if random access is supported, otherwise false.  The
 * result is only meaningful if a file descriptor has been attached to
 * this streambuffer.
 */
  bool can_seek() const;

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};

/**
 * @headerfile fdstream.h c++-gtk-utils/fdstream.h
 * @brief Input stream for unix file descriptors
 * @sa fdstreams
 * @ingroup fdstreams
 *
 * This class provides standard istream services for unix file
 * descriptors.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_fdistream : public std::basic_istream<charT, Traits> {

  basic_fdinbuf<charT , Traits> buf;

public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_fdistream(const basic_fdistream&) = delete;

/**
 * This class cannot be copied.  The assignment operator is deleted.
 */
  basic_fdistream& operator=(const basic_fdistream&) = delete;

 /**
  * This is the constructor which passes a file descriptor.  It will
  * not throw unless the constructor of std::basic_streambuf or
  * std::basic_istream throws.  fdstreams do not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @param fd The file descriptor to be attached to the stream object.
  *
  * @param manage Whether the stream should manage the file descriptor
  * (that is, close it in its destructor or when a new file descriptor
  * is attached).
  */
  // using uniform initializer syntax here confuses doxygen
  basic_fdistream (int fd, bool manage = true) : std::basic_istream<charT, Traits>(0),
                                                 buf(fd, manage) { // pass the descriptor at construction
    this->rdbuf(&buf);
  }

 /**
  * With this constructor, the file descriptor must be attached later
  * with the attach() method.  It will not throw unless the
  * constructor of std::basic_streambuf or std::basic_istream throws.
  * fdstreams do not offer concurrent access from multiple threads to
  * the same stream object, and if that is required users should
  * provide their own synchronisation.
  */
  // using uniform initializer syntax here confuses doxygen
  basic_fdistream () : std::basic_istream<charT, Traits>(0) {      // attach the descriptor later
    this->rdbuf(&buf);
  }

 /**
  * Attach a new file descriptor to the stream object (and close any
  * file descriptor at present managed by it).  In the case of wide
  * character streams, it also switches off byte swapping, if it was
  * previously on.  From version 1.2.6, if any stream state flags were
  * set (eofbit, failbit or badbit), they will be cleared by a call to
  * clear() (prior to that version, the user had to call clear()
  * explicitly to do so).  If this method closes a file descriptor at
  * present managed by it and the close fails, failbit is not set and
  * no exception will be thrown.  Accordingly, if the user needs to
  * know whether there was an error in this method closing any
  * descriptor, she should call close() explicitly before calling this
  * method.  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @param fd The new file descriptor to be attached to the stream
  * object.
  *
  * @param manage Whether the stream object should manage the new file
  * descriptor (that is, close it in its destructor or when a further
  * file descriptor is attached).
  */
  void attach(int fd, bool manage = true) {buf.attach_fd(fd, manage); this->clear();}

 /**
  * Close the file descriptor at present attached to the stream object
  * (if any).  From version 1.2.6, if the close fails, the failbit
  * will be set with setstate(std::ios_base::failbit).  fdstreams do
  * not offer concurrent access from multiple threads to the same
  * stream object, and if that is required users should provide their
  * own synchronisation.
  *
  * @exception std::ios_base::failure From version 1.2.6, this
  * exception will be thrown if an error arises on closing the
  * descriptor and such an exception has been required by a call to
  * the exceptions() method of this class (inherited from
  * std::basic_ios<>).  No exception will be thrown if exceptions()
  * has not been called.
  */
  void close() {if (!buf.close_fd()) this->setstate(std::ios_base::failbit);}

 /**
  * Get the file descriptor at present attached to the stream object
  * (if any).  This method does not throw.  fdstreams do not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The file descriptor at present attached to the
  * stream object, or -1 if none has been attached
  */
  int filedesc() const {return buf.get_fd();}

 /**
  * Causes the underlying stream buffer to swap bytes in the incoming
  * text, so as to convert big endian text to little endian text, or
  * little endian text to big endian text.  It is called in response
  * to finding a byte order marker (BOM) 0xfffe (UTF-16) or 0xfffe0000
  * (UTF-32) as the first character of a newly opened file/stream, or
  * if the user knows by some other means that the native endianness
  * of the machine doing the reading differs from the endianness of
  * the file/stream being read.  This only has effect on wide
  * character istreams (for example, wfdistream), and not the
  * fdistream narrow character stream.  This method does not throw.
  * fdstreams do not offer concurrent access from multiple threads to
  * the same stream object, and if that is required users should
  * provide their own synchronisation.
  *
  * @param swap 'true' if byte swapping is to be turned on, 'false' if
  * it is to be turned off.  This will affect all characters extracted
  * from the underlying streambuffer after this call is made.  If any
  * previously extracted character is to be putback(), it must be put
  * back before this function is called (or unget() should be called
  * instead) to avoid a putback mismatch, because this call will
  * byte-swap anything already in the buffers.  (Characters extracted
  * after the call to this method may be putback normally.)
  */
  void set_byteswap(bool swap) {buf.set_byteswap(swap);}

/**
 * This method indicates whether the input device concerned supports
 * random access, so that a call to tellg() or seekg() can succeed.
 * Note that in the seekg(off_type off, ios_base::seekdir dir)
 * variant, on wide character streams the 'off' argument is
 * dimensioned as the number of wchar_t units not the number of bytes
 * (that is, it is bytes/sizeof(char_type)).  This method does not
 * throw.  fdstreams do not offer concurrent access from multiple
 * threads to the same stream object, and if that is required users
 * should provide their own synchronisation.
 *
 * @return true if random access is supported, otherwise false.  The
 * result is only meaningful if a file descriptor has been attached to
 * this stream.
 */
  bool can_seek() const {return buf.can_seek();}

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};

/**
 * @defgroup fdstreams fdstreams
 */
/**
 * @typedef fdinbuf.
 * @brief Input stream buffer for file descriptors for char type
 * @ingroup fdstreams
 */
typedef basic_fdinbuf<char> fdinbuf;

/**
 * @typedef fdoutbuf.
 * @brief Output stream buffer for file descriptors for char type
 * @ingroup fdstreams
 */
typedef basic_fdoutbuf<char> fdoutbuf;

/**
 * @typedef fdistream.
 * @brief Input stream for file descriptors for char type
 * @anchor fdistreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdistream<char> fdistream;

/**
 * @typedef fdostream.
 * @brief Output stream for file descriptors for char type
 * @anchor fdostreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdostream<char> fdostream;

/**
 * @typedef wfdinbuf.
 * @brief Input stream buffer for file descriptors for wchar_t type
 * @ingroup fdstreams
 */
typedef basic_fdinbuf<wchar_t> wfdinbuf;

/**
 * @typedef wfdoutbuf.
 * @brief Output stream buffer for file descriptors for wchar_t type
 * @ingroup fdstreams
 */
typedef basic_fdoutbuf<wchar_t> wfdoutbuf;

/**
 * @typedef wfdistream.
 * @brief Input stream for file descriptors for wchar_t type
 * @anchor wfdistreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdistream<wchar_t> wfdistream;

/**
 * @typedef wfdostream.
 * @brief Output stream for file descriptors for wchar_t type
 * @anchor wfdostreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdostream<wchar_t> wfdostream;

/**
 * @typedef u16fdinbuf.
 * @brief Input stream buffer for file descriptors for char16_t type
 * @ingroup fdstreams
 */
 typedef basic_fdinbuf<char16_t> u16fdinbuf;

/**
 * @typedef u16fdoutbuf.
 * @brief Output stream buffer for file descriptors for char16_t type
 * @ingroup fdstreams
 */
typedef basic_fdoutbuf<char16_t> u16fdoutbuf;

/**
 * @typedef u16fdistream.
 * @brief Input stream for file descriptors for char16_t type
 * @anchor u16fdistreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdistream<char16_t> u16fdistream;

/**
 * @typedef u16fdostream.
 * @brief Output stream for file descriptors for char16_t type
 * @anchor u16fdostreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdostream<char16_t> u16fdostream;

/**
 * @typedef u32fdinbuf.
 * @brief Input stream buffer for file descriptors for char32_t type
 * @ingroup fdstreams
 */
typedef basic_fdinbuf<char32_t> u32fdinbuf;

/**
 * @typedef u32fdoutbuf.
 * @brief Output stream buffer for file descriptors for char32_t type
 * @ingroup fdstreams
 */
typedef basic_fdoutbuf<char32_t> u32fdoutbuf;

/**
 * @typedef u32fdistream.
 * @brief Input stream for file descriptors for char32_t type
 * @anchor u32fdistreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdistream<char32_t> u32fdistream;

/**
 * @typedef u32fdostream.
 * @brief Output stream for file descriptors for char32_t type
 * @anchor u32fdostreamAnchor
 * @ingroup fdstreams
 */
typedef basic_fdostream<char32_t> u32fdostream;

} // namespace Cgu

#include <c++-gtk-utils/fdstream.tpp>

#endif /*CGU_FDSTREAM_H*/
