1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * 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 5.1 (Berkeley) 03/07/91"; 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 } 114 115 116 char out_junk[16]; 117 118 119 void 120 emptyoutbuf(dest) 121 struct output *dest; 122 { 123 int offset; 124 125 if (dest->fd == BLOCK_OUT) { 126 dest->nextc = out_junk; 127 dest->nleft = sizeof out_junk; 128 dest->flags |= OUTPUT_ERR; 129 } else if (dest->buf == NULL) { 130 INTOFF; 131 dest->buf = ckmalloc(dest->bufsize); 132 dest->nextc = dest->buf; 133 dest->nleft = dest->bufsize; 134 INTON; 135 } else if (dest->fd == MEM_OUT) { 136 offset = dest->bufsize; 137 INTOFF; 138 dest->bufsize <<= 1; 139 dest->buf = ckrealloc(dest->buf, dest->bufsize); 140 dest->nleft = dest->bufsize - offset; 141 dest->nextc = dest->buf + offset; 142 INTON; 143 } else { 144 flushout(dest); 145 } 146 dest->nleft--; 147 } 148 149 150 void 151 flushall() { 152 flushout(&output); 153 flushout(&errout); 154 } 155 156 157 void 158 flushout(dest) 159 struct output *dest; 160 { 161 162 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 163 return; 164 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 165 dest->flags |= OUTPUT_ERR; 166 dest->nextc = dest->buf; 167 dest->nleft = dest->bufsize; 168 } 169 170 171 void 172 freestdout() { 173 INTOFF; 174 if (output.buf) { 175 ckfree(output.buf); 176 output.buf = NULL; 177 output.nleft = 0; 178 } 179 INTON; 180 } 181 182 183 #ifdef __STDC__ 184 void 185 outfmt(struct output *file, char *fmt, ...) { 186 va_list ap; 187 188 va_start(ap, fmt); 189 doformat(file, fmt, ap); 190 va_end(ap); 191 } 192 193 194 void 195 out1fmt(char *fmt, ...) { 196 va_list ap; 197 198 va_start(ap, fmt); 199 doformat(out1, fmt, ap); 200 va_end(ap); 201 } 202 203 204 void 205 fmtstr(char *outbuf, int length, char *fmt, ...) { 206 va_list ap; 207 struct output strout; 208 209 va_start(ap, fmt); 210 strout.nextc = outbuf; 211 strout.nleft = length; 212 strout.fd = BLOCK_OUT; 213 strout.flags = 0; 214 doformat(&strout, fmt, ap); 215 outc('\0', &strout); 216 if (strout.flags & OUTPUT_ERR) 217 outbuf[length - 1] = '\0'; 218 } 219 220 #else /* not __STDC__ */ 221 222 void 223 outfmt(va_alist) 224 va_dcl 225 { 226 va_list ap; 227 struct output *file; 228 char *fmt; 229 230 va_start(ap); 231 file = va_arg(ap, struct output *); 232 fmt = va_arg(ap, char *); 233 doformat(file, fmt, ap); 234 va_end(ap); 235 } 236 237 238 void 239 out1fmt(va_alist) 240 va_dcl 241 { 242 va_list ap; 243 char *fmt; 244 245 va_start(ap); 246 fmt = va_arg(ap, char *); 247 doformat(out1, fmt, ap); 248 va_end(ap); 249 } 250 251 252 void 253 fmtstr(va_alist) 254 va_dcl 255 { 256 va_list ap; 257 struct output strout; 258 char *outbuf; 259 int length; 260 char *fmt; 261 262 va_start(ap); 263 outbuf = va_arg(ap, char *); 264 length = va_arg(ap, int); 265 fmt = va_arg(ap, char *); 266 strout.nextc = outbuf; 267 strout.nleft = length; 268 strout.fd = BLOCK_OUT; 269 strout.flags = 0; 270 doformat(&strout, fmt, ap); 271 outc('\0', &strout); 272 if (strout.flags & OUTPUT_ERR) 273 outbuf[length - 1] = '\0'; 274 } 275 #endif /* __STDC__ */ 276 277 278 /* 279 * Formatted output. This routine handles a subset of the printf formats: 280 * - Formats supported: d, u, o, X, s, and c. 281 * - The x format is also accepted but is treated like X. 282 * - The l modifier is accepted. 283 * - The - and # flags are accepted; # only works with the o format. 284 * - Width and precision may be specified with any format except c. 285 * - An * may be given for the width or precision. 286 * - The obsolete practice of preceding the width with a zero to get 287 * zero padding is not supported; use the precision field. 288 * - A % may be printed by writing %% in the format string. 289 */ 290 291 #define TEMPSIZE 24 292 293 #ifdef __STDC__ 294 static const char digit[16] = "0123456789ABCDEF"; 295 #else 296 static const char digit[17] = "0123456789ABCDEF"; 297 #endif 298 299 300 void 301 doformat(dest, f, ap) 302 register struct output *dest; 303 register char *f; /* format string */ 304 va_list ap; 305 { 306 register char c; 307 char temp[TEMPSIZE]; 308 int flushleft; 309 int sharp; 310 int width; 311 int prec; 312 int islong; 313 char *p; 314 int sign; 315 long l; 316 unsigned long num; 317 unsigned base; 318 int len; 319 int size; 320 int pad; 321 322 while ((c = *f++) != '\0') { 323 if (c != '%') { 324 outc(c, dest); 325 continue; 326 } 327 flushleft = 0; 328 sharp = 0; 329 width = 0; 330 prec = -1; 331 islong = 0; 332 for (;;) { 333 if (*f == '-') 334 flushleft++; 335 else if (*f == '#') 336 sharp++; 337 else 338 break; 339 f++; 340 } 341 if (*f == '*') { 342 width = va_arg(ap, int); 343 f++; 344 } else { 345 while (is_digit(*f)) { 346 width = 10 * width + digit_val(*f++); 347 } 348 } 349 if (*f == '.') { 350 if (*++f == '*') { 351 prec = va_arg(ap, int); 352 f++; 353 } else { 354 prec = 0; 355 while (is_digit(*f)) { 356 prec = 10 * prec + digit_val(*f++); 357 } 358 } 359 } 360 if (*f == 'l') { 361 islong++; 362 f++; 363 } 364 switch (*f) { 365 case 'd': 366 if (islong) 367 l = va_arg(ap, long); 368 else 369 l = va_arg(ap, int); 370 sign = 0; 371 num = l; 372 if (l < 0) { 373 num = -l; 374 sign = 1; 375 } 376 base = 10; 377 goto number; 378 case 'u': 379 base = 10; 380 goto uns_number; 381 case 'o': 382 base = 8; 383 goto uns_number; 384 case 'x': 385 /* we don't implement 'x'; treat like 'X' */ 386 case 'X': 387 base = 16; 388 uns_number: /* an unsigned number */ 389 sign = 0; 390 if (islong) 391 num = va_arg(ap, unsigned long); 392 else 393 num = va_arg(ap, unsigned int); 394 number: /* process a number */ 395 p = temp + TEMPSIZE - 1; 396 *p = '\0'; 397 while (num) { 398 *--p = digit[num % base]; 399 num /= base; 400 } 401 len = (temp + TEMPSIZE - 1) - p; 402 if (prec < 0) 403 prec = 1; 404 if (sharp && *f == 'o' && prec <= len) 405 prec = len + 1; 406 pad = 0; 407 if (width) { 408 size = len; 409 if (size < prec) 410 size = prec; 411 size += sign; 412 pad = width - size; 413 if (flushleft == 0) { 414 while (--pad >= 0) 415 outc(' ', dest); 416 } 417 } 418 if (sign) 419 outc('-', dest); 420 prec -= len; 421 while (--prec >= 0) 422 outc('0', dest); 423 while (*p) 424 outc(*p++, dest); 425 while (--pad >= 0) 426 outc(' ', dest); 427 break; 428 case 's': 429 p = va_arg(ap, char *); 430 pad = 0; 431 if (width) { 432 len = strlen(p); 433 if (prec >= 0 && len > prec) 434 len = prec; 435 pad = width - len; 436 if (flushleft == 0) { 437 while (--pad >= 0) 438 outc(' ', dest); 439 } 440 } 441 prec++; 442 while (--prec != 0 && *p) 443 outc(*p++, dest); 444 while (--pad >= 0) 445 outc(' ', dest); 446 break; 447 case 'c': 448 c = va_arg(ap, int); 449 outc(c, dest); 450 break; 451 default: 452 outc(*f, dest); 453 break; 454 } 455 f++; 456 } 457 } 458 459 460 461 /* 462 * Version of write which resumes after a signal is caught. 463 */ 464 465 int 466 xwrite(fd, buf, nbytes) 467 int fd; 468 char *buf; 469 int nbytes; 470 { 471 int ntry; 472 int i; 473 int n; 474 475 n = nbytes; 476 ntry = 0; 477 for (;;) { 478 i = write(fd, buf, n); 479 if (i > 0) { 480 if ((n -= i) <= 0) 481 return nbytes; 482 buf += i; 483 ntry = 0; 484 } else if (i == 0) { 485 if (++ntry > 10) 486 return nbytes - n; 487 } else if (errno != EINTR) { 488 return -1; 489 } 490 } 491 } 492 493 494 /* 495 * Version of ioctl that retries after a signal is caught. 496 */ 497 498 int 499 xioctl(fd, request, arg) { 500 int i; 501 502 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); 503 return i; 504 } 505