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