output.c revision 1556
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 371556Srgrimes#ifndef lint 381556Srgrimesstatic char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93"; 391556Srgrimes#endif /* not lint */ 401556Srgrimes 411556Srgrimes/* 421556Srgrimes * Shell output routines. We use our own output routines because: 431556Srgrimes * When a builtin command is interrupted we have to discard 441556Srgrimes * any pending output. 451556Srgrimes * When a builtin command appears in back quotes, we want to 461556Srgrimes * save the output of the command in a region obtained 471556Srgrimes * via malloc, rather than doing a fork and reading the 481556Srgrimes * output of the command via a pipe. 491556Srgrimes * Our output routines may be smaller than the stdio routines. 501556Srgrimes */ 511556Srgrimes 521556Srgrimes#include <stdio.h> /* defines BUFSIZ */ 531556Srgrimes#include "shell.h" 541556Srgrimes#include "syntax.h" 551556Srgrimes#include "output.h" 561556Srgrimes#include "memalloc.h" 571556Srgrimes#include "error.h" 581556Srgrimes#ifdef __STDC__ 591556Srgrimes#include "stdarg.h" 601556Srgrimes#else 611556Srgrimes#include <varargs.h> 621556Srgrimes#endif 631556Srgrimes#include <errno.h> 641556Srgrimes 651556Srgrimes 661556Srgrimes#define OUTBUFSIZ BUFSIZ 671556Srgrimes#define BLOCK_OUT -2 /* output to a fixed block of memory */ 681556Srgrimes#define MEM_OUT -3 /* output to dynamically allocated memory */ 691556Srgrimes#define OUTPUT_ERR 01 /* error occurred on output */ 701556Srgrimes 711556Srgrimes 721556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 731556Srgrimesstruct output errout = {NULL, 0, NULL, 100, 2, 0};; 741556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 751556Srgrimesstruct output *out1 = &output; 761556Srgrimesstruct output *out2 = &errout; 771556Srgrimes 781556Srgrimes 791556Srgrimes 801556Srgrimes#ifdef mkinit 811556Srgrimes 821556SrgrimesINCLUDE "output.h" 831556SrgrimesINCLUDE "memalloc.h" 841556Srgrimes 851556SrgrimesRESET { 861556Srgrimes out1 = &output; 871556Srgrimes out2 = &errout; 881556Srgrimes if (memout.buf != NULL) { 891556Srgrimes ckfree(memout.buf); 901556Srgrimes memout.buf = NULL; 911556Srgrimes } 921556Srgrimes} 931556Srgrimes 941556Srgrimes#endif 951556Srgrimes 961556Srgrimes 971556Srgrimes#ifdef notdef /* no longer used */ 981556Srgrimes/* 991556Srgrimes * Set up an output file to write to memory rather than a file. 1001556Srgrimes */ 1011556Srgrimes 1021556Srgrimesvoid 1031556Srgrimesopen_mem(block, length, file) 1041556Srgrimes char *block; 1051556Srgrimes int length; 1061556Srgrimes struct output *file; 1071556Srgrimes { 1081556Srgrimes file->nextc = block; 1091556Srgrimes file->nleft = --length; 1101556Srgrimes file->fd = BLOCK_OUT; 1111556Srgrimes file->flags = 0; 1121556Srgrimes} 1131556Srgrimes#endif 1141556Srgrimes 1151556Srgrimes 1161556Srgrimesvoid 1171556Srgrimesout1str(p) 1181556Srgrimes char *p; 1191556Srgrimes { 1201556Srgrimes outstr(p, out1); 1211556Srgrimes} 1221556Srgrimes 1231556Srgrimes 1241556Srgrimesvoid 1251556Srgrimesout2str(p) 1261556Srgrimes char *p; 1271556Srgrimes { 1281556Srgrimes outstr(p, out2); 1291556Srgrimes} 1301556Srgrimes 1311556Srgrimes 1321556Srgrimesvoid 1331556Srgrimesoutstr(p, file) 1341556Srgrimes register char *p; 1351556Srgrimes register struct output *file; 1361556Srgrimes { 1371556Srgrimes while (*p) 1381556Srgrimes outc(*p++, file); 1391556Srgrimes if (file == out2) 1401556Srgrimes flushout(file); 1411556Srgrimes} 1421556Srgrimes 1431556Srgrimes 1441556Srgrimeschar out_junk[16]; 1451556Srgrimes 1461556Srgrimes 1471556Srgrimesvoid 1481556Srgrimesemptyoutbuf(dest) 1491556Srgrimes struct output *dest; 1501556Srgrimes { 1511556Srgrimes int offset; 1521556Srgrimes 1531556Srgrimes if (dest->fd == BLOCK_OUT) { 1541556Srgrimes dest->nextc = out_junk; 1551556Srgrimes dest->nleft = sizeof out_junk; 1561556Srgrimes dest->flags |= OUTPUT_ERR; 1571556Srgrimes } else if (dest->buf == NULL) { 1581556Srgrimes INTOFF; 1591556Srgrimes dest->buf = ckmalloc(dest->bufsize); 1601556Srgrimes dest->nextc = dest->buf; 1611556Srgrimes dest->nleft = dest->bufsize; 1621556Srgrimes INTON; 1631556Srgrimes } else if (dest->fd == MEM_OUT) { 1641556Srgrimes offset = dest->bufsize; 1651556Srgrimes INTOFF; 1661556Srgrimes dest->bufsize <<= 1; 1671556Srgrimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 1681556Srgrimes dest->nleft = dest->bufsize - offset; 1691556Srgrimes dest->nextc = dest->buf + offset; 1701556Srgrimes INTON; 1711556Srgrimes } else { 1721556Srgrimes flushout(dest); 1731556Srgrimes } 1741556Srgrimes dest->nleft--; 1751556Srgrimes} 1761556Srgrimes 1771556Srgrimes 1781556Srgrimesvoid 1791556Srgrimesflushall() { 1801556Srgrimes flushout(&output); 1811556Srgrimes flushout(&errout); 1821556Srgrimes} 1831556Srgrimes 1841556Srgrimes 1851556Srgrimesvoid 1861556Srgrimesflushout(dest) 1871556Srgrimes struct output *dest; 1881556Srgrimes { 1891556Srgrimes 1901556Srgrimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 1911556Srgrimes return; 1921556Srgrimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 1931556Srgrimes dest->flags |= OUTPUT_ERR; 1941556Srgrimes dest->nextc = dest->buf; 1951556Srgrimes dest->nleft = dest->bufsize; 1961556Srgrimes} 1971556Srgrimes 1981556Srgrimes 1991556Srgrimesvoid 2001556Srgrimesfreestdout() { 2011556Srgrimes INTOFF; 2021556Srgrimes if (output.buf) { 2031556Srgrimes ckfree(output.buf); 2041556Srgrimes output.buf = NULL; 2051556Srgrimes output.nleft = 0; 2061556Srgrimes } 2071556Srgrimes INTON; 2081556Srgrimes} 2091556Srgrimes 2101556Srgrimes 2111556Srgrimes#ifdef __STDC__ 2121556Srgrimesvoid 2131556Srgrimesoutfmt(struct output *file, char *fmt, ...) { 2141556Srgrimes va_list ap; 2151556Srgrimes 2161556Srgrimes va_start(ap, fmt); 2171556Srgrimes doformat(file, fmt, ap); 2181556Srgrimes va_end(ap); 2191556Srgrimes} 2201556Srgrimes 2211556Srgrimes 2221556Srgrimesvoid 2231556Srgrimesout1fmt(char *fmt, ...) { 2241556Srgrimes va_list ap; 2251556Srgrimes 2261556Srgrimes va_start(ap, fmt); 2271556Srgrimes doformat(out1, fmt, ap); 2281556Srgrimes va_end(ap); 2291556Srgrimes} 2301556Srgrimes 2311556Srgrimesvoid 2321556Srgrimesdprintf(char *fmt, ...) { 2331556Srgrimes va_list ap; 2341556Srgrimes 2351556Srgrimes va_start(ap, fmt); 2361556Srgrimes doformat(out2, fmt, ap); 2371556Srgrimes va_end(ap); 2381556Srgrimes flushout(out2); 2391556Srgrimes} 2401556Srgrimes 2411556Srgrimesvoid 2421556Srgrimesfmtstr(char *outbuf, int length, char *fmt, ...) { 2431556Srgrimes va_list ap; 2441556Srgrimes struct output strout; 2451556Srgrimes 2461556Srgrimes va_start(ap, fmt); 2471556Srgrimes strout.nextc = outbuf; 2481556Srgrimes strout.nleft = length; 2491556Srgrimes strout.fd = BLOCK_OUT; 2501556Srgrimes strout.flags = 0; 2511556Srgrimes doformat(&strout, fmt, ap); 2521556Srgrimes outc('\0', &strout); 2531556Srgrimes if (strout.flags & OUTPUT_ERR) 2541556Srgrimes outbuf[length - 1] = '\0'; 2551556Srgrimes} 2561556Srgrimes 2571556Srgrimes#else /* not __STDC__ */ 2581556Srgrimes 2591556Srgrimesvoid 2601556Srgrimesoutfmt(va_alist) 2611556Srgrimes va_dcl 2621556Srgrimes { 2631556Srgrimes va_list ap; 2641556Srgrimes struct output *file; 2651556Srgrimes char *fmt; 2661556Srgrimes 2671556Srgrimes va_start(ap); 2681556Srgrimes file = va_arg(ap, struct output *); 2691556Srgrimes fmt = va_arg(ap, char *); 2701556Srgrimes doformat(file, fmt, ap); 2711556Srgrimes va_end(ap); 2721556Srgrimes} 2731556Srgrimes 2741556Srgrimes 2751556Srgrimesvoid 2761556Srgrimesout1fmt(va_alist) 2771556Srgrimes va_dcl 2781556Srgrimes { 2791556Srgrimes va_list ap; 2801556Srgrimes char *fmt; 2811556Srgrimes 2821556Srgrimes va_start(ap); 2831556Srgrimes fmt = va_arg(ap, char *); 2841556Srgrimes doformat(out1, fmt, ap); 2851556Srgrimes va_end(ap); 2861556Srgrimes} 2871556Srgrimes 2881556Srgrimesvoid 2891556Srgrimesdprintf(va_alist) 2901556Srgrimes va_dcl 2911556Srgrimes { 2921556Srgrimes va_list ap; 2931556Srgrimes char *fmt; 2941556Srgrimes 2951556Srgrimes va_start(ap); 2961556Srgrimes fmt = va_arg(ap, char *); 2971556Srgrimes doformat(out2, fmt, ap); 2981556Srgrimes va_end(ap); 2991556Srgrimes flushout(out2); 3001556Srgrimes} 3011556Srgrimes 3021556Srgrimesvoid 3031556Srgrimesfmtstr(va_alist) 3041556Srgrimes va_dcl 3051556Srgrimes { 3061556Srgrimes va_list ap; 3071556Srgrimes struct output strout; 3081556Srgrimes char *outbuf; 3091556Srgrimes int length; 3101556Srgrimes char *fmt; 3111556Srgrimes 3121556Srgrimes va_start(ap); 3131556Srgrimes outbuf = va_arg(ap, char *); 3141556Srgrimes length = va_arg(ap, int); 3151556Srgrimes fmt = va_arg(ap, char *); 3161556Srgrimes strout.nextc = outbuf; 3171556Srgrimes strout.nleft = length; 3181556Srgrimes strout.fd = BLOCK_OUT; 3191556Srgrimes strout.flags = 0; 3201556Srgrimes doformat(&strout, fmt, ap); 3211556Srgrimes outc('\0', &strout); 3221556Srgrimes if (strout.flags & OUTPUT_ERR) 3231556Srgrimes outbuf[length - 1] = '\0'; 3241556Srgrimes} 3251556Srgrimes#endif /* __STDC__ */ 3261556Srgrimes 3271556Srgrimes 3281556Srgrimes/* 3291556Srgrimes * Formatted output. This routine handles a subset of the printf formats: 3301556Srgrimes * - Formats supported: d, u, o, X, s, and c. 3311556Srgrimes * - The x format is also accepted but is treated like X. 3321556Srgrimes * - The l modifier is accepted. 3331556Srgrimes * - The - and # flags are accepted; # only works with the o format. 3341556Srgrimes * - Width and precision may be specified with any format except c. 3351556Srgrimes * - An * may be given for the width or precision. 3361556Srgrimes * - The obsolete practice of preceding the width with a zero to get 3371556Srgrimes * zero padding is not supported; use the precision field. 3381556Srgrimes * - A % may be printed by writing %% in the format string. 3391556Srgrimes */ 3401556Srgrimes 3411556Srgrimes#define TEMPSIZE 24 3421556Srgrimes 3431556Srgrimes#ifdef __STDC__ 3441556Srgrimesstatic const char digit[16] = "0123456789ABCDEF"; 3451556Srgrimes#else 3461556Srgrimesstatic const char digit[17] = "0123456789ABCDEF"; 3471556Srgrimes#endif 3481556Srgrimes 3491556Srgrimes 3501556Srgrimesvoid 3511556Srgrimesdoformat(dest, f, ap) 3521556Srgrimes register struct output *dest; 3531556Srgrimes register char *f; /* format string */ 3541556Srgrimes va_list ap; 3551556Srgrimes { 3561556Srgrimes register char c; 3571556Srgrimes char temp[TEMPSIZE]; 3581556Srgrimes int flushleft; 3591556Srgrimes int sharp; 3601556Srgrimes int width; 3611556Srgrimes int prec; 3621556Srgrimes int islong; 3631556Srgrimes char *p; 3641556Srgrimes int sign; 3651556Srgrimes long l; 3661556Srgrimes unsigned long num; 3671556Srgrimes unsigned base; 3681556Srgrimes int len; 3691556Srgrimes int size; 3701556Srgrimes int pad; 3711556Srgrimes 3721556Srgrimes while ((c = *f++) != '\0') { 3731556Srgrimes if (c != '%') { 3741556Srgrimes outc(c, dest); 3751556Srgrimes continue; 3761556Srgrimes } 3771556Srgrimes flushleft = 0; 3781556Srgrimes sharp = 0; 3791556Srgrimes width = 0; 3801556Srgrimes prec = -1; 3811556Srgrimes islong = 0; 3821556Srgrimes for (;;) { 3831556Srgrimes if (*f == '-') 3841556Srgrimes flushleft++; 3851556Srgrimes else if (*f == '#') 3861556Srgrimes sharp++; 3871556Srgrimes else 3881556Srgrimes break; 3891556Srgrimes f++; 3901556Srgrimes } 3911556Srgrimes if (*f == '*') { 3921556Srgrimes width = va_arg(ap, int); 3931556Srgrimes f++; 3941556Srgrimes } else { 3951556Srgrimes while (is_digit(*f)) { 3961556Srgrimes width = 10 * width + digit_val(*f++); 3971556Srgrimes } 3981556Srgrimes } 3991556Srgrimes if (*f == '.') { 4001556Srgrimes if (*++f == '*') { 4011556Srgrimes prec = va_arg(ap, int); 4021556Srgrimes f++; 4031556Srgrimes } else { 4041556Srgrimes prec = 0; 4051556Srgrimes while (is_digit(*f)) { 4061556Srgrimes prec = 10 * prec + digit_val(*f++); 4071556Srgrimes } 4081556Srgrimes } 4091556Srgrimes } 4101556Srgrimes if (*f == 'l') { 4111556Srgrimes islong++; 4121556Srgrimes f++; 4131556Srgrimes } 4141556Srgrimes switch (*f) { 4151556Srgrimes case 'd': 4161556Srgrimes if (islong) 4171556Srgrimes l = va_arg(ap, long); 4181556Srgrimes else 4191556Srgrimes l = va_arg(ap, int); 4201556Srgrimes sign = 0; 4211556Srgrimes num = l; 4221556Srgrimes if (l < 0) { 4231556Srgrimes num = -l; 4241556Srgrimes sign = 1; 4251556Srgrimes } 4261556Srgrimes base = 10; 4271556Srgrimes goto number; 4281556Srgrimes case 'u': 4291556Srgrimes base = 10; 4301556Srgrimes goto uns_number; 4311556Srgrimes case 'o': 4321556Srgrimes base = 8; 4331556Srgrimes goto uns_number; 4341556Srgrimes case 'x': 4351556Srgrimes /* we don't implement 'x'; treat like 'X' */ 4361556Srgrimes case 'X': 4371556Srgrimes base = 16; 4381556Srgrimesuns_number: /* an unsigned number */ 4391556Srgrimes sign = 0; 4401556Srgrimes if (islong) 4411556Srgrimes num = va_arg(ap, unsigned long); 4421556Srgrimes else 4431556Srgrimes num = va_arg(ap, unsigned int); 4441556Srgrimesnumber: /* process a number */ 4451556Srgrimes p = temp + TEMPSIZE - 1; 4461556Srgrimes *p = '\0'; 4471556Srgrimes while (num) { 4481556Srgrimes *--p = digit[num % base]; 4491556Srgrimes num /= base; 4501556Srgrimes } 4511556Srgrimes len = (temp + TEMPSIZE - 1) - p; 4521556Srgrimes if (prec < 0) 4531556Srgrimes prec = 1; 4541556Srgrimes if (sharp && *f == 'o' && prec <= len) 4551556Srgrimes prec = len + 1; 4561556Srgrimes pad = 0; 4571556Srgrimes if (width) { 4581556Srgrimes size = len; 4591556Srgrimes if (size < prec) 4601556Srgrimes size = prec; 4611556Srgrimes size += sign; 4621556Srgrimes pad = width - size; 4631556Srgrimes if (flushleft == 0) { 4641556Srgrimes while (--pad >= 0) 4651556Srgrimes outc(' ', dest); 4661556Srgrimes } 4671556Srgrimes } 4681556Srgrimes if (sign) 4691556Srgrimes outc('-', dest); 4701556Srgrimes prec -= len; 4711556Srgrimes while (--prec >= 0) 4721556Srgrimes outc('0', dest); 4731556Srgrimes while (*p) 4741556Srgrimes outc(*p++, dest); 4751556Srgrimes while (--pad >= 0) 4761556Srgrimes outc(' ', dest); 4771556Srgrimes break; 4781556Srgrimes case 's': 4791556Srgrimes p = va_arg(ap, char *); 4801556Srgrimes pad = 0; 4811556Srgrimes if (width) { 4821556Srgrimes len = strlen(p); 4831556Srgrimes if (prec >= 0 && len > prec) 4841556Srgrimes len = prec; 4851556Srgrimes pad = width - len; 4861556Srgrimes if (flushleft == 0) { 4871556Srgrimes while (--pad >= 0) 4881556Srgrimes outc(' ', dest); 4891556Srgrimes } 4901556Srgrimes } 4911556Srgrimes prec++; 4921556Srgrimes while (--prec != 0 && *p) 4931556Srgrimes outc(*p++, dest); 4941556Srgrimes while (--pad >= 0) 4951556Srgrimes outc(' ', dest); 4961556Srgrimes break; 4971556Srgrimes case 'c': 4981556Srgrimes c = va_arg(ap, int); 4991556Srgrimes outc(c, dest); 5001556Srgrimes break; 5011556Srgrimes default: 5021556Srgrimes outc(*f, dest); 5031556Srgrimes break; 5041556Srgrimes } 5051556Srgrimes f++; 5061556Srgrimes } 5071556Srgrimes} 5081556Srgrimes 5091556Srgrimes 5101556Srgrimes 5111556Srgrimes/* 5121556Srgrimes * Version of write which resumes after a signal is caught. 5131556Srgrimes */ 5141556Srgrimes 5151556Srgrimesint 5161556Srgrimesxwrite(fd, buf, nbytes) 5171556Srgrimes int fd; 5181556Srgrimes char *buf; 5191556Srgrimes int nbytes; 5201556Srgrimes { 5211556Srgrimes int ntry; 5221556Srgrimes int i; 5231556Srgrimes int n; 5241556Srgrimes 5251556Srgrimes n = nbytes; 5261556Srgrimes ntry = 0; 5271556Srgrimes for (;;) { 5281556Srgrimes i = write(fd, buf, n); 5291556Srgrimes if (i > 0) { 5301556Srgrimes if ((n -= i) <= 0) 5311556Srgrimes return nbytes; 5321556Srgrimes buf += i; 5331556Srgrimes ntry = 0; 5341556Srgrimes } else if (i == 0) { 5351556Srgrimes if (++ntry > 10) 5361556Srgrimes return nbytes - n; 5371556Srgrimes } else if (errno != EINTR) { 5381556Srgrimes return -1; 5391556Srgrimes } 5401556Srgrimes } 5411556Srgrimes} 5421556Srgrimes 5431556Srgrimes 5441556Srgrimes/* 5451556Srgrimes * Version of ioctl that retries after a signal is caught. 5461556Srgrimes */ 5471556Srgrimes 5481556Srgrimesint 5491556Srgrimesxioctl(fd, request, arg) { 5501556Srgrimes int i; 5511556Srgrimes 5521556Srgrimes while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 5531556Srgrimes return i; 5541556Srgrimes} 555