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