xref: /freebsd/bin/sh/output.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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: output.c,v 1.3 1996/09/01 10:21:23 peter Exp $
37  */
38 
39 #ifndef lint
40 static char 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/ioctl.h>
55 #include <sys/types.h>	/* quad_t */
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 is 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 #ifdef __STDC__
353 static const char digit[] = "0123456789ABCDEF";
354 #else
355 static const char digit[17] = "0123456789ABCDEF";
356 #endif
357 
358 
359 void
360 doformat(dest, f, ap)
361 	register struct output *dest;
362 	register char *f;		/* format string */
363 	va_list ap;
364 	{
365 	register char c;
366 	char temp[TEMPSIZE];
367 	int flushleft;
368 	int sharp;
369 	int width;
370 	int prec;
371 	int islong;
372 	int isquad;
373 	char *p;
374 	int sign;
375 	quad_t l;
376 	u_quad_t num;
377 	unsigned base;
378 	int len;
379 	int size;
380 	int pad;
381 
382 	while ((c = *f++) != '\0') {
383 		if (c != '%') {
384 			outc(c, dest);
385 			continue;
386 		}
387 		flushleft = 0;
388 		sharp = 0;
389 		width = 0;
390 		prec = -1;
391 		islong = 0;
392 		isquad = 0;
393 		for (;;) {
394 			if (*f == '-')
395 				flushleft++;
396 			else if (*f == '#')
397 				sharp++;
398 			else
399 				break;
400 			f++;
401 		}
402 		if (*f == '*') {
403 			width = va_arg(ap, int);
404 			f++;
405 		} else {
406 			while (is_digit(*f)) {
407 				width = 10 * width + digit_val(*f++);
408 			}
409 		}
410 		if (*f == '.') {
411 			if (*++f == '*') {
412 				prec = va_arg(ap, int);
413 				f++;
414 			} else {
415 				prec = 0;
416 				while (is_digit(*f)) {
417 					prec = 10 * prec + digit_val(*f++);
418 				}
419 			}
420 		}
421 		if (*f == 'l') {
422 			islong++;
423 			f++;
424 		} else if (*f == 'q') {
425 			isquad++;
426 			f++;
427 		}
428 		switch (*f) {
429 		case 'd':
430 			if (islong)
431 				l = va_arg(ap, long);
432 			else if (isquad)
433 				l = va_arg(ap, quad_t);
434 			else
435 				l = va_arg(ap, int);
436 			sign = 0;
437 			num = l;
438 			if (l < 0) {
439 				num = -l;
440 				sign = 1;
441 			}
442 			base = 10;
443 			goto number;
444 		case 'u':
445 			base = 10;
446 			goto uns_number;
447 		case 'o':
448 			base = 8;
449 			goto uns_number;
450 		case 'x':
451 			/* we don't implement 'x'; treat like 'X' */
452 		case 'X':
453 			base = 16;
454 uns_number:	  /* an unsigned number */
455 			sign = 0;
456 			if (islong)
457 				num = va_arg(ap, unsigned long);
458 			else if (isquad)
459 				num = va_arg(ap, u_quad_t);
460 			else
461 				num = va_arg(ap, unsigned int);
462 number:		  /* process a number */
463 			p = temp + TEMPSIZE - 1;
464 			*p = '\0';
465 			while (num) {
466 				*--p = digit[num % base];
467 				num /= base;
468 			}
469 			len = (temp + TEMPSIZE - 1) - p;
470 			if (prec < 0)
471 				prec = 1;
472 			if (sharp && *f == 'o' && prec <= len)
473 				prec = len + 1;
474 			pad = 0;
475 			if (width) {
476 				size = len;
477 				if (size < prec)
478 					size = prec;
479 				size += sign;
480 				pad = width - size;
481 				if (flushleft == 0) {
482 					while (--pad >= 0)
483 						outc(' ', dest);
484 				}
485 			}
486 			if (sign)
487 				outc('-', dest);
488 			prec -= len;
489 			while (--prec >= 0)
490 				outc('0', dest);
491 			while (*p)
492 				outc(*p++, dest);
493 			while (--pad >= 0)
494 				outc(' ', dest);
495 			break;
496 		case 's':
497 			p = va_arg(ap, char *);
498 			pad = 0;
499 			if (width) {
500 				len = strlen(p);
501 				if (prec >= 0 && len > prec)
502 					len = prec;
503 				pad = width - len;
504 				if (flushleft == 0) {
505 					while (--pad >= 0)
506 						outc(' ', dest);
507 				}
508 			}
509 			prec++;
510 			while (--prec != 0 && *p)
511 				outc(*p++, dest);
512 			while (--pad >= 0)
513 				outc(' ', dest);
514 			break;
515 		case 'c':
516 			c = va_arg(ap, int);
517 			outc(c, dest);
518 			break;
519 		default:
520 			outc(*f, dest);
521 			break;
522 		}
523 		f++;
524 	}
525 }
526 
527 
528 
529 /*
530  * Version of write which resumes after a signal is caught.
531  */
532 
533 int
534 xwrite(fd, buf, nbytes)
535 	int fd;
536 	char *buf;
537 	int nbytes;
538 	{
539 	int ntry;
540 	int i;
541 	int n;
542 
543 	n = nbytes;
544 	ntry = 0;
545 	for (;;) {
546 		i = write(fd, buf, n);
547 		if (i > 0) {
548 			if ((n -= i) <= 0)
549 				return nbytes;
550 			buf += i;
551 			ntry = 0;
552 		} else if (i == 0) {
553 			if (++ntry > 10)
554 				return nbytes - n;
555 		} else if (errno != EINTR) {
556 			return -1;
557 		}
558 	}
559 }
560 
561 
562 /*
563  * Version of ioctl that retries after a signal is caught.
564  * XXX unused function
565  */
566 
567 int
568 xioctl(fd, request, arg)
569 	int fd;
570 	unsigned long request;
571 	char * arg;
572 {
573 	int i;
574 
575 	while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
576 	return i;
577 }
578