/* This is -*- C++ -*- */
#ifndef GENFILES_H
#pragma interface
#define GENFILES_H

#define EOF_ptr (void*)(-1)
#include "iostream.h"
#include "types.h"
/*#include <newtype.h>*/
class GenRecur;

#ifdef __GNU_LIBRARY__
#define SPACE_LEFT(stream) (stream)->__bp != (stream)->__rlim
#define GET_FIRST(stream) *(unsigned char*)(stream)->__bp++
#else
#define SPACE_LEFT(stream) --(stream)->_cnt>=0
#define GET_FIRST(stream) (int)(*(unsigned char *)(stream)->_ptr++)
#endif

#if 0
class Generator : public Root {
  public:
    virtual Root *get();
    virtual void close();
};

class GenFile : public Generator {
  public:
    virtual Root *get();
    virtual void put(Root *);
    virtual void seek(long offset, int kind);
};

class Gatherer : private GenFile {
  public:
    virtual void put(Root *);
};

class IOStream : public GenFile {
  public:
    FILE *filep;
    virtual Root* get() { int c = getc(filep);
			  return c < 0 ? Missing : CCharToChar(c); }
    virtual Root* put(Root* ob) { ob->printon(filep); }
    inline OutStream& operator<<(char c) { putc(c, filep); }
    inline InStream& operator>>(char& c) { c = gutc(filep); }
};

class InStream : private IOStream {
  public:
    IOStream::operator>>;
};

class OutStream : private IOStream {
    IOStream::operator<<;
};
#endif

#if 0
class Iterator {
};

typedef Iterator ObReader;

class IStrean : public Iterator {
    FILE *stream;
    char get() ...;
};

class CharWriter : public IStream, public OStream {
};

class ObWriter : public CharWriter {
    ???;
    stream = ??;
};
#endif

class GenFile : public Root {
// protected:
//    short flags; short stride;
  public:
    virtual Root* key();
    virtual Root *next();
    virtual Root *peek_next();
    virtual void put(Root *ob);
    virtual void putback(Root*);
//   Root *get() { return next(); }
    virtual GenSeq * get(size_t n);
    virtual void destroy();
    virtual ~GenFile();
    virtual GenFile *file() { return this; }
#if 0
    void *current;
    void *readLimit;
    inline void *peek() {
	    if (current < readLimit) return current;
	    else return fillBuffer();
	}
    inline void *get() {
	    void *result =
		current < readLimit ? current : fillBuffer();
	    current += stride;
	    return result;
	}
    virtual void *fillBuffer();
    virtual struct Any getAny();
#endif
    virtual int seek(void *arg, int kind);
    virtual int seek(long offset, int kind);
    virtual int seek(Root*);
    HandlerDesc *handlerAtLastSeek;
    virtual int close();
    virtual void printon(ostream&) const;
    void reset();
};

class Iterator : public GenFile { // Deliberately like NIHCL
  public:
    GenMap* cltn; // Collection being iterated over
    streambuf *stream;
    int index;              // If >= 0: index of next Object
    Root* state;          // additional state, e.g., a Stack
    Iterator() { }
    // Reset to beginning of Collection:
    const GenMap* collection() const    { return cltn; }
    streambuf* rdbuf() const { return stream; }
    virtual GenSeq * get(size_t n);
};

class SeqIterator : public Iterator {
  public:
    SeqIterator() { }
    virtual Root *next();
    virtual int seek(long offset, int kind);
    virtual Root* key();
    virtual void put(Root*);
    virtual void putback(Root*);
};

class SubSeqIterator : Iterator {
    friend class SubSeq;
    GenFile *base() { return (GenFile*)(this+1); }
    long _count;
    long _limit;
    long _start;
  public:
    SubSeqIterator(SubSeq*);
    Root* next();
#if 0
#endif
};

class CharFile : public Iterator {
    DECLARE_MEMBERS(CharFile)
  public:
    friend int Fill(CharFile*);
    // GenSeq *seq;
    //    FILE *stream;

    short state;
    // g++ 1.91 doesn't like: { stream = s; state = s ? _good : _bad; }
    CharFile(streambuf *s);
    CharFile(GenSeq& m, streambuf *s);
    void destroy();
    virtual Root *key();
    virtual Root *next();
    virtual void putback(Root*);
    virtual GenSeq * get(size_t n);
#if 1
    int get() { return stream->sbumpc(); }
#else
    inline int get() { return getc(stream); }
#endif
    inline void get(char& c)
	{ int ch = get();
	  if (ch == EOF) state = (int)state | int(ios::eofbit); else c = ch; }
    virtual int seek(long offset, int kind);
    virtual int close();
    inline good() { return state == 0; }
    inline eof() { return int(state) & int(ios::eofbit); }
    inline fail() { return int(state) & int(ios::failbit); }
    inline bad() { return int(state) & int(ios::badbit); }
  protected:
//    int fill(); // Just calls underflow().
//    virtual int underflow(); // Should actually be in streambuf.
};

class InStream : private CharFile {
  public:
    InStream(streambuf *s) : CharFile(s) { }
    CharFile::stream;
    CharFile::next;
    CharFile::get;
    CharFile::close;
    CharFile::rdbuf;
    InStream& putback(char ch) { stream->sputbackc(ch); return *this; }
    int peek() { return stream->sgetc(); }
//  protected:
//    CharFile::underflow();
};

#if 0
class IOStream : public InStream {
  public:
};

class RangeFile : public Iterator {
  public:
    long bufIndex;
    // Followed by buffer of current data.
    const GenRecur* range() const { return (const GenRecur*)cltn; }
    inline char* _buf() { return (char*)(this+1); }
    RangeFile(GenRecur* r);
    virtual Root *next();
};
#endif

class MapFile : public GenFile {
    int i;
    const struct Mapping *map;
  public:
    MapFile(const struct Mapping *m, int pos=0);
    virtual Root *key();
    virtual Root *next();
    virtual int seek(void *arg, int kind);
    virtual int seek(Root*);
};

extern StringC *ReadFileDescToString(int fd);
extern CharFile* Coerce2CharFile(Root* arg);
extern GenFile* Coerce2GenFile(Root* arg);

#if 0
extern CharFile StdIn;
extern CharFile StdOut;
extern CharFile StdErr;
#endif

extern CharFile* DefaultInFile();
extern CharFile* DefaultOutFile();
#define DEFAULT_IN_FILE DefaultInFile()
#define DEFAULT_OUT_FILE DefaultInFile()

#define CONSTRUCT(PTR, TYPE, ARGS) PTR->TYPE::TYPE ARGS

class StackIterator {
  GenFile *file;
public:
  StackIterator(void* ptr) { file = (GenFile*)ptr; }
  ~StackIterator();
  Root *next() { return file->next(); }
  Root* key() { return file->key(); }
  void reset() { file->reset(); }
};

#define ITERATOR(NAME, COLL) \
    GenMap *NAME##coll = (COLL); \
    char NAME##file [NAME##coll->sizeof_file()]; \
    NAME##coll->open((GenFile*)NAME##file); \
    StackIterator NAME((void*)NAME##file)

#endif /*GENFILES_H*/
