output.c revision 97815
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 3836150Scharnier#if 0 3936150Scharnierstatic char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 4036150Scharnier#endif 4136150Scharnierstatic const char rcsid[] = 4250471Speter "$FreeBSD: head/bin/sh/output.c 97815 2002-06-04 12:59:12Z tjr $"; 431556Srgrimes#endif /* not lint */ 441556Srgrimes 451556Srgrimes/* 461556Srgrimes * Shell output routines. We use our own output routines because: 471556Srgrimes * When a builtin command is interrupted we have to discard 481556Srgrimes * any pending output. 491556Srgrimes * When a builtin command appears in back quotes, we want to 501556Srgrimes * save the output of the command in a region obtained 511556Srgrimes * via malloc, rather than doing a fork and reading the 521556Srgrimes * output of the command via a pipe. 531556Srgrimes * Our output routines may be smaller than the stdio routines. 541556Srgrimes */ 551556Srgrimes 5620425Ssteve#include <sys/types.h> /* quad_t */ 5717987Speter#include <sys/ioctl.h> 5817987Speter 591556Srgrimes#include <stdio.h> /* defines BUFSIZ */ 6017987Speter#include <string.h> 6117987Speter#include <stdarg.h> 621556Srgrimes#include <errno.h> 6317987Speter#include <unistd.h> 6417987Speter#include <stdlib.h> 651556Srgrimes 6617987Speter#include "shell.h" 6717987Speter#include "syntax.h" 6817987Speter#include "output.h" 6917987Speter#include "memalloc.h" 7017987Speter#include "error.h" 711556Srgrimes 7217987Speter 731556Srgrimes#define OUTBUFSIZ BUFSIZ 741556Srgrimes#define BLOCK_OUT -2 /* output to a fixed block of memory */ 751556Srgrimes#define MEM_OUT -3 /* output to dynamically allocated memory */ 761556Srgrimes#define OUTPUT_ERR 01 /* error occurred on output */ 771556Srgrimes 781556Srgrimes 791556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 8025232Sstevestruct output errout = {NULL, 0, NULL, 100, 2, 0}; 811556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 821556Srgrimesstruct output *out1 = &output; 831556Srgrimesstruct output *out2 = &errout; 841556Srgrimes 851556Srgrimes 861556Srgrimes 871556Srgrimes#ifdef mkinit 881556Srgrimes 891556SrgrimesINCLUDE "output.h" 901556SrgrimesINCLUDE "memalloc.h" 911556Srgrimes 921556SrgrimesRESET { 931556Srgrimes out1 = &output; 941556Srgrimes out2 = &errout; 951556Srgrimes if (memout.buf != NULL) { 961556Srgrimes ckfree(memout.buf); 971556Srgrimes memout.buf = NULL; 981556Srgrimes } 991556Srgrimes} 1001556Srgrimes 1011556Srgrimes#endif 1021556Srgrimes 1031556Srgrimes 1041556Srgrimesvoid 10590111Simpout1str(const char *p) 10690111Simp{ 1071556Srgrimes outstr(p, out1); 1081556Srgrimes} 1091556Srgrimes 11097815Stjrvoid 11197815Stjrout1qstr(const char *p) 11297815Stjr{ 11397815Stjr outqstr(p, out1); 11497815Stjr} 1151556Srgrimes 1161556Srgrimesvoid 11790111Simpout2str(const char *p) 11890111Simp{ 1191556Srgrimes outstr(p, out2); 1201556Srgrimes} 1211556Srgrimes 12297815Stjrvoid 12397815Stjrout2qstr(const char *p) 12497815Stjr{ 12597815Stjr outqstr(p, out2); 12697815Stjr} 1271556Srgrimes 1281556Srgrimesvoid 12990111Simpoutstr(const char *p, struct output *file) 13090111Simp{ 1311556Srgrimes while (*p) 1321556Srgrimes outc(*p++, file); 1331556Srgrimes if (file == out2) 1341556Srgrimes flushout(file); 1351556Srgrimes} 1361556Srgrimes 13797815Stjr/* Like outstr(), but quote for re-input into the shell. */ 13897815Stjrvoid 13997815Stjroutqstr(const char *p, struct output *file) 14097815Stjr{ 14197815Stjr char ch; 1421556Srgrimes 14397815Stjr out1c('\''); 14497815Stjr while ((ch = *p++) != '\0') { 14597815Stjr switch (ch) { 14697815Stjr case '\'': 14797815Stjr /* 14897815Stjr * Can't quote single quotes inside single quotes; 14997815Stjr * close them, write escaped single quote, open again. 15097815Stjr */ 15197815Stjr outstr("'\\''", file); 15297815Stjr break; 15397815Stjr default: 15497815Stjr outc(ch, file); 15597815Stjr } 15697815Stjr } 15797815Stjr out1c('\''); 15897815Stjr} 15997815Stjr 1601556Srgrimeschar out_junk[16]; 1611556Srgrimes 1621556Srgrimesvoid 16390111Simpemptyoutbuf(struct output *dest) 16490111Simp{ 1651556Srgrimes int offset; 1661556Srgrimes 1671556Srgrimes if (dest->fd == BLOCK_OUT) { 1681556Srgrimes dest->nextc = out_junk; 1691556Srgrimes dest->nleft = sizeof out_junk; 1701556Srgrimes dest->flags |= OUTPUT_ERR; 1711556Srgrimes } else if (dest->buf == NULL) { 1721556Srgrimes INTOFF; 1731556Srgrimes dest->buf = ckmalloc(dest->bufsize); 1741556Srgrimes dest->nextc = dest->buf; 1751556Srgrimes dest->nleft = dest->bufsize; 1761556Srgrimes INTON; 1771556Srgrimes } else if (dest->fd == MEM_OUT) { 1781556Srgrimes offset = dest->bufsize; 1791556Srgrimes INTOFF; 1801556Srgrimes dest->bufsize <<= 1; 1811556Srgrimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 1821556Srgrimes dest->nleft = dest->bufsize - offset; 1831556Srgrimes dest->nextc = dest->buf + offset; 1841556Srgrimes INTON; 1851556Srgrimes } else { 1861556Srgrimes flushout(dest); 1871556Srgrimes } 1881556Srgrimes dest->nleft--; 1891556Srgrimes} 1901556Srgrimes 1911556Srgrimes 1921556Srgrimesvoid 19390111Simpflushall(void) 19490111Simp{ 1951556Srgrimes flushout(&output); 1961556Srgrimes flushout(&errout); 1971556Srgrimes} 1981556Srgrimes 1991556Srgrimes 2001556Srgrimesvoid 20190111Simpflushout(struct output *dest) 20290111Simp{ 2031556Srgrimes 2041556Srgrimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 2051556Srgrimes return; 2061556Srgrimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2071556Srgrimes dest->flags |= OUTPUT_ERR; 2081556Srgrimes dest->nextc = dest->buf; 2091556Srgrimes dest->nleft = dest->bufsize; 2101556Srgrimes} 2111556Srgrimes 2121556Srgrimes 2131556Srgrimesvoid 21490111Simpfreestdout(void) 21590111Simp{ 2161556Srgrimes INTOFF; 2171556Srgrimes if (output.buf) { 2181556Srgrimes ckfree(output.buf); 2191556Srgrimes output.buf = NULL; 2201556Srgrimes output.nleft = 0; 2211556Srgrimes } 2221556Srgrimes INTON; 2231556Srgrimes} 2241556Srgrimes 2251556Srgrimes 2261556Srgrimesvoid 22790111Simpoutfmt(struct output *file, const char *fmt, ...) 22890111Simp{ 2291556Srgrimes va_list ap; 2301556Srgrimes 2311556Srgrimes va_start(ap, fmt); 2321556Srgrimes doformat(file, fmt, ap); 2331556Srgrimes va_end(ap); 2341556Srgrimes} 2351556Srgrimes 2361556Srgrimes 2371556Srgrimesvoid 23890111Simpout1fmt(const char *fmt, ...) 23990111Simp{ 2401556Srgrimes va_list ap; 2411556Srgrimes 2421556Srgrimes va_start(ap, fmt); 2431556Srgrimes doformat(out1, fmt, ap); 2441556Srgrimes va_end(ap); 2451556Srgrimes} 2461556Srgrimes 2471556Srgrimesvoid 24890111Simpdprintf(const char *fmt, ...) 24990111Simp{ 2501556Srgrimes va_list ap; 2511556Srgrimes 2521556Srgrimes va_start(ap, fmt); 2531556Srgrimes doformat(out2, fmt, ap); 2541556Srgrimes va_end(ap); 2551556Srgrimes flushout(out2); 2561556Srgrimes} 2571556Srgrimes 2581556Srgrimesvoid 25990111Simpfmtstr(char *outbuf, int length, const char *fmt, ...) 26090111Simp{ 2611556Srgrimes va_list ap; 2621556Srgrimes struct output strout; 2631556Srgrimes 2641556Srgrimes va_start(ap, fmt); 2651556Srgrimes strout.nextc = outbuf; 2661556Srgrimes strout.nleft = length; 2671556Srgrimes strout.fd = BLOCK_OUT; 2681556Srgrimes strout.flags = 0; 2691556Srgrimes doformat(&strout, fmt, ap); 2701556Srgrimes outc('\0', &strout); 2711556Srgrimes if (strout.flags & OUTPUT_ERR) 2721556Srgrimes outbuf[length - 1] = '\0'; 2731556Srgrimes} 2741556Srgrimes 2751556Srgrimes/* 2761556Srgrimes * Formatted output. This routine handles a subset of the printf formats: 2771556Srgrimes * - Formats supported: d, u, o, X, s, and c. 2781556Srgrimes * - The x format is also accepted but is treated like X. 27920425Ssteve * - The l and q modifiers are accepted. 2801556Srgrimes * - The - and # flags are accepted; # only works with the o format. 2811556Srgrimes * - Width and precision may be specified with any format except c. 2821556Srgrimes * - An * may be given for the width or precision. 2831556Srgrimes * - The obsolete practice of preceding the width with a zero to get 2841556Srgrimes * zero padding is not supported; use the precision field. 2851556Srgrimes * - A % may be printed by writing %% in the format string. 2861556Srgrimes */ 2871556Srgrimes 2881556Srgrimes#define TEMPSIZE 24 2891556Srgrimes 29018018Speterstatic const char digit[] = "0123456789ABCDEF"; 2911556Srgrimes 2921556Srgrimes 2931556Srgrimesvoid 29490111Simpdoformat(struct output *dest, const char *f, va_list ap) 29590111Simp{ 29625232Ssteve char c; 2971556Srgrimes char temp[TEMPSIZE]; 2981556Srgrimes int flushleft; 2991556Srgrimes int sharp; 3001556Srgrimes int width; 3011556Srgrimes int prec; 3021556Srgrimes int islong; 30318018Speter int isquad; 3041556Srgrimes char *p; 3051556Srgrimes int sign; 30618018Speter quad_t l; 30718018Speter u_quad_t num; 3081556Srgrimes unsigned base; 3091556Srgrimes int len; 3101556Srgrimes int size; 3111556Srgrimes int pad; 3121556Srgrimes 3131556Srgrimes while ((c = *f++) != '\0') { 3141556Srgrimes if (c != '%') { 3151556Srgrimes outc(c, dest); 3161556Srgrimes continue; 3171556Srgrimes } 3181556Srgrimes flushleft = 0; 3191556Srgrimes sharp = 0; 3201556Srgrimes width = 0; 3211556Srgrimes prec = -1; 3221556Srgrimes islong = 0; 32318018Speter isquad = 0; 3241556Srgrimes for (;;) { 3251556Srgrimes if (*f == '-') 3261556Srgrimes flushleft++; 3271556Srgrimes else if (*f == '#') 3281556Srgrimes sharp++; 3291556Srgrimes else 3301556Srgrimes break; 3311556Srgrimes f++; 3321556Srgrimes } 3331556Srgrimes if (*f == '*') { 3341556Srgrimes width = va_arg(ap, int); 3351556Srgrimes f++; 3361556Srgrimes } else { 3371556Srgrimes while (is_digit(*f)) { 3381556Srgrimes width = 10 * width + digit_val(*f++); 3391556Srgrimes } 3401556Srgrimes } 3411556Srgrimes if (*f == '.') { 3421556Srgrimes if (*++f == '*') { 3431556Srgrimes prec = va_arg(ap, int); 3441556Srgrimes f++; 3451556Srgrimes } else { 3461556Srgrimes prec = 0; 3471556Srgrimes while (is_digit(*f)) { 3481556Srgrimes prec = 10 * prec + digit_val(*f++); 3491556Srgrimes } 3501556Srgrimes } 3511556Srgrimes } 3521556Srgrimes if (*f == 'l') { 3531556Srgrimes islong++; 3541556Srgrimes f++; 35518018Speter } else if (*f == 'q') { 35618018Speter isquad++; 35718018Speter f++; 3581556Srgrimes } 3591556Srgrimes switch (*f) { 3601556Srgrimes case 'd': 36120425Ssteve if (isquad) 36220425Ssteve l = va_arg(ap, quad_t); 36320425Ssteve else if (islong) 3641556Srgrimes l = va_arg(ap, long); 3651556Srgrimes else 3661556Srgrimes l = va_arg(ap, int); 3671556Srgrimes sign = 0; 3681556Srgrimes num = l; 3691556Srgrimes if (l < 0) { 3701556Srgrimes num = -l; 3711556Srgrimes sign = 1; 3721556Srgrimes } 3731556Srgrimes base = 10; 3741556Srgrimes goto number; 3751556Srgrimes case 'u': 3761556Srgrimes base = 10; 3771556Srgrimes goto uns_number; 3781556Srgrimes case 'o': 3791556Srgrimes base = 8; 3801556Srgrimes goto uns_number; 3811556Srgrimes case 'x': 3821556Srgrimes /* we don't implement 'x'; treat like 'X' */ 3831556Srgrimes case 'X': 3841556Srgrimes base = 16; 3851556Srgrimesuns_number: /* an unsigned number */ 3861556Srgrimes sign = 0; 38720425Ssteve if (isquad) 38820425Ssteve num = va_arg(ap, u_quad_t); 38920425Ssteve else if (islong) 3901556Srgrimes num = va_arg(ap, unsigned long); 3911556Srgrimes else 3921556Srgrimes num = va_arg(ap, unsigned int); 3931556Srgrimesnumber: /* process a number */ 3941556Srgrimes p = temp + TEMPSIZE - 1; 3951556Srgrimes *p = '\0'; 3961556Srgrimes while (num) { 3971556Srgrimes *--p = digit[num % base]; 3981556Srgrimes num /= base; 3991556Srgrimes } 4001556Srgrimes len = (temp + TEMPSIZE - 1) - p; 4011556Srgrimes if (prec < 0) 4021556Srgrimes prec = 1; 4031556Srgrimes if (sharp && *f == 'o' && prec <= len) 4041556Srgrimes prec = len + 1; 4051556Srgrimes pad = 0; 4061556Srgrimes if (width) { 4071556Srgrimes size = len; 4081556Srgrimes if (size < prec) 4091556Srgrimes size = prec; 4101556Srgrimes size += sign; 4111556Srgrimes pad = width - size; 4121556Srgrimes if (flushleft == 0) { 4131556Srgrimes while (--pad >= 0) 4141556Srgrimes outc(' ', dest); 4151556Srgrimes } 4161556Srgrimes } 4171556Srgrimes if (sign) 4181556Srgrimes outc('-', dest); 4191556Srgrimes prec -= len; 4201556Srgrimes while (--prec >= 0) 4211556Srgrimes outc('0', dest); 4221556Srgrimes while (*p) 4231556Srgrimes outc(*p++, dest); 4241556Srgrimes while (--pad >= 0) 4251556Srgrimes outc(' ', dest); 4261556Srgrimes break; 4271556Srgrimes case 's': 4281556Srgrimes p = va_arg(ap, char *); 4291556Srgrimes pad = 0; 4301556Srgrimes if (width) { 4311556Srgrimes len = strlen(p); 4321556Srgrimes if (prec >= 0 && len > prec) 4331556Srgrimes len = prec; 4341556Srgrimes pad = width - len; 4351556Srgrimes if (flushleft == 0) { 4361556Srgrimes while (--pad >= 0) 4371556Srgrimes outc(' ', dest); 4381556Srgrimes } 4391556Srgrimes } 4401556Srgrimes prec++; 4411556Srgrimes while (--prec != 0 && *p) 4421556Srgrimes outc(*p++, dest); 4431556Srgrimes while (--pad >= 0) 4441556Srgrimes outc(' ', dest); 4451556Srgrimes break; 4461556Srgrimes case 'c': 4471556Srgrimes c = va_arg(ap, int); 4481556Srgrimes outc(c, dest); 4491556Srgrimes break; 4501556Srgrimes default: 4511556Srgrimes outc(*f, dest); 4521556Srgrimes break; 4531556Srgrimes } 4541556Srgrimes f++; 4551556Srgrimes } 4561556Srgrimes} 4571556Srgrimes 4581556Srgrimes 4591556Srgrimes 4601556Srgrimes/* 4611556Srgrimes * Version of write which resumes after a signal is caught. 4621556Srgrimes */ 4631556Srgrimes 4641556Srgrimesint 46590111Simpxwrite(int fd, char *buf, int nbytes) 46690111Simp{ 4671556Srgrimes int ntry; 4681556Srgrimes int i; 4691556Srgrimes int n; 4701556Srgrimes 4711556Srgrimes n = nbytes; 4721556Srgrimes ntry = 0; 4731556Srgrimes for (;;) { 4741556Srgrimes i = write(fd, buf, n); 4751556Srgrimes if (i > 0) { 4761556Srgrimes if ((n -= i) <= 0) 4771556Srgrimes return nbytes; 4781556Srgrimes buf += i; 4791556Srgrimes ntry = 0; 4801556Srgrimes } else if (i == 0) { 4811556Srgrimes if (++ntry > 10) 4821556Srgrimes return nbytes - n; 4831556Srgrimes } else if (errno != EINTR) { 4841556Srgrimes return -1; 4851556Srgrimes } 4861556Srgrimes } 4871556Srgrimes} 488