flushbuffer: make EOL conversion code more robust against I/O errors
authorOwen Shepherd <owen.shepherd@e43.eu>
Wed, 12 Nov 2014 20:38:32 +0000 (20:38 +0000)
committerOwen Shepherd <owen.shepherd@e43.eu>
Wed, 12 Nov 2014 20:38:32 +0000 (20:38 +0000)
functions/stdio/_PDCLIB_flushbuffer.c
functions/stdio/_PDCLIB_fvopen.c
internals/_PDCLIB_io.h

index 44066d87dbd24099d40fe16ca657f25ef786c858..b3357ade950233953a03b74a0a535f63c2816df3 100644 (file)
 #include <_PDCLIB_glue.h>\r
 #include <_PDCLIB_io.h>\r
 \r
+\r
 static int flushsubbuffer( FILE * stream, size_t length )\r
 {\r
+    size_t justWrote;\r
     size_t written = 0;\r
     int rv = 0;\r
 \r
+#if 0\r
+    // Very useful for debugging buffering issues\r
+    char l = '<', r = '>';\r
+    stream->ops->write( stream->handle, &l,  1, &justWrote );\r
+#endif\r
+\r
     while( written != length )\r
     {\r
-        size_t justWrote;\r
         size_t toWrite = length - written;\r
+\r
         bool res = stream->ops->write( stream->handle, stream->buffer + written,\r
                               toWrite, &justWrote);\r
         written += justWrote;\r
@@ -27,55 +35,71 @@ static int flushsubbuffer( FILE * stream, size_t length )
 \r
         if (!res)\r
         {\r
-            stream->status |=_PDCLIB_ERRORFLAG;\r
+            stream->status |= _PDCLIB_ERRORFLAG;\r
             rv = EOF;\r
             break;\r
         }\r
     }\r
 \r
-    stream->bufidx -= written;\r
+#if 0\r
+    stream->ops->write( stream->handle, &r,  1, &justWrote );\r
+#endif\r
+\r
+    stream->bufidx   -= written;\r
+#ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
+    stream->bufnlexp -= written;\r
+#endif\r
     memmove( stream->buffer, stream->buffer + written, stream->bufidx );\r
 \r
     return rv;\r
 }\r
 \r
-#if defined(_PDCLIB_NEED_EOL_TRANSLATION)\r
-#undef  _PDCLIB_NEED_EOL_TRANSLATION\r
-#define _PDCLIB_NEED_EOL_TRANSLATION 1\r
-#else\r
-#define _PDCLIB_NEED_EOL_TRANSLATION 0\r
-#endif\r
-\r
 int _PDCLIB_flushbuffer( FILE * stream )\r
 {\r
+#ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
     // if a text stream, and this platform needs EOL translation, well...\r
-    if ( ! ( stream->status & _PDCLIB_FBIN ) && _PDCLIB_NEED_EOL_TRANSLATION )\r
+    if ( ! ( stream->status & _PDCLIB_FBIN ) )\r
     {\r
-        size_t pos;\r
-        for ( pos = 0; pos < stream->bufidx; pos++ )\r
+        // Special case: buffer is full and we start with a \n\r
+        if ( stream->bufnlexp == 0\r
+            && stream->bufidx == stream->bufend\r
+            && stream->buffer[0] == '\n' )\r
         {\r
-            if (stream->buffer[pos] == '\n' ) {\r
+            char cr = '\r';\r
+            size_t written = 0;\r
+            bool res = stream->ops->write( stream->handle, &cr, 1, &written );\r
+\r
+            if (!res) {\r
+                stream->status |= _PDCLIB_ERRORFLAG;\r
+                return EOF;\r
+            }\r
+\r
+        }\r
+\r
+        for ( ; stream->bufnlexp < stream->bufidx; stream->bufnlexp++ )\r
+        {\r
+            if (stream->buffer[stream->bufnlexp] == '\n' ) {\r
                 if ( stream->bufidx == stream->bufend ) {\r
                     // buffer is full. Need to print out everything up till now\r
-                    if( flushsubbuffer( stream, pos ) )\r
+                    if( flushsubbuffer( stream, stream->bufnlexp - 1 ) )\r
                     {\r
                         return EOF;\r
                     }\r
-\r
-                    pos = 0;\r
                 }\r
 \r
                 // we have spare space in buffer. Shift everything 1char and\r
                 // insert \r\r
-                memmove( &stream->buffer[pos+1], &stream->buffer[pos], stream->bufidx - pos );\r
-                stream->buffer[pos] = '\r';\r
+                memmove( &stream->buffer[stream->bufnlexp + 1],\r
+                         &stream->buffer[stream->bufnlexp],\r
+                         stream->bufidx - stream->bufnlexp );\r
+                stream->buffer[stream->bufnlexp] = '\r';\r
 \r
-                pos += 2;\r
+                stream->bufnlexp++;\r
                 stream->bufidx++;\r
             }\r
         }\r
     }\r
-\r
+#endif\r
     return flushsubbuffer( stream, stream->bufidx );\r
 }\r
 \r
index 4fc98ffe610fcc86845073d7bfa6e4964a73138b..2a5720948cd10251b4e5e07eb3ca47d7e7079fa5 100644 (file)
@@ -17,8 +17,8 @@
 \r
 extern FILE * _PDCLIB_filelist;\r
 \r
-FILE * _PDCLIB_fvopen( \r
-    _PDCLIB_fd_t                                    fd, \r
+FILE * _PDCLIB_fvopen(\r
+    _PDCLIB_fd_t                                    fd,\r
     const _PDCLIB_fileops_t    *_PDCLIB_restrict    ops,\r
     int                                             mode,\r
     const char                  *_PDCLIB_restrict   filename\r
@@ -62,6 +62,9 @@ FILE * _PDCLIB_fvopen(
     /* Initializing the rest of the structure */\r
     rc->bufsize = BUFSIZ;\r
     rc->bufidx = 0;\r
+#ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
+    rc->bufnlexp = 0;\r
+#endif\r
     rc->ungetidx = 0;\r
     /* Setting buffer to _IOLBF because "when opened, a stream is fully\r
        buffered if and only if it can be determined not to refer to an\r
index 2df3ff5ca6dd1b31927a32abd8097938acef24d6..3561b211dcb16d87279ad5c2b6921836f3f4b867 100644 (file)
@@ -179,6 +179,9 @@ struct _PDCLIB_file
     _PDCLIB_size_t            bufsize;  /* Size of buffer */\r
     _PDCLIB_size_t            bufidx;   /* Index of current position in buffer */\r
     _PDCLIB_size_t            bufend;   /* Index of last pre-read character in buffer */\r
+#ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
+    _PDCLIB_size_t            bufnlexp; /* Current position of buffer newline expansion */\r
+#endif\r
     _PDCLIB_size_t            ungetidx; /* Number of ungetc()'ed characters */\r
     unsigned char *           ungetbuf; /* ungetc() buffer */\r
     unsigned int              status;   /* Status flags; see above */\r