// 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

#include <sstream>

#ifndef SSINLINE
#define SSINLINE
#endif

namespace std {
  
SSINLINE stringbuf::stringbuf(ios::openmode which)
  : mode_(which)
{
  str("");
}

SSINLINE stringbuf::stringbuf(const string& s, ios::openmode which)
  : mode_(which)
{
  str(s);
}

SSINLINE string stringbuf::str() const
{
  const_cast<stringbuf*>(this)->sync();
  return theString_;
}

SSINLINE void stringbuf::str(const string& s)
{
  sync();
  theString_ = s;
  gnext = pnext = 0;
}

SSINLINE stringbuf::int_type stringbuf::underflow()
{
  if (gnext < theString_.size())
    return theString_[gnext];
  else
    return eof();
}

SSINLINE stringbuf::int_type stringbuf::uflow()
{
  if (gnext < theString_.size())
    return theString_[gnext++];
  else
    return eof();
}

SSINLINE stringbuf::int_type stringbuf::overflow(int_type c)
{
  if ( ! (mode_ & ios::out))
    return eof();	// Failed (wrong mode)
  
  if (c == eof())
    return ~eof();	// Return a value other than eof()

  if (pnext < theString_.size())
    theString_[pnext] = c;
  else
    theString_ += char_type(c);
  
  ++pnext;
  return c;
}

SSINLINE stringbuf::int_type stringbuf::pbackfail(int_type c)
{
  if (gnext == 0)
    return eof();

  --gnext;

  // If c is last retrieved character or c is eof(), putback undoes last uflow.
  if (theString_[gnext] == c)
    return c;		// Putback same character as last gotten
  else if (c == eof())
    return ~eof();	// Putback eof. Return any non-eof value.
  else
    ++gnext;		// Putback differnt character. Undo putback and fail

  return eof();
}

SSINLINE stringbuf::pos_type stringbuf::seekoff(off_type off, ios::seekdir way,
				       ios::openmode which)
{
  off_type newgoff = 0;
  off_type newpoff = 0;
  
  switch (way)
  {
  case ios::beg: newgoff = newpoff = 0; break;
  case ios::end: newgoff = newpoff = theString_.size(); break;
  case ios::cur:
    if ((which & ios::in) && (which & ios::out))
    {
      // Force error
      newgoff = newpoff = -1;
      off = 0;
    }
    else
    {
      newgoff = gnext;
      newpoff = pnext;
    }
    break;
  }

  newgoff += off;
  newpoff += off;

  if (which & ios::in)
    if (newgoff < 0 || newgoff > theString_.size())
      gnext = pos_type(-1);
    else
      gnext = newgoff;

  if (which & ios::out)
    if (newpoff < 0 || newpoff > theString_.size())
      pnext = pos_type(-1);
    else
      pnext = newpoff;

  if (which & ios::in)
    return gnext;
  else
    return pnext;
}

SSINLINE stringbuf::pos_type stringbuf::seekpos(pos_type sp, ios::openmode which)
{
  if ((which & (ios::in | ios::out)) == 0 || sp > theString_.size())
    return pos_type(-1);

  if (which & ios::in)
    gnext = sp;

  if (which & ios::out)
    pnext = sp;

  return sp;
}

SSINLINE istringstream::istringstream(ios::openmode which)
  : istream(0), sb_(which | ios::in)
{
  istream::rdbuf(&sb_);
}

SSINLINE istringstream::istringstream(const string& s, ios::openmode which)
  : istream(0), sb_(s, which | ios::in)
{
  istream::rdbuf(&sb_);
}

SSINLINE ostringstream::ostringstream(ios::openmode which)
  : ostream(0), sb_(which | ios::out)
{
  ostream::rdbuf(&sb_);
}

SSINLINE ostringstream::ostringstream(const string& s, ios::openmode which)
  : ostream(0), sb_(s, which | ios::out)
{
  ostream::rdbuf(&sb_);
}

SSINLINE stringstream::stringstream(ios::openmode which)
  : iostream(0), sb_(which)
{
  iostream::rdbuf(&sb_);
}

SSINLINE stringstream::stringstream(const string& s, ios::openmode which)
  : iostream(0), sb_(s, which)
{
  iostream::rdbuf(&sb_);
}

} // End namepace std
