]> git.saurik.com Git - apple/libc.git/blame - stdio/FreeBSD/makebuf.c
Libc-1439.100.3.tar.gz
[apple/libc.git] / stdio / FreeBSD / makebuf.c
CommitLineData
9385eb3d 1/*-
70ad1dc8
A
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
e9ce8d39
A
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
70ad1dc8 18 * 3. Neither the name of the University nor the names of its contributors
e9ce8d39
A
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
9385eb3d
A
35#if defined(LIBC_SCCS) && !defined(lint)
36static char sccsid[] = "@(#)makebuf.c 8.1 (Berkeley) 6/4/93";
37#endif /* LIBC_SCCS and not lint */
38#include <sys/cdefs.h>
70ad1dc8 39__FBSDID("$FreeBSD$");
e9ce8d39 40
9385eb3d 41#include "namespace.h"
e9ce8d39
A
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <unistd.h>
45#include <stdio.h>
46#include <stdlib.h>
9385eb3d 47#include "un-namespace.h"
e9ce8d39 48
1f2f436a
A
49#include "libc_private.h"
50#include "local.h"
70ad1dc8
A
51#include <xlocale/_stdio.h>
52#include <xlocale/_stdlib.h>
53#include <os/once_private.h>
1f2f436a 54
6465356a
A
55#ifdef FEATURE_SMALL_STDIOBUF
56# define MAXBUFSIZE (1 << 12)
57#else
58# define MAXBUFSIZE (1 << 16)
59#endif
60
ad3c9f2a 61#define TTYBUFSIZE 4096
70ad1dc8
A
62#define MAXEVPSIZE 16
63
64static char __fallback_evp[MAXEVPSIZE];
65static char __stdout_evp[MAXEVPSIZE];
66
67static void
68__loadevp(const char* key, char destination[MAXEVPSIZE])
69{
70 char* evp = getenv(key);
71 if (evp != NULL) {
72 strlcpy(destination, evp, MAXEVPSIZE);
73 } else {
74 destination[0] = '\0';
75 }
76}
77
78static void
79__evpinit(void* __unused unused)
80{
81 __loadevp("STDBUF", __fallback_evp);
82 __loadevp("STDBUF1", __stdout_evp);
83}
84
85static char*
86__getevp(int fd)
87{
88 static os_once_t predicate;
89 os_once(&predicate, NULL, __evpinit);
90
91 if (fd == STDOUT_FILENO && __stdout_evp[0] != '\0') {
92 return __stdout_evp;
93 } else if (__fallback_evp[0] != '\0') {
94 return __fallback_evp;
95 } else {
96 return NULL;
97 }
98
99}
100
101/*
102 * Internal routine to determine environment override buffering for a file.
103 *
104 * Sections of the below taken from NetBSD's version of this file under the same license.
105 */
106static int
107__senvbuf(FILE *fp, size_t *bufsize, int *couldbetty)
108{
109 char* evp;
110 char* end;
111 int flags;
112 long size;
113
114 flags = 0; // Default to fully buffered
115
116 if ((evp = __getevp(fp->_file)) == NULL) {
117 return flags;
118 }
119
120 // Look at the first character only to determine buffering mode
121 switch (*evp) {
122 case 'u':
123 case 'U':
124 flags |= __SNBF;
125 break;
126 case 'l':
127 case 'L':
128 flags |= __SLBF;
129 break;
130 case 'f':
131 case 'F':
132 // Default flags is fully buffered
133 break;
134 default:
135 // Unexpected buffering mode, use default fully buffered
136 return flags;
137 }
138 // User specified envrionment defaults have higher priority than tty defaults
139 *couldbetty = 0;
140
141 // Advance the envrionment variable pointer, so we can attempt to parse the number
142 evp++;
143 if (!isdigit(*evp)) {
144 return flags; // No number found, this protects us from negative size values
145 }
146
507116e3 147 size = strtol_l(evp, &end, 10, LC_C_LOCALE);
70ad1dc8
A
148 if (*end != '\0') {
149 return flags;
150 }
151
152 if (size <= 0) {
153 return __SNBF; // Override with unbuffered if the buffer size is 0
154 }
155
156 // We had a non zero buffer, cap it and return the flags;
157 *bufsize = size > MAXBUFSIZE ? MAXBUFSIZE : size;
158 return flags;
159}
ad3c9f2a 160
e9ce8d39
A
161/*
162 * Allocate a file buffer, or switch to unbuffered I/O.
163 * Per the ANSI C standard, ALL tty devices default to line buffered.
164 *
165 * As a side effect, we set __SOPT or __SNPT (en/dis-able fseek
9385eb3d 166 * optimisation) right after the _fstat() that finds the buffer size.
e9ce8d39
A
167 */
168void
70ad1dc8 169__smakebuf(FILE *fp)
e9ce8d39 170{
9385eb3d
A
171 void *p;
172 int flags;
e9ce8d39
A
173 size_t size;
174 int couldbetty;
175
176 if (fp->_flags & __SNBF) {
177 fp->_bf._base = fp->_p = fp->_nbuf;
178 fp->_bf._size = 1;
179 return;
180 }
181 flags = __swhatbuf(fp, &size, &couldbetty);
70ad1dc8
A
182 if (fp->_file >= 0) {
183 flags |= __senvbuf(fp, &size, &couldbetty);
184
185 if (flags & __SNBF) {
186 fp->_flags |= __SNBF;
187 fp->_bf._base = fp->_p = fp->_nbuf;
188 fp->_bf._size = 1;
189 return;
190 }
191 }
192
ad3c9f2a
A
193 if (couldbetty && isatty(fp->_file)) {
194 flags |= __SLBF;
195 /* st_blksize for ttys is 128K, so make it more reasonable */
196 if (size > TTYBUFSIZE)
197 fp->_blksize = size = TTYBUFSIZE;
198 }
e9ce8d39
A
199 if ((p = malloc(size)) == NULL) {
200 fp->_flags |= __SNBF;
201 fp->_bf._base = fp->_p = fp->_nbuf;
202 fp->_bf._size = 1;
203 return;
204 }
205 __cleanup = _cleanup;
206 flags |= __SMBF;
207 fp->_bf._base = fp->_p = p;
208 fp->_bf._size = size;
e9ce8d39
A
209 fp->_flags |= flags;
210}
211
212/*
213 * Internal routine to determine `proper' buffering for a file.
214 */
215int
70ad1dc8 216__swhatbuf(FILE *fp, size_t *bufsize, int *couldbetty)
e9ce8d39
A
217{
218 struct stat st;
219
9385eb3d 220 if (fp->_file < 0 || _fstat(fp->_file, &st) < 0) {
e9ce8d39
A
221 *couldbetty = 0;
222 *bufsize = BUFSIZ;
223 return (__SNPT);
224 }
225
226 /* could be a tty iff it is a character device */
227 *couldbetty = (st.st_mode & S_IFMT) == S_IFCHR;
228 if (st.st_blksize <= 0) {
229 *bufsize = BUFSIZ;
230 return (__SNPT);
231 }
232
233 /*
234 * Optimise fseek() only if it is a regular file. (The test for
235 * __sseek is mainly paranoia.) It is safe to set _blksize
236 * unconditionally; it will only be used if __SOPT is also set.
237 */
ad3c9f2a 238 fp->_blksize = *bufsize = st.st_blksize > MAXBUFSIZE ? MAXBUFSIZE : st.st_blksize;
e9ce8d39
A
239 return ((st.st_mode & S_IFMT) == S_IFREG && fp->_seek == __sseek ?
240 __SOPT : __SNPT);
241}