kolibrios-fun/programs/develop/ktcc/trunk/libc/stdio/fread.c

95 lines
2.6 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kolibrisys.h>
int fread(void *buffer,int size,int count,FILE* file)
{
dword res, readbytes;
dword fullsize, read4cache, toread, readcount;
if(!file || !buffer)
{
errno = E_INVALIDPTR;
return 0;
}
if ((file->mode &3)!=FILE_OPEN_READ && (file->mode & FILE_OPEN_PLUS)==0)
{
errno = E_ACCESS;
return 0;
}
fullsize=count*size;
if (fullsize + file->filepos >= file->filesize)
{
fullsize=file->filesize - file->filepos;
if (fullsize <= 0) return 0;
}
/***** file buffering strategy, just read forward *****
if we read small part - read full buffer, but if buffer have this data - dont read again nothing (or partial read forward 4k pages)
any writes drops buffers as ungetc_buf */
read4cache = 0;
readcount = 0;
if (file->filepos >= file->buffer_start && file->filepos < file->buffer_end)
{
read4cache = min(file->buffer_end - file->filepos, fullsize);
memcpy(buffer, file->buffer + file->filepos - file->buffer_start, read4cache);
file->filepos += read4cache;
if (file->ungetc_buf != EOF) // subst ungetc byte
{
*((char*)buffer) = (char)file->ungetc_buf;
file->ungetc_buf = EOF;
}
buffer += read4cache; // ! advance
fullsize -= read4cache;
readcount = read4cache / size;
}
toread = max(fullsize, file->buffersize);
if (toread + file->filepos >= file->filesize)
{
toread = file->filesize - file->filepos;
}
if (fullsize <= 0 || toread <= 0)
res = 0; // already read or file end
else
{
file->buffer_start = file->filepos;
if (toread <= fullsize) // read to bigger buffer
{
res = _ksys_readfile(file->filename, file->filepos, toread, buffer, &readbytes);
read4cache = min(readbytes, file->buffersize);
memcpy(file->buffer, buffer, read4cache);
file->filepos += readbytes;
} else
{
res = _ksys_readfile(file->filename, file->filepos, toread, file->buffer, &readbytes);
read4cache = readbytes;
memcpy(buffer, file->buffer, min(fullsize, read4cache));
file->filepos += min(fullsize, read4cache);
}
file->buffer_end = file->buffer_start + read4cache;
if (readbytes >= fullsize)
readcount += fullsize / size;
else
readcount += readbytes / size;
}
if (file->ungetc_buf != EOF) // subst ungetc byte
{
*((char*)buffer) = (char)file->ungetc_buf;
file->ungetc_buf = EOF;
}
if (res != 0)
{
file->ungetc_buf = EOF;
errno = -res;
}
return readcount; // really full readed plus cached items
}