1 /* 2 * Convert integer string representation to an integer. 3 * If an integer doesn't fit into specified type, -E is returned. 4 * 5 * Integer starts with optional sign. 6 * kstrtou*() functions do not accept sign "-". 7 * 8 * Radix 0 means autodetection: leading "0x" implies radix 16, 9 * leading "0" implies radix 8, otherwise radix is 10. 10 * Autodetection hints work after optional sign, but not before. 11 * 12 * If -E is returned, result is not touched. 13 */ 14 #include <linux/ctype.h> 15 #include <linux/errno.h> 16 #include <linux/kernel.h> 17 #include <linux/math64.h> 18 #include <linux/module.h> 19 #include <linux/types.h> 20 21 static inline char _tolower(const char c) 22 { 23 return c | 0x20; 24 } 25 26 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) 27 { 28 unsigned long long acc; 29 int ok; 30 31 if (base == 0) { 32 if (s[0] == '0') { 33 if (_tolower(s[1]) == 'x' && isxdigit(s[2])) 34 base = 16; 35 else 36 base = 8; 37 } else 38 base = 10; 39 } 40 if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') 41 s += 2; 42 43 acc = 0; 44 ok = 0; 45 while (*s) { 46 unsigned int val; 47 48 if ('0' <= *s && *s <= '9') 49 val = *s - '0'; 50 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f') 51 val = _tolower(*s) - 'a' + 10; 52 else if (*s == '\n' && *(s + 1) == '\0') 53 break; 54 else 55 return -EINVAL; 56 57 if (val >= base) 58 return -EINVAL; 59 if (acc > div_u64(ULLONG_MAX - val, base)) 60 return -ERANGE; 61 acc = acc * base + val; 62 ok = 1; 63 64 s++; 65 } 66 if (!ok) 67 return -EINVAL; 68 *res = acc; 69 return 0; 70 } 71 72 int kstrtoull(const char *s, unsigned int base, unsigned long long *res) 73 { 74 if (s[0] == '+') 75 s++; 76 return _kstrtoull(s, base, res); 77 } 78 EXPORT_SYMBOL(kstrtoull); 79 80 int kstrtoll(const char *s, unsigned int base, long long *res) 81 { 82 unsigned long long tmp; 83 int rv; 84 85 if (s[0] == '-') { 86 rv = _kstrtoull(s + 1, base, &tmp); 87 if (rv < 0) 88 return rv; 89 if ((long long)(-tmp) >= 0) 90 return -ERANGE; 91 *res = -tmp; 92 } else { 93 rv = kstrtoull(s, base, &tmp); 94 if (rv < 0) 95 return rv; 96 if ((long long)tmp < 0) 97 return -ERANGE; 98 *res = tmp; 99 } 100 return 0; 101 } 102 EXPORT_SYMBOL(kstrtoll); 103 104 /* Internal, do not use. */ 105 int _kstrtoul(const char *s, unsigned int base, unsigned long *res) 106 { 107 unsigned long long tmp; 108 int rv; 109 110 rv = kstrtoull(s, base, &tmp); 111 if (rv < 0) 112 return rv; 113 if (tmp != (unsigned long long)(unsigned long)tmp) 114 return -ERANGE; 115 *res = tmp; 116 return 0; 117 } 118 EXPORT_SYMBOL(_kstrtoul); 119 120 /* Internal, do not use. */ 121 int _kstrtol(const char *s, unsigned int base, long *res) 122 { 123 long long tmp; 124 int rv; 125 126 rv = kstrtoll(s, base, &tmp); 127 if (rv < 0) 128 return rv; 129 if (tmp != (long long)(long)tmp) 130 return -ERANGE; 131 *res = tmp; 132 return 0; 133 } 134 EXPORT_SYMBOL(_kstrtol); 135 136 int kstrtouint(const char *s, unsigned int base, unsigned int *res) 137 { 138 unsigned long long tmp; 139 int rv; 140 141 rv = kstrtoull(s, base, &tmp); 142 if (rv < 0) 143 return rv; 144 if (tmp != (unsigned long long)(unsigned int)tmp) 145 return -ERANGE; 146 *res = tmp; 147 return 0; 148 } 149 EXPORT_SYMBOL(kstrtouint); 150 151 int kstrtoint(const char *s, unsigned int base, int *res) 152 { 153 long long tmp; 154 int rv; 155 156 rv = kstrtoll(s, base, &tmp); 157 if (rv < 0) 158 return rv; 159 if (tmp != (long long)(int)tmp) 160 return -ERANGE; 161 *res = tmp; 162 return 0; 163 } 164 EXPORT_SYMBOL(kstrtoint); 165 166 int kstrtou16(const char *s, unsigned int base, u16 *res) 167 { 168 unsigned long long tmp; 169 int rv; 170 171 rv = kstrtoull(s, base, &tmp); 172 if (rv < 0) 173 return rv; 174 if (tmp != (unsigned long long)(u16)tmp) 175 return -ERANGE; 176 *res = tmp; 177 return 0; 178 } 179 EXPORT_SYMBOL(kstrtou16); 180 181 int kstrtos16(const char *s, unsigned int base, s16 *res) 182 { 183 long long tmp; 184 int rv; 185 186 rv = kstrtoll(s, base, &tmp); 187 if (rv < 0) 188 return rv; 189 if (tmp != (long long)(s16)tmp) 190 return -ERANGE; 191 *res = tmp; 192 return 0; 193 } 194 EXPORT_SYMBOL(kstrtos16); 195 196 int kstrtou8(const char *s, unsigned int base, u8 *res) 197 { 198 unsigned long long tmp; 199 int rv; 200 201 rv = kstrtoull(s, base, &tmp); 202 if (rv < 0) 203 return rv; 204 if (tmp != (unsigned long long)(u8)tmp) 205 return -ERANGE; 206 *res = tmp; 207 return 0; 208 } 209 EXPORT_SYMBOL(kstrtou8); 210 211 int kstrtos8(const char *s, unsigned int base, s8 *res) 212 { 213 long long tmp; 214 int rv; 215 216 rv = kstrtoll(s, base, &tmp); 217 if (rv < 0) 218 return rv; 219 if (tmp != (long long)(s8)tmp) 220 return -ERANGE; 221 *res = tmp; 222 return 0; 223 } 224 EXPORT_SYMBOL(kstrtos8); 225