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