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 39 static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 40 #endif 41 static const char rcsid[] = 42 "$FreeBSD$"; 43 #endif /* not lint */ 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 * Our output routines may be smaller than the stdio routines. 54 */ 55 56 #include <sys/types.h> /* quad_t */ 57 #include <sys/ioctl.h> 58 59 #include <stdio.h> /* defines BUFSIZ */ 60 #include <string.h> 61 #include <stdarg.h> 62 #include <errno.h> 63 #include <unistd.h> 64 #include <stdlib.h> 65 66 #include "shell.h" 67 #include "syntax.h" 68 #include "output.h" 69 #include "memalloc.h" 70 #include "error.h" 71 72 73 #define OUTBUFSIZ BUFSIZ 74 #define BLOCK_OUT -2 /* output to a fixed block of memory */ 75 #define MEM_OUT -3 /* output to dynamically allocated memory */ 76 #define OUTPUT_ERR 01 /* error occurred on output */ 77 78 79 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 80 struct output errout = {NULL, 0, NULL, 100, 2, 0}; 81 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 82 struct output *out1 = &output; 83 struct output *out2 = &errout; 84 85 86 87 #ifdef mkinit 88 89 INCLUDE "output.h" 90 INCLUDE "memalloc.h" 91 92 RESET { 93 out1 = &output; 94 out2 = &errout; 95 if (memout.buf != NULL) { 96 ckfree(memout.buf); 97 memout.buf = NULL; 98 } 99 } 100 101 #endif 102 103 104 void 105 out1str(const char *p) 106 { 107 outstr(p, out1); 108 } 109 110 111 void 112 out2str(const char *p) 113 { 114 outstr(p, out2); 115 } 116 117 118 void 119 outstr(const char *p, struct output *file) 120 { 121 while (*p) 122 outc(*p++, file); 123 if (file == out2) 124 flushout(file); 125 } 126 127 128 char out_junk[16]; 129 130 131 void 132 emptyoutbuf(struct output *dest) 133 { 134 int offset; 135 136 if (dest->fd == BLOCK_OUT) { 137 dest->nextc = out_junk; 138 dest->nleft = sizeof out_junk; 139 dest->flags |= OUTPUT_ERR; 140 } else if (dest->buf == NULL) { 141 INTOFF; 142 dest->buf = ckmalloc(dest->bufsize); 143 dest->nextc = dest->buf; 144 dest->nleft = dest->bufsize; 145 INTON; 146 } else if (dest->fd == MEM_OUT) { 147 offset = dest->bufsize; 148 INTOFF; 149 dest->bufsize <<= 1; 150 dest->buf = ckrealloc(dest->buf, dest->bufsize); 151 dest->nleft = dest->bufsize - offset; 152 dest->nextc = dest->buf + offset; 153 INTON; 154 } else { 155 flushout(dest); 156 } 157 dest->nleft--; 158 } 159 160 161 void 162 flushall(void) 163 { 164 flushout(&output); 165 flushout(&errout); 166 } 167 168 169 void 170 flushout(struct output *dest) 171 { 172 173 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 174 return; 175 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 176 dest->flags |= OUTPUT_ERR; 177 dest->nextc = dest->buf; 178 dest->nleft = dest->bufsize; 179 } 180 181 182 void 183 freestdout(void) 184 { 185 INTOFF; 186 if (output.buf) { 187 ckfree(output.buf); 188 output.buf = NULL; 189 output.nleft = 0; 190 } 191 INTON; 192 } 193 194 195 void 196 outfmt(struct output *file, const char *fmt, ...) 197 { 198 va_list ap; 199 200 va_start(ap, fmt); 201 doformat(file, fmt, ap); 202 va_end(ap); 203 } 204 205 206 void 207 out1fmt(const char *fmt, ...) 208 { 209 va_list ap; 210 211 va_start(ap, fmt); 212 doformat(out1, fmt, ap); 213 va_end(ap); 214 } 215 216 void 217 dprintf(const char *fmt, ...) 218 { 219 va_list ap; 220 221 va_start(ap, fmt); 222 doformat(out2, fmt, ap); 223 va_end(ap); 224 flushout(out2); 225 } 226 227 void 228 fmtstr(char *outbuf, int length, const char *fmt, ...) 229 { 230 va_list ap; 231 struct output strout; 232 233 va_start(ap, fmt); 234 strout.nextc = outbuf; 235 strout.nleft = length; 236 strout.fd = BLOCK_OUT; 237 strout.flags = 0; 238 doformat(&strout, fmt, ap); 239 outc('\0', &strout); 240 if (strout.flags & OUTPUT_ERR) 241 outbuf[length - 1] = '\0'; 242 } 243 244 /* 245 * Formatted output. This routine handles a subset of the printf formats: 246 * - Formats supported: d, u, o, X, s, and c. 247 * - The x format is also accepted but is treated like X. 248 * - The l and q modifiers are accepted. 249 * - The - and # flags are accepted; # only works with the o format. 250 * - Width and precision may be specified with any format except c. 251 * - An * may be given for the width or precision. 252 * - The obsolete practice of preceding the width with a zero to get 253 * zero padding is not supported; use the precision field. 254 * - A % may be printed by writing %% in the format string. 255 */ 256 257 #define TEMPSIZE 24 258 259 static const char digit[] = "0123456789ABCDEF"; 260 261 262 void 263 doformat(struct output *dest, const char *f, va_list ap) 264 { 265 char c; 266 char temp[TEMPSIZE]; 267 int flushleft; 268 int sharp; 269 int width; 270 int prec; 271 int islong; 272 int isquad; 273 char *p; 274 int sign; 275 quad_t l; 276 u_quad_t num; 277 unsigned base; 278 int len; 279 int size; 280 int pad; 281 282 while ((c = *f++) != '\0') { 283 if (c != '%') { 284 outc(c, dest); 285 continue; 286 } 287 flushleft = 0; 288 sharp = 0; 289 width = 0; 290 prec = -1; 291 islong = 0; 292 isquad = 0; 293 for (;;) { 294 if (*f == '-') 295 flushleft++; 296 else if (*f == '#') 297 sharp++; 298 else 299 break; 300 f++; 301 } 302 if (*f == '*') { 303 width = va_arg(ap, int); 304 f++; 305 } else { 306 while (is_digit(*f)) { 307 width = 10 * width + digit_val(*f++); 308 } 309 } 310 if (*f == '.') { 311 if (*++f == '*') { 312 prec = va_arg(ap, int); 313 f++; 314 } else { 315 prec = 0; 316 while (is_digit(*f)) { 317 prec = 10 * prec + digit_val(*f++); 318 } 319 } 320 } 321 if (*f == 'l') { 322 islong++; 323 f++; 324 } else if (*f == 'q') { 325 isquad++; 326 f++; 327 } 328 switch (*f) { 329 case 'd': 330 if (isquad) 331 l = va_arg(ap, quad_t); 332 else if (islong) 333 l = va_arg(ap, long); 334 else 335 l = va_arg(ap, int); 336 sign = 0; 337 num = l; 338 if (l < 0) { 339 num = -l; 340 sign = 1; 341 } 342 base = 10; 343 goto number; 344 case 'u': 345 base = 10; 346 goto uns_number; 347 case 'o': 348 base = 8; 349 goto uns_number; 350 case 'x': 351 /* we don't implement 'x'; treat like 'X' */ 352 case 'X': 353 base = 16; 354 uns_number: /* an unsigned number */ 355 sign = 0; 356 if (isquad) 357 num = va_arg(ap, u_quad_t); 358 else if (islong) 359 num = va_arg(ap, unsigned long); 360 else 361 num = va_arg(ap, unsigned int); 362 number: /* process a number */ 363 p = temp + TEMPSIZE - 1; 364 *p = '\0'; 365 while (num) { 366 *--p = digit[num % base]; 367 num /= base; 368 } 369 len = (temp + TEMPSIZE - 1) - p; 370 if (prec < 0) 371 prec = 1; 372 if (sharp && *f == 'o' && prec <= len) 373 prec = len + 1; 374 pad = 0; 375 if (width) { 376 size = len; 377 if (size < prec) 378 size = prec; 379 size += sign; 380 pad = width - size; 381 if (flushleft == 0) { 382 while (--pad >= 0) 383 outc(' ', dest); 384 } 385 } 386 if (sign) 387 outc('-', dest); 388 prec -= len; 389 while (--prec >= 0) 390 outc('0', dest); 391 while (*p) 392 outc(*p++, dest); 393 while (--pad >= 0) 394 outc(' ', dest); 395 break; 396 case 's': 397 p = va_arg(ap, char *); 398 pad = 0; 399 if (width) { 400 len = strlen(p); 401 if (prec >= 0 && len > prec) 402 len = prec; 403 pad = width - len; 404 if (flushleft == 0) { 405 while (--pad >= 0) 406 outc(' ', dest); 407 } 408 } 409 prec++; 410 while (--prec != 0 && *p) 411 outc(*p++, dest); 412 while (--pad >= 0) 413 outc(' ', dest); 414 break; 415 case 'c': 416 c = va_arg(ap, int); 417 outc(c, dest); 418 break; 419 default: 420 outc(*f, dest); 421 break; 422 } 423 f++; 424 } 425 } 426 427 428 429 /* 430 * Version of write which resumes after a signal is caught. 431 */ 432 433 int 434 xwrite(int fd, char *buf, int nbytes) 435 { 436 int ntry; 437 int i; 438 int n; 439 440 n = nbytes; 441 ntry = 0; 442 for (;;) { 443 i = write(fd, buf, n); 444 if (i > 0) { 445 if ((n -= i) <= 0) 446 return nbytes; 447 buf += i; 448 ntry = 0; 449 } else if (i == 0) { 450 if (++ntry > 10) 451 return nbytes - n; 452 } else if (errno != EINTR) { 453 return -1; 454 } 455 } 456 } 457