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