aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-03-06 11:21:50 -0500
committerIngo Molnar <mingo@elte.hu>2009-03-06 11:44:27 -0500
commitfef20d9c1380f04ba9492d6463148db07b413708 (patch)
tree37ada8bb39b6d1094bc2a58db65b349971836a73 /lib
parent4370aa4aa75391a5e2e06bccb0919109f725ed8e (diff)
vsprintf: unify the format decoding layer for its 3 users
An new optimization is making its way to ftrace. Its purpose is to make trace_printk() consuming less memory and be faster. Written by Lai Jiangshan, the approach is to delay the formatting job from tracing time to output time. Currently, a call to trace_printk() will format the whole string and insert it into the ring buffer. Then you can read it on /debug/tracing/trace file. The new implementation stores the address of the format string and the binary parameters into the ring buffer, making the packet more compact and faster to insert. Later, when the user exports the traces, the format string is retrieved with the binary parameters and the formatting job is eventually done. The new implementation rewrites a lot of format decoding bits from vsnprintf() function, making now 3 differents functions to maintain in their duplicated parts of printf format decoding bits. Suggested by Ingo Molnar, this patch tries to factorize the most possible common bits from these functions. The real common part between them is the format decoding. Although they do somewhat similar jobs, their way to export or import the parameters is very different. Thus, only the decoding layer is extracted, unless you see other parts that could be worth factorized. Changes in V2: - Address a suggestion from Linus to group the format_decode() parameters inside a structure. Changes in v3: - Address other cleanups suggested by Ingo and Linus such as passing the printf_spec struct to the format helpers: pointer()/number()/string() Note that this struct is passed by copy and not by address. This is to avoid side effects because these functions often change these values and the changes shoudn't be persistant when a callee helper returns. It would be too risky. - Various cleanups (code alignement, switch/case instead of if/else fountains). - Fix a bug that printed the first format specifier following a %p Changes in v4: - drop unapropriate const qualifier loss while casting fmt to a char * (thanks to Vegard Nossum for having pointed this out). Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Acked-by: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1236356510-8381-6-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'lib')
-rw-r--r--lib/vsprintf.c972
1 files changed, 541 insertions, 431 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 3543bbe8b1bc..25f01578c856 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -396,7 +396,38 @@ static noinline char* put_dec(char *buf, unsigned long long num)
396#define SMALL 32 /* Must be 32 == 0x20 */ 396#define SMALL 32 /* Must be 32 == 0x20 */
397#define SPECIAL 64 /* 0x */ 397#define SPECIAL 64 /* 0x */
398 398
399static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) 399enum format_type {
400 FORMAT_TYPE_NONE, /* Just a string part */
401 FORMAT_TYPE_WITDH,
402 FORMAT_TYPE_PRECISION,
403 FORMAT_TYPE_CHAR,
404 FORMAT_TYPE_STR,
405 FORMAT_TYPE_PTR,
406 FORMAT_TYPE_PERCENT_CHAR,
407 FORMAT_TYPE_INVALID,
408 FORMAT_TYPE_LONG_LONG,
409 FORMAT_TYPE_ULONG,
410 FORMAT_TYPE_LONG,
411 FORMAT_TYPE_USHORT,
412 FORMAT_TYPE_SHORT,
413 FORMAT_TYPE_UINT,
414 FORMAT_TYPE_INT,
415 FORMAT_TYPE_NRCHARS,
416 FORMAT_TYPE_SIZE_T,
417 FORMAT_TYPE_PTRDIFF
418};
419
420struct printf_spec {
421 enum format_type type;
422 int flags; /* flags to number() */
423 int field_width; /* width of output field */
424 int base;
425 int precision; /* # of digits/chars */
426 int qualifier;
427};
428
429static char *number(char *buf, char *end, unsigned long long num,
430 struct printf_spec spec)
400{ 431{
401 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 432 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
402 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 433 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
@@ -404,32 +435,32 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
404 char tmp[66]; 435 char tmp[66];
405 char sign; 436 char sign;
406 char locase; 437 char locase;
407 int need_pfx = ((type & SPECIAL) && base != 10); 438 int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
408 int i; 439 int i;
409 440
410 /* locase = 0 or 0x20. ORing digits or letters with 'locase' 441 /* locase = 0 or 0x20. ORing digits or letters with 'locase'
411 * produces same digits or (maybe lowercased) letters */ 442 * produces same digits or (maybe lowercased) letters */
412 locase = (type & SMALL); 443 locase = (spec.flags & SMALL);
413 if (type & LEFT) 444 if (spec.flags & LEFT)
414 type &= ~ZEROPAD; 445 spec.flags &= ~ZEROPAD;
415 sign = 0; 446 sign = 0;
416 if (type & SIGN) { 447 if (spec.flags & SIGN) {
417 if ((signed long long) num < 0) { 448 if ((signed long long) num < 0) {
418 sign = '-'; 449 sign = '-';
419 num = - (signed long long) num; 450 num = - (signed long long) num;
420 size--; 451 spec.field_width--;
421 } else if (type & PLUS) { 452 } else if (spec.flags & PLUS) {
422 sign = '+'; 453 sign = '+';
423 size--; 454 spec.field_width--;
424 } else if (type & SPACE) { 455 } else if (spec.flags & SPACE) {
425 sign = ' '; 456 sign = ' ';
426 size--; 457 spec.field_width--;
427 } 458 }
428 } 459 }
429 if (need_pfx) { 460 if (need_pfx) {
430 size--; 461 spec.field_width--;
431 if (base == 16) 462 if (spec.base == 16)
432 size--; 463 spec.field_width--;
433 } 464 }
434 465
435 /* generate full string in tmp[], in reverse order */ 466 /* generate full string in tmp[], in reverse order */
@@ -441,10 +472,10 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
441 tmp[i++] = (digits[do_div(num,base)] | locase); 472 tmp[i++] = (digits[do_div(num,base)] | locase);
442 } while (num != 0); 473 } while (num != 0);
443 */ 474 */
444 else if (base != 10) { /* 8 or 16 */ 475 else if (spec.base != 10) { /* 8 or 16 */
445 int mask = base - 1; 476 int mask = spec.base - 1;
446 int shift = 3; 477 int shift = 3;
447 if (base == 16) shift = 4; 478 if (spec.base == 16) shift = 4;
448 do { 479 do {
449 tmp[i++] = (digits[((unsigned char)num) & mask] | locase); 480 tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
450 num >>= shift; 481 num >>= shift;
@@ -454,12 +485,12 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
454 } 485 }
455 486
456 /* printing 100 using %2d gives "100", not "00" */ 487 /* printing 100 using %2d gives "100", not "00" */
457 if (i > precision) 488 if (i > spec.precision)
458 precision = i; 489 spec.precision = i;
459 /* leading space padding */ 490 /* leading space padding */
460 size -= precision; 491 spec.field_width -= spec.precision;
461 if (!(type & (ZEROPAD+LEFT))) { 492 if (!(spec.flags & (ZEROPAD+LEFT))) {
462 while(--size >= 0) { 493 while(--spec.field_width >= 0) {
463 if (buf < end) 494 if (buf < end)
464 *buf = ' '; 495 *buf = ' ';
465 ++buf; 496 ++buf;
@@ -476,23 +507,23 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
476 if (buf < end) 507 if (buf < end)
477 *buf = '0'; 508 *buf = '0';
478 ++buf; 509 ++buf;
479 if (base == 16) { 510 if (spec.base == 16) {
480 if (buf < end) 511 if (buf < end)
481 *buf = ('X' | locase); 512 *buf = ('X' | locase);
482 ++buf; 513 ++buf;
483 } 514 }
484 } 515 }
485 /* zero or space padding */ 516 /* zero or space padding */
486 if (!(type & LEFT)) { 517 if (!(spec.flags & LEFT)) {
487 char c = (type & ZEROPAD) ? '0' : ' '; 518 char c = (spec.flags & ZEROPAD) ? '0' : ' ';
488 while (--size >= 0) { 519 while (--spec.field_width >= 0) {
489 if (buf < end) 520 if (buf < end)
490 *buf = c; 521 *buf = c;
491 ++buf; 522 ++buf;
492 } 523 }
493 } 524 }
494 /* hmm even more zero padding? */ 525 /* hmm even more zero padding? */
495 while (i <= --precision) { 526 while (i <= --spec.precision) {
496 if (buf < end) 527 if (buf < end)
497 *buf = '0'; 528 *buf = '0';
498 ++buf; 529 ++buf;
@@ -504,7 +535,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
504 ++buf; 535 ++buf;
505 } 536 }
506 /* trailing space padding */ 537 /* trailing space padding */
507 while (--size >= 0) { 538 while (--spec.field_width >= 0) {
508 if (buf < end) 539 if (buf < end)
509 *buf = ' '; 540 *buf = ' ';
510 ++buf; 541 ++buf;
@@ -512,17 +543,17 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
512 return buf; 543 return buf;
513} 544}
514 545
515static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags) 546static char *string(char *buf, char *end, char *s, struct printf_spec spec)
516{ 547{
517 int len, i; 548 int len, i;
518 549
519 if ((unsigned long)s < PAGE_SIZE) 550 if ((unsigned long)s < PAGE_SIZE)
520 s = "<NULL>"; 551 s = "<NULL>";
521 552
522 len = strnlen(s, precision); 553 len = strnlen(s, spec.precision);
523 554
524 if (!(flags & LEFT)) { 555 if (!(spec.flags & LEFT)) {
525 while (len < field_width--) { 556 while (len < spec.field_width--) {
526 if (buf < end) 557 if (buf < end)
527 *buf = ' '; 558 *buf = ' ';
528 ++buf; 559 ++buf;
@@ -533,7 +564,7 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
533 *buf = *s; 564 *buf = *s;
534 ++buf; ++s; 565 ++buf; ++s;
535 } 566 }
536 while (len < field_width--) { 567 while (len < spec.field_width--) {
537 if (buf < end) 568 if (buf < end)
538 *buf = ' '; 569 *buf = ' ';
539 ++buf; 570 ++buf;
@@ -541,21 +572,24 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
541 return buf; 572 return buf;
542} 573}
543 574
544static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags) 575static char *symbol_string(char *buf, char *end, void *ptr,
576 struct printf_spec spec)
545{ 577{
546 unsigned long value = (unsigned long) ptr; 578 unsigned long value = (unsigned long) ptr;
547#ifdef CONFIG_KALLSYMS 579#ifdef CONFIG_KALLSYMS
548 char sym[KSYM_SYMBOL_LEN]; 580 char sym[KSYM_SYMBOL_LEN];
549 sprint_symbol(sym, value); 581 sprint_symbol(sym, value);
550 return string(buf, end, sym, field_width, precision, flags); 582 return string(buf, end, sym, spec);
551#else 583#else
552 field_width = 2*sizeof(void *); 584 spec.field_width = 2*sizeof(void *);
553 flags |= SPECIAL | SMALL | ZEROPAD; 585 spec.flags |= SPECIAL | SMALL | ZEROPAD;
554 return number(buf, end, value, 16, field_width, precision, flags); 586 spec.base = 16;
587 return number(buf, end, value, spec);
555#endif 588#endif
556} 589}
557 590
558static char *resource_string(char *buf, char *end, struct resource *res, int field_width, int precision, int flags) 591static char *resource_string(char *buf, char *end, struct resource *res,
592 struct printf_spec spec)
559{ 593{
560#ifndef IO_RSRC_PRINTK_SIZE 594#ifndef IO_RSRC_PRINTK_SIZE
561#define IO_RSRC_PRINTK_SIZE 4 595#define IO_RSRC_PRINTK_SIZE 4
@@ -564,7 +598,11 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie
564#ifndef MEM_RSRC_PRINTK_SIZE 598#ifndef MEM_RSRC_PRINTK_SIZE
565#define MEM_RSRC_PRINTK_SIZE 8 599#define MEM_RSRC_PRINTK_SIZE 8
566#endif 600#endif
567 601 struct printf_spec num_spec = {
602 .base = 16,
603 .precision = -1,
604 .flags = SPECIAL | SMALL | ZEROPAD,
605 };
568 /* room for the actual numbers, the two "0x", -, [, ] and the final zero */ 606 /* room for the actual numbers, the two "0x", -, [, ] and the final zero */
569 char sym[4*sizeof(resource_size_t) + 8]; 607 char sym[4*sizeof(resource_size_t) + 8];
570 char *p = sym, *pend = sym + sizeof(sym); 608 char *p = sym, *pend = sym + sizeof(sym);
@@ -576,17 +614,18 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie
576 size = MEM_RSRC_PRINTK_SIZE; 614 size = MEM_RSRC_PRINTK_SIZE;
577 615
578 *p++ = '['; 616 *p++ = '[';
579 p = number(p, pend, res->start, 16, size, -1, SPECIAL | SMALL | ZEROPAD); 617 num_spec.field_width = size;
618 p = number(p, pend, res->start, num_spec);
580 *p++ = '-'; 619 *p++ = '-';
581 p = number(p, pend, res->end, 16, size, -1, SPECIAL | SMALL | ZEROPAD); 620 p = number(p, pend, res->end, num_spec);
582 *p++ = ']'; 621 *p++ = ']';
583 *p = 0; 622 *p = 0;
584 623
585 return string(buf, end, sym, field_width, precision, flags); 624 return string(buf, end, sym, spec);
586} 625}
587 626
588static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, 627static char *mac_address_string(char *buf, char *end, u8 *addr,
589 int precision, int flags) 628 struct printf_spec spec)
590{ 629{
591 char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ 630 char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
592 char *p = mac_addr; 631 char *p = mac_addr;
@@ -594,16 +633,17 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
594 633
595 for (i = 0; i < 6; i++) { 634 for (i = 0; i < 6; i++) {
596 p = pack_hex_byte(p, addr[i]); 635 p = pack_hex_byte(p, addr[i]);
597 if (!(flags & SPECIAL) && i != 5) 636 if (!(spec.flags & SPECIAL) && i != 5)
598 *p++ = ':'; 637 *p++ = ':';
599 } 638 }
600 *p = '\0'; 639 *p = '\0';
640 spec.flags &= ~SPECIAL;
601 641
602 return string(buf, end, mac_addr, field_width, precision, flags & ~SPECIAL); 642 return string(buf, end, mac_addr, spec);
603} 643}
604 644
605static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, 645static char *ip6_addr_string(char *buf, char *end, u8 *addr,
606 int precision, int flags) 646 struct printf_spec spec)
607{ 647{
608 char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ 648 char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
609 char *p = ip6_addr; 649 char *p = ip6_addr;
@@ -612,16 +652,17 @@ static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
612 for (i = 0; i < 8; i++) { 652 for (i = 0; i < 8; i++) {
613 p = pack_hex_byte(p, addr[2 * i]); 653 p = pack_hex_byte(p, addr[2 * i]);
614 p = pack_hex_byte(p, addr[2 * i + 1]); 654 p = pack_hex_byte(p, addr[2 * i + 1]);
615 if (!(flags & SPECIAL) && i != 7) 655 if (!(spec.flags & SPECIAL) && i != 7)
616 *p++ = ':'; 656 *p++ = ':';
617 } 657 }
618 *p = '\0'; 658 *p = '\0';
659 spec.flags &= ~SPECIAL;
619 660
620 return string(buf, end, ip6_addr, field_width, precision, flags & ~SPECIAL); 661 return string(buf, end, ip6_addr, spec);
621} 662}
622 663
623static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, 664static char *ip4_addr_string(char *buf, char *end, u8 *addr,
624 int precision, int flags) 665 struct printf_spec spec)
625{ 666{
626 char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ 667 char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
627 char temp[3]; /* hold each IP quad in reverse order */ 668 char temp[3]; /* hold each IP quad in reverse order */
@@ -637,8 +678,9 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
637 *p++ = '.'; 678 *p++ = '.';
638 } 679 }
639 *p = '\0'; 680 *p = '\0';
681 spec.flags &= ~SPECIAL;
640 682
641 return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); 683 return string(buf, end, ip4_addr, spec);
642} 684}
643 685
644/* 686/*
@@ -663,41 +705,234 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
663 * function pointers are really function descriptors, which contain a 705 * function pointers are really function descriptors, which contain a
664 * pointer to the real address. 706 * pointer to the real address.
665 */ 707 */
666static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags) 708static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
709 struct printf_spec spec)
667{ 710{
668 if (!ptr) 711 if (!ptr)
669 return string(buf, end, "(null)", field_width, precision, flags); 712 return string(buf, end, "(null)", spec);
670 713
671 switch (*fmt) { 714 switch (*fmt) {
672 case 'F': 715 case 'F':
673 ptr = dereference_function_descriptor(ptr); 716 ptr = dereference_function_descriptor(ptr);
674 /* Fallthrough */ 717 /* Fallthrough */
675 case 'S': 718 case 'S':
676 return symbol_string(buf, end, ptr, field_width, precision, flags); 719 return symbol_string(buf, end, ptr, spec);
677 case 'R': 720 case 'R':
678 return resource_string(buf, end, ptr, field_width, precision, flags); 721 return resource_string(buf, end, ptr, spec);
679 case 'm': 722 case 'm':
680 flags |= SPECIAL; 723 spec.flags |= SPECIAL;
681 /* Fallthrough */ 724 /* Fallthrough */
682 case 'M': 725 case 'M':
683 return mac_address_string(buf, end, ptr, field_width, precision, flags); 726 return mac_address_string(buf, end, ptr, spec);
684 case 'i': 727 case 'i':
685 flags |= SPECIAL; 728 spec.flags |= SPECIAL;
686 /* Fallthrough */ 729 /* Fallthrough */
687 case 'I': 730 case 'I':
688 if (fmt[1] == '6') 731 if (fmt[1] == '6')
689 return ip6_addr_string(buf, end, ptr, field_width, precision, flags); 732 return ip6_addr_string(buf, end, ptr, spec);
690 if (fmt[1] == '4') 733 if (fmt[1] == '4')
691 return ip4_addr_string(buf, end, ptr, field_width, precision, flags); 734 return ip4_addr_string(buf, end, ptr, spec);
692 flags &= ~SPECIAL; 735 spec.flags &= ~SPECIAL;
736 break;
737 }
738 spec.flags |= SMALL;
739 if (spec.field_width == -1) {
740 spec.field_width = 2*sizeof(void *);
741 spec.flags |= ZEROPAD;
742 }
743 spec.base = 16;
744
745 return number(buf, end, (unsigned long) ptr, spec);
746}
747
748/*
749 * Helper function to decode printf style format.
750 * Each call decode a token from the format and return the
751 * number of characters read (or likely the delta where it wants
752 * to go on the next call).
753 * The decoded token is returned through the parameters
754 *
755 * 'h', 'l', or 'L' for integer fields
756 * 'z' support added 23/7/1999 S.H.
757 * 'z' changed to 'Z' --davidm 1/25/99
758 * 't' added for ptrdiff_t
759 *
760 * @fmt: the format string
761 * @type of the token returned
762 * @flags: various flags such as +, -, # tokens..
763 * @field_width: overwritten width
764 * @base: base of the number (octal, hex, ...)
765 * @precision: precision of a number
766 * @qualifier: qualifier of a number (long, size_t, ...)
767 */
768static int format_decode(const char *fmt, struct printf_spec *spec)
769{
770 const char *start = fmt;
771 bool sign = false;
772
773 /* we finished early by reading the field width */
774 if (spec->type == FORMAT_TYPE_WITDH) {
775 if (spec->field_width < 0) {
776 spec->field_width = -spec->field_width;
777 spec->flags |= LEFT;
778 }
779 spec->type = FORMAT_TYPE_NONE;
780 goto precision;
781 }
782
783 /* we finished early by reading the precision */
784 if (spec->type == FORMAT_TYPE_PRECISION) {
785 if (spec->precision < 0)
786 spec->precision = 0;
787
788 spec->type = FORMAT_TYPE_NONE;
789 goto qualifier;
790 }
791
792 /* By default */
793 spec->type = FORMAT_TYPE_NONE;
794
795 for (; *fmt ; ++fmt) {
796 if (*fmt == '%')
797 break;
798 }
799
800 /* Return the current non-format string */
801 if (fmt != start || !*fmt)
802 return fmt - start;
803
804 /* Process flags */
805 spec->flags = 0;
806
807 while (1) { /* this also skips first '%' */
808 bool found = true;
809
810 ++fmt;
811
812 switch (*fmt) {
813 case '-': spec->flags |= LEFT; break;
814 case '+': spec->flags |= PLUS; break;
815 case ' ': spec->flags |= SPACE; break;
816 case '#': spec->flags |= SPECIAL; break;
817 case '0': spec->flags |= ZEROPAD; break;
818 default: found = false;
819 }
820
821 if (!found)
822 break;
823 }
824
825 /* get field width */
826 spec->field_width = -1;
827
828 if (isdigit(*fmt))
829 spec->field_width = skip_atoi(&fmt);
830 else if (*fmt == '*') {
831 /* it's the next argument */
832 spec->type = FORMAT_TYPE_WITDH;
833 return ++fmt - start;
834 }
835
836precision:
837 /* get the precision */
838 spec->precision = -1;
839 if (*fmt == '.') {
840 ++fmt;
841 if (isdigit(*fmt)) {
842 spec->precision = skip_atoi(&fmt);
843 if (spec->precision < 0)
844 spec->precision = 0;
845 } else if (*fmt == '*') {
846 /* it's the next argument */
847 spec->type = FORMAT_TYPE_WITDH;
848 return ++fmt - start;
849 }
850 }
851
852qualifier:
853 /* get the conversion qualifier */
854 spec->qualifier = -1;
855 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
856 *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
857 spec->qualifier = *fmt;
858 ++fmt;
859 if (spec->qualifier == 'l' && *fmt == 'l') {
860 spec->qualifier = 'L';
861 ++fmt;
862 }
863 }
864
865 /* default base */
866 spec->base = 10;
867 switch (*fmt) {
868 case 'c':
869 spec->type = FORMAT_TYPE_CHAR;
870 return ++fmt - start;
871
872 case 's':
873 spec->type = FORMAT_TYPE_STR;
874 return ++fmt - start;
875
876 case 'p':
877 spec->type = FORMAT_TYPE_PTR;
878 return fmt - start;
879 /* skip alnum */
880
881 case 'n':
882 spec->type = FORMAT_TYPE_NRCHARS;
883 return ++fmt - start;
884
885 case '%':
886 spec->type = FORMAT_TYPE_PERCENT_CHAR;
887 return ++fmt - start;
888
889 /* integer number formats - set up the flags and "break" */
890 case 'o':
891 spec->base = 8;
693 break; 892 break;
893
894 case 'x':
895 spec->flags |= SMALL;
896
897 case 'X':
898 spec->base = 16;
899 break;
900
901 case 'd':
902 case 'i':
903 sign = true;
904 case 'u':
905 break;
906
907 default:
908 spec->type = FORMAT_TYPE_INVALID;
909 return fmt - start;
694 } 910 }
695 flags |= SMALL; 911
696 if (field_width == -1) { 912 if (spec->qualifier == 'L')
697 field_width = 2*sizeof(void *); 913 spec->type = FORMAT_TYPE_LONG_LONG;
698 flags |= ZEROPAD; 914 else if (spec->qualifier == 'l') {
915 if (sign)
916 spec->type = FORMAT_TYPE_LONG;
917 else
918 spec->type = FORMAT_TYPE_ULONG;
919 } else if (spec->qualifier == 'Z' || spec->qualifier == 'z') {
920 spec->type = FORMAT_TYPE_SIZE_T;
921 } else if (spec->qualifier == 't') {
922 spec->type = FORMAT_TYPE_PTRDIFF;
923 } else if (spec->qualifier == 'h') {
924 if (sign)
925 spec->type = FORMAT_TYPE_SHORT;
926 else
927 spec->type = FORMAT_TYPE_USHORT;
928 } else {
929 if (sign)
930 spec->type = FORMAT_TYPE_INT;
931 else
932 spec->type = FORMAT_TYPE_UINT;
699 } 933 }
700 return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags); 934
935 return ++fmt - start;
701} 936}
702 937
703/** 938/**
@@ -726,18 +961,9 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
726int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) 961int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
727{ 962{
728 unsigned long long num; 963 unsigned long long num;
729 int base;
730 char *str, *end, c; 964 char *str, *end, c;
731 965 int read;
732 int flags; /* flags to number() */ 966 struct printf_spec spec = {0};
733
734 int field_width; /* width of output field */
735 int precision; /* min. # of digits for integers; max
736 number of chars for from string */
737 int qualifier; /* 'h', 'l', or 'L' for integer fields */
738 /* 'z' support added 23/7/1999 S.H. */
739 /* 'z' changed to 'Z' --davidm 1/25/99 */
740 /* 't' added for ptrdiff_t */
741 967
742 /* Reject out-of-range values early. Large positive sizes are 968 /* Reject out-of-range values early. Large positive sizes are
743 used for unknown buffer sizes. */ 969 used for unknown buffer sizes. */
@@ -758,184 +984,144 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
758 size = end - buf; 984 size = end - buf;
759 } 985 }
760 986
761 for (; *fmt ; ++fmt) { 987 while (*fmt) {
762 if (*fmt != '%') { 988 const char *old_fmt = fmt;
763 if (str < end)
764 *str = *fmt;
765 ++str;
766 continue;
767 }
768 989
769 /* process flags */ 990 read = format_decode(fmt, &spec);
770 flags = 0;
771 repeat:
772 ++fmt; /* this also skips first '%' */
773 switch (*fmt) {
774 case '-': flags |= LEFT; goto repeat;
775 case '+': flags |= PLUS; goto repeat;
776 case ' ': flags |= SPACE; goto repeat;
777 case '#': flags |= SPECIAL; goto repeat;
778 case '0': flags |= ZEROPAD; goto repeat;
779 }
780 991
781 /* get field width */ 992 fmt += read;
782 field_width = -1;
783 if (isdigit(*fmt))
784 field_width = skip_atoi(&fmt);
785 else if (*fmt == '*') {
786 ++fmt;
787 /* it's the next argument */
788 field_width = va_arg(args, int);
789 if (field_width < 0) {
790 field_width = -field_width;
791 flags |= LEFT;
792 }
793 }
794 993
795 /* get the precision */ 994 switch (spec.type) {
796 precision = -1; 995 case FORMAT_TYPE_NONE: {
797 if (*fmt == '.') { 996 int copy = read;
798 ++fmt; 997 if (str < end) {
799 if (isdigit(*fmt)) 998 if (copy > end - str)
800 precision = skip_atoi(&fmt); 999 copy = end - str;
801 else if (*fmt == '*') { 1000 memcpy(str, old_fmt, copy);
802 ++fmt;
803 /* it's the next argument */
804 precision = va_arg(args, int);
805 } 1001 }
806 if (precision < 0) 1002 str += read;
807 precision = 0; 1003 break;
808 } 1004 }
809 1005
810 /* get the conversion qualifier */ 1006 case FORMAT_TYPE_WITDH:
811 qualifier = -1; 1007 spec.field_width = va_arg(args, int);
812 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 1008 break;
813 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
814 qualifier = *fmt;
815 ++fmt;
816 if (qualifier == 'l' && *fmt == 'l') {
817 qualifier = 'L';
818 ++fmt;
819 }
820 }
821 1009
822 /* default base */ 1010 case FORMAT_TYPE_PRECISION:
823 base = 10; 1011 spec.precision = va_arg(args, int);
1012 break;
824 1013
825 switch (*fmt) { 1014 case FORMAT_TYPE_CHAR:
826 case 'c': 1015 if (!(spec.flags & LEFT)) {
827 if (!(flags & LEFT)) { 1016 while (--spec.field_width > 0) {
828 while (--field_width > 0) {
829 if (str < end)
830 *str = ' ';
831 ++str;
832 }
833 }
834 c = (unsigned char) va_arg(args, int);
835 if (str < end)
836 *str = c;
837 ++str;
838 while (--field_width > 0) {
839 if (str < end) 1017 if (str < end)
840 *str = ' '; 1018 *str = ' ';
841 ++str; 1019 ++str;
842 }
843 continue;
844
845 case 's':
846 str = string(str, end, va_arg(args, char *), field_width, precision, flags);
847 continue;
848
849 case 'p':
850 str = pointer(fmt+1, str, end,
851 va_arg(args, void *),
852 field_width, precision, flags);
853 /* Skip all alphanumeric pointer suffixes */
854 while (isalnum(fmt[1]))
855 fmt++;
856 continue;
857
858 case 'n':
859 /* FIXME:
860 * What does C99 say about the overflow case here? */
861 if (qualifier == 'l') {
862 long * ip = va_arg(args, long *);
863 *ip = (str - buf);
864 } else if (qualifier == 'Z' || qualifier == 'z') {
865 size_t * ip = va_arg(args, size_t *);
866 *ip = (str - buf);
867 } else {
868 int * ip = va_arg(args, int *);
869 *ip = (str - buf);
870 }
871 continue;
872 1020
873 case '%': 1021 }
1022 }
1023 c = (unsigned char) va_arg(args, int);
1024 if (str < end)
1025 *str = c;
1026 ++str;
1027 while (--spec.field_width > 0) {
874 if (str < end) 1028 if (str < end)
875 *str = '%'; 1029 *str = ' ';
876 ++str; 1030 ++str;
877 continue; 1031 }
1032 break;
878 1033
879 /* integer number formats - set up the flags and "break" */ 1034 case FORMAT_TYPE_STR:
880 case 'o': 1035 str = string(str, end, va_arg(args, char *), spec);
881 base = 8; 1036 break;
882 break;
883 1037
884 case 'x': 1038 case FORMAT_TYPE_PTR:
885 flags |= SMALL; 1039 str = pointer(fmt+1, str, end, va_arg(args, void *),
886 case 'X': 1040 spec);
887 base = 16; 1041 while (isalnum(*fmt))
888 break; 1042 fmt++;
1043 break;
889 1044
890 case 'd': 1045 case FORMAT_TYPE_PERCENT_CHAR:
891 case 'i': 1046 if (str < end)
892 flags |= SIGN; 1047 *str = '%';
893 case 'u': 1048 ++str;
894 break; 1049 break;
895 1050
896 default: 1051 case FORMAT_TYPE_INVALID:
1052 if (str < end)
1053 *str = '%';
1054 ++str;
1055 if (*fmt) {
897 if (str < end) 1056 if (str < end)
898 *str = '%'; 1057 *str = *fmt;
899 ++str; 1058 ++str;
900 if (*fmt) { 1059 } else {
901 if (str < end) 1060 --fmt;
902 *str = *fmt; 1061 }
903 ++str; 1062 break;
904 } else { 1063
905 --fmt; 1064 case FORMAT_TYPE_NRCHARS: {
906 } 1065 int qualifier = spec.qualifier;
907 continue; 1066
1067 if (qualifier == 'l') {
1068 long *ip = va_arg(args, long *);
1069 *ip = (str - buf);
1070 } else if (qualifier == 'Z' ||
1071 qualifier == 'z') {
1072 size_t *ip = va_arg(args, size_t *);
1073 *ip = (str - buf);
1074 } else {
1075 int *ip = va_arg(args, int *);
1076 *ip = (str - buf);
1077 }
1078 break;
908 } 1079 }
909 if (qualifier == 'L') 1080
910 num = va_arg(args, long long); 1081 default:
911 else if (qualifier == 'l') { 1082 switch (spec.type) {
912 num = va_arg(args, unsigned long); 1083 case FORMAT_TYPE_LONG_LONG:
913 if (flags & SIGN) 1084 num = va_arg(args, long long);
914 num = (signed long) num; 1085 break;
915 } else if (qualifier == 'Z' || qualifier == 'z') { 1086 case FORMAT_TYPE_ULONG:
916 num = va_arg(args, size_t); 1087 num = va_arg(args, unsigned long);
917 } else if (qualifier == 't') { 1088 break;
918 num = va_arg(args, ptrdiff_t); 1089 case FORMAT_TYPE_LONG:
919 } else if (qualifier == 'h') { 1090 num = va_arg(args, long);
920 num = (unsigned short) va_arg(args, int); 1091 break;
921 if (flags & SIGN) 1092 case FORMAT_TYPE_SIZE_T:
922 num = (signed short) num; 1093 num = va_arg(args, size_t);
923 } else { 1094 break;
924 num = va_arg(args, unsigned int); 1095 case FORMAT_TYPE_PTRDIFF:
925 if (flags & SIGN) 1096 num = va_arg(args, ptrdiff_t);
926 num = (signed int) num; 1097 break;
1098 case FORMAT_TYPE_USHORT:
1099 num = (unsigned short) va_arg(args, int);
1100 break;
1101 case FORMAT_TYPE_SHORT:
1102 num = (short) va_arg(args, int);
1103 break;
1104 case FORMAT_TYPE_UINT:
1105 num = va_arg(args, unsigned int);
1106 break;
1107 default:
1108 num = va_arg(args, unsigned int);
1109 }
1110
1111 str = number(str, end, num, spec);
927 } 1112 }
928 str = number(str, end, num, base,
929 field_width, precision, flags);
930 } 1113 }
1114
931 if (size > 0) { 1115 if (size > 0) {
932 if (str < end) 1116 if (str < end)
933 *str = '\0'; 1117 *str = '\0';
934 else 1118 else
935 end[-1] = '\0'; 1119 end[-1] = '\0';
936 } 1120 }
1121
937 /* the trailing null byte doesn't count towards the total */ 1122 /* the trailing null byte doesn't count towards the total */
938 return str-buf; 1123 return str-buf;
1124
939} 1125}
940EXPORT_SYMBOL(vsnprintf); 1126EXPORT_SYMBOL(vsnprintf);
941 1127
@@ -1084,8 +1270,9 @@ EXPORT_SYMBOL(sprintf);
1084 */ 1270 */
1085int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) 1271int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
1086{ 1272{
1273 struct printf_spec spec = {0};
1087 char *str, *end; 1274 char *str, *end;
1088 int qualifier; 1275 int read;
1089 1276
1090 str = (char *)bin_buf; 1277 str = (char *)bin_buf;
1091 end = (char *)(bin_buf + size); 1278 end = (char *)(bin_buf + size);
@@ -1110,57 +1297,26 @@ do { \
1110 str += sizeof(type); \ 1297 str += sizeof(type); \
1111} while (0) 1298} while (0)
1112 1299
1113 for (; *fmt ; ++fmt) {
1114 if (*fmt != '%')
1115 continue;
1116 1300
1117repeat: 1301 while (*fmt) {
1118 /* parse flags */ 1302 read = format_decode(fmt, &spec);
1119 ++fmt; /* this also skips first '%' */
1120 if (*fmt == '-' || *fmt == '+' || *fmt == ' '
1121 || *fmt == '#' || *fmt == '0')
1122 goto repeat;
1123 1303
1124 /* parse field width */ 1304 fmt += read;
1125 if (isdigit(*fmt))
1126 skip_atoi(&fmt);
1127 else if (*fmt == '*') {
1128 ++fmt;
1129 /* it's the next argument */
1130 save_arg(int);
1131 }
1132 1305
1133 /* parse the precision */ 1306 switch (spec.type) {
1134 if (*fmt == '.') { 1307 case FORMAT_TYPE_NONE:
1135 ++fmt; 1308 break;
1136 if (isdigit(*fmt))
1137 skip_atoi(&fmt);
1138 else if (*fmt == '*') {
1139 ++fmt;
1140 /* it's the next argument */
1141 save_arg(int);
1142 }
1143 }
1144 1309
1145 /* parse the conversion qualifier */ 1310 case FORMAT_TYPE_WITDH:
1146 qualifier = -1; 1311 case FORMAT_TYPE_PRECISION:
1147 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 1312 save_arg(int);
1148 *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { 1313 break;
1149 qualifier = *fmt;
1150 ++fmt;
1151 if (qualifier == 'l' && *fmt == 'l') {
1152 qualifier = 'L';
1153 ++fmt;
1154 }
1155 }
1156 1314
1157 /* parse format type */ 1315 case FORMAT_TYPE_CHAR:
1158 switch (*fmt) {
1159 case 'c':
1160 save_arg(char); 1316 save_arg(char);
1161 continue; 1317 break;
1162 case 's': { 1318
1163 /* save the string argument */ 1319 case FORMAT_TYPE_STR: {
1164 const char *save_str = va_arg(args, char *); 1320 const char *save_str = va_arg(args, char *);
1165 size_t len; 1321 size_t len;
1166 if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE 1322 if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
@@ -1170,16 +1326,27 @@ repeat:
1170 if (str + len + 1 < end) 1326 if (str + len + 1 < end)
1171 memcpy(str, save_str, len + 1); 1327 memcpy(str, save_str, len + 1);
1172 str += len + 1; 1328 str += len + 1;
1173 continue; 1329 break;
1174 } 1330 }
1175 case 'p': 1331
1332 case FORMAT_TYPE_PTR:
1176 save_arg(void *); 1333 save_arg(void *);
1177 /* skip all alphanumeric pointer suffixes */ 1334 /* skip all alphanumeric pointer suffixes */
1178 while (isalnum(fmt[1])) 1335 while (isalnum(*fmt))
1179 fmt++; 1336 fmt++;
1180 continue; 1337 break;
1181 case 'n': { 1338
1339 case FORMAT_TYPE_PERCENT_CHAR:
1340 break;
1341
1342 case FORMAT_TYPE_INVALID:
1343 if (!*fmt)
1344 --fmt;
1345 break;
1346
1347 case FORMAT_TYPE_NRCHARS: {
1182 /* skip %n 's argument */ 1348 /* skip %n 's argument */
1349 int qualifier = spec.qualifier;
1183 void *skip_arg; 1350 void *skip_arg;
1184 if (qualifier == 'l') 1351 if (qualifier == 'l')
1185 skip_arg = va_arg(args, long *); 1352 skip_arg = va_arg(args, long *);
@@ -1187,37 +1354,37 @@ repeat:
1187 skip_arg = va_arg(args, size_t *); 1354 skip_arg = va_arg(args, size_t *);
1188 else 1355 else
1189 skip_arg = va_arg(args, int *); 1356 skip_arg = va_arg(args, int *);
1190 continue; 1357 break;
1191 } 1358 }
1192 case 'o': 1359
1193 case 'x': 1360 default:
1194 case 'X': 1361 switch (spec.type) {
1195 case 'd': 1362
1196 case 'i': 1363 case FORMAT_TYPE_LONG_LONG:
1197 case 'u':
1198 /* save arg for case: 'o', 'x', 'X', 'd', 'i', 'u' */
1199 if (qualifier == 'L')
1200 save_arg(long long); 1364 save_arg(long long);
1201 else if (qualifier == 'l') 1365 break;
1366 case FORMAT_TYPE_ULONG:
1367 case FORMAT_TYPE_LONG:
1202 save_arg(unsigned long); 1368 save_arg(unsigned long);
1203 else if (qualifier == 'Z' || qualifier == 'z') 1369 break;
1370 case FORMAT_TYPE_SIZE_T:
1204 save_arg(size_t); 1371 save_arg(size_t);
1205 else if (qualifier == 't') 1372 break;
1373 case FORMAT_TYPE_PTRDIFF:
1206 save_arg(ptrdiff_t); 1374 save_arg(ptrdiff_t);
1207 else if (qualifier == 'h') 1375 break;
1376 case FORMAT_TYPE_USHORT:
1377 case FORMAT_TYPE_SHORT:
1208 save_arg(short); 1378 save_arg(short);
1209 else 1379 break;
1380 default:
1210 save_arg(int); 1381 save_arg(int);
1211 continue; 1382 }
1212 default:
1213 if (!*fmt)
1214 --fmt;
1215 continue;
1216 } 1383 }
1217 } 1384 }
1218#undef save_arg
1219
1220 return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf; 1385 return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
1386
1387#undef save_arg
1221} 1388}
1222EXPORT_SYMBOL_GPL(vbin_printf); 1389EXPORT_SYMBOL_GPL(vbin_printf);
1223 1390
@@ -1249,14 +1416,10 @@ EXPORT_SYMBOL_GPL(vbin_printf);
1249int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) 1416int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
1250{ 1417{
1251 unsigned long long num; 1418 unsigned long long num;
1252 int base;
1253 char *str, *end, c; 1419 char *str, *end, c;
1254 const char *args = (const char *)bin_buf; 1420 const char *args = (const char *)bin_buf;
1255 1421
1256 int flags; 1422 struct printf_spec spec = {0};
1257 int field_width;
1258 int precision;
1259 int qualifier;
1260 1423
1261 if (unlikely((int) size < 0)) { 1424 if (unlikely((int) size < 0)) {
1262 /* There can be only one.. */ 1425 /* There can be only one.. */
@@ -1290,84 +1453,37 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
1290 size = end - buf; 1453 size = end - buf;
1291 } 1454 }
1292 1455
1293 for (; *fmt ; ++fmt) { 1456 while (*fmt) {
1294 if (*fmt != '%') { 1457 int read;
1295 if (str < end) 1458 const char *old_fmt = fmt;
1296 *str = *fmt;
1297 ++str;
1298 continue;
1299 }
1300 1459
1301 /* process flags */ 1460 read = format_decode(fmt, &spec);
1302 flags = 0;
1303repeat:
1304 ++fmt; /* this also skips first '%' */
1305 switch (*fmt) {
1306 case '-':
1307 flags |= LEFT;
1308 goto repeat;
1309 case '+':
1310 flags |= PLUS;
1311 goto repeat;
1312 case ' ':
1313 flags |= SPACE;
1314 goto repeat;
1315 case '#':
1316 flags |= SPECIAL;
1317 goto repeat;
1318 case '0':
1319 flags |= ZEROPAD;
1320 goto repeat;
1321 }
1322 1461
1323 /* get field width */ 1462 fmt += read;
1324 field_width = -1;
1325 if (isdigit(*fmt))
1326 field_width = skip_atoi(&fmt);
1327 else if (*fmt == '*') {
1328 ++fmt;
1329 /* it's the next argument */
1330 field_width = get_arg(int);
1331 if (field_width < 0) {
1332 field_width = -field_width;
1333 flags |= LEFT;
1334 }
1335 }
1336 1463
1337 /* get the precision */ 1464 switch (spec.type) {
1338 precision = -1; 1465 case FORMAT_TYPE_NONE: {
1339 if (*fmt == '.') { 1466 int copy = read;
1340 ++fmt; 1467 if (str < end) {
1341 if (isdigit(*fmt)) 1468 if (copy > end - str)
1342 precision = skip_atoi(&fmt); 1469 copy = end - str;
1343 else if (*fmt == '*') { 1470 memcpy(str, old_fmt, copy);
1344 ++fmt;
1345 /* it's the next argument */
1346 precision = get_arg(int);
1347 } 1471 }
1348 if (precision < 0) 1472 str += read;
1349 precision = 0; 1473 break;
1350 } 1474 }
1351 1475
1352 /* get the conversion qualifier */ 1476 case FORMAT_TYPE_WITDH:
1353 qualifier = -1; 1477 spec.field_width = get_arg(int);
1354 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 1478 break;
1355 *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
1356 qualifier = *fmt;
1357 ++fmt;
1358 if (qualifier == 'l' && *fmt == 'l') {
1359 qualifier = 'L';
1360 ++fmt;
1361 }
1362 }
1363 1479
1364 /* default base */ 1480 case FORMAT_TYPE_PRECISION:
1365 base = 10; 1481 spec.precision = get_arg(int);
1482 break;
1366 1483
1367 switch (*fmt) { 1484 case FORMAT_TYPE_CHAR:
1368 case 'c': 1485 if (!(spec.flags & LEFT)) {
1369 if (!(flags & LEFT)) { 1486 while (--spec.field_width > 0) {
1370 while (--field_width > 0) {
1371 if (str < end) 1487 if (str < end)
1372 *str = ' '; 1488 *str = ' ';
1373 ++str; 1489 ++str;
@@ -1377,58 +1493,34 @@ repeat:
1377 if (str < end) 1493 if (str < end)
1378 *str = c; 1494 *str = c;
1379 ++str; 1495 ++str;
1380 while (--field_width > 0) { 1496 while (--spec.field_width > 0) {
1381 if (str < end) 1497 if (str < end)
1382 *str = ' '; 1498 *str = ' ';
1383 ++str; 1499 ++str;
1384 } 1500 }
1385 continue; 1501 break;
1386 1502
1387 case 's':{ 1503 case FORMAT_TYPE_STR: {
1388 const char *str_arg = args; 1504 const char *str_arg = args;
1389 size_t len = strlen(str_arg); 1505 size_t len = strlen(str_arg);
1390 args += len + 1; 1506 args += len + 1;
1391 str = string(str, end, (char *)str_arg, field_width, 1507 str = string(str, end, (char *)str_arg, spec);
1392 precision, flags); 1508 break;
1393 continue;
1394 } 1509 }
1395 1510
1396 case 'p': 1511 case FORMAT_TYPE_PTR:
1397 str = pointer(fmt+1, str, end, get_arg(void *), 1512 str = pointer(fmt+1, str, end, get_arg(void *), spec);
1398 field_width, precision, flags); 1513 while (isalnum(*fmt))
1399 /* Skip all alphanumeric pointer suffixes */
1400 while (isalnum(fmt[1]))
1401 fmt++; 1514 fmt++;
1402 continue; 1515 break;
1403
1404 case 'n':
1405 /* skip %n */
1406 continue;
1407 1516
1408 case '%': 1517 case FORMAT_TYPE_PERCENT_CHAR:
1409 if (str < end) 1518 if (str < end)
1410 *str = '%'; 1519 *str = '%';
1411 ++str; 1520 ++str;
1412 continue;
1413
1414 /* integer number formats - set up the flags and "break" */
1415 case 'o':
1416 base = 8;
1417 break;
1418
1419 case 'x':
1420 flags |= SMALL;
1421 case 'X':
1422 base = 16;
1423 break; 1521 break;
1424 1522
1425 case 'd': 1523 case FORMAT_TYPE_INVALID:
1426 case 'i':
1427 flags |= SIGN;
1428 case 'u':
1429 break;
1430
1431 default:
1432 if (str < end) 1524 if (str < end)
1433 *str = '%'; 1525 *str = '%';
1434 ++str; 1526 ++str;
@@ -1439,36 +1531,54 @@ repeat:
1439 } else { 1531 } else {
1440 --fmt; 1532 --fmt;
1441 } 1533 }
1442 continue; 1534 break;
1443 } 1535
1444 if (qualifier == 'L') 1536 case FORMAT_TYPE_NRCHARS:
1445 num = get_arg(long long); 1537 /* skip */
1446 else if (qualifier == 'l') { 1538 break;
1447 num = get_arg(unsigned long); 1539
1448 if (flags & SIGN) 1540 default:
1449 num = (signed long) num; 1541 switch (spec.type) {
1450 } else if (qualifier == 'Z' || qualifier == 'z') { 1542
1451 num = get_arg(size_t); 1543 case FORMAT_TYPE_LONG_LONG:
1452 } else if (qualifier == 't') { 1544 num = get_arg(long long);
1453 num = get_arg(ptrdiff_t); 1545 break;
1454 } else if (qualifier == 'h') { 1546 case FORMAT_TYPE_ULONG:
1455 num = (unsigned short) get_arg(short); 1547 num = get_arg(unsigned long);
1456 if (flags & SIGN) 1548 break;
1457 num = (signed short) num; 1549 case FORMAT_TYPE_LONG:
1458 } else { 1550 num = get_arg(unsigned long);
1459 num = get_arg(unsigned int); 1551 break;
1460 if (flags & SIGN) 1552 case FORMAT_TYPE_SIZE_T:
1461 num = (signed int) num; 1553 num = get_arg(size_t);
1554 break;
1555 case FORMAT_TYPE_PTRDIFF:
1556 num = get_arg(ptrdiff_t);
1557 break;
1558 case FORMAT_TYPE_USHORT:
1559 num = get_arg(unsigned short);
1560 break;
1561 case FORMAT_TYPE_SHORT:
1562 num = get_arg(short);
1563 break;
1564 case FORMAT_TYPE_UINT:
1565 num = get_arg(unsigned int);
1566 break;
1567 default:
1568 num = get_arg(int);
1569 }
1570
1571 str = number(str, end, num, spec);
1462 } 1572 }
1463 str = number(str, end, num, base,
1464 field_width, precision, flags);
1465 } 1573 }
1574
1466 if (size > 0) { 1575 if (size > 0) {
1467 if (str < end) 1576 if (str < end)
1468 *str = '\0'; 1577 *str = '\0';
1469 else 1578 else
1470 end[-1] = '\0'; 1579 end[-1] = '\0';
1471 } 1580 }
1581
1472#undef get_arg 1582#undef get_arg
1473 1583
1474 /* the trailing null byte doesn't count towards the total */ 1584 /* the trailing null byte doesn't count towards the total */