xref: /dragonfly/bin/sh/output.c (revision 20c2db9a)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)output.c	8.2 (Berkeley) 5/4/95
37  * $FreeBSD: head/bin/sh/output.c 244162 2012-12-12 22:01:10Z jilles $
38  */
39 
40 /*
41  * Shell output routines.  We use our own output routines because:
42  *	When a builtin command is interrupted we have to discard
43  *		any pending output.
44  *	When a builtin command appears in back quotes, we want to
45  *		save the output of the command in a region obtained
46  *		via malloc, rather than doing a fork and reading the
47  *		output of the command via a pipe.
48  */
49 
50 #include <stdio.h>	/* defines BUFSIZ */
51 #include <string.h>
52 #include <stdarg.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 
57 #include "shell.h"
58 #include "syntax.h"
59 #include "output.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "var.h"
63 
64 
65 #define OUTBUFSIZ BUFSIZ
66 #define MEM_OUT -2		/* output to dynamically allocated memory */
67 #define OUTPUT_ERR 01		/* error occurred on output */
68 
69 static int doformat_wr(void *, const char *, int);
70 
71 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
72 struct output errout = {NULL, 0, NULL, 256, 2, 0};
73 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
74 struct output *out1 = &output;
75 struct output *out2 = &errout;
76 
77 
78 
79 #ifdef mkinit
80 
81 INCLUDE "output.h"
82 INCLUDE "memalloc.h"
83 
84 RESET {
85 	out1 = &output;
86 	out2 = &errout;
87 	if (memout.buf != NULL) {
88 		ckfree(memout.buf);
89 		memout.buf = NULL;
90 	}
91 }
92 
93 #endif
94 
95 
96 void
97 outcslow(int c, struct output *file)
98 {
99 	outc(c, file);
100 }
101 
102 void
103 out1str(const char *p)
104 {
105 	outstr(p, out1);
106 }
107 
108 void
109 out1qstr(const char *p)
110 {
111 	outqstr(p, out1);
112 }
113 
114 void
115 out2str(const char *p)
116 {
117 	outstr(p, out2);
118 }
119 
120 void
121 out2qstr(const char *p)
122 {
123 	outqstr(p, out2);
124 }
125 
126 void
127 outstr(const char *p, struct output *file)
128 {
129 	outbin(p, strlen(p), file);
130 }
131 
132 /* Like outstr(), but quote for re-input into the shell. */
133 void
134 outqstr(const char *p, struct output *file)
135 {
136 	char ch;
137 	int inquotes;
138 
139 	if (p[0] == '\0') {
140 		outstr("''", file);
141 		return;
142 	}
143 	/* Caller will handle '=' if necessary */
144 	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
145 			strcmp(p, "[") == 0) {
146 		outstr(p, file);
147 		return;
148 	}
149 
150 	inquotes = 0;
151 	while ((ch = *p++) != '\0') {
152 		switch (ch) {
153 		case '\'':
154 			/* Can't quote single quotes inside single quotes. */
155 			if (inquotes)
156 				outcslow('\'', file);
157 			inquotes = 0;
158 			outstr("\\'", file);
159 			break;
160 		default:
161 			if (!inquotes)
162 				outcslow('\'', file);
163 			inquotes = 1;
164 			outc(ch, file);
165 		}
166 	}
167 	if (inquotes)
168 		outcslow('\'', file);
169 }
170 
171 void
172 outbin(const void *data, size_t len, struct output *file)
173 {
174 	const char *p;
175 
176 	p = data;
177 	while (len-- > 0)
178 		outc(*p++, file);
179 }
180 
181 void
182 emptyoutbuf(struct output *dest)
183 {
184 	int offset;
185 
186 	if (dest->buf == NULL) {
187 		INTOFF;
188 		dest->buf = ckmalloc(dest->bufsize);
189 		dest->nextc = dest->buf;
190 		dest->nleft = dest->bufsize;
191 		INTON;
192 	} else if (dest->fd == MEM_OUT) {
193 		offset = dest->bufsize;
194 		INTOFF;
195 		dest->bufsize <<= 1;
196 		dest->buf = ckrealloc(dest->buf, dest->bufsize);
197 		dest->nleft = dest->bufsize - offset;
198 		dest->nextc = dest->buf + offset;
199 		INTON;
200 	} else {
201 		flushout(dest);
202 	}
203 	dest->nleft--;
204 }
205 
206 
207 void
208 flushall(void)
209 {
210 	flushout(&output);
211 	flushout(&errout);
212 }
213 
214 
215 void
216 flushout(struct output *dest)
217 {
218 
219 	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
220 		return;
221 	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
222 		dest->flags |= OUTPUT_ERR;
223 	dest->nextc = dest->buf;
224 	dest->nleft = dest->bufsize;
225 }
226 
227 
228 void
229 freestdout(void)
230 {
231 	INTOFF;
232 	if (output.buf) {
233 		ckfree(output.buf);
234 		output.buf = NULL;
235 		output.nleft = 0;
236 	}
237 	INTON;
238 }
239 
240 
241 int
242 outiserror(struct output *file)
243 {
244 	return (file->flags & OUTPUT_ERR);
245 }
246 
247 
248 void
249 outclearerror(struct output *file)
250 {
251 	file->flags &= ~OUTPUT_ERR;
252 }
253 
254 
255 void
256 outfmt(struct output *file, const char *fmt, ...)
257 {
258 	va_list ap;
259 
260 	va_start(ap, fmt);
261 	doformat(file, fmt, ap);
262 	va_end(ap);
263 }
264 
265 
266 void
267 out1fmt(const char *fmt, ...)
268 {
269 	va_list ap;
270 
271 	va_start(ap, fmt);
272 	doformat(out1, fmt, ap);
273 	va_end(ap);
274 }
275 
276 void
277 out2fmt_flush(const char *fmt, ...)
278 {
279 	va_list ap;
280 
281 	va_start(ap, fmt);
282 	doformat(out2, fmt, ap);
283 	va_end(ap);
284 	flushout(out2);
285 }
286 
287 void
288 fmtstr(char *outbuf, int length, const char *fmt, ...)
289 {
290 	va_list ap;
291 
292 	INTOFF;
293 	va_start(ap, fmt);
294 	vsnprintf(outbuf, length, fmt, ap);
295 	va_end(ap);
296 	INTON;
297 }
298 
299 static int
300 doformat_wr(void *cookie, const char *buf, int len)
301 {
302 	struct output *o;
303 
304 	o = (struct output *)cookie;
305 	outbin(buf, len, o);
306 
307 	return (len);
308 }
309 
310 void
311 doformat(struct output *dest, const char *f, va_list ap)
312 {
313 	FILE *fp;
314 
315 	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
316 		vfprintf(fp, f, ap);
317 		fclose(fp);
318 	}
319 }
320 
321 /*
322  * Version of write which resumes after a signal is caught.
323  */
324 
325 int
326 xwrite(int fd, const char *buf, int nbytes)
327 {
328 	int ntry;
329 	int i;
330 	int n;
331 
332 	n = nbytes;
333 	ntry = 0;
334 	for (;;) {
335 		i = write(fd, buf, n);
336 		if (i > 0) {
337 			if ((n -= i) <= 0)
338 				return nbytes;
339 			buf += i;
340 			ntry = 0;
341 		} else if (i == 0) {
342 			if (++ntry > 10)
343 				return nbytes - n;
344 		} else if (errno != EINTR) {
345 			return -1;
346 		}
347 	}
348 }
349