From d3b5514e75f0c1a767271a8d1dea7cf4a89afa62 Mon Sep 17 00:00:00 2001 From: deadwood Date: Sun, 27 Apr 2014 15:28:33 +0000 Subject: [PATCH] dos.library: allow FRead to read directly from the buffer without need for going through FGetC Previous implementation caused a function call for each byte read. 1MB of data = 1 million calls. git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@48974 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- rom/dos/dos_intern.h | 1 + rom/dos/fgetc.c | 221 ++++++++++++++----------------------------- rom/dos/{fgetc.c => fread.c} | 119 +++++++++++++++++------ 3 files changed, 160 insertions(+), 181 deletions(-) rewrite rom/dos/fgetc.c (64%) copy rom/dos/{fgetc.c => fread.c} (52%) diff --git a/rom/dos/dos_intern.h b/rom/dos/dos_intern.h index 84a1536811..d46942312b 100644 --- a/rom/dos/dos_intern.h +++ b/rom/dos/dos_intern.h @@ -269,6 +269,7 @@ typedef struct FileHandle* FileHandlePtr; void vbuf_free(FileHandlePtr fh); APTR vbuf_alloc(FileHandlePtr fh, STRPTR buf, ULONG size); BOOL vbuf_inject(BPTR fh, CONST_STRPTR argptr, ULONG argsize, struct DosLibrary *DOSBase); +LONG vbuf_fetch(BPTR file, UBYTE * buffer, LONG fetchsize, struct DosLibrary *DOSBase); LONG FWriteChars(BPTR file, CONST UBYTE* buffer, ULONG length, struct DosLibrary *DOSBase); diff --git a/rom/dos/fgetc.c b/rom/dos/fgetc.c dissimilarity index 64% index b6ca1b1586..3bca524119 100644 --- a/rom/dos/fgetc.c +++ b/rom/dos/fgetc.c @@ -1,150 +1,71 @@ -/* - Copyright © 1995-2011, The AROS Development Team. All rights reserved. - $Id$ - - Desc: - Lang: english -*/ - -#include -#include -#include - -#include -#include - -#include "dos_intern.h" - - -/***************************************************************************** - - NAME */ -#include - - AROS_LH1(LONG, FGetC, - -/* SYNOPSIS */ - AROS_LHA(BPTR, file, D1), - -/* LOCATION */ - struct DosLibrary *, DOSBase, 51, Dos) - -/* FUNCTION - Get a character from a buffered file. Buffered I/O is more efficient - for small amounts of data but less for big chunks. You have to - use Flush() between buffered and non-buffered I/O or you'll - clutter your I/O stream. - - INPUTS - file - filehandle - - RESULT - The character read or EOF if the file ended or an error happened. - IoErr() gives additional information in that case. - - NOTES - - EXAMPLE - - BUGS - - SEE ALSO - IoErr(), Flush() - - INTERNALS - -*****************************************************************************/ -{ - AROS_LIBFUNC_INIT - - /* Get pointer to filehandle */ - struct FileHandle *fh = (struct FileHandle *)BADDR(file); - - LONG size; - LONG bufsize; - - if (fh == NULL) - { - return EOF; - } - - /* If the file is in write mode... */ - if(fh->fh_Flags & FHF_WRITE) - { - /* write the buffer (in many pieces if the first one isn't enough). */ - LONG pos = 0; - - while(pos != fh->fh_Pos) - { - size = Write(file, BADDR(fh->fh_Buf) + pos, fh->fh_Pos - pos); - - /* An error happened? Return it. */ - if(size < 0) - { - return EOF; - } - - pos += size; - } - - /* Reinit filehandle. */ - fh->fh_Flags &= ~FHF_WRITE; - fh->fh_Pos = fh->fh_End = 0; - } - - /* No normal characters left. */ - if(fh->fh_Pos >= fh->fh_End) - { - /* Check for a pushed back EOF. */ - if(fh->fh_Pos > fh->fh_End) - { - D(bug("FGetC: Weird pos: fh_Pos (%d) > fh_End (%d)\n", fh->fh_Pos, fh->fh_End)); - /* Return EOF. */ - return EOF; - } - - /* Is there a buffer? */ - if(fh->fh_Buf == BNULL) - { - if (NULL == vbuf_alloc(fh, NULL, IOBUFSIZE)) - { - D(bug("FGetC: Can't allocate buffer\n")); - return(EOF); - } - } - - /* Fill the buffer. */ - if (fh->fh_Buf != fh->fh_OrigBuf) { - D(bug("FGetC: Can't trust fh_BufSize. Using 208 as the buffer size.\n")); - bufsize = 208; - } else { - bufsize = fh->fh_BufSize; - } - size = Read(file, BADDR(fh->fh_Buf), bufsize); - - /* Prepare filehandle for data. */ - if(size <= 0) - size = 0; - - fh->fh_Pos = 0; - fh->fh_End = size; - - /* No data read? Return EOF. */ - if(size == 0) - { - D(bug("FGetC: Tried to Read() to a %d byte buffer, got 0)\n", bufsize)); - return EOF; - } - } - - /* If fh_End == 0, simulate an EOF */ - if (fh->fh_End == 0) { - D(bug("FGetC: Got an EOF via fh_End == 0\n")); - return EOF; - } - - /* All OK. Get data. */ - return ((UBYTE *)BADDR(fh->fh_Buf))[fh->fh_Pos++]; - - AROS_LIBFUNC_EXIT -} /* FGetC */ +/* + Copyright © 1995-2011, The AROS Development Team. All rights reserved. + $Id$ + + Desc: + Lang: english +*/ + +#include +#include +#include + +#include +#include + +#include "dos_intern.h" + + +/***************************************************************************** + + NAME */ +#include + + AROS_LH1(LONG, FGetC, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + +/* LOCATION */ + struct DosLibrary *, DOSBase, 51, Dos) + +/* FUNCTION + Get a character from a buffered file. Buffered I/O is more efficient + for small amounts of data but less for big chunks. You have to + use Flush() between buffered and non-buffered I/O or you'll + clutter your I/O stream. + + INPUTS + file - filehandle + + RESULT + The character read or EOF if the file ended or an error happened. + IoErr() gives additional information in that case. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + IoErr(), Flush() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + UBYTE c; + LONG res; + + res = vbuf_fetch(file, &c, 1, DOSBase); + + if (res < 0) + return EOF; + else + return c; + + AROS_LIBFUNC_EXIT +} /* FGetC */ diff --git a/rom/dos/fgetc.c b/rom/dos/fread.c similarity index 52% copy from rom/dos/fgetc.c copy to rom/dos/fread.c index b6ca1b1586..aee1a12330 100644 --- a/rom/dos/fgetc.c +++ b/rom/dos/fread.c @@ -1,46 +1,45 @@ /* - Copyright © 1995-2011, The AROS Development Team. All rights reserved. + Copyright © 1995-2007, The AROS Development Team. All rights reserved. $Id$ Desc: Lang: english */ - #include -#include -#include - -#include -#include #include "dos_intern.h" +#define FETCHERR (-2) /***************************************************************************** NAME */ #include - AROS_LH1(LONG, FGetC, + AROS_LH4(LONG, FRead, /* SYNOPSIS */ - AROS_LHA(BPTR, file, D1), + AROS_LHA(BPTR , fh, D1), + AROS_LHA(APTR , block, D2), + AROS_LHA(ULONG, blocklen, D3), + AROS_LHA(ULONG, number, D4), /* LOCATION */ - struct DosLibrary *, DOSBase, 51, Dos) + struct DosLibrary *, DOSBase, 54, Dos) /* FUNCTION - Get a character from a buffered file. Buffered I/O is more efficient - for small amounts of data but less for big chunks. You have to - use Flush() between buffered and non-buffered I/O or you'll - clutter your I/O stream. + Read a number of blocks from a file. INPUTS - file - filehandle + fh - Read from this file + block - The data is put here + blocklen - This is the size of a single block + number - The number of blocks RESULT - The character read or EOF if the file ended or an error happened. - IoErr() gives additional information in that case. + The number of blocks read from the file or 0 on EOF. + This function may return fewer than the requested number of blocks. + IoErr() gives additional information in case of an error. NOTES @@ -49,7 +48,7 @@ BUGS SEE ALSO - IoErr(), Flush() + Open(), FWrite(), FPutc(), Close() INTERNALS @@ -57,17 +56,41 @@ { AROS_LIBFUNC_INIT - /* Get pointer to filehandle */ - struct FileHandle *fh = (struct FileHandle *)BADDR(file); + UBYTE *ptr; + LONG res; + LONG fetchsize = number * blocklen; + LONG readsize; - LONG size; - LONG bufsize; + ptr = block; - if (fh == NULL) + SetIoErr(0); + + while(fetchsize > 0) + { + res = vbuf_fetch(fh, ptr, fetchsize, DOSBase); + if (res < 0) + break; + ptr += res; + fetchsize -= res; + } + + if(res == FETCHERR) { return EOF; } - + + readsize = (LONG)(ptr - (UBYTE *)block); + + + return readsize / blocklen; + + AROS_LIBFUNC_EXIT +} /* FRead */ + +static LONG handle_write_mode(BPTR file, struct DosLibrary * DOSBase) +{ + struct FileHandle *fh = (struct FileHandle *)BADDR(file); + /* If the file is in write mode... */ if(fh->fh_Flags & FHF_WRITE) { @@ -76,12 +99,12 @@ while(pos != fh->fh_Pos) { - size = Write(file, BADDR(fh->fh_Buf) + pos, fh->fh_Pos - pos); + LONG size = Write(file, BADDR(fh->fh_Buf) + pos, fh->fh_Pos - pos); /* An error happened? Return it. */ if(size < 0) { - return EOF; + return FETCHERR; } pos += size; @@ -92,6 +115,33 @@ fh->fh_Pos = fh->fh_End = 0; } + return 0; +} + +/* Fetches up to remaining buffer content from file buffer + * Return values: + * (-2) on error + * (EOF) on EOF + * (>0) on sucesfull fetch + */ +LONG vbuf_fetch(BPTR file, UBYTE * buffer, LONG fetchsize, struct DosLibrary *DOSBase) +{ + /* Get pointer to filehandle */ + struct FileHandle *fh = (struct FileHandle *)BADDR(file); + + LONG size; + LONG bufsize; + + if (fh == NULL) + { + return FETCHERR; + } + + if (handle_write_mode(file, DOSBase) == FETCHERR) + { + return FETCHERR; + } + /* No normal characters left. */ if(fh->fh_Pos >= fh->fh_End) { @@ -109,7 +159,7 @@ if (NULL == vbuf_alloc(fh, NULL, IOBUFSIZE)) { D(bug("FGetC: Can't allocate buffer\n")); - return(EOF); + return FETCHERR; } } @@ -143,8 +193,15 @@ return EOF; } - /* All OK. Get data. */ - return ((UBYTE *)BADDR(fh->fh_Buf))[fh->fh_Pos++]; + /* All OK. Get requested data. */ + size = fh->fh_End - fh->fh_Pos; + if (size > fetchsize) size = fetchsize; + if (size == 1) /* Don't do function call for 1 byte reads */ + *buffer = ((UBYTE *)BADDR(fh->fh_Buf))[fh->fh_Pos]; + else + CopyMem(((UBYTE *)BADDR(fh->fh_Buf)) + fh->fh_Pos, buffer, size); - AROS_LIBFUNC_EXIT -} /* FGetC */ + fh->fh_Pos += size; + + return size; +} -- 2.11.4.GIT