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