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