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