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') { 53 if (*(s + 1) == '\0') 54 break; 55 else 56 return -EINVAL; 57 } else 58 return -EINVAL; 59 60 if (val >= base) 61 return -EINVAL; 62 if (acc > div_u64(ULLONG_MAX - val, base)) 63 return -ERANGE; 64 acc = acc * base + val; 65 ok = 1; 66 67 s++; 68 } 69 if (!ok) 70 return -EINVAL; 71 *res = acc; 72 return 0; 73 } 74 75 int kstrtoull(const char *s, unsigned int base, unsigned long long *res) 76 { 77 if (s[0] == '+') 78 s++; 79 return _kstrtoull(s, base, res); 80 } 81 EXPORT_SYMBOL(kstrtoull); 82 83 int kstrtoll(const char *s, unsigned int base, long long *res) 84 { 85 unsigned long long tmp; 86 int rv; 87 88 if (s[0] == '-') { 89 rv = _kstrtoull(s + 1, base, &tmp); 90 if (rv < 0) 91 return rv; 92 if ((long long)(-tmp) >= 0) 93 return -ERANGE; 94 *res = -tmp; 95 } else { 96 rv = kstrtoull(s, base, &tmp); 97 if (rv < 0) 98 return rv; 99 if ((long long)tmp < 0) 100 return -ERANGE; 101 *res = tmp; 102 } 103 return 0; 104 } 105 EXPORT_SYMBOL(kstrtoll); 106 107 /* Internal, do not use. */ 108 int _kstrtoul(const char *s, unsigned int base, unsigned long *res) 109 { 110 unsigned long long tmp; 111 int rv; 112 113 rv = kstrtoull(s, base, &tmp); 114 if (rv < 0) 115 return rv; 116 if (tmp != (unsigned long long)(unsigned long)tmp) 117 return -ERANGE; 118 *res = tmp; 119 return 0; 120 } 121 EXPORT_SYMBOL(_kstrtoul); 122 123 /* Internal, do not use. */ 124 int _kstrtol(const char *s, unsigned int base, long *res) 125 { 126 long long tmp; 127 int rv; 128 129 rv = kstrtoll(s, base, &tmp); 130 if (rv < 0) 131 return rv; 132 if (tmp != (long long)(long)tmp) 133 return -ERANGE; 134 *res = tmp; 135 return 0; 136 } 137 EXPORT_SYMBOL(_kstrtol); 138 139 int kstrtouint(const char *s, unsigned int base, unsigned int *res) 140 { 141 unsigned long long tmp; 142 int rv; 143 144 rv = kstrtoull(s, base, &tmp); 145 if (rv < 0) 146 return rv; 147 if (tmp != (unsigned long long)(unsigned int)tmp) 148 return -ERANGE; 149 *res = tmp; 150 return 0; 151 } 152 EXPORT_SYMBOL(kstrtouint); 153 154 int kstrtoint(const char *s, unsigned int base, int *res) 155 { 156 long long tmp; 157 int rv; 158 159 rv = kstrtoll(s, base, &tmp); 160 if (rv < 0) 161 return rv; 162 if (tmp != (long long)(int)tmp) 163 return -ERANGE; 164 *res = tmp; 165 return 0; 166 } 167 EXPORT_SYMBOL(kstrtoint); 168 169 int kstrtou16(const char *s, unsigned int base, u16 *res) 170 { 171 unsigned long long tmp; 172 int rv; 173 174 rv = kstrtoull(s, base, &tmp); 175 if (rv < 0) 176 return rv; 177 if (tmp != (unsigned long long)(u16)tmp) 178 return -ERANGE; 179 *res = tmp; 180 return 0; 181 } 182 EXPORT_SYMBOL(kstrtou16); 183 184 int kstrtos16(const char *s, unsigned int base, s16 *res) 185 { 186 long long tmp; 187 int rv; 188 189 rv = kstrtoll(s, base, &tmp); 190 if (rv < 0) 191 return rv; 192 if (tmp != (long long)(s16)tmp) 193 return -ERANGE; 194 *res = tmp; 195 return 0; 196 } 197 EXPORT_SYMBOL(kstrtos16); 198 199 int kstrtou8(const char *s, unsigned int base, u8 *res) 200 { 201 unsigned long long tmp; 202 int rv; 203 204 rv = kstrtoull(s, base, &tmp); 205 if (rv < 0) 206 return rv; 207 if (tmp != (unsigned long long)(u8)tmp) 208 return -ERANGE; 209 *res = tmp; 210 return 0; 211 } 212 EXPORT_SYMBOL(kstrtou8); 213 214 int kstrtos8(const char *s, unsigned int base, s8 *res) 215 { 216 long long tmp; 217 int rv; 218 219 rv = kstrtoll(s, base, &tmp); 220 if (rv < 0) 221 return rv; 222 if (tmp != (long long)(s8)tmp) 223 return -ERANGE; 224 *res = tmp; 225 return 0; 226 } 227 EXPORT_SYMBOL(kstrtos8); 228