output.c revision 225736
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 36#endif 37#endif /* not lint */ 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: stable/9/bin/sh/output.c 216380 2010-12-11 17:47:27Z jilles $"); 40 41/* 42 * Shell output routines. We use our own output routines because: 43 * When a builtin command is interrupted we have to discard 44 * any pending output. 45 * When a builtin command appears in back quotes, we want to 46 * save the output of the command in a region obtained 47 * via malloc, rather than doing a fork and reading the 48 * output of the command via a pipe. 49 */ 50 51#include <stdio.h> /* defines BUFSIZ */ 52#include <string.h> 53#include <stdarg.h> 54#include <errno.h> 55#include <unistd.h> 56#include <stdlib.h> 57 58#include "shell.h" 59#include "syntax.h" 60#include "output.h" 61#include "memalloc.h" 62#include "error.h" 63#include "var.h" 64 65 66#define OUTBUFSIZ BUFSIZ 67#define MEM_OUT -2 /* output to dynamically allocated memory */ 68#define OUTPUT_ERR 01 /* error occurred on output */ 69 70static int doformat_wr(void *, const char *, int); 71 72struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 73struct output errout = {NULL, 0, NULL, 256, 2, 0}; 74struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 75struct output *out1 = &output; 76struct output *out2 = &errout; 77 78 79 80#ifdef mkinit 81 82INCLUDE "output.h" 83INCLUDE "memalloc.h" 84 85RESET { 86 out1 = &output; 87 out2 = &errout; 88 if (memout.buf != NULL) { 89 ckfree(memout.buf); 90 memout.buf = NULL; 91 } 92} 93 94#endif 95 96 97void 98outcslow(int c, struct output *file) 99{ 100 outc(c, file); 101} 102 103void 104out1str(const char *p) 105{ 106 outstr(p, out1); 107} 108 109void 110out1qstr(const char *p) 111{ 112 outqstr(p, out1); 113} 114 115void 116out2str(const char *p) 117{ 118 outstr(p, out2); 119} 120 121void 122out2qstr(const char *p) 123{ 124 outqstr(p, out2); 125} 126 127void 128outstr(const char *p, struct output *file) 129{ 130 outbin(p, strlen(p), file); 131} 132 133/* Like outstr(), but quote for re-input into the shell. */ 134void 135outqstr(const char *p, struct output *file) 136{ 137 char ch; 138 int inquotes; 139 140 if (p[0] == '\0') { 141 outstr("''", file); 142 return; 143 } 144 /* Caller will handle '=' if necessary */ 145 if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' || 146 strcmp(p, "[") == 0) { 147 outstr(p, file); 148 return; 149 } 150 151 inquotes = 0; 152 while ((ch = *p++) != '\0') { 153 switch (ch) { 154 case '\'': 155 /* Can't quote single quotes inside single quotes. */ 156 if (inquotes) 157 outcslow('\'', file); 158 inquotes = 0; 159 outstr("\\'", file); 160 break; 161 default: 162 if (!inquotes) 163 outcslow('\'', file); 164 inquotes = 1; 165 outc(ch, file); 166 } 167 } 168 if (inquotes) 169 outcslow('\'', file); 170} 171 172void 173outbin(const void *data, size_t len, struct output *file) 174{ 175 const char *p; 176 177 p = data; 178 while (len-- > 0) 179 outc(*p++, file); 180} 181 182void 183emptyoutbuf(struct output *dest) 184{ 185 int offset; 186 187 if (dest->buf == NULL) { 188 INTOFF; 189 dest->buf = ckmalloc(dest->bufsize); 190 dest->nextc = dest->buf; 191 dest->nleft = dest->bufsize; 192 INTON; 193 } else if (dest->fd == MEM_OUT) { 194 offset = dest->bufsize; 195 INTOFF; 196 dest->bufsize <<= 1; 197 dest->buf = ckrealloc(dest->buf, dest->bufsize); 198 dest->nleft = dest->bufsize - offset; 199 dest->nextc = dest->buf + offset; 200 INTON; 201 } else { 202 flushout(dest); 203 } 204 dest->nleft--; 205} 206 207 208void 209flushall(void) 210{ 211 flushout(&output); 212 flushout(&errout); 213} 214 215 216void 217flushout(struct output *dest) 218{ 219 220 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 221 return; 222 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 223 dest->flags |= OUTPUT_ERR; 224 dest->nextc = dest->buf; 225 dest->nleft = dest->bufsize; 226} 227 228 229void 230freestdout(void) 231{ 232 INTOFF; 233 if (output.buf) { 234 ckfree(output.buf); 235 output.buf = NULL; 236 output.nleft = 0; 237 } 238 INTON; 239} 240 241 242void 243outfmt(struct output *file, const char *fmt, ...) 244{ 245 va_list ap; 246 247 va_start(ap, fmt); 248 doformat(file, fmt, ap); 249 va_end(ap); 250} 251 252 253void 254out1fmt(const char *fmt, ...) 255{ 256 va_list ap; 257 258 va_start(ap, fmt); 259 doformat(out1, fmt, ap); 260 va_end(ap); 261} 262 263void 264out2fmt_flush(const char *fmt, ...) 265{ 266 va_list ap; 267 268 va_start(ap, fmt); 269 doformat(out2, fmt, ap); 270 va_end(ap); 271 flushout(out2); 272} 273 274void 275fmtstr(char *outbuf, int length, const char *fmt, ...) 276{ 277 va_list ap; 278 279 INTOFF; 280 va_start(ap, fmt); 281 vsnprintf(outbuf, length, fmt, ap); 282 va_end(ap); 283 INTON; 284} 285 286static int 287doformat_wr(void *cookie, const char *buf, int len) 288{ 289 struct output *o; 290 291 o = (struct output *)cookie; 292 outbin(buf, len, o); 293 294 return (len); 295} 296 297void 298doformat(struct output *dest, const char *f, va_list ap) 299{ 300 FILE *fp; 301 302 if ((fp = fwopen(dest, doformat_wr)) != NULL) { 303 vfprintf(fp, f, ap); 304 fclose(fp); 305 } 306} 307 308/* 309 * Version of write which resumes after a signal is caught. 310 */ 311 312int 313xwrite(int fd, const char *buf, int nbytes) 314{ 315 int ntry; 316 int i; 317 int n; 318 319 n = nbytes; 320 ntry = 0; 321 for (;;) { 322 i = write(fd, buf, n); 323 if (i > 0) { 324 if ((n -= i) <= 0) 325 return nbytes; 326 buf += i; 327 ntry = 0; 328 } else if (i == 0) { 329 if (++ntry > 10) 330 return nbytes - n; 331 } else if (errno != EINTR) { 332 return -1; 333 } 334 } 335} 336