X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=lib%2Fvsprintf.c;h=b4edee29b0dbe07e39cf1016d31fbc62c16beabb;hb=c366a45649a33fc75857afb72f2e7358a906d3d7;hp=4c82837cc41e8e55899d945e8f27d399a0b0be71;hpb=6f4e050639241218987541f4729172e4e0e2ff31;p=oweals%2Fu-boot.git diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 4c82837cc4..b4edee29b0 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -2,6 +2,8 @@ * linux/lib/vsprintf.c * * Copyright (C) 1991, 1992 Linus Torvalds + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. */ /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ @@ -11,180 +13,20 @@ * from hush: simple_itoa() was lifted from boa-0.93.15 */ +#include +#include +#include +#include +#include #include +#include +#include +#include #include #include -#include -#include -#include -#if !defined(CONFIG_PANIC_HANG) -#include -#endif - -#include #define noinline __attribute__((noinline)) -unsigned long simple_strtoul(const char *cp, char **endp, - unsigned int base) -{ - unsigned long result = 0; - unsigned long value; - - if (*cp == '0') { - cp++; - if ((*cp == 'x') && isxdigit(cp[1])) { - base = 16; - cp++; - } - - if (!base) - base = 8; - } - - if (!base) - base = 10; - - while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) - ? toupper(*cp) : *cp)-'A'+10) < base) { - result = result*base + value; - cp++; - } - - if (endp) - *endp = (char *)cp; - - return result; -} - -int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) -{ - char *tail; - unsigned long val; - size_t len; - - *res = 0; - len = strlen(cp); - if (len == 0) - return -EINVAL; - - val = simple_strtoul(cp, &tail, base); - if (tail == cp) - return -EINVAL; - - if ((*tail == '\0') || - ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { - *res = val; - return 0; - } - - return -EINVAL; -} - -long simple_strtol(const char *cp, char **endp, unsigned int base) -{ - if (*cp == '-') - return -simple_strtoul(cp + 1, endp, base); - - return simple_strtoul(cp, endp, base); -} - -unsigned long ustrtoul(const char *cp, char **endp, unsigned int base) -{ - unsigned long result = simple_strtoul(cp, endp, base); - switch (**endp) { - case 'G': - result *= 1024; - /* fall through */ - case 'M': - result *= 1024; - /* fall through */ - case 'K': - case 'k': - result *= 1024; - if ((*endp)[1] == 'i') { - if ((*endp)[2] == 'B') - (*endp) += 3; - else - (*endp) += 2; - } - } - return result; -} - -unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base) -{ - unsigned long long result = simple_strtoull(cp, endp, base); - switch (**endp) { - case 'G': - result *= 1024; - /* fall through */ - case 'M': - result *= 1024; - /* fall through */ - case 'K': - case 'k': - result *= 1024; - if ((*endp)[1] == 'i') { - if ((*endp)[2] == 'B') - (*endp) += 3; - else - (*endp) += 2; - } - } - return result; -} - -unsigned long long simple_strtoull(const char *cp, char **endp, - unsigned int base) -{ - unsigned long long result = 0, value; - - if (*cp == '0') { - cp++; - if ((*cp == 'x') && isxdigit(cp[1])) { - base = 16; - cp++; - } - - if (!base) - base = 8; - } - - if (!base) - base = 10; - - while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0' - : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) { - result = result * base + value; - cp++; - } - - if (endp) - *endp = (char *) cp; - - return result; -} - -long trailing_strtoln(const char *str, const char *end) -{ - const char *p; - - if (!end) - end = str + strlen(str); - for (p = end - 1; p > str; p--) { - if (!isdigit(*p)) - return simple_strtoul(p + 1, NULL, 10); - } - - return -1; -} - -long trailing_strtol(const char *str) -{ - return trailing_strtoln(str, NULL); -} - /* we use this so that we can do without the ctype library */ #define is_digit(c) ((c) >= '0' && (c) <= '9') @@ -305,7 +147,6 @@ static noinline char *put_dec(char *buf, uint64_t num) #define SMALL 32 /* Must be 32 == 0x20 */ #define SPECIAL 64 /* 0x */ -#ifdef CONFIG_SYS_VSNPRINTF /* * Macro to add a new character to our output string, but only if it will * fit. The macro moves to the next character position in the output string. @@ -315,9 +156,6 @@ static noinline char *put_dec(char *buf, uint64_t num) *(str) = (ch); \ ++str; \ } while (0) -#else -#define ADDCH(str, ch) (*(str)++ = (ch)) -#endif static char *number(char *buf, char *end, u64 num, int base, int size, int precision, int type) @@ -438,17 +276,49 @@ static char *string(char *buf, char *end, char *s, int field_width, return buf; } -#ifdef CONFIG_CMD_NET -static const char hex_asc[] = "0123456789abcdef"; -#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] -#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] +/* U-Boot uses UTF-16 strings in the EFI context only. */ +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) +static char *string16(char *buf, char *end, u16 *s, int field_width, + int precision, int flags) +{ + const u16 *str = s ? s : L""; + ssize_t i, len = utf16_strnlen(str, precision); + + if (!(flags & LEFT)) + for (; len < field_width; --field_width) + ADDCH(buf, ' '); + for (i = 0; i < len && buf + utf16_utf8_strnlen(str, 1) <= end; ++i) { + s32 s = utf16_get(&str); + + if (s < 0) + s = '?'; + utf8_put(s, &buf); + } + for (; len < field_width; --field_width) + ADDCH(buf, ' '); + return buf; +} -static inline char *pack_hex_byte(char *buf, u8 byte) +#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT) +static char *device_path_string(char *buf, char *end, void *dp, int field_width, + int precision, int flags) { - *buf++ = hex_asc_hi(byte); - *buf++ = hex_asc_lo(byte); + u16 *str; + + /* If dp == NULL output the string '' */ + if (!dp) + return string16(buf, end, dp, field_width, precision, flags); + + str = efi_dp_str((struct efi_device_path *)dp); + if (!str) + return ERR_PTR(-ENOMEM); + + buf = string16(buf, end, str, field_width, precision, flags); + efi_free_pool(str); return buf; } +#endif +#endif static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, int precision, int flags) @@ -459,7 +329,7 @@ static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, int i; for (i = 0; i < 6; i++) { - p = pack_hex_byte(p, addr[i]); + p = hex_byte_pack(p, addr[i]); if (!(flags & SPECIAL) && i != 5) *p++ = ':'; } @@ -478,8 +348,8 @@ static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, int i; for (i = 0; i < 8; i++) { - p = pack_hex_byte(p, addr[2 * i]); - p = pack_hex_byte(p, addr[2 * i + 1]); + p = hex_byte_pack(p, addr[2 * i]); + p = hex_byte_pack(p, addr[2 * i + 1]); if (!(flags & SPECIAL) && i != 7) *p++ = ':'; } @@ -511,6 +381,44 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); } + +#ifdef CONFIG_LIB_UUID +/* + * This works (roughly) the same way as Linux's. + * + * %pUb: 01020304-0506-0708-090a-0b0c0d0e0f10 + * %pUB: 01020304-0506-0708-090A-0B0C0D0E0F10 + * %pUl: 04030201-0605-0807-090a-0b0c0d0e0f10 + * %pUL: 04030201-0605-0807-090A-0B0C0D0E0F10 + */ +static char *uuid_string(char *buf, char *end, u8 *addr, int field_width, + int precision, int flags, const char *fmt) +{ + char uuid[UUID_STR_LEN + 1]; + int str_format; + + switch (*(++fmt)) { + case 'L': + str_format = UUID_STR_FORMAT_GUID | UUID_STR_UPPER_CASE; + break; + case 'l': + str_format = UUID_STR_FORMAT_GUID; + break; + case 'B': + str_format = UUID_STR_FORMAT_STD | UUID_STR_UPPER_CASE; + break; + default: + str_format = UUID_STR_FORMAT_STD; + break; + } + + if (addr) + uuid_bin_to_str(addr, uuid, str_format); + else + strcpy(uuid, ""); + + return string(buf, end, uuid, field_width, precision, flags); +} #endif /* @@ -546,8 +454,13 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, flags); #endif -#ifdef CONFIG_CMD_NET switch (*fmt) { +/* Device paths only exist in the EFI context. */ +#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT) && !defined(API_BUILD) + case 'D': + return device_path_string(buf, end, ptr, field_width, + precision, flags); +#endif case 'a': flags |= SPECIAL | ZEROPAD; @@ -577,8 +490,14 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, precision, flags); flags &= ~SPECIAL; break; - } +#ifdef CONFIG_LIB_UUID + case 'U': + return uuid_string(buf, end, ptr, field_width, precision, + flags, fmt); #endif + default: + break; + } flags |= SMALL; if (field_width == -1) { field_width = 2*sizeof(void *); @@ -605,13 +524,11 @@ static int vsnprintf_internal(char *buf, size_t size, const char *fmt, /* 't' added for ptrdiff_t */ char *end = buf + size; -#ifdef CONFIG_SYS_VSNPRINTF /* Make sure end is always >= buf - do we want this in U-Boot? */ if (end < buf) { end = ((void *)-1); size = end - buf; } -#endif str = buf; for (; *fmt ; ++fmt) { @@ -698,14 +615,25 @@ repeat: continue; case 's': - str = string(str, end, va_arg(args, char *), - field_width, precision, flags); +/* U-Boot uses UTF-16 strings in the EFI context only. */ +#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) + if (qualifier == 'l') { + str = string16(str, end, va_arg(args, u16 *), + field_width, precision, flags); + } else +#endif + { + str = string(str, end, va_arg(args, char *), + field_width, precision, flags); + } continue; case 'p': str = pointer(fmt + 1, str, end, va_arg(args, void *), field_width, precision, flags); + if (IS_ERR(str)) + return PTR_ERR(str); /* Skip all alphanumeric pointer suffixes */ while (isalnum(fmt[1])) fmt++; @@ -773,21 +701,16 @@ repeat: flags); } -#ifdef CONFIG_SYS_VSNPRINTF if (size > 0) { ADDCH(str, '\0'); if (str > end) end[-1] = '\0'; --str; } -#else - *str = '\0'; -#endif /* the trailing null byte doesn't count towards the total */ return str - buf; } -#ifdef CONFIG_SYS_VSNPRINTF int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { @@ -830,7 +753,6 @@ int scnprintf(char *buf, size_t size, const char *fmt, ...) return i; } -#endif /* CONFIG_SYS_VSNPRINT */ /** * Format a string and place it in a buffer (va_list version) @@ -861,43 +783,49 @@ int sprintf(char *buf, const char *fmt, ...) return i; } -static void panic_finish(void) __attribute__ ((noreturn)); - -static void panic_finish(void) -{ - putc('\n'); -#if defined(CONFIG_PANIC_HANG) - hang(); -#else - udelay(100000); /* allow messages to go out */ - do_reset(NULL, 0, 0, NULL); -#endif - while (1) - ; -} - -void panic_str(const char *str) -{ - puts(str); - panic_finish(); -} - -void panic(const char *fmt, ...) +#if CONFIG_IS_ENABLED(PRINTF) +int printf(const char *fmt, ...) { va_list args; + uint i; + char printbuffer[CONFIG_SYS_PBSIZE]; + va_start(args, fmt); - vprintf(fmt, args); + + /* + * For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); va_end(args); - panic_finish(); + + /* Handle error */ + if (i <= 0) + return i; + /* Print the string */ + puts(printbuffer); + return i; } -void __assert_fail(const char *assertion, const char *file, unsigned line, - const char *function) +int vprintf(const char *fmt, va_list args) { - /* This will not return */ - panic("%s:%u: %s: Assertion `%s' failed.", file, line, function, - assertion); + uint i; + char printbuffer[CONFIG_SYS_PBSIZE]; + + /* + * For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); + + /* Handle error */ + if (i <= 0) + return i; + /* Print the string */ + puts(printbuffer); + return i; } +#endif char *simple_itoa(ulong i) { @@ -944,3 +872,19 @@ bool str2long(const char *p, ulong *num) *num = simple_strtoul(p, &endptr, 16); return *p != '\0' && *endptr == '\0'; } + +char *strmhz(char *buf, unsigned long hz) +{ + long l, n; + long m; + + n = DIV_ROUND_CLOSEST(hz, 1000) / 1000L; + l = sprintf(buf, "%ld", n); + + hz -= n * 1000000L; + m = DIV_ROUND_CLOSEST(hz, 1000L); + if (m != 0) + sprintf(buf + l, ".%03ld", m); + + return buf; +}