setvbuf: Correct some errors detected by code review.
This commit is contained in:
parent
ea53894e51
commit
a92887c63d
@ -249,7 +249,6 @@ FAR struct file_struct *fs_fdopen(int fd, int oflags, FAR struct tcb_s *tcb)
|
|||||||
|
|
||||||
stream->fs_bufend = &stream->fs_bufstart[CONFIG_STDIO_BUFFER_SIZE];
|
stream->fs_bufend = &stream->fs_bufstart[CONFIG_STDIO_BUFFER_SIZE];
|
||||||
stream->fs_bufpos = stream->fs_bufstart;
|
stream->fs_bufpos = stream->fs_bufstart;
|
||||||
stream->fs_bufpos = stream->fs_bufstart;
|
|
||||||
stream->fs_bufread = stream->fs_bufstart;
|
stream->fs_bufread = stream->fs_bufstart;
|
||||||
|
|
||||||
/* Setup buffer flags */
|
/* Setup buffer flags */
|
||||||
|
@ -98,11 +98,12 @@
|
|||||||
int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
||||||
{
|
{
|
||||||
#if CONFIG_STDIO_BUFFER_SIZE > 0
|
#if CONFIG_STDIO_BUFFER_SIZE > 0
|
||||||
|
FAR unsigned char *newbuf;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
int errcode;
|
int errcode;
|
||||||
int ret = OK;
|
|
||||||
|
|
||||||
/* Verify arguments */
|
/* Verify arguments */
|
||||||
|
/* Make sure that a valid mode was provided */
|
||||||
|
|
||||||
if (mode != _IOFBF && mode != _IOLBF && mode != _IONBF)
|
if (mode != _IOFBF && mode != _IOLBF && mode != _IONBF)
|
||||||
{
|
{
|
||||||
@ -110,24 +111,7 @@ int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that the size argument agrees with the mode */
|
/* If a buffer pointer is provided, then it must have a non-zero size */
|
||||||
|
|
||||||
if (((mode == _IOFBF || mode == _IOLBF) && size == 0) ||
|
|
||||||
(mode == _IONBF && size > 0))
|
|
||||||
{
|
|
||||||
errcode = EINVAL;
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure that the buffer argument agrees with mode */
|
|
||||||
|
|
||||||
if (mode == _IONBF && buffer != NULL)
|
|
||||||
{
|
|
||||||
errcode = EINVAL;
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure that the buffer and size argeuments agree */
|
|
||||||
|
|
||||||
if (buffer != NULL && size == 0)
|
if (buffer != NULL && size == 0)
|
||||||
{
|
{
|
||||||
@ -135,6 +119,16 @@ int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A non-zero size (or a non-NULL buffer) with mode = _IONBF makes no
|
||||||
|
* sense.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (mode == _IONBF && size > 0)
|
||||||
|
{
|
||||||
|
errcode = EINVAL;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
#if 1 /* REVISIT: _IONBF not yet supported */
|
#if 1 /* REVISIT: _IONBF not yet supported */
|
||||||
/* Not all features are be available. Without some additional logic,
|
/* Not all features are be available. Without some additional logic,
|
||||||
* we cannot disable buffering if CONFIG_STDIO_BUFFER_SIZE > 0
|
* we cannot disable buffering if CONFIG_STDIO_BUFFER_SIZE > 0
|
||||||
@ -147,6 +141,19 @@ int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* My assumption is that if size is zero for modes {_IOFBF, _IOLBF} the
|
||||||
|
* caller is only attempting to change the buffering mode. In this case,
|
||||||
|
* the existing buffer should be re-used (if there is one). If there is no
|
||||||
|
* existing buffer, then I suppose we should allocate one of the default
|
||||||
|
* size?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((mode == _IOFBF || mode == _IOLBF) && size == 0 &&
|
||||||
|
stream->fs_bufstart == NULL)
|
||||||
|
{
|
||||||
|
size = CONFIG_STDIO_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure that we have exclusive access to the stream */
|
/* Make sure that we have exclusive access to the stream */
|
||||||
|
|
||||||
lib_take_semaphore(stream);
|
lib_take_semaphore(stream);
|
||||||
@ -166,6 +173,8 @@ int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
|||||||
/* Return EBUSY if operations have already been performed on the buffer.
|
/* Return EBUSY if operations have already been performed on the buffer.
|
||||||
* Here we really only verify that there is no valid data in the existing
|
* Here we really only verify that there is no valid data in the existing
|
||||||
* buffer.
|
* buffer.
|
||||||
|
*
|
||||||
|
* REVIST: There could be race conditions here, could there not?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (stream->fs_bufpos != stream->fs_bufstart)
|
if (stream->fs_bufpos != stream->fs_bufstart)
|
||||||
@ -185,82 +194,96 @@ int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
|
|||||||
flags = stream->fs_flags & ~(__FS_FLAG_LBF | __FS_FLAG_NBF | __FS_FLAG_UBF);
|
flags = stream->fs_flags & ~(__FS_FLAG_LBF | __FS_FLAG_NBF | __FS_FLAG_UBF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate a new buffer if one is needed. We have already verified that:
|
/* Allocate a new buffer if one is needed or reuse the existing buffer it
|
||||||
*
|
* is appropriate to do so.
|
||||||
* If a buffer is needed, then size > 0
|
|
||||||
* If a buffer is NOT needed, then buffer is NULL
|
|
||||||
* If buffer != NULL, then size > 0
|
|
||||||
*
|
|
||||||
* That simplifies the following check:
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if 0 /* REVISIT: _IONBF not yet supported */
|
switch (mode)
|
||||||
if (size > 0)
|
|
||||||
#else
|
|
||||||
DEBUGASSERT(size > 0);
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
FAR unsigned char *newbuf;
|
case _IOLBF:
|
||||||
|
flags |= __FS_FLAG_LBF;
|
||||||
|
|
||||||
/* A buffer is needed. Did the caller provide the buffer memory? */
|
/* Fall through */
|
||||||
|
|
||||||
DEBUGASSERT(mode == _IOFBF || mode == _IOLBF);
|
case _IOFBF:
|
||||||
if (buffer != NULL)
|
/* Use the existing buffer if size == 0 */
|
||||||
{
|
|
||||||
newbuf = (FAR unsigned char *)buffer;
|
|
||||||
|
|
||||||
/* Indicate that we have an I/O buffer managed by the caller of
|
if (size > 0)
|
||||||
* setvbuf.
|
{
|
||||||
*/
|
/* A new buffer is needed. Did the caller provide the buffer
|
||||||
|
* memory?
|
||||||
|
*/
|
||||||
|
|
||||||
flags |= __FS_FLAG_UBF;
|
if (buffer != NULL)
|
||||||
}
|
{
|
||||||
else
|
newbuf = (FAR unsigned char *)buffer;
|
||||||
{
|
|
||||||
newbuf = (FAR unsigned char *)lib_malloc(size);
|
|
||||||
if (newbuf == NULL)
|
|
||||||
{
|
|
||||||
errcode = ENOMEM;
|
|
||||||
goto errout_with_semaphore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not release the previous buffer if it was allocated by the user
|
/* Indicate that we have an I/O buffer managed by the caller of
|
||||||
* on a previous call to setvbuf().
|
* setvbuf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((stream->fs_flags & __FS_FLAG_UBF) != 0)
|
flags |= __FS_FLAG_UBF;
|
||||||
{
|
}
|
||||||
lib_free(stream->fs_bufstart);
|
else
|
||||||
}
|
{
|
||||||
|
newbuf = (FAR unsigned char *)lib_malloc(size);
|
||||||
|
if (newbuf == NULL)
|
||||||
|
{
|
||||||
|
errcode = ENOMEM;
|
||||||
|
goto errout_with_semaphore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Re-use the existing buffer and retain some existing flags.
|
||||||
|
* This supports changing the buffering mode without changing
|
||||||
|
* the buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Use the new buffer */
|
DEBUGASSERT(stream->fs_bufstart != NULL);
|
||||||
|
flags |= stream->fs_flags & __FS_FLAG_UBF;
|
||||||
|
goto reuse_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
stream->fs_bufstart = newbuf;
|
break;
|
||||||
stream->fs_bufend = newbuf;
|
|
||||||
stream->fs_bufpos = newbuf;
|
|
||||||
stream->fs_bufread = newbuf;
|
|
||||||
|
|
||||||
/* Check for line buffering */
|
case _IONBF:
|
||||||
|
|
||||||
if (mode == _IOLBF)
|
|
||||||
{
|
|
||||||
flags |= __FS_FLAG_LBF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if 0 /* REVISIT: _IONBF not yet supported */
|
#if 0 /* REVISIT: _IONBF not yet supported */
|
||||||
else
|
/* No buffer needed... We must be performing unbuffered I/O */
|
||||||
{
|
|
||||||
/* No buffer needed... We must be performing unbuffered I/O */
|
|
||||||
|
|
||||||
DEBUGASSERT(mode == _IONBF);
|
DEBUGASSERT(size == 0);
|
||||||
flags |= __FS_FLAG_NBF;
|
newbuf = NULL;
|
||||||
}
|
flags |= __FS_FLAG_NBF;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
PANIC();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not release the previous buffer if it was allocated by the user
|
||||||
|
* on a previous call to setvbuf().
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (stream->fs_bufstart != NULL &&
|
||||||
|
(stream->fs_flags & __FS_FLAG_UBF) == 0)
|
||||||
|
{
|
||||||
|
lib_free(stream->fs_bufstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the new buffer information */
|
||||||
|
|
||||||
|
stream->fs_bufstart = newbuf;
|
||||||
|
stream->fs_bufpos = newbuf;
|
||||||
|
stream->fs_bufread = newbuf;
|
||||||
|
stream->fs_bufend = newbuf + size;
|
||||||
|
|
||||||
/* Update the stream flags and return success */
|
/* Update the stream flags and return success */
|
||||||
|
|
||||||
stream->fs_flags = flags;
|
reuse_buffer:
|
||||||
|
|
||||||
|
stream->fs_flags = flags;
|
||||||
lib_give_semaphore(stream);
|
lib_give_semaphore(stream);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user