Commit 1dff46d6987484eaa31f2fb1425216ba06418be3

Authored by Alexey Dobriyan
Committed by Linus Torvalds
1 parent b3c49c05b7

lib/kstrtox: common code between kstrto*() and simple_strto*() functions

Currently termination logic (\0 or \n\0) is hardcoded in _kstrtoull(),
avoid that for code reuse between kstrto*() and simple_strtoull().
Essentially, make them different only in termination logic.

simple_strtoull() (and scanf(), BTW) ignores integer overflow, that's a
bug we currently don't have guts to fix, making KSTRTOX_OVERFLOW hack
necessary.

Almost forgot: patch shrinks code size by about ~80 bytes on x86_64.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 68 additions and 48 deletions Side-by-side Diff

... ... @@ -18,26 +18,40 @@
18 18 #include <linux/module.h>
19 19 #include <linux/types.h>
20 20 #include <asm/uaccess.h>
  21 +#include "kstrtox.h"
21 22  
22   -static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
  23 +const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
23 24 {
24   - unsigned long long acc;
25   - int ok;
26   -
27   - if (base == 0) {
  25 + if (*base == 0) {
28 26 if (s[0] == '0') {
29 27 if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
30   - base = 16;
  28 + *base = 16;
31 29 else
32   - base = 8;
  30 + *base = 8;
33 31 } else
34   - base = 10;
  32 + *base = 10;
35 33 }
36   - if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
  34 + if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
37 35 s += 2;
  36 + return s;
  37 +}
38 38  
39   - acc = 0;
40   - ok = 0;
  39 +/*
  40 + * Convert non-negative integer string representation in explicitly given radix
  41 + * to an integer.
  42 + * Return number of characters consumed maybe or-ed with overflow bit.
  43 + * If overflow occurs, result integer (incorrect) is still returned.
  44 + *
  45 + * Don't you dare use this function.
  46 + */
  47 +unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res)
  48 +{
  49 + unsigned int rv;
  50 + int overflow;
  51 +
  52 + *res = 0;
  53 + rv = 0;
  54 + overflow = 0;
41 55 while (*s) {
42 56 unsigned int val;
43 57  
44 58  
45 59  
46 60  
47 61  
... ... @@ -45,23 +59,40 @@
45 59 val = *s - '0';
46 60 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
47 61 val = _tolower(*s) - 'a' + 10;
48   - else if (*s == '\n' && *(s + 1) == '\0')
49   - break;
50 62 else
51   - return -EINVAL;
  63 + break;
52 64  
53 65 if (val >= base)
54   - return -EINVAL;
55   - if (acc > div_u64(ULLONG_MAX - val, base))
56   - return -ERANGE;
57   - acc = acc * base + val;
58   - ok = 1;
59   -
  66 + break;
  67 + if (*res > div_u64(ULLONG_MAX - val, base))
  68 + overflow = 1;
  69 + *res = *res * base + val;
  70 + rv++;
60 71 s++;
61 72 }
62   - if (!ok)
  73 + if (overflow)
  74 + rv |= KSTRTOX_OVERFLOW;
  75 + return rv;
  76 +}
  77 +
  78 +static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
  79 +{
  80 + unsigned long long _res;
  81 + unsigned int rv;
  82 +
  83 + s = _parse_integer_fixup_radix(s, &base);
  84 + rv = _parse_integer(s, base, &_res);
  85 + if (rv & KSTRTOX_OVERFLOW)
  86 + return -ERANGE;
  87 + rv &= ~KSTRTOX_OVERFLOW;
  88 + if (rv == 0)
63 89 return -EINVAL;
64   - *res = acc;
  90 + s += rv;
  91 + if (*s == '\n')
  92 + s++;
  93 + if (*s)
  94 + return -EINVAL;
  95 + *res = _res;
65 96 return 0;
66 97 }
67 98  
  1 +#ifndef _LIB_KSTRTOX_H
  2 +#define _LIB_KSTRTOX_H
  3 +
  4 +#define KSTRTOX_OVERFLOW (1U << 31)
  5 +const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
  6 +unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res);
  7 +
  8 +#endif
... ... @@ -31,17 +31,7 @@
31 31 #include <asm/div64.h>
32 32 #include <asm/sections.h> /* for dereference_function_descriptor() */
33 33  
34   -static unsigned int simple_guess_base(const char *cp)
35   -{
36   - if (cp[0] == '0') {
37   - if (_tolower(cp[1]) == 'x' && isxdigit(cp[2]))
38   - return 16;
39   - else
40   - return 8;
41   - } else {
42   - return 10;
43   - }
44   -}
  34 +#include "kstrtox.h"
45 35  
46 36 /**
47 37 * simple_strtoull - convert a string to an unsigned long long
48 38  
49 39  
... ... @@ -51,23 +41,14 @@
51 41 */
52 42 unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
53 43 {
54   - unsigned long long result = 0;
  44 + unsigned long long result;
  45 + unsigned int rv;
55 46  
56   - if (!base)
57   - base = simple_guess_base(cp);
  47 + cp = _parse_integer_fixup_radix(cp, &base);
  48 + rv = _parse_integer(cp, base, &result);
  49 + /* FIXME */
  50 + cp += (rv & ~KSTRTOX_OVERFLOW);
58 51  
59   - if (base == 16 && cp[0] == '0' && _tolower(cp[1]) == 'x')
60   - cp += 2;
61   -
62   - while (isxdigit(*cp)) {
63   - unsigned int value;
64   -
65   - value = isdigit(*cp) ? *cp - '0' : _tolower(*cp) - 'a' + 10;
66   - if (value >= base)
67   - break;
68   - result = result * base + value;
69   - cp++;
70   - }
71 52 if (endp)
72 53 *endp = (char *)cp;
73 54