X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=functions%2Fstdio%2Ffwrite.c;h=3c40186500a88ceac20eed0e02989a2d5ab7d113;hb=55cf35957bf8dec0a489ba758c02c83303a5eb50;hp=d2698b840de8efca2f10f0e03eeb338f76f5eaaf;hpb=1d9d92ba957a0b8307c9a65c35867fde68e6533b;p=pdclib diff --git a/functions/stdio/fwrite.c b/functions/stdio/fwrite.c index d2698b8..3c40186 100644 --- a/functions/stdio/fwrite.c +++ b/functions/stdio/fwrite.c @@ -1,482 +1,101 @@ -/* ---------------------------------------------------------------------------- - * $Id$ - * ---------------------------------------------------------------------------- - * Public Domain C Library - http://pdclib.sourceforge.net - * This code is Public Domain. Use, modify, and redistribute at will. - * --------------------------------------------------------------------------*/ +/* $Id$ */ -size_t fwrite( const void * restrict ptr, size_t size, size_t nelem, FILE * restrict stream ) { /* TODO */ }; +/* fwrite( const void *, size_t, size_t, FILE * ) -/* PDPC code - unreviewed, verbatim. -Read the note in fopen.c. -#ifndef __MVS__ -size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t towrite; - size_t elemWritten; -#ifdef __OS2__ - ULONG actualWritten; - APIRET rc; -#endif -#ifdef __MSDOS__ - size_t actualWritten; - int errind; -#endif - - if (nmemb == 1) - { - towrite = size; - } - else if (size == 1) - { - towrite = nmemb; - } - else - { - towrite = size * nmemb; - } - if (towrite < stream->szfbuf) - { - stream->quickBin = 0; - if ((stream->bufTech == _IONBF) && !stream->textMode) - { - stream->quickBin = 1; - } - } - if (!stream->quickBin) - { - fwriteSlow(ptr, size, nmemb, stream, towrite, &elemWritten); - return (elemWritten); - } - else - { -#ifdef __OS2__ - rc = DosWrite(stream->hfile, (VOID *)ptr, towrite, &actualWritten); - if (rc != 0) - { - stream->errorInd = 1; - actualWritten = 0; - errno = rc; - } -#endif -#ifdef __MSDOS__ - actualWritten = __write(stream->hfile, - ptr, - towrite, - &errind); - if (errind) - { - stream->errorInd = 1; - actualWritten = 0; - errno = actualWritten; - } -#endif - if (nmemb == 1) - { - if (actualWritten == size) - { - elemWritten = 1; - } - else - { - elemWritten = 0; - } - } - else if (size == 1) - { - elemWritten = actualWritten; - } - else - { - elemWritten = actualWritten / size; - } - stream->bufStartR += actualWritten; - return (elemWritten); - } -} - -static void fwriteSlow(const void *ptr, - size_t size, - size_t nmemb, - FILE *stream, - size_t towrite, - size_t *elemWritten) -{ - size_t actualWritten; + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ - /* Normally, on output, there will never be a situation where - the write buffer is full, but it hasn't been written out. - If we find this to be the case, then it is because we have - done an fseek, and didn't know whether we were going to do - a read or a write after it, so now that we know, we switch - the buffer to being set up for write. We could use a flag, - but I thought it would be better to just put some magic - code in with a comment */ - if (stream->upto == stream->endbuf) - { - stream->bufStartR += (stream->endbuf - stream->fbuf); - stream->upto = stream->fbuf; - stream->mode = __WRITE_MODE; - } - if ((stream->textMode) || (stream->bufTech == _IOLBF)) - { - fwriteSlowT(ptr, stream, towrite, &actualWritten); - } - else - { - fwriteSlowB(ptr, stream, towrite, &actualWritten); - } - if (nmemb == 1) - { - if (actualWritten == size) - { - *elemWritten = 1; - } - else - { - *elemWritten = 0; - } - } - else if (size == 1) - { - *elemWritten = actualWritten; - } - else - { - *elemWritten = actualWritten / size; - } - return; -} +#include +#include <_PDCLIB_glue.h> +#ifndef REGTEST -/* can still be called on binary files, if the binary file is - line buffered */ +#include +#include -static void fwriteSlowT(const void *ptr, - FILE *stream, - size_t towrite, - size_t *actualWritten) +size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) { - char *p; - char *tptr; - char *oldp; - size_t diffp; - size_t rem; - int fin; -#ifdef __OS2__ - ULONG tempWritten; - APIRET rc; -#endif -#ifdef __MSDOS__ - size_t tempWritten; - int errind; -#endif - - *actualWritten = 0; - tptr = (char *)ptr; - p = tptr; - oldp = p; - p = (char *)memchr(oldp, '\n', towrite - (size_t)(oldp - tptr)); - while (p != NULL) + if ( _PDCLIB_prepwrite( stream ) == EOF ) + { + return 0; + } + _PDCLIB_size_t offset = 0; + bool lineend = false; + size_t nmemb_i; + for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i ) { - diffp = (size_t)(p - oldp); - fin = 0; - while (!fin) + for ( size_t size_i = 0; size_i < size; ++size_i ) { - rem = (size_t)(stream->endbuf - stream->upto); - if (diffp < rem) + /* TODO: Should line-buffered streams be flushed on '\n' or system EOL? */ + if ( ( stream->buffer[ stream->bufidx++ ] = ((char*)ptr)[ nmemb_i * size + size_i ] ) == '\n' ) { - memcpy(stream->upto, oldp, diffp); - stream->upto += diffp; - *actualWritten += diffp; - fin = 1; + /* Remember last newline, in case we have to do a partial line-buffered flush */ + offset = stream->bufidx; + lineend = true; } - else + if ( stream->bufidx == stream->bufsize ) { - memcpy(stream->upto, oldp, rem); - oldp += rem; - diffp -= rem; -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - stream->fbuf, - stream->szfbuf, - &tempWritten); - if (rc != 0) - { - stream->errorInd = 1; - return; - } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - stream->fbuf, - stream->szfbuf, - &errind); - if (errind) - { - stream->errorInd = 1; - return; - } -#endif - else + if ( _PDCLIB_flushbuffer( stream ) == EOF ) { - *actualWritten += rem; - stream->upto = stream->fbuf; - stream->bufStartR += tempWritten; + /* Returning number of objects completely buffered */ + return nmemb_i; } + lineend = false; } } - rem = (size_t)(stream->endbuf - stream->upto); - if (rem < 2) - { -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - stream->fbuf, - (size_t)(stream->upto - stream->fbuf), - &tempWritten); - if (rc != 0) - { - stream->errorInd = 1; - errno = rc; - return; - } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - stream->fbuf, - (size_t)(stream->upto - stream->fbuf), - &errind); - if (errind) - { - stream->errorInd = 1; - errno = tempWritten; - return; - } -#endif - stream->upto = stream->fbuf; - stream->bufStartR += tempWritten; - } - if (stream->textMode) - { - memcpy(stream->upto, "\r\n", 2); - stream->upto += 2; - } - else - { - memcpy(stream->upto, "\n", 1); - stream->upto += 1; - } - *actualWritten += 1; - oldp = p + 1; - p = (char *)memchr(oldp, '\n', towrite - (size_t)(oldp - tptr)); } - - if ((stream->bufTech == _IOLBF) - && (stream->upto != stream->fbuf) - && (oldp != tptr)) + /* Fully-buffered streams are OK. Non-buffered streams must be flushed, + line-buffered streams only if there's a newline in the buffer. + */ + switch ( stream->status & ( _IONBF | _IOLBF ) ) { -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - stream->fbuf, - (size_t)(stream->upto - stream->fbuf), - &tempWritten); - if (rc != 0) - { - stream->errorInd = 1; - errno = rc; - return; - } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - stream->fbuf, - (size_t)(stream->upto - stream->fbuf), - &errind); - if (errind) - { - stream->errorInd = 1; - errno = tempWritten; - return; - } -#endif - stream->upto = stream->fbuf; - stream->bufStartR += tempWritten; - } - - diffp = towrite - *actualWritten; - while (diffp != 0) - { - rem = (size_t)(stream->endbuf - stream->upto); - if (diffp < rem) - { - memcpy(stream->upto, oldp, diffp); - stream->upto += diffp; - *actualWritten += diffp; - } - else - { - memcpy(stream->upto, oldp, rem); -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - stream->fbuf, - stream->szfbuf, - &tempWritten); - if (rc != 0) + case _IONBF: + if ( _PDCLIB_flushbuffer( stream ) == EOF ) { - stream->errorInd = 1; - errno = rc; - return; + /* We are in a pinch here. We have an error, which requires a + return value < nmemb. On the other hand, all objects have + been written to buffer, which means all the caller had to + do was removing the error cause, and re-flush the stream... + Catch 22. We'll return a value one short, to indicate the + error, and can't really do anything about the inconsistency. + */ + return nmemb_i - 1; } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - stream->fbuf, - stream->szfbuf, - &errind); - if (errind) + break; + case _IOLBF: { - stream->errorInd = 1; - errno = tempWritten; - return; - } -#endif - else + size_t bufidx = stream->bufidx; + stream->bufidx = offset; + if ( _PDCLIB_flushbuffer( stream ) == EOF ) { - *actualWritten += rem; - stream->upto = stream->fbuf; + /* See comment above. */ + stream->bufidx = bufidx; + return nmemb_i - 1; + } + stream->bufidx = bufidx - offset; + memmove( stream->buffer, stream->buffer + offset, stream->bufidx ); } - stream->bufStartR += tempWritten; - oldp += rem; - } - diffp = towrite - *actualWritten; - } - if ((stream->bufTech == _IONBF) - && (stream->upto != stream->fbuf)) - { -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - stream->fbuf, - (size_t)(stream->upto - stream->fbuf), - &tempWritten); - if (rc != 0) - { - stream->errorInd = 1; - errno = rc; - return; - } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - stream->fbuf, - (size_t)(stream->upto - stream->fbuf), - &errind); - if (errind) - { - stream->errorInd = 1; - errno = tempWritten; - return; - } -#endif - stream->upto = stream->fbuf; - stream->bufStartR += tempWritten; } - return; + return nmemb_i; } -/* whilst write requests are smaller than a buffer, we do not turn - on quickbin */ - -static void fwriteSlowB(const void *ptr, - FILE *stream, - size_t towrite, - size_t *actualWritten) -{ - size_t spare; -#ifdef __OS2__ - ULONG tempWritten; - APIRET rc; -#endif -#ifdef __MSDOS__ - size_t tempWritten; - int errind; #endif - spare = (size_t)(stream->endbuf - stream->upto); - if (towrite < spare) - { - memcpy(stream->upto, ptr, towrite); - *actualWritten = towrite; - stream->upto += towrite; - return; - } - memcpy(stream->upto, ptr, spare); -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - stream->fbuf, - stream->szfbuf, - &tempWritten); - if (rc != 0) - { - stream->errorInd = 1; - errno = rc; - return; - } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - stream->fbuf, - stream->szfbuf, - &errind); - if (errind) - { - stream->errorInd = 1; - errno = tempWritten; - return; - } -#endif - *actualWritten = spare; - stream->upto = stream->fbuf; - stream->bufStartR += tempWritten; - if (towrite > stream->szfbuf) - { - stream->quickBin = 1; -#ifdef __OS2__ - rc = DosWrite(stream->hfile, - (char *)ptr + *actualWritten, - towrite - *actualWritten, - &tempWritten); - if (rc != 0) - { - stream->errorInd = 1; - errno = rc; - return; - } -#endif -#ifdef __MSDOS__ - tempWritten = __write(stream->hfile, - (char *)ptr + *actualWritten, - towrite - *actualWritten, - &errind); - if (errind) - { - stream->errorInd = 1; - errno = tempWritten; - return; - } -#endif - *actualWritten += tempWritten; - stream->bufStartR += tempWritten; - } - else - { - memcpy(stream->fbuf, - (char *)ptr + *actualWritten, - towrite - *actualWritten); - stream->upto += (towrite - *actualWritten); - *actualWritten = towrite; - } - stream->bufStartR += *actualWritten; - return; +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + FILE * fh; + remove( testfile ); + TESTCASE( ( fh = fopen( testfile, "w" ) ) != NULL ); + TESTCASE( fwrite( "SUCCESS testing fwrite()\n", 1, 25, fh ) == 25 ); + TESTCASE( fclose( fh ) == 0 ); + /* TODO: Add readback test. */ + TESTCASE( remove( testfile ) == 0 ); + return TEST_RESULTS; } + #endif -*/ +