1 /* $NetBSD: shf.c,v 1.16 2024/02/05 21:20:09 andvar 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.16 2024/02/05 21:20:09 andvar Exp $"); 10 #endif 11 12 #include <sys/stat.h> 13 14 #include "sh.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 581 } while (!end && bsize); 582 *buf = '\0'; 583 return buf; 584 } 585 586 /* Returns the char read. Returns EOF for error and end of file. */ 587 int 588 shf_getchar(shf) 589 struct shf *shf; 590 { 591 if (!(shf->flags & SHF_RD)) 592 internal_errorf(1, "shf_getchar: flags %x", shf->flags); 593 594 if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 595 return EOF; 596 --shf->rnleft; 597 return *shf->rp++; 598 } 599 600 /* Put a character back in the input stream. Returns the character if 601 * successful, EOF if there is no room. 602 */ 603 int 604 shf_ungetc(c, shf) 605 int c; 606 struct shf *shf; 607 { 608 if (!(shf->flags & SHF_RD)) 609 internal_errorf(1, "shf_ungetc: flags %x", shf->flags); 610 611 if ((shf->flags & SHF_ERROR) || c == EOF 612 || (shf->rp == shf->buf && shf->rnleft)) 613 return EOF; 614 615 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 616 return EOF; 617 618 if (shf->rp == shf->buf) 619 shf->rp = shf->buf + shf->rbsize; 620 if (shf->flags & SHF_STRING) { 621 /* Can unget what was read, but not something different - we 622 * don't want to modify a string. 623 */ 624 if (shf->rp[-1] != c) 625 return EOF; 626 shf->flags &= ~SHF_EOF; 627 shf->rp--; 628 shf->rnleft++; 629 return c; 630 } 631 shf->flags &= ~SHF_EOF; 632 *--(shf->rp) = c; 633 shf->rnleft++; 634 return c; 635 } 636 637 /* Write a character. Returns the character if successful, EOF if 638 * the char could not be written. 639 */ 640 int 641 shf_putchar(c, shf) 642 int c; 643 struct shf *shf; 644 { 645 if (!(shf->flags & SHF_WR)) 646 internal_errorf(1, "shf_putchar: flags %x", shf->flags); 647 648 if (c == EOF) 649 return EOF; 650 651 if (shf->flags & SHF_UNBUF) { 652 char cc = c; 653 int n; 654 655 if (shf->fd < 0) 656 internal_errorf(1, "shf_putchar: no fd"); 657 if (shf->flags & SHF_ERROR) { 658 errno = shf->errno_; 659 return EOF; 660 } 661 while ((n = write(shf->fd, &cc, 1)) != 1) 662 if (n < 0) { 663 if (errno == EINTR 664 && !(shf->flags & SHF_INTERRUPT)) 665 continue; 666 shf->flags |= SHF_ERROR; 667 shf->errno_ = errno; 668 return EOF; 669 } 670 } else { 671 /* Flush deals with strings and sticky errors */ 672 if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) 673 return EOF; 674 shf->wnleft--; 675 *shf->wp++ = c; 676 } 677 678 return c; 679 } 680 681 /* Write a string. Returns the length of the string if successful, EOF if 682 * the string could not be written. 683 */ 684 int 685 shf_puts(s, shf) 686 const char *s; 687 struct shf *shf; 688 { 689 if (!s) 690 return EOF; 691 692 return shf_write(s, strlen(s), shf); 693 } 694 695 /* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ 696 int 697 shf_write(buf, nbytes, shf) 698 const char *buf; 699 int nbytes; 700 struct shf *shf; 701 { 702 int orig_nbytes = nbytes; 703 int n; 704 int ncopy; 705 706 if (!(shf->flags & SHF_WR)) 707 internal_errorf(1, "shf_write: flags %x", shf->flags); 708 709 if (nbytes < 0) 710 internal_errorf(1, "shf_write: nbytes %d", nbytes); 711 712 /* Don't buffer if buffer is empty and we're writing a large amount. */ 713 if ((ncopy = shf->wnleft) 714 && (shf->wp != shf->buf || nbytes < shf->wnleft)) 715 { 716 if (ncopy > nbytes) 717 ncopy = nbytes; 718 memcpy(shf->wp, buf, ncopy); 719 nbytes -= ncopy; 720 buf += ncopy; 721 shf->wp += ncopy; 722 shf->wnleft -= ncopy; 723 } 724 if (nbytes > 0) { 725 /* Flush deals with strings and sticky errors */ 726 if (shf_emptybuf(shf, EB_GROW) == EOF) 727 return EOF; 728 if (nbytes > shf->wbsize) { 729 ncopy = nbytes; 730 if (shf->wbsize) 731 ncopy -= nbytes % shf->wbsize; 732 nbytes -= ncopy; 733 while (ncopy > 0) { 734 n = write(shf->fd, buf, ncopy); 735 if (n < 0) { 736 if (errno == EINTR 737 && !(shf->flags & SHF_INTERRUPT)) 738 continue; 739 shf->flags |= SHF_ERROR; 740 shf->errno_ = errno; 741 shf->wnleft = 0; 742 /* Note: fwrite(3S) returns 0 for 743 * errors - this doesn't */ 744 return EOF; 745 } 746 buf += n; 747 ncopy -= n; 748 } 749 } 750 if (nbytes > 0) { 751 memcpy(shf->wp, buf, nbytes); 752 shf->wp += nbytes; 753 shf->wnleft -= nbytes; 754 } 755 } 756 757 return orig_nbytes; 758 } 759 760 int 761 shf_fprintf(struct shf *shf, const char *fmt, ...) 762 { 763 va_list args; 764 int n; 765 766 va_start(args, fmt); 767 n = shf_vfprintf(shf, fmt, args); 768 va_end(args); 769 770 return n; 771 } 772 773 int 774 shf_snprintf(char *buf, int bsize, const char *fmt, ...) 775 { 776 struct shf shf; 777 va_list args; 778 int n; 779 780 if (!buf || bsize <= 0) 781 internal_errorf(1, "shf_snprintf: buf %lx, bsize %d", 782 (long) buf, bsize); 783 784 shf_sopen(buf, bsize, SHF_WR, &shf); 785 va_start(args, fmt); 786 n = shf_vfprintf(&shf, fmt, args); 787 va_end(args); 788 shf_sclose(&shf); /* null terminates */ 789 return n; 790 } 791 792 char * 793 shf_smprintf(const char *fmt, ...) 794 { 795 struct shf shf; 796 va_list args; 797 798 shf_sopen((char *) 0, 0, SHF_WR|SHF_DYNAMIC, &shf); 799 va_start(args, fmt); 800 shf_vfprintf(&shf, fmt, args); 801 va_end(args); 802 return shf_sclose(&shf); /* null terminates */ 803 } 804 805 #undef FP /* if you want floating point stuff */ 806 807 #define BUF_SIZE 128 808 #define FPBUF_SIZE (DMAXEXP+16)/* this must be > 809 * MAX(DMAXEXP, log10(pow(2, DSIGNIF))) 810 * + ceil(log10(DMAXEXP)) + 8 (I think). 811 * Since this is hard to express as a 812 * constant, just use a large buffer. 813 */ 814 815 /* 816 * What kinda of machine we on? Hopefully the C compiler will optimize 817 * this out... 818 * 819 * For shorts, we want sign extend for %d but not for %[oxu] - on 16 bit 820 * machines it don't matter. Assumes C compiler has converted shorts to 821 * ints before pushing them. 822 */ 823 #define POP_INT(f, s, a) (((f) & FL_LONG) ? \ 824 va_arg((a), unsigned long) \ 825 : \ 826 (sizeof(int) < sizeof(long) ? \ 827 ((s) ? \ 828 (long) va_arg((a), int) \ 829 : \ 830 va_arg((a), unsigned)) \ 831 : \ 832 va_arg((a), unsigned))) 833 834 #define ABIGNUM 32000 /* big numer that will fit in a short */ 835 #define LOG2_10 3.321928094887362347870319429 /* log base 2 of 10 */ 836 837 #define FL_HASH 0x001 /* `#' seen */ 838 #define FL_PLUS 0x002 /* `+' seen */ 839 #define FL_RIGHT 0x004 /* `-' seen */ 840 #define FL_BLANK 0x008 /* ` ' seen */ 841 #define FL_SHORT 0x010 /* `h' seen */ 842 #define FL_LONG 0x020 /* `l' seen */ 843 #define FL_ZERO 0x040 /* `0' seen */ 844 #define FL_DOT 0x080 /* '.' seen */ 845 #define FL_UPPER 0x100 /* format character was uppercase */ 846 #define FL_NUMBER 0x200 /* a number was formatted %[douxefg] */ 847 848 849 #ifdef FP 850 #include <math.h> 851 852 static double 853 my_ceil(d) 854 double d; 855 { 856 double i; 857 858 return d - modf(d, &i) + (d < 0 ? -1 : 1); 859 } 860 #endif /* FP */ 861 862 int 863 shf_vfprintf(shf, fmt, args) 864 struct shf *shf; 865 const char *fmt; 866 va_list args; 867 { 868 char c, *s; 869 int UNINITIALIZED(tmp); 870 int field, precision; 871 int len; 872 int flags; 873 unsigned long lnum; 874 /* %#o produces the longest output */ 875 char numbuf[(BITS(long) + 2) / 3 + 1]; 876 /* this stuff for dealing with the buffer */ 877 int nwritten = 0; 878 static char nulls[] = "(null %s)"; 879 #ifdef FP 880 /* should be in <math.h> 881 * extern double frexp(); 882 */ 883 extern char *ecvt(); 884 885 double fpnum; 886 int expo, decpt; 887 char style; 888 char fpbuf[FPBUF_SIZE]; 889 #endif /* FP */ 890 891 if (!fmt) 892 return 0; 893 894 while ((c = *fmt++)) { 895 if (c != '%') { 896 shf_putc(c, shf); 897 nwritten++; 898 continue; 899 } 900 /* 901 * This will accept flags/fields in any order - not 902 * just the order specified in printf(3), but this is 903 * the way _doprnt() seems to work (on bsd and sysV). 904 * The only restriction is that the format character must 905 * come last :-). 906 */ 907 flags = field = precision = 0; 908 for ( ; (c = *fmt++) ; ) { 909 switch (c) { 910 case '#': 911 flags |= FL_HASH; 912 continue; 913 914 case '+': 915 flags |= FL_PLUS; 916 continue; 917 918 case '-': 919 flags |= FL_RIGHT; 920 continue; 921 922 case ' ': 923 flags |= FL_BLANK; 924 continue; 925 926 case '0': 927 if (!(flags & FL_DOT)) 928 flags |= FL_ZERO; 929 continue; 930 931 case '.': 932 flags |= FL_DOT; 933 precision = 0; 934 continue; 935 936 case '*': 937 tmp = va_arg(args, int); 938 if (flags & FL_DOT) 939 precision = tmp; 940 else if ((field = tmp) < 0) { 941 field = -field; 942 flags |= FL_RIGHT; 943 } 944 continue; 945 946 case 'l': 947 flags |= FL_LONG; 948 continue; 949 950 case 'h': 951 flags |= FL_SHORT; 952 continue; 953 } 954 if (digit(c)) { 955 tmp = c - '0'; 956 while (c = *fmt++, digit(c)) 957 tmp = tmp * 10 + c - '0'; 958 --fmt; 959 if (tmp < 0) /* overflow? */ 960 tmp = 0; 961 if (flags & FL_DOT) 962 precision = tmp; 963 else 964 field = tmp; 965 continue; 966 } 967 break; 968 } 969 970 if (precision < 0) 971 precision = 0; 972 973 if (!c) /* nasty format */ 974 break; 975 976 if (c >= 'A' && c <= 'Z') { 977 flags |= FL_UPPER; 978 c = c - 'A' + 'a'; 979 } 980 981 switch (c) { 982 case 'p': /* pointer */ 983 flags &= ~(FL_LONG | FL_SHORT); 984 if (sizeof(char *) > sizeof(int)) 985 flags |= FL_LONG; /* hope it fits.. */ 986 /* aaahhh... */ 987 /*FALLTHROUGH*/ 988 case 'd': 989 case 'i': 990 case 'o': 991 case 'u': 992 case 'x': 993 flags |= FL_NUMBER; 994 s = &numbuf[sizeof(numbuf)]; 995 lnum = POP_INT(flags, c == 'd', args); 996 switch (c) { 997 case 'd': 998 case 'i': 999 if (0 > (long) lnum) 1000 lnum = - (long) lnum, tmp = 1; 1001 else 1002 tmp = 0; 1003 /* aaahhhh..... */ 1004 /*FALLTHROUGH*/ 1005 case 'u': 1006 do { 1007 *--s = lnum % 10 + '0'; 1008 lnum /= 10; 1009 } while (lnum); 1010 1011 if (c != 'u') { 1012 if (tmp) 1013 *--s = '-'; 1014 else if (flags & FL_PLUS) 1015 *--s = '+'; 1016 else if (flags & FL_BLANK) 1017 *--s = ' '; 1018 } 1019 break; 1020 1021 case 'o': 1022 do { 1023 *--s = (lnum & 0x7) + '0'; 1024 lnum >>= 3; 1025 } while (lnum); 1026 1027 if ((flags & FL_HASH) && *s != '0') 1028 *--s = '0'; 1029 break; 1030 1031 case 'p': 1032 case 'x': 1033 { 1034 const char *digits = (flags & FL_UPPER) ? 1035 "0123456789ABCDEF" 1036 : "0123456789abcdef"; 1037 do { 1038 *--s = digits[lnum & 0xf]; 1039 lnum >>= 4; 1040 } while (lnum); 1041 1042 if (flags & FL_HASH) { 1043 *--s = (flags & FL_UPPER) ? 'X' : 'x'; 1044 *--s = '0'; 1045 } 1046 } 1047 } 1048 len = &numbuf[sizeof(numbuf)] - s; 1049 if (flags & FL_DOT) { 1050 if (precision > len) { 1051 field = precision; 1052 flags |= FL_ZERO; 1053 } else 1054 precision = len; /* no loss */ 1055 } 1056 break; 1057 1058 #ifdef FP 1059 case 'e': 1060 case 'g': 1061 case 'f': 1062 { 1063 char *p; 1064 1065 /* 1066 * This could probably be done better, 1067 * but it seems to work. Note that gcvt() 1068 * is not used, as you cannot tell it to 1069 * not strip the zeros. 1070 */ 1071 flags |= FL_NUMBER; 1072 if (!(flags & FL_DOT)) 1073 precision = 6; /* default */ 1074 /* 1075 * Assumes doubles are pushed on 1076 * the stack. If this is not so, then 1077 * FL_LONG/FL_SHORT should be checked. 1078 */ 1079 fpnum = va_arg(args, double); 1080 s = fpbuf; 1081 style = c; 1082 /* 1083 * This is the same as 1084 * expo = ceil(log10(fpnum)) 1085 * but doesn't need -lm. This is an 1086 * approximation as expo is rounded up. 1087 */ 1088 (void) frexp(fpnum, &expo); 1089 expo = my_ceil(expo / LOG2_10); 1090 1091 if (expo < 0) 1092 expo = 0; 1093 1094 p = ecvt(fpnum, precision + 1 + expo, 1095 &decpt, &tmp); 1096 if (c == 'g') { 1097 if (decpt < -4 || decpt > precision) 1098 style = 'e'; 1099 else 1100 style = 'f'; 1101 if (decpt > 0 && (precision -= decpt) < 0) 1102 precision = 0; 1103 } 1104 if (tmp) 1105 *s++ = '-'; 1106 else if (flags & FL_PLUS) 1107 *s++ = '+'; 1108 else if (flags & FL_BLANK) 1109 *s++ = ' '; 1110 1111 if (style == 'e') 1112 *s++ = *p++; 1113 else { 1114 if (decpt > 0) { 1115 /* Overflow check - should 1116 * never have this problem. 1117 */ 1118 if (decpt > 1119 &fpbuf[sizeof(fpbuf)] 1120 - s - 8) 1121 decpt = 1122 &fpbuf[sizeof(fpbuf)] 1123 - s - 8; 1124 (void) memcpy(s, p, decpt); 1125 s += decpt; 1126 p += decpt; 1127 } else 1128 *s++ = '0'; 1129 } 1130 1131 /* print the fraction? */ 1132 if (precision > 0) { 1133 *s++ = '.'; 1134 /* Overflow check - should 1135 * never have this problem. 1136 */ 1137 if (precision > &fpbuf[sizeof(fpbuf)] 1138 - s - 7) 1139 precision = 1140 &fpbuf[sizeof(fpbuf)] 1141 - s - 7; 1142 for (tmp = decpt; tmp++ < 0 && 1143 precision > 0 ; precision--) 1144 *s++ = '0'; 1145 tmp = strlen(p); 1146 if (precision > tmp) 1147 precision = tmp; 1148 /* Overflow check - should 1149 * never have this problem. 1150 */ 1151 if (precision > &fpbuf[sizeof(fpbuf)] 1152 - s - 7) 1153 precision = 1154 &fpbuf[sizeof(fpbuf)] 1155 - s - 7; 1156 (void) memcpy(s, p, precision); 1157 s += precision; 1158 /* 1159 * `g' format strips trailing 1160 * zeros after the decimal. 1161 */ 1162 if (c == 'g' && !(flags & FL_HASH)) { 1163 while (*--s == '0') 1164 ; 1165 if (*s != '.') 1166 s++; 1167 } 1168 } else if (flags & FL_HASH) 1169 *s++ = '.'; 1170 1171 if (style == 'e') { 1172 *s++ = (flags & FL_UPPER) ? 'E' : 'e'; 1173 if (--decpt >= 0) 1174 *s++ = '+'; 1175 else { 1176 *s++ = '-'; 1177 decpt = -decpt; 1178 } 1179 p = &numbuf[sizeof(numbuf)]; 1180 for (tmp = 0; tmp < 2 || decpt ; tmp++) { 1181 *--p = '0' + decpt % 10; 1182 decpt /= 10; 1183 } 1184 tmp = &numbuf[sizeof(numbuf)] - p; 1185 (void) memcpy(s, p, tmp); 1186 s += tmp; 1187 } 1188 1189 len = s - fpbuf; 1190 s = fpbuf; 1191 precision = len; 1192 break; 1193 } 1194 #endif /* FP */ 1195 1196 case 's': 1197 if (!(s = va_arg(args, char *))) 1198 s = nulls; 1199 len = strlen(s); 1200 break; 1201 1202 case 'c': 1203 flags &= ~FL_DOT; 1204 numbuf[0] = va_arg(args, int); 1205 s = numbuf; 1206 len = 1; 1207 break; 1208 1209 case '%': 1210 default: 1211 numbuf[0] = c; 1212 s = numbuf; 1213 len = 1; 1214 break; 1215 } 1216 1217 /* 1218 * At this point s should point to a string that is 1219 * to be formatted, and len should be the length of the 1220 * string. 1221 */ 1222 if (!(flags & FL_DOT) || len < precision) 1223 precision = len; 1224 if (field > precision) { 1225 field -= precision; 1226 if (!(flags & FL_RIGHT)) { 1227 field = -field; 1228 /* skip past sign or 0x when padding with 0 */ 1229 if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { 1230 if (*s == '+' || *s == '-' || *s ==' ') 1231 { 1232 shf_putc(*s, shf); 1233 s++; 1234 precision--; 1235 nwritten++; 1236 } else if (*s == '0') { 1237 shf_putc(*s, shf); 1238 s++; 1239 nwritten++; 1240 if (--precision > 0 && 1241 (*s | 0x20) == 'x') 1242 { 1243 shf_putc(*s, shf); 1244 s++; 1245 precision--; 1246 nwritten++; 1247 } 1248 } 1249 c = '0'; 1250 } else 1251 c = flags & FL_ZERO ? '0' : ' '; 1252 if (field < 0) { 1253 nwritten += -field; 1254 for ( ; field < 0 ; field++) 1255 shf_putc(c, shf); 1256 } 1257 } else 1258 c = ' '; 1259 } else 1260 field = 0; 1261 1262 if (precision > 0) { 1263 nwritten += precision; 1264 for ( ; precision-- > 0 ; s++) 1265 shf_putc(*s, shf); 1266 } 1267 if (field > 0) { 1268 nwritten += field; 1269 for ( ; field > 0 ; --field) 1270 shf_putc(c, shf); 1271 } 1272 } 1273 1274 return shf_error(shf) ? EOF : nwritten; 1275 } 1276