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