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
781556Srgrimes
791556Srgrimes
801556Srgrimes#ifdef mkinit
811556Srgrimes
821556SrgrimesINCLUDE "output.h"
831556SrgrimesINCLUDE "memalloc.h"
841556Srgrimes
851556SrgrimesRESET {
861556Srgrimes	out1 = &output;
871556Srgrimes	out2 = &errout;
881556Srgrimes	if (memout.buf != NULL) {
891556Srgrimes		ckfree(memout.buf);
901556Srgrimes		memout.buf = NULL;
911556Srgrimes	}
921556Srgrimes}
931556Srgrimes
941556Srgrimes#endif
951556Srgrimes
961556Srgrimes
971556Srgrimesvoid
98215567Sjillesoutcslow(int c, struct output *file)
99215567Sjilles{
100215567Sjilles	outc(c, file);
101215567Sjilles}
102215567Sjilles
103215567Sjillesvoid
10490111Simpout1str(const char *p)
10590111Simp{
1061556Srgrimes	outstr(p, out1);
1071556Srgrimes}
1081556Srgrimes
10997815Stjrvoid
11097815Stjrout1qstr(const char *p)
11197815Stjr{
11297815Stjr	outqstr(p, out1);
11397815Stjr}
1141556Srgrimes
1151556Srgrimesvoid
11690111Simpout2str(const char *p)
11790111Simp{
1181556Srgrimes	outstr(p, out2);
1191556Srgrimes}
1201556Srgrimes
12197815Stjrvoid
12297815Stjrout2qstr(const char *p)
12397815Stjr{
12497815Stjr	outqstr(p, out2);
12597815Stjr}
1261556Srgrimes
1271556Srgrimesvoid
12890111Simpoutstr(const char *p, struct output *file)
12990111Simp{
130215303Sjilles	outbin(p, strlen(p), file);
1311556Srgrimes}
1321556Srgrimes
13397815Stjr/* Like outstr(), but quote for re-input into the shell. */
13497815Stjrvoid
13597815Stjroutqstr(const char *p, struct output *file)
13697815Stjr{
13797815Stjr	char ch;
138194516Sjilles	int inquotes;
1391556Srgrimes
140153245Sstefanf	if (p[0] == '\0') {
141153245Sstefanf		outstr("''", file);
142153245Sstefanf		return;
143153245Sstefanf	}
144194516Sjilles	/* Caller will handle '=' if necessary */
145194516Sjilles	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
146194516Sjilles			strcmp(p, "[") == 0) {
14797909Stjr		outstr(p, file);
14897909Stjr		return;
14997909Stjr	}
15097909Stjr
151194516Sjilles	inquotes = 0;
15297815Stjr	while ((ch = *p++) != '\0') {
15397815Stjr		switch (ch) {
15497815Stjr		case '\'':
155194516Sjilles			/* Can't quote single quotes inside single quotes. */
156194516Sjilles			if (inquotes)
157215567Sjilles				outcslow('\'', file);
158194516Sjilles			inquotes = 0;
159194516Sjilles			outstr("\\'", file);
16097815Stjr			break;
16197815Stjr		default:
162194516Sjilles			if (!inquotes)
163215567Sjilles				outcslow('\'', file);
164194516Sjilles			inquotes = 1;
16597815Stjr			outc(ch, file);
16697815Stjr		}
16797815Stjr	}
168194516Sjilles	if (inquotes)
169215567Sjilles		outcslow('\'', file);
17097815Stjr}
17197815Stjr
172215303Sjillesvoid
173215303Sjillesoutbin(const void *data, size_t len, struct output *file)
174215303Sjilles{
175215303Sjilles	const char *p;
176215303Sjilles
177215303Sjilles	p = data;
178215303Sjilles	while (len-- > 0)
179215303Sjilles		outc(*p++, file);
180215303Sjilles}
181215303Sjilles
1821556Srgrimesvoid
18390111Simpemptyoutbuf(struct output *dest)
18490111Simp{
1851556Srgrimes	int offset;
1861556Srgrimes
187216380Sjilles	if (dest->buf == NULL) {
1881556Srgrimes		INTOFF;
1891556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
1901556Srgrimes		dest->nextc = dest->buf;
1911556Srgrimes		dest->nleft = dest->bufsize;
1921556Srgrimes		INTON;
1931556Srgrimes	} else if (dest->fd == MEM_OUT) {
1941556Srgrimes		offset = dest->bufsize;
1951556Srgrimes		INTOFF;
1961556Srgrimes		dest->bufsize <<= 1;
1971556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1981556Srgrimes		dest->nleft = dest->bufsize - offset;
1991556Srgrimes		dest->nextc = dest->buf + offset;
2001556Srgrimes		INTON;
2011556Srgrimes	} else {
2021556Srgrimes		flushout(dest);
2031556Srgrimes	}
2041556Srgrimes	dest->nleft--;
2051556Srgrimes}
2061556Srgrimes
2071556Srgrimes
2081556Srgrimesvoid
20990111Simpflushall(void)
21090111Simp{
2111556Srgrimes	flushout(&output);
2121556Srgrimes	flushout(&errout);
2131556Srgrimes}
2141556Srgrimes
2151556Srgrimes
2161556Srgrimesvoid
21790111Simpflushout(struct output *dest)
21890111Simp{
2191556Srgrimes
2201556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2211556Srgrimes		return;
2221556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2231556Srgrimes		dest->flags |= OUTPUT_ERR;
2241556Srgrimes	dest->nextc = dest->buf;
2251556Srgrimes	dest->nleft = dest->bufsize;
2261556Srgrimes}
2271556Srgrimes
2281556Srgrimes
2291556Srgrimesvoid
23090111Simpfreestdout(void)
23190111Simp{
2321556Srgrimes	INTOFF;
2331556Srgrimes	if (output.buf) {
2341556Srgrimes		ckfree(output.buf);
2351556Srgrimes		output.buf = NULL;
2361556Srgrimes		output.nleft = 0;
2371556Srgrimes	}
2381556Srgrimes	INTON;
2391556Srgrimes}
2401556Srgrimes
2411556Srgrimes
2421556Srgrimesvoid
24390111Simpoutfmt(struct output *file, const char *fmt, ...)
24490111Simp{
2451556Srgrimes	va_list ap;
2461556Srgrimes
2471556Srgrimes	va_start(ap, fmt);
2481556Srgrimes	doformat(file, fmt, ap);
2491556Srgrimes	va_end(ap);
2501556Srgrimes}
2511556Srgrimes
2521556Srgrimes
2531556Srgrimesvoid
25490111Simpout1fmt(const char *fmt, ...)
25590111Simp{
2561556Srgrimes	va_list ap;
2571556Srgrimes
2581556Srgrimes	va_start(ap, fmt);
2591556Srgrimes	doformat(out1, fmt, ap);
2601556Srgrimes	va_end(ap);
2611556Srgrimes}
2621556Srgrimes
2631556Srgrimesvoid
264199629Sjillesout2fmt_flush(const char *fmt, ...)
26590111Simp{
2661556Srgrimes	va_list ap;
2671556Srgrimes
2681556Srgrimes	va_start(ap, fmt);
2691556Srgrimes	doformat(out2, fmt, ap);
2701556Srgrimes	va_end(ap);
2711556Srgrimes	flushout(out2);
2721556Srgrimes}
2731556Srgrimes
2741556Srgrimesvoid
27590111Simpfmtstr(char *outbuf, int length, const char *fmt, ...)
27690111Simp{
2771556Srgrimes	va_list ap;
2781556Srgrimes
279216380Sjilles	INTOFF;
2801556Srgrimes	va_start(ap, fmt);
281216380Sjilles	vsnprintf(outbuf, length, fmt, ap);
282104286Stjr	va_end(ap);
283216380Sjilles	INTON;
2841556Srgrimes}
2851556Srgrimes
286213811Sobrienstatic int
287104286Stjrdoformat_wr(void *cookie, const char *buf, int len)
288104286Stjr{
289104286Stjr	struct output *o;
2901556Srgrimes
291104286Stjr	o = (struct output *)cookie;
292215303Sjilles	outbin(buf, len, o);
2931556Srgrimes
294215303Sjilles	return (len);
295104286Stjr}
2961556Srgrimes
2971556Srgrimesvoid
29890111Simpdoformat(struct output *dest, const char *f, va_list ap)
29990111Simp{
300104286Stjr	FILE *fp;
3011556Srgrimes
302104286Stjr	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
303104286Stjr		vfprintf(fp, f, ap);
304104286Stjr		fclose(fp);
3051556Srgrimes	}
3061556Srgrimes}
3071556Srgrimes
3081556Srgrimes/*
3091556Srgrimes * Version of write which resumes after a signal is caught.
3101556Srgrimes */
3111556Srgrimes
3121556Srgrimesint
313200956Sjillesxwrite(int fd, const char *buf, int nbytes)
31490111Simp{
3151556Srgrimes	int ntry;
3161556Srgrimes	int i;
3171556Srgrimes	int n;
3181556Srgrimes
3191556Srgrimes	n = nbytes;
3201556Srgrimes	ntry = 0;
3211556Srgrimes	for (;;) {
3221556Srgrimes		i = write(fd, buf, n);
3231556Srgrimes		if (i > 0) {
3241556Srgrimes			if ((n -= i) <= 0)
3251556Srgrimes				return nbytes;
3261556Srgrimes			buf += i;
3271556Srgrimes			ntry = 0;
3281556Srgrimes		} else if (i == 0) {
3291556Srgrimes			if (++ntry > 10)
3301556Srgrimes				return nbytes - n;
3311556Srgrimes		} else if (errno != EINTR) {
3321556Srgrimes			return -1;
3331556Srgrimes		}
3341556Srgrimes	}
3351556Srgrimes}
336