output.c revision 104286
1/*-
2 * Copyright (c) 1991, 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 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38#if 0
39static char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
40#endif
41#endif /* not lint */
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/bin/sh/output.c 104286 2002-10-01 13:22:12Z tjr $");
44
45/*
46 * Shell output routines.  We use our own output routines because:
47 *	When a builtin command is interrupted we have to discard
48 *		any pending output.
49 *	When a builtin command appears in back quotes, we want to
50 *		save the output of the command in a region obtained
51 *		via malloc, rather than doing a fork and reading the
52 *		output of the command via a pipe.
53 */
54
55#include <stdio.h>	/* defines BUFSIZ */
56#include <string.h>
57#include <stdarg.h>
58#include <errno.h>
59#include <unistd.h>
60#include <stdlib.h>
61
62#include "shell.h"
63#include "syntax.h"
64#include "output.h"
65#include "memalloc.h"
66#include "error.h"
67#include "var.h"
68
69
70#define OUTBUFSIZ BUFSIZ
71#define BLOCK_OUT -2		/* output to a fixed block of memory */
72#define MEM_OUT -3		/* output to dynamically allocated memory */
73#define OUTPUT_ERR 01		/* error occurred on output */
74
75static int doformat_wr(void *, const char *, int);
76
77struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
78struct output errout = {NULL, 0, NULL, 100, 2, 0};
79struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
80struct output *out1 = &output;
81struct output *out2 = &errout;
82
83
84
85#ifdef mkinit
86
87INCLUDE "output.h"
88INCLUDE "memalloc.h"
89
90RESET {
91	out1 = &output;
92	out2 = &errout;
93	if (memout.buf != NULL) {
94		ckfree(memout.buf);
95		memout.buf = NULL;
96	}
97}
98
99#endif
100
101
102void
103out1str(const char *p)
104{
105	outstr(p, out1);
106}
107
108void
109out1qstr(const char *p)
110{
111	outqstr(p, out1);
112}
113
114void
115out2str(const char *p)
116{
117	outstr(p, out2);
118}
119
120void
121out2qstr(const char *p)
122{
123	outqstr(p, out2);
124}
125
126void
127outstr(const char *p, struct output *file)
128{
129	while (*p)
130		outc(*p++, file);
131	if (file == out2)
132		flushout(file);
133}
134
135/* Like outstr(), but quote for re-input into the shell. */
136void
137outqstr(const char *p, struct output *file)
138{
139	char ch;
140
141	if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
142	    p[strcspn(p, ifsval())] == '\0')) {
143		outstr(p, file);
144		return;
145	}
146
147	out1c('\'');
148	while ((ch = *p++) != '\0') {
149		switch (ch) {
150		case '\'':
151			/*
152			 * Can't quote single quotes inside single quotes;
153			 * close them, write escaped single quote, open again.
154			 */
155			outstr("'\\''", file);
156			break;
157		default:
158			outc(ch, file);
159		}
160	}
161	out1c('\'');
162}
163
164char out_junk[16];
165
166void
167emptyoutbuf(struct output *dest)
168{
169	int offset;
170
171	if (dest->fd == BLOCK_OUT) {
172		dest->nextc = out_junk;
173		dest->nleft = sizeof out_junk;
174		dest->flags |= OUTPUT_ERR;
175	} else if (dest->buf == NULL) {
176		INTOFF;
177		dest->buf = ckmalloc(dest->bufsize);
178		dest->nextc = dest->buf;
179		dest->nleft = dest->bufsize;
180		INTON;
181	} else if (dest->fd == MEM_OUT) {
182		offset = dest->bufsize;
183		INTOFF;
184		dest->bufsize <<= 1;
185		dest->buf = ckrealloc(dest->buf, dest->bufsize);
186		dest->nleft = dest->bufsize - offset;
187		dest->nextc = dest->buf + offset;
188		INTON;
189	} else {
190		flushout(dest);
191	}
192	dest->nleft--;
193}
194
195
196void
197flushall(void)
198{
199	flushout(&output);
200	flushout(&errout);
201}
202
203
204void
205flushout(struct output *dest)
206{
207
208	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
209		return;
210	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
211		dest->flags |= OUTPUT_ERR;
212	dest->nextc = dest->buf;
213	dest->nleft = dest->bufsize;
214}
215
216
217void
218freestdout(void)
219{
220	INTOFF;
221	if (output.buf) {
222		ckfree(output.buf);
223		output.buf = NULL;
224		output.nleft = 0;
225	}
226	INTON;
227}
228
229
230void
231outfmt(struct output *file, const char *fmt, ...)
232{
233	va_list ap;
234
235	va_start(ap, fmt);
236	doformat(file, fmt, ap);
237	va_end(ap);
238}
239
240
241void
242out1fmt(const char *fmt, ...)
243{
244	va_list ap;
245
246	va_start(ap, fmt);
247	doformat(out1, fmt, ap);
248	va_end(ap);
249}
250
251void
252dprintf(const char *fmt, ...)
253{
254	va_list ap;
255
256	va_start(ap, fmt);
257	doformat(out2, fmt, ap);
258	va_end(ap);
259	flushout(out2);
260}
261
262void
263fmtstr(char *outbuf, int length, const char *fmt, ...)
264{
265	va_list ap;
266
267	va_start(ap, fmt);
268	snprintf(outbuf, length, fmt, ap);
269	va_end(ap);
270}
271
272static int
273doformat_wr(void *cookie, const char *buf, int len)
274{
275	struct output *o;
276	int origlen;
277	unsigned char c;
278
279	o = (struct output *)cookie;
280	origlen = len;
281	while (len-- != 0) {
282		c = (unsigned char)*buf++;
283		outc(c, o);
284	}
285
286	return (origlen);
287}
288
289void
290doformat(struct output *dest, const char *f, va_list ap)
291{
292	FILE *fp;
293
294	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
295		vfprintf(fp, f, ap);
296		fclose(fp);
297	}
298}
299
300/*
301 * Version of write which resumes after a signal is caught.
302 */
303
304int
305xwrite(int fd, char *buf, int nbytes)
306{
307	int ntry;
308	int i;
309	int n;
310
311	n = nbytes;
312	ntry = 0;
313	for (;;) {
314		i = write(fd, buf, n);
315		if (i > 0) {
316			if ((n -= i) <= 0)
317				return nbytes;
318			buf += i;
319			ntry = 0;
320		} else if (i == 0) {
321			if (++ntry > 10)
322				return nbytes - n;
323		} else if (errno != EINTR) {
324			return -1;
325		}
326	}
327}
328