1 /* $NetBSD: output.c,v 1.24 2001/09/24 13:22:26 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 43 #else 44 __RCSID("$NetBSD: output.c,v 1.24 2001/09/24 13:22:26 wiz Exp $"); 45 #endif 46 #endif /* not lint */ 47 48 /* 49 * Shell output routines. We use our own output routines because: 50 * When a builtin command is interrupted we have to discard 51 * any pending output. 52 * When a builtin command appears in back quotes, we want to 53 * save the output of the command in a region obtained 54 * via malloc, rather than doing a fork and reading the 55 * output of the command via a pipe. 56 * Our output routines may be smaller than the stdio routines. 57 */ 58 59 #include <sys/types.h> /* quad_t */ 60 #include <sys/param.h> /* BSD4_4 */ 61 #include <sys/ioctl.h> 62 63 #include <stdio.h> /* defines BUFSIZ */ 64 #include <string.h> 65 #include <errno.h> 66 #include <unistd.h> 67 #include <stdlib.h> 68 69 #include "shell.h" 70 #include "syntax.h" 71 #include "output.h" 72 #include "memalloc.h" 73 #include "error.h" 74 75 76 #define OUTBUFSIZ BUFSIZ 77 #define BLOCK_OUT -2 /* output to a fixed block of memory */ 78 #define MEM_OUT -3 /* output to dynamically allocated memory */ 79 #define OUTPUT_ERR 01 /* error occurred on output */ 80 81 82 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 83 struct output errout = {NULL, 0, NULL, 100, 2, 0}; 84 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 85 struct output *out1 = &output; 86 struct output *out2 = &errout; 87 88 89 90 #ifdef mkinit 91 92 INCLUDE "output.h" 93 INCLUDE "memalloc.h" 94 95 RESET { 96 out1 = &output; 97 out2 = &errout; 98 if (memout.buf != NULL) { 99 ckfree(memout.buf); 100 memout.buf = NULL; 101 } 102 } 103 104 #endif 105 106 107 #ifdef notdef /* no longer used */ 108 /* 109 * Set up an output file to write to memory rather than a file. 110 */ 111 112 void 113 open_mem(block, length, file) 114 char *block; 115 int length; 116 struct output *file; 117 { 118 file->nextc = block; 119 file->nleft = --length; 120 file->fd = BLOCK_OUT; 121 file->flags = 0; 122 } 123 #endif 124 125 126 void 127 out1str(p) 128 const char *p; 129 { 130 outstr(p, out1); 131 } 132 133 134 void 135 out2str(p) 136 const char *p; 137 { 138 outstr(p, out2); 139 } 140 141 142 void 143 outstr(p, file) 144 const char *p; 145 struct output *file; 146 { 147 while (*p) 148 outc(*p++, file); 149 if (file == out2) 150 flushout(file); 151 } 152 153 154 char out_junk[16]; 155 156 157 void 158 emptyoutbuf(dest) 159 struct output *dest; 160 { 161 int offset; 162 163 if (dest->fd == BLOCK_OUT) { 164 dest->nextc = out_junk; 165 dest->nleft = sizeof out_junk; 166 dest->flags |= OUTPUT_ERR; 167 } else 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() { 190 flushout(&output); 191 flushout(&errout); 192 } 193 194 195 void 196 flushout(dest) 197 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() { 211 INTOFF; 212 if (output.buf) { 213 ckfree(output.buf); 214 output.buf = NULL; 215 output.nleft = 0; 216 } 217 INTON; 218 } 219 220 221 void 222 #ifdef __STDC__ 223 outfmt(struct output *file, const char *fmt, ...) 224 #else 225 void 226 outfmt(va_alist) 227 va_dcl 228 #endif 229 { 230 va_list ap; 231 #ifndef __STDC__ 232 struct output *file; 233 const char *fmt; 234 235 va_start(ap); 236 file = va_arg(ap, struct output *); 237 fmt = va_arg(ap, const char *); 238 #else 239 va_start(ap, fmt); 240 #endif 241 doformat(file, fmt, ap); 242 va_end(ap); 243 } 244 245 246 void 247 #ifdef __STDC__ 248 out1fmt(const char *fmt, ...) 249 #else 250 out1fmt(va_alist) 251 va_dcl 252 #endif 253 { 254 va_list ap; 255 #ifndef __STDC__ 256 const char *fmt; 257 258 va_start(ap); 259 fmt = va_arg(ap, const char *); 260 #else 261 va_start(ap, fmt); 262 #endif 263 doformat(out1, fmt, ap); 264 va_end(ap); 265 } 266 267 void 268 #ifdef __STDC__ 269 dprintf(const char *fmt, ...) 270 #else 271 dprintf(va_alist) 272 va_dcl 273 #endif 274 { 275 va_list ap; 276 #ifndef __STDC__ 277 const char *fmt; 278 279 va_start(ap); 280 fmt = va_arg(ap, const char *); 281 #else 282 va_start(ap, fmt); 283 #endif 284 doformat(out2, fmt, ap); 285 va_end(ap); 286 flushout(out2); 287 } 288 289 void 290 #ifdef __STDC__ 291 fmtstr(char *outbuf, size_t length, const char *fmt, ...) 292 #else 293 fmtstr(va_alist) 294 va_dcl 295 #endif 296 { 297 va_list ap; 298 struct output strout; 299 #ifndef __STDC__ 300 char *outbuf; 301 size_t length; 302 const char *fmt; 303 304 va_start(ap); 305 outbuf = va_arg(ap, char *); 306 length = va_arg(ap, size_t); 307 fmt = va_arg(ap, const char *); 308 #else 309 va_start(ap, fmt); 310 #endif 311 strout.nextc = outbuf; 312 strout.nleft = length; 313 strout.fd = BLOCK_OUT; 314 strout.flags = 0; 315 doformat(&strout, fmt, ap); 316 outc('\0', &strout); 317 if (strout.flags & OUTPUT_ERR) 318 outbuf[length - 1] = '\0'; 319 va_end(ap); 320 } 321 322 /* 323 * Formatted output. This routine handles a subset of the printf formats: 324 * - Formats supported: d, u, o, p, X, s, and c. 325 * - The x format is also accepted but is treated like X. 326 * - The l, ll and q modifiers are accepted. 327 * - The - and # flags are accepted; # only works with the o format. 328 * - Width and precision may be specified with any format except c. 329 * - An * may be given for the width or precision. 330 * - The obsolete practice of preceding the width with a zero to get 331 * zero padding is not supported; use the precision field. 332 * - A % may be printed by writing %% in the format string. 333 */ 334 335 #define TEMPSIZE 24 336 337 static const char digit[] = "0123456789ABCDEF"; 338 339 #ifdef BSD4_4 340 #define HAVE_VASPRINTF 1 341 #endif 342 343 344 void 345 doformat(dest, f, ap) 346 struct output *dest; 347 const char *f; /* format string */ 348 va_list ap; 349 { 350 #if HAVE_VASPRINTF 351 char *s; 352 353 vasprintf(&s, f, ap); 354 outstr(s, dest); 355 free(s); 356 #else /* !HAVE_VASPRINTF */ 357 char c; 358 char temp[TEMPSIZE]; 359 int flushleft; 360 int sharp; 361 int width; 362 int prec; 363 int islong; 364 int isquad; 365 char *p; 366 int sign; 367 #ifdef BSD4_4 368 quad_t l; 369 u_quad_t num; 370 #else 371 long l; 372 u_long num; 373 #endif 374 unsigned base; 375 int len; 376 int size; 377 int pad; 378 379 while ((c = *f++) != '\0') { 380 if (c != '%') { 381 outc(c, dest); 382 continue; 383 } 384 flushleft = 0; 385 sharp = 0; 386 width = 0; 387 prec = -1; 388 islong = 0; 389 isquad = 0; 390 for (;;) { 391 if (*f == '-') 392 flushleft++; 393 else if (*f == '#') 394 sharp++; 395 else 396 break; 397 f++; 398 } 399 if (*f == '*') { 400 width = va_arg(ap, int); 401 f++; 402 } else { 403 while (is_digit(*f)) { 404 width = 10 * width + digit_val(*f++); 405 } 406 } 407 if (*f == '.') { 408 if (*++f == '*') { 409 prec = va_arg(ap, int); 410 f++; 411 } else { 412 prec = 0; 413 while (is_digit(*f)) { 414 prec = 10 * prec + digit_val(*f++); 415 } 416 } 417 } 418 if (*f == 'l') { 419 f++; 420 if (*f == 'l') { 421 isquad++; 422 f++; 423 } else 424 islong++; 425 } else if (*f == 'q') { 426 isquad++; 427 f++; 428 } 429 switch (*f) { 430 case 'd': 431 #ifdef BSD4_4 432 if (isquad) 433 l = va_arg(ap, quad_t); 434 else 435 #endif 436 if (islong) 437 l = va_arg(ap, long); 438 else 439 l = va_arg(ap, int); 440 sign = 0; 441 num = l; 442 if (l < 0) { 443 num = -l; 444 sign = 1; 445 } 446 base = 10; 447 goto number; 448 case 'u': 449 base = 10; 450 goto uns_number; 451 case 'o': 452 base = 8; 453 goto uns_number; 454 case 'p': 455 outc('0', dest); 456 outc('x', dest); 457 /*FALLTHROUGH*/ 458 case 'x': 459 /* we don't implement 'x'; treat like 'X' */ 460 case 'X': 461 base = 16; 462 uns_number: /* an unsigned number */ 463 sign = 0; 464 #ifdef BSD4_4 465 if (isquad) 466 num = va_arg(ap, u_quad_t); 467 else 468 #endif 469 if (islong) 470 num = va_arg(ap, unsigned long); 471 else 472 num = va_arg(ap, unsigned int); 473 number: /* process a number */ 474 p = temp + TEMPSIZE - 1; 475 *p = '\0'; 476 while (num) { 477 *--p = digit[num % base]; 478 num /= base; 479 } 480 len = (temp + TEMPSIZE - 1) - p; 481 if (prec < 0) 482 prec = 1; 483 if (sharp && *f == 'o' && prec <= len) 484 prec = len + 1; 485 pad = 0; 486 if (width) { 487 size = len; 488 if (size < prec) 489 size = prec; 490 size += sign; 491 pad = width - size; 492 if (flushleft == 0) { 493 while (--pad >= 0) 494 outc(' ', dest); 495 } 496 } 497 if (sign) 498 outc('-', dest); 499 prec -= len; 500 while (--prec >= 0) 501 outc('0', dest); 502 while (*p) 503 outc(*p++, dest); 504 while (--pad >= 0) 505 outc(' ', dest); 506 break; 507 case 's': 508 p = va_arg(ap, char *); 509 pad = 0; 510 if (width) { 511 len = strlen(p); 512 if (prec >= 0 && len > prec) 513 len = prec; 514 pad = width - len; 515 if (flushleft == 0) { 516 while (--pad >= 0) 517 outc(' ', dest); 518 } 519 } 520 prec++; 521 while (--prec != 0 && *p) 522 outc(*p++, dest); 523 while (--pad >= 0) 524 outc(' ', dest); 525 break; 526 case 'c': 527 c = va_arg(ap, int); 528 outc(c, dest); 529 break; 530 default: 531 outc(*f, dest); 532 break; 533 } 534 f++; 535 } 536 #endif /* !HAVE_VASPRINTF */ 537 } 538 539 540 541 /* 542 * Version of write which resumes after a signal is caught. 543 */ 544 545 int 546 xwrite(fd, buf, nbytes) 547 int fd; 548 char *buf; 549 int nbytes; 550 { 551 int ntry; 552 int i; 553 int n; 554 555 n = nbytes; 556 ntry = 0; 557 for (;;) { 558 i = write(fd, buf, n); 559 if (i > 0) { 560 if ((n -= i) <= 0) 561 return nbytes; 562 buf += i; 563 ntry = 0; 564 } else if (i == 0) { 565 if (++ntry > 10) 566 return nbytes - n; 567 } else if (errno != EINTR) { 568 return -1; 569 } 570 } 571 } 572 573 574 /* 575 * Version of ioctl that retries after a signal is caught. 576 * XXX unused function 577 */ 578 579 int 580 xioctl(fd, request, arg) 581 int fd; 582 unsigned long request; 583 char * arg; 584 { 585 int i; 586 587 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 588 return i; 589 } 590