]>
Commit | Line | Data |
---|---|---|
082e680b MNI |
1 | /* Copyright (C) 2004 Manuel Novoa III <[email protected]> |
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 | } |