diff options
Diffstat (limited to 'lib/vsprintf.c')
| -rw-r--r-- | lib/vsprintf.c | 133 |
1 files changed, 93 insertions, 40 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 3b8aeec4e327..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,12 +943,15 @@ 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://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00 | 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 |
| @@ -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 |
| @@ -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 | ||
