// Quick and dirty stringstream implementation.
// Copyright (c) 1999 Pablo Halpern
// http://www.halpernwightsoftware.com
//
// Permission is granted to use, modify and redistribute this code freely,
// provided the above copyright is retained in the source code.

// This is an incomplete, not-fully-conforming implementation of the
// stringstream class. It is written for the egcs 1.1.2 compiler, which
// does not come with with its own stringstream implementation. It may be
// adapted for other compilers.
//
// This implementation should be useful for must common uses, but there are no
// guarantees. I have not attempted to optimize for effiency, nor have
// I tested this extensively. Feedback and bug fixes appreciated.
// mail-to:phalpern@newview.org

#ifndef sstream_dot_h
#define sstream_dot_h 1

#include <iostream>
#include <string>

namespace std {

  class stringbuf : public streambuf
  {
  public:
    // types
    typedef char		char_type;
    typedef int			int_type;
    typedef streampos		pos_type;
    typedef streamoff		off_type;

    // constructors
    explicit stringbuf(ios::openmode which = ios::in | ios::out);
    explicit stringbuf(const string& s,
		       ios::openmode which = ios::in | ios::out);

    // get and set
    string str() const;
    void str(const string& s);

  protected:
    virtual int_type underflow();
    virtual int_type uflow();
    virtual int_type overflow(int_type c = EOF);

    virtual int_type pbackfail(int_type c = EOF);

    // setbuf implemented as a no-op for now
    virtual streambuf* setbuf(char_type*, int) { return this; }

    virtual pos_type seekoff(off_type off, ios::seekdir way,
			     ios::openmode which = ios::in | ios::out);
    virtual pos_type seekpos(pos_type sp,
			     ios::openmode which = ios::in | ios::out);

  private:
    string		theString_;
    ios::openmode	mode_;

    string::size_type	gnext, pnext;

    static int_type eof() { return EOF; }
  };

  class istringstream : public istream
  {
  public:
    // types
    typedef char		char_type;
    typedef int			int_type;
    typedef streampos		pos_type;
    typedef streamoff		off_type;

    // constructors
    istringstream(ios::openmode which = ios::in);
    istringstream(const string& s, ios::openmode which = ios::in);

    // members
    stringbuf* rdbuf() const { return const_cast<stringbuf*>(&sb_); }

    string str() const { return sb_.str(); }
    void str(const string& s) { sb_.str(s); }

  private:
    stringbuf sb_;
  };
  
  class ostringstream : public ostream
  {
  public:
    // types
    typedef char		char_type;
    typedef int			int_type;
    typedef streampos		pos_type;
    typedef streamoff		off_type;

    // constructors
    ostringstream(ios::openmode which = ios::out);
    ostringstream(const string& s, ios::openmode which = ios::out);

    // members
    stringbuf* rdbuf() const { return const_cast<stringbuf*>(&sb_); }

    string str() const { return sb_.str(); }
    void str(const string& s) { sb_.str(s); }

  private:
    stringbuf sb_;
  };

  class stringstream : public iostream
  {
  public:
    // types
    typedef char		char_type;
    typedef int			int_type;
    typedef streampos		pos_type;
    typedef streamoff		off_type;

    // constructors
    stringstream(ios::openmode which = ios::in | ios::out);
    stringstream(const string& s,
		 ios::openmode which = ios::in | ios::out);

    // members
    stringbuf* rdbuf() const { return const_cast<stringbuf*>(&sb_); }

    string str() const { return sb_.str(); }
    void str(const string& s) { sb_.str(s); }

  private:
    stringbuf sb_;
  };

} // end namespace std

#ifdef SSTREAM_INLINE
#undef SSINLINE
#define SSINLINE inline
#include "sstream.cc"
#endif

#endif /* sstream_dot_h */
