/*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)output.c 8.2 (Berkeley) 5/4/95 * $FreeBSD: src/bin/sh/output.c,v 1.20 2005/12/08 21:00:39 stefanf Exp $ * $DragonFly: src/bin/sh/output.c,v 1.4 2007/01/14 05:12:40 pavalos Exp $ */ /* * Shell output routines. We use our own output routines because: * When a builtin command is interrupted we have to discard * any pending output. * When a builtin command appears in back quotes, we want to * save the output of the command in a region obtained * via malloc, rather than doing a fork and reading the * output of the command via a pipe. */ #include /* defines BUFSIZ */ #include #include #include #include #include #include "shell.h" #include "syntax.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "var.h" #define OUTBUFSIZ BUFSIZ #define BLOCK_OUT -2 /* output to a fixed block of memory */ #define MEM_OUT -3 /* output to dynamically allocated memory */ #define OUTPUT_ERR 01 /* error occurred on output */ static int doformat_wr(void *, const char *, int); struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; struct output errout = {NULL, 0, NULL, 100, 2, 0}; struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; struct output *out1 = &output; struct output *out2 = &errout; #ifdef mkinit INCLUDE "output.h" INCLUDE "memalloc.h" RESET { out1 = &output; out2 = &errout; if (memout.buf != NULL) { ckfree(memout.buf); memout.buf = NULL; } } #endif void out1str(const char *p) { outstr(p, out1); } void out1qstr(const char *p) { outqstr(p, out1); } void out2str(const char *p) { outstr(p, out2); } void out2qstr(const char *p) { outqstr(p, out2); } void outstr(const char *p, struct output *file) { while (*p) outc(*p++, file); if (file == out2) flushout(file); } /* Like outstr(), but quote for re-input into the shell. */ void outqstr(const char *p, struct output *file) { char ch; if (p[0] == '\0') { outstr("''", file); return; } if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() || p[strcspn(p, ifsval())] == '\0')) { outstr(p, file); return; } out1c('\''); while ((ch = *p++) != '\0') { switch (ch) { case '\'': /* * Can't quote single quotes inside single quotes; * close them, write escaped single quote, open again. */ outstr("'\\''", file); break; default: outc(ch, file); } } out1c('\''); } STATIC char out_junk[16]; void emptyoutbuf(struct output *dest) { int offset; if (dest->fd == BLOCK_OUT) { dest->nextc = out_junk; dest->nleft = sizeof out_junk; dest->flags |= OUTPUT_ERR; } else if (dest->buf == NULL) { INTOFF; dest->buf = ckmalloc(dest->bufsize); dest->nextc = dest->buf; dest->nleft = dest->bufsize; INTON; } else if (dest->fd == MEM_OUT) { offset = dest->bufsize; INTOFF; dest->bufsize <<= 1; dest->buf = ckrealloc(dest->buf, dest->bufsize); dest->nleft = dest->bufsize - offset; dest->nextc = dest->buf + offset; INTON; } else { flushout(dest); } dest->nleft--; } void flushall(void) { flushout(&output); flushout(&errout); } void flushout(struct output *dest) { if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) return; if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) dest->flags |= OUTPUT_ERR; dest->nextc = dest->buf; dest->nleft = dest->bufsize; } void freestdout(void) { INTOFF; if (output.buf) { ckfree(output.buf); output.buf = NULL; output.nleft = 0; } INTON; } void outfmt(struct output *file, const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(file, fmt, ap); va_end(ap); } void out1fmt(const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(out1, fmt, ap); va_end(ap); } void dprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); doformat(out2, fmt, ap); va_end(ap); flushout(out2); } void fmtstr(char *outbuf, int length, const char *fmt, ...) { va_list ap; struct output strout; strout.nextc = outbuf; strout.nleft = length; strout.fd = BLOCK_OUT; strout.flags = 0; va_start(ap, fmt); doformat(&strout, fmt, ap); va_end(ap); outc('\0', &strout); if (strout.flags & OUTPUT_ERR) outbuf[length - 1] = '\0'; } static int doformat_wr(void *cookie, const char *buf, int len) { struct output *o; int origlen; unsigned char c; o = (struct output *)cookie; origlen = len; while (len-- != 0) { c = (unsigned char)*buf++; outc(c, o); } return (origlen); } void doformat(struct output *dest, const char *f, va_list ap) { FILE *fp; if ((fp = fwopen(dest, doformat_wr)) != NULL) { vfprintf(fp, f, ap); fclose(fp); } } /* * Version of write which resumes after a signal is caught. */ int xwrite(int fd, char *buf, int nbytes) { int ntry; int i; int n; n = nbytes; ntry = 0; for (;;) { i = write(fd, buf, n); if (i > 0) { if ((n -= i) <= 0) return nbytes; buf += i; ntry = 0; } else if (i == 0) { if (++ntry > 10) return nbytes - n; } else if (errno != EINTR) { return -1; } } }