OSDN Git Service

New stdio core. Should be more maintainable. Fixes a couple of bugs.
[uclinux-h8/uClibc.git] / libc / stdio / setvbuf.c
1 /* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
2  *
3  * GNU Library General Public License (LGPL) version 2 or later.
4  *
5  * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
6  */
7
8 #include "_stdio.h"
9
10 #if (_IOFBF != 0) || (_IOLBF != 1) || (_IONBF != 2)
11 #error Assumption violated -- values of _IOFBF, _IOLBF, _IONBF
12 #endif
13 #if (__FLAG_FBF != 0) || (__FLAG_NBF != (2*__FLAG_LBF))
14 #error Assumption violated for buffering mode flags
15 #endif
16
17 int setvbuf(register FILE * __restrict stream, register char * __restrict buf,
18                         int mode, size_t size)
19 {
20 #ifdef __STDIO_BUFFERS
21
22         int retval = EOF;
23         int alloc_flag = 0;
24         __STDIO_AUTO_THREADLOCK_VAR;
25
26         __STDIO_AUTO_THREADLOCK(stream);
27         __STDIO_STREAM_VALIDATE(stream);
28
29         if (((unsigned int) mode) > 2) {
30                 __set_errno(EINVAL);
31                 goto ERROR;
32         }
33
34         /* C99 states that setvbuf may only be used between a successful
35          * open of the stream and before any other operation other than
36          * an unsuccessful call to setvbuf. */
37
38 #ifdef __STDIO_FLEXIBLE_SETVBUF
39         /* If we aren't currently reading (including ungots) or writing,
40          * then allow the request to proceed. */
41
42         if (stream->__modeflags & (__MASK_READING|__FLAG_WRITING)) {
43                 goto ERROR;
44         }
45 #else
46         /* The following test isn't quite as strict as C99, as it will
47          * not detect file positioning operations. */
48
49         if (stream->__modeflags & (__MASK_READING|__FLAG_WRITING
50                                                          |__FLAG_NARROW|__FLAG_WIDE
51                                                          |__FLAG_ERROR|__FLAG_EOF)
52                 ) {
53                 goto ERROR;
54         }
55 #endif
56
57         stream->__modeflags &= ~(__MASK_BUFMODE);       /* Clear current mode */
58         stream->__modeflags |= mode * __FLAG_LBF;       /*   and set new one. */
59
60         if ((mode == _IONBF) || !size) {
61                 size = 0;
62                 buf = NULL;
63         } else if (!buf) {
64                 if ((__STDIO_STREAM_BUFFER_SIZE(stream) == size) /* Same size or */
65                         || !(buf = malloc(size)) /* malloc failed, so don't change. */
66                         ) {
67                         goto DONE;
68                 }
69                 alloc_flag = __FLAG_FREEBUF;
70         }
71
72         if (stream->__modeflags & __FLAG_FREEBUF) {
73                 stream->__modeflags &= ~(__FLAG_FREEBUF);
74                 free(stream->__bufstart);
75         }
76
77         stream->__modeflags |= alloc_flag;
78         stream->__bufstart = buf;
79         stream->__bufend = buf + size;
80         __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);
81         __STDIO_STREAM_DISABLE_GETC(stream);
82         __STDIO_STREAM_DISABLE_PUTC(stream);
83
84  DONE:
85         retval = 0;
86
87  ERROR:
88         __STDIO_STREAM_VALIDATE(stream);
89         __STDIO_AUTO_THREADUNLOCK(stream);
90
91         return retval;
92
93 #else  /* __STDIO_BUFFERS  */
94
95         if (mode == _IONBF) {
96                 return 0;
97         }
98
99         if (((unsigned int) mode) > 2) {
100                 __set_errno(EINVAL);
101         }
102
103         return EOF;
104
105 #endif
106 }