1 /* $OpenBSD: shf.c,v 1.15 2006/04/02 00:48:33 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 5 * Thorsten Glaser <tg (at) mirbsd.org> 6 * 7 * Provided that these terms and disclaimer and all copyright notices 8 * are retained or reproduced in an accompanying document, permission 9 * is granted to deal in this work without restriction, including un- 10 * limited rights to use, publicly perform, distribute, sell, modify, 11 * merge, give away, or sublicence. 12 * 13 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 14 * the utmost extent permitted by applicable law, neither express nor 15 * implied; without malicious intent or gross negligence. In no event 16 * may a licensor, author or contributor be held liable for indirect, 17 * direct, other damage, loss, or other issues arising in any way out 18 * of dealing in the work, even if advised of the possibility of such 19 * damage or existence of a defect, except proven that it results out 20 * of said person's immediate fault when using the work as intended. 21 */ 22 23 #include "sh.h" 24 25 __RCSID("$MirOS: src/bin/mksh/shf.c,v 1.36 2010/07/19 22:41:04 tg Exp $"); 26 27 /* flags to shf_emptybuf() */ 28 #define EB_READSW 0x01 /* about to switch to reading */ 29 #define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ 30 31 /* 32 * Replacement stdio routines. Stdio is too flakey on too many machines 33 * to be useful when you have multiple processes using the same underlying 34 * file descriptors. 35 */ 36 37 static int shf_fillbuf(struct shf *); 38 static int shf_emptybuf(struct shf *, int); 39 40 /* Open a file. First three args are for open(), last arg is flags for 41 * this package. Returns NULL if file could not be opened, or if a dup 42 * fails. 43 */ 44 struct shf * 45 shf_open(const char *name, int oflags, int mode, int sflags) 46 { 47 struct shf *shf; 48 int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 49 int fd; 50 51 /* Done before open so if alloca fails, fd won't be lost. */ 52 shf = alloc(sizeof(struct shf) + bsize, ATEMP); 53 shf->areap = ATEMP; 54 shf->buf = (unsigned char *)&shf[1]; 55 shf->bsize = bsize; 56 shf->flags = SHF_ALLOCS; 57 /* Rest filled in by reopen. */ 58 59 fd = open(name, oflags, mode); 60 if (fd < 0) { 61 afree(shf, shf->areap); 62 return (NULL); 63 } 64 if ((sflags & SHF_MAPHI) && fd < FDBASE) { 65 int nfd; 66 67 nfd = fcntl(fd, F_DUPFD, FDBASE); 68 close(fd); 69 if (nfd < 0) { 70 afree(shf, shf->areap); 71 return (NULL); 72 } 73 fd = nfd; 74 } 75 sflags &= ~SHF_ACCMODE; 76 sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD : 77 ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR); 78 79 return (shf_reopen(fd, sflags, shf)); 80 } 81 82 /* Set up the shf structure for a file descriptor. Doesn't fail. */ 83 struct shf * 84 shf_fdopen(int fd, int sflags, struct shf *shf) 85 { 86 int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 87 88 /* use fcntl() to figure out correct read/write flags */ 89 if (sflags & SHF_GETFL) { 90 int flags = fcntl(fd, F_GETFL, 0); 91 92 if (flags < 0) 93 /* will get an error on first read/write */ 94 sflags |= SHF_RDWR; 95 else { 96 switch (flags & O_ACCMODE) { 97 case O_RDONLY: 98 sflags |= SHF_RD; 99 break; 100 case O_WRONLY: 101 sflags |= SHF_WR; 102 break; 103 case O_RDWR: 104 sflags |= SHF_RDWR; 105 break; 106 } 107 } 108 } 109 110 if (!(sflags & (SHF_RD | SHF_WR))) 111 internal_errorf("shf_fdopen: missing read/write"); 112 113 if (shf) { 114 if (bsize) { 115 shf->buf = alloc(bsize, ATEMP); 116 sflags |= SHF_ALLOCB; 117 } else 118 shf->buf = NULL; 119 } else { 120 shf = alloc(sizeof(struct shf) + bsize, ATEMP); 121 shf->buf = (unsigned char *)&shf[1]; 122 sflags |= SHF_ALLOCS; 123 } 124 shf->areap = ATEMP; 125 shf->fd = fd; 126 shf->rp = shf->wp = shf->buf; 127 shf->rnleft = 0; 128 shf->rbsize = bsize; 129 shf->wnleft = 0; /* force call to shf_emptybuf() */ 130 shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; 131 shf->flags = sflags; 132 shf->errno_ = 0; 133 shf->bsize = bsize; 134 if (sflags & SHF_CLEXEC) 135 fcntl(fd, F_SETFD, FD_CLOEXEC); 136 return (shf); 137 } 138 139 /* Set up an existing shf (and buffer) to use the given fd */ 140 struct shf * 141 shf_reopen(int fd, int sflags, struct shf *shf) 142 { 143 int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; 144 145 /* use fcntl() to figure out correct read/write flags */ 146 if (sflags & SHF_GETFL) { 147 int flags = fcntl(fd, F_GETFL, 0); 148 149 if (flags < 0) 150 /* will get an error on first read/write */ 151 sflags |= SHF_RDWR; 152 else { 153 switch (flags & O_ACCMODE) { 154 case O_RDONLY: 155 sflags |= SHF_RD; 156 break; 157 case O_WRONLY: 158 sflags |= SHF_WR; 159 break; 160 case O_RDWR: 161 sflags |= SHF_RDWR; 162 break; 163 } 164 } 165 } 166 167 if (!(sflags & (SHF_RD | SHF_WR))) 168 internal_errorf("shf_reopen: missing read/write"); 169 if (!shf || !shf->buf || shf->bsize < bsize) 170 internal_errorf("shf_reopen: bad shf/buf/bsize"); 171 172 /* assumes shf->buf and shf->bsize already set up */ 173 shf->fd = fd; 174 shf->rp = shf->wp = shf->buf; 175 shf->rnleft = 0; 176 shf->rbsize = bsize; 177 shf->wnleft = 0; /* force call to shf_emptybuf() */ 178 shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; 179 shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; 180 shf->errno_ = 0; 181 if (sflags & SHF_CLEXEC) 182 fcntl(fd, F_SETFD, FD_CLOEXEC); 183 return (shf); 184 } 185 186 /* Open a string for reading or writing. If reading, bsize is the number 187 * of bytes that can be read. If writing, bsize is the maximum number of 188 * bytes that can be written. If shf is not null, it is filled in and 189 * returned, if it is null, shf is allocated. If writing and buf is null 190 * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is 191 * used for the initial size). Doesn't fail. 192 * When writing, a byte is reserved for a trailing null - see shf_sclose(). 193 */ 194 struct shf * 195 shf_sopen(char *buf, int bsize, int sflags, struct shf *shf) 196 { 197 /* can't have a read+write string */ 198 if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR))) 199 internal_errorf("shf_sopen: flags 0x%x", sflags); 200 201 if (!shf) { 202 shf = alloc(sizeof(struct shf), ATEMP); 203 sflags |= SHF_ALLOCS; 204 } 205 shf->areap = ATEMP; 206 if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { 207 if (bsize <= 0) 208 bsize = 64; 209 sflags |= SHF_ALLOCB; 210 buf = alloc(bsize, shf->areap); 211 } 212 shf->fd = -1; 213 shf->buf = shf->rp = shf->wp = (unsigned char *)buf; 214 shf->rnleft = bsize; 215 shf->rbsize = bsize; 216 shf->wnleft = bsize - 1; /* space for a '\0' */ 217 shf->wbsize = bsize; 218 shf->flags = sflags | SHF_STRING; 219 shf->errno_ = 0; 220 shf->bsize = bsize; 221 222 return (shf); 223 } 224 225 /* Flush and close file descriptor, free the shf structure */ 226 int 227 shf_close(struct shf *shf) 228 { 229 int ret = 0; 230 231 if (shf->fd >= 0) { 232 ret = shf_flush(shf); 233 if (close(shf->fd) < 0) 234 ret = EOF; 235 } 236 if (shf->flags & SHF_ALLOCS) 237 afree(shf, shf->areap); 238 else if (shf->flags & SHF_ALLOCB) 239 afree(shf->buf, shf->areap); 240 241 return (ret); 242 } 243 244 /* Flush and close file descriptor, don't free file structure */ 245 int 246 shf_fdclose(struct shf *shf) 247 { 248 int ret = 0; 249 250 if (shf->fd >= 0) { 251 ret = shf_flush(shf); 252 if (close(shf->fd) < 0) 253 ret = EOF; 254 shf->rnleft = 0; 255 shf->rp = shf->buf; 256 shf->wnleft = 0; 257 shf->fd = -1; 258 } 259 260 return (ret); 261 } 262 263 /* Close a string - if it was opened for writing, it is null terminated; 264 * returns a pointer to the string and frees shf if it was allocated 265 * (does not free string if it was allocated). 266 */ 267 char * 268 shf_sclose(struct shf *shf) 269 { 270 unsigned char *s = shf->buf; 271 272 /* null terminate */ 273 if (shf->flags & SHF_WR) { 274 shf->wnleft++; 275 shf_putc('\0', shf); 276 } 277 if (shf->flags & SHF_ALLOCS) 278 afree(shf, shf->areap); 279 return ((char *)s); 280 } 281 282 /* Un-read what has been read but not examined, or write what has been 283 * buffered. Returns 0 for success, EOF for (write) error. 284 */ 285 int 286 shf_flush(struct shf *shf) 287 { 288 if (shf->flags & SHF_STRING) 289 return ((shf->flags & SHF_WR) ? EOF : 0); 290 291 if (shf->fd < 0) 292 internal_errorf("shf_flush: no fd"); 293 294 if (shf->flags & SHF_ERROR) { 295 errno = shf->errno_; 296 return (EOF); 297 } 298 299 if (shf->flags & SHF_READING) { 300 shf->flags &= ~(SHF_EOF | SHF_READING); 301 if (shf->rnleft > 0) { 302 lseek(shf->fd, (off_t)-shf->rnleft, SEEK_CUR); 303 shf->rnleft = 0; 304 shf->rp = shf->buf; 305 } 306 return (0); 307 } else if (shf->flags & SHF_WRITING) 308 return (shf_emptybuf(shf, 0)); 309 310 return (0); 311 } 312 313 /* Write out any buffered data. If currently reading, flushes the read 314 * buffer. Returns 0 for success, EOF for (write) error. 315 */ 316 static int 317 shf_emptybuf(struct shf *shf, int flags) 318 { 319 int ret = 0; 320 321 if (!(shf->flags & SHF_STRING) && shf->fd < 0) 322 internal_errorf("shf_emptybuf: no fd"); 323 324 if (shf->flags & SHF_ERROR) { 325 errno = shf->errno_; 326 return (EOF); 327 } 328 329 if (shf->flags & SHF_READING) { 330 if (flags & EB_READSW) /* doesn't happen */ 331 return (0); 332 ret = shf_flush(shf); 333 shf->flags &= ~SHF_READING; 334 } 335 if (shf->flags & SHF_STRING) { 336 unsigned char *nbuf; 337 338 /* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB 339 * is set... (changing the shf pointer could cause problems) 340 */ 341 if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) || 342 !(shf->flags & SHF_ALLOCB)) 343 return (EOF); 344 /* allocate more space for buffer */ 345 nbuf = aresize(shf->buf, 2 * shf->wbsize, shf->areap); 346 shf->rp = nbuf + (shf->rp - shf->buf); 347 shf->wp = nbuf + (shf->wp - shf->buf); 348 shf->rbsize += shf->wbsize; 349 shf->wnleft += shf->wbsize; 350 shf->wbsize *= 2; 351 shf->buf = nbuf; 352 } else { 353 if (shf->flags & SHF_WRITING) { 354 int ntowrite = shf->wp - shf->buf; 355 unsigned char *buf = shf->buf; 356 int n; 357 358 while (ntowrite > 0) { 359 n = write(shf->fd, buf, ntowrite); 360 if (n < 0) { 361 if (errno == EINTR && 362 !(shf->flags & SHF_INTERRUPT)) 363 continue; 364 shf->flags |= SHF_ERROR; 365 shf->errno_ = errno; 366 shf->wnleft = 0; 367 if (buf != shf->buf) { 368 /* allow a second flush 369 * to work */ 370 memmove(shf->buf, buf, 371 ntowrite); 372 shf->wp = shf->buf + ntowrite; 373 } 374 return (EOF); 375 } 376 buf += n; 377 ntowrite -= n; 378 } 379 if (flags & EB_READSW) { 380 shf->wp = shf->buf; 381 shf->wnleft = 0; 382 shf->flags &= ~SHF_WRITING; 383 return (0); 384 } 385 } 386 shf->wp = shf->buf; 387 shf->wnleft = shf->wbsize; 388 } 389 shf->flags |= SHF_WRITING; 390 391 return (ret); 392 } 393 394 /* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ 395 static int 396 shf_fillbuf(struct shf *shf) 397 { 398 if (shf->flags & SHF_STRING) 399 return (0); 400 401 if (shf->fd < 0) 402 internal_errorf("shf_fillbuf: no fd"); 403 404 if (shf->flags & (SHF_EOF | SHF_ERROR)) { 405 if (shf->flags & SHF_ERROR) 406 errno = shf->errno_; 407 return (EOF); 408 } 409 410 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 411 return (EOF); 412 413 shf->flags |= SHF_READING; 414 415 shf->rp = shf->buf; 416 while (1) { 417 shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, 418 shf->rbsize); 419 if (shf->rnleft < 0 && errno == EINTR && 420 !(shf->flags & SHF_INTERRUPT)) 421 continue; 422 break; 423 } 424 if (shf->rnleft <= 0) { 425 if (shf->rnleft < 0) { 426 shf->flags |= SHF_ERROR; 427 shf->errno_ = errno; 428 shf->rnleft = 0; 429 shf->rp = shf->buf; 430 return (EOF); 431 } 432 shf->flags |= SHF_EOF; 433 } 434 return (0); 435 } 436 437 /* Read a buffer from shf. Returns the number of bytes read into buf, 438 * if no bytes were read, returns 0 if end of file was seen, EOF if 439 * a read error occurred. 440 */ 441 int 442 shf_read(char *buf, int bsize, struct shf *shf) 443 { 444 int orig_bsize = bsize; 445 int ncopy; 446 447 if (!(shf->flags & SHF_RD)) 448 internal_errorf("shf_read: flags %x", shf->flags); 449 450 if (bsize <= 0) 451 internal_errorf("shf_read: bsize %d", bsize); 452 453 while (bsize > 0) { 454 if (shf->rnleft == 0 && 455 (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 456 break; 457 ncopy = shf->rnleft; 458 if (ncopy > bsize) 459 ncopy = bsize; 460 memcpy(buf, shf->rp, ncopy); 461 buf += ncopy; 462 bsize -= ncopy; 463 shf->rp += ncopy; 464 shf->rnleft -= ncopy; 465 } 466 /* Note: fread(3S) returns 0 for errors - this doesn't */ 467 return (orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) : 468 orig_bsize - bsize); 469 } 470 471 /* Read up to a newline or EOF. The newline is put in buf; buf is always 472 * null terminated. Returns NULL on read error or if nothing was read before 473 * end of file, returns a pointer to the null byte in buf otherwise. 474 */ 475 char * 476 shf_getse(char *buf, int bsize, struct shf *shf) 477 { 478 unsigned char *end; 479 int ncopy; 480 char *orig_buf = buf; 481 482 if (!(shf->flags & SHF_RD)) 483 internal_errorf("shf_getse: flags %x", shf->flags); 484 485 if (bsize <= 0) 486 return (NULL); 487 488 --bsize; /* save room for null */ 489 do { 490 if (shf->rnleft == 0) { 491 if (shf_fillbuf(shf) == EOF) 492 return (NULL); 493 if (shf->rnleft == 0) { 494 *buf = '\0'; 495 return (buf == orig_buf ? NULL : buf); 496 } 497 } 498 end = (unsigned char *)memchr((char *) shf->rp, '\n', 499 shf->rnleft); 500 ncopy = end ? end - shf->rp + 1 : shf->rnleft; 501 if (ncopy > bsize) 502 ncopy = bsize; 503 memcpy(buf, (char *) shf->rp, ncopy); 504 shf->rp += ncopy; 505 shf->rnleft -= ncopy; 506 buf += ncopy; 507 bsize -= ncopy; 508 } while (!end && bsize); 509 *buf = '\0'; 510 return (buf); 511 } 512 513 /* Returns the char read. Returns EOF for error and end of file. */ 514 int 515 shf_getchar(struct shf *shf) 516 { 517 if (!(shf->flags & SHF_RD)) 518 internal_errorf("shf_getchar: flags %x", shf->flags); 519 520 if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 521 return (EOF); 522 --shf->rnleft; 523 return (*shf->rp++); 524 } 525 526 /* Put a character back in the input stream. Returns the character if 527 * successful, EOF if there is no room. 528 */ 529 int 530 shf_ungetc(int c, struct shf *shf) 531 { 532 if (!(shf->flags & SHF_RD)) 533 internal_errorf("shf_ungetc: flags %x", shf->flags); 534 535 if ((shf->flags & SHF_ERROR) || c == EOF || 536 (shf->rp == shf->buf && shf->rnleft)) 537 return (EOF); 538 539 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 540 return (EOF); 541 542 if (shf->rp == shf->buf) 543 shf->rp = shf->buf + shf->rbsize; 544 if (shf->flags & SHF_STRING) { 545 /* Can unget what was read, but not something different - we 546 * don't want to modify a string. 547 */ 548 if (shf->rp[-1] != c) 549 return (EOF); 550 shf->flags &= ~SHF_EOF; 551 shf->rp--; 552 shf->rnleft++; 553 return (c); 554 } 555 shf->flags &= ~SHF_EOF; 556 *--(shf->rp) = c; 557 shf->rnleft++; 558 return (c); 559 } 560 561 /* Write a character. Returns the character if successful, EOF if 562 * the char could not be written. 563 */ 564 int 565 shf_putchar(int c, struct shf *shf) 566 { 567 if (!(shf->flags & SHF_WR)) 568 internal_errorf("shf_putchar: flags %x", shf->flags); 569 570 if (c == EOF) 571 return (EOF); 572 573 if (shf->flags & SHF_UNBUF) { 574 unsigned char cc = (unsigned char)c; 575 int n; 576 577 if (shf->fd < 0) 578 internal_errorf("shf_putchar: no fd"); 579 if (shf->flags & SHF_ERROR) { 580 errno = shf->errno_; 581 return (EOF); 582 } 583 while ((n = write(shf->fd, &cc, 1)) != 1) 584 if (n < 0) { 585 if (errno == EINTR && 586 !(shf->flags & SHF_INTERRUPT)) 587 continue; 588 shf->flags |= SHF_ERROR; 589 shf->errno_ = errno; 590 return (EOF); 591 } 592 } else { 593 /* Flush deals with strings and sticky errors */ 594 if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) 595 return (EOF); 596 shf->wnleft--; 597 *shf->wp++ = c; 598 } 599 600 return (c); 601 } 602 603 /* Write a string. Returns the length of the string if successful, EOF if 604 * the string could not be written. 605 */ 606 int 607 shf_puts(const char *s, struct shf *shf) 608 { 609 if (!s) 610 return (EOF); 611 612 return (shf_write(s, strlen(s), shf)); 613 } 614 615 /* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ 616 int 617 shf_write(const char *buf, int nbytes, struct shf *shf) 618 { 619 int n, ncopy, orig_nbytes = nbytes; 620 621 if (!(shf->flags & SHF_WR)) 622 internal_errorf("shf_write: flags %x", shf->flags); 623 624 if (nbytes < 0) 625 internal_errorf("shf_write: nbytes %d", nbytes); 626 627 /* Don't buffer if buffer is empty and we're writting a large amount. */ 628 if ((ncopy = shf->wnleft) && 629 (shf->wp != shf->buf || nbytes < shf->wnleft)) { 630 if (ncopy > nbytes) 631 ncopy = nbytes; 632 memcpy(shf->wp, buf, ncopy); 633 nbytes -= ncopy; 634 buf += ncopy; 635 shf->wp += ncopy; 636 shf->wnleft -= ncopy; 637 } 638 if (nbytes > 0) { 639 if (shf->flags & SHF_STRING) { 640 /* resize buffer until there's enough space left */ 641 while (nbytes > shf->wnleft) 642 if (shf_emptybuf(shf, EB_GROW) == EOF) 643 return (EOF); 644 /* then write everything into the buffer */ 645 } else { 646 /* flush deals with sticky errors */ 647 if (shf_emptybuf(shf, EB_GROW) == EOF) 648 return (EOF); 649 /* write chunks larger than window size directly */ 650 if (nbytes > shf->wbsize) { 651 ncopy = nbytes; 652 if (shf->wbsize) 653 ncopy -= nbytes % shf->wbsize; 654 nbytes -= ncopy; 655 while (ncopy > 0) { 656 n = write(shf->fd, buf, ncopy); 657 if (n < 0) { 658 if (errno == EINTR && 659 !(shf->flags & SHF_INTERRUPT)) 660 continue; 661 shf->flags |= SHF_ERROR; 662 shf->errno_ = errno; 663 shf->wnleft = 0; 664 /* 665 * Note: fwrite(3) returns 0 666 * for errors - this doesn't 667 */ 668 return (EOF); 669 } 670 buf += n; 671 ncopy -= n; 672 } 673 } 674 /* ... and buffer the rest */ 675 } 676 if (nbytes > 0) { 677 /* write remaining bytes to buffer */ 678 memcpy(shf->wp, buf, nbytes); 679 shf->wp += nbytes; 680 shf->wnleft -= nbytes; 681 } 682 } 683 684 return (orig_nbytes); 685 } 686 687 int 688 shf_fprintf(struct shf *shf, const char *fmt, ...) 689 { 690 va_list args; 691 int n; 692 693 va_start(args, fmt); 694 n = shf_vfprintf(shf, fmt, args); 695 va_end(args); 696 697 return (n); 698 } 699 700 int 701 shf_snprintf(char *buf, int bsize, const char *fmt, ...) 702 { 703 struct shf shf; 704 va_list args; 705 int n; 706 707 if (!buf || bsize <= 0) 708 internal_errorf("shf_snprintf: buf %p, bsize %d", buf, bsize); 709 710 shf_sopen(buf, bsize, SHF_WR, &shf); 711 va_start(args, fmt); 712 n = shf_vfprintf(&shf, fmt, args); 713 va_end(args); 714 shf_sclose(&shf); /* null terminates */ 715 return (n); 716 } 717 718 char * 719 shf_smprintf(const char *fmt, ...) 720 { 721 struct shf shf; 722 va_list args; 723 724 shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf); 725 va_start(args, fmt); 726 shf_vfprintf(&shf, fmt, args); 727 va_end(args); 728 return (shf_sclose(&shf)); /* null terminates */ 729 } 730 731 #undef FP /* if you want floating point stuff */ 732 733 #ifndef DMAXEXP 734 # define DMAXEXP 128 /* should be big enough */ 735 #endif 736 737 #define BUF_SIZE 128 738 /* must be > MAX(DMAXEXP, log10(pow(2, DSIGNIF))) + ceil(log10(DMAXEXP)) + 8 739 * (I think); since it's hard to express as a constant, just use a large buffer 740 */ 741 #define FPBUF_SIZE (DMAXEXP+16) 742 743 #define FL_HASH 0x001 /* '#' seen */ 744 #define FL_PLUS 0x002 /* '+' seen */ 745 #define FL_RIGHT 0x004 /* '-' seen */ 746 #define FL_BLANK 0x008 /* ' ' seen */ 747 #define FL_SHORT 0x010 /* 'h' seen */ 748 #define FL_LONG 0x020 /* 'l' seen */ 749 #define FL_ZERO 0x040 /* '0' seen */ 750 #define FL_DOT 0x080 /* '.' seen */ 751 #define FL_UPPER 0x100 /* format character was uppercase */ 752 #define FL_NUMBER 0x200 /* a number was formated %[douxefg] */ 753 754 755 int 756 shf_vfprintf(struct shf *shf, const char *fmt, va_list args) 757 { 758 const char *s; 759 char c, *cp; 760 int tmp = 0, field, precision, len, flags; 761 unsigned long lnum; 762 /* %#o produces the longest output */ 763 char numbuf[(8 * sizeof(long) + 2) / 3 + 1]; 764 /* this stuff for dealing with the buffer */ 765 int nwritten = 0; 766 767 if (!fmt) 768 return (0); 769 770 while ((c = *fmt++)) { 771 if (c != '%') { 772 shf_putc(c, shf); 773 nwritten++; 774 continue; 775 } 776 /* 777 * This will accept flags/fields in any order - not 778 * just the order specified in printf(3), but this is 779 * the way _doprnt() seems to work (on bsd and sysV). 780 * The only restriction is that the format character must 781 * come last :-). 782 */ 783 flags = field = precision = 0; 784 for ( ; (c = *fmt++) ; ) { 785 switch (c) { 786 case '#': 787 flags |= FL_HASH; 788 continue; 789 790 case '+': 791 flags |= FL_PLUS; 792 continue; 793 794 case '-': 795 flags |= FL_RIGHT; 796 continue; 797 798 case ' ': 799 flags |= FL_BLANK; 800 continue; 801 802 case '0': 803 if (!(flags & FL_DOT)) 804 flags |= FL_ZERO; 805 continue; 806 807 case '.': 808 flags |= FL_DOT; 809 precision = 0; 810 continue; 811 812 case '*': 813 tmp = va_arg(args, int); 814 if (flags & FL_DOT) 815 precision = tmp; 816 else if ((field = tmp) < 0) { 817 field = -field; 818 flags |= FL_RIGHT; 819 } 820 continue; 821 822 case 'l': 823 flags |= FL_LONG; 824 continue; 825 826 case 'h': 827 flags |= FL_SHORT; 828 continue; 829 } 830 if (ksh_isdigit(c)) { 831 tmp = c - '0'; 832 while (c = *fmt++, ksh_isdigit(c)) 833 tmp = tmp * 10 + c - '0'; 834 --fmt; 835 if (tmp < 0) /* overflow? */ 836 tmp = 0; 837 if (flags & FL_DOT) 838 precision = tmp; 839 else 840 field = tmp; 841 continue; 842 } 843 break; 844 } 845 846 if (precision < 0) 847 precision = 0; 848 849 if (!c) /* nasty format */ 850 break; 851 852 if (c >= 'A' && c <= 'Z') { 853 flags |= FL_UPPER; 854 c = ksh_tolower(c); 855 } 856 857 switch (c) { 858 case 'p': /* pointer */ 859 flags &= ~(FL_LONG | FL_SHORT); 860 flags |= (sizeof(char *) > sizeof(int)) ? 861 /* hope it fits.. */ FL_LONG : 0; 862 /* aaahhh... */ 863 case 'd': 864 case 'i': 865 case 'o': 866 case 'u': 867 case 'x': 868 flags |= FL_NUMBER; 869 cp = numbuf + sizeof(numbuf); 870 /*- 871 * XXX any better way to do this? 872 * XXX hopefully the compiler optimises this out 873 * 874 * For shorts, we want sign extend for %d but not 875 * for %[oxu] - on 16 bit machines it doesn't matter. 876 * Assumes C compiler has converted shorts to ints 877 * before pushing them. XXX optimise this -tg 878 */ 879 if (flags & FL_LONG) 880 lnum = va_arg(args, unsigned long); 881 else if ((sizeof(int) < sizeof(long)) && (c == 'd')) 882 lnum = (long)va_arg(args, int); 883 else 884 lnum = va_arg(args, unsigned int); 885 switch (c) { 886 case 'd': 887 case 'i': 888 if (0 > (long)lnum) { 889 lnum = -(long)lnum; 890 tmp = 1; 891 } else 892 tmp = 0; 893 /* FALLTHROUGH */ 894 case 'u': 895 do { 896 *--cp = lnum % 10 + '0'; 897 lnum /= 10; 898 } while (lnum); 899 900 if (c != 'u') { 901 if (tmp) 902 *--cp = '-'; 903 else if (flags & FL_PLUS) 904 *--cp = '+'; 905 else if (flags & FL_BLANK) 906 *--cp = ' '; 907 } 908 break; 909 910 case 'o': 911 do { 912 *--cp = (lnum & 0x7) + '0'; 913 lnum >>= 3; 914 } while (lnum); 915 916 if ((flags & FL_HASH) && *cp != '0') 917 *--cp = '0'; 918 break; 919 920 case 'p': 921 case 'x': { 922 const char *digits = (flags & FL_UPPER) ? 923 digits_uc : digits_lc; 924 do { 925 *--cp = digits[lnum & 0xf]; 926 lnum >>= 4; 927 } while (lnum); 928 929 if (flags & FL_HASH) { 930 *--cp = (flags & FL_UPPER) ? 'X' : 'x'; 931 *--cp = '0'; 932 } 933 } 934 } 935 len = numbuf + sizeof(numbuf) - (s = cp); 936 if (flags & FL_DOT) { 937 if (precision > len) { 938 field = precision; 939 flags |= FL_ZERO; 940 } else 941 precision = len; /* no loss */ 942 } 943 break; 944 945 case 's': 946 if (!(s = va_arg(args, const char *))) 947 s = "(null)"; 948 len = utf_mbswidth(s); 949 break; 950 951 case 'c': 952 flags &= ~FL_DOT; 953 numbuf[0] = (char)(va_arg(args, int)); 954 s = numbuf; 955 len = 1; 956 break; 957 958 case '%': 959 default: 960 numbuf[0] = c; 961 s = numbuf; 962 len = 1; 963 break; 964 } 965 966 /* 967 * At this point s should point to a string that is to be 968 * formatted, and len should be the length of the string. 969 */ 970 if (!(flags & FL_DOT) || len < precision) 971 precision = len; 972 if (field > precision) { 973 field -= precision; 974 if (!(flags & FL_RIGHT)) { 975 field = -field; 976 /* skip past sign or 0x when padding with 0 */ 977 if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { 978 if (*s == '+' || *s == '-' || 979 *s == ' ') { 980 shf_putc(*s, shf); 981 s++; 982 precision--; 983 nwritten++; 984 } else if (*s == '0') { 985 shf_putc(*s, shf); 986 s++; 987 nwritten++; 988 if (--precision > 0 && 989 (*s | 0x20) == 'x') { 990 shf_putc(*s, shf); 991 s++; 992 precision--; 993 nwritten++; 994 } 995 } 996 c = '0'; 997 } else 998 c = flags & FL_ZERO ? '0' : ' '; 999 if (field < 0) { 1000 nwritten += -field; 1001 for ( ; field < 0 ; field++) 1002 shf_putc(c, shf); 1003 } 1004 } else 1005 c = ' '; 1006 } else 1007 field = 0; 1008 1009 if (precision > 0) { 1010 const char *q; 1011 1012 nwritten += precision; 1013 q = utf_skipcols(s, precision); 1014 do { 1015 shf_putc(*s, shf); 1016 } while (++s < q); 1017 } 1018 if (field > 0) { 1019 nwritten += field; 1020 for ( ; field > 0 ; --field) 1021 shf_putc(c, shf); 1022 } 1023 } 1024 1025 return (shf_error(shf) ? EOF : nwritten); 1026 } 1027 1028 #ifdef MKSH_SMALL 1029 int 1030 shf_getc(struct shf *shf) 1031 { 1032 return ((shf)->rnleft > 0 ? (shf)->rnleft--, *(shf)->rp++ : 1033 shf_getchar(shf)); 1034 } 1035 1036 int 1037 shf_putc(int c, struct shf *shf) 1038 { 1039 return ((shf)->wnleft == 0 ? shf_putchar((c), (shf)) : 1040 ((shf)->wnleft--, *(shf)->wp++ = (c))); 1041 } 1042 #endif 1043