1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. 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 8.2 (Berkeley) 11/16/93";
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 */
setvbuf(fp,buf,mode,size)23 setvbuf(fp, buf, mode, size)
24 register FILE *fp;
25 char *buf;
26 register int mode;
27 register size_t size;
28 {
29 register int ret, flags;
30 size_t iosize;
31 int ttyflag;
32
33 /*
34 * Verify arguments. The `int' limit on `size' is due to this
35 * particular implementation. Note, buf and size are ignored
36 * when setting _IONBF.
37 */
38 if (mode != _IONBF)
39 if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0)
40 return (EOF);
41
42 /*
43 * Write current buffer, if any. Discard unread input (including
44 * ungetc data), cancel line buffering, and free old buffer if
45 * malloc()ed. We also clear any eof condition, as if this were
46 * a seek.
47 */
48 ret = 0;
49 (void)__sflush(fp);
50 if (HASUB(fp))
51 FREEUB(fp);
52 fp->_r = fp->_lbfsize = 0;
53 flags = fp->_flags;
54 if (flags & __SMBF)
55 free((void *)fp->_bf._base);
56 flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT | __SEOF);
57
58 /* If setting unbuffered mode, skip all the hard work. */
59 if (mode == _IONBF)
60 goto nbf;
61
62 /*
63 * Find optimal I/O size for seek optimization. This also returns
64 * a `tty flag' to suggest that we check isatty(fd), but we do not
65 * care since our caller told us how to buffer.
66 */
67 flags |= __swhatbuf(fp, &iosize, &ttyflag);
68 if (size == 0) {
69 buf = NULL; /* force local allocation */
70 size = iosize;
71 }
72
73 /* Allocate buffer if needed. */
74 if (buf == NULL) {
75 if ((buf = malloc(size)) == NULL) {
76 /*
77 * Unable to honor user's request. We will return
78 * failure, but try again with file system size.
79 */
80 ret = EOF;
81 if (size != iosize) {
82 size = iosize;
83 buf = malloc(size);
84 }
85 }
86 if (buf == NULL) {
87 /* No luck; switch to unbuffered I/O. */
88 nbf:
89 fp->_flags = flags | __SNBF;
90 fp->_w = 0;
91 fp->_bf._base = fp->_p = fp->_nbuf;
92 fp->_bf._size = 1;
93 return (ret);
94 }
95 flags |= __SMBF;
96 }
97
98 /*
99 * Kill any seek optimization if the buffer is not the
100 * right size.
101 *
102 * SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)?
103 */
104 if (size != iosize)
105 flags |= __SNPT;
106
107 /*
108 * Fix up the FILE fields, and set __cleanup for output flush on
109 * exit (since we are buffered in some way).
110 */
111 if (mode == _IOLBF)
112 flags |= __SLBF;
113 fp->_flags = flags;
114 fp->_bf._base = fp->_p = (unsigned char *)buf;
115 fp->_bf._size = size;
116 /* fp->_lbfsize is still 0 */
117 if (flags & __SWR) {
118 /*
119 * Begin or continue writing: see __swsetup(). Note
120 * that __SNBF is impossible (it was handled earlier).
121 */
122 if (flags & __SLBF) {
123 fp->_w = 0;
124 fp->_lbfsize = -fp->_bf._size;
125 } else
126 fp->_w = size;
127 } else {
128 /* begin/continue reading, or stay in intermediate state */
129 fp->_w = 0;
130 }
131 __cleanup = _cleanup;
132
133 return (ret);
134 }
135