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$");
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
67216380Sjilles#define MEM_OUT -2		/* output to dynamically allocated memory */
681556Srgrimes#define OUTPUT_ERR 01		/* error occurred on output */
691556Srgrimes
70213811Sobrienstatic int doformat_wr(void *, const char *, int);
711556Srgrimes
721556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
73199629Sjillesstruct output errout = {NULL, 0, NULL, 256, 2, 0};
741556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
751556Srgrimesstruct output *out1 = &output;
761556Srgrimesstruct output *out2 = &errout;
771556Srgrimes
781556Srgrimesvoid
79215567Sjillesoutcslow(int c, struct output *file)
80215567Sjilles{
81215567Sjilles	outc(c, file);
82215567Sjilles}
83215567Sjilles
84215567Sjillesvoid
8590111Simpout1str(const char *p)
8690111Simp{
871556Srgrimes	outstr(p, out1);
881556Srgrimes}
891556Srgrimes
9097815Stjrvoid
9197815Stjrout1qstr(const char *p)
9297815Stjr{
9397815Stjr	outqstr(p, out1);
9497815Stjr}
951556Srgrimes
961556Srgrimesvoid
9790111Simpout2str(const char *p)
9890111Simp{
991556Srgrimes	outstr(p, out2);
1001556Srgrimes}
1011556Srgrimes
10297815Stjrvoid
10397815Stjrout2qstr(const char *p)
10497815Stjr{
10597815Stjr	outqstr(p, out2);
10697815Stjr}
1071556Srgrimes
1081556Srgrimesvoid
10990111Simpoutstr(const char *p, struct output *file)
11090111Simp{
111215303Sjilles	outbin(p, strlen(p), file);
1121556Srgrimes}
1131556Srgrimes
11497815Stjr/* Like outstr(), but quote for re-input into the shell. */
11597815Stjrvoid
11697815Stjroutqstr(const char *p, struct output *file)
11797815Stjr{
11897815Stjr	char ch;
119194516Sjilles	int inquotes;
1201556Srgrimes
121153245Sstefanf	if (p[0] == '\0') {
122153245Sstefanf		outstr("''", file);
123153245Sstefanf		return;
124153245Sstefanf	}
125194516Sjilles	/* Caller will handle '=' if necessary */
126194516Sjilles	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
127194516Sjilles			strcmp(p, "[") == 0) {
12897909Stjr		outstr(p, file);
12997909Stjr		return;
13097909Stjr	}
13197909Stjr
132194516Sjilles	inquotes = 0;
13397815Stjr	while ((ch = *p++) != '\0') {
13497815Stjr		switch (ch) {
13597815Stjr		case '\'':
136194516Sjilles			/* Can't quote single quotes inside single quotes. */
137194516Sjilles			if (inquotes)
138215567Sjilles				outcslow('\'', file);
139194516Sjilles			inquotes = 0;
140194516Sjilles			outstr("\\'", file);
14197815Stjr			break;
14297815Stjr		default:
143194516Sjilles			if (!inquotes)
144215567Sjilles				outcslow('\'', file);
145194516Sjilles			inquotes = 1;
14697815Stjr			outc(ch, file);
14797815Stjr		}
14897815Stjr	}
149194516Sjilles	if (inquotes)
150215567Sjilles		outcslow('\'', file);
15197815Stjr}
15297815Stjr
153215303Sjillesvoid
154215303Sjillesoutbin(const void *data, size_t len, struct output *file)
155215303Sjilles{
156215303Sjilles	const char *p;
157215303Sjilles
158215303Sjilles	p = data;
159215303Sjilles	while (len-- > 0)
160215303Sjilles		outc(*p++, file);
161215303Sjilles}
162215303Sjilles
1631556Srgrimesvoid
16490111Simpemptyoutbuf(struct output *dest)
16590111Simp{
1661556Srgrimes	int offset;
1671556Srgrimes
168216380Sjilles	if (dest->buf == NULL) {
1691556Srgrimes		INTOFF;
1701556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
1711556Srgrimes		dest->nextc = dest->buf;
1721556Srgrimes		dest->nleft = dest->bufsize;
1731556Srgrimes		INTON;
1741556Srgrimes	} else if (dest->fd == MEM_OUT) {
1751556Srgrimes		offset = dest->bufsize;
1761556Srgrimes		INTOFF;
1771556Srgrimes		dest->bufsize <<= 1;
1781556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1791556Srgrimes		dest->nleft = dest->bufsize - offset;
1801556Srgrimes		dest->nextc = dest->buf + offset;
1811556Srgrimes		INTON;
1821556Srgrimes	} else {
1831556Srgrimes		flushout(dest);
1841556Srgrimes	}
1851556Srgrimes	dest->nleft--;
1861556Srgrimes}
1871556Srgrimes
1881556Srgrimes
1891556Srgrimesvoid
19090111Simpflushall(void)
19190111Simp{
1921556Srgrimes	flushout(&output);
1931556Srgrimes	flushout(&errout);
1941556Srgrimes}
1951556Srgrimes
1961556Srgrimes
1971556Srgrimesvoid
19890111Simpflushout(struct output *dest)
19990111Simp{
2001556Srgrimes
2011556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2021556Srgrimes		return;
2031556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2041556Srgrimes		dest->flags |= OUTPUT_ERR;
2051556Srgrimes	dest->nextc = dest->buf;
2061556Srgrimes	dest->nleft = dest->bufsize;
2071556Srgrimes}
2081556Srgrimes
2091556Srgrimes
2101556Srgrimesvoid
21190111Simpfreestdout(void)
21290111Simp{
2131556Srgrimes	INTOFF;
2141556Srgrimes	if (output.buf) {
2151556Srgrimes		ckfree(output.buf);
2161556Srgrimes		output.buf = NULL;
2171556Srgrimes		output.nleft = 0;
2181556Srgrimes	}
2191556Srgrimes	INTON;
2201556Srgrimes}
2211556Srgrimes
2221556Srgrimes
223244162Sjillesint
224244162Sjillesoutiserror(struct output *file)
225244162Sjilles{
226244162Sjilles	return (file->flags & OUTPUT_ERR);
227244162Sjilles}
228244162Sjilles
229244162Sjilles
2301556Srgrimesvoid
231244162Sjillesoutclearerror(struct output *file)
232244162Sjilles{
233244162Sjilles	file->flags &= ~OUTPUT_ERR;
234244162Sjilles}
235244162Sjilles
236244162Sjilles
237244162Sjillesvoid
23890111Simpoutfmt(struct output *file, const char *fmt, ...)
23990111Simp{
2401556Srgrimes	va_list ap;
2411556Srgrimes
2421556Srgrimes	va_start(ap, fmt);
2431556Srgrimes	doformat(file, fmt, ap);
2441556Srgrimes	va_end(ap);
2451556Srgrimes}
2461556Srgrimes
2471556Srgrimes
2481556Srgrimesvoid
24990111Simpout1fmt(const char *fmt, ...)
25090111Simp{
2511556Srgrimes	va_list ap;
2521556Srgrimes
2531556Srgrimes	va_start(ap, fmt);
2541556Srgrimes	doformat(out1, fmt, ap);
2551556Srgrimes	va_end(ap);
2561556Srgrimes}
2571556Srgrimes
2581556Srgrimesvoid
259199629Sjillesout2fmt_flush(const char *fmt, ...)
26090111Simp{
2611556Srgrimes	va_list ap;
2621556Srgrimes
2631556Srgrimes	va_start(ap, fmt);
2641556Srgrimes	doformat(out2, fmt, ap);
2651556Srgrimes	va_end(ap);
2661556Srgrimes	flushout(out2);
2671556Srgrimes}
2681556Srgrimes
2691556Srgrimesvoid
27090111Simpfmtstr(char *outbuf, int length, const char *fmt, ...)
27190111Simp{
2721556Srgrimes	va_list ap;
2731556Srgrimes
274216380Sjilles	INTOFF;
2751556Srgrimes	va_start(ap, fmt);
276216380Sjilles	vsnprintf(outbuf, length, fmt, ap);
277104286Stjr	va_end(ap);
278216380Sjilles	INTON;
2791556Srgrimes}
2801556Srgrimes
281213811Sobrienstatic int
282104286Stjrdoformat_wr(void *cookie, const char *buf, int len)
283104286Stjr{
284104286Stjr	struct output *o;
2851556Srgrimes
286104286Stjr	o = (struct output *)cookie;
287215303Sjilles	outbin(buf, len, o);
2881556Srgrimes
289215303Sjilles	return (len);
290104286Stjr}
2911556Srgrimes
2921556Srgrimesvoid
29390111Simpdoformat(struct output *dest, const char *f, va_list ap)
29490111Simp{
295104286Stjr	FILE *fp;
2961556Srgrimes
297104286Stjr	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
298104286Stjr		vfprintf(fp, f, ap);
299104286Stjr		fclose(fp);
3001556Srgrimes	}
3011556Srgrimes}
3021556Srgrimes
3031556Srgrimes/*
3041556Srgrimes * Version of write which resumes after a signal is caught.
3051556Srgrimes */
3061556Srgrimes
3071556Srgrimesint
308200956Sjillesxwrite(int fd, const char *buf, int nbytes)
30990111Simp{
3101556Srgrimes	int ntry;
3111556Srgrimes	int i;
3121556Srgrimes	int n;
3131556Srgrimes
3141556Srgrimes	n = nbytes;
3151556Srgrimes	ntry = 0;
3161556Srgrimes	for (;;) {
3171556Srgrimes		i = write(fd, buf, n);
3181556Srgrimes		if (i > 0) {
3191556Srgrimes			if ((n -= i) <= 0)
3201556Srgrimes				return nbytes;
3211556Srgrimes			buf += i;
3221556Srgrimes			ntry = 0;
3231556Srgrimes		} else if (i == 0) {
3241556Srgrimes			if (++ntry > 10)
3251556Srgrimes				return nbytes - n;
3261556Srgrimes		} else if (errno != EINTR) {
3271556Srgrimes			return -1;
3281556Srgrimes		}
3291556Srgrimes	}
3301556Srgrimes}
331