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