
/*
 *  DNRead.C
 */

#include "lib.h"

long
DNRead(_chan, _buf, bytes)
void *_chan;
void *_buf;
long bytes;
{
    CHANN *chan = (CHANN *)_chan;
    char *buf = (char *)_buf;
    IOSTD *ior;
    int len = 0;
    long n;

    if (chan->eof)
	return(-1);
    while (bytes && ((ior = (IOSTD *)RemHead(&chan->rdylist)) || (ior = (IOSTD *)GetMsg(&chan->port)))) {
#ifdef DEBUG
	printf("IOR %08lx cmd %d len %d act %d\n", ior, ior->io_Command, ior->io_Length, ior->io_Actual);
#endif
	if (ior->io_Message.mn_Node.ln_Type == NT_REPLYMSG) {
	    if (!chan->queued)
#ifdef DEBUG
		puts("DNRead: Software Error");
#else
		;
#endif
	    else
		--chan->queued;
	    if (ior->io_Length)
		FreeMem(ior->io_Data, ior->io_Length);
	    FreeMem(ior, sizeof(IOSTD));
	    continue;
	}
	switch(ior->io_Command) {
	case DNCMD_CLOSE:
	case DNCMD_EOF:
	    chan->eof = 1;
	    ReplyMsg((MSG *)ior);
	    break;
	case DNCMD_IOCTL:
	    if (ior->io_Message.mn_Node.ln_Type == NT_REQUEUE)
		AddHead(&chan->rdylist, (NODE *)ior);
	    else
		AddTail(&chan->rdylist, (NODE *)ior);
	    ior->io_Message.mn_Node.ln_Type = NT_REQUEUE;
	    if (len == 0)
		len = -2;
	    goto done;
	case DNCMD_WRITE:
#ifdef DEBUG
	    printf("IOR LEN/ACT %ld/%ld\n", ior->io_Length, ior->io_Actual);
#endif
	    n = ior->io_Length - ior->io_Actual;
#ifdef DEBUG
	    if (n < 0)
		puts("len fail");
#endif
	    if (n <= bytes) {
		BMov((char *)ior->io_Data + ior->io_Actual, buf, n);
		bytes -= n;
		len += n;
		buf += n;
		ReplyMsg((MSG *)ior);
	    } else {
		BMov((char *)ior->io_Data + ior->io_Actual, buf, bytes);
		len += bytes;
		ior->io_Actual += bytes;
		bytes = 0;
		if (ior->io_Message.mn_Node.ln_Type == NT_REQUEUE)
		    AddHead(&chan->rdylist, (NODE *)ior);
		else
		    AddTail(&chan->rdylist, (NODE *)ior);
		ior->io_Message.mn_Node.ln_Type = NT_REQUEUE;
	    }
	    break;
	default:
	    ior->io_Error = 1;
	    ReplyMsg((MSG *)ior);
	}
    }
#ifdef DEBUG
    puts("DONE1");
#endif
done:
    FixSignal(chan);
    if (chan->eof)
	SetSignal(1 << chan->port.mp_SigBit, 1 << chan->port.mp_SigBit);
#ifdef DEBUG
    printf("RETURN %ld\n", len);
#endif
    return(len);
}

