#ifndef _ARRAY_H_
#define _ARRAY_H_ 90

/*   _____________________________________________________________
    /                                                             \ 
    | Header file:  ARRAY CLASSES of expansion library
    \_____________________________________________________________/

    Description:

    Notes:          This source is 100% public domain and might be
                    copied, modified and used by everyone as he likes it.

    Contents:

    Developers: ID: Name:
    =========== --- -----
                JTH Jürgen Thumm

  _____________________________________/VERSION HISTORY\____________________
 /Date_ Version Who What____________________________________________________\ 
 yymmdd ------- --- ---------------------------------------------------------
 940407 0.90    JTH created

 940907 0.91    Windows 3.1 port: changed getc to getchr, putc to putchr
                in array classes
 950501         ScalarPipe::flush() now public.
*/

#ifndef _EXPDEF_H_
#   include "expdef.h"
#endif
#ifndef _EXPLIB_H_
#   include "explib.h"
#endif

#   include <limits.h>

//   _____________________________________________________________  
//  /                                                             \ 
//  |   the BUFFER class
//  \_____________________________________________________________/ 

//|| Buffer     

class   Buffer  {

    //  in front and after the user buffer, two securtiy areas (SA)
    //  are hold. these are checked for illegal write hits on resizing.

#define BUF_SA_SIZE 4   // size of each SA

    size_t  isize;  // data size without SECSIZE
    uchar   *imem;  // internally alloc'ed memory including SA's

 public:

    Buffer(size_t initial_size = 0);
    ~Buffer();

    uchar*  adr;    // pointer to user data

    bool testhit(); // returns 1 if damaged by writing

    size_t  size(size_t newsize=-1);    // read or set new size

    };

//   _____________________________________________________________  
//  /                                                             \ 
//  |   virtual BASE ARRAY class
//  \_____________________________________________________________/ 

//|| BaseArray

class BaseArray {

 protected:

    size_t  lsize;  // logical size
    size_t  idx;    // current index, -1 if invalid

    bool    tadr;   // adress testing on/off switch

 public:

    bool    dead;

             BaseArray();
    virtual ~BaseArray();

    virtual bool    eod()   = 0;
    virtual rcode   error() = 0;
    virtual size_t  index(size_t newidx=-1);

    virtual rcode   getchr(uchar& x)    = 0;
    virtual rcode   putchr(uchar x)     = 0;

    size_t  get(size_t byteindex, void* adr, size_t maxsize);
    size_t  put(size_t byteindex, void* adr, size_t maxsize);
    size_t  size(); // returns no. of bytes stored in array

    };

//   _____________________________________________________________  
//  /                                                             \ 
//  |   a dynamic MEMORY ARRAY, derived from BASE ARRAY
//  \_____________________________________________________________/ 

//|| MemArray 

class MemArray : public BaseArray {

    uchar*  aadr;   // alloc'ed adr
    size_t  asize;  // alloc'ed size

 public:

    MemArray();
    ~MemArray();

    bool    eod();
    rcode   error();

    virtual rcode   getchr(uchar& x);
    virtual rcode   putchr(uchar x);

    };

//   _____________________________________________________________  
//  /                                                             \ 
//  |   a FILE ARRAY, derived from BASE ARRAY
//  \_____________________________________________________________/ 

//|| FileArray 

class FileArray : public BaseArray {

    size_t  fidx;   // file index

    FILE *f;    // current file

 public:

    FileArray(char* filename);
    ~FileArray();

    bool    eod();
    rcode   error();

    virtual rcode   getchr(uchar& x);
    virtual rcode   putchr(uchar x);

    };

//   _____________________________________________________________  
//  /                                                             \ 
//  |   a common array
//  \_____________________________________________________________/ 

//|| Array     

class Array {

    static long instcnt;    // instance counter

    BaseArray*  ba;

    union   {

        uchar   ub;
        uword   us;
        uint    ui;
        ulong   ul;

            }   scalb;  // scalar object buffer

    bool    tadr;       // adress testing on/off

    // gbuf, the buffer global to all instances
    // USAGE:   only for temporar purposes, e.g. sprintf

    static  Buffer  gbuf;

    // ibuf, the linear buffer of an instance
    // USAGE:   after working on gbuf, result is copied to ibuf,
    //          then ibuf's data adress is given to caller

    Buffer  ibuf;

 public:

    bool    dead;

    Array(char* filename=0);
    ~Array();

    inline  bool    eod();
    inline  rcode   error();

    inline  size_t  index(size_t newidx=-1);
    inline  size_t  size(); // how many bytes are stored in the array

    //  ---

    rcode   getb(uchar& x);
    rcode   putb(uchar  x);     // returns OK if successfull

    rcode   getw(ushort& x);    // in this class, WORD means
    rcode   putw(ushort  x);    // always UNSIGNED SHORT!

    size_t  get(void* adr, size_t maxsize);
    size_t  put(void* adr, size_t size);

    //  --- string functions ---

    char*   gets(char* str, size_t maxsize);    // get a string
    // str:     store string including line terminator and '\0' there
    // maxsize: including line terminator and '\0', string may have
    //          this maximum size
    // result:  str or NULL in case eof(), error()

    char*   printf(char *format, ...);  // write formatted string

    //  ---

    Array& operator [] (size_t sidx);   // index selection

    /*
    rcode operator << (char x)  {   return putb(x); }
    rcode operator << (uchar x) {   return putb(x); }

    rcode operator << (short x) {   return putw(x); }
    rcode operator << (ushort x){   return putw(x); }
    */

    };

//   _____________________________________________________________  
//  /                                                             \ 
//  |   a pipe for a stream of scalars
//  \_____________________________________________________________/ 

//  V 0.90 / 0704941615 / tested.

//  the pipe will automatically pack the stream, i.e. only deltas
//  are stored.
//  NOTE! Currently only to be used on streams with large redundancies,
//        i.e. with large areas of same bytes!

//|| ScalarPipe 

class   ScalarPipe : public Array {

    struct  DInfo   {

        union   {

            uchar   b;

            }   dat;

        struct  {

            short   b;  // byte counter

            }   cnt;

        DInfo()     {   memset(&cnt, 0, sizeof(cnt));   }

        };

    DInfo   wdi;    // write data infos
    DInfo   rdi;    // read  data infos

 public:

    rcode   putb(uchar  x);

    rcode   flush();    // completes writing process
    // this MUST be called at the end of a data stream
    // to make sure that all data were stored.

    rcode   getb(uchar& x);

    size_t  index(size_t newidx=-1);

    };

/*  TEST SAMPLE 1:

    Array src("tmp2:dummy");
    if(src.dead)    {   printf("ugh\n"); return;    }

    ScalarPipe  sp;
    uchar   x;

    while(1)
    {
        if(src.getb(x)) break;  // EOD
        if( sp.putb(x)) {SysErr(704941539); return;}
    }

    if(sp.index(0) != 0)    {SysErr(704941541); return;}

    while(1)
    {
        if( sp.getb(x)) break;  // EOD

        printf("%c", x);
    }
*/

/*  TEST SAMPLE 2:

    ScalarPipe  sp;

    for(int i=0; i<40000; i++)

        if(sp.putb(0xFF))   {SysErr(704941610);return;}

    sp.putb(0xA);

    sp.index(0);

    int cnt=0; uchar x;

    for(i=0; i<50000; i++)
    {
        if(sp.getb(x))  {SysErr(704941611);return;}

        if(x==0xFF) cnt++;  else break;
    }

    printf("last char %d, no. of 0xFF is %d\n", x, cnt);
*/

#   endif   // not already included
