xref: /csrg-svn/bin/sh/output.c (revision 69272)
147137Sbostic /*-
260698Sbostic  * Copyright (c) 1991, 1993
360698Sbostic  *	The Regents of the University of California.  All rights reserved.
447137Sbostic  *
547137Sbostic  * This code is derived from software contributed to Berkeley by
647137Sbostic  * Kenneth Almquist.
747137Sbostic  *
847137Sbostic  * %sccs.include.redist.c%
947137Sbostic  */
1047137Sbostic 
1147137Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)output.c	8.2 (Berkeley) 05/04/95";
1347137Sbostic #endif /* not lint */
1447137Sbostic 
1547137Sbostic /*
1647137Sbostic  * Shell output routines.  We use our own output routines because:
1747137Sbostic  *	When a builtin command is interrupted we have to discard
1847137Sbostic  *		any pending output.
1947137Sbostic  *	When a builtin command appears in back quotes, we want to
2047137Sbostic  *		save the output of the command in a region obtained
2147137Sbostic  *		via malloc, rather than doing a fork and reading the
2247137Sbostic  *		output of the command via a pipe.
2347137Sbostic  *	Our output routines may be smaller than the stdio routines.
2447137Sbostic  */
2547137Sbostic 
26*69272Schristos #include <sys/ioctl.h>
27*69272Schristos 
2847137Sbostic #include <stdio.h>	/* defines BUFSIZ */
29*69272Schristos #include <string.h>
3047137Sbostic #ifdef __STDC__
31*69272Schristos #include <stdarg.h>
3247137Sbostic #else
3347137Sbostic #include <varargs.h>
3447137Sbostic #endif
3547137Sbostic #include <errno.h>
36*69272Schristos #include <unistd.h>
37*69272Schristos #include <stdlib.h>
3847137Sbostic 
39*69272Schristos #include "shell.h"
40*69272Schristos #include "syntax.h"
41*69272Schristos #include "output.h"
42*69272Schristos #include "memalloc.h"
43*69272Schristos #include "error.h"
4447137Sbostic 
45*69272Schristos 
4647137Sbostic #define OUTBUFSIZ BUFSIZ
4747137Sbostic #define BLOCK_OUT -2		/* output to a fixed block of memory */
4847137Sbostic #define MEM_OUT -3		/* output to dynamically allocated memory */
4947137Sbostic #define OUTPUT_ERR 01		/* error occurred on output */
5047137Sbostic 
5147137Sbostic 
5247137Sbostic struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
5347137Sbostic struct output errout = {NULL, 0, NULL, 100, 2, 0};;
5447137Sbostic struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
5547137Sbostic struct output *out1 = &output;
5647137Sbostic struct output *out2 = &errout;
5747137Sbostic 
5847137Sbostic 
5947137Sbostic 
6047137Sbostic #ifdef mkinit
6147137Sbostic 
6247137Sbostic INCLUDE "output.h"
6347137Sbostic INCLUDE "memalloc.h"
6447137Sbostic 
6547137Sbostic RESET {
6647137Sbostic 	out1 = &output;
6747137Sbostic 	out2 = &errout;
6847137Sbostic 	if (memout.buf != NULL) {
6947137Sbostic 		ckfree(memout.buf);
7047137Sbostic 		memout.buf = NULL;
7147137Sbostic 	}
7247137Sbostic }
7347137Sbostic 
7447137Sbostic #endif
7547137Sbostic 
7647137Sbostic 
7747137Sbostic #ifdef notdef	/* no longer used */
7847137Sbostic /*
7947137Sbostic  * Set up an output file to write to memory rather than a file.
8047137Sbostic  */
8147137Sbostic 
8247137Sbostic void
open_mem(block,length,file)8347137Sbostic open_mem(block, length, file)
8447137Sbostic 	char *block;
8547137Sbostic 	int length;
8647137Sbostic 	struct output *file;
8747137Sbostic 	{
8847137Sbostic 	file->nextc = block;
8947137Sbostic 	file->nleft = --length;
9047137Sbostic 	file->fd = BLOCK_OUT;
9147137Sbostic 	file->flags = 0;
9247137Sbostic }
9347137Sbostic #endif
9447137Sbostic 
9547137Sbostic 
9647137Sbostic void
out1str(p)9747137Sbostic out1str(p)
98*69272Schristos 	const char *p;
9947137Sbostic 	{
10047137Sbostic 	outstr(p, out1);
10147137Sbostic }
10247137Sbostic 
10347137Sbostic 
10447137Sbostic void
out2str(p)10547137Sbostic out2str(p)
106*69272Schristos 	const char *p;
10747137Sbostic 	{
10847137Sbostic 	outstr(p, out2);
10947137Sbostic }
11047137Sbostic 
11147137Sbostic 
11247137Sbostic void
outstr(p,file)11347137Sbostic outstr(p, file)
114*69272Schristos 	register const char *p;
11547137Sbostic 	register struct output *file;
11647137Sbostic 	{
11747137Sbostic 	while (*p)
11847137Sbostic 		outc(*p++, file);
11955228Smarc 	if (file == out2)
12055228Smarc 		flushout(file);
12147137Sbostic }
12247137Sbostic 
12347137Sbostic 
12447137Sbostic char out_junk[16];
12547137Sbostic 
12647137Sbostic 
12747137Sbostic void
emptyoutbuf(dest)12847137Sbostic emptyoutbuf(dest)
12947137Sbostic 	struct output *dest;
13047137Sbostic 	{
13147137Sbostic 	int offset;
13247137Sbostic 
13347137Sbostic 	if (dest->fd == BLOCK_OUT) {
13447137Sbostic 		dest->nextc = out_junk;
13547137Sbostic 		dest->nleft = sizeof out_junk;
13647137Sbostic 		dest->flags |= OUTPUT_ERR;
13747137Sbostic 	} else if (dest->buf == NULL) {
13847137Sbostic 		INTOFF;
13947137Sbostic 		dest->buf = ckmalloc(dest->bufsize);
14047137Sbostic 		dest->nextc = dest->buf;
14147137Sbostic 		dest->nleft = dest->bufsize;
14247137Sbostic 		INTON;
14347137Sbostic 	} else if (dest->fd == MEM_OUT) {
14447137Sbostic 		offset = dest->bufsize;
14547137Sbostic 		INTOFF;
14647137Sbostic 		dest->bufsize <<= 1;
14747137Sbostic 		dest->buf = ckrealloc(dest->buf, dest->bufsize);
14847137Sbostic 		dest->nleft = dest->bufsize - offset;
14947137Sbostic 		dest->nextc = dest->buf + offset;
15047137Sbostic 		INTON;
15147137Sbostic 	} else {
15247137Sbostic 		flushout(dest);
15347137Sbostic 	}
15447137Sbostic 	dest->nleft--;
15547137Sbostic }
15647137Sbostic 
15747137Sbostic 
15847137Sbostic void
flushall()15947137Sbostic flushall() {
16047137Sbostic 	flushout(&output);
16147137Sbostic 	flushout(&errout);
16247137Sbostic }
16347137Sbostic 
16447137Sbostic 
16547137Sbostic void
flushout(dest)16647137Sbostic flushout(dest)
16747137Sbostic 	struct output *dest;
16847137Sbostic 	{
16947137Sbostic 
17047137Sbostic 	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
17147137Sbostic 		return;
17247137Sbostic 	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
17347137Sbostic 		dest->flags |= OUTPUT_ERR;
17447137Sbostic 	dest->nextc = dest->buf;
17547137Sbostic 	dest->nleft = dest->bufsize;
17647137Sbostic }
17747137Sbostic 
17847137Sbostic 
17947137Sbostic void
freestdout()18047137Sbostic freestdout() {
18147137Sbostic 	INTOFF;
18247137Sbostic 	if (output.buf) {
18347137Sbostic 		ckfree(output.buf);
18447137Sbostic 		output.buf = NULL;
18547137Sbostic 		output.nleft = 0;
18647137Sbostic 	}
18747137Sbostic 	INTON;
18847137Sbostic }
18947137Sbostic 
19047137Sbostic 
19147137Sbostic #ifdef __STDC__
19247137Sbostic void
outfmt(struct output * file,char * fmt,...)19347137Sbostic outfmt(struct output *file, char *fmt, ...) {
19447137Sbostic 	va_list ap;
19547137Sbostic 
19647137Sbostic 	va_start(ap, fmt);
19747137Sbostic 	doformat(file, fmt, ap);
19847137Sbostic 	va_end(ap);
19947137Sbostic }
20047137Sbostic 
20147137Sbostic 
20247137Sbostic void
out1fmt(char * fmt,...)20347137Sbostic out1fmt(char *fmt, ...) {
20447137Sbostic 	va_list ap;
20547137Sbostic 
20647137Sbostic 	va_start(ap, fmt);
20747137Sbostic 	doformat(out1, fmt, ap);
20847137Sbostic 	va_end(ap);
20947137Sbostic }
21047137Sbostic 
21154324Smarc void
dprintf(char * fmt,...)21254324Smarc dprintf(char *fmt, ...) {
21354324Smarc 	va_list ap;
21447137Sbostic 
21554324Smarc 	va_start(ap, fmt);
21654324Smarc 	doformat(out2, fmt, ap);
21754324Smarc 	va_end(ap);
21854324Smarc 	flushout(out2);
21954324Smarc }
22054324Smarc 
22147137Sbostic void
fmtstr(char * outbuf,int length,char * fmt,...)22247137Sbostic fmtstr(char *outbuf, int length, char *fmt, ...) {
22347137Sbostic 	va_list ap;
22447137Sbostic 	struct output strout;
22547137Sbostic 
22647137Sbostic 	va_start(ap, fmt);
22747137Sbostic 	strout.nextc = outbuf;
22847137Sbostic 	strout.nleft = length;
22947137Sbostic 	strout.fd = BLOCK_OUT;
23047137Sbostic 	strout.flags = 0;
23147137Sbostic 	doformat(&strout, fmt, ap);
23247137Sbostic 	outc('\0', &strout);
23347137Sbostic 	if (strout.flags & OUTPUT_ERR)
23447137Sbostic 		outbuf[length - 1] = '\0';
23547137Sbostic }
23647137Sbostic 
23747137Sbostic #else /* not __STDC__ */
23847137Sbostic 
23947137Sbostic void
outfmt(va_alist)24047137Sbostic outfmt(va_alist)
24147137Sbostic 	va_dcl
24247137Sbostic 	{
24347137Sbostic 	va_list ap;
24447137Sbostic 	struct output *file;
24547137Sbostic 	char *fmt;
24647137Sbostic 
24747137Sbostic 	va_start(ap);
24847137Sbostic 	file = va_arg(ap, struct output *);
24947137Sbostic 	fmt = va_arg(ap, char *);
25047137Sbostic 	doformat(file, fmt, ap);
25147137Sbostic 	va_end(ap);
25247137Sbostic }
25347137Sbostic 
25447137Sbostic 
25547137Sbostic void
out1fmt(va_alist)25647137Sbostic out1fmt(va_alist)
25747137Sbostic 	va_dcl
25847137Sbostic 	{
25947137Sbostic 	va_list ap;
26047137Sbostic 	char *fmt;
26147137Sbostic 
26247137Sbostic 	va_start(ap);
26347137Sbostic 	fmt = va_arg(ap, char *);
26447137Sbostic 	doformat(out1, fmt, ap);
26547137Sbostic 	va_end(ap);
26647137Sbostic }
26747137Sbostic 
26854324Smarc void
dprintf(va_alist)26954324Smarc dprintf(va_alist)
27054324Smarc 	va_dcl
27154324Smarc 	{
27254324Smarc 	va_list ap;
27354324Smarc 	char *fmt;
27447137Sbostic 
27554324Smarc 	va_start(ap);
27654324Smarc 	fmt = va_arg(ap, char *);
27754324Smarc 	doformat(out2, fmt, ap);
27854324Smarc 	va_end(ap);
27954324Smarc 	flushout(out2);
28054324Smarc }
28154324Smarc 
28247137Sbostic void
fmtstr(va_alist)28347137Sbostic fmtstr(va_alist)
28447137Sbostic 	va_dcl
28547137Sbostic 	{
28647137Sbostic 	va_list ap;
28747137Sbostic 	struct output strout;
28847137Sbostic 	char *outbuf;
28947137Sbostic 	int length;
29047137Sbostic 	char *fmt;
29147137Sbostic 
29247137Sbostic 	va_start(ap);
29347137Sbostic 	outbuf = va_arg(ap, char *);
29447137Sbostic 	length = va_arg(ap, int);
29547137Sbostic 	fmt = va_arg(ap, char *);
29647137Sbostic 	strout.nextc = outbuf;
29747137Sbostic 	strout.nleft = length;
29847137Sbostic 	strout.fd = BLOCK_OUT;
29947137Sbostic 	strout.flags = 0;
30047137Sbostic 	doformat(&strout, fmt, ap);
30147137Sbostic 	outc('\0', &strout);
30247137Sbostic 	if (strout.flags & OUTPUT_ERR)
30347137Sbostic 		outbuf[length - 1] = '\0';
30447137Sbostic }
30547137Sbostic #endif /* __STDC__ */
30647137Sbostic 
30747137Sbostic 
30847137Sbostic /*
30947137Sbostic  * Formatted output.  This routine handles a subset of the printf formats:
31047137Sbostic  * - Formats supported: d, u, o, X, s, and c.
31147137Sbostic  * - The x format is also accepted but is treated like X.
31247137Sbostic  * - The l modifier is accepted.
31347137Sbostic  * - The - and # flags are accepted; # only works with the o format.
31447137Sbostic  * - Width and precision may be specified with any format except c.
31547137Sbostic  * - An * may be given for the width or precision.
31647137Sbostic  * - The obsolete practice of preceding the width with a zero to get
31747137Sbostic  *   zero padding is not supported; use the precision field.
31847137Sbostic  * - A % may be printed by writing %% in the format string.
31947137Sbostic  */
32047137Sbostic 
32147137Sbostic #define TEMPSIZE 24
32247137Sbostic 
32347137Sbostic #ifdef __STDC__
32447137Sbostic static const char digit[16] = "0123456789ABCDEF";
32547137Sbostic #else
32647137Sbostic static const char digit[17] = "0123456789ABCDEF";
32747137Sbostic #endif
32847137Sbostic 
32947137Sbostic 
33047137Sbostic void
doformat(dest,f,ap)33147137Sbostic doformat(dest, f, ap)
33247137Sbostic 	register struct output *dest;
33347137Sbostic 	register char *f;		/* format string */
33447137Sbostic 	va_list ap;
33547137Sbostic 	{
33647137Sbostic 	register char c;
33747137Sbostic 	char temp[TEMPSIZE];
33847137Sbostic 	int flushleft;
33947137Sbostic 	int sharp;
34047137Sbostic 	int width;
34147137Sbostic 	int prec;
34247137Sbostic 	int islong;
34347137Sbostic 	char *p;
34447137Sbostic 	int sign;
34547137Sbostic 	long l;
34647137Sbostic 	unsigned long num;
34747137Sbostic 	unsigned base;
34847137Sbostic 	int len;
34947137Sbostic 	int size;
35047137Sbostic 	int pad;
35147137Sbostic 
35247137Sbostic 	while ((c = *f++) != '\0') {
35347137Sbostic 		if (c != '%') {
35447137Sbostic 			outc(c, dest);
35547137Sbostic 			continue;
35647137Sbostic 		}
35747137Sbostic 		flushleft = 0;
35847137Sbostic 		sharp = 0;
35947137Sbostic 		width = 0;
36047137Sbostic 		prec = -1;
36147137Sbostic 		islong = 0;
36247137Sbostic 		for (;;) {
36347137Sbostic 			if (*f == '-')
36447137Sbostic 				flushleft++;
36547137Sbostic 			else if (*f == '#')
36647137Sbostic 				sharp++;
36747137Sbostic 			else
36847137Sbostic 				break;
36947137Sbostic 			f++;
37047137Sbostic 		}
37147137Sbostic 		if (*f == '*') {
37247137Sbostic 			width = va_arg(ap, int);
37347137Sbostic 			f++;
37447137Sbostic 		} else {
37547137Sbostic 			while (is_digit(*f)) {
37647137Sbostic 				width = 10 * width + digit_val(*f++);
37747137Sbostic 			}
37847137Sbostic 		}
37947137Sbostic 		if (*f == '.') {
38047137Sbostic 			if (*++f == '*') {
38147137Sbostic 				prec = va_arg(ap, int);
38247137Sbostic 				f++;
38347137Sbostic 			} else {
38447137Sbostic 				prec = 0;
38547137Sbostic 				while (is_digit(*f)) {
38647137Sbostic 					prec = 10 * prec + digit_val(*f++);
38747137Sbostic 				}
38847137Sbostic 			}
38947137Sbostic 		}
39047137Sbostic 		if (*f == 'l') {
39147137Sbostic 			islong++;
39247137Sbostic 			f++;
39347137Sbostic 		}
39447137Sbostic 		switch (*f) {
39547137Sbostic 		case 'd':
39647137Sbostic 			if (islong)
39747137Sbostic 				l = va_arg(ap, long);
39847137Sbostic 			else
39947137Sbostic 				l = va_arg(ap, int);
40047137Sbostic 			sign = 0;
40147137Sbostic 			num = l;
40247137Sbostic 			if (l < 0) {
40347137Sbostic 				num = -l;
40447137Sbostic 				sign = 1;
40547137Sbostic 			}
40647137Sbostic 			base = 10;
40747137Sbostic 			goto number;
40847137Sbostic 		case 'u':
40947137Sbostic 			base = 10;
41047137Sbostic 			goto uns_number;
41147137Sbostic 		case 'o':
41247137Sbostic 			base = 8;
41347137Sbostic 			goto uns_number;
41447137Sbostic 		case 'x':
41547137Sbostic 			/* we don't implement 'x'; treat like 'X' */
41647137Sbostic 		case 'X':
41747137Sbostic 			base = 16;
41847137Sbostic uns_number:	  /* an unsigned number */
41947137Sbostic 			sign = 0;
42047137Sbostic 			if (islong)
42147137Sbostic 				num = va_arg(ap, unsigned long);
42247137Sbostic 			else
42347137Sbostic 				num = va_arg(ap, unsigned int);
42447137Sbostic number:		  /* process a number */
42547137Sbostic 			p = temp + TEMPSIZE - 1;
42647137Sbostic 			*p = '\0';
42747137Sbostic 			while (num) {
42847137Sbostic 				*--p = digit[num % base];
42947137Sbostic 				num /= base;
43047137Sbostic 			}
43147137Sbostic 			len = (temp + TEMPSIZE - 1) - p;
43247137Sbostic 			if (prec < 0)
43347137Sbostic 				prec = 1;
43447137Sbostic 			if (sharp && *f == 'o' && prec <= len)
43547137Sbostic 				prec = len + 1;
43647137Sbostic 			pad = 0;
43747137Sbostic 			if (width) {
43847137Sbostic 				size = len;
43947137Sbostic 				if (size < prec)
44047137Sbostic 					size = prec;
44147137Sbostic 				size += sign;
44247137Sbostic 				pad = width - size;
44347137Sbostic 				if (flushleft == 0) {
44447137Sbostic 					while (--pad >= 0)
44547137Sbostic 						outc(' ', dest);
44647137Sbostic 				}
44747137Sbostic 			}
44847137Sbostic 			if (sign)
44947137Sbostic 				outc('-', dest);
45047137Sbostic 			prec -= len;
45147137Sbostic 			while (--prec >= 0)
45247137Sbostic 				outc('0', dest);
45347137Sbostic 			while (*p)
45447137Sbostic 				outc(*p++, dest);
45547137Sbostic 			while (--pad >= 0)
45647137Sbostic 				outc(' ', dest);
45747137Sbostic 			break;
45847137Sbostic 		case 's':
45947137Sbostic 			p = va_arg(ap, char *);
46047137Sbostic 			pad = 0;
46147137Sbostic 			if (width) {
46247137Sbostic 				len = strlen(p);
46347137Sbostic 				if (prec >= 0 && len > prec)
46447137Sbostic 					len = prec;
46547137Sbostic 				pad = width - len;
46647137Sbostic 				if (flushleft == 0) {
46747137Sbostic 					while (--pad >= 0)
46847137Sbostic 						outc(' ', dest);
46947137Sbostic 				}
47047137Sbostic 			}
47147137Sbostic 			prec++;
47247137Sbostic 			while (--prec != 0 && *p)
47347137Sbostic 				outc(*p++, dest);
47447137Sbostic 			while (--pad >= 0)
47547137Sbostic 				outc(' ', dest);
47647137Sbostic 			break;
47747137Sbostic 		case 'c':
47847137Sbostic 			c = va_arg(ap, int);
47947137Sbostic 			outc(c, dest);
48047137Sbostic 			break;
48147137Sbostic 		default:
48247137Sbostic 			outc(*f, dest);
48347137Sbostic 			break;
48447137Sbostic 		}
48547137Sbostic 		f++;
48647137Sbostic 	}
48747137Sbostic }
48847137Sbostic 
48947137Sbostic 
49047137Sbostic 
49147137Sbostic /*
49247137Sbostic  * Version of write which resumes after a signal is caught.
49347137Sbostic  */
49447137Sbostic 
49547137Sbostic int
xwrite(fd,buf,nbytes)49647137Sbostic xwrite(fd, buf, nbytes)
49747137Sbostic 	int fd;
49847137Sbostic 	char *buf;
49947137Sbostic 	int nbytes;
50047137Sbostic 	{
50147137Sbostic 	int ntry;
50247137Sbostic 	int i;
50347137Sbostic 	int n;
50447137Sbostic 
50547137Sbostic 	n = nbytes;
50647137Sbostic 	ntry = 0;
50747137Sbostic 	for (;;) {
50847137Sbostic 		i = write(fd, buf, n);
50947137Sbostic 		if (i > 0) {
51047137Sbostic 			if ((n -= i) <= 0)
51147137Sbostic 				return nbytes;
51247137Sbostic 			buf += i;
51347137Sbostic 			ntry = 0;
51447137Sbostic 		} else if (i == 0) {
51547137Sbostic 			if (++ntry > 10)
51647137Sbostic 				return nbytes - n;
51747137Sbostic 		} else if (errno != EINTR) {
51847137Sbostic 			return -1;
51947137Sbostic 		}
52047137Sbostic 	}
52147137Sbostic }
52247137Sbostic 
52347137Sbostic 
52447137Sbostic /*
52547137Sbostic  * Version of ioctl that retries after a signal is caught.
526*69272Schristos  * XXX unused function
52747137Sbostic  */
52847137Sbostic 
52947137Sbostic int
xioctl(fd,request,arg)530*69272Schristos xioctl(fd, request, arg)
531*69272Schristos 	int fd;
532*69272Schristos 	unsigned long request;
533*69272Schristos 	char * arg;
534*69272Schristos {
53547137Sbostic 	int i;
53647137Sbostic 
53747137Sbostic 	while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
53847137Sbostic 	return i;
53947137Sbostic }
540