output.c revision 200956
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 * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/output.c 200956 2009-12-24 18:41:14Z jilles $");
401556Srgrimes
411556Srgrimes/*
421556Srgrimes * Shell output routines.  We use our own output routines because:
431556Srgrimes *	When a builtin command is interrupted we have to discard
441556Srgrimes *		any pending output.
451556Srgrimes *	When a builtin command appears in back quotes, we want to
461556Srgrimes *		save the output of the command in a region obtained
471556Srgrimes *		via malloc, rather than doing a fork and reading the
481556Srgrimes *		output of the command via a pipe.
491556Srgrimes */
501556Srgrimes
511556Srgrimes#include <stdio.h>	/* defines BUFSIZ */
5217987Speter#include <string.h>
5317987Speter#include <stdarg.h>
541556Srgrimes#include <errno.h>
5517987Speter#include <unistd.h>
5617987Speter#include <stdlib.h>
571556Srgrimes
5817987Speter#include "shell.h"
5917987Speter#include "syntax.h"
6017987Speter#include "output.h"
6117987Speter#include "memalloc.h"
6217987Speter#include "error.h"
6397909Stjr#include "var.h"
641556Srgrimes
6517987Speter
661556Srgrimes#define OUTBUFSIZ BUFSIZ
671556Srgrimes#define BLOCK_OUT -2		/* output to a fixed block of memory */
681556Srgrimes#define MEM_OUT -3		/* output to dynamically allocated memory */
691556Srgrimes#define OUTPUT_ERR 01		/* error occurred on output */
701556Srgrimes
71104286Stjrstatic int doformat_wr(void *, const char *, int);
721556Srgrimes
731556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
74199629Sjillesstruct output errout = {NULL, 0, NULL, 256, 2, 0};
751556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
761556Srgrimesstruct output *out1 = &output;
771556Srgrimesstruct output *out2 = &errout;
781556Srgrimes
791556Srgrimes
801556Srgrimes
811556Srgrimes#ifdef mkinit
821556Srgrimes
831556SrgrimesINCLUDE "output.h"
841556SrgrimesINCLUDE "memalloc.h"
851556Srgrimes
861556SrgrimesRESET {
871556Srgrimes	out1 = &output;
881556Srgrimes	out2 = &errout;
891556Srgrimes	if (memout.buf != NULL) {
901556Srgrimes		ckfree(memout.buf);
911556Srgrimes		memout.buf = NULL;
921556Srgrimes	}
931556Srgrimes}
941556Srgrimes
951556Srgrimes#endif
961556Srgrimes
971556Srgrimes
981556Srgrimesvoid
9990111Simpout1str(const char *p)
10090111Simp{
1011556Srgrimes	outstr(p, out1);
1021556Srgrimes}
1031556Srgrimes
10497815Stjrvoid
10597815Stjrout1qstr(const char *p)
10697815Stjr{
10797815Stjr	outqstr(p, out1);
10897815Stjr}
1091556Srgrimes
1101556Srgrimesvoid
11190111Simpout2str(const char *p)
11290111Simp{
1131556Srgrimes	outstr(p, out2);
1141556Srgrimes}
1151556Srgrimes
11697815Stjrvoid
11797815Stjrout2qstr(const char *p)
11897815Stjr{
11997815Stjr	outqstr(p, out2);
12097815Stjr}
1211556Srgrimes
1221556Srgrimesvoid
12390111Simpoutstr(const char *p, struct output *file)
12490111Simp{
1251556Srgrimes	while (*p)
1261556Srgrimes		outc(*p++, file);
1271556Srgrimes}
1281556Srgrimes
12997815Stjr/* Like outstr(), but quote for re-input into the shell. */
13097815Stjrvoid
13197815Stjroutqstr(const char *p, struct output *file)
13297815Stjr{
13397815Stjr	char ch;
134194516Sjilles	int inquotes;
1351556Srgrimes
136153245Sstefanf	if (p[0] == '\0') {
137153245Sstefanf		outstr("''", file);
138153245Sstefanf		return;
139153245Sstefanf	}
140194516Sjilles	/* Caller will handle '=' if necessary */
141194516Sjilles	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
142194516Sjilles			strcmp(p, "[") == 0) {
14397909Stjr		outstr(p, file);
14497909Stjr		return;
14597909Stjr	}
14697909Stjr
147194516Sjilles	inquotes = 0;
14897815Stjr	while ((ch = *p++) != '\0') {
14997815Stjr		switch (ch) {
15097815Stjr		case '\'':
151194516Sjilles			/* Can't quote single quotes inside single quotes. */
152194516Sjilles			if (inquotes)
153194516Sjilles				outc('\'', file);
154194516Sjilles			inquotes = 0;
155194516Sjilles			outstr("\\'", file);
15697815Stjr			break;
15797815Stjr		default:
158194516Sjilles			if (!inquotes)
159194516Sjilles				outc('\'', file);
160194516Sjilles			inquotes = 1;
16197815Stjr			outc(ch, file);
16297815Stjr		}
16397815Stjr	}
164194516Sjilles	if (inquotes)
165194516Sjilles		outc('\'', file);
16697815Stjr}
16797815Stjr
168117261SddsSTATIC char out_junk[16];
1691556Srgrimes
1701556Srgrimesvoid
17190111Simpemptyoutbuf(struct output *dest)
17290111Simp{
1731556Srgrimes	int offset;
1741556Srgrimes
1751556Srgrimes	if (dest->fd == BLOCK_OUT) {
1761556Srgrimes		dest->nextc = out_junk;
1771556Srgrimes		dest->nleft = sizeof out_junk;
1781556Srgrimes		dest->flags |= OUTPUT_ERR;
1791556Srgrimes	} else if (dest->buf == NULL) {
1801556Srgrimes		INTOFF;
1811556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
1821556Srgrimes		dest->nextc = dest->buf;
1831556Srgrimes		dest->nleft = dest->bufsize;
1841556Srgrimes		INTON;
1851556Srgrimes	} else if (dest->fd == MEM_OUT) {
1861556Srgrimes		offset = dest->bufsize;
1871556Srgrimes		INTOFF;
1881556Srgrimes		dest->bufsize <<= 1;
1891556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1901556Srgrimes		dest->nleft = dest->bufsize - offset;
1911556Srgrimes		dest->nextc = dest->buf + offset;
1921556Srgrimes		INTON;
1931556Srgrimes	} else {
1941556Srgrimes		flushout(dest);
1951556Srgrimes	}
1961556Srgrimes	dest->nleft--;
1971556Srgrimes}
1981556Srgrimes
1991556Srgrimes
2001556Srgrimesvoid
20190111Simpflushall(void)
20290111Simp{
2031556Srgrimes	flushout(&output);
2041556Srgrimes	flushout(&errout);
2051556Srgrimes}
2061556Srgrimes
2071556Srgrimes
2081556Srgrimesvoid
20990111Simpflushout(struct output *dest)
21090111Simp{
2111556Srgrimes
2121556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2131556Srgrimes		return;
2141556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2151556Srgrimes		dest->flags |= OUTPUT_ERR;
2161556Srgrimes	dest->nextc = dest->buf;
2171556Srgrimes	dest->nleft = dest->bufsize;
2181556Srgrimes}
2191556Srgrimes
2201556Srgrimes
2211556Srgrimesvoid
22290111Simpfreestdout(void)
22390111Simp{
2241556Srgrimes	INTOFF;
2251556Srgrimes	if (output.buf) {
2261556Srgrimes		ckfree(output.buf);
2271556Srgrimes		output.buf = NULL;
2281556Srgrimes		output.nleft = 0;
2291556Srgrimes	}
2301556Srgrimes	INTON;
2311556Srgrimes}
2321556Srgrimes
2331556Srgrimes
2341556Srgrimesvoid
23590111Simpoutfmt(struct output *file, const char *fmt, ...)
23690111Simp{
2371556Srgrimes	va_list ap;
2381556Srgrimes
2391556Srgrimes	va_start(ap, fmt);
2401556Srgrimes	doformat(file, fmt, ap);
2411556Srgrimes	va_end(ap);
2421556Srgrimes}
2431556Srgrimes
2441556Srgrimes
2451556Srgrimesvoid
24690111Simpout1fmt(const char *fmt, ...)
24790111Simp{
2481556Srgrimes	va_list ap;
2491556Srgrimes
2501556Srgrimes	va_start(ap, fmt);
2511556Srgrimes	doformat(out1, fmt, ap);
2521556Srgrimes	va_end(ap);
2531556Srgrimes}
2541556Srgrimes
2551556Srgrimesvoid
256199629Sjillesout2fmt_flush(const char *fmt, ...)
25790111Simp{
2581556Srgrimes	va_list ap;
2591556Srgrimes
2601556Srgrimes	va_start(ap, fmt);
2611556Srgrimes	doformat(out2, fmt, ap);
2621556Srgrimes	va_end(ap);
2631556Srgrimes	flushout(out2);
2641556Srgrimes}
2651556Srgrimes
2661556Srgrimesvoid
26790111Simpfmtstr(char *outbuf, int length, const char *fmt, ...)
26890111Simp{
2691556Srgrimes	va_list ap;
270104289Stjr	struct output strout;
2711556Srgrimes
272104289Stjr	strout.nextc = outbuf;
273104289Stjr	strout.nleft = length;
274104289Stjr	strout.fd = BLOCK_OUT;
275104289Stjr	strout.flags = 0;
2761556Srgrimes	va_start(ap, fmt);
277104289Stjr	doformat(&strout, fmt, ap);
278104286Stjr	va_end(ap);
279104289Stjr	outc('\0', &strout);
280104289Stjr	if (strout.flags & OUTPUT_ERR)
281104289Stjr		outbuf[length - 1] = '\0';
2821556Srgrimes}
2831556Srgrimes
284104286Stjrstatic int
285104286Stjrdoformat_wr(void *cookie, const char *buf, int len)
286104286Stjr{
287104286Stjr	struct output *o;
288104286Stjr	int origlen;
289104286Stjr	unsigned char c;
2901556Srgrimes
291104286Stjr	o = (struct output *)cookie;
292104286Stjr	origlen = len;
293104286Stjr	while (len-- != 0) {
294104286Stjr		c = (unsigned char)*buf++;
295104286Stjr		outc(c, o);
296104286Stjr	}
2971556Srgrimes
298104286Stjr	return (origlen);
299104286Stjr}
3001556Srgrimes
3011556Srgrimesvoid
30290111Simpdoformat(struct output *dest, const char *f, va_list ap)
30390111Simp{
304104286Stjr	FILE *fp;
3051556Srgrimes
306104286Stjr	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
307104286Stjr		vfprintf(fp, f, ap);
308104286Stjr		fclose(fp);
3091556Srgrimes	}
3101556Srgrimes}
3111556Srgrimes
3121556Srgrimes/*
3131556Srgrimes * Version of write which resumes after a signal is caught.
3141556Srgrimes */
3151556Srgrimes
3161556Srgrimesint
317200956Sjillesxwrite(int fd, const char *buf, int nbytes)
31890111Simp{
3191556Srgrimes	int ntry;
3201556Srgrimes	int i;
3211556Srgrimes	int n;
3221556Srgrimes
3231556Srgrimes	n = nbytes;
3241556Srgrimes	ntry = 0;
3251556Srgrimes	for (;;) {
3261556Srgrimes		i = write(fd, buf, n);
3271556Srgrimes		if (i > 0) {
3281556Srgrimes			if ((n -= i) <= 0)
3291556Srgrimes				return nbytes;
3301556Srgrimes			buf += i;
3311556Srgrimes			ntry = 0;
3321556Srgrimes		} else if (i == 0) {
3331556Srgrimes			if (++ntry > 10)
3341556Srgrimes				return nbytes - n;
3351556Srgrimes		} else if (errno != EINTR) {
3361556Srgrimes			return -1;
3371556Srgrimes		}
3381556Srgrimes	}
3391556Srgrimes}
340