/*
*  FSAccess.c
*
* WARNING: This does not allow proper use of read-write streams
* No checks are made to invalidate a read buffer on a write stream.
*/
#include "DataExch.h"
#include "FSAccess.h"
void PutPacket(), WatchPacketsIn();
unsigned min(n1, n2)
unsigned n1, n2;
{
if (n1<n2) return(n1);
else return(n2);
}
unsigned getTextLength(name)
char *name;
{
unsigned len = 0;
while (*name != 0 ) {
++len;
++name;
}
return (len);
}
static char *tempmsg;
static void action←open(chars, len, type, data1, data2)
char *chars;
unsigned len, type, data1, data2;
{
unsigned i;
if (len==0) return;
for ( i=0; i<len; ++i) {
*tempmsg++ = chars[i];
}
*tempmsg = 0;
}
unsigned streamNo = 0x100; /* 0 is console in, 1 is console out, 2 is stderr */
unsigned FSStreamOpen(name, access, msg)
char *name, *msg;
unsigned access;
{
unsigned len;
++streamNo;
len = getTextLength(name);
tempmsg = msg;
*msg = 0;
(void) PutPacket(SOPEN, streamNo, access, name, len);
WatchPacketsIn();
if (*msg == 0) return(streamNo);
else return(0xff);
}
unsigned TypeScriptCreate(name)
char *name;
{
unsigned len;
++streamNo;
len = getTextLength(name);
(void) PutPacket(SOPEN, streamNo, TSCREATE, name, len);
++streamNo; /* we are actually creating */
++streamNo; /* three streams: in, out, err */
return(streamNo);
}
void PutBlock(stream, r, start, len)
unsigned stream, start, len;
char *r;
{
unsigned chunk;
r = r+start;
while (len>0) {
chunk = min(len, MSGSIZE);
(void) PutPacket(SWRITE, stream, 0, r, chunk);
len = len - chunk;
r = r + chunk;
};
}
int write(d, buf, nbytes)
int d;
char *buf;
int nbytes;
{
(void) PutBlock((unsigned) d, buf, 0, (unsigned) nbytes);
return(nbytes);
}
void PutText(stream, txt)
unsigned stream;
char *txt;
{
unsigned len;
len = getTextLength(txt);
(void) PutBlock(stream, txt, 0, len);
}
#define SBUFSIZE 8*1024
static struct streamBuffer {
unsigned stream;
unsigned indexOfStart;
unsigned lastIndexUsed;
unsigned last;
unsigned length;  /* the buffer is valid till buff[length] */
char buff[SBUFSIZE];
};
#define STRBUFNO 8
static struct streamBuffer streamBuffers[STRBUFNO];
long findLastBuffer(stream)
unsigned stream;
{
long i;
for (i=0; i<STRBUFNO; i++)
if (streamBuffers[i].stream==stream) {
if (streamBuffers[i].last!=0) return(i);
};
return(-1);
}
long findBuffer(stream, index)
unsigned stream, index;
{
long i;
for (i=0; i<STRBUFNO; i++)
if (streamBuffers[i].stream==stream) {
long indexDiff;
indexDiff = index-streamBuffers[i].indexOfStart;
if (indexDiff>=0 && indexDiff<streamBuffers[i].length) return(i);
};
return(-1);
}
unsigned lastAlloc = 0;
static unsigned allocBuffer(stream)
unsigned stream;
{
unsigned iBuf, firstBuf;
int found = 0; /* BOOLEAN */
if (lastAlloc==STRBUFNO-1)
firstBuf = 0;
else
firstBuf = lastAlloc+1;
iBuf = firstBuf;
do { /* try to find a deallocated buffer */
if (streamBuffers[iBuf].stream==0xff)
{lastAlloc = iBuf; found = 1; break;};
if (iBuf==STRBUFNO-1)
iBuf = 0;
else
iBuf = iBuf+1;
} while (iBuf!=firstBuf) ;
if (found==0) { /* try to find a non last buffer */
iBuf = firstBuf;
do {
if (streamBuffers[iBuf].last==0)
{lastAlloc = iBuf; found = 1; break;};
if (iBuf==STRBUFNO-1)
iBuf = 0;
else
iBuf = iBuf+1;
} while (iBuf!=firstBuf);
};
if (found==0) { /* take the next one anyway */
lastAlloc=firstBuf;
(void) PutPacket(SSETINDEX, streamBuffers[lastAlloc].stream, streamBuffers[lastAlloc].lastIndexUsed, (char *) 0, 0);
};
streamBuffers[lastAlloc].stream = stream;
streamBuffers[lastAlloc].length = 0;
return(lastAlloc);
}
char *blockPtr, *blockLimit, *strBuf;
static void action←getblock(chars, len, type, data1, data2)
char *chars;
unsigned len, type, data1, data2;
{
unsigned i;
if (len==0) return;
for ( i=0; i<len; ++i) {
if (blockPtr==blockLimit) {
blockPtr = strBuf;
strBuf = blockLimit; /* just to let others know */
};
*blockPtr++ = chars[i];
}
}
unsigned DoGetBlock(stream, index, r, start, len)
unsigned stream, index, start, len;
char *r;
{
long iBuf;
iBuf = allocBuffer(stream);
blockPtr = &r[start];
blockLimit = blockPtr+len;
strBuf = streamBuffers[iBuf].buff;
(void) PutPacket(SREAD, stream, len, (char *) 0, 0);
WatchPacketsIn();
if (strBuf == streamBuffers[iBuf].buff) {
streamBuffers[iBuf].stream = 0xff;
lastAlloc=iBuf-1;
return(blockPtr-&r[start]);
}
else {
/*  char hexa[12];
PutText(1, "\tput in buffer(");
itoh(iBuf, hexa);
PutText(1, hexa);
PutText(1, ") : ");
itoh(streamBuffers[iBuf].length, hexa);
PutText(1, hexa);
PutText(1, "H \n"); */
streamBuffers[iBuf].last = 1;
streamBuffers[iBuf].indexOfStart = index+len;
streamBuffers[iBuf].lastIndexUsed = index+len;
streamBuffers[iBuf].length = blockPtr-streamBuffers[iBuf].buff;
return(len);
};
}
unsigned GetFromBuffer(stream, index, r, start, len)
unsigned stream, index, start, len;
char *r;
{
char *localBuf, *limit, hexa[12];
long iBuf;
unsigned localLen, indexDiff;
iBuf = findBuffer(stream, index);
if (iBuf==-1) return(0);
r = r+start;
if (streamBuffers[iBuf].last==0) {
long iLast = findLastBuffer(stream);
if (iLast!=-1) streamBuffers[iLast].last = 0;
streamBuffers[iBuf].last = 1;
};
indexDiff = index-streamBuffers[iBuf].indexOfStart;
localBuf = streamBuffers[iBuf].buff+indexDiff;
localLen = min(len, streamBuffers[iBuf].length-indexDiff);
limit = localBuf+localLen;
while (localBuf<limit) *r++ = *localBuf++;
streamBuffers[iBuf].lastIndexUsed = index+localLen;
if (localLen<len && (indexDiff+localLen == streamBuffers[iBuf].length)) {
streamBuffers[iBuf].stream = 0xff;
};
/* PutText(1, "\tget from buffer(");
itoh(iBuf, hexa);
PutText(1, hexa);
PutText(1, ") index: ");
itoh(index, hexa);
PutText(1, hexa);
PutText(1, "H (total : ");
itoh(streamBuffers[iBuf].length, hexa);
PutText(1, hexa);
PutText(1, "H, startInd : ");
itoh(streamBuffers[iBuf].indexOfStart, hexa);
PutText(1, hexa);
PutText(1, "H) taken : ");
itoh(localLen, hexa);
PutText(1, hexa);
PutText(1, "H \n");*/
return(localLen);
}
unsigned GetBlock(stream, index, r, start, len)
unsigned stream, index, start, len;
char *r;
{
unsigned localLen, externLen;
localLen = GetFromBuffer(stream, index, r, start, len);
if (localLen==len) return(len);
index = index+localLen;
externLen = DoGetBlock(stream, index, r, start+localLen, len-localLen);
return(localLen+externLen);
}
static unsigned indexOfStream;
static void action←getindex(chars, len, type, data1, data2)
char *chars;
unsigned len, type, data1, data2;
{
indexOfStream=data2;
}
unsigned GetIndex(stream)
unsigned stream;
{
unsigned iBuf;
iBuf = findLastBuffer(stream);
if (iBuf!=-1)
indexOfStream = streamBuffers[iBuf].lastIndexUsed;
else {
(void) PutPacket(SGETINDEX, stream, 0, (char *) 0, 0);
WatchPacketsIn();
};
return(indexOfStream);
}
static unsigned lengthOfStream;
static void action←getlength(chars, len, type, data1, data2)
char *chars;
unsigned len, type, data1, data2;
{
lengthOfStream=data2;
}
unsigned GetLength(stream)
unsigned stream;
{
(void) PutPacket(SGETLENGTH, stream, 0, (char *) 0, 0);
WatchPacketsIn();
return(lengthOfStream);
}
void SetIndex(stream, index)
unsigned stream, index;
{
unsigned iBuf;
iBuf = findBuffer(stream, index);
if (iBuf!=-1) {
if (streamBuffers[iBuf].last==0) {
unsigned iLast, nextIndexToCall;
iLast = findLastBuffer(stream);
if (iLast!=-1) streamBuffers[iLast].last = 0;
nextIndexToCall = streamBuffers[iBuf].indexOfStart+streamBuffers[iBuf].length;
(void) PutPacket(SSETINDEX, stream, nextIndexToCall, (char *) 0, 0);
};
streamBuffers[iBuf].last = 1;
streamBuffers[iBuf].lastIndexUsed = index;
return;
};
iBuf = findLastBuffer(stream);
if (iBuf!=-1) streamBuffers[iBuf].last = 0;
(void) PutPacket(SSETINDEX, stream, index, (char *) 0, 0);
}
void SetLength(stream, length)
unsigned stream, length;
{
(void) PutPacket(SSETLENGTH, stream, length, (char *) 0, 0);
}
void FSClose(stream)
unsigned stream;
{
unsigned iBuf, i;
for (i=0; i<STRBUFNO; i++)
if (streamBuffers[i].stream==stream) {
streamBuffers[i].stream = 0xff;
};
(void) PutPacket(SCLOSE, stream, 0, (char*) 0, 0);
}
int read(d, buf, nbytes)
int d;
char *buf;
int nbytes;
{
int nread;
unsigned index;
index = GetIndex((unsigned) d);
nread = GetBlock((unsigned) d, index, buf, 0, (unsigned) nbytes);
if (nread==0 && nbytes != 0) nread = -1;
return(nread);
}
long GetLine(stream, buf)
unsigned stream;
char *buf;
{
unsigned start, index;
long n = 1;
start = 0;
index = GetIndex(stream);
while (n==1) {
n = GetBlock(stream, index, buf, start, 1);
if (buf[start] =='\n' || buf[start] =='\r') break;
++start;
};
buf[start] = 0;
return(start);
}
void initFS()
{
unsigned iBuf;
for (iBuf=0; iBuf<STRBUFNO; iBuf++) {
streamBuffers[iBuf].stream=0xff;
}
registration[SOPEN].a = action←open;
registration[SOPEN].t = 0;
registration[SREAD].a = action←getblock;
registration[SREAD].t = 0;
registration[SGETLENGTH].a = action←getlength;
registration[SGETLENGTH].t = 0;
registration[SGETINDEX].a = action←getindex;
registration[SGETINDEX].t = 0;
}