xref: /dflybsd-src/lib/libstdbuf/stdbuf.c (revision ec21d9fbfac028108ef0d30283d74b804e16da33)
1*ec21d9fbSAaron LI /*-
2*ec21d9fbSAaron LI  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*ec21d9fbSAaron LI  *
4*ec21d9fbSAaron LI  * Copyright (c) 2012 Jeremie Le Hen <jlh@FreeBSD.org>
5*ec21d9fbSAaron LI  * All rights reserved.
6*ec21d9fbSAaron LI  *
7*ec21d9fbSAaron LI  * Redistribution and use in source and binary forms, with or without
8*ec21d9fbSAaron LI  * modification, are permitted provided that the following conditions
9*ec21d9fbSAaron LI  * are met:
10*ec21d9fbSAaron LI  * 1. Redistributions of source code must retain the above copyright
11*ec21d9fbSAaron LI  *    notice, this list of conditions and the following disclaimer.
12*ec21d9fbSAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
13*ec21d9fbSAaron LI  *    notice, this list of conditions and the following disclaimer in the
14*ec21d9fbSAaron LI  *    documentation and/or other materials provided with the distribution.
15*ec21d9fbSAaron LI  *
16*ec21d9fbSAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*ec21d9fbSAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*ec21d9fbSAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*ec21d9fbSAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*ec21d9fbSAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*ec21d9fbSAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*ec21d9fbSAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*ec21d9fbSAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*ec21d9fbSAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*ec21d9fbSAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*ec21d9fbSAaron LI  * SUCH DAMAGE.
27*ec21d9fbSAaron LI  *
28*ec21d9fbSAaron LI  * $FreeBSD$
29*ec21d9fbSAaron LI  */
30*ec21d9fbSAaron LI 
31*ec21d9fbSAaron LI #include <err.h>
32*ec21d9fbSAaron LI #include <errno.h>
33*ec21d9fbSAaron LI #include <limits.h>
34*ec21d9fbSAaron LI #include <stdio.h>
35*ec21d9fbSAaron LI #include <stdlib.h>
36*ec21d9fbSAaron LI #include <string.h>
37*ec21d9fbSAaron LI 
38*ec21d9fbSAaron LI static const char *
stream_name(FILE * s)39*ec21d9fbSAaron LI stream_name(FILE *s)
40*ec21d9fbSAaron LI {
41*ec21d9fbSAaron LI 
42*ec21d9fbSAaron LI 	if (s == stdin)
43*ec21d9fbSAaron LI 		return "stdin";
44*ec21d9fbSAaron LI 	if (s == stdout)
45*ec21d9fbSAaron LI 		return "stdout";
46*ec21d9fbSAaron LI 	if (s == stderr)
47*ec21d9fbSAaron LI 		return "stderr";
48*ec21d9fbSAaron LI 	/* This should not happen. */
49*ec21d9fbSAaron LI 	abort();
50*ec21d9fbSAaron LI }
51*ec21d9fbSAaron LI 
52*ec21d9fbSAaron LI static void
change_buf(FILE * s,const char * bufmode)53*ec21d9fbSAaron LI change_buf(FILE *s, const char *bufmode)
54*ec21d9fbSAaron LI {
55*ec21d9fbSAaron LI 	char *unit;
56*ec21d9fbSAaron LI 	size_t bufsize;
57*ec21d9fbSAaron LI 	int mode;
58*ec21d9fbSAaron LI 
59*ec21d9fbSAaron LI 	bufsize = 0;
60*ec21d9fbSAaron LI 	if (bufmode[0] == '0' && bufmode[1] == '\0')
61*ec21d9fbSAaron LI 		mode = _IONBF;
62*ec21d9fbSAaron LI 	else if (bufmode[0] == 'L' && bufmode[1] == '\0')
63*ec21d9fbSAaron LI 		mode = _IOLBF;
64*ec21d9fbSAaron LI 	else if (bufmode[0] == 'B' && bufmode[1] == '\0') {
65*ec21d9fbSAaron LI 		mode = _IOFBF;
66*ec21d9fbSAaron LI 		bufsize = 0;
67*ec21d9fbSAaron LI 	} else {
68*ec21d9fbSAaron LI 		/*
69*ec21d9fbSAaron LI 		 * This library being preloaded, depending on libutil
70*ec21d9fbSAaron LI 		 * would lead to excessive namespace pollution.
71*ec21d9fbSAaron LI 		 * Thus we do not use expand_number().
72*ec21d9fbSAaron LI 		 */
73*ec21d9fbSAaron LI 		errno = 0;
74*ec21d9fbSAaron LI 		bufsize = strtol(bufmode, &unit, 0);
75*ec21d9fbSAaron LI 		if (errno == EINVAL || errno == ERANGE || unit == bufmode)
76*ec21d9fbSAaron LI 			warn("Wrong buffer mode '%s' for %s", bufmode,
77*ec21d9fbSAaron LI 			    stream_name(s));
78*ec21d9fbSAaron LI 		switch (*unit) {
79*ec21d9fbSAaron LI 		case 'G':
80*ec21d9fbSAaron LI 			bufsize *= 1024 * 1024 * 1024;
81*ec21d9fbSAaron LI 			break;
82*ec21d9fbSAaron LI 		case 'M':
83*ec21d9fbSAaron LI 			bufsize *= 1024 * 1024;
84*ec21d9fbSAaron LI 			break;
85*ec21d9fbSAaron LI 		case 'k':
86*ec21d9fbSAaron LI 			bufsize *= 1024;
87*ec21d9fbSAaron LI 			break;
88*ec21d9fbSAaron LI 		case '\0':
89*ec21d9fbSAaron LI 			break;
90*ec21d9fbSAaron LI 		default:
91*ec21d9fbSAaron LI 			warnx("Unknown suffix '%c' for %s", *unit,
92*ec21d9fbSAaron LI 			    stream_name(s));
93*ec21d9fbSAaron LI 			return;
94*ec21d9fbSAaron LI 		}
95*ec21d9fbSAaron LI 		mode = _IOFBF;
96*ec21d9fbSAaron LI 	}
97*ec21d9fbSAaron LI 	if (setvbuf(s, NULL, mode, bufsize) != 0)
98*ec21d9fbSAaron LI 		warn("Cannot set buffer mode '%s' for %s", bufmode,
99*ec21d9fbSAaron LI 		    stream_name(s));
100*ec21d9fbSAaron LI }
101*ec21d9fbSAaron LI 
102*ec21d9fbSAaron LI __attribute__ ((constructor)) static void
stdbuf(void)103*ec21d9fbSAaron LI stdbuf(void)
104*ec21d9fbSAaron LI {
105*ec21d9fbSAaron LI 	char *i_mode, *o_mode, *e_mode;
106*ec21d9fbSAaron LI 
107*ec21d9fbSAaron LI 	i_mode = getenv("_STDBUF_I");
108*ec21d9fbSAaron LI 	o_mode = getenv("_STDBUF_O");
109*ec21d9fbSAaron LI 	e_mode = getenv("_STDBUF_E");
110*ec21d9fbSAaron LI 
111*ec21d9fbSAaron LI 	if (e_mode != NULL)
112*ec21d9fbSAaron LI 		change_buf(stderr, e_mode);
113*ec21d9fbSAaron LI 	if (i_mode != NULL)
114*ec21d9fbSAaron LI 		change_buf(stdin, i_mode);
115*ec21d9fbSAaron LI 	if (o_mode != NULL)
116*ec21d9fbSAaron LI 		change_buf(stdout, o_mode);
117*ec21d9fbSAaron LI }
118