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