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