/* Release 3.10 */
/*-------------------------------------------------------------------------*
*                                                                          *
*  STDIOSTR.CPP - 2.0 stream class implementations.      		   *
*                                                                          *
*  COPYRIGHT (C) 1989..1992 Clarion Software Corporation.                  *
*  All Rights Reserved                                                     *
*                                                                          *
*--------------------------------------------------------------------------*/

#include <clib.h>
#include <stdiostr.hpp>

#pragma module(init_prio=>22)

stdiobuf::stdiobuf(FILE *f) : streambuf(NULL, 0) {

  if(unbuffered()) {
    setb(lahead, &lahead[1], 0);
    unbuffered(1);
  }
  setp(base(), base());
  setg(base(), ebuf(), ebuf());
  sio=f;
  last_seek=0;
  gs=0;
  sync();
}

stdiobuf::~stdiobuf() {

//  fclose(f);
}

int stdiobuf::overflow(int  c) {

  int nw;

  if(unbuffered()) {
    if((c == EOF) || (fputc(c, sio) == EOF))
      return EOF;
  }
  else {
    nw=pptr()-pbase();
    if(nw) {
      if(::fwrite(pbase(), sizeof(char), nw, sio) != nw)
        return EOF;
    }
  }
  last_seek=ftell(sio);
  setp(pbase(), epptr());
  if((c != EOF) && (!unbuffered()))
    sputc(c);
  return c;
}

int stdiobuf::last_op() {

  int ret;

  if(pptr() > pbase())
    ret= ios::out;
  else if(gs)
    ret= ios::in;
  else
    ret = 0;
  return ret;
}

int stdiobuf::pbackfail(int c) {

  if(!unbuffered())
    sync();
  return ungetc(c, sio);
}

int stdiobuf::sync() {

  if(unbuffered()) {
    setp(base(), base());
    setg(base(), ebuf(), ebuf());
    return fflush(sio);
  }
  if(last_op() == ios::out)
    overflow();
  else if(last_op() == ios::in) {
    last_seek+= gptr()-eback();
    ::fseek(sio, last_seek, SEEK_SET);
  }
  else
    return 0;
  setp(base(), ebuf());
  setg(base(), ebuf(), ebuf());
  gs=0;
  return 0;
}

int stdiobuf::underflow() {

  int nr, c;

  gs=1;
  nr=ebuf()-eback();
  last_seek=ftell(sio);
  if(nr == 1) {
    c=fgetc(sio);
    if(c == EOF)
      return EOF;
    *eback()=c;
  }
  else {
    nr=fread(eback(), sizeof(char), nr, sio);
    if(ferror(sio) || (nr == 0))
       return EOF;
  }
  setg(eback(), eback(), eback()+nr);
  return *gptr();
}

streampos stdiobuf::seekoff(streamoff off, ios::seek_dir d, int) {

  streampos p;
  ios::seek_dir dir;

  if(d == ios::cur) {
    if(last_op() == ios::out)
      p = pptr()-pbase();
    else if(last_op() == ios::in)
      p = gptr()-eback();
    else
      p=0;
    p += last_seek + off;
    dir=ios::beg;
  }
  else {
    p=off;
    dir=d;
  }
  sync();
  last_seek = p;
  fseek(sio, p, dir);
  setp(base(), epptr());
  setg(base(), ebuf(), ebuf());
  return last_seek;
}


stdiostream::stdiostream(FILE *f) : ios(&buf),
                                    buf(f) {

}

stdiostream::~stdiostream() {

}

