From d1f1e007f149be8a8c3084d144599a7456d15aba Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 5 Feb 2008 18:13:13 +0000 Subject: Various fixes for buffered R/W I/O and seeking git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@630 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/lib/Makefile | 5 +- nuttx/lib/dq_remlast.c | 24 ++-- nuttx/lib/lib_fflush.c | 207 +++++++++++++++++++++--------- nuttx/lib/lib_fseek.c | 28 +++- nuttx/lib/lib_fwrite.c | 54 ++++---- nuttx/lib/lib_internal.h | 12 ++ nuttx/lib/lib_libfread.c | 320 ++++++++++++++++++++++++---------------------- nuttx/lib/lib_libfwrite.c | 106 ++++++++------- nuttx/lib/lib_rdflush.c | 144 +++++++++++++++++++++ nuttx/lib/lib_wrflush.c | 111 ++++++++++++++++ 10 files changed, 710 insertions(+), 301 deletions(-) create mode 100644 nuttx/lib/lib_rdflush.c create mode 100644 nuttx/lib/lib_wrflush.c (limited to 'nuttx/lib') diff --git a/nuttx/lib/Makefile b/nuttx/lib/Makefile index 96ceb3a02..6e852d9d0 100644 --- a/nuttx/lib/Makefile +++ b/nuttx/lib/Makefile @@ -61,8 +61,9 @@ STDIO_SRCS += lib_rawstream.c ifneq ($(CONFIG_NFILE_STREAMS),0) STDIO_SRCS += lib_fopen.c lib_fclose.c lib_fread.c lib_libfread.c lib_fseek.c \ lib_fgetc.c lib_fgets.c lib_gets.c lib_fwrite.c lib_libfwrite.c \ - lib_fflush.c lib_fputc.c lib_puts.c lib_fputs.c lib_ungetc.c \ - lib_vprintf.c lib_fprintf.c lib_vfprintf.c lib_stdstream.c + lib_fflush.c lib_rdflush.c lib_wrflush.c lib_fputc.c lib_puts.c \ + lib_fputs.c lib_ungetc.c lib_vprintf.c lib_fprintf.c lib_vfprintf.c \ + lib_stdstream.c endif endif diff --git a/nuttx/lib/dq_remlast.c b/nuttx/lib/dq_remlast.c index 812e1f701..ed24c664f 100644 --- a/nuttx/lib/dq_remlast.c +++ b/nuttx/lib/dq_remlast.c @@ -1,7 +1,7 @@ -/************************************************************ +/**************************************************************************** * dq_remlast.c * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -14,7 +14,7 @@ * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,29 +31,29 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Compilation Switches - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Included Files - ************************************************************/ + ****************************************************************************/ #include -/************************************************************ +/**************************************************************************** * Public Functions - ************************************************************/ + ****************************************************************************/ -/***********************************(************************ +/***************************************************(************************ * Name: dq_remlast * * Description: * dq_remlast removes the last entry from 'queue' * - ************************************************************/ + ****************************************************************************/ FAR dq_entry_t *dq_remlast(dq_queue_t *queue) { diff --git a/nuttx/lib/lib_fflush.c b/nuttx/lib/lib_fflush.c index c9751df61..929597ea8 100644 --- a/nuttx/lib/lib_fflush.c +++ b/nuttx/lib/lib_fflush.c @@ -1,5 +1,5 @@ /**************************************************************************** - * lib_fflush.c + * lib/lib_fflush.c * * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -42,11 +42,15 @@ ****************************************************************************/ #include /* for CONFIG_STDIO_BUFFER_SIZE */ + +#include #include #include #include #include + #include + #include "lib_internal.h" /**************************************************************************** @@ -77,6 +81,115 @@ * Private Variables ****************************************************************************/ +/**************************************************************************** + * Name: fflush_internal + * + * Description: + * The function fflush() forces a write of all user-space buffered data for + * the given output or update stream via the stream's underlying write + * function. The open status of the stream is unaffected. + * + * Parmeters: + * stream - the stream to flush + * bforce - flush must be complete. + * + * Return: + * ERROR on failure, otherwise the number of bytes remaining in the buffer. + * If bforce is set, then only the values ERROR and 0 will be returned. + * + ****************************************************************************/ + +ssize_t fflush_internal(FILE *stream, boolean bforce) +{ +#if CONFIG_STDIO_BUFFER_SIZE > 0 + const unsigned char *src; + size_t bytes_written; + size_t nbuffer; + + /* Return EBADF if the file is not opened for writing */ + + if (stream->fs_filedes < 0 || (stream->fs_oflags & O_WROK) == 0) + { + *get_errno_ptr() = EBADF; + return ERROR; + } + + /* Make sure that we have exclusive access to the stream */ + + lib_take_semaphore(stream); + + /* Make sure tht the buffer holds valid data */ + + if (stream->fs_bufpos != stream->fs_bufstart) + { + /* Make sure that the buffer holds buffered write data. We do not + * support concurrent read/write buffer usage. + */ + + if (stream->fs_bufread != stream->fs_bufstart) + { + /* The buffer holds read data... just return zero */ + + return 0; + } + + /* How many bytes of write data are used in the buffer now */ + + nbuffer = stream->fs_bufpos - stream->fs_bufstart; + + /* Try to write that amount */ + + src = stream->fs_bufstart; + do + { + /* Perform the write */ + + bytes_written = write(stream->fs_filedes, src, nbuffer); + if (bytes_written < 0) + { + lib_give_semaphore(stream); + return ERROR; + } + + /* Handle partial writes. fflush() must either return with + * an error condition or with the data successfully flushed + * from the buffer. + */ + + src += bytes_written; + nbuffer -= bytes_written; + } + while (bforce && nbuffer > 0); + + /* Reset the buffer position to the beginning of the buffer */ + + stream->fs_bufpos = stream->fs_bufstart; + + /* For the case of an incomplete write, nbuffer will be non-zero + * It will hold the number of bytes that were not written. + * Move the data down in the buffer to handle this (rare) case + */ + + while (nbuffer) + { + *stream->fs_bufpos++ = *src++; + --nbuffer; + } + } + + /* Restore normal access to the stream and return the number of bytes + * remaining in the buffer. + */ + + lib_give_semaphore(stream); + return stream->fs_bufpos - stream->fs_bufstart; +#else + /* Return no bytes remaining in the buffer */ + + return 0; +#endif +} + /**************************************************************************** * Global Functions ****************************************************************************/ @@ -85,11 +198,16 @@ * Name: lib_fflushall * * Description: - * Called by the OS when a task exits + * Called either (1) by the OS when a task exits, or (2) from fflush() + * when a NULL stream argument is provided. + * ****************************************************************************/ -void lib_flushall(FAR struct streamlist *list) +int lib_flushall(FAR struct streamlist *list) { + int lasterrno = OK; + int ret; + /* Make sure that there are streams associated with this thread */ if (list) @@ -101,81 +219,54 @@ void lib_flushall(FAR struct streamlist *list) stream_semtake(list); for (i = 0; i < CONFIG_NFILE_STREAMS; i++) { - /* If the stream is open (i.e., assigned a non- - * negative file descriptor), then flush the + /* If the stream is open (i.e., assigned a non-negative file + * descriptor), then flush all of the pending write data in the * stream. */ if (list->sl_streams[i].fs_filedes >= 0) { - (void)fflush(&list->sl_streams[i]); + if (fflush_internal(&list->sl_streams[i], TRUE) != 0) + { + lasterrno = *get_errno_ptr(); + ret = ERROR; + } } } stream_semgive(list); } + + /* If any flush failed, return that last failed flush */ + + *get_errno_ptr() = lasterrno; + return ret; } /**************************************************************************** * Name: fflush + * + * Description: + * The function fflush() forces a write of all user-space buffered data for + * the given output or update stream via the stream's underlying write + * function. The open status of the stream is unaffected. + * + * If the stream argument is NULL, fflush() flushes all open output streams. + * + * Return: + * OK on success EOF on failure (with errno set appropriately) + * ****************************************************************************/ int fflush(FILE *stream) { -#if CONFIG_STDIO_BUFFER_SIZE > 0 - const unsigned char *src; - size_t bytes_written; - size_t nbuffer; - - if (stream->fs_filedes < 0 || (stream->fs_oflags & O_WROK) == 0) - { - *get_errno_ptr() = EBADF; - return ERROR; - } - - /* Make sure that we have exclusive access to the stream */ - - lib_take_semaphore(stream); - - /* How many bytes are used in the buffer now */ - - nbuffer = stream->fs_bufpos - stream->fs_bufstart; - - /* Try to write that amount */ - - src = stream->fs_bufstart; - bytes_written = write(stream->fs_filedes, src, nbuffer); - if (bytes_written < 0) + if (!stream) { - lib_give_semaphore(stream); - return bytes_written; + return lib_flushall(sched_getstreams()); } - - /* Update pointers and counts */ - - src += bytes_written; - nbuffer -= bytes_written; - - /* Reset the buffer position to the beginning of the buffer */ - - stream->fs_bufpos = stream->fs_bufstart; - - /* For the case of an incomplete write, nbuffer will be non-zero - * It will hold the number of bytes that were not written. - * Move the data down in the buffer to handle this (rare) case - */ - - while (nbuffer) + else if (fflush_internal(stream, TRUE) != 0) { - *stream->fs_bufpos++ = *src++; - --nbuffer; + return EOF; } - - /* Return the number of bytes remaining in the buffer */ - - lib_give_semaphore(stream); - return stream->fs_bufpos - stream->fs_bufstart; -#else - return 0; -#endif + return OK; } diff --git a/nuttx/lib/lib_fseek.c b/nuttx/lib/lib_fseek.c index a770f8f30..18781b6e3 100644 --- a/nuttx/lib/lib_fseek.c +++ b/nuttx/lib/lib_fseek.c @@ -41,8 +41,13 @@ * Included Files ****************************************************************************/ +#include + +#include #include #include +#include +#include #include "lib_internal.h" @@ -75,7 +80,11 @@ ****************************************************************************/ /**************************************************************************** - * Global Functions + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -84,6 +93,23 @@ int fseek(FILE *stream, long int offset, int whence) { +#if CONFIG_STDIO_BUFFER_SIZE > 0 + /* Flush any valid read/write data in the buffer (also verifies stream) */ + + if (lib_rdflush(stream) < 0 || lib_wrflush(stream) < 0) + { + return ERROR; + } +#else + /* Verify that we were provided with a stream */ + + if (!stream) + { + *get_errno_ptr() = EBADF; + return ERROR; + } +#endif + /* Perform the fseek on the underlying file descriptor */ return lseek(stream->fs_filedes, offset, whence) >= 0 ? OK : ERROR; diff --git a/nuttx/lib/lib_fwrite.c b/nuttx/lib/lib_fwrite.c index 3dd22ba8b..11d9c1eae 100644 --- a/nuttx/lib/lib_fwrite.c +++ b/nuttx/lib/lib_fwrite.c @@ -1,7 +1,7 @@ -/************************************************************ - * lib_fwrite.c +/**************************************************************************** + * lib/lib_fwrite.c * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -14,7 +14,7 @@ * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,53 +31,53 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Compilation Switches - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Included Files - ************************************************************/ + ****************************************************************************/ #include #include "lib_internal.h" -/************************************************************ +/**************************************************************************** * Definitions - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Type Declarations - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Function Prototypes - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Global Constant Data - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Global Variables - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Constant Data - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Variables - ************************************************************/ -/************************************************************ + ****************************************************************************/ +/**************************************************************************** * Global Functions - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * fwrite - ************************************************************/ + ****************************************************************************/ size_t fwrite(const void *ptr, size_t size, size_t n_items, FILE *stream) { diff --git a/nuttx/lib/lib_internal.h b/nuttx/lib/lib_internal.h index a2dd3b36b..4e3a508a8 100644 --- a/nuttx/lib/lib_internal.h +++ b/nuttx/lib/lib_internal.h @@ -160,6 +160,18 @@ extern ssize_t lib_fwrite(const void *ptr, size_t count, FILE *stream); extern ssize_t lib_fread(void *ptr, size_t count, FILE *stream); +/* Defined in lib_fflush.c */ + +extern ssize_t fflush_internal(FILE *stream, boolean bforce); + +/* Defined in lib_rdflush.c */ + +extern int lib_rdflush(FILE *stream); + +/* Defined in lib_wrflush.c */ + +int lib_wrflush(FILE *stream); + /* Defined in lib_sem.c */ #if CONFIG_STDIO_BUFFER_SIZE > 0 diff --git a/nuttx/lib/lib_libfread.c b/nuttx/lib/lib_libfread.c index 6607b55cc..15d50fbe9 100644 --- a/nuttx/lib/lib_libfread.c +++ b/nuttx/lib/lib_libfread.c @@ -1,7 +1,7 @@ -/************************************************************ - * lib_libfread.c +/**************************************************************************** + * lib/lib_libfread.c * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -14,7 +14,7 @@ * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. - * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,15 +31,15 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Compilation Switches - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Included Files - ************************************************************/ + ****************************************************************************/ #include /* for CONFIG_STDIO_BUFFER_SIZE */ #include @@ -49,41 +49,41 @@ #include #include "lib_internal.h" -/************************************************************ +/**************************************************************************** * Definitions - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Type Declarations - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Function Prototypes - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Global Constant Data - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Global Variables - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Constant Data - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Private Variables - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Global Functions - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * lib_fread - ************************************************************/ + ****************************************************************************/ ssize_t lib_fread(void *ptr, size_t count, FILE *stream) { @@ -92,7 +92,7 @@ ssize_t lib_fread(void *ptr, size_t count, FILE *stream) /* Make sure that reading from this stream is allowed */ - if ((!stream) || ((stream->fs_oflags & O_RDOK) == 0)) + if (!stream || (stream->fs_oflags & O_RDOK) == 0) { *get_errno_ptr() = EBADF; bytes_read = -1; @@ -107,148 +107,158 @@ ssize_t lib_fread(void *ptr, size_t count, FILE *stream) /* First, re-read any previously ungotten characters */ while ((stream->fs_nungotten > 0) && (count > 0)) - { - /* Decrement the count of ungotten bytes to get an index */ + { + /* Decrement the count of ungotten bytes to get an index */ - stream->fs_nungotten--; + stream->fs_nungotten--; - /* Return the last ungotten byte */ + /* Return the last ungotten byte */ - *dest++ = stream->fs_ungotten[stream->fs_nungotten]; + *dest++ = stream->fs_ungotten[stream->fs_nungotten]; - /* That's one less byte that we have to read */ + /* That's one less byte that we have to read */ - count--; - } + count--; + } #endif #if CONFIG_STDIO_BUFFER_SIZE > 0 + /* If the buffer is currently being used for write access, then + * flush all of the buffered write data. We do not support concurrent + * buffered read/write access. + */ + + if (lib_wrflush(stream) != 0) + { + return ERROR; + } + /* Now get any other needed chars from the buffer or the file. */ while (count > 0) - { - /* Is there readable data in the buffer? */ - - while ((count > 0) && (stream->fs_bufpos < stream->fs_bufread)) - { - /* Yes, copy a byte into the user buffer */ - - *dest++ = *stream->fs_bufpos++; - count--; - } - - /* The buffer is empty OR we have already supplied the number of - * bytes requested in the read. Check if we need to read - * more from the file. - */ - - if (count > 0) - { - size_t buffer_available; - - /* We need to read more data into the buffer from the file */ - - /* Mark the buffer empty */ - - stream->fs_bufpos = stream->fs_bufread = stream->fs_bufstart; - - /* How much space is available in the buffer? */ - - buffer_available = stream->fs_bufend - stream->fs_bufread; - - /* Will the number of bytes that we need to read fit into - * the buffer space that is available? If the read size is - * larger than the buffer, then read some of the data - * directly into the user's buffer. - */ - - if (count > buffer_available) - { - bytes_read = read(stream->fs_filedes, dest, count); - if (bytes_read < 0) - { - /* An error occurred on the read */ - - goto err_out; - } - else if (bytes_read == 0) - { - /* We are at the end of the file */ - - goto short_read; - } - else - { - /* Some bytes were read. Adjust the dest pointer */ - - dest += bytes_read; - - /* Were all of the requested bytes read? */ - - if (bytes_read < count) - { - /* No. We must be at the end of file. */ - - goto short_read; - } - else - { - /* Yes. We are done. */ - - count = 0; - } - } - } - else - { - /* The number of bytes required to satisfy the read - * is less than or equal to the size of the buffer - * space that we have left. Read as much as we can - * into the buffer. - */ - - bytes_read = read(stream->fs_filedes, stream->fs_bufread, buffer_available); - if (bytes_read < 0) - { - /* An error occurred on the read */ - - goto err_out; - } - else if (bytes_read == 0) - { - /* We are at the end of the file */ - - goto short_read; - } - else - { - /* Some bytes were read */ - - stream->fs_bufread += bytes_read; - } - } - } - } + { + /* Is there readable data in the buffer? */ + + while ((count > 0) && (stream->fs_bufpos < stream->fs_bufread)) + { + /* Yes, copy a byte into the user buffer */ + + *dest++ = *stream->fs_bufpos++; + count--; + } + + /* The buffer is empty OR we have already supplied the number of + * bytes requested in the read. Check if we need to read + * more from the file. + */ + + if (count > 0) + { + size_t buffer_available; + + /* We need to read more data into the buffer from the file */ + + /* Mark the buffer empty */ + + stream->fs_bufpos = stream->fs_bufread = stream->fs_bufstart; + + /* How much space is available in the buffer? */ + + buffer_available = stream->fs_bufend - stream->fs_bufread; + + /* Will the number of bytes that we need to read fit into + * the buffer space that is available? If the read size is + * larger than the buffer, then read some of the data + * directly into the user's buffer. + */ + + if (count > buffer_available) + { + bytes_read = read(stream->fs_filedes, dest, count); + if (bytes_read < 0) + { + /* An error occurred on the read */ + + goto err_out; + } + else if (bytes_read == 0) + { + /* We are at the end of the file */ + + goto short_read; + } + else + { + /* Some bytes were read. Adjust the dest pointer */ + + dest += bytes_read; + + /* Were all of the requested bytes read? */ + + if (bytes_read < count) + { + /* No. We must be at the end of file. */ + + goto short_read; + } + else + { + /* Yes. We are done. */ + + count = 0; + } + } + } + else + { + /* The number of bytes required to satisfy the read + * is less than or equal to the size of the buffer + * space that we have left. Read as much as we can + * into the buffer. + */ + + bytes_read = read(stream->fs_filedes, stream->fs_bufread, buffer_available); + if (bytes_read < 0) + { + /* An error occurred on the read */ + + goto err_out; + } + else if (bytes_read == 0) + { + /* We are at the end of the file */ + + goto short_read; + } + else + { + /* Some bytes were read */ + + stream->fs_bufread += bytes_read; + } + } + } + } #else /* Now get any other needed chars from the file. */ while (count > 0) - { - bytes_read = read(stream->fs_filedes, dest, count); - if (bytes_read < 0) - { - goto err_out; - } - else if (bytes_read == 0) - { - break; - } - else - { - dest += bytes_read; - count -= bytes_read; - } - } + { + bytes_read = read(stream->fs_filedes, dest, count); + if (bytes_read < 0) + { + goto err_out; + } + else if (bytes_read == 0) + { + break; + } + else + { + dest += bytes_read; + count -= bytes_read; + } + } #endif short_read: bytes_read = dest - (unsigned char*)ptr; diff --git a/nuttx/lib/lib_libfwrite.c b/nuttx/lib/lib_libfwrite.c index 361d88127..01bc3c285 100644 --- a/nuttx/lib/lib_libfwrite.c +++ b/nuttx/lib/lib_libfwrite.c @@ -83,7 +83,7 @@ ****************************************************************************/ /**************************************************************************** - * lib_fwrite + * Name: lib_fwrite ****************************************************************************/ ssize_t lib_fwrite(const void *ptr, size_t count, FILE *stream) @@ -91,73 +91,87 @@ ssize_t lib_fwrite(const void *ptr, size_t count, FILE *stream) { const unsigned char *start = ptr; const unsigned char *src = ptr; - ssize_t bytes_written; + ssize_t ret = ERROR; unsigned char *dest; /* Make sure that writing to this stream is allowed */ - if ((!stream) || ((stream->fs_oflags & O_WROK) == 0)) + if (!stream || (stream->fs_oflags & O_WROK) == 0) { *get_errno_ptr() = EBADF; - bytes_written = -1; + goto errout; } - else + + /* Get exclusive access to the stream */ + + lib_take_semaphore(stream); + + /* If the buffer is currently being used for read access, then + * discard all of the read-ahead data. We do not support concurrent + * buffered read/write access. + */ + + if (lib_rdflush(stream) < 0) { - /* Loop until all of the bytes have been buffered */ + goto errout_with_semaphore; + } - lib_take_semaphore(stream); - while (count > 0) - { - /* Determine the number of bytes left in the buffer */ + /* Loop until all of the bytes have been buffered */ - size_t gulp_size = stream->fs_bufend - stream->fs_bufpos; + while (count > 0) + { + /* Determine the number of bytes left in the buffer */ - /* Will the user data fit into the amount of buffer space - * that we have left? - */ + size_t gulp_size = stream->fs_bufend - stream->fs_bufpos; - if (gulp_size > count) - { - /* Yes, clip the gulp to the size of the user data */ + /* Will the user data fit into the amount of buffer space + * that we have left? + */ - gulp_size = count; - } + if (gulp_size > count) + { + /* Yes, clip the gulp to the size of the user data */ - /* Adjust the number of bytes remaining to be transferred - * on the next pass through the loop (might be zero). - */ + gulp_size = count; + } - count -= gulp_size; + /* Adjust the number of bytes remaining to be transferred + * on the next pass through the loop (might be zero). + */ - /* Transfer the data into the buffer */ + count -= gulp_size; - for (dest = stream->fs_bufpos; gulp_size > 0; gulp_size--) - { - *dest++ = *src++; - } - stream->fs_bufpos = dest; + /* Transfer the data into the buffer */ - /* Is the buffer full? */ + for (dest = stream->fs_bufpos; gulp_size > 0; gulp_size--) + { + *dest++ = *src++; + } + stream->fs_bufpos = dest; - if (dest >= stream->fs_bufend) - { - /* flush the buffered data to the IO stream */ + /* Is the buffer full? */ - int bytes_buffered = fflush(stream); - if (bytes_buffered < 0) - { - bytes_written = bytes_buffered; - goto err_out; - } - } - } - - bytes_written = src - start; + if (dest >= stream->fs_bufend) + { + /* Flush the buffered data to the IO stream */ - err_out: - lib_give_semaphore(stream); + int bytes_buffered = fflush_internal(stream, FALSE); + if (bytes_buffered < 0) + { + goto errout_with_semaphore; + } + } } - return bytes_written; + + /* Return the number of bytes written */ + + ret = src - start; + +errout_with_semaphore: + lib_give_semaphore(stream); + +errout: + return ret; } #else { diff --git a/nuttx/lib/lib_rdflush.c b/nuttx/lib/lib_rdflush.c new file mode 100644 index 000000000..d7d4380c5 --- /dev/null +++ b/nuttx/lib/lib_rdflush.c @@ -0,0 +1,144 @@ +/**************************************************************************** + * lib/lib_rdflush.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Compilation Switches + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "lib_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Global Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_rdflush + * + * Description: + * Flush read data from the I/O buffer and adjust the file pointer to + * account for the unread data + * + ****************************************************************************/ + +#if CONFIG_STDIO_BUFFER_SIZE > 0 +int lib_rdflush(FILE *stream) +{ + if (!stream) + { + *get_errno_ptr() = EBADF; + return ERROR; + } + + /* Get exclusive access to the stream */ + + lib_take_semaphore(stream); + + /* If the buffer is currently being used for read access, then discard all + * of the read-ahead data. We do not support concurrent buffered read/write + * access. + */ + + if (stream->fs_bufread != stream->fs_bufstart) + { + /* Now adjust the stream pointer to account for the read-ahead data that + * was not actually read by the user. + */ + +#if CONFIG_NUNGET_CHARS > 0 + off_t rdoffset = stream->fs_bufread - stream->fs_bufpos + stream->fs_nungotten; +#else + off_t rdoffset = stream->fs_bufread - stream->fs_bufpos; +#endif + /* Mark the buffer as empty (do this before calling fseek() because fseek() + * also calls this function). + */ + + stream->fs_bufpos = stream->fs_bufread = stream->fs_bufstart; +#if CONFIG_NUNGET_CHARS > 0 + stream->fs_nungotten = 0; +#endif + /* Then seek to the position corresponding to the last data read by the user */ + + if (fseek(stream, -rdoffset, SEEK_CUR) < 0) + { + lib_give_semaphore(stream); + return ERROR; + } + } + + lib_give_semaphore(stream); + return OK; +} +#endif /* CONFIG_STDIO_BUFFER_SIZE */ + diff --git a/nuttx/lib/lib_wrflush.c b/nuttx/lib/lib_wrflush.c new file mode 100644 index 000000000..cc2f65543 --- /dev/null +++ b/nuttx/lib/lib_wrflush.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * lib/lib_wrlush.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Compilation Switches + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "lib_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Global Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_wrflush + * + * Description: + * This is simply a version of fflush that does not report an error if + * the file is not open for writing. + * + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_wrflush + ****************************************************************************/ + +int lib_wrflush(FILE *stream) +{ +#if CONFIG_STDIO_BUFFER_SIZE > 0 + /* Verify that the stream is opened for writing... flush will return an + * error if it is called for a stream that is not opened for writing. + */ + + if (stream && (stream->fs_oflags & O_WROK) != 0) + { + return fflush(stream); + } +#endif + return OK; +} + -- cgit v1.2.3