/* Copyright Per Bothner 1987. Read the file Q-INFO */
#include "Vioprotocol.h"
#include "stdio.h"
ProcessId BufServerPid = 0;
#define Buffer char
#define PIPE_BLOCK_SIZE 1024
typedef struct
  {
    struct File *f;
    unsigned lastblock, nextblock;
    struct File saveMark;	/* in case of duplicate read requests */

  } BufDesc;
#define BufFileMax 8
BufDesc *(BufFileTable[BufFileMax]);
#define GetBufDesc(id) BufFileTable[id]
SystemCode CreateBufFile(), ReleaseBufFile(), ReadBufFile(), QueryBufFile(),
    ProcessRead();

BufServer()

    /* Base function executed by the pipe server process. */
  {
    register ProcessId  pid;
    SystemCode  reply;
    Message	msg;
    register IoRequest *req = (IoRequest *) msg;
    register IoReply *replymsg = (IoReply *) msg;

    BufInitialize();
    while(1)
      {
        pid = Receive( req);
        switch( req->requestcode )
          {
            case QUERY_INSTANCE:
                reply = QueryBufFile( req, pid );
		break;
            case SET_INSTANCE_OWNER:
                reply = OK;
		break;
            case RELEASE_INSTANCE:
                reply = ReleaseBufFile( req, pid );
		break;
            case READ_INSTANCE:
                reply = ReadBufFile( req, pid );
		break;
            case CREATE_INSTANCE:
		reply = CreateBufFile( req, pid );
		break;
            case WRITE_INSTANCE:
	    case WRITESHORT_INSTANCE:
            default: /* unrecognized request */
                reply = ILLEGAL_REQUEST;
          }
        if( reply == NO_REPLY ) continue;
        replymsg->replycode = reply;
        Reply( req, pid );
      }
  }

NewBufFile(f) FILE *f;
  { CreateInstanceRequest msg;
    if (BufServerPid == 0)
        BufServerPid = Ready(Create(2, BufServer, 1000), 0);
    msg.requestcode = CREATE_INSTANCE;
    msg.filemode = FREAD;
    msg.filename = "";
    msg.filenamelen = 0;
    msg.unspecified[0] = f;
    Send(&msg, BufServerPid);
    return ((CreateInstanceReply*)&msg)->fileid;
  }

BufInitialize()
  { register int i;
    for (i = 0; i < BufFileMax; i++) BufFileTable[i] = 0;
  }

SystemCode CreateBufFile( req, pid )
    CreateInstanceRequest *req; ProcessId pid;
  { register BufDesc *bufFile;
    register CreateInstanceReply *reply = (CreateInstanceReply *) req;
    InstanceId id;
    for (id = 0; BufFileTable[id] != 0; )
	if (id++ >= BufFileMax) return (NO_SERVER_RESOURCES);
    bufFile = (BufDesc*)malloc(sizeof(BufDesc));
    BufFileTable[id] = bufFile;
    bufFile->f = req->unspecified[0];
    bufFile->lastblock = (0-1);
    bufFile->nextblock = 0;
    bufFile->saveMark.kind = FileClosed;
    reply->fileid = id;
    return OK;
  }
SystemCode ReleaseBufFile( req, pid )
    IoRequest *req; ProcessId pid;
  { InstanceId id = req->fileid;
    free(BufFileTable[id]);
    BufFileTable[id] = 0;
    return OK;
  }
SystemCode QueryBufFile( req, pid )
   QueryInstanceRequest *req; ProcessId pid;
  
    /* handle the "QUERY_INSTANCE" operation on a pipe */
    /* The nextblock field indicates the next block to be read
    /* and the last block field indicates the last block written
    /* for both ends of the pipe. */
  {
    register CreateInstanceReply *reply = (CreateInstanceReply *) req;
    register BufDesc *pipe;

    if( (pipe = GetBufDesc(req->fileid) ) == NULL ) return( NOT_FOUND );

    reply->fileserver       = BufServerPid;
    reply->blocksize   = PIPE_BLOCK_SIZE;
    reply->filetype         = STREAM | VARIABLE_BLOCK | READABLE;
    reply->filelastblock = pipe->lastblock;
    reply->filelastbytes = PIPE_BLOCK_SIZE;
    reply->filenextblock = pipe->nextblock;

    return( OK );
  }


SystemCode ReadBufFile( req, pid )
   IoRequest *req; ProcessId pid;

    /* perform the "READ_INSTANCE" operation on a BufFile. */
  {
    register Buffer *buffer;
    register IoReply *reply = (IoReply *) req;
    register BufDesc  *pipe;
    long i;

    if( (pipe = GetBufDesc(req->fileid)) == NULL ) return( NOT_FOUND );

    if( req->bytecount > PIPE_BLOCK_SIZE ) return( BAD_BYTE_COUNT );

    /* Handle a duplicate or retransmitted read operation. */
#if 0
    if( (req->blocknumber == pipe->nextblock-1)
      && !(pipe->saveMark.kind & FileClosed) )
      {
	buffer = pipe->lastbufferread;
	pipe->lastbufferread = NULL;
	ProcessRead( pipe, req, pid, buffer );
	return( NO_REPLY );
      }
#endif
    if( req->blocknumber != pipe->nextblock ) return( BAD_BLOCK_NO );

#if 0
    if( (buffer = pipe->nextbuffer) == NULL )
      { /* No data buffers available. */
	if( pipe->writeowner == 0 )
	  {
	    reply->bytecount = 0;
	    return( END_OF_FILE );
	  }
	pipe->reader = pid;
	return( NO_REPLY );
      }
#endif
    return( ProcessRead( pipe, req, pid, buffer) );
  }

SystemCode ProcessRead( pipe, req, pid, buffer )
	BufDesc *pipe; IoRequest *req; ProcessId pid; Buffer *buffer;
  {
    register IoReply *reply = (IoReply *) req;
    register ProcessId writer;
    register struct File *f = pipe->f;
    long count;
    register SystemCode r;

#if 0
    /* Zero the reader field */
    pipe->reader = 0;
    
    if( (buf=pipe->lastbufferread) != NULL )
      {
	/* Free last buffer read. */
	buf->next = pipe->freebuffers;
	pipe->freebuffers = buf;
      }
    pipe->lastbufferread = buffer;
    if( pipe->nextbuffer == buffer ) /* If in the queue of buffers, remove */
	if( (pipe->nextbuffer = buffer->next) == NULL )
		pipe->lastbuffer = NULL;
#endif
    peekc(f); /* to force alignment */
    count = f->readLimit - f->current;
    if (count <= 0)
      { reply->bytecount = 0; return END_OF_FILE; }
    if (req->bytecount < count) count = req->bytecount;
    reply->bytecount = count;
    reply->replycode = OK;
    if( count <= IO_MSG_BUFFER )
      {
	Copy( reply->shortbuffer, f->current, count );
	reply->replycode = OK;
	Reply( reply, pid );
      }
    else
	ReplyWithSegment(reply,pid,f->current,req->bufferptr,count);
    f->current += count;
    pipe->nextblock++;

    return( OK );
 }
