
include "ParseUtil.inc"

macro ReadNextItem(w,s,i,  b)
=============================
/**
  @param w
**/
  int b=i
  do
    stepitem(s,i)
    select ascb
      case 0  : exit do
      case 44 : exit do
    end select
  end do
  w=mid(s,b,i-b-lenw)
end macro


class BufferObject
==================
  bstring prbuf
  sys    prpos,prblen, prslen, prquantum
  '
  method in(string s, n=-1) as sys
  ================================
    prslen=len(s)
    if n>=0 then 'PATCH
      if n+prslen<=prblen then
        mid prbuf,n+1,s
        return 1
      end if
      return 0
    end if
    if prpos+prslen>prblen then
      if prquantum<=0 then prquantum=0x1000
      prbuf+=nuls prquantum + prslen*2 : prblen=len(prbuf)
    end if
    mid prbuf,prpos+1,s
    prpos+=prslen
    return 1
  end method
  '
  method empty()
  ==============
    prblen=0 : prpos=0 : del prbuf
  end method
  '
  method quantum(sys q)
  =====================
    prquantum=q 'BUFFER EXTENSION STEP
  end method
  '
  method size() as int
  ====================
    return prpos
  end method
  '
  method out(int oo=-1,le=-1) as string
  =====================================
    if oo<0 then method=left prbuf,prpos : empty : exit method
    if le<0 then le=prpos
    if oo+le>prpos then le=prpos-oo
    return mid prbuf,oo+1,le
  end method
end class




class recordbuffer
==================
  has BufferObject buf
  int rsize
  '
  method padclip(string s) as string
    int le=len s
    if le>rsize then le=rsize
    return  left(s,le)+space(rsize-le)
  end method
  '
  method in(string s, int n=-1,oo=-1) as sys
    if oo<0 and n>=0 then return buf.in padclip(s),n*rsize
    return buf.in s,n*rsize+oo
  end method
  '
  method out(int n=-1,oo=0,le=-1) as string
    if n<0 then return buf.out 0 'export whole buffer. 0 to retain content
    if le<0 then le=rsize
    return buf.out n*rsize+oo, le
  end method
  '
  method empty()
    buf.empty
  end method
  method width(int n)
    rsize=n
  end method
  '
  method count() as sys
    if rsize then return buf.prpos/rsize
  end method
  '
  method quantum(int n)
    buf.quantum n
  end method
  '
end class


type fieldRecord
================
{
  char  name[64]
  char  type[8]
  int   width
  int   pos
}


class fieldBuffer
================
  has fieldRecord   field[0x100] 'up to 256 fields
  int endf,pos
  '
  method in(string s)
    indexbase 0
    int i=1
    string w
    do
      fieldRecord fr at endf * sizeof(fieldRecord) + @field
      readNextItem w,s,i
      if ascb=0 then exit do
      fr.name=unquote w
      readNextItem w,s,i
      fr.type=unquote w
      skiplspace s,i
      if ascb>32 then
        readNextItem w,s,i
        fr.width=val unquote w
        fr.pos=pos
        pos+=fr.width
      end if
      fr.pos+=sizeof fieldrecord
      endf++
    end do
  end method
  '
  method find(string s, int *i,*oo,*w) as sys
    fieldRecord f at @field
    for i=1 to endf
      if f.name=s then w=f.width : oo=f.pos : return -1
      @f+=sizeof field
    next
  end method
  '
  method clear()
    endf=0
  end method
  '
end class


class dataBuffer
================
  has fieldBuffer fbuf
  has recordBuffer rbuf
  sys fdx,idx,width
  indexbase 0
  '
  sys init() { idx=-1 : width=fbuf.pos+4 : rbuf.width width }
  sys index() { return idx }
  sys index(sys i) { idx=i : return -1 }
  sys in(string s) { return rbuf.in s, idx }
  string out(string s) { return rbuf.out idx }
  sys delete() { rbuf.in "-",idx,width-4 }
  sys undelete() { rbuf.in " ",idx,width-4 }
  sys deleted() { if rbuf.out (idx,width-4,1) = "-" then return -1 }
  '
  string getfieldname(int i) { i-- : if i>=0 then fdx=i+1 : return fbuf.field[i].name }
  sys field(string s) { int i, oo, wi : if fbuf.find s,i,oo,wi then fdx=i+1 : return fdx }
  sys field(int i) { fdx=i }
  sys field() { return fdx }
  sys findfield(string s) { int i,oo, wi : if fbuf.find s,i,oo,wi then fdx=i+1 : return i } 
  '
  string getfield() {
  int i=fdx-1
  if i>=0 and idx>=0 then
    fieldBuffer f at @fbuf.field + i * sizeof fieldRecord
    return rbuf.out(idx,f.field.pos,f.field.width)
  end if
  }
  '
  sys putfield(string s) {
  if fdx then
    int i=fdx-1
    fieldBuffer f at @fbuf.field + i * sizeof fieldRecord
    if idx>=0 then
      rbuf.in left(s,f.field.width), idx, f.field.pos
      return -1
    end if
  end if
  }
  '
  sys pack() {
    int i
    recordBuffer tbuf
    tbuf.width width
    tbuf.quantum width*rbuf.count 'memory allocation chunk size
    for i=0 to rbuf.count()-1
      if not deleted then tbuf.in rbuf.out(i) 'transfer record
    next
    idx=0
    rbuf.empty 'remove entire content
    rbuf.in tbuf.out(-1) 'tbuf is emptied automatically
  }
  method filter(s as string) as sys
  end method
  '
  method order(s as string) as sys
  end method
  '
  method find(s as string) as sys
  end method
  '
end class

