1 /* $NetBSD: shf.c,v 1.4 2000/11/02 01:10:08 christos Exp $ */ 2 3 /* 4 * Shell file I/O routines 5 */ 6 7 #include "sh.h" 8 #include "ksh_stat.h" 9 #include "ksh_limval.h" 10 11 12 /* flags to shf_emptybuf() */ 13 #define EB_READSW 0x01 /* about to switch to reading */ 14 #define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ 15 16 /* 17 * Replacement stdio routines. Stdio is too flakey on too many machines 18 * to be useful when you have multiple processes using the same underlying 19 * file descriptors. 20 */ 21 22 static int shf_fillbuf ARGS((struct shf *shf)); 23 static int shf_emptybuf ARGS((struct shf *shf, int flags)); 24 25 /* Open a file. First three args are for open(), last arg is flags for 26 * this package. Returns NULL if file could not be opened, or if a dup 27 * fails. 28 */ 29 struct shf * 30 shf_open(name, oflags, mode, sflags) 31 const char *name; 32 int oflags; 33 int mode; 34 int sflags; 35 { 36 struct shf *shf; 37 int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 38 int fd; 39 40 /* Done before open so if alloca fails, fd won't be lost. */ 41 shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); 42 shf->areap = ATEMP; 43 shf->buf = (unsigned char *) &shf[1]; 44 shf->bsize = bsize; 45 shf->flags = SHF_ALLOCS; 46 /* Rest filled in by reopen. */ 47 48 fd = open(name, oflags, mode); 49 if (fd < 0) { 50 afree(shf, shf->areap); 51 return NULL; 52 } 53 if ((sflags & SHF_MAPHI) && fd < FDBASE) { 54 int nfd; 55 56 nfd = ksh_dupbase(fd, FDBASE); 57 close(fd); 58 if (nfd < 0) { 59 afree(shf, shf->areap); 60 return NULL; 61 } 62 fd = nfd; 63 } 64 sflags &= ~SHF_ACCMODE; 65 sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD 66 : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR 67 : SHF_RDWR); 68 69 return shf_reopen(fd, sflags, shf); 70 } 71 72 /* Set up the shf structure for a file descriptor. Doesn't fail. */ 73 struct shf * 74 shf_fdopen(fd, sflags, shf) 75 int fd; 76 int sflags; 77 struct shf *shf; 78 { 79 int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 80 81 /* use fcntl() to figure out correct read/write flags */ 82 if (sflags & SHF_GETFL) { 83 int flags = fcntl(fd, F_GETFL, 0); 84 85 if (flags < 0) 86 /* will get an error on first read/write */ 87 sflags |= SHF_RDWR; 88 else 89 switch (flags & O_ACCMODE) { 90 case O_RDONLY: sflags |= SHF_RD; break; 91 case O_WRONLY: sflags |= SHF_WR; break; 92 case O_RDWR: sflags |= SHF_RDWR; break; 93 } 94 } 95 96 if (!(sflags & (SHF_RD | SHF_WR))) 97 internal_errorf(1, "shf_fdopen: missing read/write"); 98 99 if (shf) { 100 if (bsize) { 101 shf->buf = (unsigned char *) alloc(bsize, ATEMP); 102 sflags |= SHF_ALLOCB; 103 } else 104 shf->buf = (unsigned char *) 0; 105 } else { 106 shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); 107 shf->buf = (unsigned char *) &shf[1]; 108 sflags |= SHF_ALLOCS; 109 } 110 shf->areap = ATEMP; 111 shf->fd = fd; 112 shf->rp = shf->wp = shf->buf; 113 shf->rnleft = 0; 114 shf->rbsize = bsize; 115 shf->wnleft = 0; /* force call to shf_emptybuf() */ 116 shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; 117 shf->flags = sflags; 118 shf->errno_ = 0; 119 shf->bsize = bsize; 120 if (sflags & SHF_CLEXEC) 121 fd_clexec(fd); 122 return shf; 123 } 124 125 /* Set up an existing shf (and buffer) to use the given fd */ 126 struct shf * 127 shf_reopen(fd, sflags, shf) 128 int fd; 129 int sflags; 130 struct shf *shf; 131 { 132 int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 133 134 /* use fcntl() to figure out correct read/write flags */ 135 if (sflags & SHF_GETFL) { 136 int flags = fcntl(fd, F_GETFL, 0); 137 138 if (flags < 0) 139 /* will get an error on first read/write */ 140 sflags |= SHF_RDWR; 141 else 142 switch (flags & O_ACCMODE) { 143 case O_RDONLY: sflags |= SHF_RD; break; 144 case O_WRONLY: sflags |= SHF_WR; break; 145 case O_RDWR: sflags |= SHF_RDWR; break; 146 } 147 } 148 149 if (!(sflags & (SHF_RD | SHF_WR))) 150 internal_errorf(1, "shf_reopen: missing read/write"); 151 if (!shf || !shf->buf || shf->bsize < bsize) 152 internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); 153 154 /* assumes shf->buf and shf->bsize already set up */ 155 shf->fd = fd; 156 shf->rp = shf->wp = shf->buf; 157 shf->rnleft = 0; 158 shf->rbsize = bsize; 159 shf->wnleft = 0; /* force call to shf_emptybuf() */ 160 shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; 161 shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; 162 shf->errno_ = 0; 163 if (sflags & SHF_CLEXEC) 164 fd_clexec(fd); 165 return shf; 166 } 167 168 /* Open a string for reading or writing. If reading, bsize is the number 169 * of bytes that can be read. If writing, bsize is the maximum number of 170 * bytes that can be written. If shf is not null, it is filled in and 171 * returned, if it is null, shf is allocated. If writing and buf is null 172 * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is 173 * used for the initial size). Doesn't fail. 174 * When writing, a byte is reserved for a trailing null - see shf_sclose(). 175 */ 176 struct shf * 177 shf_sopen(buf, bsize, sflags, shf) 178 char *buf; 179 int bsize; 180 int sflags; 181 struct shf *shf; 182 { 183 /* can't have a read+write string */ 184 if (!(sflags & (SHF_RD | SHF_WR)) 185 || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR)) 186 internal_errorf(1, "shf_sopen: flags 0x%x", sflags); 187 188 if (!shf) { 189 shf = (struct shf *) alloc(sizeof(struct shf), ATEMP); 190 sflags |= SHF_ALLOCS; 191 } 192 shf->areap = ATEMP; 193 if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { 194 if (bsize <= 0) 195 bsize = 64; 196 sflags |= SHF_ALLOCB; 197 buf = alloc(bsize, shf->areap); 198 } 199 shf->fd = -1; 200 shf->buf = shf->rp = shf->wp = (unsigned char *) buf; 201 shf->rnleft = bsize; 202 shf->rbsize = bsize; 203 shf->wnleft = bsize - 1; /* space for a '\0' */ 204 shf->wbsize = bsize; 205 shf->flags = sflags | SHF_STRING; 206 shf->errno_ = 0; 207 shf->bsize = bsize; 208 209 return shf; 210 } 211 212 /* Flush and close file descriptor, free the shf structure */ 213 int 214 shf_close(shf) 215 struct shf *shf; 216 { 217 int ret = 0; 218 219 if (shf->fd >= 0) { 220 ret = shf_flush(shf); 221 if (close(shf->fd) < 0) 222 ret = EOF; 223 } 224 if (shf->flags & SHF_ALLOCS) 225 afree(shf, shf->areap); 226 else if (shf->flags & SHF_ALLOCB) 227 afree(shf->buf, shf->areap); 228 229 return ret; 230 } 231 232 /* Flush and close file descriptor, don't free file structure */ 233 int 234 shf_fdclose(shf) 235 struct shf *shf; 236 { 237 int ret = 0; 238 239 if (shf->fd >= 0) { 240 ret = shf_flush(shf); 241 if (close(shf->fd) < 0) 242 ret = EOF; 243 shf->rnleft = 0; 244 shf->rp = shf->buf; 245 shf->wnleft = 0; 246 shf->fd = -1; 247 } 248 249 return ret; 250 } 251 252 /* Close a string - if it was opened for writing, it is null terminated; 253 * returns a pointer to the string and frees shf if it was allocated 254 * (does not free string if it was allocated). 255 */ 256 char * 257 shf_sclose(shf) 258 struct shf *shf; 259 { 260 unsigned char *s = shf->buf; 261 262 /* null terminate */ 263 if (shf->flags & SHF_WR) { 264 shf->wnleft++; 265 shf_putc('\0', shf); 266 } 267 if (shf->flags & SHF_ALLOCS) 268 afree(shf, shf->areap); 269 return (char *) s; 270 } 271 272 /* Flush and free file structure, don't close file descriptor */ 273 int 274 shf_finish(shf) 275 struct shf *shf; 276 { 277 int ret = 0; 278 279 if (shf->fd >= 0) 280 ret = shf_flush(shf); 281 if (shf->flags & SHF_ALLOCS) 282 afree(shf, shf->areap); 283 else if (shf->flags & SHF_ALLOCB) 284 afree(shf->buf, shf->areap); 285 286 return ret; 287 } 288 289 /* Un-read what has been read but not examined, or write what has been 290 * buffered. Returns 0 for success, EOF for (write) error. 291 */ 292 int 293 shf_flush(shf) 294 struct shf *shf; 295 { 296 if (shf->flags & SHF_STRING) 297 return (shf->flags & SHF_WR) ? EOF : 0; 298 299 if (shf->fd < 0) 300 internal_errorf(1, "shf_flush: no fd"); 301 302 if (shf->flags & SHF_ERROR) { 303 errno = shf->errno_; 304 return EOF; 305 } 306 307 if (shf->flags & SHF_READING) { 308 shf->flags &= ~(SHF_EOF | SHF_READING); 309 if (shf->rnleft > 0) { 310 lseek(shf->fd, (off_t) -shf->rnleft, 1); 311 shf->rnleft = 0; 312 shf->rp = shf->buf; 313 } 314 return 0; 315 } else if (shf->flags & SHF_WRITING) 316 return shf_emptybuf(shf, 0); 317 318 return 0; 319 } 320 321 /* Write out any buffered data. If currently reading, flushes the read 322 * buffer. Returns 0 for success, EOF for (write) error. 323 */ 324 static int 325 shf_emptybuf(shf, flags) 326 struct shf *shf; 327 int flags; 328 { 329 int ret = 0; 330 331 if (!(shf->flags & SHF_STRING) && shf->fd < 0) 332 internal_errorf(1, "shf_emptybuf: no fd"); 333 334 if (shf->flags & SHF_ERROR) { 335 errno = shf->errno_; 336 return EOF; 337 } 338 339 if (shf->flags & SHF_READING) { 340 if (flags & EB_READSW) /* doesn't happen */ 341 return 0; 342 ret = shf_flush(shf); 343 shf->flags &= ~SHF_READING; 344 } 345 if (shf->flags & SHF_STRING) { 346 unsigned char *nbuf; 347 348 /* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB 349 * is set... (changing the shf pointer could cause problems) 350 */ 351 if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) 352 || !(shf->flags & SHF_ALLOCB)) 353 return EOF; 354 /* allocate more space for buffer */ 355 nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2, 356 shf->areap); 357 shf->rp = nbuf + (shf->rp - shf->buf); 358 shf->wp = nbuf + (shf->wp - shf->buf); 359 shf->rbsize += shf->wbsize; 360 shf->wnleft += shf->wbsize; 361 shf->wbsize *= 2; 362 shf->buf = nbuf; 363 } else { 364 if (shf->flags & SHF_WRITING) { 365 int ntowrite = shf->wp - shf->buf; 366 unsigned char *buf = shf->buf; 367 int n; 368 369 while (ntowrite > 0) { 370 n = write(shf->fd, buf, ntowrite); 371 if (n < 0) { 372 if (errno == EINTR 373 && !(shf->flags & SHF_INTERRUPT)) 374 continue; 375 shf->flags |= SHF_ERROR; 376 shf->errno_ = errno; 377 shf->wnleft = 0; 378 if (buf != shf->buf) { 379 /* allow a second flush 380 * to work */ 381 memmove(shf->buf, buf, 382 ntowrite); 383 shf->wp = shf->buf + ntowrite; 384 } 385 return EOF; 386 } 387 buf += n; 388 ntowrite -= n; 389 } 390 if (flags & EB_READSW) { 391 shf->wp = shf->buf; 392 shf->wnleft = 0; 393 shf->flags &= ~SHF_WRITING; 394 return 0; 395 } 396 } 397 shf->wp = shf->buf; 398 shf->wnleft = shf->wbsize; 399 } 400 shf->flags |= SHF_WRITING; 401 402 return ret; 403 } 404 405 /* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ 406 static int 407 shf_fillbuf(shf) 408 struct shf *shf; 409 { 410 if (shf->flags & SHF_STRING) 411 return 0; 412 413 if (shf->fd < 0) 414 internal_errorf(1, "shf_fillbuf: no fd"); 415 416 if (shf->flags & (SHF_EOF | SHF_ERROR)) { 417 if (shf->flags & SHF_ERROR) 418 errno = shf->errno_; 419 return EOF; 420 } 421 422 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 423 return EOF; 424 425 shf->flags |= SHF_READING; 426 427 shf->rp = shf->buf; 428 while (1) { 429 shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, 430 shf->rbsize); 431 if (shf->rnleft < 0 && errno == EINTR 432 && !(shf->flags & SHF_INTERRUPT)) 433 continue; 434 break; 435 } 436 if (shf->rnleft <= 0) { 437 if (shf->rnleft < 0) { 438 shf->flags |= SHF_ERROR; 439 shf->errno_ = errno; 440 shf->rnleft = 0; 441 shf->rp = shf->buf; 442 return EOF; 443 } 444 shf->flags |= SHF_EOF; 445 } 446 return 0; 447 } 448 449 /* Seek to a new position in the file. If writing, flushes the buffer 450 * first. If reading, optimizes small relative seeks that stay inside the 451 * buffer. Returns 0 for success, EOF otherwise. 452 */ 453 int 454 shf_seek(shf, where, from) 455 struct shf *shf; 456 off_t where; 457 int from; 458 { 459 if (shf->fd < 0) { 460 errno = EINVAL; 461 return EOF; 462 } 463 464 if (shf->flags & SHF_ERROR) { 465 errno = shf->errno_; 466 return EOF; 467 } 468 469 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 470 return EOF; 471 472 if (shf->flags & SHF_READING) { 473 if (from == SEEK_CUR && 474 (where < 0 ? 475 -where >= shf->rbsize - shf->rnleft : 476 where < shf->rnleft)) { 477 shf->rnleft -= where; 478 shf->rp += where; 479 return 0; 480 } 481 shf->rnleft = 0; 482 shf->rp = shf->buf; 483 } 484 485 shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING); 486 487 if (lseek(shf->fd, where, from) < 0) { 488 shf->errno_ = errno; 489 shf->flags |= SHF_ERROR; 490 return EOF; 491 } 492 493 return 0; 494 } 495 496 497 /* Read a buffer from shf. Returns the number of bytes read into buf, 498 * if no bytes were read, returns 0 if end of file was seen, EOF if 499 * a read error occurred. 500 */ 501 int 502 shf_read(buf, bsize, shf) 503 char *buf; 504 int bsize; 505 struct shf *shf; 506 { 507 int orig_bsize = bsize; 508 int ncopy; 509 510 if (!(shf->flags & SHF_RD)) 511 internal_errorf(1, "shf_read: flags %x", shf->flags); 512 513 if (bsize <= 0) 514 internal_errorf(1, "shf_read: bsize %d", bsize); 515 516 while (bsize > 0) { 517 if (shf->rnleft == 0 518 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 519 break; 520 ncopy = shf->rnleft; 521 if (ncopy > bsize) 522 ncopy = bsize; 523 memcpy(buf, shf->rp, ncopy); 524 buf += ncopy; 525 bsize -= ncopy; 526 shf->rp += ncopy; 527 shf->rnleft -= ncopy; 528 } 529 /* Note: fread(3S) returns 0 for errors - this doesn't */ 530 return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) 531 : orig_bsize - bsize; 532 } 533 534 /* Read up to a newline or EOF. The newline is put in buf; buf is always 535 * null terminated. Returns NULL on read error or if nothing was read before 536 * end of file, returns a pointer to the null byte in buf otherwise. 537 */ 538 char * 539 shf_getse(buf, bsize, shf) 540 char *buf; 541 int bsize; 542 struct shf *shf; 543 { 544 unsigned char *end; 545 int ncopy; 546 char *orig_buf = buf; 547 548 if (!(shf->flags & SHF_RD)) 549 internal_errorf(1, "shf_getse: flags %x", shf->flags); 550 551 if (bsize <= 0) 552 return (char *) 0; 553 554 --bsize; /* save room for null */ 555 do { 556 if (shf->rnleft == 0) { 557 if (shf_fillbuf(shf) == EOF) 558 return NULL; 559 if (shf->rnleft == 0) { 560 *buf = '\0'; 561 return buf == orig_buf ? NULL : buf; 562 } 563 } 564 end = (unsigned char *) memchr((char *) shf->rp, '\n', 565 shf->rnleft); 566 ncopy = end ? end - shf->rp + 1 : shf->rnleft; 567 if (ncopy > bsize) 568 ncopy = bsize; 569 memcpy(buf, (char *) shf->rp, ncopy); 570 shf->rp += ncopy; 571 shf->rnleft -= ncopy; 572 buf += ncopy; 573 bsize -= ncopy; 574 #ifdef OS2 575 if (end && buf > orig_buf + 1 && buf[-2] == '\r') { 576 buf--; 577 bsize++; 578 buf[-1] = '\n'; 579 } 580 #endif 581 582 } while (!end && bsize); 583 *buf = '\0'; 584 return buf; 585 } 586 587 /* Returns the char read. Returns EOF for error and end of file. */ 588 int 589 shf_getchar(shf) 590 struct shf *shf; 591 { 592 if (!(shf->flags & SHF_RD)) 593 internal_errorf(1, "shf_getchar: flags %x", shf->flags); 594 595 if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 596 return EOF; 597 --shf->rnleft; 598 return *shf->rp++; 599 } 600 601 /* Put a character back in the input stream. Returns the character if 602 * successful, EOF if there is no room. 603 */ 604 int 605 shf_ungetc(c, shf) 606 int c; 607 struct shf *shf; 608 { 609 if (!(shf->flags & SHF_RD)) 610 internal_errorf(1, "shf_ungetc: flags %x", shf->flags); 611 612 if ((shf->flags & SHF_ERROR) || c == EOF 613 || (shf->rp == shf->buf && shf->rnleft)) 614 return EOF; 615 616 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 617 return EOF; 618 619 if (shf->rp == shf->buf) 620 shf->rp = shf->buf + shf->rbsize; 621 if (shf->flags & SHF_STRING) { 622 /* Can unget what was read, but not something different - we 623 * don't want to modify a string. 624 */ 625 if (shf->rp[-1] != c) 626 return EOF; 627 shf->flags &= ~SHF_EOF; 628 shf->rp--; 629 shf->rnleft++; 630 return c; 631 } 632 shf->flags &= ~SHF_EOF; 633 *--(shf->rp) = c; 634 shf->rnleft++; 635 return c; 636 } 637 638 /* Write a character. Returns the character if successful, EOF if 639 * the char could not be written. 640 */ 641 int 642 shf_putchar(c, shf) 643 int c; 644 struct shf *shf; 645 { 646 if (!(shf->flags & SHF_WR)) 647 internal_errorf(1, "shf_putchar: flags %x", shf->flags); 648 649 if (c == EOF) 650 return EOF; 651 652 if (shf->flags & SHF_UNBUF) { 653 char cc = c; 654 int n; 655 656 if (shf->fd < 0) 657 internal_errorf(1, "shf_putchar: no fd"); 658 if (shf->flags & SHF_ERROR) { 659 errno = shf->errno_; 660 return EOF; 661 } 662 while ((n = write(shf->fd, &cc, 1)) != 1) 663 if (n < 0) { 664 if (errno == EINTR 665 && !(shf->flags & SHF_INTERRUPT)) 666 continue; 667 shf->flags |= SHF_ERROR; 668 shf->errno_ = errno; 669 return EOF; 670 } 671 } else { 672 /* Flush deals with strings and sticky errors */ 673 if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) 674 return EOF; 675 shf->wnleft--; 676 *shf->wp++ = c; 677 } 678 679 return c; 680 } 681 682 /* Write a string. Returns the length of the string if successful, EOF if 683 * the string could not be written. 684 */ 685 int 686 shf_puts(s, shf) 687 const char *s; 688 struct shf *shf; 689 { 690 if (!s) 691 return EOF; 692 693 return shf_write(s, strlen(s), shf); 694 } 695 696 /* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ 697 int 698 shf_write(buf, nbytes, shf) 699 const char *buf; 700 int nbytes; 701 struct shf *shf; 702 { 703 int orig_nbytes = nbytes; 704 int n; 705 int ncopy; 706 707 if (!(shf->flags & SHF_WR)) 708 internal_errorf(1, "shf_write: flags %x", shf->flags); 709 710 if (nbytes < 0) 711 internal_errorf(1, "shf_write: nbytes %d", nbytes); 712 713 /* Don't buffer if buffer is empty and we're writting a large amount. */ 714 if ((ncopy = shf->wnleft) 715 && (shf->wp != shf->buf || nbytes < shf->wnleft)) 716 { 717 if (ncopy > nbytes) 718 ncopy = nbytes; 719 memcpy(shf->wp, buf, ncopy); 720 nbytes -= ncopy; 721 buf += ncopy; 722 shf->wp += ncopy; 723 shf->wnleft -= ncopy; 724 } 725 if (nbytes > 0) { 726 /* Flush deals with strings and sticky errors */ 727 if (shf_emptybuf(shf, EB_GROW) == EOF) 728 return EOF; 729 if (nbytes > shf->wbsize) { 730 ncopy = nbytes; 731 if (shf->wbsize) 732 ncopy -= nbytes % shf->wbsize; 733 nbytes -= ncopy; 734 while (ncopy > 0) { 735 n = write(shf->fd, buf, ncopy); 736 if (n < 0) { 737 if (errno == EINTR 738 && !(shf->flags & SHF_INTERRUPT)) 739 continue; 740 shf->flags |= SHF_ERROR; 741 shf->errno_ = errno; 742 shf->wnleft = 0; 743 /* Note: fwrite(3S) returns 0 for 744 * errors - this doesn't */ 745 return EOF; 746 } 747 buf += n; 748 ncopy -= n; 749 } 750 } 751 if (nbytes > 0) { 752 memcpy(shf->wp, buf, nbytes); 753 shf->wp += nbytes; 754 shf->wnleft -= nbytes; 755 } 756 } 757 758 return orig_nbytes; 759 } 760 761 int 762 #ifdef HAVE_PROTOTYPES 763 shf_fprintf(struct shf *shf, const char *fmt, ...) 764 #else 765 shf_fprintf(shf, fmt, va_alist) 766 struct shf *shf; 767 const char *fmt; 768 va_dcl 769 #endif 770 { 771 va_list args; 772 int n; 773 774 SH_VA_START(args, fmt); 775 n = shf_vfprintf(shf, fmt, args); 776 va_end(args); 777 778 return n; 779 } 780 781 int 782 #ifdef HAVE_PROTOTYPES 783 shf_snprintf(char *buf, int bsize, const char *fmt, ...) 784 #else 785 shf_snprintf(buf, bsize, fmt, va_alist) 786 char *buf; 787 int bsize; 788 const char *fmt; 789 va_dcl 790 #endif 791 { 792 struct shf shf; 793 va_list args; 794 int n; 795 796 if (!buf || bsize <= 0) 797 internal_errorf(1, "shf_snprintf: buf %lx, bsize %d", 798 (long) buf, bsize); 799 800 shf_sopen(buf, bsize, SHF_WR, &shf); 801 SH_VA_START(args, fmt); 802 n = shf_vfprintf(&shf, fmt, args); 803 va_end(args); 804 shf_sclose(&shf); /* null terminates */ 805 return n; 806 } 807 808 char * 809 #ifdef HAVE_PROTOTYPES 810 shf_smprintf(const char *fmt, ...) 811 #else 812 shf_smprintf(fmt, va_alist) 813 char *fmt; 814 va_dcl 815 #endif 816 { 817 struct shf shf; 818 va_list args; 819 820 shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf); 821 SH_VA_START(args, fmt); 822 shf_vfprintf(&shf, fmt, args); 823 va_end(args); 824 return shf_sclose(&shf); /* null terminates */ 825 } 826 827 #undef FP /* if you want floating point stuff */ 828 829 #define BUF_SIZE 128 830 #define FPBUF_SIZE (DMAXEXP+16)/* this must be > 831 * MAX(DMAXEXP, log10(pow(2, DSIGNIF))) 832 * + ceil(log10(DMAXEXP)) + 8 (I think). 833 * Since this is hard to express as a 834 * constant, just use a large buffer. 835 */ 836 837 /* 838 * What kinda of machine we on? Hopefully the C compiler will optimize 839 * this out... 840 * 841 * For shorts, we want sign extend for %d but not for %[oxu] - on 16 bit 842 * machines it don't matter. Assmumes C compiler has converted shorts to 843 * ints before pushing them. 844 */ 845 #define POP_INT(f, s, a) (((f) & FL_LONG) ? \ 846 va_arg((a), unsigned long) \ 847 : \ 848 (sizeof(int) < sizeof(long) ? \ 849 ((s) ? \ 850 (long) va_arg((a), int) \ 851 : \ 852 va_arg((a), unsigned)) \ 853 : \ 854 va_arg((a), unsigned))) 855 856 #define ABIGNUM 32000 /* big numer that will fit in a short */ 857 #define LOG2_10 3.321928094887362347870319429 /* log base 2 of 10 */ 858 859 #define FL_HASH 0x001 /* `#' seen */ 860 #define FL_PLUS 0x002 /* `+' seen */ 861 #define FL_RIGHT 0x004 /* `-' seen */ 862 #define FL_BLANK 0x008 /* ` ' seen */ 863 #define FL_SHORT 0x010 /* `h' seen */ 864 #define FL_LONG 0x020 /* `l' seen */ 865 #define FL_ZERO 0x040 /* `0' seen */ 866 #define FL_DOT 0x080 /* '.' seen */ 867 #define FL_UPPER 0x100 /* format character was uppercase */ 868 #define FL_NUMBER 0x200 /* a number was formated %[douxefg] */ 869 870 871 #ifdef FP 872 #include <math.h> 873 874 static double 875 my_ceil(d) 876 double d; 877 { 878 double i; 879 880 return d - modf(d, &i) + (d < 0 ? -1 : 1); 881 } 882 #endif /* FP */ 883 884 int 885 shf_vfprintf(shf, fmt, args) 886 struct shf *shf; 887 const char *fmt; 888 va_list args; 889 { 890 char c, *s; 891 int UNINITIALIZED(tmp); 892 int field, precision; 893 int len; 894 int flags; 895 unsigned long lnum; 896 /* %#o produces the longest output */ 897 char numbuf[(BITS(long) + 2) / 3 + 1]; 898 /* this stuff for dealing with the buffer */ 899 int nwritten = 0; 900 #ifdef FP 901 /* should be in <math.h> 902 * extern double frexp(); 903 */ 904 extern char *ecvt(); 905 906 double fpnum; 907 int expo, decpt; 908 char style; 909 char fpbuf[FPBUF_SIZE]; 910 #endif /* FP */ 911 912 if (!fmt) 913 return 0; 914 915 while ((c = *fmt++)) { 916 if (c != '%') { 917 shf_putc(c, shf); 918 nwritten++; 919 continue; 920 } 921 /* 922 * This will accept flags/fields in any order - not 923 * just the order specified in printf(3), but this is 924 * the way _doprnt() seems to work (on bsd and sysV). 925 * The only resriction is that the format character must 926 * come last :-). 927 */ 928 flags = field = precision = 0; 929 for ( ; (c = *fmt++) ; ) { 930 switch (c) { 931 case '#': 932 flags |= FL_HASH; 933 continue; 934 935 case '+': 936 flags |= FL_PLUS; 937 continue; 938 939 case '-': 940 flags |= FL_RIGHT; 941 continue; 942 943 case ' ': 944 flags |= FL_BLANK; 945 continue; 946 947 case '0': 948 if (!(flags & FL_DOT)) 949 flags |= FL_ZERO; 950 continue; 951 952 case '.': 953 flags |= FL_DOT; 954 precision = 0; 955 continue; 956 957 case '*': 958 tmp = va_arg(args, int); 959 if (flags & FL_DOT) 960 precision = tmp; 961 else if ((field = tmp) < 0) { 962 field = -field; 963 flags |= FL_RIGHT; 964 } 965 continue; 966 967 case 'l': 968 flags |= FL_LONG; 969 continue; 970 971 case 'h': 972 flags |= FL_SHORT; 973 continue; 974 } 975 if (digit(c)) { 976 tmp = c - '0'; 977 while (c = *fmt++, digit(c)) 978 tmp = tmp * 10 + c - '0'; 979 --fmt; 980 if (tmp < 0) /* overflow? */ 981 tmp = 0; 982 if (flags & FL_DOT) 983 precision = tmp; 984 else 985 field = tmp; 986 continue; 987 } 988 break; 989 } 990 991 if (precision < 0) 992 precision = 0; 993 994 if (!c) /* nasty format */ 995 break; 996 997 if (c >= 'A' && c <= 'Z') { 998 flags |= FL_UPPER; 999 c = c - 'A' + 'a'; 1000 } 1001 1002 switch (c) { 1003 case 'p': /* pointer */ 1004 flags &= ~(FL_LONG | FL_SHORT); 1005 if (sizeof(char *) > sizeof(int)) 1006 flags |= FL_LONG; /* hope it fits.. */ 1007 /* aaahhh... */ 1008 case 'd': 1009 case 'i': 1010 case 'o': 1011 case 'u': 1012 case 'x': 1013 flags |= FL_NUMBER; 1014 s = &numbuf[sizeof(numbuf)]; 1015 lnum = POP_INT(flags, c == 'd', args); 1016 switch (c) { 1017 case 'd': 1018 case 'i': 1019 if (0 > (long) lnum) 1020 lnum = - (long) lnum, tmp = 1; 1021 else 1022 tmp = 0; 1023 /* aaahhhh..... */ 1024 1025 case 'u': 1026 do { 1027 *--s = lnum % 10 + '0'; 1028 lnum /= 10; 1029 } while (lnum); 1030 1031 if (c != 'u') { 1032 if (tmp) 1033 *--s = '-'; 1034 else if (flags & FL_PLUS) 1035 *--s = '+'; 1036 else if (flags & FL_BLANK) 1037 *--s = ' '; 1038 } 1039 break; 1040 1041 case 'o': 1042 do { 1043 *--s = (lnum & 0x7) + '0'; 1044 lnum >>= 3; 1045 } while (lnum); 1046 1047 if ((flags & FL_HASH) && *s != '0') 1048 *--s = '0'; 1049 break; 1050 1051 case 'p': 1052 case 'x': 1053 { 1054 const char *digits = (flags & FL_UPPER) ? 1055 "0123456789ABCDEF" 1056 : "0123456789abcdef"; 1057 do { 1058 *--s = digits[lnum & 0xf]; 1059 lnum >>= 4; 1060 } while (lnum); 1061 1062 if (flags & FL_HASH) { 1063 *--s = (flags & FL_UPPER) ? 'X' : 'x'; 1064 *--s = '0'; 1065 } 1066 } 1067 } 1068 len = &numbuf[sizeof(numbuf)] - s; 1069 if (flags & FL_DOT) { 1070 if (precision > len) { 1071 field = precision; 1072 flags |= FL_ZERO; 1073 } else 1074 precision = len; /* no loss */ 1075 } 1076 break; 1077 1078 #ifdef FP 1079 case 'e': 1080 case 'g': 1081 case 'f': 1082 { 1083 char *p; 1084 1085 /* 1086 * This could proabably be done better, 1087 * but it seems to work. Note that gcvt() 1088 * is not used, as you cannot tell it to 1089 * not strip the zeros. 1090 */ 1091 flags |= FL_NUMBER; 1092 if (!(flags & FL_DOT)) 1093 precision = 6; /* default */ 1094 /* 1095 * Assumes doubles are pushed on 1096 * the stack. If this is not so, then 1097 * FL_LONG/FL_SHORT should be checked. 1098 */ 1099 fpnum = va_arg(args, double); 1100 s = fpbuf; 1101 style = c; 1102 /* 1103 * This is the same as 1104 * expo = ceil(log10(fpnum)) 1105 * but doesn't need -lm. This is an 1106 * aproximation as expo is rounded up. 1107 */ 1108 (void) frexp(fpnum, &expo); 1109 expo = my_ceil(expo / LOG2_10); 1110 1111 if (expo < 0) 1112 expo = 0; 1113 1114 p = ecvt(fpnum, precision + 1 + expo, 1115 &decpt, &tmp); 1116 if (c == 'g') { 1117 if (decpt < -4 || decpt > precision) 1118 style = 'e'; 1119 else 1120 style = 'f'; 1121 if (decpt > 0 && (precision -= decpt) < 0) 1122 precision = 0; 1123 } 1124 if (tmp) 1125 *s++ = '-'; 1126 else if (flags & FL_PLUS) 1127 *s++ = '+'; 1128 else if (flags & FL_BLANK) 1129 *s++ = ' '; 1130 1131 if (style == 'e') 1132 *s++ = *p++; 1133 else { 1134 if (decpt > 0) { 1135 /* Overflow check - should 1136 * never have this problem. 1137 */ 1138 if (decpt > 1139 &fpbuf[sizeof(fpbuf)] 1140 - s - 8) 1141 decpt = 1142 &fpbuf[sizeof(fpbuf)] 1143 - s - 8; 1144 (void) memcpy(s, p, decpt); 1145 s += decpt; 1146 p += decpt; 1147 } else 1148 *s++ = '0'; 1149 } 1150 1151 /* print the fraction? */ 1152 if (precision > 0) { 1153 *s++ = '.'; 1154 /* Overflow check - should 1155 * never have this problem. 1156 */ 1157 if (precision > &fpbuf[sizeof(fpbuf)] 1158 - s - 7) 1159 precision = 1160 &fpbuf[sizeof(fpbuf)] 1161 - s - 7; 1162 for (tmp = decpt; tmp++ < 0 && 1163 precision > 0 ; precision--) 1164 *s++ = '0'; 1165 tmp = strlen(p); 1166 if (precision > tmp) 1167 precision = tmp; 1168 /* Overflow check - should 1169 * never have this problem. 1170 */ 1171 if (precision > &fpbuf[sizeof(fpbuf)] 1172 - s - 7) 1173 precision = 1174 &fpbuf[sizeof(fpbuf)] 1175 - s - 7; 1176 (void) memcpy(s, p, precision); 1177 s += precision; 1178 /* 1179 * `g' format strips trailing 1180 * zeros after the decimal. 1181 */ 1182 if (c == 'g' && !(flags & FL_HASH)) { 1183 while (*--s == '0') 1184 ; 1185 if (*s != '.') 1186 s++; 1187 } 1188 } else if (flags & FL_HASH) 1189 *s++ = '.'; 1190 1191 if (style == 'e') { 1192 *s++ = (flags & FL_UPPER) ? 'E' : 'e'; 1193 if (--decpt >= 0) 1194 *s++ = '+'; 1195 else { 1196 *s++ = '-'; 1197 decpt = -decpt; 1198 } 1199 p = &numbuf[sizeof(numbuf)]; 1200 for (tmp = 0; tmp < 2 || decpt ; tmp++) { 1201 *--p = '0' + decpt % 10; 1202 decpt /= 10; 1203 } 1204 tmp = &numbuf[sizeof(numbuf)] - p; 1205 (void) memcpy(s, p, tmp); 1206 s += tmp; 1207 } 1208 1209 len = s - fpbuf; 1210 s = fpbuf; 1211 precision = len; 1212 break; 1213 } 1214 #endif /* FP */ 1215 1216 case 's': 1217 if (!(s = va_arg(args, char *))) 1218 s = "(null %s)"; 1219 len = strlen(s); 1220 break; 1221 1222 case 'c': 1223 flags &= ~FL_DOT; 1224 numbuf[0] = va_arg(args, int); 1225 s = numbuf; 1226 len = 1; 1227 break; 1228 1229 case '%': 1230 default: 1231 numbuf[0] = c; 1232 s = numbuf; 1233 len = 1; 1234 break; 1235 } 1236 1237 /* 1238 * At this point s should point to a string that is 1239 * to be formatted, and len should be the length of the 1240 * string. 1241 */ 1242 if (!(flags & FL_DOT) || len < precision) 1243 precision = len; 1244 if (field > precision) { 1245 field -= precision; 1246 if (!(flags & FL_RIGHT)) { 1247 field = -field; 1248 /* skip past sign or 0x when padding with 0 */ 1249 if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { 1250 if (*s == '+' || *s == '-' || *s ==' ') 1251 { 1252 shf_putc(*s, shf); 1253 s++; 1254 precision--; 1255 nwritten++; 1256 } else if (*s == '0') { 1257 shf_putc(*s, shf); 1258 s++; 1259 nwritten++; 1260 if (--precision > 0 && 1261 (*s | 0x20) == 'x') 1262 { 1263 shf_putc(*s, shf); 1264 s++; 1265 precision--; 1266 nwritten++; 1267 } 1268 } 1269 c = '0'; 1270 } else 1271 c = flags & FL_ZERO ? '0' : ' '; 1272 if (field < 0) { 1273 nwritten += -field; 1274 for ( ; field < 0 ; field++) 1275 shf_putc(c, shf); 1276 } 1277 } else 1278 c = ' '; 1279 } else 1280 field = 0; 1281 1282 if (precision > 0) { 1283 nwritten += precision; 1284 for ( ; precision-- > 0 ; s++) 1285 shf_putc(*s, shf); 1286 } 1287 if (field > 0) { 1288 nwritten += field; 1289 for ( ; field > 0 ; --field) 1290 shf_putc(c, shf); 1291 } 1292 } 1293 1294 return shf_error(shf) ? EOF : nwritten; 1295 } 1296