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 
setvbuf(register FILE * __restrict stream,register char * __restrict buf,int mode,size_t size)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 = (unsigned char *) buf;
79 	stream->__bufend = (unsigned char *) 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 }
107 libc_hidden_def(setvbuf)
108