147137Sbostic /*- 2*60698Sbostic * Copyright (c) 1991, 1993 3*60698Sbostic * 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*60698Sbostic static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 05/31/93"; 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 2647137Sbostic #include <stdio.h> /* defines BUFSIZ */ 2747137Sbostic #include "shell.h" 2847137Sbostic #include "syntax.h" 2947137Sbostic #include "output.h" 3047137Sbostic #include "memalloc.h" 3147137Sbostic #include "error.h" 3247137Sbostic #ifdef __STDC__ 3347137Sbostic #include "stdarg.h" 3447137Sbostic #else 3547137Sbostic #include <varargs.h> 3647137Sbostic #endif 3747137Sbostic #include <errno.h> 3847137Sbostic 3947137Sbostic 4047137Sbostic #define OUTBUFSIZ BUFSIZ 4147137Sbostic #define BLOCK_OUT -2 /* output to a fixed block of memory */ 4247137Sbostic #define MEM_OUT -3 /* output to dynamically allocated memory */ 4347137Sbostic #define OUTPUT_ERR 01 /* error occurred on output */ 4447137Sbostic 4547137Sbostic 4647137Sbostic struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 4747137Sbostic struct output errout = {NULL, 0, NULL, 100, 2, 0};; 4847137Sbostic struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 4947137Sbostic struct output *out1 = &output; 5047137Sbostic struct output *out2 = &errout; 5147137Sbostic 5247137Sbostic 5347137Sbostic 5447137Sbostic #ifdef mkinit 5547137Sbostic 5647137Sbostic INCLUDE "output.h" 5747137Sbostic INCLUDE "memalloc.h" 5847137Sbostic 5947137Sbostic RESET { 6047137Sbostic out1 = &output; 6147137Sbostic out2 = &errout; 6247137Sbostic if (memout.buf != NULL) { 6347137Sbostic ckfree(memout.buf); 6447137Sbostic memout.buf = NULL; 6547137Sbostic } 6647137Sbostic } 6747137Sbostic 6847137Sbostic #endif 6947137Sbostic 7047137Sbostic 7147137Sbostic #ifdef notdef /* no longer used */ 7247137Sbostic /* 7347137Sbostic * Set up an output file to write to memory rather than a file. 7447137Sbostic */ 7547137Sbostic 7647137Sbostic void 7747137Sbostic open_mem(block, length, file) 7847137Sbostic char *block; 7947137Sbostic int length; 8047137Sbostic struct output *file; 8147137Sbostic { 8247137Sbostic file->nextc = block; 8347137Sbostic file->nleft = --length; 8447137Sbostic file->fd = BLOCK_OUT; 8547137Sbostic file->flags = 0; 8647137Sbostic } 8747137Sbostic #endif 8847137Sbostic 8947137Sbostic 9047137Sbostic void 9147137Sbostic out1str(p) 9247137Sbostic char *p; 9347137Sbostic { 9447137Sbostic outstr(p, out1); 9547137Sbostic } 9647137Sbostic 9747137Sbostic 9847137Sbostic void 9947137Sbostic out2str(p) 10047137Sbostic char *p; 10147137Sbostic { 10247137Sbostic outstr(p, out2); 10347137Sbostic } 10447137Sbostic 10547137Sbostic 10647137Sbostic void 10747137Sbostic outstr(p, file) 10847137Sbostic register char *p; 10947137Sbostic register struct output *file; 11047137Sbostic { 11147137Sbostic while (*p) 11247137Sbostic outc(*p++, file); 11355228Smarc if (file == out2) 11455228Smarc flushout(file); 11547137Sbostic } 11647137Sbostic 11747137Sbostic 11847137Sbostic char out_junk[16]; 11947137Sbostic 12047137Sbostic 12147137Sbostic void 12247137Sbostic emptyoutbuf(dest) 12347137Sbostic struct output *dest; 12447137Sbostic { 12547137Sbostic int offset; 12647137Sbostic 12747137Sbostic if (dest->fd == BLOCK_OUT) { 12847137Sbostic dest->nextc = out_junk; 12947137Sbostic dest->nleft = sizeof out_junk; 13047137Sbostic dest->flags |= OUTPUT_ERR; 13147137Sbostic } else if (dest->buf == NULL) { 13247137Sbostic INTOFF; 13347137Sbostic dest->buf = ckmalloc(dest->bufsize); 13447137Sbostic dest->nextc = dest->buf; 13547137Sbostic dest->nleft = dest->bufsize; 13647137Sbostic INTON; 13747137Sbostic } else if (dest->fd == MEM_OUT) { 13847137Sbostic offset = dest->bufsize; 13947137Sbostic INTOFF; 14047137Sbostic dest->bufsize <<= 1; 14147137Sbostic dest->buf = ckrealloc(dest->buf, dest->bufsize); 14247137Sbostic dest->nleft = dest->bufsize - offset; 14347137Sbostic dest->nextc = dest->buf + offset; 14447137Sbostic INTON; 14547137Sbostic } else { 14647137Sbostic flushout(dest); 14747137Sbostic } 14847137Sbostic dest->nleft--; 14947137Sbostic } 15047137Sbostic 15147137Sbostic 15247137Sbostic void 15347137Sbostic flushall() { 15447137Sbostic flushout(&output); 15547137Sbostic flushout(&errout); 15647137Sbostic } 15747137Sbostic 15847137Sbostic 15947137Sbostic void 16047137Sbostic flushout(dest) 16147137Sbostic struct output *dest; 16247137Sbostic { 16347137Sbostic 16447137Sbostic if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 16547137Sbostic return; 16647137Sbostic if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 16747137Sbostic dest->flags |= OUTPUT_ERR; 16847137Sbostic dest->nextc = dest->buf; 16947137Sbostic dest->nleft = dest->bufsize; 17047137Sbostic } 17147137Sbostic 17247137Sbostic 17347137Sbostic void 17447137Sbostic freestdout() { 17547137Sbostic INTOFF; 17647137Sbostic if (output.buf) { 17747137Sbostic ckfree(output.buf); 17847137Sbostic output.buf = NULL; 17947137Sbostic output.nleft = 0; 18047137Sbostic } 18147137Sbostic INTON; 18247137Sbostic } 18347137Sbostic 18447137Sbostic 18547137Sbostic #ifdef __STDC__ 18647137Sbostic void 18747137Sbostic outfmt(struct output *file, char *fmt, ...) { 18847137Sbostic va_list ap; 18947137Sbostic 19047137Sbostic va_start(ap, fmt); 19147137Sbostic doformat(file, fmt, ap); 19247137Sbostic va_end(ap); 19347137Sbostic } 19447137Sbostic 19547137Sbostic 19647137Sbostic void 19747137Sbostic out1fmt(char *fmt, ...) { 19847137Sbostic va_list ap; 19947137Sbostic 20047137Sbostic va_start(ap, fmt); 20147137Sbostic doformat(out1, fmt, ap); 20247137Sbostic va_end(ap); 20347137Sbostic } 20447137Sbostic 20554324Smarc void 20654324Smarc dprintf(char *fmt, ...) { 20754324Smarc va_list ap; 20847137Sbostic 20954324Smarc va_start(ap, fmt); 21054324Smarc doformat(out2, fmt, ap); 21154324Smarc va_end(ap); 21254324Smarc flushout(out2); 21354324Smarc } 21454324Smarc 21547137Sbostic void 21647137Sbostic fmtstr(char *outbuf, int length, char *fmt, ...) { 21747137Sbostic va_list ap; 21847137Sbostic struct output strout; 21947137Sbostic 22047137Sbostic va_start(ap, fmt); 22147137Sbostic strout.nextc = outbuf; 22247137Sbostic strout.nleft = length; 22347137Sbostic strout.fd = BLOCK_OUT; 22447137Sbostic strout.flags = 0; 22547137Sbostic doformat(&strout, fmt, ap); 22647137Sbostic outc('\0', &strout); 22747137Sbostic if (strout.flags & OUTPUT_ERR) 22847137Sbostic outbuf[length - 1] = '\0'; 22947137Sbostic } 23047137Sbostic 23147137Sbostic #else /* not __STDC__ */ 23247137Sbostic 23347137Sbostic void 23447137Sbostic outfmt(va_alist) 23547137Sbostic va_dcl 23647137Sbostic { 23747137Sbostic va_list ap; 23847137Sbostic struct output *file; 23947137Sbostic char *fmt; 24047137Sbostic 24147137Sbostic va_start(ap); 24247137Sbostic file = va_arg(ap, struct output *); 24347137Sbostic fmt = va_arg(ap, char *); 24447137Sbostic doformat(file, fmt, ap); 24547137Sbostic va_end(ap); 24647137Sbostic } 24747137Sbostic 24847137Sbostic 24947137Sbostic void 25047137Sbostic out1fmt(va_alist) 25147137Sbostic va_dcl 25247137Sbostic { 25347137Sbostic va_list ap; 25447137Sbostic char *fmt; 25547137Sbostic 25647137Sbostic va_start(ap); 25747137Sbostic fmt = va_arg(ap, char *); 25847137Sbostic doformat(out1, fmt, ap); 25947137Sbostic va_end(ap); 26047137Sbostic } 26147137Sbostic 26254324Smarc void 26354324Smarc dprintf(va_alist) 26454324Smarc va_dcl 26554324Smarc { 26654324Smarc va_list ap; 26754324Smarc char *fmt; 26847137Sbostic 26954324Smarc va_start(ap); 27054324Smarc fmt = va_arg(ap, char *); 27154324Smarc doformat(out2, fmt, ap); 27254324Smarc va_end(ap); 27354324Smarc flushout(out2); 27454324Smarc } 27554324Smarc 27647137Sbostic void 27747137Sbostic fmtstr(va_alist) 27847137Sbostic va_dcl 27947137Sbostic { 28047137Sbostic va_list ap; 28147137Sbostic struct output strout; 28247137Sbostic char *outbuf; 28347137Sbostic int length; 28447137Sbostic char *fmt; 28547137Sbostic 28647137Sbostic va_start(ap); 28747137Sbostic outbuf = va_arg(ap, char *); 28847137Sbostic length = va_arg(ap, int); 28947137Sbostic fmt = va_arg(ap, char *); 29047137Sbostic strout.nextc = outbuf; 29147137Sbostic strout.nleft = length; 29247137Sbostic strout.fd = BLOCK_OUT; 29347137Sbostic strout.flags = 0; 29447137Sbostic doformat(&strout, fmt, ap); 29547137Sbostic outc('\0', &strout); 29647137Sbostic if (strout.flags & OUTPUT_ERR) 29747137Sbostic outbuf[length - 1] = '\0'; 29847137Sbostic } 29947137Sbostic #endif /* __STDC__ */ 30047137Sbostic 30147137Sbostic 30247137Sbostic /* 30347137Sbostic * Formatted output. This routine handles a subset of the printf formats: 30447137Sbostic * - Formats supported: d, u, o, X, s, and c. 30547137Sbostic * - The x format is also accepted but is treated like X. 30647137Sbostic * - The l modifier is accepted. 30747137Sbostic * - The - and # flags are accepted; # only works with the o format. 30847137Sbostic * - Width and precision may be specified with any format except c. 30947137Sbostic * - An * may be given for the width or precision. 31047137Sbostic * - The obsolete practice of preceding the width with a zero to get 31147137Sbostic * zero padding is not supported; use the precision field. 31247137Sbostic * - A % may be printed by writing %% in the format string. 31347137Sbostic */ 31447137Sbostic 31547137Sbostic #define TEMPSIZE 24 31647137Sbostic 31747137Sbostic #ifdef __STDC__ 31847137Sbostic static const char digit[16] = "0123456789ABCDEF"; 31947137Sbostic #else 32047137Sbostic static const char digit[17] = "0123456789ABCDEF"; 32147137Sbostic #endif 32247137Sbostic 32347137Sbostic 32447137Sbostic void 32547137Sbostic doformat(dest, f, ap) 32647137Sbostic register struct output *dest; 32747137Sbostic register char *f; /* format string */ 32847137Sbostic va_list ap; 32947137Sbostic { 33047137Sbostic register char c; 33147137Sbostic char temp[TEMPSIZE]; 33247137Sbostic int flushleft; 33347137Sbostic int sharp; 33447137Sbostic int width; 33547137Sbostic int prec; 33647137Sbostic int islong; 33747137Sbostic char *p; 33847137Sbostic int sign; 33947137Sbostic long l; 34047137Sbostic unsigned long num; 34147137Sbostic unsigned base; 34247137Sbostic int len; 34347137Sbostic int size; 34447137Sbostic int pad; 34547137Sbostic 34647137Sbostic while ((c = *f++) != '\0') { 34747137Sbostic if (c != '%') { 34847137Sbostic outc(c, dest); 34947137Sbostic continue; 35047137Sbostic } 35147137Sbostic flushleft = 0; 35247137Sbostic sharp = 0; 35347137Sbostic width = 0; 35447137Sbostic prec = -1; 35547137Sbostic islong = 0; 35647137Sbostic for (;;) { 35747137Sbostic if (*f == '-') 35847137Sbostic flushleft++; 35947137Sbostic else if (*f == '#') 36047137Sbostic sharp++; 36147137Sbostic else 36247137Sbostic break; 36347137Sbostic f++; 36447137Sbostic } 36547137Sbostic if (*f == '*') { 36647137Sbostic width = va_arg(ap, int); 36747137Sbostic f++; 36847137Sbostic } else { 36947137Sbostic while (is_digit(*f)) { 37047137Sbostic width = 10 * width + digit_val(*f++); 37147137Sbostic } 37247137Sbostic } 37347137Sbostic if (*f == '.') { 37447137Sbostic if (*++f == '*') { 37547137Sbostic prec = va_arg(ap, int); 37647137Sbostic f++; 37747137Sbostic } else { 37847137Sbostic prec = 0; 37947137Sbostic while (is_digit(*f)) { 38047137Sbostic prec = 10 * prec + digit_val(*f++); 38147137Sbostic } 38247137Sbostic } 38347137Sbostic } 38447137Sbostic if (*f == 'l') { 38547137Sbostic islong++; 38647137Sbostic f++; 38747137Sbostic } 38847137Sbostic switch (*f) { 38947137Sbostic case 'd': 39047137Sbostic if (islong) 39147137Sbostic l = va_arg(ap, long); 39247137Sbostic else 39347137Sbostic l = va_arg(ap, int); 39447137Sbostic sign = 0; 39547137Sbostic num = l; 39647137Sbostic if (l < 0) { 39747137Sbostic num = -l; 39847137Sbostic sign = 1; 39947137Sbostic } 40047137Sbostic base = 10; 40147137Sbostic goto number; 40247137Sbostic case 'u': 40347137Sbostic base = 10; 40447137Sbostic goto uns_number; 40547137Sbostic case 'o': 40647137Sbostic base = 8; 40747137Sbostic goto uns_number; 40847137Sbostic case 'x': 40947137Sbostic /* we don't implement 'x'; treat like 'X' */ 41047137Sbostic case 'X': 41147137Sbostic base = 16; 41247137Sbostic uns_number: /* an unsigned number */ 41347137Sbostic sign = 0; 41447137Sbostic if (islong) 41547137Sbostic num = va_arg(ap, unsigned long); 41647137Sbostic else 41747137Sbostic num = va_arg(ap, unsigned int); 41847137Sbostic number: /* process a number */ 41947137Sbostic p = temp + TEMPSIZE - 1; 42047137Sbostic *p = '\0'; 42147137Sbostic while (num) { 42247137Sbostic *--p = digit[num % base]; 42347137Sbostic num /= base; 42447137Sbostic } 42547137Sbostic len = (temp + TEMPSIZE - 1) - p; 42647137Sbostic if (prec < 0) 42747137Sbostic prec = 1; 42847137Sbostic if (sharp && *f == 'o' && prec <= len) 42947137Sbostic prec = len + 1; 43047137Sbostic pad = 0; 43147137Sbostic if (width) { 43247137Sbostic size = len; 43347137Sbostic if (size < prec) 43447137Sbostic size = prec; 43547137Sbostic size += sign; 43647137Sbostic pad = width - size; 43747137Sbostic if (flushleft == 0) { 43847137Sbostic while (--pad >= 0) 43947137Sbostic outc(' ', dest); 44047137Sbostic } 44147137Sbostic } 44247137Sbostic if (sign) 44347137Sbostic outc('-', dest); 44447137Sbostic prec -= len; 44547137Sbostic while (--prec >= 0) 44647137Sbostic outc('0', dest); 44747137Sbostic while (*p) 44847137Sbostic outc(*p++, dest); 44947137Sbostic while (--pad >= 0) 45047137Sbostic outc(' ', dest); 45147137Sbostic break; 45247137Sbostic case 's': 45347137Sbostic p = va_arg(ap, char *); 45447137Sbostic pad = 0; 45547137Sbostic if (width) { 45647137Sbostic len = strlen(p); 45747137Sbostic if (prec >= 0 && len > prec) 45847137Sbostic len = prec; 45947137Sbostic pad = width - len; 46047137Sbostic if (flushleft == 0) { 46147137Sbostic while (--pad >= 0) 46247137Sbostic outc(' ', dest); 46347137Sbostic } 46447137Sbostic } 46547137Sbostic prec++; 46647137Sbostic while (--prec != 0 && *p) 46747137Sbostic outc(*p++, dest); 46847137Sbostic while (--pad >= 0) 46947137Sbostic outc(' ', dest); 47047137Sbostic break; 47147137Sbostic case 'c': 47247137Sbostic c = va_arg(ap, int); 47347137Sbostic outc(c, dest); 47447137Sbostic break; 47547137Sbostic default: 47647137Sbostic outc(*f, dest); 47747137Sbostic break; 47847137Sbostic } 47947137Sbostic f++; 48047137Sbostic } 48147137Sbostic } 48247137Sbostic 48347137Sbostic 48447137Sbostic 48547137Sbostic /* 48647137Sbostic * Version of write which resumes after a signal is caught. 48747137Sbostic */ 48847137Sbostic 48947137Sbostic int 49047137Sbostic xwrite(fd, buf, nbytes) 49147137Sbostic int fd; 49247137Sbostic char *buf; 49347137Sbostic int nbytes; 49447137Sbostic { 49547137Sbostic int ntry; 49647137Sbostic int i; 49747137Sbostic int n; 49847137Sbostic 49947137Sbostic n = nbytes; 50047137Sbostic ntry = 0; 50147137Sbostic for (;;) { 50247137Sbostic i = write(fd, buf, n); 50347137Sbostic if (i > 0) { 50447137Sbostic if ((n -= i) <= 0) 50547137Sbostic return nbytes; 50647137Sbostic buf += i; 50747137Sbostic ntry = 0; 50847137Sbostic } else if (i == 0) { 50947137Sbostic if (++ntry > 10) 51047137Sbostic return nbytes - n; 51147137Sbostic } else if (errno != EINTR) { 51247137Sbostic return -1; 51347137Sbostic } 51447137Sbostic } 51547137Sbostic } 51647137Sbostic 51747137Sbostic 51847137Sbostic /* 51947137Sbostic * Version of ioctl that retries after a signal is caught. 52047137Sbostic */ 52147137Sbostic 52247137Sbostic int 52347137Sbostic xioctl(fd, request, arg) { 52447137Sbostic int i; 52547137Sbostic 52647137Sbostic while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 52747137Sbostic return i; 52847137Sbostic } 529