output.c revision 153245
182518Sgallatin/*-
282518Sgallatin * Copyright (c) 1991, 1993
382518Sgallatin *	The Regents of the University of California.  All rights reserved.
482518Sgallatin *
5281882Strasz * This code is derived from software contributed to Berkeley by
682518Sgallatin * Kenneth Almquist.
782518Sgallatin *
882518Sgallatin * Redistribution and use in source and binary forms, with or without
982518Sgallatin * modification, are permitted provided that the following conditions
1082518Sgallatin * are met:
11281882Strasz * 1. Redistributions of source code must retain the above copyright
12281882Strasz *    notice, this list of conditions and the following disclaimer.
13281882Strasz * 2. Redistributions in binary form must reproduce the above copyright
1482518Sgallatin *    notice, this list of conditions and the following disclaimer in the
1582518Sgallatin *    documentation and/or other materials provided with the distribution.
1682518Sgallatin * 4. Neither the name of the University nor the names of its contributors
1782518Sgallatin *    may be used to endorse or promote products derived from this software
1882518Sgallatin *    without specific prior written permission.
1982518Sgallatin *
2082518Sgallatin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2182518Sgallatin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2282518Sgallatin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2382518Sgallatin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2482518Sgallatin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2582518Sgallatin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2682518Sgallatin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2782518Sgallatin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2882518Sgallatin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2982518Sgallatin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3082518Sgallatin * SUCH DAMAGE.
3182518Sgallatin */
3282518Sgallatin
3382518Sgallatin#ifndef lint
3482518Sgallatin#if 0
35116173Sobrienstatic char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
36116173Sobrien#endif
37116173Sobrien#endif /* not lint */
38116173Sobrien#include <sys/cdefs.h>
39156874Sru__FBSDID("$FreeBSD: head/bin/sh/output.c 153245 2005-12-08 21:00:39Z stefanf $");
4082518Sgallatin
4182518Sgallatin/*
4282518Sgallatin * Shell output routines.  We use our own output routines because:
43102872Siedowse *	When a builtin command is interrupted we have to discard
4482518Sgallatin *		any pending output.
45112430Sphk *	When a builtin command appears in back quotes, we want to
4682518Sgallatin *		save the output of the command in a region obtained
47140214Sobrien *		via malloc, rather than doing a fork and reading the
48140214Sobrien *		output of the command via a pipe.
49140214Sobrien */
50140214Sobrien
5182518Sgallatin#include <stdio.h>	/* defines BUFSIZ */
5282518Sgallatin#include <string.h>
53133816Stjr#include <stdarg.h>
54281829Strasz#include <errno.h>
55112430Sphk#include <unistd.h>
5682518Sgallatin#include <stdlib.h>
5782518Sgallatin
5882518Sgallatin#include "shell.h"
5982518Sgallatin#include "syntax.h"
6082518Sgallatin#include "output.h"
6183366Sjulian#include "memalloc.h"
6282518Sgallatin#include "error.h"
63281882Strasz#include "var.h"
64281882Strasz
65112430Sphk
66112430Sphk#define OUTBUFSIZ BUFSIZ
67164379Skib#define BLOCK_OUT -2		/* output to a fixed block of memory */
68164383Skib#define MEM_OUT -3		/* output to dynamically allocated memory */
69112430Sphk#define OUTPUT_ERR 01		/* error occurred on output */
70112430Sphk
71281882Straszstatic int doformat_wr(void *, const char *, int);
72281882Strasz
73281882Straszstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
74281882Straszstruct output errout = {NULL, 0, NULL, 100, 2, 0};
75281882Straszstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
76112430Sphkstruct output *out1 = &output;
77281882Straszstruct output *out2 = &errout;
78112430Sphk
79281882Strasz
80281882Strasz
81281882Strasz#ifdef mkinit
82112430Sphk
83281882StraszINCLUDE "output.h"
84281882StraszINCLUDE "memalloc.h"
85112430Sphk
86281882StraszRESET {
87112430Sphk	out1 = &output;
88112430Sphk	out2 = &errout;
89112430Sphk	if (memout.buf != NULL) {
9082518Sgallatin		ckfree(memout.buf);
91		memout.buf = NULL;
92	}
93}
94
95#endif
96
97
98void
99out1str(const char *p)
100{
101	outstr(p, out1);
102}
103
104void
105out1qstr(const char *p)
106{
107	outqstr(p, out1);
108}
109
110void
111out2str(const char *p)
112{
113	outstr(p, out2);
114}
115
116void
117out2qstr(const char *p)
118{
119	outqstr(p, out2);
120}
121
122void
123outstr(const char *p, struct output *file)
124{
125	while (*p)
126		outc(*p++, file);
127	if (file == out2)
128		flushout(file);
129}
130
131/* Like outstr(), but quote for re-input into the shell. */
132void
133outqstr(const char *p, struct output *file)
134{
135	char ch;
136
137	if (p[0] == '\0') {
138		outstr("''", file);
139		return;
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
164STATIC char 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	struct output strout;
267
268	strout.nextc = outbuf;
269	strout.nleft = length;
270	strout.fd = BLOCK_OUT;
271	strout.flags = 0;
272	va_start(ap, fmt);
273	doformat(&strout, fmt, ap);
274	va_end(ap);
275	outc('\0', &strout);
276	if (strout.flags & OUTPUT_ERR)
277		outbuf[length - 1] = '\0';
278}
279
280static int
281doformat_wr(void *cookie, const char *buf, int len)
282{
283	struct output *o;
284	int origlen;
285	unsigned char c;
286
287	o = (struct output *)cookie;
288	origlen = len;
289	while (len-- != 0) {
290		c = (unsigned char)*buf++;
291		outc(c, o);
292	}
293
294	return (origlen);
295}
296
297void
298doformat(struct output *dest, const char *f, va_list ap)
299{
300	FILE *fp;
301
302	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
303		vfprintf(fp, f, ap);
304		fclose(fp);
305	}
306}
307
308/*
309 * Version of write which resumes after a signal is caught.
310 */
311
312int
313xwrite(int fd, char *buf, int nbytes)
314{
315	int ntry;
316	int i;
317	int n;
318
319	n = nbytes;
320	ntry = 0;
321	for (;;) {
322		i = write(fd, buf, n);
323		if (i > 0) {
324			if ((n -= i) <= 0)
325				return nbytes;
326			buf += i;
327			ntry = 0;
328		} else if (i == 0) {
329			if (++ntry > 10)
330				return nbytes - n;
331		} else if (errno != EINTR) {
332			return -1;
333		}
334	}
335}
336