/** @file stkstream.h
* This is an TNet C++ Library header.
*/
#ifndef TNet_StkStream_h
#define TNet_StkStream_h
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <stdexcept>
#pragma GCC system_header
//extern const char * gpFilterWldcrd;
namespace TNet
{
/**
* @brief Expands a filter command into a runnable form
*
* This function replaces all occurances of *filter_wldcard in *command by
* *filename
*/
//char * ExpandFilterCommand(const char *command, const char *filename);
/**
* @brief Provides a layer of compatibility for C/POSIX.
*
* This GNU extension provides extensions for working with standard C
* FILE*'s and POSIX file descriptors. It must be instantiated by the
* user with the type of character used in the file stream, e.g.,
* basic_stkbuf<char>.
*/
template<
typename _CharT,
typename _Traits = std::char_traits<_CharT>
>
class basic_stkbuf : public std::basic_filebuf<_CharT, _Traits>
{
public:
typedef basic_stkbuf<_CharT, _Traits> this_type;
// Types:
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;
typedef std::size_t size_t;
public:
/// @{
/// Type of streambuffer
static const unsigned int t_undef = 0; ///< undefined
static const unsigned int t_file = 1; ///< file stream
static const unsigned int t_pipe = 2; ///< pipe
static const unsigned int t_filter = 4; ///< filter
static const unsigned int t_stdio = 8; ///< standard input/output
/// @}
public:
/**
* deferred initialization
*/
basic_stkbuf() : std::basic_filebuf<_CharT, _Traits>(),
mFilename(""), mpFilePtr(0), mStreamType(t_undef){}
/**
* @brief Opens a stream.
* @param fName The name of the file.
* @param m The open mode flags.
* @param pFilter The pFilter command to use
* @return @c this on success, NULL on failure
*
* If a file is already open, this function immediately fails.
* Otherwise it tries to open the file named @a s using the flags
* given in @a mode.
*
* [Table 92 gives the relation between openmode combinations and the
* equivalent fopen() flags, but the table has not been copied yet.]
*/
basic_stkbuf(const char* fName, std::ios_base::openmode m, const char* pFilter="");
/**
* @return The underlying FILE*.
*
* This function can be used to access the underlying "C" file pointer.
* Note that there is no way for the library to track what you do
* with the file, so be careful.
*/
std::__c_file*
file() { return this->_M_file.file(); }
/**
* @return The underlying FILE*.
*
* This function can be used to access the underlying "C" file pointer.
* Note that there is no way for the library to track what you do
* with the file, so be careful.
*/
std::__c_file*
fp() { return this->_M_file.file(); }
/**
* @brief Opens an external file.
* @param fName The name of the file.
* @param m The open mode flags.
* @param pFilter The pFilter command to use
* @return @c this on success, NULL on failure
*
* If a file is already open, this function immediately fails.
* Otherwise it tries to open the file named @a s using the flags
* given in @a mode.
*
* [Table 92 gives the relation between openmode combinations and the
* equivalent fopen() flags, but the table has not been copied yet.]
*/
this_type*
open(const char* pFName, std::ios_base::openmode m, const char* pFilter="");
/**
* @brief Closes the currently associated file.
* @return @c this on success, NULL on failure
*
* If no file is currently open, this function immediately fails.
*
* If a "put buffer area" exists, @c overflow(eof) is called to flush
* all the characters. The file is then closed.
*
* If any operations fail, this function also fails.
*/
this_type*
close();
/**
* Closes the external data stream if the file descriptor constructor
* was used.
*/
virtual
~basic_stkbuf()
{close();};
/// Returns the file name
const std::string
name() const
{return mFilename;}
private:
/// converts the ios::xxx mode to stdio style
static void open_mode(std::ios_base::openmode __mode, int&, int&, char* __c_mode);
/**
* @param __f An open @c FILE*.
* @param __mode Same meaning as in a standard filebuf.
* @param __size Optimal or preferred size of internal buffer, in chars.
* Defaults to system's @c BUFSIZ.
*
* This method associates a file stream buffer with an open
* C @c FILE*. The @c FILE* will not be automatically closed when the
* basic_stkbuf is closed/destroyed. It is equivalent to one of the constructors
* of the stdio_filebuf class defined in GNU ISO C++ ext/stdio_filebuf.h
*/
void superopen(std::__c_file* __f, std::ios_base::openmode __mode,
size_t __size = static_cast<size_t>(BUFSIZ));
private:
/// Holds the full file name
std::string mFilename;
std::ios_base::openmode mMode;
/// Holds a pointer to the main FILE structure
FILE * mpFilePtr;
/// tells what kind of stream we use (stdio, file, pipe)
unsigned int mStreamType;
};
/**
* @brief This extension wraps stkbuf stream buffer into the standard ios class.
*
* This class is inherited by (i/o)stkstream classes which make explicit use of
* the custom stream buffer
*/
template<
typename _CharT,
typename _Traits = std::char_traits<_CharT>
>
class BasicStkIos
: virtual public std::basic_ios<_CharT, _Traits>
{
public:
typedef basic_stkbuf <_CharT,_Traits> StkBufType;
BasicStkIos()
: mBuf()
{ this->init(&mBuf) ;};
BasicStkIos(const char* fName, std::ios::openmode m, const char* pFilter)
: mBuf(fName, m, pFilter)
{ this->init(&mBuf) ; }
StkBufType*
rdbuf()
{ return &mBuf; }
protected:
StkBufType mBuf;
};
/**
* @brief Controlling input for files.
*
* This class supports reading from named files, using the inherited
* functions from std::istream. To control the associated
* sequence, an instance of std::stkbuf is used.
*/
template<
typename _CharT,
typename _Traits = std::char_traits<_CharT>
>
class BasicIStkStream
: public BasicStkIos<_CharT, _Traits>,
public std::basic_istream<_CharT, _Traits>
{
public:
typedef BasicStkIos<_CharT, _Traits> BasicStkIosType;
typedef std::basic_istream<_CharT,_Traits> IStreamType;
// Constructors:
/**
* @brief Default constructor.
*
* Initializes @c mBuf using its default constructor, and passes
* @c &sb to the base class initializer. Does not open any files
* (you haven't given it a filename to open).
*/
BasicIStkStream()
: BasicStkIosType(),
IStreamType(BasicStkIosType::rdbuf())
{};
/**
* @brief Create an input file stream.
* @param fName String specifying the filename.
* @param m Open file in specified mode (see std::ios_base).
* @param pFilter String specifying pFilter command to use on fName
*
* @c ios_base::in is automatically included in
* @a m.
*
* Tip: When using std::string to hold the filename, you must use
* .c_str() before passing it to this constructor.
*/
BasicIStkStream(const char* pFName, std::ios::openmode m=std::ios::out, const char* pFilter="")
: BasicStkIosType(),
IStreamType(BasicStkIosType::rdbuf())
{this->open(pFName, std::ios::in, pFilter);}
~BasicIStkStream()
{
this->close();
}
/**
* @brief Opens an external file.
* @param s The name of the file.
* @param mode The open mode flags.
* @param pFilter The pFilter command to use
*
* Calls @c std::basic_filebuf::open(s,mode|in). If that function
* fails, @c failbit is set in the stream's error state.
*
* Tip: When using std::string to hold the filename, you must use
* .c_str() before passing it to this constructor.
*/
void open(const char* pFName, std::ios::openmode m=std::ios::in, const char* pFilter = "")
{
if (!BasicStkIosType::mBuf.open(pFName, m | std::ios_base::in, pFilter)) {
this->setstate(std::ios_base::failbit);
}
else {
// Closing an fstream should clear error state
BasicStkIosType::clear();
}
}
/**
* @brief Returns true if the external file is open.
*/
bool is_open() const {return BasicStkIosType::mBuf.is_open();}
/**
* @brief Closes the stream
*/
void close() {BasicStkIosType::mBuf.close();}
/**
* @brief Returns the filename
*/
const std::string name() const {return BasicStkIosType::mBuf.name();}
/// Returns a pointer to the main FILE structure
std::__c_file*
file() {return BasicStkIosType::mBuf.file();}
/// Returns a pointer to the main FILE structure
std::__c_file*
fp() {return BasicStkIosType::mBuf.fp();}
// /**
// * @brief Reads a single line
// *
// * This is a specialized function as std::getline does not provide a way to
// * read multiple end-of-line symbols (we need both '\n' and EOF to delimit
// * the line)
// */
// void
// GetLine(string& rLine);
}; // class BasicIStkStream
/**
* @brief Controlling output for files.
*
* This class supports reading from named files, using the inherited
* functions from std::ostream. To control the associated
* sequence, an instance of TNet::stkbuf is used.
*/
template<
typename _CharT,
typename _Traits = std::char_traits<_CharT>
>
class BasicOStkStream
: public BasicStkIos<_CharT, _Traits>,
public std::basic_ostream<_CharT, _Traits>
{
public:
typedef BasicStkIos<_CharT, _Traits> BasicStkIosType;
typedef std::basic_ostream<_CharT,_Traits> OStreamType;
// Constructors:
/**
* @brief Default constructor.
*
* Initializes @c sb using its default constructor, and passes
* @c &sb to the base class initializer. Does not open any files
* (you haven't given it a filename to open).
*/
BasicOStkStream()
: BasicStkIosType(),
OStreamType(BasicStkIosType::rdbuf())
{};
/**
* @brief Create an output file stream.
* @param fName String specifying the filename.
* @param m Open file in specified mode (see std::ios_base).
* @param pFilter String specifying pFilter command to use on fName
*
* @c ios_base::out|ios_base::trunc is automatically included in
* @a mode.
*
* Tip: When using std::string to hold the filename, you must use
* .c_str() before passing it to this constructor.
*/
BasicOStkStream(const char* pFName, std::ios::openmode m=std::ios::out, const char* pFilter="")
: BasicStkIosType(),
OStreamType(BasicStkIosType::rdbuf())
{this->open(pFName, std::ios::out, pFilter);}
/**
* @brief Opens an external file.
* @param fName The name of the file.
* @param m The open mode flags.
* @param pFilter String specifying pFilter command to use on fName
*
* Calls @c std::basic_filebuf::open(s,mode|out). If that function
* fails, @c failbit is set in the stream's error state.
*
* Tip: When using std::string to hold the filename, you must use
* .c_str() before passing it to this constructor.
*/
void open(const char* pFName, std::ios::openmode m=std::ios::out, const char* pFilter="")
{
if (!BasicStkIosType::mBuf.open(pFName, m | std::ios_base::out, pFilter))
this->setstate(std::ios_base::failbit);
else
// Closing an fstream should clear error state
this->clear();
}
/**
* @brief Returns true if the external file is open.
*/
bool is_open() const
{ return BasicStkIosType::mBuf.is_open();}
/**
* @brief Closes the stream
*/
void close()
{ BasicStkIosType::mBuf.close();}
/**
* @brief Returns the filename
*/
const std::string name() const
{ return BasicStkIosType::mBuf.name();}
/// Returns a pointer to the main FILE structure
std::__c_file*
file()
{ return BasicStkIosType::mBuf.file();}
/// Returns a pointer to the main FILE structure
std::__c_file*
fp()
{ return BasicStkIosType::mBuf.fp();}
}; // class BasicOStkStream
/**
* We define some implicit stkbuf class
*/
///@{
#ifndef _GLIBCPP_USE_WCHAR_T
typedef BasicOStkStream<char> OStkStream;
typedef BasicOStkStream<wchar_t> WOStkStream;
typedef BasicIStkStream<char> IStkStream;
typedef BasicIStkStream<wchar_t> WIStkStream;
#else
typedef BasicOStkStream<char> WOStkStream;
typedef BasicOStkStream<wchar_t> WOStkStream;
typedef BasicIStkStream<char> WIStkStream;
typedef BasicIStkStream<wchar_t> WIStkStream;
#endif
/// @}
/*
template<class T,class char_type> inline
BasicOStkStream<char_type>& operator << (BasicOStkStream<char_type> &ostream, const std::vector<T> &vec){
ostream << vec.size() << std::endl;
for(size_t i=0;i<vec.size();i++) ostream << vec[i];
return ostream;
}
template<class T,class char_type> inline BasicIStkStream<char_type> &operator >> (BasicIStkStream<char_type> &istream, std::vector<T> &vec){
size_t sz;
istream >> sz; if(!istream.good()){ throw std::runtime_error(std::string("Error reading to vector of [something]: stream bad\n")); }
int ch = istream.get(); if(ch!='\n' || !istream.good()){ throw std::runtime_error(std::string("Expecting newline after vector size, got " + (std::string)(char)ch));} // TODO: This code may not be right for wchar.
vec.resize(sz);
for(size_t i=0;i<vec.size();i++) istream >> vec[i];
return istream;
}*/
template<class T> inline
std::ostream & operator << (std::ostream &ostream, const std::vector<T> &vec){
ostream << vec.size() << std::endl;
for(size_t i=0;i<vec.size();i++) ostream << vec[i] << "\n"; // '\n' is necessary in case item is atomic e.g. a number.
return ostream;
}
template<class T> inline std::istream& operator >> (std::istream &istream, std::vector<T> &vec){
size_t sz;
istream >> sz; if(!istream.good()){ throw std::runtime_error(std::string("Error reading to vector of [something]: stream bad\n")); }
// int ch = istream.get(); if(ch!='\n' || !istream.good()){ throw std::runtime_error(std::string("Expecting newline after vector size\n")); // TODO: This code may not be right for wchar.
vec.resize(sz);
for(size_t i=0;i<vec.size();i++) istream >> vec[i];
return istream;
}
template<class T> inline
std::ostream & operator << (std::ostream &ostream, const std::list<T> &lst){
ostream << lst.size() << std::endl;
typename std::list<T>::iterator it;
for(it = lst.begin(); it != lst.end(); it++)
ostream << *it << "\n"; // '\n' is necessary in case item is atomic e.g. a number.
return ostream;
}
template<class T> inline std::istream& operator >> (std::istream &istream, std::list<T> &lst){
size_t sz;
istream >> sz; if(!istream.good()){ throw std::runtime_error(std::string("Error reading to list of [something]: stream bad\n")); }
lst.resize(sz);
typename std::list<T>::iterator it;
for(it = lst.begin(); it != lst.end(); it++)
istream >> *it;
return istream;
}
}; // namespace TNet
using TNet::operator >>;
using TNet::operator <<;
# include "StkStream.tcc"
// TNet_StkStream_h
#endif