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