diff options
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 137 |
1 files changed, 95 insertions, 42 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d4996cf46eb6..46d34b0b74a8 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -118,6 +118,7 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base) | |||
118 | 118 | ||
119 | return simple_strtoull(cp, endp, base); | 119 | return simple_strtoull(cp, endp, base); |
120 | } | 120 | } |
121 | EXPORT_SYMBOL(simple_strtoll); | ||
121 | 122 | ||
122 | /** | 123 | /** |
123 | * strict_strtoul - convert a string to an unsigned long strictly | 124 | * strict_strtoul - convert a string to an unsigned long strictly |
@@ -381,8 +382,8 @@ static noinline char *put_dec(char *buf, unsigned long long num) | |||
381 | #define PLUS 4 /* show plus */ | 382 | #define PLUS 4 /* show plus */ |
382 | #define SPACE 8 /* space if plus */ | 383 | #define SPACE 8 /* space if plus */ |
383 | #define LEFT 16 /* left justified */ | 384 | #define LEFT 16 /* left justified */ |
384 | #define SMALL 32 /* Must be 32 == 0x20 */ | 385 | #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ |
385 | #define SPECIAL 64 /* 0x */ | 386 | #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ |
386 | 387 | ||
387 | enum format_type { | 388 | enum format_type { |
388 | FORMAT_TYPE_NONE, /* Just a string part */ | 389 | FORMAT_TYPE_NONE, /* Just a string part */ |
@@ -408,12 +409,12 @@ enum format_type { | |||
408 | }; | 409 | }; |
409 | 410 | ||
410 | struct printf_spec { | 411 | struct printf_spec { |
411 | enum format_type type; | 412 | u8 type; /* format_type enum */ |
412 | int flags; /* flags to number() */ | 413 | u8 flags; /* flags to number() */ |
413 | int field_width; /* width of output field */ | 414 | u8 base; /* number base, 8, 10 or 16 only */ |
414 | int base; | 415 | u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ |
415 | int precision; /* # of digits/chars */ | 416 | s16 field_width; /* width of output field */ |
416 | int qualifier; | 417 | s16 precision; /* # of digits/chars */ |
417 | }; | 418 | }; |
418 | 419 | ||
419 | static char *number(char *buf, char *end, unsigned long long num, | 420 | static char *number(char *buf, char *end, unsigned long long num, |
@@ -597,22 +598,35 @@ static char *resource_string(char *buf, char *end, struct resource *res, | |||
597 | #ifndef MEM_RSRC_PRINTK_SIZE | 598 | #ifndef MEM_RSRC_PRINTK_SIZE |
598 | #define MEM_RSRC_PRINTK_SIZE 10 | 599 | #define MEM_RSRC_PRINTK_SIZE 10 |
599 | #endif | 600 | #endif |
600 | struct printf_spec hex_spec = { | 601 | static const struct printf_spec io_spec = { |
601 | .base = 16, | 602 | .base = 16, |
603 | .field_width = IO_RSRC_PRINTK_SIZE, | ||
602 | .precision = -1, | 604 | .precision = -1, |
603 | .flags = SPECIAL | SMALL | ZEROPAD, | 605 | .flags = SPECIAL | SMALL | ZEROPAD, |
604 | }; | 606 | }; |
605 | struct printf_spec dec_spec = { | 607 | static const struct printf_spec mem_spec = { |
608 | .base = 16, | ||
609 | .field_width = MEM_RSRC_PRINTK_SIZE, | ||
610 | .precision = -1, | ||
611 | .flags = SPECIAL | SMALL | ZEROPAD, | ||
612 | }; | ||
613 | static const struct printf_spec bus_spec = { | ||
614 | .base = 16, | ||
615 | .field_width = 2, | ||
616 | .precision = -1, | ||
617 | .flags = SMALL | ZEROPAD, | ||
618 | }; | ||
619 | static const struct printf_spec dec_spec = { | ||
606 | .base = 10, | 620 | .base = 10, |
607 | .precision = -1, | 621 | .precision = -1, |
608 | .flags = 0, | 622 | .flags = 0, |
609 | }; | 623 | }; |
610 | struct printf_spec str_spec = { | 624 | static const struct printf_spec str_spec = { |
611 | .field_width = -1, | 625 | .field_width = -1, |
612 | .precision = 10, | 626 | .precision = 10, |
613 | .flags = LEFT, | 627 | .flags = LEFT, |
614 | }; | 628 | }; |
615 | struct printf_spec flag_spec = { | 629 | static const struct printf_spec flag_spec = { |
616 | .base = 16, | 630 | .base = 16, |
617 | .precision = -1, | 631 | .precision = -1, |
618 | .flags = SPECIAL | SMALL, | 632 | .flags = SPECIAL | SMALL, |
@@ -622,47 +636,48 @@ static char *resource_string(char *buf, char *end, struct resource *res, | |||
622 | * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */ | 636 | * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */ |
623 | #define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4) | 637 | #define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4) |
624 | #define FLAG_BUF_SIZE (2 * sizeof(res->flags)) | 638 | #define FLAG_BUF_SIZE (2 * sizeof(res->flags)) |
625 | #define DECODED_BUF_SIZE sizeof("[mem - 64bit pref disabled]") | 639 | #define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]") |
626 | #define RAW_BUF_SIZE sizeof("[mem - flags 0x]") | 640 | #define RAW_BUF_SIZE sizeof("[mem - flags 0x]") |
627 | char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, | 641 | char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, |
628 | 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; | 642 | 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; |
629 | 643 | ||
630 | char *p = sym, *pend = sym + sizeof(sym); | 644 | char *p = sym, *pend = sym + sizeof(sym); |
631 | int size = -1, addr = 0; | ||
632 | int decode = (fmt[0] == 'R') ? 1 : 0; | 645 | int decode = (fmt[0] == 'R') ? 1 : 0; |
633 | 646 | const struct printf_spec *specp; | |
634 | if (res->flags & IORESOURCE_IO) { | ||
635 | size = IO_RSRC_PRINTK_SIZE; | ||
636 | addr = 1; | ||
637 | } else if (res->flags & IORESOURCE_MEM) { | ||
638 | size = MEM_RSRC_PRINTK_SIZE; | ||
639 | addr = 1; | ||
640 | } | ||
641 | 647 | ||
642 | *p++ = '['; | 648 | *p++ = '['; |
643 | if (res->flags & IORESOURCE_IO) | 649 | if (res->flags & IORESOURCE_IO) { |
644 | p = string(p, pend, "io ", str_spec); | 650 | p = string(p, pend, "io ", str_spec); |
645 | else if (res->flags & IORESOURCE_MEM) | 651 | specp = &io_spec; |
652 | } else if (res->flags & IORESOURCE_MEM) { | ||
646 | p = string(p, pend, "mem ", str_spec); | 653 | p = string(p, pend, "mem ", str_spec); |
647 | else if (res->flags & IORESOURCE_IRQ) | 654 | specp = &mem_spec; |
655 | } else if (res->flags & IORESOURCE_IRQ) { | ||
648 | p = string(p, pend, "irq ", str_spec); | 656 | p = string(p, pend, "irq ", str_spec); |
649 | else if (res->flags & IORESOURCE_DMA) | 657 | specp = &dec_spec; |
658 | } else if (res->flags & IORESOURCE_DMA) { | ||
650 | p = string(p, pend, "dma ", str_spec); | 659 | p = string(p, pend, "dma ", str_spec); |
651 | else { | 660 | specp = &dec_spec; |
661 | } else if (res->flags & IORESOURCE_BUS) { | ||
662 | p = string(p, pend, "bus ", str_spec); | ||
663 | specp = &bus_spec; | ||
664 | } else { | ||
652 | p = string(p, pend, "??? ", str_spec); | 665 | p = string(p, pend, "??? ", str_spec); |
666 | specp = &mem_spec; | ||
653 | decode = 0; | 667 | decode = 0; |
654 | } | 668 | } |
655 | hex_spec.field_width = size; | 669 | p = number(p, pend, res->start, *specp); |
656 | p = number(p, pend, res->start, addr ? hex_spec : dec_spec); | ||
657 | if (res->start != res->end) { | 670 | if (res->start != res->end) { |
658 | *p++ = '-'; | 671 | *p++ = '-'; |
659 | p = number(p, pend, res->end, addr ? hex_spec : dec_spec); | 672 | p = number(p, pend, res->end, *specp); |
660 | } | 673 | } |
661 | if (decode) { | 674 | if (decode) { |
662 | if (res->flags & IORESOURCE_MEM_64) | 675 | if (res->flags & IORESOURCE_MEM_64) |
663 | p = string(p, pend, " 64bit", str_spec); | 676 | p = string(p, pend, " 64bit", str_spec); |
664 | if (res->flags & IORESOURCE_PREFETCH) | 677 | if (res->flags & IORESOURCE_PREFETCH) |
665 | p = string(p, pend, " pref", str_spec); | 678 | p = string(p, pend, " pref", str_spec); |
679 | if (res->flags & IORESOURCE_WINDOW) | ||
680 | p = string(p, pend, " window", str_spec); | ||
666 | if (res->flags & IORESOURCE_DISABLED) | 681 | if (res->flags & IORESOURCE_DISABLED) |
667 | p = string(p, pend, " disabled", str_spec); | 682 | p = string(p, pend, " disabled", str_spec); |
668 | } else { | 683 | } else { |
@@ -681,24 +696,55 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, | |||
681 | char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; | 696 | char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; |
682 | char *p = mac_addr; | 697 | char *p = mac_addr; |
683 | int i; | 698 | int i; |
699 | char separator; | ||
700 | |||
701 | if (fmt[1] == 'F') { /* FDDI canonical format */ | ||
702 | separator = '-'; | ||
703 | } else { | ||
704 | separator = ':'; | ||
705 | } | ||
684 | 706 | ||
685 | for (i = 0; i < 6; i++) { | 707 | for (i = 0; i < 6; i++) { |
686 | p = pack_hex_byte(p, addr[i]); | 708 | p = pack_hex_byte(p, addr[i]); |
687 | if (fmt[0] == 'M' && i != 5) | 709 | if (fmt[0] == 'M' && i != 5) |
688 | *p++ = ':'; | 710 | *p++ = separator; |
689 | } | 711 | } |
690 | *p = '\0'; | 712 | *p = '\0'; |
691 | 713 | ||
692 | return string(buf, end, mac_addr, spec); | 714 | return string(buf, end, mac_addr, spec); |
693 | } | 715 | } |
694 | 716 | ||
695 | static char *ip4_string(char *p, const u8 *addr, bool leading_zeros) | 717 | static char *ip4_string(char *p, const u8 *addr, const char *fmt) |
696 | { | 718 | { |
697 | int i; | 719 | int i; |
698 | 720 | bool leading_zeros = (fmt[0] == 'i'); | |
721 | int index; | ||
722 | int step; | ||
723 | |||
724 | switch (fmt[2]) { | ||
725 | case 'h': | ||
726 | #ifdef __BIG_ENDIAN | ||
727 | index = 0; | ||
728 | step = 1; | ||
729 | #else | ||
730 | index = 3; | ||
731 | step = -1; | ||
732 | #endif | ||
733 | break; | ||
734 | case 'l': | ||
735 | index = 3; | ||
736 | step = -1; | ||
737 | break; | ||
738 | case 'n': | ||
739 | case 'b': | ||
740 | default: | ||
741 | index = 0; | ||
742 | step = 1; | ||
743 | break; | ||
744 | } | ||
699 | for (i = 0; i < 4; i++) { | 745 | for (i = 0; i < 4; i++) { |
700 | char temp[3]; /* hold each IP quad in reverse order */ | 746 | char temp[3]; /* hold each IP quad in reverse order */ |
701 | int digits = put_dec_trunc(temp, addr[i]) - temp; | 747 | int digits = put_dec_trunc(temp, addr[index]) - temp; |
702 | if (leading_zeros) { | 748 | if (leading_zeros) { |
703 | if (digits < 3) | 749 | if (digits < 3) |
704 | *p++ = '0'; | 750 | *p++ = '0'; |
@@ -710,6 +756,7 @@ static char *ip4_string(char *p, const u8 *addr, bool leading_zeros) | |||
710 | *p++ = temp[digits]; | 756 | *p++ = temp[digits]; |
711 | if (i < 3) | 757 | if (i < 3) |
712 | *p++ = '.'; | 758 | *p++ = '.'; |
759 | index += step; | ||
713 | } | 760 | } |
714 | *p = '\0'; | 761 | *p = '\0'; |
715 | 762 | ||
@@ -789,7 +836,7 @@ static char *ip6_compressed_string(char *p, const char *addr) | |||
789 | if (useIPv4) { | 836 | if (useIPv4) { |
790 | if (needcolon) | 837 | if (needcolon) |
791 | *p++ = ':'; | 838 | *p++ = ':'; |
792 | p = ip4_string(p, &in6.s6_addr[12], false); | 839 | p = ip4_string(p, &in6.s6_addr[12], "I4"); |
793 | } | 840 | } |
794 | *p = '\0'; | 841 | *p = '\0'; |
795 | 842 | ||
@@ -829,7 +876,7 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr, | |||
829 | { | 876 | { |
830 | char ip4_addr[sizeof("255.255.255.255")]; | 877 | char ip4_addr[sizeof("255.255.255.255")]; |
831 | 878 | ||
832 | ip4_string(ip4_addr, addr, fmt[0] == 'i'); | 879 | ip4_string(ip4_addr, addr, fmt); |
833 | 880 | ||
834 | return string(buf, end, ip4_addr, spec); | 881 | return string(buf, end, ip4_addr, spec); |
835 | } | 882 | } |
@@ -896,14 +943,17 @@ static char *uuid_string(char *buf, char *end, const u8 *addr, | |||
896 | * - 'M' For a 6-byte MAC address, it prints the address in the | 943 | * - 'M' For a 6-byte MAC address, it prints the address in the |
897 | * usual colon-separated hex notation | 944 | * usual colon-separated hex notation |
898 | * - 'm' For a 6-byte MAC address, it prints the hex address without colons | 945 | * - 'm' For a 6-byte MAC address, it prints the hex address without colons |
946 | * - 'MF' For a 6-byte MAC FDDI address, it prints the address | ||
947 | * with a dash-separated hex notation | ||
899 | * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way | 948 | * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way |
900 | * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) | 949 | * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) |
901 | * IPv6 uses colon separated network-order 16 bit hex with leading 0's | 950 | * IPv6 uses colon separated network-order 16 bit hex with leading 0's |
902 | * - 'i' [46] for 'raw' IPv4/IPv6 addresses | 951 | * - 'i' [46] for 'raw' IPv4/IPv6 addresses |
903 | * IPv6 omits the colons (01020304...0f) | 952 | * IPv6 omits the colons (01020304...0f) |
904 | * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) | 953 | * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) |
954 | * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order | ||
905 | * - 'I6c' for IPv6 addresses printed as specified by | 955 | * - 'I6c' for IPv6 addresses printed as specified by |
906 | * http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt | 956 | * http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00 |
907 | * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form | 957 | * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form |
908 | * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | 958 | * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" |
909 | * Options for %pU are: | 959 | * Options for %pU are: |
@@ -939,6 +989,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
939 | return resource_string(buf, end, ptr, spec, fmt); | 989 | return resource_string(buf, end, ptr, spec, fmt); |
940 | case 'M': /* Colon separated: 00:01:02:03:04:05 */ | 990 | case 'M': /* Colon separated: 00:01:02:03:04:05 */ |
941 | case 'm': /* Contiguous: 000102030405 */ | 991 | case 'm': /* Contiguous: 000102030405 */ |
992 | /* [mM]F (FDDI, bit reversed) */ | ||
942 | return mac_address_string(buf, end, ptr, spec, fmt); | 993 | return mac_address_string(buf, end, ptr, spec, fmt); |
943 | case 'I': /* Formatted IP supported | 994 | case 'I': /* Formatted IP supported |
944 | * 4: 1.2.3.4 | 995 | * 4: 1.2.3.4 |
@@ -1188,7 +1239,7 @@ qualifier: | |||
1188 | * %pI6 print an IPv6 address with colons | 1239 | * %pI6 print an IPv6 address with colons |
1189 | * %pi6 print an IPv6 address without colons | 1240 | * %pi6 print an IPv6 address without colons |
1190 | * %pI6c print an IPv6 address as specified by | 1241 | * %pI6c print an IPv6 address as specified by |
1191 | * http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt | 1242 | * http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00 |
1192 | * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper | 1243 | * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper |
1193 | * case. | 1244 | * case. |
1194 | * %n is ignored | 1245 | * %n is ignored |
@@ -1297,7 +1348,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
1297 | break; | 1348 | break; |
1298 | 1349 | ||
1299 | case FORMAT_TYPE_NRCHARS: { | 1350 | case FORMAT_TYPE_NRCHARS: { |
1300 | int qualifier = spec.qualifier; | 1351 | u8 qualifier = spec.qualifier; |
1301 | 1352 | ||
1302 | if (qualifier == 'l') { | 1353 | if (qualifier == 'l') { |
1303 | long *ip = va_arg(args, long *); | 1354 | long *ip = va_arg(args, long *); |
@@ -1583,7 +1634,7 @@ do { \ | |||
1583 | 1634 | ||
1584 | case FORMAT_TYPE_NRCHARS: { | 1635 | case FORMAT_TYPE_NRCHARS: { |
1585 | /* skip %n 's argument */ | 1636 | /* skip %n 's argument */ |
1586 | int qualifier = spec.qualifier; | 1637 | u8 qualifier = spec.qualifier; |
1587 | void *skip_arg; | 1638 | void *skip_arg; |
1588 | if (qualifier == 'l') | 1639 | if (qualifier == 'l') |
1589 | skip_arg = va_arg(args, long *); | 1640 | skip_arg = va_arg(args, long *); |
@@ -1849,7 +1900,9 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
1849 | char *next; | 1900 | char *next; |
1850 | char digit; | 1901 | char digit; |
1851 | int num = 0; | 1902 | int num = 0; |
1852 | int qualifier, base, field_width; | 1903 | u8 qualifier; |
1904 | u8 base; | ||
1905 | s16 field_width; | ||
1853 | bool is_sign; | 1906 | bool is_sign; |
1854 | 1907 | ||
1855 | while (*fmt && *str) { | 1908 | while (*fmt && *str) { |
@@ -1927,7 +1980,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
1927 | { | 1980 | { |
1928 | char *s = (char *)va_arg(args, char *); | 1981 | char *s = (char *)va_arg(args, char *); |
1929 | if (field_width == -1) | 1982 | if (field_width == -1) |
1930 | field_width = INT_MAX; | 1983 | field_width = SHORT_MAX; |
1931 | /* first, skip leading white space in buffer */ | 1984 | /* first, skip leading white space in buffer */ |
1932 | str = skip_spaces(str); | 1985 | str = skip_spaces(str); |
1933 | 1986 | ||