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