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