178acc472SPeter Tyser /* 278acc472SPeter Tyser * linux/lib/vsprintf.c 378acc472SPeter Tyser * 478acc472SPeter Tyser * Copyright (C) 1991, 1992 Linus Torvalds 578acc472SPeter Tyser */ 678acc472SPeter Tyser 778acc472SPeter Tyser /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 878acc472SPeter Tyser /* 978acc472SPeter Tyser * Wirzenius wrote this portably, Torvalds fucked it up :-) 103cce8a54SSimon Glass * 113cce8a54SSimon Glass * from hush: simple_itoa() was lifted from boa-0.93.15 1278acc472SPeter Tyser */ 1378acc472SPeter Tyser 1478acc472SPeter Tyser #include <stdarg.h> 1578acc472SPeter Tyser #include <linux/types.h> 1678acc472SPeter Tyser #include <linux/string.h> 1778acc472SPeter Tyser #include <linux/ctype.h> 18a7fd0d9fSHeiko Schocher #include <errno.h> 1978acc472SPeter Tyser 2078acc472SPeter Tyser #include <common.h> 2178acc472SPeter Tyser #if !defined(CONFIG_PANIC_HANG) 2278acc472SPeter Tyser #include <command.h> 2378acc472SPeter Tyser #endif 2478acc472SPeter Tyser 2578acc472SPeter Tyser #include <div64.h> 2678acc472SPeter Tyser #define noinline __attribute__((noinline)) 2778acc472SPeter Tyser 288acdae68SDaniel Schwierzeck unsigned long simple_strtoul(const char *cp, char **endp, 298acdae68SDaniel Schwierzeck unsigned int base) 3078acc472SPeter Tyser { 318acdae68SDaniel Schwierzeck unsigned long result = 0; 328acdae68SDaniel Schwierzeck unsigned long value; 3378acc472SPeter Tyser 3478acc472SPeter Tyser if (*cp == '0') { 3578acc472SPeter Tyser cp++; 3678acc472SPeter Tyser if ((*cp == 'x') && isxdigit(cp[1])) { 3778acc472SPeter Tyser base = 16; 3878acc472SPeter Tyser cp++; 3978acc472SPeter Tyser } 408acdae68SDaniel Schwierzeck 418acdae68SDaniel Schwierzeck if (!base) 4278acc472SPeter Tyser base = 8; 4378acc472SPeter Tyser } 448acdae68SDaniel Schwierzeck 458acdae68SDaniel Schwierzeck if (!base) 4678acc472SPeter Tyser base = 10; 478acdae68SDaniel Schwierzeck 4878acc472SPeter Tyser while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) 4978acc472SPeter Tyser ? toupper(*cp) : *cp)-'A'+10) < base) { 5078acc472SPeter Tyser result = result*base + value; 5178acc472SPeter Tyser cp++; 5278acc472SPeter Tyser } 538acdae68SDaniel Schwierzeck 5478acc472SPeter Tyser if (endp) 5578acc472SPeter Tyser *endp = (char *)cp; 568acdae68SDaniel Schwierzeck 5778acc472SPeter Tyser return result; 5878acc472SPeter Tyser } 5978acc472SPeter Tyser 60a7fd0d9fSHeiko Schocher int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) 61a7fd0d9fSHeiko Schocher { 62a7fd0d9fSHeiko Schocher char *tail; 63a7fd0d9fSHeiko Schocher unsigned long val; 64a7fd0d9fSHeiko Schocher size_t len; 65a7fd0d9fSHeiko Schocher 66a7fd0d9fSHeiko Schocher *res = 0; 67a7fd0d9fSHeiko Schocher len = strlen(cp); 68a7fd0d9fSHeiko Schocher if (len == 0) 69a7fd0d9fSHeiko Schocher return -EINVAL; 70a7fd0d9fSHeiko Schocher 71a7fd0d9fSHeiko Schocher val = simple_strtoul(cp, &tail, base); 72a7fd0d9fSHeiko Schocher if (tail == cp) 73a7fd0d9fSHeiko Schocher return -EINVAL; 74a7fd0d9fSHeiko Schocher 75a7fd0d9fSHeiko Schocher if ((*tail == '\0') || 76a7fd0d9fSHeiko Schocher ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { 77a7fd0d9fSHeiko Schocher *res = val; 78a7fd0d9fSHeiko Schocher return 0; 79a7fd0d9fSHeiko Schocher } 80a7fd0d9fSHeiko Schocher 81a7fd0d9fSHeiko Schocher return -EINVAL; 82a7fd0d9fSHeiko Schocher } 83a7fd0d9fSHeiko Schocher 8478acc472SPeter Tyser long simple_strtol(const char *cp, char **endp, unsigned int base) 8578acc472SPeter Tyser { 8678acc472SPeter Tyser if (*cp == '-') 8778acc472SPeter Tyser return -simple_strtoul(cp + 1, endp, base); 888acdae68SDaniel Schwierzeck 8978acc472SPeter Tyser return simple_strtoul(cp, endp, base); 9078acc472SPeter Tyser } 9178acc472SPeter Tyser 923ec44111SLukasz Majewski unsigned long ustrtoul(const char *cp, char **endp, unsigned int base) 9378acc472SPeter Tyser { 9478acc472SPeter Tyser unsigned long result = simple_strtoul(cp, endp, base); 9578acc472SPeter Tyser switch (**endp) { 9678acc472SPeter Tyser case 'G': 9778acc472SPeter Tyser result *= 1024; 9878acc472SPeter Tyser /* fall through */ 9978acc472SPeter Tyser case 'M': 10078acc472SPeter Tyser result *= 1024; 10178acc472SPeter Tyser /* fall through */ 10278acc472SPeter Tyser case 'K': 10378acc472SPeter Tyser case 'k': 10478acc472SPeter Tyser result *= 1024; 10578acc472SPeter Tyser if ((*endp)[1] == 'i') { 10678acc472SPeter Tyser if ((*endp)[2] == 'B') 10778acc472SPeter Tyser (*endp) += 3; 10878acc472SPeter Tyser else 10978acc472SPeter Tyser (*endp) += 2; 11078acc472SPeter Tyser } 11178acc472SPeter Tyser } 11278acc472SPeter Tyser return result; 11378acc472SPeter Tyser } 11478acc472SPeter Tyser 1157df54d31SPiotr Wilczek unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base) 1167df54d31SPiotr Wilczek { 1177df54d31SPiotr Wilczek unsigned long long result = simple_strtoull(cp, endp, base); 1187df54d31SPiotr Wilczek switch (**endp) { 1197df54d31SPiotr Wilczek case 'G': 1207df54d31SPiotr Wilczek result *= 1024; 1217df54d31SPiotr Wilczek /* fall through */ 1227df54d31SPiotr Wilczek case 'M': 1237df54d31SPiotr Wilczek result *= 1024; 1247df54d31SPiotr Wilczek /* fall through */ 1257df54d31SPiotr Wilczek case 'K': 1267df54d31SPiotr Wilczek case 'k': 1277df54d31SPiotr Wilczek result *= 1024; 1287df54d31SPiotr Wilczek if ((*endp)[1] == 'i') { 1297df54d31SPiotr Wilczek if ((*endp)[2] == 'B') 1307df54d31SPiotr Wilczek (*endp) += 3; 1317df54d31SPiotr Wilczek else 1327df54d31SPiotr Wilczek (*endp) += 2; 1337df54d31SPiotr Wilczek } 1347df54d31SPiotr Wilczek } 1357df54d31SPiotr Wilczek return result; 1367df54d31SPiotr Wilczek } 1377df54d31SPiotr Wilczek 1388acdae68SDaniel Schwierzeck unsigned long long simple_strtoull(const char *cp, char **endp, 1398acdae68SDaniel Schwierzeck unsigned int base) 14078acc472SPeter Tyser { 14178acc472SPeter Tyser unsigned long long result = 0, value; 14278acc472SPeter Tyser 14378acc472SPeter Tyser if (*cp == '0') { 14478acc472SPeter Tyser cp++; 14578acc472SPeter Tyser if ((*cp == 'x') && isxdigit(cp[1])) { 14678acc472SPeter Tyser base = 16; 14778acc472SPeter Tyser cp++; 14878acc472SPeter Tyser } 1498acdae68SDaniel Schwierzeck 1508acdae68SDaniel Schwierzeck if (!base) 15178acc472SPeter Tyser base = 8; 15278acc472SPeter Tyser } 1538acdae68SDaniel Schwierzeck 1548acdae68SDaniel Schwierzeck if (!base) 15578acc472SPeter Tyser base = 10; 1568acdae68SDaniel Schwierzeck 1578acdae68SDaniel Schwierzeck while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0' 15878acc472SPeter Tyser : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) { 15978acc472SPeter Tyser result = result * base + value; 16078acc472SPeter Tyser cp++; 16178acc472SPeter Tyser } 1628acdae68SDaniel Schwierzeck 16378acc472SPeter Tyser if (endp) 16478acc472SPeter Tyser *endp = (char *) cp; 1658acdae68SDaniel Schwierzeck 16678acc472SPeter Tyser return result; 16778acc472SPeter Tyser } 16878acc472SPeter Tyser 169*c4af6732SSimon Glass long trailing_strtoln(const char *str, const char *end) 170*c4af6732SSimon Glass { 171*c4af6732SSimon Glass const char *p; 172*c4af6732SSimon Glass 173*c4af6732SSimon Glass if (!end) 174*c4af6732SSimon Glass end = str + strlen(str); 175*c4af6732SSimon Glass for (p = end - 1; p > str; p--) { 176*c4af6732SSimon Glass if (!isdigit(*p)) 177*c4af6732SSimon Glass return simple_strtoul(p + 1, NULL, 10); 178*c4af6732SSimon Glass } 179*c4af6732SSimon Glass 180*c4af6732SSimon Glass return -1; 181*c4af6732SSimon Glass } 182*c4af6732SSimon Glass 183*c4af6732SSimon Glass long trailing_strtol(const char *str) 184*c4af6732SSimon Glass { 185*c4af6732SSimon Glass return trailing_strtoln(str, NULL); 186*c4af6732SSimon Glass } 187*c4af6732SSimon Glass 18878acc472SPeter Tyser /* we use this so that we can do without the ctype library */ 18978acc472SPeter Tyser #define is_digit(c) ((c) >= '0' && (c) <= '9') 19078acc472SPeter Tyser 19178acc472SPeter Tyser static int skip_atoi(const char **s) 19278acc472SPeter Tyser { 19378acc472SPeter Tyser int i = 0; 19478acc472SPeter Tyser 19578acc472SPeter Tyser while (is_digit(**s)) 19678acc472SPeter Tyser i = i * 10 + *((*s)++) - '0'; 1978acdae68SDaniel Schwierzeck 19878acc472SPeter Tyser return i; 19978acc472SPeter Tyser } 20078acc472SPeter Tyser 20178acc472SPeter Tyser /* Decimal conversion is by far the most typical, and is used 20278acc472SPeter Tyser * for /proc and /sys data. This directly impacts e.g. top performance 20378acc472SPeter Tyser * with many processes running. We optimize it for speed 20478acc472SPeter Tyser * using code from 20578acc472SPeter Tyser * http://www.cs.uiowa.edu/~jones/bcd/decimal.html 20678acc472SPeter Tyser * (with permission from the author, Douglas W. Jones). */ 20778acc472SPeter Tyser 20878acc472SPeter Tyser /* Formats correctly any integer in [0,99999]. 20978acc472SPeter Tyser * Outputs from one to five digits depending on input. 21078acc472SPeter Tyser * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ 21178acc472SPeter Tyser static char *put_dec_trunc(char *buf, unsigned q) 21278acc472SPeter Tyser { 21378acc472SPeter Tyser unsigned d3, d2, d1, d0; 21478acc472SPeter Tyser d1 = (q>>4) & 0xf; 21578acc472SPeter Tyser d2 = (q>>8) & 0xf; 21678acc472SPeter Tyser d3 = (q>>12); 21778acc472SPeter Tyser 21878acc472SPeter Tyser d0 = 6*(d3 + d2 + d1) + (q & 0xf); 21978acc472SPeter Tyser q = (d0 * 0xcd) >> 11; 22078acc472SPeter Tyser d0 = d0 - 10*q; 22178acc472SPeter Tyser *buf++ = d0 + '0'; /* least significant digit */ 22278acc472SPeter Tyser d1 = q + 9*d3 + 5*d2 + d1; 22378acc472SPeter Tyser if (d1 != 0) { 22478acc472SPeter Tyser q = (d1 * 0xcd) >> 11; 22578acc472SPeter Tyser d1 = d1 - 10*q; 22678acc472SPeter Tyser *buf++ = d1 + '0'; /* next digit */ 22778acc472SPeter Tyser 22878acc472SPeter Tyser d2 = q + 2*d2; 22978acc472SPeter Tyser if ((d2 != 0) || (d3 != 0)) { 23078acc472SPeter Tyser q = (d2 * 0xd) >> 7; 23178acc472SPeter Tyser d2 = d2 - 10*q; 23278acc472SPeter Tyser *buf++ = d2 + '0'; /* next digit */ 23378acc472SPeter Tyser 23478acc472SPeter Tyser d3 = q + 4*d3; 23578acc472SPeter Tyser if (d3 != 0) { 23678acc472SPeter Tyser q = (d3 * 0xcd) >> 11; 23778acc472SPeter Tyser d3 = d3 - 10*q; 23878acc472SPeter Tyser *buf++ = d3 + '0'; /* next digit */ 23978acc472SPeter Tyser if (q != 0) 24078acc472SPeter Tyser *buf++ = q + '0'; /* most sign. digit */ 24178acc472SPeter Tyser } 24278acc472SPeter Tyser } 24378acc472SPeter Tyser } 24478acc472SPeter Tyser return buf; 24578acc472SPeter Tyser } 24678acc472SPeter Tyser /* Same with if's removed. Always emits five digits */ 24778acc472SPeter Tyser static char *put_dec_full(char *buf, unsigned q) 24878acc472SPeter Tyser { 24978acc472SPeter Tyser /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ 25078acc472SPeter Tyser /* but anyway, gcc produces better code with full-sized ints */ 25178acc472SPeter Tyser unsigned d3, d2, d1, d0; 25278acc472SPeter Tyser d1 = (q>>4) & 0xf; 25378acc472SPeter Tyser d2 = (q>>8) & 0xf; 25478acc472SPeter Tyser d3 = (q>>12); 25578acc472SPeter Tyser 25678acc472SPeter Tyser /* 25778acc472SPeter Tyser * Possible ways to approx. divide by 10 25878acc472SPeter Tyser * gcc -O2 replaces multiply with shifts and adds 25978acc472SPeter Tyser * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) 26078acc472SPeter Tyser * (x * 0x67) >> 10: 1100111 26178acc472SPeter Tyser * (x * 0x34) >> 9: 110100 - same 26278acc472SPeter Tyser * (x * 0x1a) >> 8: 11010 - same 26378acc472SPeter Tyser * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) 26478acc472SPeter Tyser */ 26578acc472SPeter Tyser 26678acc472SPeter Tyser d0 = 6*(d3 + d2 + d1) + (q & 0xf); 26778acc472SPeter Tyser q = (d0 * 0xcd) >> 11; 26878acc472SPeter Tyser d0 = d0 - 10*q; 26978acc472SPeter Tyser *buf++ = d0 + '0'; 27078acc472SPeter Tyser d1 = q + 9*d3 + 5*d2 + d1; 27178acc472SPeter Tyser q = (d1 * 0xcd) >> 11; 27278acc472SPeter Tyser d1 = d1 - 10*q; 27378acc472SPeter Tyser *buf++ = d1 + '0'; 27478acc472SPeter Tyser 27578acc472SPeter Tyser d2 = q + 2*d2; 27678acc472SPeter Tyser q = (d2 * 0xd) >> 7; 27778acc472SPeter Tyser d2 = d2 - 10*q; 27878acc472SPeter Tyser *buf++ = d2 + '0'; 27978acc472SPeter Tyser 28078acc472SPeter Tyser d3 = q + 4*d3; 28178acc472SPeter Tyser q = (d3 * 0xcd) >> 11; /* - shorter code */ 28278acc472SPeter Tyser /* q = (d3 * 0x67) >> 10; - would also work */ 28378acc472SPeter Tyser d3 = d3 - 10*q; 28478acc472SPeter Tyser *buf++ = d3 + '0'; 28578acc472SPeter Tyser *buf++ = q + '0'; 28678acc472SPeter Tyser return buf; 28778acc472SPeter Tyser } 28878acc472SPeter Tyser /* No inlining helps gcc to use registers better */ 2896bf67259SSimon Glass static noinline char *put_dec(char *buf, uint64_t num) 29078acc472SPeter Tyser { 29178acc472SPeter Tyser while (1) { 29278acc472SPeter Tyser unsigned rem; 29378acc472SPeter Tyser if (num < 100000) 29478acc472SPeter Tyser return put_dec_trunc(buf, num); 29578acc472SPeter Tyser rem = do_div(num, 100000); 29678acc472SPeter Tyser buf = put_dec_full(buf, rem); 29778acc472SPeter Tyser } 29878acc472SPeter Tyser } 29978acc472SPeter Tyser 30078acc472SPeter Tyser #define ZEROPAD 1 /* pad with zero */ 30178acc472SPeter Tyser #define SIGN 2 /* unsigned/signed long */ 30278acc472SPeter Tyser #define PLUS 4 /* show plus */ 30378acc472SPeter Tyser #define SPACE 8 /* space if plus */ 30478acc472SPeter Tyser #define LEFT 16 /* left justified */ 30578acc472SPeter Tyser #define SMALL 32 /* Must be 32 == 0x20 */ 30678acc472SPeter Tyser #define SPECIAL 64 /* 0x */ 30778acc472SPeter Tyser 308046a37bdSSonny Rao #ifdef CONFIG_SYS_VSNPRINTF 309046a37bdSSonny Rao /* 310046a37bdSSonny Rao * Macro to add a new character to our output string, but only if it will 311046a37bdSSonny Rao * fit. The macro moves to the next character position in the output string. 312046a37bdSSonny Rao */ 313046a37bdSSonny Rao #define ADDCH(str, ch) do { \ 314046a37bdSSonny Rao if ((str) < end) \ 315046a37bdSSonny Rao *(str) = (ch); \ 316046a37bdSSonny Rao ++str; \ 317046a37bdSSonny Rao } while (0) 318046a37bdSSonny Rao #else 319046a37bdSSonny Rao #define ADDCH(str, ch) (*(str)++ = (ch)) 320046a37bdSSonny Rao #endif 321046a37bdSSonny Rao 3227b64f66cSDaniel Schwierzeck static char *number(char *buf, char *end, u64 num, 323046a37bdSSonny Rao int base, int size, int precision, int type) 32478acc472SPeter Tyser { 32578acc472SPeter Tyser /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 3268acdae68SDaniel Schwierzeck static const char digits[16] = "0123456789ABCDEF"; 32778acc472SPeter Tyser 32878acc472SPeter Tyser char tmp[66]; 32978acc472SPeter Tyser char sign; 33078acc472SPeter Tyser char locase; 33178acc472SPeter Tyser int need_pfx = ((type & SPECIAL) && base != 10); 33278acc472SPeter Tyser int i; 33378acc472SPeter Tyser 33478acc472SPeter Tyser /* locase = 0 or 0x20. ORing digits or letters with 'locase' 33578acc472SPeter Tyser * produces same digits or (maybe lowercased) letters */ 33678acc472SPeter Tyser locase = (type & SMALL); 33778acc472SPeter Tyser if (type & LEFT) 33878acc472SPeter Tyser type &= ~ZEROPAD; 33978acc472SPeter Tyser sign = 0; 34078acc472SPeter Tyser if (type & SIGN) { 3417b64f66cSDaniel Schwierzeck if ((s64) num < 0) { 34278acc472SPeter Tyser sign = '-'; 3437b64f66cSDaniel Schwierzeck num = -(s64) num; 34478acc472SPeter Tyser size--; 34578acc472SPeter Tyser } else if (type & PLUS) { 34678acc472SPeter Tyser sign = '+'; 34778acc472SPeter Tyser size--; 34878acc472SPeter Tyser } else if (type & SPACE) { 34978acc472SPeter Tyser sign = ' '; 35078acc472SPeter Tyser size--; 35178acc472SPeter Tyser } 35278acc472SPeter Tyser } 35378acc472SPeter Tyser if (need_pfx) { 35478acc472SPeter Tyser size--; 35578acc472SPeter Tyser if (base == 16) 35678acc472SPeter Tyser size--; 35778acc472SPeter Tyser } 35878acc472SPeter Tyser 35978acc472SPeter Tyser /* generate full string in tmp[], in reverse order */ 36078acc472SPeter Tyser i = 0; 36178acc472SPeter Tyser if (num == 0) 36278acc472SPeter Tyser tmp[i++] = '0'; 36378acc472SPeter Tyser /* Generic code, for any base: 36478acc472SPeter Tyser else do { 36578acc472SPeter Tyser tmp[i++] = (digits[do_div(num,base)] | locase); 36678acc472SPeter Tyser } while (num != 0); 36778acc472SPeter Tyser */ 36878acc472SPeter Tyser else if (base != 10) { /* 8 or 16 */ 36978acc472SPeter Tyser int mask = base - 1; 37078acc472SPeter Tyser int shift = 3; 3718acdae68SDaniel Schwierzeck 3728acdae68SDaniel Schwierzeck if (base == 16) 3738acdae68SDaniel Schwierzeck shift = 4; 3748acdae68SDaniel Schwierzeck 37578acc472SPeter Tyser do { 3768acdae68SDaniel Schwierzeck tmp[i++] = (digits[((unsigned char)num) & mask] 3778acdae68SDaniel Schwierzeck | locase); 37878acc472SPeter Tyser num >>= shift; 37978acc472SPeter Tyser } while (num); 38078acc472SPeter Tyser } else { /* base 10 */ 38178acc472SPeter Tyser i = put_dec(tmp, num) - tmp; 38278acc472SPeter Tyser } 38378acc472SPeter Tyser 38478acc472SPeter Tyser /* printing 100 using %2d gives "100", not "00" */ 38578acc472SPeter Tyser if (i > precision) 38678acc472SPeter Tyser precision = i; 38778acc472SPeter Tyser /* leading space padding */ 38878acc472SPeter Tyser size -= precision; 389046a37bdSSonny Rao if (!(type & (ZEROPAD + LEFT))) { 39078acc472SPeter Tyser while (--size >= 0) 391046a37bdSSonny Rao ADDCH(buf, ' '); 392046a37bdSSonny Rao } 39378acc472SPeter Tyser /* sign */ 39478acc472SPeter Tyser if (sign) 395046a37bdSSonny Rao ADDCH(buf, sign); 39678acc472SPeter Tyser /* "0x" / "0" prefix */ 39778acc472SPeter Tyser if (need_pfx) { 398046a37bdSSonny Rao ADDCH(buf, '0'); 39978acc472SPeter Tyser if (base == 16) 400046a37bdSSonny Rao ADDCH(buf, 'X' | locase); 40178acc472SPeter Tyser } 40278acc472SPeter Tyser /* zero or space padding */ 40378acc472SPeter Tyser if (!(type & LEFT)) { 40478acc472SPeter Tyser char c = (type & ZEROPAD) ? '0' : ' '; 405046a37bdSSonny Rao 40678acc472SPeter Tyser while (--size >= 0) 407046a37bdSSonny Rao ADDCH(buf, c); 40878acc472SPeter Tyser } 40978acc472SPeter Tyser /* hmm even more zero padding? */ 41078acc472SPeter Tyser while (i <= --precision) 411046a37bdSSonny Rao ADDCH(buf, '0'); 41278acc472SPeter Tyser /* actual digits of result */ 41378acc472SPeter Tyser while (--i >= 0) 414046a37bdSSonny Rao ADDCH(buf, tmp[i]); 41578acc472SPeter Tyser /* trailing space padding */ 41678acc472SPeter Tyser while (--size >= 0) 417046a37bdSSonny Rao ADDCH(buf, ' '); 41878acc472SPeter Tyser return buf; 41978acc472SPeter Tyser } 42078acc472SPeter Tyser 421046a37bdSSonny Rao static char *string(char *buf, char *end, char *s, int field_width, 422046a37bdSSonny Rao int precision, int flags) 42378acc472SPeter Tyser { 42478acc472SPeter Tyser int len, i; 42578acc472SPeter Tyser 4260eb25768SKim Phillips if (s == NULL) 42778acc472SPeter Tyser s = "<NULL>"; 42878acc472SPeter Tyser 42978acc472SPeter Tyser len = strnlen(s, precision); 43078acc472SPeter Tyser 43178acc472SPeter Tyser if (!(flags & LEFT)) 43278acc472SPeter Tyser while (len < field_width--) 433046a37bdSSonny Rao ADDCH(buf, ' '); 43478acc472SPeter Tyser for (i = 0; i < len; ++i) 435046a37bdSSonny Rao ADDCH(buf, *s++); 43678acc472SPeter Tyser while (len < field_width--) 437046a37bdSSonny Rao ADDCH(buf, ' '); 43878acc472SPeter Tyser return buf; 43978acc472SPeter Tyser } 44078acc472SPeter Tyser 44178acc472SPeter Tyser #ifdef CONFIG_CMD_NET 442d7b2d9dfSJeroen Hofstee static const char hex_asc[] = "0123456789abcdef"; 443d7b2d9dfSJeroen Hofstee #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] 444d7b2d9dfSJeroen Hofstee #define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] 445d7b2d9dfSJeroen Hofstee 446d7b2d9dfSJeroen Hofstee static inline char *pack_hex_byte(char *buf, u8 byte) 447d7b2d9dfSJeroen Hofstee { 448d7b2d9dfSJeroen Hofstee *buf++ = hex_asc_hi(byte); 449d7b2d9dfSJeroen Hofstee *buf++ = hex_asc_lo(byte); 450d7b2d9dfSJeroen Hofstee return buf; 451d7b2d9dfSJeroen Hofstee } 452d7b2d9dfSJeroen Hofstee 453046a37bdSSonny Rao static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, 45478acc472SPeter Tyser int precision, int flags) 45578acc472SPeter Tyser { 4568acdae68SDaniel Schwierzeck /* (6 * 2 hex digits), 5 colons and trailing zero */ 4578acdae68SDaniel Schwierzeck char mac_addr[6 * 3]; 45878acc472SPeter Tyser char *p = mac_addr; 45978acc472SPeter Tyser int i; 46078acc472SPeter Tyser 46178acc472SPeter Tyser for (i = 0; i < 6; i++) { 46278acc472SPeter Tyser p = pack_hex_byte(p, addr[i]); 46378acc472SPeter Tyser if (!(flags & SPECIAL) && i != 5) 46478acc472SPeter Tyser *p++ = ':'; 46578acc472SPeter Tyser } 46678acc472SPeter Tyser *p = '\0'; 46778acc472SPeter Tyser 468046a37bdSSonny Rao return string(buf, end, mac_addr, field_width, precision, 469046a37bdSSonny Rao flags & ~SPECIAL); 47078acc472SPeter Tyser } 47178acc472SPeter Tyser 472046a37bdSSonny Rao static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, 47378acc472SPeter Tyser int precision, int flags) 47478acc472SPeter Tyser { 4758acdae68SDaniel Schwierzeck /* (8 * 4 hex digits), 7 colons and trailing zero */ 4768acdae68SDaniel Schwierzeck char ip6_addr[8 * 5]; 47778acc472SPeter Tyser char *p = ip6_addr; 47878acc472SPeter Tyser int i; 47978acc472SPeter Tyser 48078acc472SPeter Tyser for (i = 0; i < 8; i++) { 48178acc472SPeter Tyser p = pack_hex_byte(p, addr[2 * i]); 48278acc472SPeter Tyser p = pack_hex_byte(p, addr[2 * i + 1]); 48378acc472SPeter Tyser if (!(flags & SPECIAL) && i != 7) 48478acc472SPeter Tyser *p++ = ':'; 48578acc472SPeter Tyser } 48678acc472SPeter Tyser *p = '\0'; 48778acc472SPeter Tyser 488046a37bdSSonny Rao return string(buf, end, ip6_addr, field_width, precision, 489046a37bdSSonny Rao flags & ~SPECIAL); 49078acc472SPeter Tyser } 49178acc472SPeter Tyser 492046a37bdSSonny Rao static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, 49378acc472SPeter Tyser int precision, int flags) 49478acc472SPeter Tyser { 4958acdae68SDaniel Schwierzeck /* (4 * 3 decimal digits), 3 dots and trailing zero */ 4968acdae68SDaniel Schwierzeck char ip4_addr[4 * 4]; 49778acc472SPeter Tyser char temp[3]; /* hold each IP quad in reverse order */ 49878acc472SPeter Tyser char *p = ip4_addr; 49978acc472SPeter Tyser int i, digits; 50078acc472SPeter Tyser 50178acc472SPeter Tyser for (i = 0; i < 4; i++) { 50278acc472SPeter Tyser digits = put_dec_trunc(temp, addr[i]) - temp; 50378acc472SPeter Tyser /* reverse the digits in the quad */ 50478acc472SPeter Tyser while (digits--) 50578acc472SPeter Tyser *p++ = temp[digits]; 50678acc472SPeter Tyser if (i != 3) 50778acc472SPeter Tyser *p++ = '.'; 50878acc472SPeter Tyser } 50978acc472SPeter Tyser *p = '\0'; 51078acc472SPeter Tyser 511046a37bdSSonny Rao return string(buf, end, ip4_addr, field_width, precision, 512046a37bdSSonny Rao flags & ~SPECIAL); 51378acc472SPeter Tyser } 51478acc472SPeter Tyser #endif 51578acc472SPeter Tyser 51678acc472SPeter Tyser /* 51778acc472SPeter Tyser * Show a '%p' thing. A kernel extension is that the '%p' is followed 51878acc472SPeter Tyser * by an extra set of alphanumeric characters that are extended format 51978acc472SPeter Tyser * specifiers. 52078acc472SPeter Tyser * 52178acc472SPeter Tyser * Right now we handle: 52278acc472SPeter Tyser * 52378acc472SPeter Tyser * - 'M' For a 6-byte MAC address, it prints the address in the 52478acc472SPeter Tyser * usual colon-separated hex notation 52578acc472SPeter Tyser * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated 52678acc472SPeter Tyser * decimal for v4 and colon separated network-order 16 bit hex for v6) 52778acc472SPeter Tyser * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is 52878acc472SPeter Tyser * currently the same 52978acc472SPeter Tyser * 53078acc472SPeter Tyser * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 53178acc472SPeter Tyser * function pointers are really function descriptors, which contain a 53278acc472SPeter Tyser * pointer to the real address. 53378acc472SPeter Tyser */ 534046a37bdSSonny Rao static char *pointer(const char *fmt, char *buf, char *end, void *ptr, 535046a37bdSSonny Rao int field_width, int precision, int flags) 53678acc472SPeter Tyser { 5371eebd14bSThierry Reding u64 num = (uintptr_t)ptr; 5381eebd14bSThierry Reding 539d266f669SWolfgang Denk /* 540d266f669SWolfgang Denk * Being a boot loader, we explicitly allow pointers to 541d266f669SWolfgang Denk * (physical) address null. 542d266f669SWolfgang Denk */ 543d266f669SWolfgang Denk #if 0 54478acc472SPeter Tyser if (!ptr) 545046a37bdSSonny Rao return string(buf, end, "(null)", field_width, precision, 546046a37bdSSonny Rao flags); 547d266f669SWolfgang Denk #endif 54878acc472SPeter Tyser 54978acc472SPeter Tyser #ifdef CONFIG_CMD_NET 55078acc472SPeter Tyser switch (*fmt) { 5511eebd14bSThierry Reding case 'a': 5521eebd14bSThierry Reding flags |= SPECIAL | ZEROPAD; 5531eebd14bSThierry Reding 5541eebd14bSThierry Reding switch (fmt[1]) { 5551eebd14bSThierry Reding case 'p': 5561eebd14bSThierry Reding default: 5571eebd14bSThierry Reding field_width = sizeof(phys_addr_t) * 2 + 2; 5581eebd14bSThierry Reding num = *(phys_addr_t *)ptr; 5591eebd14bSThierry Reding break; 5601eebd14bSThierry Reding } 5611eebd14bSThierry Reding break; 56278acc472SPeter Tyser case 'm': 56378acc472SPeter Tyser flags |= SPECIAL; 56478acc472SPeter Tyser /* Fallthrough */ 56578acc472SPeter Tyser case 'M': 566046a37bdSSonny Rao return mac_address_string(buf, end, ptr, field_width, 567046a37bdSSonny Rao precision, flags); 56878acc472SPeter Tyser case 'i': 56978acc472SPeter Tyser flags |= SPECIAL; 57078acc472SPeter Tyser /* Fallthrough */ 57178acc472SPeter Tyser case 'I': 57278acc472SPeter Tyser if (fmt[1] == '6') 573046a37bdSSonny Rao return ip6_addr_string(buf, end, ptr, field_width, 574046a37bdSSonny Rao precision, flags); 57578acc472SPeter Tyser if (fmt[1] == '4') 576046a37bdSSonny Rao return ip4_addr_string(buf, end, ptr, field_width, 577046a37bdSSonny Rao precision, flags); 57878acc472SPeter Tyser flags &= ~SPECIAL; 57978acc472SPeter Tyser break; 58078acc472SPeter Tyser } 58178acc472SPeter Tyser #endif 58278acc472SPeter Tyser flags |= SMALL; 58378acc472SPeter Tyser if (field_width == -1) { 58478acc472SPeter Tyser field_width = 2*sizeof(void *); 58578acc472SPeter Tyser flags |= ZEROPAD; 58678acc472SPeter Tyser } 5871eebd14bSThierry Reding return number(buf, end, num, 16, field_width, precision, flags); 58878acc472SPeter Tyser } 58978acc472SPeter Tyser 590046a37bdSSonny Rao static int vsnprintf_internal(char *buf, size_t size, const char *fmt, 591046a37bdSSonny Rao va_list args) 59278acc472SPeter Tyser { 5937b64f66cSDaniel Schwierzeck u64 num; 59478acc472SPeter Tyser int base; 59578acc472SPeter Tyser char *str; 59678acc472SPeter Tyser 59778acc472SPeter Tyser int flags; /* flags to number() */ 59878acc472SPeter Tyser 59978acc472SPeter Tyser int field_width; /* width of output field */ 60078acc472SPeter Tyser int precision; /* min. # of digits for integers; max 60178acc472SPeter Tyser number of chars for from string */ 60278acc472SPeter Tyser int qualifier; /* 'h', 'l', or 'L' for integer fields */ 60378acc472SPeter Tyser /* 'z' support added 23/7/1999 S.H. */ 60478acc472SPeter Tyser /* 'z' changed to 'Z' --davidm 1/25/99 */ 60578acc472SPeter Tyser /* 't' added for ptrdiff_t */ 606046a37bdSSonny Rao char *end = buf + size; 60778acc472SPeter Tyser 608046a37bdSSonny Rao #ifdef CONFIG_SYS_VSNPRINTF 609046a37bdSSonny Rao /* Make sure end is always >= buf - do we want this in U-Boot? */ 610046a37bdSSonny Rao if (end < buf) { 611046a37bdSSonny Rao end = ((void *)-1); 612046a37bdSSonny Rao size = end - buf; 613046a37bdSSonny Rao } 614046a37bdSSonny Rao #endif 61578acc472SPeter Tyser str = buf; 61678acc472SPeter Tyser 61778acc472SPeter Tyser for (; *fmt ; ++fmt) { 61878acc472SPeter Tyser if (*fmt != '%') { 619046a37bdSSonny Rao ADDCH(str, *fmt); 62078acc472SPeter Tyser continue; 62178acc472SPeter Tyser } 62278acc472SPeter Tyser 62378acc472SPeter Tyser /* process flags */ 62478acc472SPeter Tyser flags = 0; 62578acc472SPeter Tyser repeat: 62678acc472SPeter Tyser ++fmt; /* this also skips first '%' */ 62778acc472SPeter Tyser switch (*fmt) { 6288acdae68SDaniel Schwierzeck case '-': 6298acdae68SDaniel Schwierzeck flags |= LEFT; 6308acdae68SDaniel Schwierzeck goto repeat; 6318acdae68SDaniel Schwierzeck case '+': 6328acdae68SDaniel Schwierzeck flags |= PLUS; 6338acdae68SDaniel Schwierzeck goto repeat; 6348acdae68SDaniel Schwierzeck case ' ': 6358acdae68SDaniel Schwierzeck flags |= SPACE; 6368acdae68SDaniel Schwierzeck goto repeat; 6378acdae68SDaniel Schwierzeck case '#': 6388acdae68SDaniel Schwierzeck flags |= SPECIAL; 6398acdae68SDaniel Schwierzeck goto repeat; 6408acdae68SDaniel Schwierzeck case '0': 6418acdae68SDaniel Schwierzeck flags |= ZEROPAD; 6428acdae68SDaniel Schwierzeck goto repeat; 64378acc472SPeter Tyser } 64478acc472SPeter Tyser 64578acc472SPeter Tyser /* get field width */ 64678acc472SPeter Tyser field_width = -1; 64778acc472SPeter Tyser if (is_digit(*fmt)) 64878acc472SPeter Tyser field_width = skip_atoi(&fmt); 64978acc472SPeter Tyser else if (*fmt == '*') { 65078acc472SPeter Tyser ++fmt; 65178acc472SPeter Tyser /* it's the next argument */ 65278acc472SPeter Tyser field_width = va_arg(args, int); 65378acc472SPeter Tyser if (field_width < 0) { 65478acc472SPeter Tyser field_width = -field_width; 65578acc472SPeter Tyser flags |= LEFT; 65678acc472SPeter Tyser } 65778acc472SPeter Tyser } 65878acc472SPeter Tyser 65978acc472SPeter Tyser /* get the precision */ 66078acc472SPeter Tyser precision = -1; 66178acc472SPeter Tyser if (*fmt == '.') { 66278acc472SPeter Tyser ++fmt; 66378acc472SPeter Tyser if (is_digit(*fmt)) 66478acc472SPeter Tyser precision = skip_atoi(&fmt); 66578acc472SPeter Tyser else if (*fmt == '*') { 66678acc472SPeter Tyser ++fmt; 66778acc472SPeter Tyser /* it's the next argument */ 66878acc472SPeter Tyser precision = va_arg(args, int); 66978acc472SPeter Tyser } 67078acc472SPeter Tyser if (precision < 0) 67178acc472SPeter Tyser precision = 0; 67278acc472SPeter Tyser } 67378acc472SPeter Tyser 67478acc472SPeter Tyser /* get the conversion qualifier */ 67578acc472SPeter Tyser qualifier = -1; 67678acc472SPeter Tyser if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 67778acc472SPeter Tyser *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { 67878acc472SPeter Tyser qualifier = *fmt; 67978acc472SPeter Tyser ++fmt; 68078acc472SPeter Tyser if (qualifier == 'l' && *fmt == 'l') { 68178acc472SPeter Tyser qualifier = 'L'; 68278acc472SPeter Tyser ++fmt; 68378acc472SPeter Tyser } 68478acc472SPeter Tyser } 68578acc472SPeter Tyser 68678acc472SPeter Tyser /* default base */ 68778acc472SPeter Tyser base = 10; 68878acc472SPeter Tyser 68978acc472SPeter Tyser switch (*fmt) { 69078acc472SPeter Tyser case 'c': 691046a37bdSSonny Rao if (!(flags & LEFT)) { 69278acc472SPeter Tyser while (--field_width > 0) 693046a37bdSSonny Rao ADDCH(str, ' '); 694046a37bdSSonny Rao } 695046a37bdSSonny Rao ADDCH(str, (unsigned char) va_arg(args, int)); 69678acc472SPeter Tyser while (--field_width > 0) 697046a37bdSSonny Rao ADDCH(str, ' '); 69878acc472SPeter Tyser continue; 69978acc472SPeter Tyser 70078acc472SPeter Tyser case 's': 701046a37bdSSonny Rao str = string(str, end, va_arg(args, char *), 702046a37bdSSonny Rao field_width, precision, flags); 70378acc472SPeter Tyser continue; 70478acc472SPeter Tyser 70578acc472SPeter Tyser case 'p': 706046a37bdSSonny Rao str = pointer(fmt + 1, str, end, 70778acc472SPeter Tyser va_arg(args, void *), 70878acc472SPeter Tyser field_width, precision, flags); 70978acc472SPeter Tyser /* Skip all alphanumeric pointer suffixes */ 71078acc472SPeter Tyser while (isalnum(fmt[1])) 71178acc472SPeter Tyser fmt++; 71278acc472SPeter Tyser continue; 71378acc472SPeter Tyser 71478acc472SPeter Tyser case 'n': 71578acc472SPeter Tyser if (qualifier == 'l') { 71678acc472SPeter Tyser long *ip = va_arg(args, long *); 71778acc472SPeter Tyser *ip = (str - buf); 71878acc472SPeter Tyser } else { 71978acc472SPeter Tyser int *ip = va_arg(args, int *); 72078acc472SPeter Tyser *ip = (str - buf); 72178acc472SPeter Tyser } 72278acc472SPeter Tyser continue; 72378acc472SPeter Tyser 72478acc472SPeter Tyser case '%': 725046a37bdSSonny Rao ADDCH(str, '%'); 72678acc472SPeter Tyser continue; 72778acc472SPeter Tyser 72878acc472SPeter Tyser /* integer number formats - set up the flags and "break" */ 72978acc472SPeter Tyser case 'o': 73078acc472SPeter Tyser base = 8; 73178acc472SPeter Tyser break; 73278acc472SPeter Tyser 73378acc472SPeter Tyser case 'x': 73478acc472SPeter Tyser flags |= SMALL; 73578acc472SPeter Tyser case 'X': 73678acc472SPeter Tyser base = 16; 73778acc472SPeter Tyser break; 73878acc472SPeter Tyser 73978acc472SPeter Tyser case 'd': 74078acc472SPeter Tyser case 'i': 74178acc472SPeter Tyser flags |= SIGN; 74278acc472SPeter Tyser case 'u': 74378acc472SPeter Tyser break; 74478acc472SPeter Tyser 74578acc472SPeter Tyser default: 746046a37bdSSonny Rao ADDCH(str, '%'); 74778acc472SPeter Tyser if (*fmt) 748046a37bdSSonny Rao ADDCH(str, *fmt); 74978acc472SPeter Tyser else 75078acc472SPeter Tyser --fmt; 75178acc472SPeter Tyser continue; 75278acc472SPeter Tyser } 75378acc472SPeter Tyser if (qualifier == 'L') /* "quad" for 64 bit variables */ 75478acc472SPeter Tyser num = va_arg(args, unsigned long long); 75578acc472SPeter Tyser else if (qualifier == 'l') { 75678acc472SPeter Tyser num = va_arg(args, unsigned long); 75778acc472SPeter Tyser if (flags & SIGN) 75878acc472SPeter Tyser num = (signed long) num; 75978acc472SPeter Tyser } else if (qualifier == 'Z' || qualifier == 'z') { 76078acc472SPeter Tyser num = va_arg(args, size_t); 76178acc472SPeter Tyser } else if (qualifier == 't') { 76278acc472SPeter Tyser num = va_arg(args, ptrdiff_t); 76378acc472SPeter Tyser } else if (qualifier == 'h') { 76478acc472SPeter Tyser num = (unsigned short) va_arg(args, int); 76578acc472SPeter Tyser if (flags & SIGN) 76678acc472SPeter Tyser num = (signed short) num; 76778acc472SPeter Tyser } else { 76878acc472SPeter Tyser num = va_arg(args, unsigned int); 76978acc472SPeter Tyser if (flags & SIGN) 77078acc472SPeter Tyser num = (signed int) num; 77178acc472SPeter Tyser } 772046a37bdSSonny Rao str = number(str, end, num, base, field_width, precision, 773046a37bdSSonny Rao flags); 77478acc472SPeter Tyser } 775046a37bdSSonny Rao 776046a37bdSSonny Rao #ifdef CONFIG_SYS_VSNPRINTF 777046a37bdSSonny Rao if (size > 0) { 778046a37bdSSonny Rao ADDCH(str, '\0'); 779046a37bdSSonny Rao if (str > end) 780046a37bdSSonny Rao end[-1] = '\0'; 781686f60f5SDarwin Rambo --str; 782046a37bdSSonny Rao } 783046a37bdSSonny Rao #else 78478acc472SPeter Tyser *str = '\0'; 785046a37bdSSonny Rao #endif 786046a37bdSSonny Rao /* the trailing null byte doesn't count towards the total */ 78778acc472SPeter Tyser return str - buf; 78878acc472SPeter Tyser } 78978acc472SPeter Tyser 790046a37bdSSonny Rao #ifdef CONFIG_SYS_VSNPRINTF 791046a37bdSSonny Rao int vsnprintf(char *buf, size_t size, const char *fmt, 792046a37bdSSonny Rao va_list args) 793046a37bdSSonny Rao { 794046a37bdSSonny Rao return vsnprintf_internal(buf, size, fmt, args); 795046a37bdSSonny Rao } 796046a37bdSSonny Rao 797046a37bdSSonny Rao int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 798046a37bdSSonny Rao { 799046a37bdSSonny Rao int i; 800046a37bdSSonny Rao 801046a37bdSSonny Rao i = vsnprintf(buf, size, fmt, args); 802046a37bdSSonny Rao 803046a37bdSSonny Rao if (likely(i < size)) 804046a37bdSSonny Rao return i; 805046a37bdSSonny Rao if (size != 0) 806046a37bdSSonny Rao return size - 1; 807046a37bdSSonny Rao return 0; 808046a37bdSSonny Rao } 809046a37bdSSonny Rao 810046a37bdSSonny Rao int snprintf(char *buf, size_t size, const char *fmt, ...) 811046a37bdSSonny Rao { 812046a37bdSSonny Rao va_list args; 813046a37bdSSonny Rao int i; 814046a37bdSSonny Rao 815046a37bdSSonny Rao va_start(args, fmt); 816046a37bdSSonny Rao i = vsnprintf(buf, size, fmt, args); 817046a37bdSSonny Rao va_end(args); 818046a37bdSSonny Rao 819046a37bdSSonny Rao return i; 820046a37bdSSonny Rao } 821046a37bdSSonny Rao 822046a37bdSSonny Rao int scnprintf(char *buf, size_t size, const char *fmt, ...) 823046a37bdSSonny Rao { 824046a37bdSSonny Rao va_list args; 825046a37bdSSonny Rao int i; 826046a37bdSSonny Rao 827046a37bdSSonny Rao va_start(args, fmt); 828046a37bdSSonny Rao i = vscnprintf(buf, size, fmt, args); 829046a37bdSSonny Rao va_end(args); 830046a37bdSSonny Rao 831046a37bdSSonny Rao return i; 832046a37bdSSonny Rao } 833046a37bdSSonny Rao #endif /* CONFIG_SYS_VSNPRINT */ 834046a37bdSSonny Rao 835046a37bdSSonny Rao /** 836046a37bdSSonny Rao * Format a string and place it in a buffer (va_list version) 837046a37bdSSonny Rao * 838046a37bdSSonny Rao * @param buf The buffer to place the result into 839046a37bdSSonny Rao * @param fmt The format string to use 840046a37bdSSonny Rao * @param args Arguments for the format string 841046a37bdSSonny Rao * 842046a37bdSSonny Rao * The function returns the number of characters written 843046a37bdSSonny Rao * into @buf. Use vsnprintf() or vscnprintf() in order to avoid 844046a37bdSSonny Rao * buffer overflows. 845046a37bdSSonny Rao * 846046a37bdSSonny Rao * If you're not already dealing with a va_list consider using sprintf(). 847046a37bdSSonny Rao */ 848046a37bdSSonny Rao int vsprintf(char *buf, const char *fmt, va_list args) 849046a37bdSSonny Rao { 850046a37bdSSonny Rao return vsnprintf_internal(buf, INT_MAX, fmt, args); 851046a37bdSSonny Rao } 852046a37bdSSonny Rao 85378acc472SPeter Tyser int sprintf(char *buf, const char *fmt, ...) 85478acc472SPeter Tyser { 85578acc472SPeter Tyser va_list args; 85678acc472SPeter Tyser int i; 85778acc472SPeter Tyser 85878acc472SPeter Tyser va_start(args, fmt); 85978acc472SPeter Tyser i = vsprintf(buf, fmt, args); 86078acc472SPeter Tyser va_end(args); 86178acc472SPeter Tyser return i; 86278acc472SPeter Tyser } 86378acc472SPeter Tyser 86466312374SSimon Glass static void panic_finish(void) __attribute__ ((noreturn)); 86566312374SSimon Glass 86666312374SSimon Glass static void panic_finish(void) 86778acc472SPeter Tyser { 86878acc472SPeter Tyser putc('\n'); 86978acc472SPeter Tyser #if defined(CONFIG_PANIC_HANG) 87078acc472SPeter Tyser hang(); 87178acc472SPeter Tyser #else 87278acc472SPeter Tyser udelay(100000); /* allow messages to go out */ 87378acc472SPeter Tyser do_reset(NULL, 0, 0, NULL); 87478acc472SPeter Tyser #endif 87540e01881SHeiko Schocher while (1) 87640e01881SHeiko Schocher ; 87778acc472SPeter Tyser } 87821726a7aSSimon Glass 87966312374SSimon Glass void panic_str(const char *str) 88066312374SSimon Glass { 88166312374SSimon Glass puts(str); 88266312374SSimon Glass panic_finish(); 88366312374SSimon Glass } 88466312374SSimon Glass 88566312374SSimon Glass void panic(const char *fmt, ...) 88666312374SSimon Glass { 88766312374SSimon Glass va_list args; 88866312374SSimon Glass va_start(args, fmt); 88966312374SSimon Glass vprintf(fmt, args); 89066312374SSimon Glass va_end(args); 89166312374SSimon Glass panic_finish(); 89266312374SSimon Glass } 89366312374SSimon Glass 89421726a7aSSimon Glass void __assert_fail(const char *assertion, const char *file, unsigned line, 89521726a7aSSimon Glass const char *function) 89621726a7aSSimon Glass { 89721726a7aSSimon Glass /* This will not return */ 89821726a7aSSimon Glass panic("%s:%u: %s: Assertion `%s' failed.", file, line, function, 89921726a7aSSimon Glass assertion); 90021726a7aSSimon Glass } 9013cce8a54SSimon Glass 9023cce8a54SSimon Glass char *simple_itoa(ulong i) 9033cce8a54SSimon Glass { 9043cce8a54SSimon Glass /* 21 digits plus null terminator, good for 64-bit or smaller ints */ 9053cce8a54SSimon Glass static char local[22]; 9063cce8a54SSimon Glass char *p = &local[21]; 9073cce8a54SSimon Glass 9083cce8a54SSimon Glass *p-- = '\0'; 9093cce8a54SSimon Glass do { 9103cce8a54SSimon Glass *p-- = '0' + i % 10; 9113cce8a54SSimon Glass i /= 10; 9123cce8a54SSimon Glass } while (i > 0); 9133cce8a54SSimon Glass return p + 1; 9143cce8a54SSimon Glass } 915b8bcaa3aSSimon Glass 916b8bcaa3aSSimon Glass /* We don't seem to have %'d in U-Boot */ 917b8bcaa3aSSimon Glass void print_grouped_ull(unsigned long long int_val, int digits) 918b8bcaa3aSSimon Glass { 919b8bcaa3aSSimon Glass char str[21], *s; 920b8bcaa3aSSimon Glass int grab = 3; 921b8bcaa3aSSimon Glass 922b8bcaa3aSSimon Glass digits = (digits + 2) / 3; 923b8bcaa3aSSimon Glass sprintf(str, "%*llu", digits * 3, int_val); 924b8bcaa3aSSimon Glass for (s = str; *s; s += grab) { 925b8bcaa3aSSimon Glass if (s != str) 926b8bcaa3aSSimon Glass putc(s[-1] != ' ' ? ',' : ' '); 927b8bcaa3aSSimon Glass printf("%.*s", grab, s); 928b8bcaa3aSSimon Glass grab = 3; 929b8bcaa3aSSimon Glass } 930b8bcaa3aSSimon Glass } 93109c32807SHeiko Schocher 93209c32807SHeiko Schocher bool str2off(const char *p, loff_t *num) 93309c32807SHeiko Schocher { 93409c32807SHeiko Schocher char *endptr; 93509c32807SHeiko Schocher 93609c32807SHeiko Schocher *num = simple_strtoull(p, &endptr, 16); 93709c32807SHeiko Schocher return *p != '\0' && *endptr == '\0'; 93809c32807SHeiko Schocher } 93909c32807SHeiko Schocher 94009c32807SHeiko Schocher bool str2long(const char *p, ulong *num) 94109c32807SHeiko Schocher { 94209c32807SHeiko Schocher char *endptr; 94309c32807SHeiko Schocher 94409c32807SHeiko Schocher *num = simple_strtoul(p, &endptr, 16); 94509c32807SHeiko Schocher return *p != '\0' && *endptr == '\0'; 94609c32807SHeiko Schocher } 947