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: releng/11.0/bin/sh/output.c 275766 2014-12-14 16:26:19Z 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>
57275766Sjilles#include <wchar.h>
58275766Sjilles#include <wctype.h>
591556Srgrimes
6017987Speter#include "shell.h"
6117987Speter#include "syntax.h"
6217987Speter#include "output.h"
6317987Speter#include "memalloc.h"
6417987Speter#include "error.h"
6597909Stjr#include "var.h"
661556Srgrimes
6717987Speter
681556Srgrimes#define OUTBUFSIZ BUFSIZ
69216380Sjilles#define MEM_OUT -2		/* output to dynamically allocated memory */
701556Srgrimes#define OUTPUT_ERR 01		/* error occurred on output */
711556Srgrimes
72213811Sobrienstatic int doformat_wr(void *, const char *, int);
731556Srgrimes
741556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
75199629Sjillesstruct output errout = {NULL, 0, NULL, 256, 2, 0};
761556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
771556Srgrimesstruct output *out1 = &output;
781556Srgrimesstruct output *out2 = &errout;
791556Srgrimes
801556Srgrimesvoid
81215567Sjillesoutcslow(int c, struct output *file)
82215567Sjilles{
83215567Sjilles	outc(c, file);
84215567Sjilles}
85215567Sjilles
86215567Sjillesvoid
8790111Simpout1str(const char *p)
8890111Simp{
891556Srgrimes	outstr(p, out1);
901556Srgrimes}
911556Srgrimes
9297815Stjrvoid
9397815Stjrout1qstr(const char *p)
9497815Stjr{
9597815Stjr	outqstr(p, out1);
9697815Stjr}
971556Srgrimes
981556Srgrimesvoid
9990111Simpout2str(const char *p)
10090111Simp{
1011556Srgrimes	outstr(p, out2);
1021556Srgrimes}
1031556Srgrimes
10497815Stjrvoid
10597815Stjrout2qstr(const char *p)
10697815Stjr{
10797815Stjr	outqstr(p, out2);
10897815Stjr}
1091556Srgrimes
1101556Srgrimesvoid
11190111Simpoutstr(const char *p, struct output *file)
11290111Simp{
113215303Sjilles	outbin(p, strlen(p), file);
1141556Srgrimes}
1151556Srgrimes
116275766Sjillesstatic void
117275766Sjillesbyteseq(int ch, struct output *file)
118275766Sjilles{
119275766Sjilles	char seq[4];
120275766Sjilles
121275766Sjilles	seq[0] = '\\';
122275766Sjilles	seq[1] = (ch >> 6 & 0x3) + '0';
123275766Sjilles	seq[2] = (ch >> 3 & 0x7) + '0';
124275766Sjilles	seq[3] = (ch & 0x7) + '0';
125275766Sjilles	outbin(seq, 4, file);
126275766Sjilles}
127275766Sjilles
128275766Sjillesstatic void
129275766Sjillesoutdqstr(const char *p, struct output *file)
130275766Sjilles{
131275766Sjilles	const char *end;
132275766Sjilles	mbstate_t mbs;
133275766Sjilles	size_t clen;
134275766Sjilles	wchar_t wc;
135275766Sjilles
136275766Sjilles	memset(&mbs, '\0', sizeof(mbs));
137275766Sjilles	end = p + strlen(p);
138275766Sjilles	outstr("$'", file);
139275766Sjilles	while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) {
140275766Sjilles		if (clen == (size_t)-2) {
141275766Sjilles			while (p < end)
142275766Sjilles				byteseq(*p++, file);
143275766Sjilles			break;
144275766Sjilles		}
145275766Sjilles		if (clen == (size_t)-1) {
146275766Sjilles			memset(&mbs, '\0', sizeof(mbs));
147275766Sjilles			byteseq(*p++, file);
148275766Sjilles			continue;
149275766Sjilles		}
150275766Sjilles		if (wc == L'\n')
151275766Sjilles			outcslow('\n', file), p++;
152275766Sjilles		else if (wc == L'\r')
153275766Sjilles			outstr("\\r", file), p++;
154275766Sjilles		else if (wc == L'\t')
155275766Sjilles			outstr("\\t", file), p++;
156275766Sjilles		else if (!iswprint(wc)) {
157275766Sjilles			for (; clen > 0; clen--)
158275766Sjilles				byteseq(*p++, file);
159275766Sjilles		} else {
160275766Sjilles			if (wc == L'\'' || wc == L'\\')
161275766Sjilles				outcslow('\\', file);
162275766Sjilles			outbin(p, clen, file);
163275766Sjilles			p += clen;
164275766Sjilles		}
165275766Sjilles	}
166275766Sjilles	outcslow('\'', file);
167275766Sjilles}
168275766Sjilles
16997815Stjr/* Like outstr(), but quote for re-input into the shell. */
17097815Stjrvoid
17197815Stjroutqstr(const char *p, struct output *file)
17297815Stjr{
173275766Sjilles	int i;
1741556Srgrimes
175153245Sstefanf	if (p[0] == '\0') {
176153245Sstefanf		outstr("''", file);
177153245Sstefanf		return;
178153245Sstefanf	}
179275766Sjilles	for (i = 0; p[i] != '\0'; i++) {
180275766Sjilles		if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') ||
181275766Sjilles		    (p[i] & 0x80) != 0 || p[i] == '\'') {
182275766Sjilles			outdqstr(p, file);
183275766Sjilles			return;
184275766Sjilles		}
185275766Sjilles	}
186275766Sjilles
187275766Sjilles	if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' ||
188194516Sjilles			strcmp(p, "[") == 0) {
18997909Stjr		outstr(p, file);
19097909Stjr		return;
19197909Stjr	}
19297909Stjr
193275766Sjilles	outcslow('\'', file);
194275766Sjilles	outstr(p, file);
195275766Sjilles	outcslow('\'', file);
19697815Stjr}
19797815Stjr
198215303Sjillesvoid
199215303Sjillesoutbin(const void *data, size_t len, struct output *file)
200215303Sjilles{
201215303Sjilles	const char *p;
202215303Sjilles
203215303Sjilles	p = data;
204215303Sjilles	while (len-- > 0)
205215303Sjilles		outc(*p++, file);
206215303Sjilles}
207215303Sjilles
2081556Srgrimesvoid
20990111Simpemptyoutbuf(struct output *dest)
21090111Simp{
2111556Srgrimes	int offset;
2121556Srgrimes
213216380Sjilles	if (dest->buf == NULL) {
2141556Srgrimes		INTOFF;
2151556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
2161556Srgrimes		dest->nextc = dest->buf;
2171556Srgrimes		dest->nleft = dest->bufsize;
2181556Srgrimes		INTON;
2191556Srgrimes	} else if (dest->fd == MEM_OUT) {
2201556Srgrimes		offset = dest->bufsize;
2211556Srgrimes		INTOFF;
2221556Srgrimes		dest->bufsize <<= 1;
2231556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
2241556Srgrimes		dest->nleft = dest->bufsize - offset;
2251556Srgrimes		dest->nextc = dest->buf + offset;
2261556Srgrimes		INTON;
2271556Srgrimes	} else {
2281556Srgrimes		flushout(dest);
2291556Srgrimes	}
2301556Srgrimes	dest->nleft--;
2311556Srgrimes}
2321556Srgrimes
2331556Srgrimes
2341556Srgrimesvoid
23590111Simpflushall(void)
23690111Simp{
2371556Srgrimes	flushout(&output);
2381556Srgrimes	flushout(&errout);
2391556Srgrimes}
2401556Srgrimes
2411556Srgrimes
2421556Srgrimesvoid
24390111Simpflushout(struct output *dest)
24490111Simp{
2451556Srgrimes
2461556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2471556Srgrimes		return;
2481556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2491556Srgrimes		dest->flags |= OUTPUT_ERR;
2501556Srgrimes	dest->nextc = dest->buf;
2511556Srgrimes	dest->nleft = dest->bufsize;
2521556Srgrimes}
2531556Srgrimes
2541556Srgrimes
2551556Srgrimesvoid
25690111Simpfreestdout(void)
25790111Simp{
2581556Srgrimes	INTOFF;
2591556Srgrimes	if (output.buf) {
2601556Srgrimes		ckfree(output.buf);
2611556Srgrimes		output.buf = NULL;
2621556Srgrimes		output.nleft = 0;
2631556Srgrimes	}
2641556Srgrimes	INTON;
2651556Srgrimes}
2661556Srgrimes
2671556Srgrimes
268244162Sjillesint
269244162Sjillesoutiserror(struct output *file)
270244162Sjilles{
271244162Sjilles	return (file->flags & OUTPUT_ERR);
272244162Sjilles}
273244162Sjilles
274244162Sjilles
2751556Srgrimesvoid
276244162Sjillesoutclearerror(struct output *file)
277244162Sjilles{
278244162Sjilles	file->flags &= ~OUTPUT_ERR;
279244162Sjilles}
280244162Sjilles
281244162Sjilles
282244162Sjillesvoid
28390111Simpoutfmt(struct output *file, const char *fmt, ...)
28490111Simp{
2851556Srgrimes	va_list ap;
2861556Srgrimes
2871556Srgrimes	va_start(ap, fmt);
2881556Srgrimes	doformat(file, fmt, ap);
2891556Srgrimes	va_end(ap);
2901556Srgrimes}
2911556Srgrimes
2921556Srgrimes
2931556Srgrimesvoid
29490111Simpout1fmt(const char *fmt, ...)
29590111Simp{
2961556Srgrimes	va_list ap;
2971556Srgrimes
2981556Srgrimes	va_start(ap, fmt);
2991556Srgrimes	doformat(out1, fmt, ap);
3001556Srgrimes	va_end(ap);
3011556Srgrimes}
3021556Srgrimes
3031556Srgrimesvoid
304199629Sjillesout2fmt_flush(const char *fmt, ...)
30590111Simp{
3061556Srgrimes	va_list ap;
3071556Srgrimes
3081556Srgrimes	va_start(ap, fmt);
3091556Srgrimes	doformat(out2, fmt, ap);
3101556Srgrimes	va_end(ap);
3111556Srgrimes	flushout(out2);
3121556Srgrimes}
3131556Srgrimes
3141556Srgrimesvoid
31590111Simpfmtstr(char *outbuf, int length, const char *fmt, ...)
31690111Simp{
3171556Srgrimes	va_list ap;
3181556Srgrimes
319216380Sjilles	INTOFF;
3201556Srgrimes	va_start(ap, fmt);
321216380Sjilles	vsnprintf(outbuf, length, fmt, ap);
322104286Stjr	va_end(ap);
323216380Sjilles	INTON;
3241556Srgrimes}
3251556Srgrimes
326213811Sobrienstatic int
327104286Stjrdoformat_wr(void *cookie, const char *buf, int len)
328104286Stjr{
329104286Stjr	struct output *o;
3301556Srgrimes
331104286Stjr	o = (struct output *)cookie;
332215303Sjilles	outbin(buf, len, o);
3331556Srgrimes
334215303Sjilles	return (len);
335104286Stjr}
3361556Srgrimes
3371556Srgrimesvoid
33890111Simpdoformat(struct output *dest, const char *f, va_list ap)
33990111Simp{
340104286Stjr	FILE *fp;
3411556Srgrimes
342104286Stjr	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
343104286Stjr		vfprintf(fp, f, ap);
344104286Stjr		fclose(fp);
3451556Srgrimes	}
3461556Srgrimes}
3471556Srgrimes
3481556Srgrimes/*
3491556Srgrimes * Version of write which resumes after a signal is caught.
3501556Srgrimes */
3511556Srgrimes
3521556Srgrimesint
353200956Sjillesxwrite(int fd, const char *buf, int nbytes)
35490111Simp{
3551556Srgrimes	int ntry;
3561556Srgrimes	int i;
3571556Srgrimes	int n;
3581556Srgrimes
3591556Srgrimes	n = nbytes;
3601556Srgrimes	ntry = 0;
3611556Srgrimes	for (;;) {
3621556Srgrimes		i = write(fd, buf, n);
3631556Srgrimes		if (i > 0) {
3641556Srgrimes			if ((n -= i) <= 0)
3651556Srgrimes				return nbytes;
3661556Srgrimes			buf += i;
3671556Srgrimes			ntry = 0;
3681556Srgrimes		} else if (i == 0) {
3691556Srgrimes			if (++ntry > 10)
3701556Srgrimes				return nbytes - n;
3711556Srgrimes		} else if (errno != EINTR) {
3721556Srgrimes			return -1;
3731556Srgrimes		}
3741556Srgrimes	}
3751556Srgrimes}
376