]> pd.if.org Git - pdclib/blobdiff - functions/stdio/fwrite.c
Cleaned up the testing a bit.
[pdclib] / functions / stdio / fwrite.c
index d2698b840de8efca2f10f0e03eeb338f76f5eaaf..3c40186500a88ceac20eed0e02989a2d5ab7d113 100644 (file)
-/* ----------------------------------------------------------------------------
- * $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 <stdio.h>
+#include <_PDCLIB_glue.h>
 
+#ifndef REGTEST
 
-/* can still be called on binary files, if the binary file is
-   line buffered  */
+#include <stdbool.h>
+#include <string.h>
 
-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
-*/
+