output.c revision 17987
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. 353044Sdg * 3617987Speter * $Id: output.c,v 1.2 1994/09/24 02:58:06 davidg Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 4017987Speterstatic char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 411556Srgrimes#endif /* not lint */ 421556Srgrimes 431556Srgrimes/* 441556Srgrimes * Shell output routines. We use our own output routines because: 451556Srgrimes * When a builtin command is interrupted we have to discard 461556Srgrimes * any pending output. 471556Srgrimes * When a builtin command appears in back quotes, we want to 481556Srgrimes * save the output of the command in a region obtained 491556Srgrimes * via malloc, rather than doing a fork and reading the 501556Srgrimes * output of the command via a pipe. 511556Srgrimes * Our output routines may be smaller than the stdio routines. 521556Srgrimes */ 531556Srgrimes 5417987Speter#include <sys/ioctl.h> 5517987Speter 561556Srgrimes#include <stdio.h> /* defines BUFSIZ */ 5717987Speter#include <string.h> 581556Srgrimes#ifdef __STDC__ 5917987Speter#include <stdarg.h> 601556Srgrimes#else 611556Srgrimes#include <varargs.h> 621556Srgrimes#endif 631556Srgrimes#include <errno.h> 6417987Speter#include <unistd.h> 6517987Speter#include <stdlib.h> 661556Srgrimes 6717987Speter#include "shell.h" 6817987Speter#include "syntax.h" 6917987Speter#include "output.h" 7017987Speter#include "memalloc.h" 7117987Speter#include "error.h" 721556Srgrimes 7317987Speter 741556Srgrimes#define OUTBUFSIZ BUFSIZ 751556Srgrimes#define BLOCK_OUT -2 /* output to a fixed block of memory */ 761556Srgrimes#define MEM_OUT -3 /* output to dynamically allocated memory */ 771556Srgrimes#define OUTPUT_ERR 01 /* error occurred on output */ 781556Srgrimes 791556Srgrimes 801556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 811556Srgrimesstruct output errout = {NULL, 0, NULL, 100, 2, 0};; 821556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 831556Srgrimesstruct output *out1 = &output; 841556Srgrimesstruct output *out2 = &errout; 851556Srgrimes 861556Srgrimes 871556Srgrimes 881556Srgrimes#ifdef mkinit 891556Srgrimes 901556SrgrimesINCLUDE "output.h" 911556SrgrimesINCLUDE "memalloc.h" 921556Srgrimes 931556SrgrimesRESET { 941556Srgrimes out1 = &output; 951556Srgrimes out2 = &errout; 961556Srgrimes if (memout.buf != NULL) { 971556Srgrimes ckfree(memout.buf); 981556Srgrimes memout.buf = NULL; 991556Srgrimes } 1001556Srgrimes} 1011556Srgrimes 1021556Srgrimes#endif 1031556Srgrimes 1041556Srgrimes 1051556Srgrimes#ifdef notdef /* no longer used */ 1061556Srgrimes/* 1071556Srgrimes * Set up an output file to write to memory rather than a file. 1081556Srgrimes */ 1091556Srgrimes 1101556Srgrimesvoid 1111556Srgrimesopen_mem(block, length, file) 1121556Srgrimes char *block; 1131556Srgrimes int length; 1141556Srgrimes struct output *file; 1151556Srgrimes { 1161556Srgrimes file->nextc = block; 1171556Srgrimes file->nleft = --length; 1181556Srgrimes file->fd = BLOCK_OUT; 1191556Srgrimes file->flags = 0; 1201556Srgrimes} 1211556Srgrimes#endif 1221556Srgrimes 1231556Srgrimes 1241556Srgrimesvoid 1251556Srgrimesout1str(p) 12617987Speter const char *p; 1271556Srgrimes { 1281556Srgrimes outstr(p, out1); 1291556Srgrimes} 1301556Srgrimes 1311556Srgrimes 1321556Srgrimesvoid 1331556Srgrimesout2str(p) 13417987Speter const char *p; 1351556Srgrimes { 1361556Srgrimes outstr(p, out2); 1371556Srgrimes} 1381556Srgrimes 1391556Srgrimes 1401556Srgrimesvoid 1411556Srgrimesoutstr(p, file) 14217987Speter register const char *p; 1431556Srgrimes register struct output *file; 1441556Srgrimes { 1451556Srgrimes while (*p) 1461556Srgrimes outc(*p++, file); 1471556Srgrimes if (file == out2) 1481556Srgrimes flushout(file); 1491556Srgrimes} 1501556Srgrimes 1511556Srgrimes 1521556Srgrimeschar out_junk[16]; 1531556Srgrimes 1541556Srgrimes 1551556Srgrimesvoid 1561556Srgrimesemptyoutbuf(dest) 1571556Srgrimes struct output *dest; 1581556Srgrimes { 1591556Srgrimes int offset; 1601556Srgrimes 1611556Srgrimes if (dest->fd == BLOCK_OUT) { 1621556Srgrimes dest->nextc = out_junk; 1631556Srgrimes dest->nleft = sizeof out_junk; 1641556Srgrimes dest->flags |= OUTPUT_ERR; 1651556Srgrimes } else if (dest->buf == NULL) { 1661556Srgrimes INTOFF; 1671556Srgrimes dest->buf = ckmalloc(dest->bufsize); 1681556Srgrimes dest->nextc = dest->buf; 1691556Srgrimes dest->nleft = dest->bufsize; 1701556Srgrimes INTON; 1711556Srgrimes } else if (dest->fd == MEM_OUT) { 1721556Srgrimes offset = dest->bufsize; 1731556Srgrimes INTOFF; 1741556Srgrimes dest->bufsize <<= 1; 1751556Srgrimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 1761556Srgrimes dest->nleft = dest->bufsize - offset; 1771556Srgrimes dest->nextc = dest->buf + offset; 1781556Srgrimes INTON; 1791556Srgrimes } else { 1801556Srgrimes flushout(dest); 1811556Srgrimes } 1821556Srgrimes dest->nleft--; 1831556Srgrimes} 1841556Srgrimes 1851556Srgrimes 1861556Srgrimesvoid 1871556Srgrimesflushall() { 1881556Srgrimes flushout(&output); 1891556Srgrimes flushout(&errout); 1901556Srgrimes} 1911556Srgrimes 1921556Srgrimes 1931556Srgrimesvoid 1941556Srgrimesflushout(dest) 1951556Srgrimes struct output *dest; 1961556Srgrimes { 1971556Srgrimes 1981556Srgrimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 1991556Srgrimes return; 2001556Srgrimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2011556Srgrimes dest->flags |= OUTPUT_ERR; 2021556Srgrimes dest->nextc = dest->buf; 2031556Srgrimes dest->nleft = dest->bufsize; 2041556Srgrimes} 2051556Srgrimes 2061556Srgrimes 2071556Srgrimesvoid 2081556Srgrimesfreestdout() { 2091556Srgrimes INTOFF; 2101556Srgrimes if (output.buf) { 2111556Srgrimes ckfree(output.buf); 2121556Srgrimes output.buf = NULL; 2131556Srgrimes output.nleft = 0; 2141556Srgrimes } 2151556Srgrimes INTON; 2161556Srgrimes} 2171556Srgrimes 2181556Srgrimes 2191556Srgrimes#ifdef __STDC__ 2201556Srgrimesvoid 2211556Srgrimesoutfmt(struct output *file, char *fmt, ...) { 2221556Srgrimes va_list ap; 2231556Srgrimes 2241556Srgrimes va_start(ap, fmt); 2251556Srgrimes doformat(file, fmt, ap); 2261556Srgrimes va_end(ap); 2271556Srgrimes} 2281556Srgrimes 2291556Srgrimes 2301556Srgrimesvoid 2311556Srgrimesout1fmt(char *fmt, ...) { 2321556Srgrimes va_list ap; 2331556Srgrimes 2341556Srgrimes va_start(ap, fmt); 2351556Srgrimes doformat(out1, fmt, ap); 2361556Srgrimes va_end(ap); 2371556Srgrimes} 2381556Srgrimes 2391556Srgrimesvoid 2401556Srgrimesdprintf(char *fmt, ...) { 2411556Srgrimes va_list ap; 2421556Srgrimes 2431556Srgrimes va_start(ap, fmt); 2441556Srgrimes doformat(out2, fmt, ap); 2451556Srgrimes va_end(ap); 2461556Srgrimes flushout(out2); 2471556Srgrimes} 2481556Srgrimes 2491556Srgrimesvoid 2501556Srgrimesfmtstr(char *outbuf, int length, char *fmt, ...) { 2511556Srgrimes va_list ap; 2521556Srgrimes struct output strout; 2531556Srgrimes 2541556Srgrimes va_start(ap, fmt); 2551556Srgrimes strout.nextc = outbuf; 2561556Srgrimes strout.nleft = length; 2571556Srgrimes strout.fd = BLOCK_OUT; 2581556Srgrimes strout.flags = 0; 2591556Srgrimes doformat(&strout, fmt, ap); 2601556Srgrimes outc('\0', &strout); 2611556Srgrimes if (strout.flags & OUTPUT_ERR) 2621556Srgrimes outbuf[length - 1] = '\0'; 2631556Srgrimes} 2641556Srgrimes 2651556Srgrimes#else /* not __STDC__ */ 2661556Srgrimes 2671556Srgrimesvoid 2681556Srgrimesoutfmt(va_alist) 2691556Srgrimes va_dcl 2701556Srgrimes { 2711556Srgrimes va_list ap; 2721556Srgrimes struct output *file; 2731556Srgrimes char *fmt; 2741556Srgrimes 2751556Srgrimes va_start(ap); 2761556Srgrimes file = va_arg(ap, struct output *); 2771556Srgrimes fmt = va_arg(ap, char *); 2781556Srgrimes doformat(file, fmt, ap); 2791556Srgrimes va_end(ap); 2801556Srgrimes} 2811556Srgrimes 2821556Srgrimes 2831556Srgrimesvoid 2841556Srgrimesout1fmt(va_alist) 2851556Srgrimes va_dcl 2861556Srgrimes { 2871556Srgrimes va_list ap; 2881556Srgrimes char *fmt; 2891556Srgrimes 2901556Srgrimes va_start(ap); 2911556Srgrimes fmt = va_arg(ap, char *); 2921556Srgrimes doformat(out1, fmt, ap); 2931556Srgrimes va_end(ap); 2941556Srgrimes} 2951556Srgrimes 2961556Srgrimesvoid 2971556Srgrimesdprintf(va_alist) 2981556Srgrimes va_dcl 2991556Srgrimes { 3001556Srgrimes va_list ap; 3011556Srgrimes char *fmt; 3021556Srgrimes 3031556Srgrimes va_start(ap); 3041556Srgrimes fmt = va_arg(ap, char *); 3051556Srgrimes doformat(out2, fmt, ap); 3061556Srgrimes va_end(ap); 3071556Srgrimes flushout(out2); 3081556Srgrimes} 3091556Srgrimes 3101556Srgrimesvoid 3111556Srgrimesfmtstr(va_alist) 3121556Srgrimes va_dcl 3131556Srgrimes { 3141556Srgrimes va_list ap; 3151556Srgrimes struct output strout; 3161556Srgrimes char *outbuf; 3171556Srgrimes int length; 3181556Srgrimes char *fmt; 3191556Srgrimes 3201556Srgrimes va_start(ap); 3211556Srgrimes outbuf = va_arg(ap, char *); 3221556Srgrimes length = va_arg(ap, int); 3231556Srgrimes fmt = va_arg(ap, char *); 3241556Srgrimes strout.nextc = outbuf; 3251556Srgrimes strout.nleft = length; 3261556Srgrimes strout.fd = BLOCK_OUT; 3271556Srgrimes strout.flags = 0; 3281556Srgrimes doformat(&strout, fmt, ap); 3291556Srgrimes outc('\0', &strout); 3301556Srgrimes if (strout.flags & OUTPUT_ERR) 3311556Srgrimes outbuf[length - 1] = '\0'; 3321556Srgrimes} 3331556Srgrimes#endif /* __STDC__ */ 3341556Srgrimes 3351556Srgrimes 3361556Srgrimes/* 3371556Srgrimes * Formatted output. This routine handles a subset of the printf formats: 3381556Srgrimes * - Formats supported: d, u, o, X, s, and c. 3391556Srgrimes * - The x format is also accepted but is treated like X. 3401556Srgrimes * - The l modifier is accepted. 3411556Srgrimes * - The - and # flags are accepted; # only works with the o format. 3421556Srgrimes * - Width and precision may be specified with any format except c. 3431556Srgrimes * - An * may be given for the width or precision. 3441556Srgrimes * - The obsolete practice of preceding the width with a zero to get 3451556Srgrimes * zero padding is not supported; use the precision field. 3461556Srgrimes * - A % may be printed by writing %% in the format string. 3471556Srgrimes */ 3481556Srgrimes 3491556Srgrimes#define TEMPSIZE 24 3501556Srgrimes 3511556Srgrimes#ifdef __STDC__ 3521556Srgrimesstatic const char digit[16] = "0123456789ABCDEF"; 3531556Srgrimes#else 3541556Srgrimesstatic const char digit[17] = "0123456789ABCDEF"; 3551556Srgrimes#endif 3561556Srgrimes 3571556Srgrimes 3581556Srgrimesvoid 3591556Srgrimesdoformat(dest, f, ap) 3601556Srgrimes register struct output *dest; 3611556Srgrimes register char *f; /* format string */ 3621556Srgrimes va_list ap; 3631556Srgrimes { 3641556Srgrimes register char c; 3651556Srgrimes char temp[TEMPSIZE]; 3661556Srgrimes int flushleft; 3671556Srgrimes int sharp; 3681556Srgrimes int width; 3691556Srgrimes int prec; 3701556Srgrimes int islong; 3711556Srgrimes char *p; 3721556Srgrimes int sign; 3731556Srgrimes long l; 3741556Srgrimes unsigned long num; 3751556Srgrimes unsigned base; 3761556Srgrimes int len; 3771556Srgrimes int size; 3781556Srgrimes int pad; 3791556Srgrimes 3801556Srgrimes while ((c = *f++) != '\0') { 3811556Srgrimes if (c != '%') { 3821556Srgrimes outc(c, dest); 3831556Srgrimes continue; 3841556Srgrimes } 3851556Srgrimes flushleft = 0; 3861556Srgrimes sharp = 0; 3871556Srgrimes width = 0; 3881556Srgrimes prec = -1; 3891556Srgrimes islong = 0; 3901556Srgrimes for (;;) { 3911556Srgrimes if (*f == '-') 3921556Srgrimes flushleft++; 3931556Srgrimes else if (*f == '#') 3941556Srgrimes sharp++; 3951556Srgrimes else 3961556Srgrimes break; 3971556Srgrimes f++; 3981556Srgrimes } 3991556Srgrimes if (*f == '*') { 4001556Srgrimes width = va_arg(ap, int); 4011556Srgrimes f++; 4021556Srgrimes } else { 4031556Srgrimes while (is_digit(*f)) { 4041556Srgrimes width = 10 * width + digit_val(*f++); 4051556Srgrimes } 4061556Srgrimes } 4071556Srgrimes if (*f == '.') { 4081556Srgrimes if (*++f == '*') { 4091556Srgrimes prec = va_arg(ap, int); 4101556Srgrimes f++; 4111556Srgrimes } else { 4121556Srgrimes prec = 0; 4131556Srgrimes while (is_digit(*f)) { 4141556Srgrimes prec = 10 * prec + digit_val(*f++); 4151556Srgrimes } 4161556Srgrimes } 4171556Srgrimes } 4181556Srgrimes if (*f == 'l') { 4191556Srgrimes islong++; 4201556Srgrimes f++; 4211556Srgrimes } 4221556Srgrimes switch (*f) { 4231556Srgrimes case 'd': 4241556Srgrimes if (islong) 4251556Srgrimes l = va_arg(ap, long); 4261556Srgrimes else 4271556Srgrimes l = va_arg(ap, int); 4281556Srgrimes sign = 0; 4291556Srgrimes num = l; 4301556Srgrimes if (l < 0) { 4311556Srgrimes num = -l; 4321556Srgrimes sign = 1; 4331556Srgrimes } 4341556Srgrimes base = 10; 4351556Srgrimes goto number; 4361556Srgrimes case 'u': 4371556Srgrimes base = 10; 4381556Srgrimes goto uns_number; 4391556Srgrimes case 'o': 4401556Srgrimes base = 8; 4411556Srgrimes goto uns_number; 4421556Srgrimes case 'x': 4431556Srgrimes /* we don't implement 'x'; treat like 'X' */ 4441556Srgrimes case 'X': 4451556Srgrimes base = 16; 4461556Srgrimesuns_number: /* an unsigned number */ 4471556Srgrimes sign = 0; 4481556Srgrimes if (islong) 4491556Srgrimes num = va_arg(ap, unsigned long); 4501556Srgrimes else 4511556Srgrimes num = va_arg(ap, unsigned int); 4521556Srgrimesnumber: /* process a number */ 4531556Srgrimes p = temp + TEMPSIZE - 1; 4541556Srgrimes *p = '\0'; 4551556Srgrimes while (num) { 4561556Srgrimes *--p = digit[num % base]; 4571556Srgrimes num /= base; 4581556Srgrimes } 4591556Srgrimes len = (temp + TEMPSIZE - 1) - p; 4601556Srgrimes if (prec < 0) 4611556Srgrimes prec = 1; 4621556Srgrimes if (sharp && *f == 'o' && prec <= len) 4631556Srgrimes prec = len + 1; 4641556Srgrimes pad = 0; 4651556Srgrimes if (width) { 4661556Srgrimes size = len; 4671556Srgrimes if (size < prec) 4681556Srgrimes size = prec; 4691556Srgrimes size += sign; 4701556Srgrimes pad = width - size; 4711556Srgrimes if (flushleft == 0) { 4721556Srgrimes while (--pad >= 0) 4731556Srgrimes outc(' ', dest); 4741556Srgrimes } 4751556Srgrimes } 4761556Srgrimes if (sign) 4771556Srgrimes outc('-', dest); 4781556Srgrimes prec -= len; 4791556Srgrimes while (--prec >= 0) 4801556Srgrimes outc('0', dest); 4811556Srgrimes while (*p) 4821556Srgrimes outc(*p++, dest); 4831556Srgrimes while (--pad >= 0) 4841556Srgrimes outc(' ', dest); 4851556Srgrimes break; 4861556Srgrimes case 's': 4871556Srgrimes p = va_arg(ap, char *); 4881556Srgrimes pad = 0; 4891556Srgrimes if (width) { 4901556Srgrimes len = strlen(p); 4911556Srgrimes if (prec >= 0 && len > prec) 4921556Srgrimes len = prec; 4931556Srgrimes pad = width - len; 4941556Srgrimes if (flushleft == 0) { 4951556Srgrimes while (--pad >= 0) 4961556Srgrimes outc(' ', dest); 4971556Srgrimes } 4981556Srgrimes } 4991556Srgrimes prec++; 5001556Srgrimes while (--prec != 0 && *p) 5011556Srgrimes outc(*p++, dest); 5021556Srgrimes while (--pad >= 0) 5031556Srgrimes outc(' ', dest); 5041556Srgrimes break; 5051556Srgrimes case 'c': 5061556Srgrimes c = va_arg(ap, int); 5071556Srgrimes outc(c, dest); 5081556Srgrimes break; 5091556Srgrimes default: 5101556Srgrimes outc(*f, dest); 5111556Srgrimes break; 5121556Srgrimes } 5131556Srgrimes f++; 5141556Srgrimes } 5151556Srgrimes} 5161556Srgrimes 5171556Srgrimes 5181556Srgrimes 5191556Srgrimes/* 5201556Srgrimes * Version of write which resumes after a signal is caught. 5211556Srgrimes */ 5221556Srgrimes 5231556Srgrimesint 5241556Srgrimesxwrite(fd, buf, nbytes) 5251556Srgrimes int fd; 5261556Srgrimes char *buf; 5271556Srgrimes int nbytes; 5281556Srgrimes { 5291556Srgrimes int ntry; 5301556Srgrimes int i; 5311556Srgrimes int n; 5321556Srgrimes 5331556Srgrimes n = nbytes; 5341556Srgrimes ntry = 0; 5351556Srgrimes for (;;) { 5361556Srgrimes i = write(fd, buf, n); 5371556Srgrimes if (i > 0) { 5381556Srgrimes if ((n -= i) <= 0) 5391556Srgrimes return nbytes; 5401556Srgrimes buf += i; 5411556Srgrimes ntry = 0; 5421556Srgrimes } else if (i == 0) { 5431556Srgrimes if (++ntry > 10) 5441556Srgrimes return nbytes - n; 5451556Srgrimes } else if (errno != EINTR) { 5461556Srgrimes return -1; 5471556Srgrimes } 5481556Srgrimes } 5491556Srgrimes} 5501556Srgrimes 5511556Srgrimes 5521556Srgrimes/* 5531556Srgrimes * Version of ioctl that retries after a signal is caught. 55417987Speter * XXX unused function 5551556Srgrimes */ 5561556Srgrimes 5571556Srgrimesint 55817987Speterxioctl(fd, request, arg) 55917987Speter int fd; 56017987Speter unsigned long request; 56117987Speter char * arg; 56217987Speter{ 5631556Srgrimes int i; 5641556Srgrimes 5651556Srgrimes while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 5661556Srgrimes return i; 5671556Srgrimes} 568