kstrtox.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. static inline char _tolower(const char c)
  21. {
  22. return c | 0x20;
  23. }
  24. static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
  25. {
  26. unsigned long long acc;
  27. int ok;
  28. if (base == 0) {
  29. if (s[0] == '0') {
  30. if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
  31. base = 16;
  32. else
  33. base = 8;
  34. } else
  35. base = 10;
  36. }
  37. if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
  38. s += 2;
  39. acc = 0;
  40. ok = 0;
  41. while (*s) {
  42. unsigned int val;
  43. if ('0' <= *s && *s <= '9')
  44. val = *s - '0';
  45. else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
  46. val = _tolower(*s) - 'a' + 10;
  47. else if (*s == '\n') {
  48. if (*(s + 1) == '\0')
  49. break;
  50. else
  51. return -EINVAL;
  52. } else
  53. return -EINVAL;
  54. if (val >= base)
  55. return -EINVAL;
  56. if (acc > div_u64(ULLONG_MAX - val, base))
  57. return -ERANGE;
  58. acc = acc * base + val;
  59. ok = 1;
  60. s++;
  61. }
  62. if (!ok)
  63. return -EINVAL;
  64. *res = acc;
  65. return 0;
  66. }
  67. int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
  68. {
  69. if (s[0] == '+')
  70. s++;
  71. return _kstrtoull(s, base, res);
  72. }
  73. EXPORT_SYMBOL(kstrtoull);
  74. int kstrtoll(const char *s, unsigned int base, long long *res)
  75. {
  76. unsigned long long tmp;
  77. int rv;
  78. if (s[0] == '-') {
  79. rv = _kstrtoull(s + 1, base, &tmp);
  80. if (rv < 0)
  81. return rv;
  82. if ((long long)(-tmp) >= 0)
  83. return -ERANGE;
  84. *res = -tmp;
  85. } else {
  86. rv = kstrtoull(s, base, &tmp);
  87. if (rv < 0)
  88. return rv;
  89. if ((long long)tmp < 0)
  90. return -ERANGE;
  91. *res = tmp;
  92. }
  93. return 0;
  94. }
  95. EXPORT_SYMBOL(kstrtoll);
  96. /* Internal, do not use. */
  97. int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
  98. {
  99. unsigned long long tmp;
  100. int rv;
  101. rv = kstrtoull(s, base, &tmp);
  102. if (rv < 0)
  103. return rv;
  104. if (tmp != (unsigned long long)(unsigned long)tmp)
  105. return -ERANGE;
  106. *res = tmp;
  107. return 0;
  108. }
  109. EXPORT_SYMBOL(_kstrtoul);
  110. /* Internal, do not use. */
  111. int _kstrtol(const char *s, unsigned int base, long *res)
  112. {
  113. long long tmp;
  114. int rv;
  115. rv = kstrtoll(s, base, &tmp);
  116. if (rv < 0)
  117. return rv;
  118. if (tmp != (long long)(long)tmp)
  119. return -ERANGE;
  120. *res = tmp;
  121. return 0;
  122. }
  123. EXPORT_SYMBOL(_kstrtol);
  124. int kstrtouint(const char *s, unsigned int base, unsigned int *res)
  125. {
  126. unsigned long long tmp;
  127. int rv;
  128. rv = kstrtoull(s, base, &tmp);
  129. if (rv < 0)
  130. return rv;
  131. if (tmp != (unsigned long long)(unsigned int)tmp)
  132. return -ERANGE;
  133. *res = tmp;
  134. return 0;
  135. }
  136. EXPORT_SYMBOL(kstrtouint);
  137. int kstrtoint(const char *s, unsigned int base, int *res)
  138. {
  139. long long tmp;
  140. int rv;
  141. rv = kstrtoll(s, base, &tmp);
  142. if (rv < 0)
  143. return rv;
  144. if (tmp != (long long)(int)tmp)
  145. return -ERANGE;
  146. *res = tmp;
  147. return 0;
  148. }
  149. EXPORT_SYMBOL(kstrtoint);
  150. int kstrtou16(const char *s, unsigned int base, u16 *res)
  151. {
  152. unsigned long long tmp;
  153. int rv;
  154. rv = kstrtoull(s, base, &tmp);
  155. if (rv < 0)
  156. return rv;
  157. if (tmp != (unsigned long long)(u16)tmp)
  158. return -ERANGE;
  159. *res = tmp;
  160. return 0;
  161. }
  162. EXPORT_SYMBOL(kstrtou16);
  163. int kstrtos16(const char *s, unsigned int base, s16 *res)
  164. {
  165. long long tmp;
  166. int rv;
  167. rv = kstrtoll(s, base, &tmp);
  168. if (rv < 0)
  169. return rv;
  170. if (tmp != (long long)(s16)tmp)
  171. return -ERANGE;
  172. *res = tmp;
  173. return 0;
  174. }
  175. EXPORT_SYMBOL(kstrtos16);
  176. int kstrtou8(const char *s, unsigned int base, u8 *res)
  177. {
  178. unsigned long long tmp;
  179. int rv;
  180. rv = kstrtoull(s, base, &tmp);
  181. if (rv < 0)
  182. return rv;
  183. if (tmp != (unsigned long long)(u8)tmp)
  184. return -ERANGE;
  185. *res = tmp;
  186. return 0;
  187. }
  188. EXPORT_SYMBOL(kstrtou8);
  189. int kstrtos8(const char *s, unsigned int base, s8 *res)
  190. {
  191. long long tmp;
  192. int rv;
  193. rv = kstrtoll(s, base, &tmp);
  194. if (rv < 0)
  195. return rv;
  196. if (tmp != (long long)(s8)tmp)
  197. return -ERANGE;
  198. *res = tmp;
  199. return 0;
  200. }
  201. EXPORT_SYMBOL(kstrtos8);