output.c revision 104286
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
3836150Scharnier#if 0
3936150Scharnierstatic char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
4036150Scharnier#endif
411556Srgrimes#endif /* not lint */
4299110Sobrien#include <sys/cdefs.h>
4399110Sobrien__FBSDID("$FreeBSD: head/bin/sh/output.c 104286 2002-10-01 13:22:12Z tjr $");
441556Srgrimes
451556Srgrimes/*
461556Srgrimes * Shell output routines.  We use our own output routines because:
471556Srgrimes *	When a builtin command is interrupted we have to discard
481556Srgrimes *		any pending output.
491556Srgrimes *	When a builtin command appears in back quotes, we want to
501556Srgrimes *		save the output of the command in a region obtained
511556Srgrimes *		via malloc, rather than doing a fork and reading the
521556Srgrimes *		output of the command via a pipe.
531556Srgrimes */
541556Srgrimes
551556Srgrimes#include <stdio.h>	/* defines BUFSIZ */
5617987Speter#include <string.h>
5717987Speter#include <stdarg.h>
581556Srgrimes#include <errno.h>
5917987Speter#include <unistd.h>
6017987Speter#include <stdlib.h>
611556Srgrimes
6217987Speter#include "shell.h"
6317987Speter#include "syntax.h"
6417987Speter#include "output.h"
6517987Speter#include "memalloc.h"
6617987Speter#include "error.h"
6797909Stjr#include "var.h"
681556Srgrimes
6917987Speter
701556Srgrimes#define OUTBUFSIZ BUFSIZ
711556Srgrimes#define BLOCK_OUT -2		/* output to a fixed block of memory */
721556Srgrimes#define MEM_OUT -3		/* output to dynamically allocated memory */
731556Srgrimes#define OUTPUT_ERR 01		/* error occurred on output */
741556Srgrimes
75104286Stjrstatic int doformat_wr(void *, const char *, int);
761556Srgrimes
771556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
7825232Sstevestruct output errout = {NULL, 0, NULL, 100, 2, 0};
791556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
801556Srgrimesstruct output *out1 = &output;
811556Srgrimesstruct output *out2 = &errout;
821556Srgrimes
831556Srgrimes
841556Srgrimes
851556Srgrimes#ifdef mkinit
861556Srgrimes
871556SrgrimesINCLUDE "output.h"
881556SrgrimesINCLUDE "memalloc.h"
891556Srgrimes
901556SrgrimesRESET {
911556Srgrimes	out1 = &output;
921556Srgrimes	out2 = &errout;
931556Srgrimes	if (memout.buf != NULL) {
941556Srgrimes		ckfree(memout.buf);
951556Srgrimes		memout.buf = NULL;
961556Srgrimes	}
971556Srgrimes}
981556Srgrimes
991556Srgrimes#endif
1001556Srgrimes
1011556Srgrimes
1021556Srgrimesvoid
10390111Simpout1str(const char *p)
10490111Simp{
1051556Srgrimes	outstr(p, out1);
1061556Srgrimes}
1071556Srgrimes
10897815Stjrvoid
10997815Stjrout1qstr(const char *p)
11097815Stjr{
11197815Stjr	outqstr(p, out1);
11297815Stjr}
1131556Srgrimes
1141556Srgrimesvoid
11590111Simpout2str(const char *p)
11690111Simp{
1171556Srgrimes	outstr(p, out2);
1181556Srgrimes}
1191556Srgrimes
12097815Stjrvoid
12197815Stjrout2qstr(const char *p)
12297815Stjr{
12397815Stjr	outqstr(p, out2);
12497815Stjr}
1251556Srgrimes
1261556Srgrimesvoid
12790111Simpoutstr(const char *p, struct output *file)
12890111Simp{
1291556Srgrimes	while (*p)
1301556Srgrimes		outc(*p++, file);
1311556Srgrimes	if (file == out2)
1321556Srgrimes		flushout(file);
1331556Srgrimes}
1341556Srgrimes
13597815Stjr/* Like outstr(), but quote for re-input into the shell. */
13697815Stjrvoid
13797815Stjroutqstr(const char *p, struct output *file)
13897815Stjr{
13997815Stjr	char ch;
1401556Srgrimes
14197909Stjr	if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
14297909Stjr	    p[strcspn(p, ifsval())] == '\0')) {
14397909Stjr		outstr(p, file);
14497909Stjr		return;
14597909Stjr	}
14697909Stjr
14797815Stjr	out1c('\'');
14897815Stjr	while ((ch = *p++) != '\0') {
14997815Stjr		switch (ch) {
15097815Stjr		case '\'':
15197815Stjr			/*
15297815Stjr			 * Can't quote single quotes inside single quotes;
15397815Stjr			 * close them, write escaped single quote, open again.
15497815Stjr			 */
15597815Stjr			outstr("'\\''", file);
15697815Stjr			break;
15797815Stjr		default:
15897815Stjr			outc(ch, file);
15997815Stjr		}
16097815Stjr	}
16197815Stjr	out1c('\'');
16297815Stjr}
16397815Stjr
1641556Srgrimeschar out_junk[16];
1651556Srgrimes
1661556Srgrimesvoid
16790111Simpemptyoutbuf(struct output *dest)
16890111Simp{
1691556Srgrimes	int offset;
1701556Srgrimes
1711556Srgrimes	if (dest->fd == BLOCK_OUT) {
1721556Srgrimes		dest->nextc = out_junk;
1731556Srgrimes		dest->nleft = sizeof out_junk;
1741556Srgrimes		dest->flags |= OUTPUT_ERR;
1751556Srgrimes	} else if (dest->buf == NULL) {
1761556Srgrimes		INTOFF;
1771556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
1781556Srgrimes		dest->nextc = dest->buf;
1791556Srgrimes		dest->nleft = dest->bufsize;
1801556Srgrimes		INTON;
1811556Srgrimes	} else if (dest->fd == MEM_OUT) {
1821556Srgrimes		offset = dest->bufsize;
1831556Srgrimes		INTOFF;
1841556Srgrimes		dest->bufsize <<= 1;
1851556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1861556Srgrimes		dest->nleft = dest->bufsize - offset;
1871556Srgrimes		dest->nextc = dest->buf + offset;
1881556Srgrimes		INTON;
1891556Srgrimes	} else {
1901556Srgrimes		flushout(dest);
1911556Srgrimes	}
1921556Srgrimes	dest->nleft--;
1931556Srgrimes}
1941556Srgrimes
1951556Srgrimes
1961556Srgrimesvoid
19790111Simpflushall(void)
19890111Simp{
1991556Srgrimes	flushout(&output);
2001556Srgrimes	flushout(&errout);
2011556Srgrimes}
2021556Srgrimes
2031556Srgrimes
2041556Srgrimesvoid
20590111Simpflushout(struct output *dest)
20690111Simp{
2071556Srgrimes
2081556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2091556Srgrimes		return;
2101556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2111556Srgrimes		dest->flags |= OUTPUT_ERR;
2121556Srgrimes	dest->nextc = dest->buf;
2131556Srgrimes	dest->nleft = dest->bufsize;
2141556Srgrimes}
2151556Srgrimes
2161556Srgrimes
2171556Srgrimesvoid
21890111Simpfreestdout(void)
21990111Simp{
2201556Srgrimes	INTOFF;
2211556Srgrimes	if (output.buf) {
2221556Srgrimes		ckfree(output.buf);
2231556Srgrimes		output.buf = NULL;
2241556Srgrimes		output.nleft = 0;
2251556Srgrimes	}
2261556Srgrimes	INTON;
2271556Srgrimes}
2281556Srgrimes
2291556Srgrimes
2301556Srgrimesvoid
23190111Simpoutfmt(struct output *file, const char *fmt, ...)
23290111Simp{
2331556Srgrimes	va_list ap;
2341556Srgrimes
2351556Srgrimes	va_start(ap, fmt);
2361556Srgrimes	doformat(file, fmt, ap);
2371556Srgrimes	va_end(ap);
2381556Srgrimes}
2391556Srgrimes
2401556Srgrimes
2411556Srgrimesvoid
24290111Simpout1fmt(const char *fmt, ...)
24390111Simp{
2441556Srgrimes	va_list ap;
2451556Srgrimes
2461556Srgrimes	va_start(ap, fmt);
2471556Srgrimes	doformat(out1, fmt, ap);
2481556Srgrimes	va_end(ap);
2491556Srgrimes}
2501556Srgrimes
2511556Srgrimesvoid
25290111Simpdprintf(const char *fmt, ...)
25390111Simp{
2541556Srgrimes	va_list ap;
2551556Srgrimes
2561556Srgrimes	va_start(ap, fmt);
2571556Srgrimes	doformat(out2, fmt, ap);
2581556Srgrimes	va_end(ap);
2591556Srgrimes	flushout(out2);
2601556Srgrimes}
2611556Srgrimes
2621556Srgrimesvoid
26390111Simpfmtstr(char *outbuf, int length, const char *fmt, ...)
26490111Simp{
2651556Srgrimes	va_list ap;
2661556Srgrimes
2671556Srgrimes	va_start(ap, fmt);
268104286Stjr	snprintf(outbuf, length, fmt, ap);
269104286Stjr	va_end(ap);
2701556Srgrimes}
2711556Srgrimes
272104286Stjrstatic int
273104286Stjrdoformat_wr(void *cookie, const char *buf, int len)
274104286Stjr{
275104286Stjr	struct output *o;
276104286Stjr	int origlen;
277104286Stjr	unsigned char c;
2781556Srgrimes
279104286Stjr	o = (struct output *)cookie;
280104286Stjr	origlen = len;
281104286Stjr	while (len-- != 0) {
282104286Stjr		c = (unsigned char)*buf++;
283104286Stjr		outc(c, o);
284104286Stjr	}
2851556Srgrimes
286104286Stjr	return (origlen);
287104286Stjr}
2881556Srgrimes
2891556Srgrimesvoid
29090111Simpdoformat(struct output *dest, const char *f, va_list ap)
29190111Simp{
292104286Stjr	FILE *fp;
2931556Srgrimes
294104286Stjr	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
295104286Stjr		vfprintf(fp, f, ap);
296104286Stjr		fclose(fp);
2971556Srgrimes	}
2981556Srgrimes}
2991556Srgrimes
3001556Srgrimes/*
3011556Srgrimes * Version of write which resumes after a signal is caught.
3021556Srgrimes */
3031556Srgrimes
3041556Srgrimesint
30590111Simpxwrite(int fd, char *buf, int nbytes)
30690111Simp{
3071556Srgrimes	int ntry;
3081556Srgrimes	int i;
3091556Srgrimes	int n;
3101556Srgrimes
3111556Srgrimes	n = nbytes;
3121556Srgrimes	ntry = 0;
3131556Srgrimes	for (;;) {
3141556Srgrimes		i = write(fd, buf, n);
3151556Srgrimes		if (i > 0) {
3161556Srgrimes			if ((n -= i) <= 0)
3171556Srgrimes				return nbytes;
3181556Srgrimes			buf += i;
3191556Srgrimes			ntry = 0;
3201556Srgrimes		} else if (i == 0) {
3211556Srgrimes			if (++ntry > 10)
3221556Srgrimes				return nbytes - n;
3231556Srgrimes		} else if (errno != EINTR) {
3241556Srgrimes			return -1;
3251556Srgrimes		}
3261556Srgrimes	}
3271556Srgrimes}
328