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