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