From d1954049a406af2992113a783539aa5d86cfdfa8 Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Wed, 12 Nov 2014 20:38:32 +0000 Subject: [PATCH] flushbuffer: make EOL conversion code more robust against I/O errors --- functions/stdio/_PDCLIB_flushbuffer.c | 66 ++++++++++++++++++--------- functions/stdio/_PDCLIB_fvopen.c | 7 ++- internals/_PDCLIB_io.h | 3 ++ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/functions/stdio/_PDCLIB_flushbuffer.c b/functions/stdio/_PDCLIB_flushbuffer.c index 44066d8..b3357ad 100644 --- a/functions/stdio/_PDCLIB_flushbuffer.c +++ b/functions/stdio/_PDCLIB_flushbuffer.c @@ -11,15 +11,23 @@ #include <_PDCLIB_glue.h> #include <_PDCLIB_io.h> + static int flushsubbuffer( FILE * stream, size_t length ) { + size_t justWrote; size_t written = 0; int rv = 0; +#if 0 + // Very useful for debugging buffering issues + char l = '<', r = '>'; + stream->ops->write( stream->handle, &l, 1, &justWrote ); +#endif + while( written != length ) { - size_t justWrote; size_t toWrite = length - written; + bool res = stream->ops->write( stream->handle, stream->buffer + written, toWrite, &justWrote); written += justWrote; @@ -27,55 +35,71 @@ static int flushsubbuffer( FILE * stream, size_t length ) if (!res) { - stream->status |=_PDCLIB_ERRORFLAG; + stream->status |= _PDCLIB_ERRORFLAG; rv = EOF; break; } } - stream->bufidx -= written; +#if 0 + stream->ops->write( stream->handle, &r, 1, &justWrote ); +#endif + + stream->bufidx -= written; +#ifdef _PDCLIB_NEED_EOL_TRANSLATION + stream->bufnlexp -= written; +#endif memmove( stream->buffer, stream->buffer + written, stream->bufidx ); return rv; } -#if defined(_PDCLIB_NEED_EOL_TRANSLATION) -#undef _PDCLIB_NEED_EOL_TRANSLATION -#define _PDCLIB_NEED_EOL_TRANSLATION 1 -#else -#define _PDCLIB_NEED_EOL_TRANSLATION 0 -#endif - int _PDCLIB_flushbuffer( FILE * stream ) { +#ifdef _PDCLIB_NEED_EOL_TRANSLATION // if a text stream, and this platform needs EOL translation, well... - if ( ! ( stream->status & _PDCLIB_FBIN ) && _PDCLIB_NEED_EOL_TRANSLATION ) + if ( ! ( stream->status & _PDCLIB_FBIN ) ) { - size_t pos; - for ( pos = 0; pos < stream->bufidx; pos++ ) + // Special case: buffer is full and we start with a \n + if ( stream->bufnlexp == 0 + && stream->bufidx == stream->bufend + && stream->buffer[0] == '\n' ) { - if (stream->buffer[pos] == '\n' ) { + char cr = '\r'; + size_t written = 0; + bool res = stream->ops->write( stream->handle, &cr, 1, &written ); + + if (!res) { + stream->status |= _PDCLIB_ERRORFLAG; + return EOF; + } + + } + + for ( ; stream->bufnlexp < stream->bufidx; stream->bufnlexp++ ) + { + if (stream->buffer[stream->bufnlexp] == '\n' ) { if ( stream->bufidx == stream->bufend ) { // buffer is full. Need to print out everything up till now - if( flushsubbuffer( stream, pos ) ) + if( flushsubbuffer( stream, stream->bufnlexp - 1 ) ) { return EOF; } - - pos = 0; } // we have spare space in buffer. Shift everything 1char and // insert \r - memmove( &stream->buffer[pos+1], &stream->buffer[pos], stream->bufidx - pos ); - stream->buffer[pos] = '\r'; + memmove( &stream->buffer[stream->bufnlexp + 1], + &stream->buffer[stream->bufnlexp], + stream->bufidx - stream->bufnlexp ); + stream->buffer[stream->bufnlexp] = '\r'; - pos += 2; + stream->bufnlexp++; stream->bufidx++; } } } - +#endif return flushsubbuffer( stream, stream->bufidx ); } diff --git a/functions/stdio/_PDCLIB_fvopen.c b/functions/stdio/_PDCLIB_fvopen.c index 4fc98ff..2a57209 100644 --- a/functions/stdio/_PDCLIB_fvopen.c +++ b/functions/stdio/_PDCLIB_fvopen.c @@ -17,8 +17,8 @@ extern FILE * _PDCLIB_filelist; -FILE * _PDCLIB_fvopen( - _PDCLIB_fd_t fd, +FILE * _PDCLIB_fvopen( + _PDCLIB_fd_t fd, const _PDCLIB_fileops_t *_PDCLIB_restrict ops, int mode, const char *_PDCLIB_restrict filename @@ -62,6 +62,9 @@ FILE * _PDCLIB_fvopen( /* Initializing the rest of the structure */ rc->bufsize = BUFSIZ; rc->bufidx = 0; +#ifdef _PDCLIB_NEED_EOL_TRANSLATION + rc->bufnlexp = 0; +#endif rc->ungetidx = 0; /* Setting buffer to _IOLBF because "when opened, a stream is fully buffered if and only if it can be determined not to refer to an diff --git a/internals/_PDCLIB_io.h b/internals/_PDCLIB_io.h index 2df3ff5..3561b21 100644 --- a/internals/_PDCLIB_io.h +++ b/internals/_PDCLIB_io.h @@ -179,6 +179,9 @@ struct _PDCLIB_file _PDCLIB_size_t bufsize; /* Size of buffer */ _PDCLIB_size_t bufidx; /* Index of current position in buffer */ _PDCLIB_size_t bufend; /* Index of last pre-read character in buffer */ +#ifdef _PDCLIB_NEED_EOL_TRANSLATION + _PDCLIB_size_t bufnlexp; /* Current position of buffer newline expansion */ +#endif _PDCLIB_size_t ungetidx; /* Number of ungetc()'ed characters */ unsigned char * ungetbuf; /* ungetc() buffer */ unsigned int status; /* Status flags; see above */ -- 2.40.0