]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - lib/vsprintf.c
Merge branch 'master' of git://git.denx.de/u-boot-video
[people/ms/u-boot.git] / lib / vsprintf.c
index 533a96b85e3629a765ba807a594f8509fab9f68a..874a2951f7053ef395cfee8ffe78464eee855039 100644 (file)
 #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))
 
-/* some reluctance to put this into a new limits.h, so it is here */
-#define INT_MAX                ((int)(~0U>>1))
-
-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]
-
-static inline char *pack_hex_byte(char *buf, u8 byte)
-{
-       *buf++ = hex_asc_hi(byte);
-       *buf++ = hex_asc_lo(byte);
-       return buf;
-}
-
-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;
-}
-
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)    ((c) >= '0' && (c) <= '9')
 
@@ -281,7 +122,7 @@ static char *put_dec_full(char *buf, unsigned q)
        return buf;
 }
 /* No inlining helps gcc to use registers better */
-static noinline char *put_dec(char *buf, u64 num)
+static noinline char *put_dec(char *buf, uint64_t num)
 {
        while (1) {
                unsigned rem;
@@ -300,7 +141,6 @@ static noinline char *put_dec(char *buf, u64 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.
@@ -310,9 +150,6 @@ static noinline char *put_dec(char *buf, u64 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)
@@ -434,6 +271,17 @@ static char *string(char *buf, char *end, char *s, int field_width,
 }
 
 #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]
+
+static inline char *pack_hex_byte(char *buf, u8 byte)
+{
+       *buf++ = hex_asc_hi(byte);
+       *buf++ = hex_asc_lo(byte);
+       return buf;
+}
+
 static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
                                int precision, int flags)
 {
@@ -518,6 +366,8 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
 static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                int field_width, int precision, int flags)
 {
+       u64 num = (uintptr_t)ptr;
+
        /*
         * Being a boot loader, we explicitly allow pointers to
         * (physical) address null.
@@ -530,6 +380,17 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 
 #ifdef CONFIG_CMD_NET
        switch (*fmt) {
+       case 'a':
+               flags |= SPECIAL | ZEROPAD;
+
+               switch (fmt[1]) {
+               case 'p':
+               default:
+                       field_width = sizeof(phys_addr_t) * 2 + 2;
+                       num = *(phys_addr_t *)ptr;
+                       break;
+               }
+               break;
        case 'm':
                flags |= SPECIAL;
                /* Fallthrough */
@@ -555,8 +416,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                field_width = 2*sizeof(void *);
                flags |= ZEROPAD;
        }
-       return number(buf, end, (unsigned long)ptr, 16, field_width,
-                     precision, flags);
+       return number(buf, end, num, 16, field_width, precision, flags);
 }
 
 static int vsnprintf_internal(char *buf, size_t size, const char *fmt,
@@ -577,13 +437,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) {
@@ -745,20 +603,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)
 {
@@ -801,7 +655,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)
@@ -832,23 +685,43 @@ int sprintf(char *buf, const char *fmt, ...)
        return i;
 }
 
-void panic(const char *fmt, ...)
+int printf(const char *fmt, ...)
 {
        va_list args;
+       uint i;
+       char printbuffer[CONFIG_SYS_PBSIZE];
+
        va_start(args, fmt);
-       vprintf(fmt, args);
-       putc('\n');
+
+       /*
+        * 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);
-#if defined(CONFIG_PANIC_HANG)
-       hang();
-#else
-       udelay(100000); /* allow messages to go out */
-       do_reset(NULL, 0, 0, NULL);
-#endif
-       while (1)
-               ;
+
+       /* Print the string */
+       puts(printbuffer);
+       return i;
+}
+
+int vprintf(const char *fmt, va_list args)
+{
+       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);
+
+       /* Print the string */
+       puts(printbuffer);
+       return i;
 }
 
+
 void __assert_fail(const char *assertion, const char *file, unsigned line,
                   const char *function)
 {
@@ -870,3 +743,35 @@ char *simple_itoa(ulong i)
        } while (i > 0);
        return p + 1;
 }
+
+/* We don't seem to have %'d in U-Boot */
+void print_grouped_ull(unsigned long long int_val, int digits)
+{
+       char str[21], *s;
+       int grab = 3;
+
+       digits = (digits + 2) / 3;
+       sprintf(str, "%*llu", digits * 3, int_val);
+       for (s = str; *s; s += grab) {
+               if (s != str)
+                       putc(s[-1] != ' ' ? ',' : ' ');
+               printf("%.*s", grab, s);
+               grab = 3;
+       }
+}
+
+bool str2off(const char *p, loff_t *num)
+{
+       char *endptr;
+
+       *num = simple_strtoull(p, &endptr, 16);
+       return *p != '\0' && *endptr == '\0';
+}
+
+bool str2long(const char *p, ulong *num)
+{
+       char *endptr;
+
+       *num = simple_strtoul(p, &endptr, 16);
+       return *p != '\0' && *endptr == '\0';
+}