output.c revision 194516
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: head/bin/sh/output.c 194516 2009-06-19 22:09:55Z 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 BLOCK_OUT -2 /* output to a fixed block of memory */ 68#define MEM_OUT -3 /* output to dynamically allocated memory */ 69#define OUTPUT_ERR 01 /* error occurred on output */ 70 71static int doformat_wr(void *, const char *, int); 72 73struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 74struct output errout = {NULL, 0, NULL, 100, 2, 0}; 75struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 76struct output *out1 = &output; 77struct output *out2 = &errout; 78 79 80 81#ifdef mkinit 82 83INCLUDE "output.h" 84INCLUDE "memalloc.h" 85 86RESET { 87 out1 = &output; 88 out2 = &errout; 89 if (memout.buf != NULL) { 90 ckfree(memout.buf); 91 memout.buf = NULL; 92 } 93} 94 95#endif 96 97 98void 99out1str(const char *p) 100{ 101 outstr(p, out1); 102} 103 104void 105out1qstr(const char *p) 106{ 107 outqstr(p, out1); 108} 109 110void 111out2str(const char *p) 112{ 113 outstr(p, out2); 114} 115 116void 117out2qstr(const char *p) 118{ 119 outqstr(p, out2); 120} 121 122void 123outstr(const char *p, struct output *file) 124{ 125 while (*p) 126 outc(*p++, file); 127 if (file == out2) 128 flushout(file); 129} 130 131/* Like outstr(), but quote for re-input into the shell. */ 132void 133outqstr(const char *p, struct output *file) 134{ 135 char ch; 136 int inquotes; 137 138 if (p[0] == '\0') { 139 outstr("''", file); 140 return; 141 } 142 /* Caller will handle '=' if necessary */ 143 if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' || 144 strcmp(p, "[") == 0) { 145 outstr(p, file); 146 return; 147 } 148 149 inquotes = 0; 150 while ((ch = *p++) != '\0') { 151 switch (ch) { 152 case '\'': 153 /* Can't quote single quotes inside single quotes. */ 154 if (inquotes) 155 outc('\'', file); 156 inquotes = 0; 157 outstr("\\'", file); 158 break; 159 default: 160 if (!inquotes) 161 outc('\'', file); 162 inquotes = 1; 163 outc(ch, file); 164 } 165 } 166 if (inquotes) 167 outc('\'', file); 168} 169 170STATIC char out_junk[16]; 171 172void 173emptyoutbuf(struct output *dest) 174{ 175 int offset; 176 177 if (dest->fd == BLOCK_OUT) { 178 dest->nextc = out_junk; 179 dest->nleft = sizeof out_junk; 180 dest->flags |= OUTPUT_ERR; 181 } else if (dest->buf == NULL) { 182 INTOFF; 183 dest->buf = ckmalloc(dest->bufsize); 184 dest->nextc = dest->buf; 185 dest->nleft = dest->bufsize; 186 INTON; 187 } else if (dest->fd == MEM_OUT) { 188 offset = dest->bufsize; 189 INTOFF; 190 dest->bufsize <<= 1; 191 dest->buf = ckrealloc(dest->buf, dest->bufsize); 192 dest->nleft = dest->bufsize - offset; 193 dest->nextc = dest->buf + offset; 194 INTON; 195 } else { 196 flushout(dest); 197 } 198 dest->nleft--; 199} 200 201 202void 203flushall(void) 204{ 205 flushout(&output); 206 flushout(&errout); 207} 208 209 210void 211flushout(struct output *dest) 212{ 213 214 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 215 return; 216 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 217 dest->flags |= OUTPUT_ERR; 218 dest->nextc = dest->buf; 219 dest->nleft = dest->bufsize; 220} 221 222 223void 224freestdout(void) 225{ 226 INTOFF; 227 if (output.buf) { 228 ckfree(output.buf); 229 output.buf = NULL; 230 output.nleft = 0; 231 } 232 INTON; 233} 234 235 236void 237outfmt(struct output *file, const char *fmt, ...) 238{ 239 va_list ap; 240 241 va_start(ap, fmt); 242 doformat(file, fmt, ap); 243 va_end(ap); 244} 245 246 247void 248out1fmt(const char *fmt, ...) 249{ 250 va_list ap; 251 252 va_start(ap, fmt); 253 doformat(out1, fmt, ap); 254 va_end(ap); 255} 256 257void 258dprintf(const char *fmt, ...) 259{ 260 va_list ap; 261 262 va_start(ap, fmt); 263 doformat(out2, fmt, ap); 264 va_end(ap); 265 flushout(out2); 266} 267 268void 269fmtstr(char *outbuf, int length, const char *fmt, ...) 270{ 271 va_list ap; 272 struct output strout; 273 274 strout.nextc = outbuf; 275 strout.nleft = length; 276 strout.fd = BLOCK_OUT; 277 strout.flags = 0; 278 va_start(ap, fmt); 279 doformat(&strout, fmt, ap); 280 va_end(ap); 281 outc('\0', &strout); 282 if (strout.flags & OUTPUT_ERR) 283 outbuf[length - 1] = '\0'; 284} 285 286static int 287doformat_wr(void *cookie, const char *buf, int len) 288{ 289 struct output *o; 290 int origlen; 291 unsigned char c; 292 293 o = (struct output *)cookie; 294 origlen = len; 295 while (len-- != 0) { 296 c = (unsigned char)*buf++; 297 outc(c, o); 298 } 299 300 return (origlen); 301} 302 303void 304doformat(struct output *dest, const char *f, va_list ap) 305{ 306 FILE *fp; 307 308 if ((fp = fwopen(dest, doformat_wr)) != NULL) { 309 vfprintf(fp, f, ap); 310 fclose(fp); 311 } 312} 313 314/* 315 * Version of write which resumes after a signal is caught. 316 */ 317 318int 319xwrite(int fd, char *buf, int nbytes) 320{ 321 int ntry; 322 int i; 323 int n; 324 325 n = nbytes; 326 ntry = 0; 327 for (;;) { 328 i = write(fd, buf, n); 329 if (i > 0) { 330 if ((n -= i) <= 0) 331 return nbytes; 332 buf += i; 333 ntry = 0; 334 } else if (i == 0) { 335 if (++ntry > 10) 336 return nbytes - n; 337 } else if (errno != EINTR) { 338 return -1; 339 } 340 } 341} 342