xref: /freebsd/bin/sh/output.c (revision c6204d4a81effd8076dc5299f0b7ca807f5305b5)
14b88c807SRodney W. Grimes /*-
24b88c807SRodney W. Grimes  * Copyright (c) 1991, 1993
34b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
44b88c807SRodney W. Grimes  *
54b88c807SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
64b88c807SRodney W. Grimes  * Kenneth Almquist.
74b88c807SRodney W. Grimes  *
84b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
94b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
104b88c807SRodney W. Grimes  * are met:
114b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
124b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
134b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
144b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
154b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
164b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
174b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
184b88c807SRodney W. Grimes  *    without specific prior written permission.
194b88c807SRodney W. Grimes  *
204b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
214b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
244b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304b88c807SRodney W. Grimes  * SUCH DAMAGE.
314b88c807SRodney W. Grimes  */
324b88c807SRodney W. Grimes 
334b88c807SRodney W. Grimes #ifndef lint
343d7b5b93SPhilippe Charnier #if 0
353d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
363d7b5b93SPhilippe Charnier #endif
374b88c807SRodney W. Grimes #endif /* not lint */
382749b141SDavid E. O'Brien #include <sys/cdefs.h>
392749b141SDavid E. O'Brien __FBSDID("$FreeBSD$");
404b88c807SRodney W. Grimes 
414b88c807SRodney W. Grimes /*
424b88c807SRodney W. Grimes  * Shell output routines.  We use our own output routines because:
434b88c807SRodney W. Grimes  *	When a builtin command is interrupted we have to discard
444b88c807SRodney W. Grimes  *		any pending output.
454b88c807SRodney W. Grimes  *	When a builtin command appears in back quotes, we want to
464b88c807SRodney W. Grimes  *		save the output of the command in a region obtained
474b88c807SRodney W. Grimes  *		via malloc, rather than doing a fork and reading the
484b88c807SRodney W. Grimes  *		output of the command via a pipe.
494b88c807SRodney W. Grimes  */
504b88c807SRodney W. Grimes 
514b88c807SRodney W. Grimes #include <stdio.h>	/* defines BUFSIZ */
52aa9caaf6SPeter Wemm #include <string.h>
53aa9caaf6SPeter Wemm #include <stdarg.h>
54aa9caaf6SPeter Wemm #include <errno.h>
55aa9caaf6SPeter Wemm #include <unistd.h>
56aa9caaf6SPeter Wemm #include <stdlib.h>
57aa9caaf6SPeter Wemm 
584b88c807SRodney W. Grimes #include "shell.h"
594b88c807SRodney W. Grimes #include "syntax.h"
604b88c807SRodney W. Grimes #include "output.h"
614b88c807SRodney W. Grimes #include "memalloc.h"
624b88c807SRodney W. Grimes #include "error.h"
63dee75cf7STim J. Robbins #include "var.h"
644b88c807SRodney W. Grimes 
654b88c807SRodney W. Grimes 
664b88c807SRodney W. Grimes #define OUTBUFSIZ BUFSIZ
674b88c807SRodney W. Grimes #define BLOCK_OUT -2		/* output to a fixed block of memory */
684b88c807SRodney W. Grimes #define MEM_OUT -3		/* output to dynamically allocated memory */
694b88c807SRodney W. Grimes #define OUTPUT_ERR 01		/* error occurred on output */
704b88c807SRodney W. Grimes 
717e73d40eSTim J. Robbins static int doformat_wr(void *, const char *, int);
724b88c807SRodney W. Grimes 
734b88c807SRodney W. Grimes struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
74c6204d4aSJilles Tjoelker struct output errout = {NULL, 0, NULL, 256, 2, 0};
754b88c807SRodney W. Grimes struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
764b88c807SRodney W. Grimes struct output *out1 = &output;
774b88c807SRodney W. Grimes struct output *out2 = &errout;
784b88c807SRodney W. Grimes 
794b88c807SRodney W. Grimes 
804b88c807SRodney W. Grimes 
814b88c807SRodney W. Grimes #ifdef mkinit
824b88c807SRodney W. Grimes 
834b88c807SRodney W. Grimes INCLUDE "output.h"
844b88c807SRodney W. Grimes INCLUDE "memalloc.h"
854b88c807SRodney W. Grimes 
864b88c807SRodney W. Grimes RESET {
874b88c807SRodney W. Grimes 	out1 = &output;
884b88c807SRodney W. Grimes 	out2 = &errout;
894b88c807SRodney W. Grimes 	if (memout.buf != NULL) {
904b88c807SRodney W. Grimes 		ckfree(memout.buf);
914b88c807SRodney W. Grimes 		memout.buf = NULL;
924b88c807SRodney W. Grimes 	}
934b88c807SRodney W. Grimes }
944b88c807SRodney W. Grimes 
954b88c807SRodney W. Grimes #endif
964b88c807SRodney W. Grimes 
974b88c807SRodney W. Grimes 
984b88c807SRodney W. Grimes void
995134c3f7SWarner Losh out1str(const char *p)
1004b88c807SRodney W. Grimes {
1014b88c807SRodney W. Grimes 	outstr(p, out1);
1024b88c807SRodney W. Grimes }
1034b88c807SRodney W. Grimes 
104e5341cbbSTim J. Robbins void
105e5341cbbSTim J. Robbins out1qstr(const char *p)
106e5341cbbSTim J. Robbins {
107e5341cbbSTim J. Robbins 	outqstr(p, out1);
108e5341cbbSTim J. Robbins }
1094b88c807SRodney W. Grimes 
1104b88c807SRodney W. Grimes void
1115134c3f7SWarner Losh out2str(const char *p)
1124b88c807SRodney W. Grimes {
1134b88c807SRodney W. Grimes 	outstr(p, out2);
1144b88c807SRodney W. Grimes }
1154b88c807SRodney W. Grimes 
116e5341cbbSTim J. Robbins void
117e5341cbbSTim J. Robbins out2qstr(const char *p)
118e5341cbbSTim J. Robbins {
119e5341cbbSTim J. Robbins 	outqstr(p, out2);
120e5341cbbSTim J. Robbins }
1214b88c807SRodney W. Grimes 
1224b88c807SRodney W. Grimes void
1235134c3f7SWarner Losh outstr(const char *p, struct output *file)
1244b88c807SRodney W. Grimes {
1254b88c807SRodney W. Grimes 	while (*p)
1264b88c807SRodney W. Grimes 		outc(*p++, file);
1274b88c807SRodney W. Grimes }
1284b88c807SRodney W. Grimes 
129e5341cbbSTim J. Robbins /* Like outstr(), but quote for re-input into the shell. */
130e5341cbbSTim J. Robbins void
131e5341cbbSTim J. Robbins outqstr(const char *p, struct output *file)
132e5341cbbSTim J. Robbins {
133e5341cbbSTim J. Robbins 	char ch;
134e68165a6SJilles Tjoelker 	int inquotes;
135e5341cbbSTim J. Robbins 
1363f0131f6SStefan Farfeleder 	if (p[0] == '\0') {
1373f0131f6SStefan Farfeleder 		outstr("''", file);
1383f0131f6SStefan Farfeleder 		return;
1393f0131f6SStefan Farfeleder 	}
140e68165a6SJilles Tjoelker 	/* Caller will handle '=' if necessary */
141e68165a6SJilles Tjoelker 	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
142e68165a6SJilles Tjoelker 			strcmp(p, "[") == 0) {
143dee75cf7STim J. Robbins 		outstr(p, file);
144dee75cf7STim J. Robbins 		return;
145dee75cf7STim J. Robbins 	}
146dee75cf7STim J. Robbins 
147e68165a6SJilles Tjoelker 	inquotes = 0;
148e5341cbbSTim J. Robbins 	while ((ch = *p++) != '\0') {
149e5341cbbSTim J. Robbins 		switch (ch) {
150e5341cbbSTim J. Robbins 		case '\'':
151e68165a6SJilles Tjoelker 			/* Can't quote single quotes inside single quotes. */
152e68165a6SJilles Tjoelker 			if (inquotes)
153e68165a6SJilles Tjoelker 				outc('\'', file);
154e68165a6SJilles Tjoelker 			inquotes = 0;
155e68165a6SJilles Tjoelker 			outstr("\\'", file);
156e5341cbbSTim J. Robbins 			break;
157e5341cbbSTim J. Robbins 		default:
158e68165a6SJilles Tjoelker 			if (!inquotes)
159e68165a6SJilles Tjoelker 				outc('\'', file);
160e68165a6SJilles Tjoelker 			inquotes = 1;
161e5341cbbSTim J. Robbins 			outc(ch, file);
162e5341cbbSTim J. Robbins 		}
163e5341cbbSTim J. Robbins 	}
164e68165a6SJilles Tjoelker 	if (inquotes)
165e68165a6SJilles Tjoelker 		outc('\'', file);
166e5341cbbSTim J. Robbins }
1674b88c807SRodney W. Grimes 
1682ba1b30bSDiomidis Spinellis STATIC char out_junk[16];
1694b88c807SRodney W. Grimes 
1704b88c807SRodney W. Grimes void
1715134c3f7SWarner Losh emptyoutbuf(struct output *dest)
1724b88c807SRodney W. Grimes {
1734b88c807SRodney W. Grimes 	int offset;
1744b88c807SRodney W. Grimes 
1754b88c807SRodney W. Grimes 	if (dest->fd == BLOCK_OUT) {
1764b88c807SRodney W. Grimes 		dest->nextc = out_junk;
1774b88c807SRodney W. Grimes 		dest->nleft = sizeof out_junk;
1784b88c807SRodney W. Grimes 		dest->flags |= OUTPUT_ERR;
1794b88c807SRodney W. Grimes 	} else if (dest->buf == NULL) {
1804b88c807SRodney W. Grimes 		INTOFF;
1814b88c807SRodney W. Grimes 		dest->buf = ckmalloc(dest->bufsize);
1824b88c807SRodney W. Grimes 		dest->nextc = dest->buf;
1834b88c807SRodney W. Grimes 		dest->nleft = dest->bufsize;
1844b88c807SRodney W. Grimes 		INTON;
1854b88c807SRodney W. Grimes 	} else if (dest->fd == MEM_OUT) {
1864b88c807SRodney W. Grimes 		offset = dest->bufsize;
1874b88c807SRodney W. Grimes 		INTOFF;
1884b88c807SRodney W. Grimes 		dest->bufsize <<= 1;
1894b88c807SRodney W. Grimes 		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1904b88c807SRodney W. Grimes 		dest->nleft = dest->bufsize - offset;
1914b88c807SRodney W. Grimes 		dest->nextc = dest->buf + offset;
1924b88c807SRodney W. Grimes 		INTON;
1934b88c807SRodney W. Grimes 	} else {
1944b88c807SRodney W. Grimes 		flushout(dest);
1954b88c807SRodney W. Grimes 	}
1964b88c807SRodney W. Grimes 	dest->nleft--;
1974b88c807SRodney W. Grimes }
1984b88c807SRodney W. Grimes 
1994b88c807SRodney W. Grimes 
2004b88c807SRodney W. Grimes void
2015134c3f7SWarner Losh flushall(void)
2025134c3f7SWarner Losh {
2034b88c807SRodney W. Grimes 	flushout(&output);
2044b88c807SRodney W. Grimes 	flushout(&errout);
2054b88c807SRodney W. Grimes }
2064b88c807SRodney W. Grimes 
2074b88c807SRodney W. Grimes 
2084b88c807SRodney W. Grimes void
2095134c3f7SWarner Losh flushout(struct output *dest)
2104b88c807SRodney W. Grimes {
2114b88c807SRodney W. Grimes 
2124b88c807SRodney W. Grimes 	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2134b88c807SRodney W. Grimes 		return;
2144b88c807SRodney W. Grimes 	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2154b88c807SRodney W. Grimes 		dest->flags |= OUTPUT_ERR;
2164b88c807SRodney W. Grimes 	dest->nextc = dest->buf;
2174b88c807SRodney W. Grimes 	dest->nleft = dest->bufsize;
2184b88c807SRodney W. Grimes }
2194b88c807SRodney W. Grimes 
2204b88c807SRodney W. Grimes 
2214b88c807SRodney W. Grimes void
2225134c3f7SWarner Losh freestdout(void)
2235134c3f7SWarner Losh {
2244b88c807SRodney W. Grimes 	INTOFF;
2254b88c807SRodney W. Grimes 	if (output.buf) {
2264b88c807SRodney W. Grimes 		ckfree(output.buf);
2274b88c807SRodney W. Grimes 		output.buf = NULL;
2284b88c807SRodney W. Grimes 		output.nleft = 0;
2294b88c807SRodney W. Grimes 	}
2304b88c807SRodney W. Grimes 	INTON;
2314b88c807SRodney W. Grimes }
2324b88c807SRodney W. Grimes 
2334b88c807SRodney W. Grimes 
2344b88c807SRodney W. Grimes void
2355134c3f7SWarner Losh outfmt(struct output *file, const char *fmt, ...)
2365134c3f7SWarner Losh {
2374b88c807SRodney W. Grimes 	va_list ap;
2384b88c807SRodney W. Grimes 
2394b88c807SRodney W. Grimes 	va_start(ap, fmt);
2404b88c807SRodney W. Grimes 	doformat(file, fmt, ap);
2414b88c807SRodney W. Grimes 	va_end(ap);
2424b88c807SRodney W. Grimes }
2434b88c807SRodney W. Grimes 
2444b88c807SRodney W. Grimes 
2454b88c807SRodney W. Grimes void
2465134c3f7SWarner Losh out1fmt(const char *fmt, ...)
2475134c3f7SWarner Losh {
2484b88c807SRodney W. Grimes 	va_list ap;
2494b88c807SRodney W. Grimes 
2504b88c807SRodney W. Grimes 	va_start(ap, fmt);
2514b88c807SRodney W. Grimes 	doformat(out1, fmt, ap);
2524b88c807SRodney W. Grimes 	va_end(ap);
2534b88c807SRodney W. Grimes }
2544b88c807SRodney W. Grimes 
2554b88c807SRodney W. Grimes void
256c6204d4aSJilles Tjoelker out2fmt_flush(const char *fmt, ...)
2575134c3f7SWarner Losh {
2584b88c807SRodney W. Grimes 	va_list ap;
2594b88c807SRodney W. Grimes 
2604b88c807SRodney W. Grimes 	va_start(ap, fmt);
2614b88c807SRodney W. Grimes 	doformat(out2, fmt, ap);
2624b88c807SRodney W. Grimes 	va_end(ap);
2634b88c807SRodney W. Grimes 	flushout(out2);
2644b88c807SRodney W. Grimes }
2654b88c807SRodney W. Grimes 
2664b88c807SRodney W. Grimes void
2675134c3f7SWarner Losh fmtstr(char *outbuf, int length, const char *fmt, ...)
2685134c3f7SWarner Losh {
2694b88c807SRodney W. Grimes 	va_list ap;
270658a755bSTim J. Robbins 	struct output strout;
2714b88c807SRodney W. Grimes 
272658a755bSTim J. Robbins 	strout.nextc = outbuf;
273658a755bSTim J. Robbins 	strout.nleft = length;
274658a755bSTim J. Robbins 	strout.fd = BLOCK_OUT;
275658a755bSTim J. Robbins 	strout.flags = 0;
2764b88c807SRodney W. Grimes 	va_start(ap, fmt);
277658a755bSTim J. Robbins 	doformat(&strout, fmt, ap);
2787e73d40eSTim J. Robbins 	va_end(ap);
279658a755bSTim J. Robbins 	outc('\0', &strout);
280658a755bSTim J. Robbins 	if (strout.flags & OUTPUT_ERR)
281658a755bSTim J. Robbins 		outbuf[length - 1] = '\0';
2824b88c807SRodney W. Grimes }
2834b88c807SRodney W. Grimes 
2847e73d40eSTim J. Robbins static int
2857e73d40eSTim J. Robbins doformat_wr(void *cookie, const char *buf, int len)
2867e73d40eSTim J. Robbins {
2877e73d40eSTim J. Robbins 	struct output *o;
2887e73d40eSTim J. Robbins 	int origlen;
2897e73d40eSTim J. Robbins 	unsigned char c;
2904b88c807SRodney W. Grimes 
2917e73d40eSTim J. Robbins 	o = (struct output *)cookie;
2927e73d40eSTim J. Robbins 	origlen = len;
2937e73d40eSTim J. Robbins 	while (len-- != 0) {
2947e73d40eSTim J. Robbins 		c = (unsigned char)*buf++;
2957e73d40eSTim J. Robbins 		outc(c, o);
2967e73d40eSTim J. Robbins 	}
2974b88c807SRodney W. Grimes 
2987e73d40eSTim J. Robbins 	return (origlen);
2997e73d40eSTim J. Robbins }
3004b88c807SRodney W. Grimes 
3014b88c807SRodney W. Grimes void
3025134c3f7SWarner Losh doformat(struct output *dest, const char *f, va_list ap)
3034b88c807SRodney W. Grimes {
3047e73d40eSTim J. Robbins 	FILE *fp;
3054b88c807SRodney W. Grimes 
3067e73d40eSTim J. Robbins 	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
3077e73d40eSTim J. Robbins 		vfprintf(fp, f, ap);
3087e73d40eSTim J. Robbins 		fclose(fp);
3094b88c807SRodney W. Grimes 	}
3104b88c807SRodney W. Grimes }
3114b88c807SRodney W. Grimes 
3124b88c807SRodney W. Grimes /*
3134b88c807SRodney W. Grimes  * Version of write which resumes after a signal is caught.
3144b88c807SRodney W. Grimes  */
3154b88c807SRodney W. Grimes 
3164b88c807SRodney W. Grimes int
3175134c3f7SWarner Losh xwrite(int fd, char *buf, int nbytes)
3184b88c807SRodney W. Grimes {
3194b88c807SRodney W. Grimes 	int ntry;
3204b88c807SRodney W. Grimes 	int i;
3214b88c807SRodney W. Grimes 	int n;
3224b88c807SRodney W. Grimes 
3234b88c807SRodney W. Grimes 	n = nbytes;
3244b88c807SRodney W. Grimes 	ntry = 0;
3254b88c807SRodney W. Grimes 	for (;;) {
3264b88c807SRodney W. Grimes 		i = write(fd, buf, n);
3274b88c807SRodney W. Grimes 		if (i > 0) {
3284b88c807SRodney W. Grimes 			if ((n -= i) <= 0)
3294b88c807SRodney W. Grimes 				return nbytes;
3304b88c807SRodney W. Grimes 			buf += i;
3314b88c807SRodney W. Grimes 			ntry = 0;
3324b88c807SRodney W. Grimes 		} else if (i == 0) {
3334b88c807SRodney W. Grimes 			if (++ntry > 10)
3344b88c807SRodney W. Grimes 				return nbytes - n;
3354b88c807SRodney W. Grimes 		} else if (errno != EINTR) {
3364b88c807SRodney W. Grimes 			return -1;
3374b88c807SRodney W. Grimes 		}
3384b88c807SRodney W. Grimes 	}
3394b88c807SRodney W. Grimes }
340