
/*
 *  FREAD.C
 *
 *  (c)Copyright 1990, Matthew Dillon, All Rights Reserved
 */

#include <stdio.h>

#define buf ((char *)vbuf)

size_t
fread(vbuf, elmsize, elms, fi)
void *vbuf;
size_t elmsize;
size_t elms;
FILE *fi;
{
    int bytes;
    int origBytes;

    if (elmsize == 1)
	bytes = elms;
    else if (elms == 1)
	bytes = elmsize;
    else
	bytes = elms * elmsize;

    origBytes = bytes;

    if (fi && (fi->sd_Flags & __SIF_READ) && !(fi->sd_Flags & __SIF_EOF)) {
	int n = 0;	/*  actual read */

	if (bytes == 0)
	    return(0);

	if (fi->sd_UC >= 0) {       /*  ungotten character */
	    *buf++ = fi->sd_UC;
	    fi->sd_UC = -1;
	    --bytes;
	}

	if (fi->sd_RLeft > 0) {
	    n = (fi->sd_RLeft > bytes) ? bytes : fi->sd_RLeft;

	    movmem(fi->sd_RPtr, buf, n);
	    fi->sd_RPtr += n;
	    fi->sd_RLeft -= n;
	    buf += n;
	    bytes -= n;
	}
	if (bytes) {
	    if (bytes < fi->sd_BufSiz) {
		if (_filbuf(fi))
		    return(EOF);
	    }
	    if (fi->sd_RLeft <= 0) {    /*  unbuffered read or too-large read */
		int nn;

		nn = read(fi->sd_Fd, buf, bytes);
		if (nn < 0) {
		    fi->sd_Error = EOF;
		    return(EOF);
		}
		fi->sd_Offset += nn;
		n += nn;
	    } else {
		if (fi->sd_RLeft < bytes)
		    bytes = fi->sd_RLeft;
		movmem(fi->sd_RPtr, buf, bytes);
		fi->sd_RPtr += bytes;
		n += bytes;
	    }
	}
	if (n < 0)
	    fi->sd_Error = EOF;
	if (fi->sd_Error)
	    return(fi->sd_Error);
	if (n == origBytes)
	    return(elms);
	return(n / elmsize);
    }
    return(EOF);
}

