output.c revision 104286
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 411556Srgrimes#endif /* not lint */ 4299110Sobrien#include <sys/cdefs.h> 4399110Sobrien__FBSDID("$FreeBSD: head/bin/sh/output.c 104286 2002-10-01 13:22:12Z tjr $"); 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 */ 541556Srgrimes 551556Srgrimes#include <stdio.h> /* defines BUFSIZ */ 5617987Speter#include <string.h> 5717987Speter#include <stdarg.h> 581556Srgrimes#include <errno.h> 5917987Speter#include <unistd.h> 6017987Speter#include <stdlib.h> 611556Srgrimes 6217987Speter#include "shell.h" 6317987Speter#include "syntax.h" 6417987Speter#include "output.h" 6517987Speter#include "memalloc.h" 6617987Speter#include "error.h" 6797909Stjr#include "var.h" 681556Srgrimes 6917987Speter 701556Srgrimes#define OUTBUFSIZ BUFSIZ 711556Srgrimes#define BLOCK_OUT -2 /* output to a fixed block of memory */ 721556Srgrimes#define MEM_OUT -3 /* output to dynamically allocated memory */ 731556Srgrimes#define OUTPUT_ERR 01 /* error occurred on output */ 741556Srgrimes 75104286Stjrstatic int doformat_wr(void *, const char *, int); 761556Srgrimes 771556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 7825232Sstevestruct output errout = {NULL, 0, NULL, 100, 2, 0}; 791556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 801556Srgrimesstruct output *out1 = &output; 811556Srgrimesstruct output *out2 = &errout; 821556Srgrimes 831556Srgrimes 841556Srgrimes 851556Srgrimes#ifdef mkinit 861556Srgrimes 871556SrgrimesINCLUDE "output.h" 881556SrgrimesINCLUDE "memalloc.h" 891556Srgrimes 901556SrgrimesRESET { 911556Srgrimes out1 = &output; 921556Srgrimes out2 = &errout; 931556Srgrimes if (memout.buf != NULL) { 941556Srgrimes ckfree(memout.buf); 951556Srgrimes memout.buf = NULL; 961556Srgrimes } 971556Srgrimes} 981556Srgrimes 991556Srgrimes#endif 1001556Srgrimes 1011556Srgrimes 1021556Srgrimesvoid 10390111Simpout1str(const char *p) 10490111Simp{ 1051556Srgrimes outstr(p, out1); 1061556Srgrimes} 1071556Srgrimes 10897815Stjrvoid 10997815Stjrout1qstr(const char *p) 11097815Stjr{ 11197815Stjr outqstr(p, out1); 11297815Stjr} 1131556Srgrimes 1141556Srgrimesvoid 11590111Simpout2str(const char *p) 11690111Simp{ 1171556Srgrimes outstr(p, out2); 1181556Srgrimes} 1191556Srgrimes 12097815Stjrvoid 12197815Stjrout2qstr(const char *p) 12297815Stjr{ 12397815Stjr outqstr(p, out2); 12497815Stjr} 1251556Srgrimes 1261556Srgrimesvoid 12790111Simpoutstr(const char *p, struct output *file) 12890111Simp{ 1291556Srgrimes while (*p) 1301556Srgrimes outc(*p++, file); 1311556Srgrimes if (file == out2) 1321556Srgrimes flushout(file); 1331556Srgrimes} 1341556Srgrimes 13597815Stjr/* Like outstr(), but quote for re-input into the shell. */ 13697815Stjrvoid 13797815Stjroutqstr(const char *p, struct output *file) 13897815Stjr{ 13997815Stjr char ch; 1401556Srgrimes 14197909Stjr if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() || 14297909Stjr p[strcspn(p, ifsval())] == '\0')) { 14397909Stjr outstr(p, file); 14497909Stjr return; 14597909Stjr } 14697909Stjr 14797815Stjr out1c('\''); 14897815Stjr while ((ch = *p++) != '\0') { 14997815Stjr switch (ch) { 15097815Stjr case '\'': 15197815Stjr /* 15297815Stjr * Can't quote single quotes inside single quotes; 15397815Stjr * close them, write escaped single quote, open again. 15497815Stjr */ 15597815Stjr outstr("'\\''", file); 15697815Stjr break; 15797815Stjr default: 15897815Stjr outc(ch, file); 15997815Stjr } 16097815Stjr } 16197815Stjr out1c('\''); 16297815Stjr} 16397815Stjr 1641556Srgrimeschar out_junk[16]; 1651556Srgrimes 1661556Srgrimesvoid 16790111Simpemptyoutbuf(struct output *dest) 16890111Simp{ 1691556Srgrimes int offset; 1701556Srgrimes 1711556Srgrimes if (dest->fd == BLOCK_OUT) { 1721556Srgrimes dest->nextc = out_junk; 1731556Srgrimes dest->nleft = sizeof out_junk; 1741556Srgrimes dest->flags |= OUTPUT_ERR; 1751556Srgrimes } else if (dest->buf == NULL) { 1761556Srgrimes INTOFF; 1771556Srgrimes dest->buf = ckmalloc(dest->bufsize); 1781556Srgrimes dest->nextc = dest->buf; 1791556Srgrimes dest->nleft = dest->bufsize; 1801556Srgrimes INTON; 1811556Srgrimes } else if (dest->fd == MEM_OUT) { 1821556Srgrimes offset = dest->bufsize; 1831556Srgrimes INTOFF; 1841556Srgrimes dest->bufsize <<= 1; 1851556Srgrimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 1861556Srgrimes dest->nleft = dest->bufsize - offset; 1871556Srgrimes dest->nextc = dest->buf + offset; 1881556Srgrimes INTON; 1891556Srgrimes } else { 1901556Srgrimes flushout(dest); 1911556Srgrimes } 1921556Srgrimes dest->nleft--; 1931556Srgrimes} 1941556Srgrimes 1951556Srgrimes 1961556Srgrimesvoid 19790111Simpflushall(void) 19890111Simp{ 1991556Srgrimes flushout(&output); 2001556Srgrimes flushout(&errout); 2011556Srgrimes} 2021556Srgrimes 2031556Srgrimes 2041556Srgrimesvoid 20590111Simpflushout(struct output *dest) 20690111Simp{ 2071556Srgrimes 2081556Srgrimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 2091556Srgrimes return; 2101556Srgrimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2111556Srgrimes dest->flags |= OUTPUT_ERR; 2121556Srgrimes dest->nextc = dest->buf; 2131556Srgrimes dest->nleft = dest->bufsize; 2141556Srgrimes} 2151556Srgrimes 2161556Srgrimes 2171556Srgrimesvoid 21890111Simpfreestdout(void) 21990111Simp{ 2201556Srgrimes INTOFF; 2211556Srgrimes if (output.buf) { 2221556Srgrimes ckfree(output.buf); 2231556Srgrimes output.buf = NULL; 2241556Srgrimes output.nleft = 0; 2251556Srgrimes } 2261556Srgrimes INTON; 2271556Srgrimes} 2281556Srgrimes 2291556Srgrimes 2301556Srgrimesvoid 23190111Simpoutfmt(struct output *file, const char *fmt, ...) 23290111Simp{ 2331556Srgrimes va_list ap; 2341556Srgrimes 2351556Srgrimes va_start(ap, fmt); 2361556Srgrimes doformat(file, fmt, ap); 2371556Srgrimes va_end(ap); 2381556Srgrimes} 2391556Srgrimes 2401556Srgrimes 2411556Srgrimesvoid 24290111Simpout1fmt(const char *fmt, ...) 24390111Simp{ 2441556Srgrimes va_list ap; 2451556Srgrimes 2461556Srgrimes va_start(ap, fmt); 2471556Srgrimes doformat(out1, fmt, ap); 2481556Srgrimes va_end(ap); 2491556Srgrimes} 2501556Srgrimes 2511556Srgrimesvoid 25290111Simpdprintf(const char *fmt, ...) 25390111Simp{ 2541556Srgrimes va_list ap; 2551556Srgrimes 2561556Srgrimes va_start(ap, fmt); 2571556Srgrimes doformat(out2, fmt, ap); 2581556Srgrimes va_end(ap); 2591556Srgrimes flushout(out2); 2601556Srgrimes} 2611556Srgrimes 2621556Srgrimesvoid 26390111Simpfmtstr(char *outbuf, int length, const char *fmt, ...) 26490111Simp{ 2651556Srgrimes va_list ap; 2661556Srgrimes 2671556Srgrimes va_start(ap, fmt); 268104286Stjr snprintf(outbuf, length, fmt, ap); 269104286Stjr va_end(ap); 2701556Srgrimes} 2711556Srgrimes 272104286Stjrstatic int 273104286Stjrdoformat_wr(void *cookie, const char *buf, int len) 274104286Stjr{ 275104286Stjr struct output *o; 276104286Stjr int origlen; 277104286Stjr unsigned char c; 2781556Srgrimes 279104286Stjr o = (struct output *)cookie; 280104286Stjr origlen = len; 281104286Stjr while (len-- != 0) { 282104286Stjr c = (unsigned char)*buf++; 283104286Stjr outc(c, o); 284104286Stjr } 2851556Srgrimes 286104286Stjr return (origlen); 287104286Stjr} 2881556Srgrimes 2891556Srgrimesvoid 29090111Simpdoformat(struct output *dest, const char *f, va_list ap) 29190111Simp{ 292104286Stjr FILE *fp; 2931556Srgrimes 294104286Stjr if ((fp = fwopen(dest, doformat_wr)) != NULL) { 295104286Stjr vfprintf(fp, f, ap); 296104286Stjr fclose(fp); 2971556Srgrimes } 2981556Srgrimes} 2991556Srgrimes 3001556Srgrimes/* 3011556Srgrimes * Version of write which resumes after a signal is caught. 3021556Srgrimes */ 3031556Srgrimes 3041556Srgrimesint 30590111Simpxwrite(int fd, char *buf, int nbytes) 30690111Simp{ 3071556Srgrimes int ntry; 3081556Srgrimes int i; 3091556Srgrimes int n; 3101556Srgrimes 3111556Srgrimes n = nbytes; 3121556Srgrimes ntry = 0; 3131556Srgrimes for (;;) { 3141556Srgrimes i = write(fd, buf, n); 3151556Srgrimes if (i > 0) { 3161556Srgrimes if ((n -= i) <= 0) 3171556Srgrimes return nbytes; 3181556Srgrimes buf += i; 3191556Srgrimes ntry = 0; 3201556Srgrimes } else if (i == 0) { 3211556Srgrimes if (++ntry > 10) 3221556Srgrimes return nbytes - n; 3231556Srgrimes } else if (errno != EINTR) { 3241556Srgrimes return -1; 3251556Srgrimes } 3261556Srgrimes } 3271556Srgrimes} 328