14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1991, 1993 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 64b88c807SRodney W. Grimes * Kenneth Almquist. 74b88c807SRodney W. Grimes * 84b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 94b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 104b88c807SRodney W. Grimes * are met: 114b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 124b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 134b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 154b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 16*fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 184b88c807SRodney W. Grimes * without specific prior written permission. 194b88c807SRodney W. Grimes * 204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304b88c807SRodney W. Grimes * SUCH DAMAGE. 314b88c807SRodney W. Grimes */ 324b88c807SRodney W. Grimes 334b88c807SRodney W. Grimes #ifndef lint 343d7b5b93SPhilippe Charnier #if 0 353d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 363d7b5b93SPhilippe Charnier #endif 374b88c807SRodney W. Grimes #endif /* not lint */ 382749b141SDavid E. O'Brien #include <sys/cdefs.h> 392749b141SDavid E. O'Brien __FBSDID("$FreeBSD$"); 404b88c807SRodney W. Grimes 414b88c807SRodney W. Grimes /* 424b88c807SRodney W. Grimes * Shell output routines. We use our own output routines because: 434b88c807SRodney W. Grimes * When a builtin command is interrupted we have to discard 444b88c807SRodney W. Grimes * any pending output. 454b88c807SRodney W. Grimes * When a builtin command appears in back quotes, we want to 464b88c807SRodney W. Grimes * save the output of the command in a region obtained 474b88c807SRodney W. Grimes * via malloc, rather than doing a fork and reading the 484b88c807SRodney W. Grimes * output of the command via a pipe. 494b88c807SRodney W. Grimes */ 504b88c807SRodney W. Grimes 514b88c807SRodney W. Grimes #include <stdio.h> /* defines BUFSIZ */ 52aa9caaf6SPeter Wemm #include <string.h> 53aa9caaf6SPeter Wemm #include <stdarg.h> 54aa9caaf6SPeter Wemm #include <errno.h> 55aa9caaf6SPeter Wemm #include <unistd.h> 56aa9caaf6SPeter Wemm #include <stdlib.h> 5788ef06f3SJilles Tjoelker #include <wchar.h> 5888ef06f3SJilles Tjoelker #include <wctype.h> 59aa9caaf6SPeter Wemm 604b88c807SRodney W. Grimes #include "shell.h" 614b88c807SRodney W. Grimes #include "syntax.h" 624b88c807SRodney W. Grimes #include "output.h" 634b88c807SRodney W. Grimes #include "memalloc.h" 644b88c807SRodney W. Grimes #include "error.h" 65dee75cf7STim J. Robbins #include "var.h" 664b88c807SRodney W. Grimes 674b88c807SRodney W. Grimes 684b88c807SRodney W. Grimes #define OUTBUFSIZ BUFSIZ 696903c683SJilles Tjoelker #define MEM_OUT -2 /* output to dynamically allocated memory */ 704b88c807SRodney W. Grimes #define OUTPUT_ERR 01 /* error occurred on output */ 714b88c807SRodney W. Grimes 7288328642SDavid E. O'Brien static int doformat_wr(void *, const char *, int); 734b88c807SRodney W. Grimes 744b88c807SRodney W. Grimes struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 75c6204d4aSJilles Tjoelker struct output errout = {NULL, 0, NULL, 256, 2, 0}; 764b88c807SRodney W. Grimes struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 774b88c807SRodney W. Grimes struct output *out1 = &output; 784b88c807SRodney W. Grimes struct output *out2 = &errout; 794b88c807SRodney W. Grimes 804b88c807SRodney W. Grimes void 81aeb5d065SJilles Tjoelker outcslow(int c, struct output *file) 82aeb5d065SJilles Tjoelker { 83aeb5d065SJilles Tjoelker outc(c, file); 84aeb5d065SJilles Tjoelker } 85aeb5d065SJilles Tjoelker 86aeb5d065SJilles Tjoelker void 875134c3f7SWarner Losh out1str(const char *p) 884b88c807SRodney W. Grimes { 894b88c807SRodney W. Grimes outstr(p, out1); 904b88c807SRodney W. Grimes } 914b88c807SRodney W. Grimes 92e5341cbbSTim J. Robbins void 93e5341cbbSTim J. Robbins out1qstr(const char *p) 94e5341cbbSTim J. Robbins { 95e5341cbbSTim J. Robbins outqstr(p, out1); 96e5341cbbSTim J. Robbins } 974b88c807SRodney W. Grimes 984b88c807SRodney W. Grimes void 995134c3f7SWarner Losh out2str(const char *p) 1004b88c807SRodney W. Grimes { 1014b88c807SRodney W. Grimes outstr(p, out2); 1024b88c807SRodney W. Grimes } 1034b88c807SRodney W. Grimes 104e5341cbbSTim J. Robbins void 105e5341cbbSTim J. Robbins out2qstr(const char *p) 106e5341cbbSTim J. Robbins { 107e5341cbbSTim J. Robbins outqstr(p, out2); 108e5341cbbSTim J. Robbins } 1094b88c807SRodney W. Grimes 1104b88c807SRodney W. Grimes void 1115134c3f7SWarner Losh outstr(const char *p, struct output *file) 1124b88c807SRodney W. Grimes { 113c3f57269SJilles Tjoelker outbin(p, strlen(p), file); 1144b88c807SRodney W. Grimes } 1154b88c807SRodney W. Grimes 11688ef06f3SJilles Tjoelker static void 11788ef06f3SJilles Tjoelker byteseq(int ch, struct output *file) 11888ef06f3SJilles Tjoelker { 11988ef06f3SJilles Tjoelker char seq[4]; 12088ef06f3SJilles Tjoelker 12188ef06f3SJilles Tjoelker seq[0] = '\\'; 12288ef06f3SJilles Tjoelker seq[1] = (ch >> 6 & 0x3) + '0'; 12388ef06f3SJilles Tjoelker seq[2] = (ch >> 3 & 0x7) + '0'; 12488ef06f3SJilles Tjoelker seq[3] = (ch & 0x7) + '0'; 12588ef06f3SJilles Tjoelker outbin(seq, 4, file); 12688ef06f3SJilles Tjoelker } 12788ef06f3SJilles Tjoelker 12888ef06f3SJilles Tjoelker static void 12988ef06f3SJilles Tjoelker outdqstr(const char *p, struct output *file) 13088ef06f3SJilles Tjoelker { 13188ef06f3SJilles Tjoelker const char *end; 13288ef06f3SJilles Tjoelker mbstate_t mbs; 13388ef06f3SJilles Tjoelker size_t clen; 13488ef06f3SJilles Tjoelker wchar_t wc; 13588ef06f3SJilles Tjoelker 13688ef06f3SJilles Tjoelker memset(&mbs, '\0', sizeof(mbs)); 13788ef06f3SJilles Tjoelker end = p + strlen(p); 13888ef06f3SJilles Tjoelker outstr("$'", file); 13988ef06f3SJilles Tjoelker while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) { 14088ef06f3SJilles Tjoelker if (clen == (size_t)-2) { 14188ef06f3SJilles Tjoelker while (p < end) 14288ef06f3SJilles Tjoelker byteseq(*p++, file); 14388ef06f3SJilles Tjoelker break; 14488ef06f3SJilles Tjoelker } 14588ef06f3SJilles Tjoelker if (clen == (size_t)-1) { 14688ef06f3SJilles Tjoelker memset(&mbs, '\0', sizeof(mbs)); 14788ef06f3SJilles Tjoelker byteseq(*p++, file); 14888ef06f3SJilles Tjoelker continue; 14988ef06f3SJilles Tjoelker } 15088ef06f3SJilles Tjoelker if (wc == L'\n') 15188ef06f3SJilles Tjoelker outcslow('\n', file), p++; 15288ef06f3SJilles Tjoelker else if (wc == L'\r') 15388ef06f3SJilles Tjoelker outstr("\\r", file), p++; 15488ef06f3SJilles Tjoelker else if (wc == L'\t') 15588ef06f3SJilles Tjoelker outstr("\\t", file), p++; 15688ef06f3SJilles Tjoelker else if (!iswprint(wc)) { 15788ef06f3SJilles Tjoelker for (; clen > 0; clen--) 15888ef06f3SJilles Tjoelker byteseq(*p++, file); 15988ef06f3SJilles Tjoelker } else { 16088ef06f3SJilles Tjoelker if (wc == L'\'' || wc == L'\\') 16188ef06f3SJilles Tjoelker outcslow('\\', file); 16288ef06f3SJilles Tjoelker outbin(p, clen, file); 16388ef06f3SJilles Tjoelker p += clen; 16488ef06f3SJilles Tjoelker } 16588ef06f3SJilles Tjoelker } 16688ef06f3SJilles Tjoelker outcslow('\'', file); 16788ef06f3SJilles Tjoelker } 16888ef06f3SJilles Tjoelker 169e5341cbbSTim J. Robbins /* Like outstr(), but quote for re-input into the shell. */ 170e5341cbbSTim J. Robbins void 171e5341cbbSTim J. Robbins outqstr(const char *p, struct output *file) 172e5341cbbSTim J. Robbins { 17388ef06f3SJilles Tjoelker int i; 174e5341cbbSTim J. Robbins 1753f0131f6SStefan Farfeleder if (p[0] == '\0') { 1763f0131f6SStefan Farfeleder outstr("''", file); 1773f0131f6SStefan Farfeleder return; 1783f0131f6SStefan Farfeleder } 17988ef06f3SJilles Tjoelker for (i = 0; p[i] != '\0'; i++) { 18088ef06f3SJilles Tjoelker if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') || 18188ef06f3SJilles Tjoelker (p[i] & 0x80) != 0 || p[i] == '\'') { 18288ef06f3SJilles Tjoelker outdqstr(p, file); 18388ef06f3SJilles Tjoelker return; 18488ef06f3SJilles Tjoelker } 18588ef06f3SJilles Tjoelker } 18688ef06f3SJilles Tjoelker 18788ef06f3SJilles Tjoelker if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' || 188e68165a6SJilles Tjoelker strcmp(p, "[") == 0) { 189dee75cf7STim J. Robbins outstr(p, file); 190dee75cf7STim J. Robbins return; 191dee75cf7STim J. Robbins } 192dee75cf7STim J. Robbins 193aeb5d065SJilles Tjoelker outcslow('\'', file); 19488ef06f3SJilles Tjoelker outstr(p, file); 195aeb5d065SJilles Tjoelker outcslow('\'', file); 196e5341cbbSTim J. Robbins } 1974b88c807SRodney W. Grimes 198c3f57269SJilles Tjoelker void 199c3f57269SJilles Tjoelker outbin(const void *data, size_t len, struct output *file) 200c3f57269SJilles Tjoelker { 201c3f57269SJilles Tjoelker const char *p; 202c3f57269SJilles Tjoelker 203c3f57269SJilles Tjoelker p = data; 204c3f57269SJilles Tjoelker while (len-- > 0) 205c3f57269SJilles Tjoelker outc(*p++, file); 206c3f57269SJilles Tjoelker } 207c3f57269SJilles Tjoelker 2084b88c807SRodney W. Grimes void 2095134c3f7SWarner Losh emptyoutbuf(struct output *dest) 2104b88c807SRodney W. Grimes { 2114b88c807SRodney W. Grimes int offset; 2124b88c807SRodney W. Grimes 2136903c683SJilles Tjoelker if (dest->buf == NULL) { 2144b88c807SRodney W. Grimes INTOFF; 2154b88c807SRodney W. Grimes dest->buf = ckmalloc(dest->bufsize); 2164b88c807SRodney W. Grimes dest->nextc = dest->buf; 2174b88c807SRodney W. Grimes dest->nleft = dest->bufsize; 2184b88c807SRodney W. Grimes INTON; 2194b88c807SRodney W. Grimes } else if (dest->fd == MEM_OUT) { 2204b88c807SRodney W. Grimes offset = dest->bufsize; 2214b88c807SRodney W. Grimes INTOFF; 2224b88c807SRodney W. Grimes dest->bufsize <<= 1; 2234b88c807SRodney W. Grimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 2244b88c807SRodney W. Grimes dest->nleft = dest->bufsize - offset; 2254b88c807SRodney W. Grimes dest->nextc = dest->buf + offset; 2264b88c807SRodney W. Grimes INTON; 2274b88c807SRodney W. Grimes } else { 2284b88c807SRodney W. Grimes flushout(dest); 2294b88c807SRodney W. Grimes } 2304b88c807SRodney W. Grimes dest->nleft--; 2314b88c807SRodney W. Grimes } 2324b88c807SRodney W. Grimes 2334b88c807SRodney W. Grimes 2344b88c807SRodney W. Grimes void 2355134c3f7SWarner Losh flushall(void) 2365134c3f7SWarner Losh { 2374b88c807SRodney W. Grimes flushout(&output); 2384b88c807SRodney W. Grimes flushout(&errout); 2394b88c807SRodney W. Grimes } 2404b88c807SRodney W. Grimes 2414b88c807SRodney W. Grimes 2424b88c807SRodney W. Grimes void 2435134c3f7SWarner Losh flushout(struct output *dest) 2444b88c807SRodney W. Grimes { 2454b88c807SRodney W. Grimes 2464b88c807SRodney W. Grimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 2474b88c807SRodney W. Grimes return; 2484b88c807SRodney W. Grimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2494b88c807SRodney W. Grimes dest->flags |= OUTPUT_ERR; 2504b88c807SRodney W. Grimes dest->nextc = dest->buf; 2514b88c807SRodney W. Grimes dest->nleft = dest->bufsize; 2524b88c807SRodney W. Grimes } 2534b88c807SRodney W. Grimes 2544b88c807SRodney W. Grimes 2554b88c807SRodney W. Grimes void 2565134c3f7SWarner Losh freestdout(void) 2575134c3f7SWarner Losh { 2584b88c807SRodney W. Grimes INTOFF; 2594b88c807SRodney W. Grimes if (output.buf) { 2604b88c807SRodney W. Grimes ckfree(output.buf); 2614b88c807SRodney W. Grimes output.buf = NULL; 2624b88c807SRodney W. Grimes output.nleft = 0; 2634b88c807SRodney W. Grimes } 2644b88c807SRodney W. Grimes INTON; 2654b88c807SRodney W. Grimes } 2664b88c807SRodney W. Grimes 2674b88c807SRodney W. Grimes 268d6d66cfcSJilles Tjoelker int 269d6d66cfcSJilles Tjoelker outiserror(struct output *file) 270d6d66cfcSJilles Tjoelker { 271d6d66cfcSJilles Tjoelker return (file->flags & OUTPUT_ERR); 272d6d66cfcSJilles Tjoelker } 273d6d66cfcSJilles Tjoelker 274d6d66cfcSJilles Tjoelker 275d6d66cfcSJilles Tjoelker void 276d6d66cfcSJilles Tjoelker outclearerror(struct output *file) 277d6d66cfcSJilles Tjoelker { 278d6d66cfcSJilles Tjoelker file->flags &= ~OUTPUT_ERR; 279d6d66cfcSJilles Tjoelker } 280d6d66cfcSJilles Tjoelker 281d6d66cfcSJilles Tjoelker 2824b88c807SRodney W. Grimes void 2835134c3f7SWarner Losh outfmt(struct output *file, const char *fmt, ...) 2845134c3f7SWarner Losh { 2854b88c807SRodney W. Grimes va_list ap; 2864b88c807SRodney W. Grimes 2874b88c807SRodney W. Grimes va_start(ap, fmt); 2884b88c807SRodney W. Grimes doformat(file, fmt, ap); 2894b88c807SRodney W. Grimes va_end(ap); 2904b88c807SRodney W. Grimes } 2914b88c807SRodney W. Grimes 2924b88c807SRodney W. Grimes 2934b88c807SRodney W. Grimes void 2945134c3f7SWarner Losh out1fmt(const char *fmt, ...) 2955134c3f7SWarner Losh { 2964b88c807SRodney W. Grimes va_list ap; 2974b88c807SRodney W. Grimes 2984b88c807SRodney W. Grimes va_start(ap, fmt); 2994b88c807SRodney W. Grimes doformat(out1, fmt, ap); 3004b88c807SRodney W. Grimes va_end(ap); 3014b88c807SRodney W. Grimes } 3024b88c807SRodney W. Grimes 3034b88c807SRodney W. Grimes void 304c6204d4aSJilles Tjoelker out2fmt_flush(const char *fmt, ...) 3055134c3f7SWarner Losh { 3064b88c807SRodney W. Grimes va_list ap; 3074b88c807SRodney W. Grimes 3084b88c807SRodney W. Grimes va_start(ap, fmt); 3094b88c807SRodney W. Grimes doformat(out2, fmt, ap); 3104b88c807SRodney W. Grimes va_end(ap); 3114b88c807SRodney W. Grimes flushout(out2); 3124b88c807SRodney W. Grimes } 3134b88c807SRodney W. Grimes 3144b88c807SRodney W. Grimes void 3155134c3f7SWarner Losh fmtstr(char *outbuf, int length, const char *fmt, ...) 3165134c3f7SWarner Losh { 3174b88c807SRodney W. Grimes va_list ap; 3184b88c807SRodney W. Grimes 3196903c683SJilles Tjoelker INTOFF; 3204b88c807SRodney W. Grimes va_start(ap, fmt); 3216903c683SJilles Tjoelker vsnprintf(outbuf, length, fmt, ap); 3227e73d40eSTim J. Robbins va_end(ap); 3236903c683SJilles Tjoelker INTON; 3244b88c807SRodney W. Grimes } 3254b88c807SRodney W. Grimes 32688328642SDavid E. O'Brien static int 3277e73d40eSTim J. Robbins doformat_wr(void *cookie, const char *buf, int len) 3287e73d40eSTim J. Robbins { 3297e73d40eSTim J. Robbins struct output *o; 3304b88c807SRodney W. Grimes 3317e73d40eSTim J. Robbins o = (struct output *)cookie; 332c3f57269SJilles Tjoelker outbin(buf, len, o); 3334b88c807SRodney W. Grimes 334c3f57269SJilles Tjoelker return (len); 3357e73d40eSTim J. Robbins } 3364b88c807SRodney W. Grimes 3374b88c807SRodney W. Grimes void 3385134c3f7SWarner Losh doformat(struct output *dest, const char *f, va_list ap) 3394b88c807SRodney W. Grimes { 3407e73d40eSTim J. Robbins FILE *fp; 3414b88c807SRodney W. Grimes 3427e73d40eSTim J. Robbins if ((fp = fwopen(dest, doformat_wr)) != NULL) { 3437e73d40eSTim J. Robbins vfprintf(fp, f, ap); 3447e73d40eSTim J. Robbins fclose(fp); 3454b88c807SRodney W. Grimes } 3464b88c807SRodney W. Grimes } 3474b88c807SRodney W. Grimes 3484b88c807SRodney W. Grimes /* 3494b88c807SRodney W. Grimes * Version of write which resumes after a signal is caught. 3504b88c807SRodney W. Grimes */ 3514b88c807SRodney W. Grimes 3524b88c807SRodney W. Grimes int 3532cac6e36SJilles Tjoelker xwrite(int fd, const char *buf, int nbytes) 3544b88c807SRodney W. Grimes { 3554b88c807SRodney W. Grimes int ntry; 3564b88c807SRodney W. Grimes int i; 3574b88c807SRodney W. Grimes int n; 3584b88c807SRodney W. Grimes 3594b88c807SRodney W. Grimes n = nbytes; 3604b88c807SRodney W. Grimes ntry = 0; 3614b88c807SRodney W. Grimes for (;;) { 3624b88c807SRodney W. Grimes i = write(fd, buf, n); 3634b88c807SRodney W. Grimes if (i > 0) { 3644b88c807SRodney W. Grimes if ((n -= i) <= 0) 3654b88c807SRodney W. Grimes return nbytes; 3664b88c807SRodney W. Grimes buf += i; 3674b88c807SRodney W. Grimes ntry = 0; 3684b88c807SRodney W. Grimes } else if (i == 0) { 3694b88c807SRodney W. Grimes if (++ntry > 10) 3704b88c807SRodney W. Grimes return nbytes - n; 3714b88c807SRodney W. Grimes } else if (errno != EINTR) { 3724b88c807SRodney W. Grimes return -1; 3734b88c807SRodney W. Grimes } 3744b88c807SRodney W. Grimes } 3754b88c807SRodney W. Grimes } 376