1 /* $OpenBSD: shf.c,v 1.31 2016/03/20 00:01:21 krw 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 < 0) { 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 < 0) { 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 < 0) 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(1, "shf_fdopen: missing read/write"); 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 < 0) 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(1, "shf_reopen: missing read/write"); 161 if (!shf || !shf->buf || shf->bsize < bsize) 162 internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); 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(1, "shf_sopen: flags 0x%x", 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) < 0) 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) < 0) 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(1, "shf_flush: no fd"); 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(1, "shf_emptybuf: no fd"); 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 < 0) { 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(1, "shf_fillbuf: no fd"); 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(1, "shf_read: flags %x", shf->flags); 442 443 if (bsize <= 0) 444 internal_errorf(1, "shf_read: bsize %d", 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 memcpy(buf, shf->rp, ncopy); 454 buf += ncopy; 455 bsize -= ncopy; 456 shf->rp += ncopy; 457 shf->rnleft -= ncopy; 458 } 459 /* Note: fread(3S) returns 0 for errors - this doesn't */ 460 return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) : 461 orig_bsize - bsize; 462 } 463 464 /* Read up to a newline or EOF. The newline is put in buf; buf is always 465 * null terminated. Returns NULL on read error or if nothing was read before 466 * end of file, returns a pointer to the null byte in buf otherwise. 467 */ 468 char * 469 shf_getse(char *buf, int bsize, struct shf *shf) 470 { 471 unsigned char *end; 472 int ncopy; 473 char *orig_buf = buf; 474 475 if (!(shf->flags & SHF_RD)) 476 internal_errorf(1, "shf_getse: flags %x", shf->flags); 477 478 if (bsize <= 0) 479 return NULL; 480 481 --bsize; /* save room for null */ 482 do { 483 if (shf->rnleft == 0) { 484 if (shf_fillbuf(shf) == EOF) 485 return NULL; 486 if (shf->rnleft == 0) { 487 *buf = '\0'; 488 return buf == orig_buf ? NULL : buf; 489 } 490 } 491 end = (unsigned char *) memchr((char *) shf->rp, '\n', 492 shf->rnleft); 493 ncopy = end ? end - shf->rp + 1 : shf->rnleft; 494 if (ncopy > bsize) 495 ncopy = bsize; 496 memcpy(buf, (char *) shf->rp, ncopy); 497 shf->rp += ncopy; 498 shf->rnleft -= ncopy; 499 buf += ncopy; 500 bsize -= ncopy; 501 } while (!end && bsize); 502 *buf = '\0'; 503 return buf; 504 } 505 506 /* Returns the char read. Returns EOF for error and end of file. */ 507 int 508 shf_getchar(struct shf *shf) 509 { 510 if (!(shf->flags & SHF_RD)) 511 internal_errorf(1, "shf_getchar: flags %x", shf->flags); 512 513 if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) 514 return EOF; 515 --shf->rnleft; 516 return *shf->rp++; 517 } 518 519 /* Put a character back in the input stream. Returns the character if 520 * successful, EOF if there is no room. 521 */ 522 int 523 shf_ungetc(int c, struct shf *shf) 524 { 525 if (!(shf->flags & SHF_RD)) 526 internal_errorf(1, "shf_ungetc: flags %x", shf->flags); 527 528 if ((shf->flags & SHF_ERROR) || c == EOF || 529 (shf->rp == shf->buf && shf->rnleft)) 530 return EOF; 531 532 if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) 533 return EOF; 534 535 if (shf->rp == shf->buf) 536 shf->rp = shf->buf + shf->rbsize; 537 if (shf->flags & SHF_STRING) { 538 /* Can unget what was read, but not something different - we 539 * don't want to modify a string. 540 */ 541 if (shf->rp[-1] != c) 542 return EOF; 543 shf->flags &= ~SHF_EOF; 544 shf->rp--; 545 shf->rnleft++; 546 return c; 547 } 548 shf->flags &= ~SHF_EOF; 549 *--(shf->rp) = c; 550 shf->rnleft++; 551 return c; 552 } 553 554 /* Write a character. Returns the character if successful, EOF if 555 * the char could not be written. 556 */ 557 int 558 shf_putchar(int c, struct shf *shf) 559 { 560 if (!(shf->flags & SHF_WR)) 561 internal_errorf(1, "shf_putchar: flags %x", shf->flags); 562 563 if (c == EOF) 564 return EOF; 565 566 if (shf->flags & SHF_UNBUF) { 567 char cc = c; 568 int n; 569 570 if (shf->fd < 0) 571 internal_errorf(1, "shf_putchar: no fd"); 572 if (shf->flags & SHF_ERROR) { 573 errno = shf->errno_; 574 return EOF; 575 } 576 while ((n = write(shf->fd, &cc, 1)) != 1) 577 if (n < 0) { 578 if (errno == EINTR && 579 !(shf->flags & SHF_INTERRUPT)) 580 continue; 581 shf->flags |= SHF_ERROR; 582 shf->errno_ = errno; 583 return EOF; 584 } 585 } else { 586 /* Flush deals with strings and sticky errors */ 587 if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) 588 return EOF; 589 shf->wnleft--; 590 *shf->wp++ = c; 591 } 592 593 return c; 594 } 595 596 /* Write a string. Returns the length of the string if successful, EOF if 597 * the string could not be written. 598 */ 599 int 600 shf_puts(const char *s, struct shf *shf) 601 { 602 if (!s) 603 return EOF; 604 605 return shf_write(s, strlen(s), shf); 606 } 607 608 /* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ 609 int 610 shf_write(const char *buf, int nbytes, struct shf *shf) 611 { 612 int orig_nbytes = nbytes; 613 int n; 614 int ncopy; 615 616 if (!(shf->flags & SHF_WR)) 617 internal_errorf(1, "shf_write: flags %x", shf->flags); 618 619 if (nbytes < 0) 620 internal_errorf(1, "shf_write: nbytes %d", nbytes); 621 622 /* Don't buffer if buffer is empty and we're writting a large amount. */ 623 if ((ncopy = shf->wnleft) && 624 (shf->wp != shf->buf || nbytes < shf->wnleft)) { 625 if (ncopy > nbytes) 626 ncopy = nbytes; 627 memcpy(shf->wp, buf, ncopy); 628 nbytes -= ncopy; 629 buf += ncopy; 630 shf->wp += ncopy; 631 shf->wnleft -= ncopy; 632 } 633 if (nbytes > 0) { 634 /* Flush deals with strings and sticky errors */ 635 if (shf_emptybuf(shf, EB_GROW) == EOF) 636 return EOF; 637 if (nbytes > shf->wbsize) { 638 ncopy = nbytes; 639 if (shf->wbsize) 640 ncopy -= nbytes % shf->wbsize; 641 nbytes -= ncopy; 642 while (ncopy > 0) { 643 n = write(shf->fd, buf, ncopy); 644 if (n < 0) { 645 if (errno == EINTR && 646 !(shf->flags & SHF_INTERRUPT)) 647 continue; 648 shf->flags |= SHF_ERROR; 649 shf->errno_ = errno; 650 shf->wnleft = 0; 651 /* Note: fwrite(3S) returns 0 for 652 * errors - this doesn't */ 653 return EOF; 654 } 655 buf += n; 656 ncopy -= n; 657 } 658 } 659 if (nbytes > 0) { 660 memcpy(shf->wp, buf, nbytes); 661 shf->wp += nbytes; 662 shf->wnleft -= nbytes; 663 } 664 } 665 666 return orig_nbytes; 667 } 668 669 int 670 shf_fprintf(struct shf *shf, const char *fmt, ...) 671 { 672 va_list args; 673 int n; 674 675 va_start(args, fmt); 676 n = shf_vfprintf(shf, fmt, args); 677 va_end(args); 678 679 return n; 680 } 681 682 int 683 shf_snprintf(char *buf, int bsize, const char *fmt, ...) 684 { 685 struct shf shf; 686 va_list args; 687 int n; 688 689 if (!buf || bsize <= 0) 690 internal_errorf(1, "shf_snprintf: buf %lx, bsize %d", 691 (long) buf, bsize); 692 693 shf_sopen(buf, bsize, SHF_WR, &shf); 694 va_start(args, fmt); 695 n = shf_vfprintf(&shf, fmt, args); 696 va_end(args); 697 shf_sclose(&shf); /* null terminates */ 698 return n; 699 } 700 701 char * 702 shf_smprintf(const char *fmt, ...) 703 { 704 struct shf shf; 705 va_list args; 706 707 shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf); 708 va_start(args, fmt); 709 shf_vfprintf(&shf, fmt, args); 710 va_end(args); 711 return shf_sclose(&shf); /* null terminates */ 712 } 713 714 #define FL_HASH 0x001 /* `#' seen */ 715 #define FL_PLUS 0x002 /* `+' seen */ 716 #define FL_RIGHT 0x004 /* `-' seen */ 717 #define FL_BLANK 0x008 /* ` ' seen */ 718 #define FL_SHORT 0x010 /* `h' seen */ 719 #define FL_LONG 0x020 /* `l' seen */ 720 #define FL_LLONG 0x040 /* `ll' seen */ 721 #define FL_ZERO 0x080 /* `0' seen */ 722 #define FL_DOT 0x100 /* '.' seen */ 723 #define FL_UPPER 0x200 /* format character was uppercase */ 724 #define FL_NUMBER 0x400 /* a number was formated %[douxefg] */ 725 726 int 727 shf_vfprintf(struct shf *shf, const char *fmt, va_list args) 728 { 729 char c, *s; 730 int tmp = 0; 731 int field, precision; 732 int len; 733 int flags; 734 unsigned long long llnum; 735 /* %#o produces the longest output */ 736 char numbuf[(BITS(long long) + 2) / 3 + 1]; 737 /* this stuff for dealing with the buffer */ 738 int nwritten = 0; 739 740 if (!fmt) 741 return 0; 742 743 while ((c = *fmt++)) { 744 if (c != '%') { 745 shf_putc(c, shf); 746 nwritten++; 747 continue; 748 } 749 /* 750 * This will accept flags/fields in any order - not 751 * just the order specified in printf(3), but this is 752 * the way _doprnt() seems to work (on bsd and sysV). 753 * The only restriction is that the format character must 754 * come last :-). 755 */ 756 flags = field = precision = 0; 757 for ( ; (c = *fmt++) ; ) { 758 switch (c) { 759 case '#': 760 flags |= FL_HASH; 761 continue; 762 763 case '+': 764 flags |= FL_PLUS; 765 continue; 766 767 case '-': 768 flags |= FL_RIGHT; 769 continue; 770 771 case ' ': 772 flags |= FL_BLANK; 773 continue; 774 775 case '0': 776 if (!(flags & FL_DOT)) 777 flags |= FL_ZERO; 778 continue; 779 780 case '.': 781 flags |= FL_DOT; 782 precision = 0; 783 continue; 784 785 case '*': 786 tmp = va_arg(args, int); 787 if (flags & FL_DOT) 788 precision = tmp; 789 else if ((field = tmp) < 0) { 790 field = -field; 791 flags |= FL_RIGHT; 792 } 793 continue; 794 795 case 'l': 796 if (*fmt == 'l') { 797 fmt++; 798 flags |= FL_LLONG; 799 } else 800 flags |= FL_LONG; 801 continue; 802 803 case 'h': 804 flags |= FL_SHORT; 805 continue; 806 } 807 if (digit(c)) { 808 tmp = c - '0'; 809 while (c = *fmt++, digit(c)) 810 tmp = tmp * 10 + c - '0'; 811 --fmt; 812 if (tmp < 0) /* overflow? */ 813 tmp = 0; 814 if (flags & FL_DOT) 815 precision = tmp; 816 else 817 field = tmp; 818 continue; 819 } 820 break; 821 } 822 823 if (precision < 0) 824 precision = 0; 825 826 if (!c) /* nasty format */ 827 break; 828 829 if (c >= 'A' && c <= 'Z') { 830 flags |= FL_UPPER; 831 c = c - 'A' + 'a'; 832 } 833 834 switch (c) { 835 case 'p': /* pointer */ 836 flags &= ~(FL_LLONG | FL_SHORT); 837 flags |= FL_LONG; 838 /* aaahhh... */ 839 case 'd': 840 case 'i': 841 case 'o': 842 case 'u': 843 case 'x': 844 flags |= FL_NUMBER; 845 s = &numbuf[sizeof(numbuf)]; 846 if (flags & FL_LLONG) 847 llnum = va_arg(args, unsigned long long); 848 else if (flags & FL_LONG) { 849 if (c == 'd' || c == 'i') 850 llnum = va_arg(args, long); 851 else 852 llnum = va_arg(args, unsigned long); 853 } else { 854 if (c == 'd' || c == 'i') 855 llnum = va_arg(args, int); 856 else 857 llnum = va_arg(args, unsigned int); 858 } 859 switch (c) { 860 case 'd': 861 case 'i': 862 if (0 > (long long) llnum) 863 llnum = - (long long) llnum, tmp = 1; 864 else 865 tmp = 0; 866 /* aaahhhh..... */ 867 868 case 'u': 869 do { 870 *--s = llnum % 10 + '0'; 871 llnum /= 10; 872 } while (llnum); 873 874 if (c != 'u') { 875 if (tmp) 876 *--s = '-'; 877 else if (flags & FL_PLUS) 878 *--s = '+'; 879 else if (flags & FL_BLANK) 880 *--s = ' '; 881 } 882 break; 883 884 case 'o': 885 do { 886 *--s = (llnum & 0x7) + '0'; 887 llnum >>= 3; 888 } while (llnum); 889 890 if ((flags & FL_HASH) && *s != '0') 891 *--s = '0'; 892 break; 893 894 case 'p': 895 case 'x': 896 { 897 const char *digits = (flags & FL_UPPER) ? 898 "0123456789ABCDEF" : 899 "0123456789abcdef"; 900 do { 901 *--s = digits[llnum & 0xf]; 902 llnum >>= 4; 903 } while (llnum); 904 905 if (flags & FL_HASH) { 906 *--s = (flags & FL_UPPER) ? 'X' : 'x'; 907 *--s = '0'; 908 } 909 } 910 } 911 len = &numbuf[sizeof(numbuf)] - s; 912 if (flags & FL_DOT) { 913 if (precision > len) { 914 field = precision; 915 flags |= FL_ZERO; 916 } else 917 precision = len; /* no loss */ 918 } 919 break; 920 921 case 's': 922 if (!(s = va_arg(args, char *))) 923 s = "(null %s)"; 924 len = strlen(s); 925 break; 926 927 case 'c': 928 flags &= ~FL_DOT; 929 numbuf[0] = va_arg(args, int); 930 s = numbuf; 931 len = 1; 932 break; 933 934 case '%': 935 default: 936 numbuf[0] = c; 937 s = numbuf; 938 len = 1; 939 break; 940 } 941 942 /* 943 * At this point s should point to a string that is 944 * to be formatted, and len should be the length of the 945 * string. 946 */ 947 if (!(flags & FL_DOT) || len < precision) 948 precision = len; 949 if (field > precision) { 950 field -= precision; 951 if (!(flags & FL_RIGHT)) { 952 field = -field; 953 /* skip past sign or 0x when padding with 0 */ 954 if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { 955 if (*s == '+' || *s == '-' || *s ==' ') { 956 shf_putc(*s, shf); 957 s++; 958 precision--; 959 nwritten++; 960 } else if (*s == '0') { 961 shf_putc(*s, shf); 962 s++; 963 nwritten++; 964 if (--precision > 0 && 965 (*s | 0x20) == 'x') { 966 shf_putc(*s, shf); 967 s++; 968 precision--; 969 nwritten++; 970 } 971 } 972 c = '0'; 973 } else 974 c = flags & FL_ZERO ? '0' : ' '; 975 if (field < 0) { 976 nwritten += -field; 977 for ( ; field < 0 ; field++) 978 shf_putc(c, shf); 979 } 980 } else 981 c = ' '; 982 } else 983 field = 0; 984 985 if (precision > 0) { 986 nwritten += precision; 987 for ( ; precision-- > 0 ; s++) 988 shf_putc(*s, shf); 989 } 990 if (field > 0) { 991 nwritten += field; 992 for ( ; field > 0 ; --field) 993 shf_putc(c, shf); 994 } 995 } 996 997 return shf_error(shf) ? EOF : nwritten; 998 } 999