xref: /freebsd/bin/sh/output.c (revision 17d6c636720d00f77e5d098daf4c278f89d84f7b)
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 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
40 #endif
41 static const char rcsid[] =
42   "$FreeBSD$";
43 #endif /* not lint */
44 
45 /*
46  * Shell output routines.  We use our own output routines because:
47  *	When a builtin command is interrupted we have to discard
48  *		any pending output.
49  *	When a builtin command appears in back quotes, we want to
50  *		save the output of the command in a region obtained
51  *		via malloc, rather than doing a fork and reading the
52  *		output of the command via a pipe.
53  *	Our output routines may be smaller than the stdio routines.
54  */
55 
56 #include <sys/types.h>        /* quad_t */
57 #include <sys/ioctl.h>
58 
59 #include <stdio.h>	/* defines BUFSIZ */
60 #include <string.h>
61 #ifdef __STDC__
62 #include <stdarg.h>
63 #else
64 #include <varargs.h>
65 #endif
66 #include <errno.h>
67 #include <unistd.h>
68 #include <stdlib.h>
69 
70 #include "shell.h"
71 #include "syntax.h"
72 #include "output.h"
73 #include "memalloc.h"
74 #include "error.h"
75 
76 
77 #define OUTBUFSIZ BUFSIZ
78 #define BLOCK_OUT -2		/* output to a fixed block of memory */
79 #define MEM_OUT -3		/* output to dynamically allocated memory */
80 #define OUTPUT_ERR 01		/* error occurred on output */
81 
82 
83 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
84 struct output errout = {NULL, 0, NULL, 100, 2, 0};
85 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
86 struct output *out1 = &output;
87 struct output *out2 = &errout;
88 
89 
90 
91 #ifdef mkinit
92 
93 INCLUDE "output.h"
94 INCLUDE "memalloc.h"
95 
96 RESET {
97 	out1 = &output;
98 	out2 = &errout;
99 	if (memout.buf != NULL) {
100 		ckfree(memout.buf);
101 		memout.buf = NULL;
102 	}
103 }
104 
105 #endif
106 
107 
108 #ifdef notdef	/* no longer used */
109 /*
110  * Set up an output file to write to memory rather than a file.
111  */
112 
113 void
114 open_mem(block, length, file)
115 	char *block;
116 	int length;
117 	struct output *file;
118 	{
119 	file->nextc = block;
120 	file->nleft = --length;
121 	file->fd = BLOCK_OUT;
122 	file->flags = 0;
123 }
124 #endif
125 
126 
127 void
128 out1str(p)
129 	const char *p;
130 	{
131 	outstr(p, out1);
132 }
133 
134 
135 void
136 out2str(p)
137 	const char *p;
138 	{
139 	outstr(p, out2);
140 }
141 
142 
143 void
144 outstr(p, file)
145 	const char *p;
146 	struct output *file;
147 	{
148 	while (*p)
149 		outc(*p++, file);
150 	if (file == out2)
151 		flushout(file);
152 }
153 
154 
155 char out_junk[16];
156 
157 
158 void
159 emptyoutbuf(dest)
160 	struct output *dest;
161 	{
162 	int offset;
163 
164 	if (dest->fd == BLOCK_OUT) {
165 		dest->nextc = out_junk;
166 		dest->nleft = sizeof out_junk;
167 		dest->flags |= OUTPUT_ERR;
168 	} else if (dest->buf == NULL) {
169 		INTOFF;
170 		dest->buf = ckmalloc(dest->bufsize);
171 		dest->nextc = dest->buf;
172 		dest->nleft = dest->bufsize;
173 		INTON;
174 	} else if (dest->fd == MEM_OUT) {
175 		offset = dest->bufsize;
176 		INTOFF;
177 		dest->bufsize <<= 1;
178 		dest->buf = ckrealloc(dest->buf, dest->bufsize);
179 		dest->nleft = dest->bufsize - offset;
180 		dest->nextc = dest->buf + offset;
181 		INTON;
182 	} else {
183 		flushout(dest);
184 	}
185 	dest->nleft--;
186 }
187 
188 
189 void
190 flushall() {
191 	flushout(&output);
192 	flushout(&errout);
193 }
194 
195 
196 void
197 flushout(dest)
198 	struct output *dest;
199 	{
200 
201 	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
202 		return;
203 	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
204 		dest->flags |= OUTPUT_ERR;
205 	dest->nextc = dest->buf;
206 	dest->nleft = dest->bufsize;
207 }
208 
209 
210 void
211 freestdout() {
212 	INTOFF;
213 	if (output.buf) {
214 		ckfree(output.buf);
215 		output.buf = NULL;
216 		output.nleft = 0;
217 	}
218 	INTON;
219 }
220 
221 
222 #ifdef __STDC__
223 void
224 outfmt(struct output *file, const char *fmt, ...) {
225 	va_list ap;
226 
227 	va_start(ap, fmt);
228 	doformat(file, fmt, ap);
229 	va_end(ap);
230 }
231 
232 
233 void
234 out1fmt(const char *fmt, ...) {
235 	va_list ap;
236 
237 	va_start(ap, fmt);
238 	doformat(out1, fmt, ap);
239 	va_end(ap);
240 }
241 
242 void
243 dprintf(const char *fmt, ...) {
244 	va_list ap;
245 
246 	va_start(ap, fmt);
247 	doformat(out2, fmt, ap);
248 	va_end(ap);
249 	flushout(out2);
250 }
251 
252 void
253 fmtstr(char *outbuf, int length, const char *fmt, ...) {
254 	va_list ap;
255 	struct output strout;
256 
257 	va_start(ap, fmt);
258 	strout.nextc = outbuf;
259 	strout.nleft = length;
260 	strout.fd = BLOCK_OUT;
261 	strout.flags = 0;
262 	doformat(&strout, fmt, ap);
263 	outc('\0', &strout);
264 	if (strout.flags & OUTPUT_ERR)
265 		outbuf[length - 1] = '\0';
266 }
267 
268 #else /* not __STDC__ */
269 
270 void
271 outfmt(va_alist)
272 	va_dcl
273 	{
274 	va_list ap;
275 	struct output *file;
276 	const char *fmt;
277 
278 	va_start(ap);
279 	file = va_arg(ap, struct output *);
280 	fmt = va_arg(ap, char *);
281 	doformat(file, fmt, ap);
282 	va_end(ap);
283 }
284 
285 
286 void
287 out1fmt(va_alist)
288 	va_dcl
289 	{
290 	va_list ap;
291 	const char *fmt;
292 
293 	va_start(ap);
294 	fmt = va_arg(ap, char *);
295 	doformat(out1, fmt, ap);
296 	va_end(ap);
297 }
298 
299 void
300 dprintf(va_alist)
301 	va_dcl
302 	{
303 	va_list ap;
304 	const char *fmt;
305 
306 	va_start(ap);
307 	fmt = va_arg(ap, char *);
308 	doformat(out2, fmt, ap);
309 	va_end(ap);
310 	flushout(out2);
311 }
312 
313 void
314 fmtstr(va_alist)
315 	va_dcl
316 	{
317 	va_list ap;
318 	struct output strout;
319 	char *outbuf;
320 	int length;
321 	const char *fmt;
322 
323 	va_start(ap);
324 	outbuf = va_arg(ap, char *);
325 	length = va_arg(ap, int);
326 	fmt = va_arg(ap, char *);
327 	strout.nextc = outbuf;
328 	strout.nleft = length;
329 	strout.fd = BLOCK_OUT;
330 	strout.flags = 0;
331 	doformat(&strout, fmt, ap);
332 	outc('\0', &strout);
333 	if (strout.flags & OUTPUT_ERR)
334 		outbuf[length - 1] = '\0';
335 }
336 #endif /* __STDC__ */
337 
338 
339 /*
340  * Formatted output.  This routine handles a subset of the printf formats:
341  * - Formats supported: d, u, o, X, s, and c.
342  * - The x format is also accepted but is treated like X.
343  * - The l and q modifiers are accepted.
344  * - The - and # flags are accepted; # only works with the o format.
345  * - Width and precision may be specified with any format except c.
346  * - An * may be given for the width or precision.
347  * - The obsolete practice of preceding the width with a zero to get
348  *   zero padding is not supported; use the precision field.
349  * - A % may be printed by writing %% in the format string.
350  */
351 
352 #define TEMPSIZE 24
353 
354 static const char digit[] = "0123456789ABCDEF";
355 
356 
357 void
358 doformat(dest, f, ap)
359 	struct output *dest;
360 	const char *f;		/* format string */
361 	va_list ap;
362 	{
363 	char c;
364 	char temp[TEMPSIZE];
365 	int flushleft;
366 	int sharp;
367 	int width;
368 	int prec;
369 	int islong;
370 	int isquad;
371 	char *p;
372 	int sign;
373 	quad_t l;
374 	u_quad_t num;
375 	unsigned base;
376 	int len;
377 	int size;
378 	int pad;
379 
380 	while ((c = *f++) != '\0') {
381 		if (c != '%') {
382 			outc(c, dest);
383 			continue;
384 		}
385 		flushleft = 0;
386 		sharp = 0;
387 		width = 0;
388 		prec = -1;
389 		islong = 0;
390 		isquad = 0;
391 		for (;;) {
392 			if (*f == '-')
393 				flushleft++;
394 			else if (*f == '#')
395 				sharp++;
396 			else
397 				break;
398 			f++;
399 		}
400 		if (*f == '*') {
401 			width = va_arg(ap, int);
402 			f++;
403 		} else {
404 			while (is_digit(*f)) {
405 				width = 10 * width + digit_val(*f++);
406 			}
407 		}
408 		if (*f == '.') {
409 			if (*++f == '*') {
410 				prec = va_arg(ap, int);
411 				f++;
412 			} else {
413 				prec = 0;
414 				while (is_digit(*f)) {
415 					prec = 10 * prec + digit_val(*f++);
416 				}
417 			}
418 		}
419 		if (*f == 'l') {
420 			islong++;
421 			f++;
422 		} else if (*f == 'q') {
423 			isquad++;
424 			f++;
425 		}
426 		switch (*f) {
427 		case 'd':
428 			if (isquad)
429 				l = va_arg(ap, quad_t);
430 			else if (islong)
431 				l = va_arg(ap, long);
432 			else
433 				l = va_arg(ap, int);
434 			sign = 0;
435 			num = l;
436 			if (l < 0) {
437 				num = -l;
438 				sign = 1;
439 			}
440 			base = 10;
441 			goto number;
442 		case 'u':
443 			base = 10;
444 			goto uns_number;
445 		case 'o':
446 			base = 8;
447 			goto uns_number;
448 		case 'x':
449 			/* we don't implement 'x'; treat like 'X' */
450 		case 'X':
451 			base = 16;
452 uns_number:	  /* an unsigned number */
453 			sign = 0;
454 			if (isquad)
455 				num = va_arg(ap, u_quad_t);
456 			else if (islong)
457 				num = va_arg(ap, unsigned long);
458 			else
459 				num = va_arg(ap, unsigned int);
460 number:		  /* process a number */
461 			p = temp + TEMPSIZE - 1;
462 			*p = '\0';
463 			while (num) {
464 				*--p = digit[num % base];
465 				num /= base;
466 			}
467 			len = (temp + TEMPSIZE - 1) - p;
468 			if (prec < 0)
469 				prec = 1;
470 			if (sharp && *f == 'o' && prec <= len)
471 				prec = len + 1;
472 			pad = 0;
473 			if (width) {
474 				size = len;
475 				if (size < prec)
476 					size = prec;
477 				size += sign;
478 				pad = width - size;
479 				if (flushleft == 0) {
480 					while (--pad >= 0)
481 						outc(' ', dest);
482 				}
483 			}
484 			if (sign)
485 				outc('-', dest);
486 			prec -= len;
487 			while (--prec >= 0)
488 				outc('0', dest);
489 			while (*p)
490 				outc(*p++, dest);
491 			while (--pad >= 0)
492 				outc(' ', dest);
493 			break;
494 		case 's':
495 			p = va_arg(ap, char *);
496 			pad = 0;
497 			if (width) {
498 				len = strlen(p);
499 				if (prec >= 0 && len > prec)
500 					len = prec;
501 				pad = width - len;
502 				if (flushleft == 0) {
503 					while (--pad >= 0)
504 						outc(' ', dest);
505 				}
506 			}
507 			prec++;
508 			while (--prec != 0 && *p)
509 				outc(*p++, dest);
510 			while (--pad >= 0)
511 				outc(' ', dest);
512 			break;
513 		case 'c':
514 			c = va_arg(ap, int);
515 			outc(c, dest);
516 			break;
517 		default:
518 			outc(*f, dest);
519 			break;
520 		}
521 		f++;
522 	}
523 }
524 
525 
526 
527 /*
528  * Version of write which resumes after a signal is caught.
529  */
530 
531 int
532 xwrite(fd, buf, nbytes)
533 	int fd;
534 	char *buf;
535 	int nbytes;
536 	{
537 	int ntry;
538 	int i;
539 	int n;
540 
541 	n = nbytes;
542 	ntry = 0;
543 	for (;;) {
544 		i = write(fd, buf, n);
545 		if (i > 0) {
546 			if ((n -= i) <= 0)
547 				return nbytes;
548 			buf += i;
549 			ntry = 0;
550 		} else if (i == 0) {
551 			if (++ntry > 10)
552 				return nbytes - n;
553 		} else if (errno != EINTR) {
554 			return -1;
555 		}
556 	}
557 }
558 
559 
560 /*
561  * Version of ioctl that retries after a signal is caught.
562  * XXX unused function
563  */
564 
565 int
566 xioctl(fd, request, arg)
567 	int fd;
568 	unsigned long request;
569 	char * arg;
570 {
571 	int i;
572 
573 	while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
574 	return i;
575 }
576