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: output.c,v 1.3 1996/09/01 10:21:23 peter Exp $ 37 */ 38 39 #ifndef lint 40 static char 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/ioctl.h> 55 #include <sys/types.h> /* quad_t */ 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 is 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 #ifdef __STDC__ 353 static const char digit[] = "0123456789ABCDEF"; 354 #else 355 static const char digit[17] = "0123456789ABCDEF"; 356 #endif 357 358 359 void 360 doformat(dest, f, ap) 361 register struct output *dest; 362 register char *f; /* format string */ 363 va_list ap; 364 { 365 register char c; 366 char temp[TEMPSIZE]; 367 int flushleft; 368 int sharp; 369 int width; 370 int prec; 371 int islong; 372 int isquad; 373 char *p; 374 int sign; 375 quad_t l; 376 u_quad_t num; 377 unsigned base; 378 int len; 379 int size; 380 int pad; 381 382 while ((c = *f++) != '\0') { 383 if (c != '%') { 384 outc(c, dest); 385 continue; 386 } 387 flushleft = 0; 388 sharp = 0; 389 width = 0; 390 prec = -1; 391 islong = 0; 392 isquad = 0; 393 for (;;) { 394 if (*f == '-') 395 flushleft++; 396 else if (*f == '#') 397 sharp++; 398 else 399 break; 400 f++; 401 } 402 if (*f == '*') { 403 width = va_arg(ap, int); 404 f++; 405 } else { 406 while (is_digit(*f)) { 407 width = 10 * width + digit_val(*f++); 408 } 409 } 410 if (*f == '.') { 411 if (*++f == '*') { 412 prec = va_arg(ap, int); 413 f++; 414 } else { 415 prec = 0; 416 while (is_digit(*f)) { 417 prec = 10 * prec + digit_val(*f++); 418 } 419 } 420 } 421 if (*f == 'l') { 422 islong++; 423 f++; 424 } else if (*f == 'q') { 425 isquad++; 426 f++; 427 } 428 switch (*f) { 429 case 'd': 430 if (islong) 431 l = va_arg(ap, long); 432 else if (isquad) 433 l = va_arg(ap, quad_t); 434 else 435 l = va_arg(ap, int); 436 sign = 0; 437 num = l; 438 if (l < 0) { 439 num = -l; 440 sign = 1; 441 } 442 base = 10; 443 goto number; 444 case 'u': 445 base = 10; 446 goto uns_number; 447 case 'o': 448 base = 8; 449 goto uns_number; 450 case 'x': 451 /* we don't implement 'x'; treat like 'X' */ 452 case 'X': 453 base = 16; 454 uns_number: /* an unsigned number */ 455 sign = 0; 456 if (islong) 457 num = va_arg(ap, unsigned long); 458 else if (isquad) 459 num = va_arg(ap, u_quad_t); 460 else 461 num = va_arg(ap, unsigned int); 462 number: /* process a number */ 463 p = temp + TEMPSIZE - 1; 464 *p = '\0'; 465 while (num) { 466 *--p = digit[num % base]; 467 num /= base; 468 } 469 len = (temp + TEMPSIZE - 1) - p; 470 if (prec < 0) 471 prec = 1; 472 if (sharp && *f == 'o' && prec <= len) 473 prec = len + 1; 474 pad = 0; 475 if (width) { 476 size = len; 477 if (size < prec) 478 size = prec; 479 size += sign; 480 pad = width - size; 481 if (flushleft == 0) { 482 while (--pad >= 0) 483 outc(' ', dest); 484 } 485 } 486 if (sign) 487 outc('-', dest); 488 prec -= len; 489 while (--prec >= 0) 490 outc('0', dest); 491 while (*p) 492 outc(*p++, dest); 493 while (--pad >= 0) 494 outc(' ', dest); 495 break; 496 case 's': 497 p = va_arg(ap, char *); 498 pad = 0; 499 if (width) { 500 len = strlen(p); 501 if (prec >= 0 && len > prec) 502 len = prec; 503 pad = width - len; 504 if (flushleft == 0) { 505 while (--pad >= 0) 506 outc(' ', dest); 507 } 508 } 509 prec++; 510 while (--prec != 0 && *p) 511 outc(*p++, dest); 512 while (--pad >= 0) 513 outc(' ', dest); 514 break; 515 case 'c': 516 c = va_arg(ap, int); 517 outc(c, dest); 518 break; 519 default: 520 outc(*f, dest); 521 break; 522 } 523 f++; 524 } 525 } 526 527 528 529 /* 530 * Version of write which resumes after a signal is caught. 531 */ 532 533 int 534 xwrite(fd, buf, nbytes) 535 int fd; 536 char *buf; 537 int nbytes; 538 { 539 int ntry; 540 int i; 541 int n; 542 543 n = nbytes; 544 ntry = 0; 545 for (;;) { 546 i = write(fd, buf, n); 547 if (i > 0) { 548 if ((n -= i) <= 0) 549 return nbytes; 550 buf += i; 551 ntry = 0; 552 } else if (i == 0) { 553 if (++ntry > 10) 554 return nbytes - n; 555 } else if (errno != EINTR) { 556 return -1; 557 } 558 } 559 } 560 561 562 /* 563 * Version of ioctl that retries after a signal is caught. 564 * XXX unused function 565 */ 566 567 int 568 xioctl(fd, request, arg) 569 int fd; 570 unsigned long request; 571 char * arg; 572 { 573 int i; 574 575 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 576 return i; 577 } 578