| /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> |
| * |
| * GNU Library General Public License (LGPL) version 2 or later. |
| * |
| * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. |
| */ |
| |
| #include "_stdio.h" |
| |
| #if (_IOFBF != 0) || (_IOLBF != 1) || (_IONBF != 2) |
| #error Assumption violated -- values of _IOFBF, _IOLBF, _IONBF |
| #endif |
| #if (__FLAG_FBF != 0) || (__FLAG_NBF != (2*__FLAG_LBF)) |
| #error Assumption violated for buffering mode flags |
| #endif |
| |
| int setvbuf(register FILE * __restrict stream, register char * __restrict buf, |
| int mode, size_t size) |
| { |
| #ifdef __STDIO_BUFFERS |
| |
| int retval = EOF; |
| int alloc_flag = 0; |
| __STDIO_AUTO_THREADLOCK_VAR; |
| |
| __STDIO_AUTO_THREADLOCK(stream); |
| __STDIO_STREAM_VALIDATE(stream); |
| |
| if (((unsigned int) mode) > 2) { |
| __set_errno(EINVAL); |
| goto ERROR; |
| } |
| |
| /* C99 states that setvbuf may only be used between a successful |
| * open of the stream and before any other operation other than |
| * an unsuccessful call to setvbuf. */ |
| |
| #ifdef __STDIO_FLEXIBLE_SETVBUF |
| /* If we aren't currently reading (including ungots) or writing, |
| * then allow the request to proceed. */ |
| |
| if (stream->__modeflags & (__MASK_READING|__FLAG_WRITING)) { |
| goto ERROR; |
| } |
| #else |
| /* The following test isn't quite as strict as C99, as it will |
| * not detect file positioning operations. */ |
| |
| if (stream->__modeflags & (__MASK_READING|__FLAG_WRITING |
| |__FLAG_NARROW|__FLAG_WIDE |
| |__FLAG_ERROR|__FLAG_EOF) |
| ) { |
| goto ERROR; |
| } |
| #endif |
| |
| stream->__modeflags &= ~(__MASK_BUFMODE); /* Clear current mode */ |
| stream->__modeflags |= mode * __FLAG_LBF; /* and set new one. */ |
| |
| if ((mode == _IONBF) || !size) { |
| size = 0; |
| buf = NULL; |
| } else if (!buf) { |
| if ((__STDIO_STREAM_BUFFER_SIZE(stream) == size) /* Same size or */ |
| || !(buf = malloc(size)) /* malloc failed, so don't change. */ |
| ) { |
| goto DONE; |
| } |
| alloc_flag = __FLAG_FREEBUF; |
| } |
| |
| if (stream->__modeflags & __FLAG_FREEBUF) { |
| stream->__modeflags &= ~(__FLAG_FREEBUF); |
| free(stream->__bufstart); |
| } |
| |
| stream->__modeflags |= alloc_flag; |
| stream->__bufstart = (unsigned char *) buf; |
| stream->__bufend = (unsigned char *) buf + size; |
| __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream); |
| __STDIO_STREAM_DISABLE_GETC(stream); |
| __STDIO_STREAM_DISABLE_PUTC(stream); |
| |
| DONE: |
| retval = 0; |
| |
| ERROR: |
| __STDIO_STREAM_VALIDATE(stream); |
| __STDIO_AUTO_THREADUNLOCK(stream); |
| |
| return retval; |
| |
| #else /* __STDIO_BUFFERS */ |
| |
| if (mode == _IONBF) { |
| return 0; |
| } |
| |
| if (((unsigned int) mode) > 2) { |
| __set_errno(EINVAL); |
| } |
| |
| return EOF; |
| |
| #endif |
| } |
| libc_hidden_def(setvbuf) |