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