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 * $Id$ 37 */ 38 39 #ifndef lint 40 static char const sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 41 #endif /* not lint */ 42 43 /* 44 * Shell output routines. We use our own output routines because: 45 * When a builtin command is interrupted we have to discard 46 * any pending output. 47 * When a builtin command appears in back quotes, we want to 48 * save the output of the command in a region obtained 49 * via malloc, rather than doing a fork and reading the 50 * output of the command via a pipe. 51 * Our output routines may be smaller than the stdio routines. 52 */ 53 54 #include <sys/types.h> /* quad_t */ 55 #include <sys/ioctl.h> 56 57 #include <stdio.h> /* defines BUFSIZ */ 58 #include <string.h> 59 #ifdef __STDC__ 60 #include <stdarg.h> 61 #else 62 #include <varargs.h> 63 #endif 64 #include <errno.h> 65 #include <unistd.h> 66 #include <stdlib.h> 67 68 #include "shell.h" 69 #include "syntax.h" 70 #include "output.h" 71 #include "memalloc.h" 72 #include "error.h" 73 74 75 #define OUTBUFSIZ BUFSIZ 76 #define BLOCK_OUT -2 /* output to a fixed block of memory */ 77 #define MEM_OUT -3 /* output to dynamically allocated memory */ 78 #define OUTPUT_ERR 01 /* error occurred on output */ 79 80 81 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 82 struct output errout = {NULL, 0, NULL, 100, 2, 0};; 83 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 84 struct output *out1 = &output; 85 struct output *out2 = &errout; 86 87 88 89 #ifdef mkinit 90 91 INCLUDE "output.h" 92 INCLUDE "memalloc.h" 93 94 RESET { 95 out1 = &output; 96 out2 = &errout; 97 if (memout.buf != NULL) { 98 ckfree(memout.buf); 99 memout.buf = NULL; 100 } 101 } 102 103 #endif 104 105 106 #ifdef notdef /* no longer used */ 107 /* 108 * Set up an output file to write to memory rather than a file. 109 */ 110 111 void 112 open_mem(block, length, file) 113 char *block; 114 int length; 115 struct output *file; 116 { 117 file->nextc = block; 118 file->nleft = --length; 119 file->fd = BLOCK_OUT; 120 file->flags = 0; 121 } 122 #endif 123 124 125 void 126 out1str(p) 127 const char *p; 128 { 129 outstr(p, out1); 130 } 131 132 133 void 134 out2str(p) 135 const char *p; 136 { 137 outstr(p, out2); 138 } 139 140 141 void 142 outstr(p, file) 143 register const char *p; 144 register struct output *file; 145 { 146 while (*p) 147 outc(*p++, file); 148 if (file == out2) 149 flushout(file); 150 } 151 152 153 char out_junk[16]; 154 155 156 void 157 emptyoutbuf(dest) 158 struct output *dest; 159 { 160 int offset; 161 162 if (dest->fd == BLOCK_OUT) { 163 dest->nextc = out_junk; 164 dest->nleft = sizeof out_junk; 165 dest->flags |= OUTPUT_ERR; 166 } else if (dest->buf == NULL) { 167 INTOFF; 168 dest->buf = ckmalloc(dest->bufsize); 169 dest->nextc = dest->buf; 170 dest->nleft = dest->bufsize; 171 INTON; 172 } else if (dest->fd == MEM_OUT) { 173 offset = dest->bufsize; 174 INTOFF; 175 dest->bufsize <<= 1; 176 dest->buf = ckrealloc(dest->buf, dest->bufsize); 177 dest->nleft = dest->bufsize - offset; 178 dest->nextc = dest->buf + offset; 179 INTON; 180 } else { 181 flushout(dest); 182 } 183 dest->nleft--; 184 } 185 186 187 void 188 flushall() { 189 flushout(&output); 190 flushout(&errout); 191 } 192 193 194 void 195 flushout(dest) 196 struct output *dest; 197 { 198 199 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 200 return; 201 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 202 dest->flags |= OUTPUT_ERR; 203 dest->nextc = dest->buf; 204 dest->nleft = dest->bufsize; 205 } 206 207 208 void 209 freestdout() { 210 INTOFF; 211 if (output.buf) { 212 ckfree(output.buf); 213 output.buf = NULL; 214 output.nleft = 0; 215 } 216 INTON; 217 } 218 219 220 #ifdef __STDC__ 221 void 222 outfmt(struct output *file, char *fmt, ...) { 223 va_list ap; 224 225 va_start(ap, fmt); 226 doformat(file, fmt, ap); 227 va_end(ap); 228 } 229 230 231 void 232 out1fmt(char *fmt, ...) { 233 va_list ap; 234 235 va_start(ap, fmt); 236 doformat(out1, fmt, ap); 237 va_end(ap); 238 } 239 240 void 241 dprintf(char *fmt, ...) { 242 va_list ap; 243 244 va_start(ap, fmt); 245 doformat(out2, fmt, ap); 246 va_end(ap); 247 flushout(out2); 248 } 249 250 void 251 fmtstr(char *outbuf, int length, char *fmt, ...) { 252 va_list ap; 253 struct output strout; 254 255 va_start(ap, fmt); 256 strout.nextc = outbuf; 257 strout.nleft = length; 258 strout.fd = BLOCK_OUT; 259 strout.flags = 0; 260 doformat(&strout, fmt, ap); 261 outc('\0', &strout); 262 if (strout.flags & OUTPUT_ERR) 263 outbuf[length - 1] = '\0'; 264 } 265 266 #else /* not __STDC__ */ 267 268 void 269 outfmt(va_alist) 270 va_dcl 271 { 272 va_list ap; 273 struct output *file; 274 char *fmt; 275 276 va_start(ap); 277 file = va_arg(ap, struct output *); 278 fmt = va_arg(ap, char *); 279 doformat(file, fmt, ap); 280 va_end(ap); 281 } 282 283 284 void 285 out1fmt(va_alist) 286 va_dcl 287 { 288 va_list ap; 289 char *fmt; 290 291 va_start(ap); 292 fmt = va_arg(ap, char *); 293 doformat(out1, fmt, ap); 294 va_end(ap); 295 } 296 297 void 298 dprintf(va_alist) 299 va_dcl 300 { 301 va_list ap; 302 char *fmt; 303 304 va_start(ap); 305 fmt = va_arg(ap, char *); 306 doformat(out2, fmt, ap); 307 va_end(ap); 308 flushout(out2); 309 } 310 311 void 312 fmtstr(va_alist) 313 va_dcl 314 { 315 va_list ap; 316 struct output strout; 317 char *outbuf; 318 int length; 319 char *fmt; 320 321 va_start(ap); 322 outbuf = va_arg(ap, char *); 323 length = va_arg(ap, int); 324 fmt = va_arg(ap, char *); 325 strout.nextc = outbuf; 326 strout.nleft = length; 327 strout.fd = BLOCK_OUT; 328 strout.flags = 0; 329 doformat(&strout, fmt, ap); 330 outc('\0', &strout); 331 if (strout.flags & OUTPUT_ERR) 332 outbuf[length - 1] = '\0'; 333 } 334 #endif /* __STDC__ */ 335 336 337 /* 338 * Formatted output. This routine handles a subset of the printf formats: 339 * - Formats supported: d, u, o, X, s, and c. 340 * - The x format is also accepted but is treated like X. 341 * - The l and q modifiers are accepted. 342 * - The - and # flags are accepted; # only works with the o format. 343 * - Width and precision may be specified with any format except c. 344 * - An * may be given for the width or precision. 345 * - The obsolete practice of preceding the width with a zero to get 346 * zero padding is not supported; use the precision field. 347 * - A % may be printed by writing %% in the format string. 348 */ 349 350 #define TEMPSIZE 24 351 352 static const char digit[] = "0123456789ABCDEF"; 353 354 355 void 356 doformat(dest, f, ap) 357 register struct output *dest; 358 register char *f; /* format string */ 359 va_list ap; 360 { 361 register char c; 362 char temp[TEMPSIZE]; 363 int flushleft; 364 int sharp; 365 int width; 366 int prec; 367 int islong; 368 int isquad; 369 char *p; 370 int sign; 371 quad_t l; 372 u_quad_t num; 373 unsigned base; 374 int len; 375 int size; 376 int pad; 377 378 while ((c = *f++) != '\0') { 379 if (c != '%') { 380 outc(c, dest); 381 continue; 382 } 383 flushleft = 0; 384 sharp = 0; 385 width = 0; 386 prec = -1; 387 islong = 0; 388 isquad = 0; 389 for (;;) { 390 if (*f == '-') 391 flushleft++; 392 else if (*f == '#') 393 sharp++; 394 else 395 break; 396 f++; 397 } 398 if (*f == '*') { 399 width = va_arg(ap, int); 400 f++; 401 } else { 402 while (is_digit(*f)) { 403 width = 10 * width + digit_val(*f++); 404 } 405 } 406 if (*f == '.') { 407 if (*++f == '*') { 408 prec = va_arg(ap, int); 409 f++; 410 } else { 411 prec = 0; 412 while (is_digit(*f)) { 413 prec = 10 * prec + digit_val(*f++); 414 } 415 } 416 } 417 if (*f == 'l') { 418 islong++; 419 f++; 420 } else if (*f == 'q') { 421 isquad++; 422 f++; 423 } 424 switch (*f) { 425 case 'd': 426 if (isquad) 427 l = va_arg(ap, quad_t); 428 else if (islong) 429 l = va_arg(ap, long); 430 else 431 l = va_arg(ap, int); 432 sign = 0; 433 num = l; 434 if (l < 0) { 435 num = -l; 436 sign = 1; 437 } 438 base = 10; 439 goto number; 440 case 'u': 441 base = 10; 442 goto uns_number; 443 case 'o': 444 base = 8; 445 goto uns_number; 446 case 'x': 447 /* we don't implement 'x'; treat like 'X' */ 448 case 'X': 449 base = 16; 450 uns_number: /* an unsigned number */ 451 sign = 0; 452 if (isquad) 453 num = va_arg(ap, u_quad_t); 454 else if (islong) 455 num = va_arg(ap, unsigned long); 456 else 457 num = va_arg(ap, unsigned int); 458 number: /* process a number */ 459 p = temp + TEMPSIZE - 1; 460 *p = '\0'; 461 while (num) { 462 *--p = digit[num % base]; 463 num /= base; 464 } 465 len = (temp + TEMPSIZE - 1) - p; 466 if (prec < 0) 467 prec = 1; 468 if (sharp && *f == 'o' && prec <= len) 469 prec = len + 1; 470 pad = 0; 471 if (width) { 472 size = len; 473 if (size < prec) 474 size = prec; 475 size += sign; 476 pad = width - size; 477 if (flushleft == 0) { 478 while (--pad >= 0) 479 outc(' ', dest); 480 } 481 } 482 if (sign) 483 outc('-', dest); 484 prec -= len; 485 while (--prec >= 0) 486 outc('0', dest); 487 while (*p) 488 outc(*p++, dest); 489 while (--pad >= 0) 490 outc(' ', dest); 491 break; 492 case 's': 493 p = va_arg(ap, char *); 494 pad = 0; 495 if (width) { 496 len = strlen(p); 497 if (prec >= 0 && len > prec) 498 len = prec; 499 pad = width - len; 500 if (flushleft == 0) { 501 while (--pad >= 0) 502 outc(' ', dest); 503 } 504 } 505 prec++; 506 while (--prec != 0 && *p) 507 outc(*p++, dest); 508 while (--pad >= 0) 509 outc(' ', dest); 510 break; 511 case 'c': 512 c = va_arg(ap, int); 513 outc(c, dest); 514 break; 515 default: 516 outc(*f, dest); 517 break; 518 } 519 f++; 520 } 521 } 522 523 524 525 /* 526 * Version of write which resumes after a signal is caught. 527 */ 528 529 int 530 xwrite(fd, buf, nbytes) 531 int fd; 532 char *buf; 533 int nbytes; 534 { 535 int ntry; 536 int i; 537 int n; 538 539 n = nbytes; 540 ntry = 0; 541 for (;;) { 542 i = write(fd, buf, n); 543 if (i > 0) { 544 if ((n -= i) <= 0) 545 return nbytes; 546 buf += i; 547 ntry = 0; 548 } else if (i == 0) { 549 if (++ntry > 10) 550 return nbytes - n; 551 } else if (errno != EINTR) { 552 return -1; 553 } 554 } 555 } 556 557 558 /* 559 * Version of ioctl that retries after a signal is caught. 560 * XXX unused function 561 */ 562 563 int 564 xioctl(fd, request, arg) 565 int fd; 566 unsigned long request; 567 char * arg; 568 { 569 int i; 570 571 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 572 return i; 573 } 574