xref: /csrg-svn/lib/libc/stdio/setvbuf.c (revision 56990)
146111Sbostic /*-
246111Sbostic  * Copyright (c) 1990 The Regents of the University of California.
346111Sbostic  * All rights reserved.
446111Sbostic  *
546111Sbostic  * This code is derived from software contributed to Berkeley by
646111Sbostic  * Chris Torek.
746111Sbostic  *
846111Sbostic  * %sccs.include.redist.c%
946111Sbostic  */
1046111Sbostic 
1146111Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*56990Storek static char sccsid[] = "@(#)setvbuf.c	5.4 (Berkeley) 12/04/92";
1346111Sbostic #endif /* LIBC_SCCS and not lint */
1446111Sbostic 
1546111Sbostic #include <stdio.h>
1646111Sbostic #include <stdlib.h>
1746111Sbostic #include "local.h"
1846111Sbostic 
1946111Sbostic /*
2046111Sbostic  * Set one of the three kinds of buffering, optionally including
2146111Sbostic  * a buffer.
2246111Sbostic  */
2346111Sbostic setvbuf(fp, buf, mode, size)
2446111Sbostic 	register FILE *fp;
2546111Sbostic 	char *buf;
2646111Sbostic 	register int mode;
2746111Sbostic 	register size_t size;
2846111Sbostic {
29*56990Storek 	register int ret, flags;
3046111Sbostic 
3146111Sbostic 	/*
3246111Sbostic 	 * Verify arguments.  The `int' limit on `size' is due to this
3346111Sbostic 	 * particular implementation.
3446111Sbostic 	 */
3546111Sbostic 	if ((mode != _IOFBF && mode != _IOLBF && mode != _IONBF) ||
3646111Sbostic 	    (int)size < 0)
3746111Sbostic 		return (EOF);
3846111Sbostic 
3946111Sbostic 	/*
40*56990Storek 	 * OK so far.  Write current buffer, if any; drop read count, if
41*56990Storek 	 * any.  Make sure putc() will not think fp is line buffered.  Free
42*56990Storek 	 * old buffer if it was from malloc().  Clear line and non-buffer
43*56990Storek 	 * flags, and clear malloc flag.
4446111Sbostic 	 */
45*56990Storek 	ret = 0;
4646217Sbostic 	(void) __sflush(fp);
4746111Sbostic 	fp->_r = 0;
4846111Sbostic 	fp->_lbfsize = 0;
49*56990Storek 	flags = fp->_flags;
50*56990Storek 	if (flags & __SMBF)
5146111Sbostic 		free((void *)fp->_bf._base);
52*56990Storek 	flags &= ~(__SLBF | __SNBF | __SMBF);
5346111Sbostic 
54*56990Storek 	if (size == 0)
55*56990Storek 		buf = NULL;	/* we will make a real one later */
56*56990Storek 	else if (buf == NULL) {
57*56990Storek 		/*
58*56990Storek 		 * Caller wants specific buffering mode and size but did
59*56990Storek 		 * not provide a buffer.  Produce one of the given size.
60*56990Storek 		 * If that fails, set the size to 0 and continue, so that
61*56990Storek 		 * we will try again later with a system-supplied size
62*56990Storek 		 * (failure here is probably from someone with the bogus
63*56990Storek 		 * idea that larger is always better, asking for many MB),
64*56990Storek 		 * but return EOF to indicate failure.
65*56990Storek 		 */
66*56990Storek 		if ((buf = malloc(size)) == NULL) {
67*56990Storek 			ret = EOF;
68*56990Storek 			size = 0;
69*56990Storek 		} else
70*56990Storek 			flags |= __SMBF;
71*56990Storek 	}
72*56990Storek 
7346111Sbostic 	/*
74*56990Storek 	 * Now put back whichever flag is needed, and fix _lbfsize if line
75*56990Storek 	 * buffered.  Ensure output flush on exit if the stream will be
76*56990Storek 	 * buffered at all.
7746111Sbostic 	 */
7846111Sbostic 	switch (mode) {
7946111Sbostic 
8046111Sbostic 	case _IONBF:
81*56990Storek 		flags |= __SNBF;
8246111Sbostic 		fp->_bf._base = fp->_p = fp->_nbuf;
8346111Sbostic 		fp->_bf._size = 1;
8446111Sbostic 		break;
8546111Sbostic 
8646111Sbostic 	case _IOLBF:
87*56990Storek 		flags |= __SLBF;
8846111Sbostic 		fp->_lbfsize = -size;
8946111Sbostic 		/* FALLTHROUGH */
9046111Sbostic 
9146111Sbostic 	case _IOFBF:
9246111Sbostic 		/* no flag */
9346111Sbostic 		__cleanup = _cleanup;
9446111Sbostic 		fp->_bf._base = fp->_p = (unsigned char *)buf;
9546111Sbostic 		fp->_bf._size = size;
9646111Sbostic 		break;
9746111Sbostic 	}
9846111Sbostic 
9946111Sbostic 	/*
10046111Sbostic 	 * Patch up write count if necessary.
10146111Sbostic 	 */
102*56990Storek 	if (flags & __SWR)
103*56990Storek 		fp->_w = flags & (__SLBF | __SNBF) ? 0 : size;
104*56990Storek 	fp->_flags = flags;
10546111Sbostic 
106*56990Storek 	return (ret);
10746111Sbostic }
108