xref: /original-bsd/lib/libc/stdio/setvbuf.c (revision eafa6506)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)setvbuf.c	5.2 (Berkeley) 02/01/91";
13 #endif /* LIBC_SCCS and not lint */
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include "local.h"
18 
19 /*
20  * Set one of the three kinds of buffering, optionally including
21  * a buffer.
22  */
23 setvbuf(fp, buf, mode, size)
24 	register FILE *fp;
25 	char *buf;
26 	register int mode;
27 	register size_t size;
28 {
29 
30 	/*
31 	 * Verify arguments.  The `int' limit on `size' is due to this
32 	 * particular implementation.
33 	 */
34 	if ((mode != _IOFBF && mode != _IOLBF && mode != _IONBF) ||
35 	    (int)size < 0)
36 		return (EOF);
37 
38 	/*
39 	 * Write current buffer, if any; drop read count, if any.
40 	 * Make sure putc() will not think fp is line buffered.
41 	 * Free old buffer if it was from malloc().  Clear line and
42 	 * non buffer flags, and clear malloc flag.
43 	 */
44 	(void) __sflush(fp);
45 	fp->_r = 0;
46 	fp->_lbfsize = 0;
47 	if (fp->_flags & __SMBF)
48 		free((void *)fp->_bf._base);
49 	fp->_flags &= ~(__SLBF|__SNBF|__SMBF);
50 
51 	/*
52 	 * Now put back whichever flag is needed, and fix _lbfsize
53 	 * if line buffered.  Ensure output flush on exit if the
54 	 * stream will be buffered at all.
55 	 */
56 	switch (mode) {
57 
58 	case _IONBF:
59 		fp->_flags |= __SNBF;
60 		fp->_bf._base = fp->_p = fp->_nbuf;
61 		fp->_bf._size = 1;
62 		break;
63 
64 	case _IOLBF:
65 		fp->_flags |= __SLBF;
66 		fp->_lbfsize = -size;
67 		/* FALLTHROUGH */
68 
69 	case _IOFBF:
70 		/* no flag */
71 		__cleanup = _cleanup;
72 		fp->_bf._base = fp->_p = (unsigned char *)buf;
73 		fp->_bf._size = size;
74 		break;
75 	}
76 
77 	/*
78 	 * Patch up write count if necessary.
79 	 */
80 	if (fp->_flags & __SWR)
81 		fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : size;
82 
83 	return (0);
84 }
85