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