1234772Sjlh/*-
2234772Sjlh * Copyright (c) 2012 Jeremie Le Hen <jlh@FreeBSD.org>
3234772Sjlh * All rights reserved.
4234772Sjlh *
5234772Sjlh * Redistribution and use in source and binary forms, with or without
6234772Sjlh * modification, are permitted provided that the following conditions
7234772Sjlh * are met:
8234772Sjlh * 1. Redistributions of source code must retain the above copyright
9234772Sjlh *    notice, this list of conditions and the following disclaimer.
10234772Sjlh * 2. Redistributions in binary form must reproduce the above copyright
11234772Sjlh *    notice, this list of conditions and the following disclaimer in the
12234772Sjlh *    documentation and/or other materials provided with the distribution.
13234772Sjlh *
14234772Sjlh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15234772Sjlh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16234772Sjlh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17234772Sjlh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18234772Sjlh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19234772Sjlh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20234772Sjlh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21234772Sjlh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22234772Sjlh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23234772Sjlh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24234772Sjlh * SUCH DAMAGE.
25234772Sjlh *
26234772Sjlh * $FreeBSD$
27234772Sjlh */
28234772Sjlh
29234772Sjlh#include <err.h>
30234772Sjlh#include <errno.h>
31234772Sjlh#include <limits.h>
32234772Sjlh#include <stdio.h>
33234772Sjlh#include <stdlib.h>
34234772Sjlh#include <string.h>
35234772Sjlh
36234772Sjlhstatic const char *
37234772Sjlhstream_name(FILE *s)
38234772Sjlh{
39234772Sjlh
40234772Sjlh	if (s == stdin)
41234772Sjlh		return "stdin";
42234772Sjlh	if (s == stdout)
43234772Sjlh		return "stdout";
44234772Sjlh	if (s == stderr)
45234772Sjlh		return "stderr";
46234772Sjlh	/* This should not happen. */
47234772Sjlh	abort();
48234772Sjlh}
49234772Sjlh
50234772Sjlhstatic void
51234772Sjlhchange_buf(FILE *s, const char *bufmode)
52234772Sjlh{
53234772Sjlh	char *unit;
54234772Sjlh	size_t bufsize;
55234772Sjlh	int mode;
56234772Sjlh
57234772Sjlh	bufsize = 0;
58234772Sjlh	if (bufmode[0] == '0' && bufmode[1] == '\0')
59234772Sjlh		mode = _IONBF;
60234772Sjlh	else if (bufmode[0] == 'L' && bufmode[1] == '\0')
61234772Sjlh		mode = _IOLBF;
62234772Sjlh	else if (bufmode[0] == 'B' && bufmode[1] == '\0') {
63234772Sjlh		mode = _IOFBF;
64234772Sjlh		bufsize = 0;
65234772Sjlh	} else {
66234772Sjlh		/*
67234772Sjlh		 * This library being preloaded, depending on libutil
68234772Sjlh		 * would lead to excessive namespace pollution.
69234772Sjlh		 * Thus we do not use expand_number().
70234772Sjlh		 */
71234772Sjlh		errno = 0;
72234772Sjlh		bufsize = strtol(bufmode, &unit, 0);
73234772Sjlh		if (errno == EINVAL || errno == ERANGE || unit == bufmode)
74234772Sjlh			warn("Wrong buffer mode '%s' for %s", bufmode,
75234772Sjlh			    stream_name(s));
76234772Sjlh		switch (*unit) {
77234772Sjlh		case 'G':
78234772Sjlh			bufsize *= 1024 * 1024 * 1024;
79234772Sjlh			break;
80234772Sjlh		case 'M':
81234772Sjlh			bufsize *= 1024 * 1024;
82234772Sjlh			break;
83234772Sjlh		case 'k':
84234772Sjlh			bufsize *= 1024;
85234772Sjlh			break;
86234772Sjlh		case '\0':
87234772Sjlh			break;
88234772Sjlh		default:
89234772Sjlh			warnx("Unknown suffix '%c' for %s", *unit,
90234772Sjlh			    stream_name(s));
91234772Sjlh			return;
92234772Sjlh		}
93234772Sjlh		mode = _IOFBF;
94234772Sjlh	}
95234772Sjlh	if (setvbuf(s, NULL, mode, bufsize) != 0)
96234772Sjlh		warn("Cannot set buffer mode '%s' for %s", bufmode,
97234772Sjlh		    stream_name(s));
98234772Sjlh}
99234772Sjlh
100234772Sjlh__attribute__ ((constructor)) static void
101234772Sjlhstdbuf(void)
102234772Sjlh{
103234772Sjlh	char *i_mode, *o_mode, *e_mode;
104234772Sjlh
105234772Sjlh	i_mode = getenv("_STDBUF_I");
106234772Sjlh	o_mode = getenv("_STDBUF_O");
107234772Sjlh	e_mode = getenv("_STDBUF_E");
108234772Sjlh
109234772Sjlh	if (e_mode != NULL)
110234772Sjlh		change_buf(stderr, e_mode);
111234772Sjlh	if (i_mode != NULL)
112234772Sjlh		change_buf(stdin, i_mode);
113234772Sjlh	if (o_mode != NULL)
114234772Sjlh		change_buf(stdout, o_mode);
115234772Sjlh}
116