* 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. */
* from hush: simple_itoa() was lifted from boa-0.93.15
*/
+#include <common.h>
+#include <charset.h>
+#include <efi_loader.h>
+#include <div64.h>
+#include <hexdump.h>
#include <stdarg.h>
+#include <vsprintf.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
#include <linux/types.h>
#include <linux/string.h>
-#include <linux/ctype.h>
-#include <errno.h>
-#include <common.h>
-#if !defined(CONFIG_PANIC_HANG)
-#include <command.h>
-#endif
-
-#include <div64.h>
#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')
#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.
*(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)
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"<NULL>";
+ 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);
-static inline char *pack_hex_byte(char *buf, u8 byte)
+ if (s < 0)
+ s = '?';
+ utf8_put(s, &buf);
+ }
+ for (; len < field_width; --field_width)
+ ADDCH(buf, ' ');
+ return buf;
+}
+
+#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 '<NULL>' */
+ 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)
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++ = ':';
}
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++ = ':';
}
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, "<NULL>");
+
+ return string(buf, end, uuid, field_width, precision, flags);
+}
#endif
/*
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;
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 *);
/* '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) {
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++;
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)
{
return i;
}
-#endif /* CONFIG_SYS_VSNPRINT */
/**
* Format a string and place it in a buffer (va_list version)
return i;
}
+#if CONFIG_IS_ENABLED(PRINTF)
int printf(const char *fmt, ...)
{
va_list args;
i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
va_end(args);
+ /* Handle error */
+ if (i <= 0)
+ return i;
/* Print the string */
puts(printbuffer);
return i;
*/
i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
+ /* 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)
-{
- /* This will not return */
- panic("%s:%u: %s: Assertion `%s' failed.", file, line, function,
- assertion);
-}
+#endif
char *simple_itoa(ulong i)
{
*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;
+}