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: releng/11.0/bin/sh/output.c 275766 2014-12-14 16:26:19Z jilles $"); 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> 57275766Sjilles#include <wchar.h> 58275766Sjilles#include <wctype.h> 591556Srgrimes 6017987Speter#include "shell.h" 6117987Speter#include "syntax.h" 6217987Speter#include "output.h" 6317987Speter#include "memalloc.h" 6417987Speter#include "error.h" 6597909Stjr#include "var.h" 661556Srgrimes 6717987Speter 681556Srgrimes#define OUTBUFSIZ BUFSIZ 69216380Sjilles#define MEM_OUT -2 /* output to dynamically allocated memory */ 701556Srgrimes#define OUTPUT_ERR 01 /* error occurred on output */ 711556Srgrimes 72213811Sobrienstatic int doformat_wr(void *, const char *, int); 731556Srgrimes 741556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 75199629Sjillesstruct output errout = {NULL, 0, NULL, 256, 2, 0}; 761556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 771556Srgrimesstruct output *out1 = &output; 781556Srgrimesstruct output *out2 = &errout; 791556Srgrimes 801556Srgrimesvoid 81215567Sjillesoutcslow(int c, struct output *file) 82215567Sjilles{ 83215567Sjilles outc(c, file); 84215567Sjilles} 85215567Sjilles 86215567Sjillesvoid 8790111Simpout1str(const char *p) 8890111Simp{ 891556Srgrimes outstr(p, out1); 901556Srgrimes} 911556Srgrimes 9297815Stjrvoid 9397815Stjrout1qstr(const char *p) 9497815Stjr{ 9597815Stjr outqstr(p, out1); 9697815Stjr} 971556Srgrimes 981556Srgrimesvoid 9990111Simpout2str(const char *p) 10090111Simp{ 1011556Srgrimes outstr(p, out2); 1021556Srgrimes} 1031556Srgrimes 10497815Stjrvoid 10597815Stjrout2qstr(const char *p) 10697815Stjr{ 10797815Stjr outqstr(p, out2); 10897815Stjr} 1091556Srgrimes 1101556Srgrimesvoid 11190111Simpoutstr(const char *p, struct output *file) 11290111Simp{ 113215303Sjilles outbin(p, strlen(p), file); 1141556Srgrimes} 1151556Srgrimes 116275766Sjillesstatic void 117275766Sjillesbyteseq(int ch, struct output *file) 118275766Sjilles{ 119275766Sjilles char seq[4]; 120275766Sjilles 121275766Sjilles seq[0] = '\\'; 122275766Sjilles seq[1] = (ch >> 6 & 0x3) + '0'; 123275766Sjilles seq[2] = (ch >> 3 & 0x7) + '0'; 124275766Sjilles seq[3] = (ch & 0x7) + '0'; 125275766Sjilles outbin(seq, 4, file); 126275766Sjilles} 127275766Sjilles 128275766Sjillesstatic void 129275766Sjillesoutdqstr(const char *p, struct output *file) 130275766Sjilles{ 131275766Sjilles const char *end; 132275766Sjilles mbstate_t mbs; 133275766Sjilles size_t clen; 134275766Sjilles wchar_t wc; 135275766Sjilles 136275766Sjilles memset(&mbs, '\0', sizeof(mbs)); 137275766Sjilles end = p + strlen(p); 138275766Sjilles outstr("$'", file); 139275766Sjilles while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) { 140275766Sjilles if (clen == (size_t)-2) { 141275766Sjilles while (p < end) 142275766Sjilles byteseq(*p++, file); 143275766Sjilles break; 144275766Sjilles } 145275766Sjilles if (clen == (size_t)-1) { 146275766Sjilles memset(&mbs, '\0', sizeof(mbs)); 147275766Sjilles byteseq(*p++, file); 148275766Sjilles continue; 149275766Sjilles } 150275766Sjilles if (wc == L'\n') 151275766Sjilles outcslow('\n', file), p++; 152275766Sjilles else if (wc == L'\r') 153275766Sjilles outstr("\\r", file), p++; 154275766Sjilles else if (wc == L'\t') 155275766Sjilles outstr("\\t", file), p++; 156275766Sjilles else if (!iswprint(wc)) { 157275766Sjilles for (; clen > 0; clen--) 158275766Sjilles byteseq(*p++, file); 159275766Sjilles } else { 160275766Sjilles if (wc == L'\'' || wc == L'\\') 161275766Sjilles outcslow('\\', file); 162275766Sjilles outbin(p, clen, file); 163275766Sjilles p += clen; 164275766Sjilles } 165275766Sjilles } 166275766Sjilles outcslow('\'', file); 167275766Sjilles} 168275766Sjilles 16997815Stjr/* Like outstr(), but quote for re-input into the shell. */ 17097815Stjrvoid 17197815Stjroutqstr(const char *p, struct output *file) 17297815Stjr{ 173275766Sjilles int i; 1741556Srgrimes 175153245Sstefanf if (p[0] == '\0') { 176153245Sstefanf outstr("''", file); 177153245Sstefanf return; 178153245Sstefanf } 179275766Sjilles for (i = 0; p[i] != '\0'; i++) { 180275766Sjilles if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') || 181275766Sjilles (p[i] & 0x80) != 0 || p[i] == '\'') { 182275766Sjilles outdqstr(p, file); 183275766Sjilles return; 184275766Sjilles } 185275766Sjilles } 186275766Sjilles 187275766Sjilles if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' || 188194516Sjilles strcmp(p, "[") == 0) { 18997909Stjr outstr(p, file); 19097909Stjr return; 19197909Stjr } 19297909Stjr 193275766Sjilles outcslow('\'', file); 194275766Sjilles outstr(p, file); 195275766Sjilles outcslow('\'', file); 19697815Stjr} 19797815Stjr 198215303Sjillesvoid 199215303Sjillesoutbin(const void *data, size_t len, struct output *file) 200215303Sjilles{ 201215303Sjilles const char *p; 202215303Sjilles 203215303Sjilles p = data; 204215303Sjilles while (len-- > 0) 205215303Sjilles outc(*p++, file); 206215303Sjilles} 207215303Sjilles 2081556Srgrimesvoid 20990111Simpemptyoutbuf(struct output *dest) 21090111Simp{ 2111556Srgrimes int offset; 2121556Srgrimes 213216380Sjilles if (dest->buf == NULL) { 2141556Srgrimes INTOFF; 2151556Srgrimes dest->buf = ckmalloc(dest->bufsize); 2161556Srgrimes dest->nextc = dest->buf; 2171556Srgrimes dest->nleft = dest->bufsize; 2181556Srgrimes INTON; 2191556Srgrimes } else if (dest->fd == MEM_OUT) { 2201556Srgrimes offset = dest->bufsize; 2211556Srgrimes INTOFF; 2221556Srgrimes dest->bufsize <<= 1; 2231556Srgrimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 2241556Srgrimes dest->nleft = dest->bufsize - offset; 2251556Srgrimes dest->nextc = dest->buf + offset; 2261556Srgrimes INTON; 2271556Srgrimes } else { 2281556Srgrimes flushout(dest); 2291556Srgrimes } 2301556Srgrimes dest->nleft--; 2311556Srgrimes} 2321556Srgrimes 2331556Srgrimes 2341556Srgrimesvoid 23590111Simpflushall(void) 23690111Simp{ 2371556Srgrimes flushout(&output); 2381556Srgrimes flushout(&errout); 2391556Srgrimes} 2401556Srgrimes 2411556Srgrimes 2421556Srgrimesvoid 24390111Simpflushout(struct output *dest) 24490111Simp{ 2451556Srgrimes 2461556Srgrimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 2471556Srgrimes return; 2481556Srgrimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2491556Srgrimes dest->flags |= OUTPUT_ERR; 2501556Srgrimes dest->nextc = dest->buf; 2511556Srgrimes dest->nleft = dest->bufsize; 2521556Srgrimes} 2531556Srgrimes 2541556Srgrimes 2551556Srgrimesvoid 25690111Simpfreestdout(void) 25790111Simp{ 2581556Srgrimes INTOFF; 2591556Srgrimes if (output.buf) { 2601556Srgrimes ckfree(output.buf); 2611556Srgrimes output.buf = NULL; 2621556Srgrimes output.nleft = 0; 2631556Srgrimes } 2641556Srgrimes INTON; 2651556Srgrimes} 2661556Srgrimes 2671556Srgrimes 268244162Sjillesint 269244162Sjillesoutiserror(struct output *file) 270244162Sjilles{ 271244162Sjilles return (file->flags & OUTPUT_ERR); 272244162Sjilles} 273244162Sjilles 274244162Sjilles 2751556Srgrimesvoid 276244162Sjillesoutclearerror(struct output *file) 277244162Sjilles{ 278244162Sjilles file->flags &= ~OUTPUT_ERR; 279244162Sjilles} 280244162Sjilles 281244162Sjilles 282244162Sjillesvoid 28390111Simpoutfmt(struct output *file, const char *fmt, ...) 28490111Simp{ 2851556Srgrimes va_list ap; 2861556Srgrimes 2871556Srgrimes va_start(ap, fmt); 2881556Srgrimes doformat(file, fmt, ap); 2891556Srgrimes va_end(ap); 2901556Srgrimes} 2911556Srgrimes 2921556Srgrimes 2931556Srgrimesvoid 29490111Simpout1fmt(const char *fmt, ...) 29590111Simp{ 2961556Srgrimes va_list ap; 2971556Srgrimes 2981556Srgrimes va_start(ap, fmt); 2991556Srgrimes doformat(out1, fmt, ap); 3001556Srgrimes va_end(ap); 3011556Srgrimes} 3021556Srgrimes 3031556Srgrimesvoid 304199629Sjillesout2fmt_flush(const char *fmt, ...) 30590111Simp{ 3061556Srgrimes va_list ap; 3071556Srgrimes 3081556Srgrimes va_start(ap, fmt); 3091556Srgrimes doformat(out2, fmt, ap); 3101556Srgrimes va_end(ap); 3111556Srgrimes flushout(out2); 3121556Srgrimes} 3131556Srgrimes 3141556Srgrimesvoid 31590111Simpfmtstr(char *outbuf, int length, const char *fmt, ...) 31690111Simp{ 3171556Srgrimes va_list ap; 3181556Srgrimes 319216380Sjilles INTOFF; 3201556Srgrimes va_start(ap, fmt); 321216380Sjilles vsnprintf(outbuf, length, fmt, ap); 322104286Stjr va_end(ap); 323216380Sjilles INTON; 3241556Srgrimes} 3251556Srgrimes 326213811Sobrienstatic int 327104286Stjrdoformat_wr(void *cookie, const char *buf, int len) 328104286Stjr{ 329104286Stjr struct output *o; 3301556Srgrimes 331104286Stjr o = (struct output *)cookie; 332215303Sjilles outbin(buf, len, o); 3331556Srgrimes 334215303Sjilles return (len); 335104286Stjr} 3361556Srgrimes 3371556Srgrimesvoid 33890111Simpdoformat(struct output *dest, const char *f, va_list ap) 33990111Simp{ 340104286Stjr FILE *fp; 3411556Srgrimes 342104286Stjr if ((fp = fwopen(dest, doformat_wr)) != NULL) { 343104286Stjr vfprintf(fp, f, ap); 344104286Stjr fclose(fp); 3451556Srgrimes } 3461556Srgrimes} 3471556Srgrimes 3481556Srgrimes/* 3491556Srgrimes * Version of write which resumes after a signal is caught. 3501556Srgrimes */ 3511556Srgrimes 3521556Srgrimesint 353200956Sjillesxwrite(int fd, const char *buf, int nbytes) 35490111Simp{ 3551556Srgrimes int ntry; 3561556Srgrimes int i; 3571556Srgrimes int n; 3581556Srgrimes 3591556Srgrimes n = nbytes; 3601556Srgrimes ntry = 0; 3611556Srgrimes for (;;) { 3621556Srgrimes i = write(fd, buf, n); 3631556Srgrimes if (i > 0) { 3641556Srgrimes if ((n -= i) <= 0) 3651556Srgrimes return nbytes; 3661556Srgrimes buf += i; 3671556Srgrimes ntry = 0; 3681556Srgrimes } else if (i == 0) { 3691556Srgrimes if (++ntry > 10) 3701556Srgrimes return nbytes - n; 3711556Srgrimes } else if (errno != EINTR) { 3721556Srgrimes return -1; 3731556Srgrimes } 3741556Srgrimes } 3751556Srgrimes} 376