1 /* 2 * linux/lib/vsprintf.c 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 8 /* 9 * Wirzenius wrote this portably, Torvalds fucked it up :-) 10 */ 11 12 #include <common.h> 13 #include <errno.h> 14 #include <linux/ctype.h> 15 16 /* from lib/kstrtox.c */ 17 static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) 18 { 19 if (*base == 0) { 20 if (s[0] == '0') { 21 if (tolower(s[1]) == 'x' && isxdigit(s[2])) 22 *base = 16; 23 else 24 *base = 8; 25 } else 26 *base = 10; 27 } 28 if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x') 29 s += 2; 30 return s; 31 } 32 33 unsigned long simple_strtoul(const char *cp, char **endp, 34 unsigned int base) 35 { 36 unsigned long result = 0; 37 unsigned long value; 38 39 cp = _parse_integer_fixup_radix(cp, &base); 40 41 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) 42 ? toupper(*cp) : *cp)-'A'+10) < base) { 43 result = result*base + value; 44 cp++; 45 } 46 47 if (endp) 48 *endp = (char *)cp; 49 50 return result; 51 } 52 53 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) 54 { 55 char *tail; 56 unsigned long val; 57 size_t len; 58 59 *res = 0; 60 len = strlen(cp); 61 if (len == 0) 62 return -EINVAL; 63 64 val = simple_strtoul(cp, &tail, base); 65 if (tail == cp) 66 return -EINVAL; 67 68 if ((*tail == '\0') || 69 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { 70 *res = val; 71 return 0; 72 } 73 74 return -EINVAL; 75 } 76 77 long simple_strtol(const char *cp, char **endp, unsigned int base) 78 { 79 if (*cp == '-') 80 return -simple_strtoul(cp + 1, endp, base); 81 82 return simple_strtoul(cp, endp, base); 83 } 84 85 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base) 86 { 87 unsigned long result = simple_strtoul(cp, endp, base); 88 switch (tolower(**endp)) { 89 case 'g': 90 result *= 1024; 91 /* fall through */ 92 case 'm': 93 result *= 1024; 94 /* fall through */ 95 case 'k': 96 result *= 1024; 97 (*endp)++; 98 if (**endp == 'i') 99 (*endp)++; 100 if (**endp == 'B') 101 (*endp)++; 102 } 103 return result; 104 } 105 106 unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base) 107 { 108 unsigned long long result = simple_strtoull(cp, endp, base); 109 switch (tolower(**endp)) { 110 case 'g': 111 result *= 1024; 112 /* fall through */ 113 case 'm': 114 result *= 1024; 115 /* fall through */ 116 case 'k': 117 result *= 1024; 118 (*endp)++; 119 if (**endp == 'i') 120 (*endp)++; 121 if (**endp == 'B') 122 (*endp)++; 123 } 124 return result; 125 } 126 127 unsigned long long simple_strtoull(const char *cp, char **endp, 128 unsigned int base) 129 { 130 unsigned long long result = 0, value; 131 132 cp = _parse_integer_fixup_radix(cp, &base); 133 134 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0' 135 : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) { 136 result = result * base + value; 137 cp++; 138 } 139 140 if (endp) 141 *endp = (char *) cp; 142 143 return result; 144 } 145 146 long trailing_strtoln(const char *str, const char *end) 147 { 148 const char *p; 149 150 if (!end) 151 end = str + strlen(str); 152 if (isdigit(end[-1])) { 153 for (p = end - 1; p > str; p--) { 154 if (!isdigit(*p)) 155 return simple_strtoul(p + 1, NULL, 10); 156 } 157 } 158 159 return -1; 160 } 161 162 long trailing_strtol(const char *str) 163 { 164 return trailing_strtoln(str, NULL); 165 } 166