output.c revision 1556
1251881Speter/*- 2251881Speter * Copyright (c) 1991, 1993 3251881Speter * The Regents of the University of California. All rights reserved. 4251881Speter * 5251881Speter * This code is derived from software contributed to Berkeley by 6251881Speter * Kenneth Almquist. 7251881Speter * 8251881Speter * Redistribution and use in source and binary forms, with or without 9251881Speter * modification, are permitted provided that the following conditions 10251881Speter * are met: 11251881Speter * 1. Redistributions of source code must retain the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer. 13251881Speter * 2. Redistributions in binary form must reproduce the above copyright 14251881Speter * notice, this list of conditions and the following disclaimer in the 15251881Speter * documentation and/or other materials provided with the distribution. 16251881Speter * 3. All advertising materials mentioning features or use of this software 17251881Speter * must display the following acknowledgement: 18251881Speter * This product includes software developed by the University of 19251881Speter * California, Berkeley and its contributors. 20251881Speter * 4. Neither the name of the University nor the names of its contributors 21251881Speter * may be used to endorse or promote products derived from this software 22251881Speter * without specific prior written permission. 23251881Speter * 24251881Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34251881Speter * SUCH DAMAGE. 35251881Speter */ 36251881Speter 37251881Speter#ifndef lint 38251881Speterstatic char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93"; 39251881Speter#endif /* not lint */ 40251881Speter 41251881Speter/* 42251881Speter * Shell output routines. We use our own output routines because: 43251881Speter * When a builtin command is interrupted we have to discard 44251881Speter * any pending output. 45251881Speter * When a builtin command appears in back quotes, we want to 46251881Speter * save the output of the command in a region obtained 47251881Speter * via malloc, rather than doing a fork and reading the 48251881Speter * output of the command via a pipe. 49251881Speter * Our output routines may be smaller than the stdio routines. 50251881Speter */ 51251881Speter 52251881Speter#include <stdio.h> /* defines BUFSIZ */ 53251881Speter#include "shell.h" 54251881Speter#include "syntax.h" 55251881Speter#include "output.h" 56251881Speter#include "memalloc.h" 57251881Speter#include "error.h" 58251881Speter#ifdef __STDC__ 59251881Speter#include "stdarg.h" 60251881Speter#else 61251881Speter#include <varargs.h> 62251881Speter#endif 63251881Speter#include <errno.h> 64251881Speter 65251881Speter 66251881Speter#define OUTBUFSIZ BUFSIZ 67251881Speter#define BLOCK_OUT -2 /* output to a fixed block of memory */ 68251881Speter#define MEM_OUT -3 /* output to dynamically allocated memory */ 69251881Speter#define OUTPUT_ERR 01 /* error occurred on output */ 70251881Speter 71251881Speter 72251881Speterstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 73251881Speterstruct output errout = {NULL, 0, NULL, 100, 2, 0};; 74251881Speterstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 75251881Speterstruct output *out1 = &output; 76251881Speterstruct output *out2 = &errout; 77251881Speter 78251881Speter 79251881Speter 80251881Speter#ifdef mkinit 81251881Speter 82251881SpeterINCLUDE "output.h" 83251881SpeterINCLUDE "memalloc.h" 84251881Speter 85251881SpeterRESET { 86251881Speter out1 = &output; 87251881Speter out2 = &errout; 88251881Speter if (memout.buf != NULL) { 89251881Speter ckfree(memout.buf); 90251881Speter memout.buf = NULL; 91251881Speter } 92251881Speter} 93251881Speter 94251881Speter#endif 95251881Speter 96251881Speter 97251881Speter#ifdef notdef /* no longer used */ 98251881Speter/* 99251881Speter * Set up an output file to write to memory rather than a file. 100251881Speter */ 101251881Speter 102251881Spetervoid 103251881Speteropen_mem(block, length, file) 104251881Speter char *block; 105251881Speter int length; 106251881Speter struct output *file; 107251881Speter { 108251881Speter file->nextc = block; 109251881Speter file->nleft = --length; 110251881Speter file->fd = BLOCK_OUT; 111251881Speter file->flags = 0; 112251881Speter} 113251881Speter#endif 114251881Speter 115251881Speter 116251881Spetervoid 117251881Speterout1str(p) 118251881Speter char *p; 119251881Speter { 120251881Speter outstr(p, out1); 121251881Speter} 122251881Speter 123251881Speter 124251881Spetervoid 125251881Speterout2str(p) 126251881Speter char *p; 127251881Speter { 128251881Speter outstr(p, out2); 129251881Speter} 130251881Speter 131251881Speter 132251881Spetervoid 133251881Speteroutstr(p, file) 134251881Speter register char *p; 135251881Speter register struct output *file; 136251881Speter { 137251881Speter while (*p) 138251881Speter outc(*p++, file); 139251881Speter if (file == out2) 140251881Speter flushout(file); 141251881Speter} 142251881Speter 143251881Speter 144251881Speterchar out_junk[16]; 145251881Speter 146251881Speter 147251881Spetervoid 148251881Speteremptyoutbuf(dest) 149251881Speter struct output *dest; 150251881Speter { 151251881Speter int offset; 152251881Speter 153251881Speter if (dest->fd == BLOCK_OUT) { 154251881Speter dest->nextc = out_junk; 155251881Speter dest->nleft = sizeof out_junk; 156251881Speter dest->flags |= OUTPUT_ERR; 157251881Speter } else if (dest->buf == NULL) { 158251881Speter INTOFF; 159251881Speter dest->buf = ckmalloc(dest->bufsize); 160251881Speter dest->nextc = dest->buf; 161251881Speter dest->nleft = dest->bufsize; 162251881Speter INTON; 163251881Speter } else if (dest->fd == MEM_OUT) { 164251881Speter offset = dest->bufsize; 165251881Speter INTOFF; 166251881Speter dest->bufsize <<= 1; 167251881Speter dest->buf = ckrealloc(dest->buf, dest->bufsize); 168251881Speter dest->nleft = dest->bufsize - offset; 169251881Speter dest->nextc = dest->buf + offset; 170251881Speter INTON; 171251881Speter } else { 172251881Speter flushout(dest); 173251881Speter } 174251881Speter dest->nleft--; 175251881Speter} 176251881Speter 177251881Speter 178251881Spetervoid 179251881Speterflushall() { 180251881Speter flushout(&output); 181251881Speter flushout(&errout); 182251881Speter} 183251881Speter 184251881Speter 185251881Spetervoid 186251881Speterflushout(dest) 187251881Speter struct output *dest; 188251881Speter { 189251881Speter 190251881Speter if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 191251881Speter return; 192251881Speter if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 193251881Speter dest->flags |= OUTPUT_ERR; 194251881Speter dest->nextc = dest->buf; 195251881Speter dest->nleft = dest->bufsize; 196251881Speter} 197251881Speter 198251881Speter 199251881Spetervoid 200251881Speterfreestdout() { 201251881Speter INTOFF; 202251881Speter if (output.buf) { 203251881Speter ckfree(output.buf); 204251881Speter output.buf = NULL; 205251881Speter output.nleft = 0; 206251881Speter } 207251881Speter INTON; 208251881Speter} 209251881Speter 210251881Speter 211251881Speter#ifdef __STDC__ 212251881Spetervoid 213251881Speteroutfmt(struct output *file, char *fmt, ...) { 214251881Speter va_list ap; 215251881Speter 216251881Speter va_start(ap, fmt); 217251881Speter doformat(file, fmt, ap); 218251881Speter va_end(ap); 219251881Speter} 220251881Speter 221251881Speter 222251881Spetervoid 223251881Speterout1fmt(char *fmt, ...) { 224251881Speter va_list ap; 225251881Speter 226251881Speter va_start(ap, fmt); 227251881Speter doformat(out1, fmt, ap); 228251881Speter va_end(ap); 229251881Speter} 230251881Speter 231251881Spetervoid 232251881Speterdprintf(char *fmt, ...) { 233251881Speter va_list ap; 234251881Speter 235251881Speter va_start(ap, fmt); 236251881Speter doformat(out2, fmt, ap); 237251881Speter va_end(ap); 238251881Speter flushout(out2); 239251881Speter} 240251881Speter 241251881Spetervoid 242251881Speterfmtstr(char *outbuf, int length, char *fmt, ...) { 243251881Speter va_list ap; 244251881Speter struct output strout; 245251881Speter 246251881Speter va_start(ap, fmt); 247251881Speter strout.nextc = outbuf; 248251881Speter strout.nleft = length; 249251881Speter strout.fd = BLOCK_OUT; 250251881Speter strout.flags = 0; 251251881Speter doformat(&strout, fmt, ap); 252251881Speter outc('\0', &strout); 253251881Speter if (strout.flags & OUTPUT_ERR) 254251881Speter outbuf[length - 1] = '\0'; 255251881Speter} 256251881Speter 257251881Speter#else /* not __STDC__ */ 258251881Speter 259251881Spetervoid 260251881Speteroutfmt(va_alist) 261251881Speter va_dcl 262251881Speter { 263251881Speter va_list ap; 264251881Speter struct output *file; 265251881Speter char *fmt; 266251881Speter 267251881Speter va_start(ap); 268251881Speter file = va_arg(ap, struct output *); 269251881Speter fmt = va_arg(ap, char *); 270251881Speter doformat(file, fmt, ap); 271251881Speter va_end(ap); 272251881Speter} 273251881Speter 274251881Speter 275251881Spetervoid 276251881Speterout1fmt(va_alist) 277251881Speter va_dcl 278251881Speter { 279251881Speter va_list ap; 280251881Speter char *fmt; 281251881Speter 282251881Speter va_start(ap); 283251881Speter fmt = va_arg(ap, char *); 284251881Speter doformat(out1, fmt, ap); 285251881Speter va_end(ap); 286251881Speter} 287251881Speter 288251881Spetervoid 289251881Speterdprintf(va_alist) 290251881Speter va_dcl 291251881Speter { 292251881Speter va_list ap; 293251881Speter char *fmt; 294251881Speter 295251881Speter va_start(ap); 296251881Speter fmt = va_arg(ap, char *); 297251881Speter doformat(out2, fmt, ap); 298251881Speter va_end(ap); 299251881Speter flushout(out2); 300251881Speter} 301251881Speter 302251881Spetervoid 303251881Speterfmtstr(va_alist) 304251881Speter va_dcl 305251881Speter { 306251881Speter va_list ap; 307251881Speter struct output strout; 308251881Speter char *outbuf; 309251881Speter int length; 310251881Speter char *fmt; 311251881Speter 312251881Speter va_start(ap); 313251881Speter outbuf = va_arg(ap, char *); 314251881Speter length = va_arg(ap, int); 315251881Speter fmt = va_arg(ap, char *); 316251881Speter strout.nextc = outbuf; 317251881Speter strout.nleft = length; 318251881Speter strout.fd = BLOCK_OUT; 319251881Speter strout.flags = 0; 320251881Speter doformat(&strout, fmt, ap); 321251881Speter outc('\0', &strout); 322251881Speter if (strout.flags & OUTPUT_ERR) 323251881Speter outbuf[length - 1] = '\0'; 324251881Speter} 325251881Speter#endif /* __STDC__ */ 326251881Speter 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__ 344static const char digit[16] = "0123456789ABCDEF"; 345#else 346static const char digit[17] = "0123456789ABCDEF"; 347#endif 348 349 350void 351doformat(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; 438uns_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); 444number: /* 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 515int 516xwrite(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 548int 549xioctl(fd, request, arg) { 550 int i; 551 552 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 553 return i; 554} 555