#include #include #include #include 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 }