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 * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3436150Scharnier#if 0 3536150Scharnierstatic char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 3636150Scharnier#endif 371556Srgrimes#endif /* not lint */ 3899110Sobrien#include <sys/cdefs.h> 3999110Sobrien__FBSDID("$FreeBSD$"); 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 */ 501556Srgrimes 511556Srgrimes#include <stdio.h> /* defines BUFSIZ */ 5217987Speter#include <string.h> 5317987Speter#include <stdarg.h> 541556Srgrimes#include <errno.h> 5517987Speter#include <unistd.h> 5617987Speter#include <stdlib.h> 571556Srgrimes 5817987Speter#include "shell.h" 5917987Speter#include "syntax.h" 6017987Speter#include "output.h" 6117987Speter#include "memalloc.h" 6217987Speter#include "error.h" 6397909Stjr#include "var.h" 641556Srgrimes 6517987Speter 661556Srgrimes#define OUTBUFSIZ BUFSIZ 67216380Sjilles#define MEM_OUT -2 /* output to dynamically allocated memory */ 681556Srgrimes#define OUTPUT_ERR 01 /* error occurred on output */ 691556Srgrimes 70213811Sobrienstatic int doformat_wr(void *, const char *, int); 711556Srgrimes 721556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 73199629Sjillesstruct output errout = {NULL, 0, NULL, 256, 2, 0}; 741556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 751556Srgrimesstruct output *out1 = &output; 761556Srgrimesstruct output *out2 = &errout; 771556Srgrimes 781556Srgrimesvoid 79215567Sjillesoutcslow(int c, struct output *file) 80215567Sjilles{ 81215567Sjilles outc(c, file); 82215567Sjilles} 83215567Sjilles 84215567Sjillesvoid 8590111Simpout1str(const char *p) 8690111Simp{ 871556Srgrimes outstr(p, out1); 881556Srgrimes} 891556Srgrimes 9097815Stjrvoid 9197815Stjrout1qstr(const char *p) 9297815Stjr{ 9397815Stjr outqstr(p, out1); 9497815Stjr} 951556Srgrimes 961556Srgrimesvoid 9790111Simpout2str(const char *p) 9890111Simp{ 991556Srgrimes outstr(p, out2); 1001556Srgrimes} 1011556Srgrimes 10297815Stjrvoid 10397815Stjrout2qstr(const char *p) 10497815Stjr{ 10597815Stjr outqstr(p, out2); 10697815Stjr} 1071556Srgrimes 1081556Srgrimesvoid 10990111Simpoutstr(const char *p, struct output *file) 11090111Simp{ 111215303Sjilles outbin(p, strlen(p), file); 1121556Srgrimes} 1131556Srgrimes 11497815Stjr/* Like outstr(), but quote for re-input into the shell. */ 11597815Stjrvoid 11697815Stjroutqstr(const char *p, struct output *file) 11797815Stjr{ 11897815Stjr char ch; 119194516Sjilles int inquotes; 1201556Srgrimes 121153245Sstefanf if (p[0] == '\0') { 122153245Sstefanf outstr("''", file); 123153245Sstefanf return; 124153245Sstefanf } 125194516Sjilles /* Caller will handle '=' if necessary */ 126194516Sjilles if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' || 127194516Sjilles strcmp(p, "[") == 0) { 12897909Stjr outstr(p, file); 12997909Stjr return; 13097909Stjr } 13197909Stjr 132194516Sjilles inquotes = 0; 13397815Stjr while ((ch = *p++) != '\0') { 13497815Stjr switch (ch) { 13597815Stjr case '\'': 136194516Sjilles /* Can't quote single quotes inside single quotes. */ 137194516Sjilles if (inquotes) 138215567Sjilles outcslow('\'', file); 139194516Sjilles inquotes = 0; 140194516Sjilles outstr("\\'", file); 14197815Stjr break; 14297815Stjr default: 143194516Sjilles if (!inquotes) 144215567Sjilles outcslow('\'', file); 145194516Sjilles inquotes = 1; 14697815Stjr outc(ch, file); 14797815Stjr } 14897815Stjr } 149194516Sjilles if (inquotes) 150215567Sjilles outcslow('\'', file); 15197815Stjr} 15297815Stjr 153215303Sjillesvoid 154215303Sjillesoutbin(const void *data, size_t len, struct output *file) 155215303Sjilles{ 156215303Sjilles const char *p; 157215303Sjilles 158215303Sjilles p = data; 159215303Sjilles while (len-- > 0) 160215303Sjilles outc(*p++, file); 161215303Sjilles} 162215303Sjilles 1631556Srgrimesvoid 16490111Simpemptyoutbuf(struct output *dest) 16590111Simp{ 1661556Srgrimes int offset; 1671556Srgrimes 168216380Sjilles if (dest->buf == NULL) { 1691556Srgrimes INTOFF; 1701556Srgrimes dest->buf = ckmalloc(dest->bufsize); 1711556Srgrimes dest->nextc = dest->buf; 1721556Srgrimes dest->nleft = dest->bufsize; 1731556Srgrimes INTON; 1741556Srgrimes } else if (dest->fd == MEM_OUT) { 1751556Srgrimes offset = dest->bufsize; 1761556Srgrimes INTOFF; 1771556Srgrimes dest->bufsize <<= 1; 1781556Srgrimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 1791556Srgrimes dest->nleft = dest->bufsize - offset; 1801556Srgrimes dest->nextc = dest->buf + offset; 1811556Srgrimes INTON; 1821556Srgrimes } else { 1831556Srgrimes flushout(dest); 1841556Srgrimes } 1851556Srgrimes dest->nleft--; 1861556Srgrimes} 1871556Srgrimes 1881556Srgrimes 1891556Srgrimesvoid 19090111Simpflushall(void) 19190111Simp{ 1921556Srgrimes flushout(&output); 1931556Srgrimes flushout(&errout); 1941556Srgrimes} 1951556Srgrimes 1961556Srgrimes 1971556Srgrimesvoid 19890111Simpflushout(struct output *dest) 19990111Simp{ 2001556Srgrimes 2011556Srgrimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 2021556Srgrimes return; 2031556Srgrimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2041556Srgrimes dest->flags |= OUTPUT_ERR; 2051556Srgrimes dest->nextc = dest->buf; 2061556Srgrimes dest->nleft = dest->bufsize; 2071556Srgrimes} 2081556Srgrimes 2091556Srgrimes 2101556Srgrimesvoid 21190111Simpfreestdout(void) 21290111Simp{ 2131556Srgrimes INTOFF; 2141556Srgrimes if (output.buf) { 2151556Srgrimes ckfree(output.buf); 2161556Srgrimes output.buf = NULL; 2171556Srgrimes output.nleft = 0; 2181556Srgrimes } 2191556Srgrimes INTON; 2201556Srgrimes} 2211556Srgrimes 2221556Srgrimes 223244162Sjillesint 224244162Sjillesoutiserror(struct output *file) 225244162Sjilles{ 226244162Sjilles return (file->flags & OUTPUT_ERR); 227244162Sjilles} 228244162Sjilles 229244162Sjilles 2301556Srgrimesvoid 231244162Sjillesoutclearerror(struct output *file) 232244162Sjilles{ 233244162Sjilles file->flags &= ~OUTPUT_ERR; 234244162Sjilles} 235244162Sjilles 236244162Sjilles 237244162Sjillesvoid 23890111Simpoutfmt(struct output *file, const char *fmt, ...) 23990111Simp{ 2401556Srgrimes va_list ap; 2411556Srgrimes 2421556Srgrimes va_start(ap, fmt); 2431556Srgrimes doformat(file, fmt, ap); 2441556Srgrimes va_end(ap); 2451556Srgrimes} 2461556Srgrimes 2471556Srgrimes 2481556Srgrimesvoid 24990111Simpout1fmt(const char *fmt, ...) 25090111Simp{ 2511556Srgrimes va_list ap; 2521556Srgrimes 2531556Srgrimes va_start(ap, fmt); 2541556Srgrimes doformat(out1, fmt, ap); 2551556Srgrimes va_end(ap); 2561556Srgrimes} 2571556Srgrimes 2581556Srgrimesvoid 259199629Sjillesout2fmt_flush(const char *fmt, ...) 26090111Simp{ 2611556Srgrimes va_list ap; 2621556Srgrimes 2631556Srgrimes va_start(ap, fmt); 2641556Srgrimes doformat(out2, fmt, ap); 2651556Srgrimes va_end(ap); 2661556Srgrimes flushout(out2); 2671556Srgrimes} 2681556Srgrimes 2691556Srgrimesvoid 27090111Simpfmtstr(char *outbuf, int length, const char *fmt, ...) 27190111Simp{ 2721556Srgrimes va_list ap; 2731556Srgrimes 274216380Sjilles INTOFF; 2751556Srgrimes va_start(ap, fmt); 276216380Sjilles vsnprintf(outbuf, length, fmt, ap); 277104286Stjr va_end(ap); 278216380Sjilles INTON; 2791556Srgrimes} 2801556Srgrimes 281213811Sobrienstatic int 282104286Stjrdoformat_wr(void *cookie, const char *buf, int len) 283104286Stjr{ 284104286Stjr struct output *o; 2851556Srgrimes 286104286Stjr o = (struct output *)cookie; 287215303Sjilles outbin(buf, len, o); 2881556Srgrimes 289215303Sjilles return (len); 290104286Stjr} 2911556Srgrimes 2921556Srgrimesvoid 29390111Simpdoformat(struct output *dest, const char *f, va_list ap) 29490111Simp{ 295104286Stjr FILE *fp; 2961556Srgrimes 297104286Stjr if ((fp = fwopen(dest, doformat_wr)) != NULL) { 298104286Stjr vfprintf(fp, f, ap); 299104286Stjr fclose(fp); 3001556Srgrimes } 3011556Srgrimes} 3021556Srgrimes 3031556Srgrimes/* 3041556Srgrimes * Version of write which resumes after a signal is caught. 3051556Srgrimes */ 3061556Srgrimes 3071556Srgrimesint 308200956Sjillesxwrite(int fd, const char *buf, int nbytes) 30990111Simp{ 3101556Srgrimes int ntry; 3111556Srgrimes int i; 3121556Srgrimes int n; 3131556Srgrimes 3141556Srgrimes n = nbytes; 3151556Srgrimes ntry = 0; 3161556Srgrimes for (;;) { 3171556Srgrimes i = write(fd, buf, n); 3181556Srgrimes if (i > 0) { 3191556Srgrimes if ((n -= i) <= 0) 3201556Srgrimes return nbytes; 3211556Srgrimes buf += i; 3221556Srgrimes ntry = 0; 3231556Srgrimes } else if (i == 0) { 3241556Srgrimes if (++ntry > 10) 3251556Srgrimes return nbytes - n; 3261556Srgrimes } else if (errno != EINTR) { 3271556Srgrimes return -1; 3281556Srgrimes } 3291556Srgrimes } 3301556Srgrimes} 331