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 :-) 1078acc472SPeter Tyser */ 1178acc472SPeter Tyser 1278acc472SPeter Tyser #include <stdarg.h> 1378acc472SPeter Tyser #include <linux/types.h> 1478acc472SPeter Tyser #include <linux/string.h> 1578acc472SPeter Tyser #include <linux/ctype.h> 16a7fd0d9fSHeiko Schocher #include <errno.h> 1778acc472SPeter Tyser 1878acc472SPeter Tyser #include <common.h> 1978acc472SPeter Tyser #if !defined (CONFIG_PANIC_HANG) 2078acc472SPeter Tyser #include <command.h> 2178acc472SPeter Tyser #endif 2278acc472SPeter Tyser 2378acc472SPeter Tyser #include <div64.h> 2478acc472SPeter Tyser # define NUM_TYPE long long 2578acc472SPeter Tyser #define noinline __attribute__((noinline)) 2678acc472SPeter Tyser 2778acc472SPeter Tyser const char hex_asc[] = "0123456789abcdef"; 2878acc472SPeter Tyser #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] 2978acc472SPeter Tyser #define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] 3078acc472SPeter Tyser 3178acc472SPeter Tyser static inline char *pack_hex_byte(char *buf, u8 byte) 3278acc472SPeter Tyser { 3378acc472SPeter Tyser *buf++ = hex_asc_hi(byte); 3478acc472SPeter Tyser *buf++ = hex_asc_lo(byte); 3578acc472SPeter Tyser return buf; 3678acc472SPeter Tyser } 3778acc472SPeter Tyser 3878acc472SPeter Tyser unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) 3978acc472SPeter Tyser { 4078acc472SPeter Tyser unsigned long result = 0,value; 4178acc472SPeter Tyser 4278acc472SPeter Tyser if (*cp == '0') { 4378acc472SPeter Tyser cp++; 4478acc472SPeter Tyser if ((*cp == 'x') && isxdigit(cp[1])) { 4578acc472SPeter Tyser base = 16; 4678acc472SPeter Tyser cp++; 4778acc472SPeter Tyser } 4878acc472SPeter Tyser if (!base) { 4978acc472SPeter Tyser base = 8; 5078acc472SPeter Tyser } 5178acc472SPeter Tyser } 5278acc472SPeter Tyser if (!base) { 5378acc472SPeter Tyser base = 10; 5478acc472SPeter Tyser } 5578acc472SPeter Tyser while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) 5678acc472SPeter Tyser ? toupper(*cp) : *cp)-'A'+10) < base) { 5778acc472SPeter Tyser result = result*base + value; 5878acc472SPeter Tyser cp++; 5978acc472SPeter Tyser } 6078acc472SPeter Tyser if (endp) 6178acc472SPeter Tyser *endp = (char *)cp; 6278acc472SPeter Tyser return result; 6378acc472SPeter Tyser } 6478acc472SPeter Tyser 65a7fd0d9fSHeiko Schocher /** 66a7fd0d9fSHeiko Schocher * strict_strtoul - convert a string to an unsigned long strictly 67a7fd0d9fSHeiko Schocher * @cp: The string to be converted 68a7fd0d9fSHeiko Schocher * @base: The number base to use 69a7fd0d9fSHeiko Schocher * @res: The converted result value 70a7fd0d9fSHeiko Schocher * 71a7fd0d9fSHeiko Schocher * strict_strtoul converts a string to an unsigned long only if the 72a7fd0d9fSHeiko Schocher * string is really an unsigned long string, any string containing 73a7fd0d9fSHeiko Schocher * any invalid char at the tail will be rejected and -EINVAL is returned, 74a7fd0d9fSHeiko Schocher * only a newline char at the tail is acceptible because people generally 75a7fd0d9fSHeiko Schocher * change a module parameter in the following way: 76a7fd0d9fSHeiko Schocher * 77a7fd0d9fSHeiko Schocher * echo 1024 > /sys/module/e1000/parameters/copybreak 78a7fd0d9fSHeiko Schocher * 79a7fd0d9fSHeiko Schocher * echo will append a newline to the tail. 80a7fd0d9fSHeiko Schocher * 81a7fd0d9fSHeiko Schocher * It returns 0 if conversion is successful and *res is set to the converted 82a7fd0d9fSHeiko Schocher * value, otherwise it returns -EINVAL and *res is set to 0. 83a7fd0d9fSHeiko Schocher * 84a7fd0d9fSHeiko Schocher * simple_strtoul just ignores the successive invalid characters and 85a7fd0d9fSHeiko Schocher * return the converted value of prefix part of the string. 86a7fd0d9fSHeiko Schocher * 87a7fd0d9fSHeiko Schocher * Copied this function from Linux 2.6.38 commit ID: 88a7fd0d9fSHeiko Schocher * 521cb40b0c44418a4fd36dc633f575813d59a43d 89a7fd0d9fSHeiko Schocher * 90a7fd0d9fSHeiko Schocher */ 91a7fd0d9fSHeiko Schocher int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) 92a7fd0d9fSHeiko Schocher { 93a7fd0d9fSHeiko Schocher char *tail; 94a7fd0d9fSHeiko Schocher unsigned long val; 95a7fd0d9fSHeiko Schocher size_t len; 96a7fd0d9fSHeiko Schocher 97a7fd0d9fSHeiko Schocher *res = 0; 98a7fd0d9fSHeiko Schocher len = strlen(cp); 99a7fd0d9fSHeiko Schocher if (len == 0) 100a7fd0d9fSHeiko Schocher return -EINVAL; 101a7fd0d9fSHeiko Schocher 102a7fd0d9fSHeiko Schocher val = simple_strtoul(cp, &tail, base); 103a7fd0d9fSHeiko Schocher if (tail == cp) 104a7fd0d9fSHeiko Schocher return -EINVAL; 105a7fd0d9fSHeiko Schocher 106a7fd0d9fSHeiko Schocher if ((*tail == '\0') || 107a7fd0d9fSHeiko Schocher ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { 108a7fd0d9fSHeiko Schocher *res = val; 109a7fd0d9fSHeiko Schocher return 0; 110a7fd0d9fSHeiko Schocher } 111a7fd0d9fSHeiko Schocher 112a7fd0d9fSHeiko Schocher return -EINVAL; 113a7fd0d9fSHeiko Schocher } 114a7fd0d9fSHeiko Schocher 11578acc472SPeter Tyser long simple_strtol(const char *cp,char **endp,unsigned int base) 11678acc472SPeter Tyser { 11778acc472SPeter Tyser if(*cp=='-') 11878acc472SPeter Tyser return -simple_strtoul(cp+1,endp,base); 11978acc472SPeter Tyser return simple_strtoul(cp,endp,base); 12078acc472SPeter Tyser } 12178acc472SPeter Tyser 12278acc472SPeter Tyser int ustrtoul(const char *cp, char **endp, unsigned int base) 12378acc472SPeter Tyser { 12478acc472SPeter Tyser unsigned long result = simple_strtoul(cp, endp, base); 12578acc472SPeter Tyser switch (**endp) { 12678acc472SPeter Tyser case 'G' : 12778acc472SPeter Tyser result *= 1024; 12878acc472SPeter Tyser /* fall through */ 12978acc472SPeter Tyser case 'M': 13078acc472SPeter Tyser result *= 1024; 13178acc472SPeter Tyser /* fall through */ 13278acc472SPeter Tyser case 'K': 13378acc472SPeter Tyser case 'k': 13478acc472SPeter Tyser result *= 1024; 13578acc472SPeter Tyser if ((*endp)[1] == 'i') { 13678acc472SPeter Tyser if ((*endp)[2] == 'B') 13778acc472SPeter Tyser (*endp) += 3; 13878acc472SPeter Tyser else 13978acc472SPeter Tyser (*endp) += 2; 14078acc472SPeter Tyser } 14178acc472SPeter Tyser } 14278acc472SPeter Tyser return result; 14378acc472SPeter Tyser } 14478acc472SPeter Tyser 14578acc472SPeter Tyser unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base) 14678acc472SPeter Tyser { 14778acc472SPeter Tyser unsigned long long result = 0, value; 14878acc472SPeter Tyser 14978acc472SPeter Tyser if (*cp == '0') { 15078acc472SPeter Tyser cp++; 15178acc472SPeter Tyser if ((*cp == 'x') && isxdigit (cp[1])) { 15278acc472SPeter Tyser base = 16; 15378acc472SPeter Tyser cp++; 15478acc472SPeter Tyser } 15578acc472SPeter Tyser if (!base) { 15678acc472SPeter Tyser base = 8; 15778acc472SPeter Tyser } 15878acc472SPeter Tyser } 15978acc472SPeter Tyser if (!base) { 16078acc472SPeter Tyser base = 10; 16178acc472SPeter Tyser } 16278acc472SPeter Tyser while (isxdigit (*cp) && (value = isdigit (*cp) 16378acc472SPeter Tyser ? *cp - '0' 16478acc472SPeter Tyser : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) { 16578acc472SPeter Tyser result = result * base + value; 16678acc472SPeter Tyser cp++; 16778acc472SPeter Tyser } 16878acc472SPeter Tyser if (endp) 16978acc472SPeter Tyser *endp = (char *) cp; 17078acc472SPeter Tyser return result; 17178acc472SPeter Tyser } 17278acc472SPeter Tyser 17378acc472SPeter Tyser /* we use this so that we can do without the ctype library */ 17478acc472SPeter Tyser #define is_digit(c) ((c) >= '0' && (c) <= '9') 17578acc472SPeter Tyser 17678acc472SPeter Tyser static int skip_atoi(const char **s) 17778acc472SPeter Tyser { 17878acc472SPeter Tyser int i=0; 17978acc472SPeter Tyser 18078acc472SPeter Tyser while (is_digit(**s)) 18178acc472SPeter Tyser i = i*10 + *((*s)++) - '0'; 18278acc472SPeter Tyser return i; 18378acc472SPeter Tyser } 18478acc472SPeter Tyser 18578acc472SPeter Tyser /* Decimal conversion is by far the most typical, and is used 18678acc472SPeter Tyser * for /proc and /sys data. This directly impacts e.g. top performance 18778acc472SPeter Tyser * with many processes running. We optimize it for speed 18878acc472SPeter Tyser * using code from 18978acc472SPeter Tyser * http://www.cs.uiowa.edu/~jones/bcd/decimal.html 19078acc472SPeter Tyser * (with permission from the author, Douglas W. Jones). */ 19178acc472SPeter Tyser 19278acc472SPeter Tyser /* Formats correctly any integer in [0,99999]. 19378acc472SPeter Tyser * Outputs from one to five digits depending on input. 19478acc472SPeter Tyser * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ 19578acc472SPeter Tyser static char* put_dec_trunc(char *buf, unsigned q) 19678acc472SPeter Tyser { 19778acc472SPeter Tyser unsigned d3, d2, d1, d0; 19878acc472SPeter Tyser d1 = (q>>4) & 0xf; 19978acc472SPeter Tyser d2 = (q>>8) & 0xf; 20078acc472SPeter Tyser d3 = (q>>12); 20178acc472SPeter Tyser 20278acc472SPeter Tyser d0 = 6*(d3 + d2 + d1) + (q & 0xf); 20378acc472SPeter Tyser q = (d0 * 0xcd) >> 11; 20478acc472SPeter Tyser d0 = d0 - 10*q; 20578acc472SPeter Tyser *buf++ = d0 + '0'; /* least significant digit */ 20678acc472SPeter Tyser d1 = q + 9*d3 + 5*d2 + d1; 20778acc472SPeter Tyser if (d1 != 0) { 20878acc472SPeter Tyser q = (d1 * 0xcd) >> 11; 20978acc472SPeter Tyser d1 = d1 - 10*q; 21078acc472SPeter Tyser *buf++ = d1 + '0'; /* next digit */ 21178acc472SPeter Tyser 21278acc472SPeter Tyser d2 = q + 2*d2; 21378acc472SPeter Tyser if ((d2 != 0) || (d3 != 0)) { 21478acc472SPeter Tyser q = (d2 * 0xd) >> 7; 21578acc472SPeter Tyser d2 = d2 - 10*q; 21678acc472SPeter Tyser *buf++ = d2 + '0'; /* next digit */ 21778acc472SPeter Tyser 21878acc472SPeter Tyser d3 = q + 4*d3; 21978acc472SPeter Tyser if (d3 != 0) { 22078acc472SPeter Tyser q = (d3 * 0xcd) >> 11; 22178acc472SPeter Tyser d3 = d3 - 10*q; 22278acc472SPeter Tyser *buf++ = d3 + '0'; /* next digit */ 22378acc472SPeter Tyser if (q != 0) 22478acc472SPeter Tyser *buf++ = q + '0'; /* most sign. digit */ 22578acc472SPeter Tyser } 22678acc472SPeter Tyser } 22778acc472SPeter Tyser } 22878acc472SPeter Tyser return buf; 22978acc472SPeter Tyser } 23078acc472SPeter Tyser /* Same with if's removed. Always emits five digits */ 23178acc472SPeter Tyser static char* put_dec_full(char *buf, unsigned q) 23278acc472SPeter Tyser { 23378acc472SPeter Tyser /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ 23478acc472SPeter Tyser /* but anyway, gcc produces better code with full-sized ints */ 23578acc472SPeter Tyser unsigned d3, d2, d1, d0; 23678acc472SPeter Tyser d1 = (q>>4) & 0xf; 23778acc472SPeter Tyser d2 = (q>>8) & 0xf; 23878acc472SPeter Tyser d3 = (q>>12); 23978acc472SPeter Tyser 24078acc472SPeter Tyser /* 24178acc472SPeter Tyser * Possible ways to approx. divide by 10 24278acc472SPeter Tyser * gcc -O2 replaces multiply with shifts and adds 24378acc472SPeter Tyser * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) 24478acc472SPeter Tyser * (x * 0x67) >> 10: 1100111 24578acc472SPeter Tyser * (x * 0x34) >> 9: 110100 - same 24678acc472SPeter Tyser * (x * 0x1a) >> 8: 11010 - same 24778acc472SPeter Tyser * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) 24878acc472SPeter Tyser */ 24978acc472SPeter Tyser 25078acc472SPeter Tyser d0 = 6*(d3 + d2 + d1) + (q & 0xf); 25178acc472SPeter Tyser q = (d0 * 0xcd) >> 11; 25278acc472SPeter Tyser d0 = d0 - 10*q; 25378acc472SPeter Tyser *buf++ = d0 + '0'; 25478acc472SPeter Tyser d1 = q + 9*d3 + 5*d2 + d1; 25578acc472SPeter Tyser q = (d1 * 0xcd) >> 11; 25678acc472SPeter Tyser d1 = d1 - 10*q; 25778acc472SPeter Tyser *buf++ = d1 + '0'; 25878acc472SPeter Tyser 25978acc472SPeter Tyser d2 = q + 2*d2; 26078acc472SPeter Tyser q = (d2 * 0xd) >> 7; 26178acc472SPeter Tyser d2 = d2 - 10*q; 26278acc472SPeter Tyser *buf++ = d2 + '0'; 26378acc472SPeter Tyser 26478acc472SPeter Tyser d3 = q + 4*d3; 26578acc472SPeter Tyser q = (d3 * 0xcd) >> 11; /* - shorter code */ 26678acc472SPeter Tyser /* q = (d3 * 0x67) >> 10; - would also work */ 26778acc472SPeter Tyser d3 = d3 - 10*q; 26878acc472SPeter Tyser *buf++ = d3 + '0'; 26978acc472SPeter Tyser *buf++ = q + '0'; 27078acc472SPeter Tyser return buf; 27178acc472SPeter Tyser } 27278acc472SPeter Tyser /* No inlining helps gcc to use registers better */ 27378acc472SPeter Tyser static noinline char* put_dec(char *buf, unsigned NUM_TYPE num) 27478acc472SPeter Tyser { 27578acc472SPeter Tyser while (1) { 27678acc472SPeter Tyser unsigned rem; 27778acc472SPeter Tyser if (num < 100000) 27878acc472SPeter Tyser return put_dec_trunc(buf, num); 27978acc472SPeter Tyser rem = do_div(num, 100000); 28078acc472SPeter Tyser buf = put_dec_full(buf, rem); 28178acc472SPeter Tyser } 28278acc472SPeter Tyser } 28378acc472SPeter Tyser 28478acc472SPeter Tyser #define ZEROPAD 1 /* pad with zero */ 28578acc472SPeter Tyser #define SIGN 2 /* unsigned/signed long */ 28678acc472SPeter Tyser #define PLUS 4 /* show plus */ 28778acc472SPeter Tyser #define SPACE 8 /* space if plus */ 28878acc472SPeter Tyser #define LEFT 16 /* left justified */ 28978acc472SPeter Tyser #define SMALL 32 /* Must be 32 == 0x20 */ 29078acc472SPeter Tyser #define SPECIAL 64 /* 0x */ 29178acc472SPeter Tyser 29278acc472SPeter Tyser static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int precision, int type) 29378acc472SPeter Tyser { 29478acc472SPeter Tyser /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 29578acc472SPeter Tyser static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 29678acc472SPeter Tyser 29778acc472SPeter Tyser char tmp[66]; 29878acc472SPeter Tyser char sign; 29978acc472SPeter Tyser char locase; 30078acc472SPeter Tyser int need_pfx = ((type & SPECIAL) && base != 10); 30178acc472SPeter Tyser int i; 30278acc472SPeter Tyser 30378acc472SPeter Tyser /* locase = 0 or 0x20. ORing digits or letters with 'locase' 30478acc472SPeter Tyser * produces same digits or (maybe lowercased) letters */ 30578acc472SPeter Tyser locase = (type & SMALL); 30678acc472SPeter Tyser if (type & LEFT) 30778acc472SPeter Tyser type &= ~ZEROPAD; 30878acc472SPeter Tyser sign = 0; 30978acc472SPeter Tyser if (type & SIGN) { 31078acc472SPeter Tyser if ((signed NUM_TYPE) num < 0) { 31178acc472SPeter Tyser sign = '-'; 31278acc472SPeter Tyser num = - (signed NUM_TYPE) num; 31378acc472SPeter Tyser size--; 31478acc472SPeter Tyser } else if (type & PLUS) { 31578acc472SPeter Tyser sign = '+'; 31678acc472SPeter Tyser size--; 31778acc472SPeter Tyser } else if (type & SPACE) { 31878acc472SPeter Tyser sign = ' '; 31978acc472SPeter Tyser size--; 32078acc472SPeter Tyser } 32178acc472SPeter Tyser } 32278acc472SPeter Tyser if (need_pfx) { 32378acc472SPeter Tyser size--; 32478acc472SPeter Tyser if (base == 16) 32578acc472SPeter Tyser size--; 32678acc472SPeter Tyser } 32778acc472SPeter Tyser 32878acc472SPeter Tyser /* generate full string in tmp[], in reverse order */ 32978acc472SPeter Tyser i = 0; 33078acc472SPeter Tyser if (num == 0) 33178acc472SPeter Tyser tmp[i++] = '0'; 33278acc472SPeter Tyser /* Generic code, for any base: 33378acc472SPeter Tyser else do { 33478acc472SPeter Tyser tmp[i++] = (digits[do_div(num,base)] | locase); 33578acc472SPeter Tyser } while (num != 0); 33678acc472SPeter Tyser */ 33778acc472SPeter Tyser else if (base != 10) { /* 8 or 16 */ 33878acc472SPeter Tyser int mask = base - 1; 33978acc472SPeter Tyser int shift = 3; 34078acc472SPeter Tyser if (base == 16) shift = 4; 34178acc472SPeter Tyser do { 34278acc472SPeter Tyser tmp[i++] = (digits[((unsigned char)num) & mask] | locase); 34378acc472SPeter Tyser num >>= shift; 34478acc472SPeter Tyser } while (num); 34578acc472SPeter Tyser } else { /* base 10 */ 34678acc472SPeter Tyser i = put_dec(tmp, num) - tmp; 34778acc472SPeter Tyser } 34878acc472SPeter Tyser 34978acc472SPeter Tyser /* printing 100 using %2d gives "100", not "00" */ 35078acc472SPeter Tyser if (i > precision) 35178acc472SPeter Tyser precision = i; 35278acc472SPeter Tyser /* leading space padding */ 35378acc472SPeter Tyser size -= precision; 35478acc472SPeter Tyser if (!(type & (ZEROPAD+LEFT))) 35578acc472SPeter Tyser while(--size >= 0) 35678acc472SPeter Tyser *buf++ = ' '; 35778acc472SPeter Tyser /* sign */ 35878acc472SPeter Tyser if (sign) 35978acc472SPeter Tyser *buf++ = sign; 36078acc472SPeter Tyser /* "0x" / "0" prefix */ 36178acc472SPeter Tyser if (need_pfx) { 36278acc472SPeter Tyser *buf++ = '0'; 36378acc472SPeter Tyser if (base == 16) 36478acc472SPeter Tyser *buf++ = ('X' | locase); 36578acc472SPeter Tyser } 36678acc472SPeter Tyser /* zero or space padding */ 36778acc472SPeter Tyser if (!(type & LEFT)) { 36878acc472SPeter Tyser char c = (type & ZEROPAD) ? '0' : ' '; 36978acc472SPeter Tyser while (--size >= 0) 37078acc472SPeter Tyser *buf++ = c; 37178acc472SPeter Tyser } 37278acc472SPeter Tyser /* hmm even more zero padding? */ 37378acc472SPeter Tyser while (i <= --precision) 37478acc472SPeter Tyser *buf++ = '0'; 37578acc472SPeter Tyser /* actual digits of result */ 37678acc472SPeter Tyser while (--i >= 0) 37778acc472SPeter Tyser *buf++ = tmp[i]; 37878acc472SPeter Tyser /* trailing space padding */ 37978acc472SPeter Tyser while (--size >= 0) 38078acc472SPeter Tyser *buf++ = ' '; 38178acc472SPeter Tyser return buf; 38278acc472SPeter Tyser } 38378acc472SPeter Tyser 38478acc472SPeter Tyser static char *string(char *buf, char *s, int field_width, int precision, int flags) 38578acc472SPeter Tyser { 38678acc472SPeter Tyser int len, i; 38778acc472SPeter Tyser 38878acc472SPeter Tyser if (s == 0) 38978acc472SPeter Tyser s = "<NULL>"; 39078acc472SPeter Tyser 39178acc472SPeter Tyser len = strnlen(s, precision); 39278acc472SPeter Tyser 39378acc472SPeter Tyser if (!(flags & LEFT)) 39478acc472SPeter Tyser while (len < field_width--) 39578acc472SPeter Tyser *buf++ = ' '; 39678acc472SPeter Tyser for (i = 0; i < len; ++i) 39778acc472SPeter Tyser *buf++ = *s++; 39878acc472SPeter Tyser while (len < field_width--) 39978acc472SPeter Tyser *buf++ = ' '; 40078acc472SPeter Tyser return buf; 40178acc472SPeter Tyser } 40278acc472SPeter Tyser 40378acc472SPeter Tyser #ifdef CONFIG_CMD_NET 40478acc472SPeter Tyser static char *mac_address_string(char *buf, u8 *addr, int field_width, 40578acc472SPeter Tyser int precision, int flags) 40678acc472SPeter Tyser { 40778acc472SPeter Tyser char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ 40878acc472SPeter Tyser char *p = mac_addr; 40978acc472SPeter Tyser int i; 41078acc472SPeter Tyser 41178acc472SPeter Tyser for (i = 0; i < 6; i++) { 41278acc472SPeter Tyser p = pack_hex_byte(p, addr[i]); 41378acc472SPeter Tyser if (!(flags & SPECIAL) && i != 5) 41478acc472SPeter Tyser *p++ = ':'; 41578acc472SPeter Tyser } 41678acc472SPeter Tyser *p = '\0'; 41778acc472SPeter Tyser 41878acc472SPeter Tyser return string(buf, mac_addr, field_width, precision, flags & ~SPECIAL); 41978acc472SPeter Tyser } 42078acc472SPeter Tyser 42178acc472SPeter Tyser static char *ip6_addr_string(char *buf, u8 *addr, int field_width, 42278acc472SPeter Tyser int precision, int flags) 42378acc472SPeter Tyser { 42478acc472SPeter Tyser char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ 42578acc472SPeter Tyser char *p = ip6_addr; 42678acc472SPeter Tyser int i; 42778acc472SPeter Tyser 42878acc472SPeter Tyser for (i = 0; i < 8; i++) { 42978acc472SPeter Tyser p = pack_hex_byte(p, addr[2 * i]); 43078acc472SPeter Tyser p = pack_hex_byte(p, addr[2 * i + 1]); 43178acc472SPeter Tyser if (!(flags & SPECIAL) && i != 7) 43278acc472SPeter Tyser *p++ = ':'; 43378acc472SPeter Tyser } 43478acc472SPeter Tyser *p = '\0'; 43578acc472SPeter Tyser 43678acc472SPeter Tyser return string(buf, ip6_addr, field_width, precision, flags & ~SPECIAL); 43778acc472SPeter Tyser } 43878acc472SPeter Tyser 43978acc472SPeter Tyser static char *ip4_addr_string(char *buf, u8 *addr, int field_width, 44078acc472SPeter Tyser int precision, int flags) 44178acc472SPeter Tyser { 44278acc472SPeter Tyser char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ 44378acc472SPeter Tyser char temp[3]; /* hold each IP quad in reverse order */ 44478acc472SPeter Tyser char *p = ip4_addr; 44578acc472SPeter Tyser int i, digits; 44678acc472SPeter Tyser 44778acc472SPeter Tyser for (i = 0; i < 4; i++) { 44878acc472SPeter Tyser digits = put_dec_trunc(temp, addr[i]) - temp; 44978acc472SPeter Tyser /* reverse the digits in the quad */ 45078acc472SPeter Tyser while (digits--) 45178acc472SPeter Tyser *p++ = temp[digits]; 45278acc472SPeter Tyser if (i != 3) 45378acc472SPeter Tyser *p++ = '.'; 45478acc472SPeter Tyser } 45578acc472SPeter Tyser *p = '\0'; 45678acc472SPeter Tyser 45778acc472SPeter Tyser return string(buf, ip4_addr, field_width, precision, flags & ~SPECIAL); 45878acc472SPeter Tyser } 45978acc472SPeter Tyser #endif 46078acc472SPeter Tyser 46178acc472SPeter Tyser /* 46278acc472SPeter Tyser * Show a '%p' thing. A kernel extension is that the '%p' is followed 46378acc472SPeter Tyser * by an extra set of alphanumeric characters that are extended format 46478acc472SPeter Tyser * specifiers. 46578acc472SPeter Tyser * 46678acc472SPeter Tyser * Right now we handle: 46778acc472SPeter Tyser * 46878acc472SPeter Tyser * - 'M' For a 6-byte MAC address, it prints the address in the 46978acc472SPeter Tyser * usual colon-separated hex notation 47078acc472SPeter Tyser * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated 47178acc472SPeter Tyser * decimal for v4 and colon separated network-order 16 bit hex for v6) 47278acc472SPeter Tyser * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is 47378acc472SPeter Tyser * currently the same 47478acc472SPeter Tyser * 47578acc472SPeter Tyser * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 47678acc472SPeter Tyser * function pointers are really function descriptors, which contain a 47778acc472SPeter Tyser * pointer to the real address. 47878acc472SPeter Tyser */ 47978acc472SPeter Tyser static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int precision, int flags) 48078acc472SPeter Tyser { 48178acc472SPeter Tyser if (!ptr) 48278acc472SPeter Tyser return string(buf, "(null)", field_width, precision, flags); 48378acc472SPeter Tyser 48478acc472SPeter Tyser #ifdef CONFIG_CMD_NET 48578acc472SPeter Tyser switch (*fmt) { 48678acc472SPeter Tyser case 'm': 48778acc472SPeter Tyser flags |= SPECIAL; 48878acc472SPeter Tyser /* Fallthrough */ 48978acc472SPeter Tyser case 'M': 49078acc472SPeter Tyser return mac_address_string(buf, ptr, field_width, precision, flags); 49178acc472SPeter Tyser case 'i': 49278acc472SPeter Tyser flags |= SPECIAL; 49378acc472SPeter Tyser /* Fallthrough */ 49478acc472SPeter Tyser case 'I': 49578acc472SPeter Tyser if (fmt[1] == '6') 49678acc472SPeter Tyser return ip6_addr_string(buf, ptr, field_width, precision, flags); 49778acc472SPeter Tyser if (fmt[1] == '4') 49878acc472SPeter Tyser return ip4_addr_string(buf, ptr, field_width, precision, flags); 49978acc472SPeter Tyser flags &= ~SPECIAL; 50078acc472SPeter Tyser break; 50178acc472SPeter Tyser } 50278acc472SPeter Tyser #endif 50378acc472SPeter Tyser flags |= SMALL; 50478acc472SPeter Tyser if (field_width == -1) { 50578acc472SPeter Tyser field_width = 2*sizeof(void *); 50678acc472SPeter Tyser flags |= ZEROPAD; 50778acc472SPeter Tyser } 50878acc472SPeter Tyser return number(buf, (unsigned long) ptr, 16, field_width, precision, flags); 50978acc472SPeter Tyser } 51078acc472SPeter Tyser 51178acc472SPeter Tyser /** 51278acc472SPeter Tyser * vsprintf - Format a string and place it in a buffer 51378acc472SPeter Tyser * @buf: The buffer to place the result into 51478acc472SPeter Tyser * @fmt: The format string to use 51578acc472SPeter Tyser * @args: Arguments for the format string 51678acc472SPeter Tyser * 51778acc472SPeter Tyser * This function follows C99 vsprintf, but has some extensions: 51878acc472SPeter Tyser * %pS output the name of a text symbol 51978acc472SPeter Tyser * %pF output the name of a function pointer 52078acc472SPeter Tyser * %pR output the address range in a struct resource 52178acc472SPeter Tyser * 52278acc472SPeter Tyser * The function returns the number of characters written 52378acc472SPeter Tyser * into @buf. 52478acc472SPeter Tyser * 52578acc472SPeter Tyser * Call this function if you are already dealing with a va_list. 52678acc472SPeter Tyser * You probably want sprintf() instead. 52778acc472SPeter Tyser */ 52878acc472SPeter Tyser int vsprintf(char *buf, const char *fmt, va_list args) 52978acc472SPeter Tyser { 53078acc472SPeter Tyser unsigned NUM_TYPE num; 53178acc472SPeter Tyser int base; 53278acc472SPeter Tyser char *str; 53378acc472SPeter Tyser 53478acc472SPeter Tyser int flags; /* flags to number() */ 53578acc472SPeter Tyser 53678acc472SPeter Tyser int field_width; /* width of output field */ 53778acc472SPeter Tyser int precision; /* min. # of digits for integers; max 53878acc472SPeter Tyser number of chars for from string */ 53978acc472SPeter Tyser int qualifier; /* 'h', 'l', or 'L' for integer fields */ 54078acc472SPeter Tyser /* 'z' support added 23/7/1999 S.H. */ 54178acc472SPeter Tyser /* 'z' changed to 'Z' --davidm 1/25/99 */ 54278acc472SPeter Tyser /* 't' added for ptrdiff_t */ 54378acc472SPeter Tyser 54478acc472SPeter Tyser str = buf; 54578acc472SPeter Tyser 54678acc472SPeter Tyser for (; *fmt ; ++fmt) { 54778acc472SPeter Tyser if (*fmt != '%') { 54878acc472SPeter Tyser *str++ = *fmt; 54978acc472SPeter Tyser continue; 55078acc472SPeter Tyser } 55178acc472SPeter Tyser 55278acc472SPeter Tyser /* process flags */ 55378acc472SPeter Tyser flags = 0; 55478acc472SPeter Tyser repeat: 55578acc472SPeter Tyser ++fmt; /* this also skips first '%' */ 55678acc472SPeter Tyser switch (*fmt) { 55778acc472SPeter Tyser case '-': flags |= LEFT; goto repeat; 55878acc472SPeter Tyser case '+': flags |= PLUS; goto repeat; 55978acc472SPeter Tyser case ' ': flags |= SPACE; goto repeat; 56078acc472SPeter Tyser case '#': flags |= SPECIAL; goto repeat; 56178acc472SPeter Tyser case '0': flags |= ZEROPAD; goto repeat; 56278acc472SPeter Tyser } 56378acc472SPeter Tyser 56478acc472SPeter Tyser /* get field width */ 56578acc472SPeter Tyser field_width = -1; 56678acc472SPeter Tyser if (is_digit(*fmt)) 56778acc472SPeter Tyser field_width = skip_atoi(&fmt); 56878acc472SPeter Tyser else if (*fmt == '*') { 56978acc472SPeter Tyser ++fmt; 57078acc472SPeter Tyser /* it's the next argument */ 57178acc472SPeter Tyser field_width = va_arg(args, int); 57278acc472SPeter Tyser if (field_width < 0) { 57378acc472SPeter Tyser field_width = -field_width; 57478acc472SPeter Tyser flags |= LEFT; 57578acc472SPeter Tyser } 57678acc472SPeter Tyser } 57778acc472SPeter Tyser 57878acc472SPeter Tyser /* get the precision */ 57978acc472SPeter Tyser precision = -1; 58078acc472SPeter Tyser if (*fmt == '.') { 58178acc472SPeter Tyser ++fmt; 58278acc472SPeter Tyser if (is_digit(*fmt)) 58378acc472SPeter Tyser precision = skip_atoi(&fmt); 58478acc472SPeter Tyser else if (*fmt == '*') { 58578acc472SPeter Tyser ++fmt; 58678acc472SPeter Tyser /* it's the next argument */ 58778acc472SPeter Tyser precision = va_arg(args, int); 58878acc472SPeter Tyser } 58978acc472SPeter Tyser if (precision < 0) 59078acc472SPeter Tyser precision = 0; 59178acc472SPeter Tyser } 59278acc472SPeter Tyser 59378acc472SPeter Tyser /* get the conversion qualifier */ 59478acc472SPeter Tyser qualifier = -1; 59578acc472SPeter Tyser if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 59678acc472SPeter Tyser *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { 59778acc472SPeter Tyser qualifier = *fmt; 59878acc472SPeter Tyser ++fmt; 59978acc472SPeter Tyser if (qualifier == 'l' && *fmt == 'l') { 60078acc472SPeter Tyser qualifier = 'L'; 60178acc472SPeter Tyser ++fmt; 60278acc472SPeter Tyser } 60378acc472SPeter Tyser } 60478acc472SPeter Tyser 60578acc472SPeter Tyser /* default base */ 60678acc472SPeter Tyser base = 10; 60778acc472SPeter Tyser 60878acc472SPeter Tyser switch (*fmt) { 60978acc472SPeter Tyser case 'c': 61078acc472SPeter Tyser if (!(flags & LEFT)) 61178acc472SPeter Tyser while (--field_width > 0) 61278acc472SPeter Tyser *str++ = ' '; 61378acc472SPeter Tyser *str++ = (unsigned char) va_arg(args, int); 61478acc472SPeter Tyser while (--field_width > 0) 61578acc472SPeter Tyser *str++ = ' '; 61678acc472SPeter Tyser continue; 61778acc472SPeter Tyser 61878acc472SPeter Tyser case 's': 61978acc472SPeter Tyser str = string(str, va_arg(args, char *), field_width, precision, flags); 62078acc472SPeter Tyser continue; 62178acc472SPeter Tyser 62278acc472SPeter Tyser case 'p': 62378acc472SPeter Tyser str = pointer(fmt+1, str, 62478acc472SPeter Tyser va_arg(args, void *), 62578acc472SPeter Tyser field_width, precision, flags); 62678acc472SPeter Tyser /* Skip all alphanumeric pointer suffixes */ 62778acc472SPeter Tyser while (isalnum(fmt[1])) 62878acc472SPeter Tyser fmt++; 62978acc472SPeter Tyser continue; 63078acc472SPeter Tyser 63178acc472SPeter Tyser case 'n': 63278acc472SPeter Tyser if (qualifier == 'l') { 63378acc472SPeter Tyser long * ip = va_arg(args, long *); 63478acc472SPeter Tyser *ip = (str - buf); 63578acc472SPeter Tyser } else { 63678acc472SPeter Tyser int * ip = va_arg(args, int *); 63778acc472SPeter Tyser *ip = (str - buf); 63878acc472SPeter Tyser } 63978acc472SPeter Tyser continue; 64078acc472SPeter Tyser 64178acc472SPeter Tyser case '%': 64278acc472SPeter Tyser *str++ = '%'; 64378acc472SPeter Tyser continue; 64478acc472SPeter Tyser 64578acc472SPeter Tyser /* integer number formats - set up the flags and "break" */ 64678acc472SPeter Tyser case 'o': 64778acc472SPeter Tyser base = 8; 64878acc472SPeter Tyser break; 64978acc472SPeter Tyser 65078acc472SPeter Tyser case 'x': 65178acc472SPeter Tyser flags |= SMALL; 65278acc472SPeter Tyser case 'X': 65378acc472SPeter Tyser base = 16; 65478acc472SPeter Tyser break; 65578acc472SPeter Tyser 65678acc472SPeter Tyser case 'd': 65778acc472SPeter Tyser case 'i': 65878acc472SPeter Tyser flags |= SIGN; 65978acc472SPeter Tyser case 'u': 66078acc472SPeter Tyser break; 66178acc472SPeter Tyser 66278acc472SPeter Tyser default: 66378acc472SPeter Tyser *str++ = '%'; 66478acc472SPeter Tyser if (*fmt) 66578acc472SPeter Tyser *str++ = *fmt; 66678acc472SPeter Tyser else 66778acc472SPeter Tyser --fmt; 66878acc472SPeter Tyser continue; 66978acc472SPeter Tyser } 67078acc472SPeter Tyser if (qualifier == 'L') /* "quad" for 64 bit variables */ 67178acc472SPeter Tyser num = va_arg(args, unsigned long long); 67278acc472SPeter Tyser else if (qualifier == 'l') { 67378acc472SPeter Tyser num = va_arg(args, unsigned long); 67478acc472SPeter Tyser if (flags & SIGN) 67578acc472SPeter Tyser num = (signed long) num; 67678acc472SPeter Tyser } else if (qualifier == 'Z' || qualifier == 'z') { 67778acc472SPeter Tyser num = va_arg(args, size_t); 67878acc472SPeter Tyser } else if (qualifier == 't') { 67978acc472SPeter Tyser num = va_arg(args, ptrdiff_t); 68078acc472SPeter Tyser } else if (qualifier == 'h') { 68178acc472SPeter Tyser num = (unsigned short) va_arg(args, int); 68278acc472SPeter Tyser if (flags & SIGN) 68378acc472SPeter Tyser num = (signed short) num; 68478acc472SPeter Tyser } else { 68578acc472SPeter Tyser num = va_arg(args, unsigned int); 68678acc472SPeter Tyser if (flags & SIGN) 68778acc472SPeter Tyser num = (signed int) num; 68878acc472SPeter Tyser } 68978acc472SPeter Tyser str = number(str, num, base, field_width, precision, flags); 69078acc472SPeter Tyser } 69178acc472SPeter Tyser *str = '\0'; 69278acc472SPeter Tyser return str-buf; 69378acc472SPeter Tyser } 69478acc472SPeter Tyser 69578acc472SPeter Tyser /** 69678acc472SPeter Tyser * sprintf - Format a string and place it in a buffer 69778acc472SPeter Tyser * @buf: The buffer to place the result into 69878acc472SPeter Tyser * @fmt: The format string to use 69978acc472SPeter Tyser * @...: Arguments for the format string 70078acc472SPeter Tyser * 70178acc472SPeter Tyser * The function returns the number of characters written 70278acc472SPeter Tyser * into @buf. 70378acc472SPeter Tyser * 70478acc472SPeter Tyser * See the vsprintf() documentation for format string extensions over C99. 70578acc472SPeter Tyser */ 70678acc472SPeter Tyser int sprintf(char * buf, const char *fmt, ...) 70778acc472SPeter Tyser { 70878acc472SPeter Tyser va_list args; 70978acc472SPeter Tyser int i; 71078acc472SPeter Tyser 71178acc472SPeter Tyser va_start(args, fmt); 71278acc472SPeter Tyser i=vsprintf(buf,fmt,args); 71378acc472SPeter Tyser va_end(args); 71478acc472SPeter Tyser return i; 71578acc472SPeter Tyser } 71678acc472SPeter Tyser 71778acc472SPeter Tyser void panic(const char *fmt, ...) 71878acc472SPeter Tyser { 71978acc472SPeter Tyser va_list args; 72078acc472SPeter Tyser va_start(args, fmt); 72178acc472SPeter Tyser vprintf(fmt, args); 72278acc472SPeter Tyser putc('\n'); 72378acc472SPeter Tyser va_end(args); 72478acc472SPeter Tyser #if defined (CONFIG_PANIC_HANG) 72578acc472SPeter Tyser hang(); 72678acc472SPeter Tyser #else 72778acc472SPeter Tyser udelay (100000); /* allow messages to go out */ 72878acc472SPeter Tyser do_reset (NULL, 0, 0, NULL); 72978acc472SPeter Tyser #endif 730*40e01881SHeiko Schocher while (1) 731*40e01881SHeiko Schocher ; 73278acc472SPeter Tyser } 733