Messages in this thread Patches in this message | | | From | Rasmus Villemoes <> | Subject | Re: [PATCH 02/12] Add parse_integer() (replacement for simple_strto*()) | Date | Fri, 08 May 2015 23:52:22 +0200 |
| |
On Fri, May 08 2015, Andrew Morton <akpm@linux-foundation.org> wrote:
> My overall reaction to this is "oh god, not again". Is it really worth > it?
I think it is, if it's done right. The problem is to get consensus on what right means, but I think Alexey's approach is ok. The huge macro may be ugly, but it puts the ugliness in one place.
>> +/* internal, do not use */ >> +int _parse_integer_sc(const char *s, unsigned int base, signed char *val); >> +int _parse_integer_uc(const char *s, unsigned int base, unsigned char *val); >> +int _parse_integer_s(const char *s, unsigned int base, short *val); >> +int _parse_integer_us(const char *s, unsigned int base, unsigned short *val); >> +int _parse_integer_i(const char *s, unsigned int base, int *val); >> +int _parse_integer_u(const char *s, unsigned int base, unsigned int *val); >> +int _parse_integer_ll(const char *s, unsigned int base, long long *val); >> +int _parse_integer_ull(const char *s, unsigned int base, unsigned long long *val); > > These all have fairly lengthy implementations. Could it all be done > with a single function? > > int __parse_integer(const char *s, unsigned int base, unsigned int size, void *val); > > Where "size" is 1,2,4,8 with the top bit set if signed?
I suggested something like that in private. These two patches roughly correspond to 02/12 and 04/12 (they are just proof-of-concept).
Subject: [PATCH 1/2] lib: introduce parse_integer
This is an alternative implementation of parse_integer. It has a slightly smaller code footprint (both in #LOC and in .text). Another motivation was to expand on the idea of passing flags to the underlying function, easing implementation of other interfaces in terms of parse_integer.
In the other proposal, PARSE_INTEGER_NEWLINE means three things, which I split into separate flags:
* Accept (but don't require) a single trailing newline.
* Require that the entire string is consumed (possibly after eating the trailing newline), otherwise return -EINVAL.
* Change return semantics: 0 for ok instead of #characters consumed.
Besides the three flags doing the above, I also added flags allowing consuming leading and/or trailing whitespace. This may be used to remove some boilerplate from code elsewhere. But this may be over-engineering at this point, and it's easy enough to rip out (and maybe add later). Still, I think it's nice to keep the behaviour-changing flags separate.
Implementation-wise (and what saves ~500 bytes of .text), the main difference is that there's only a single underlying function, and the type of the destination is communicated to it with another few bits in the base parameter. In the vast majority of cases, the combined base_type_flags parameter will be a compile-time constant.
--- include/linux/parse-integer.h | 78 ++++++++++++++++++++ lib/Makefile | 1 + lib/kstrtox.c | 16 ---- lib/kstrtox.h | 3 +- lib/parse-integer.c | 166 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 247 insertions(+), 17 deletions(-) create mode 100644 include/linux/parse-integer.h create mode 100644 lib/parse-integer.c
diff --git a/include/linux/parse-integer.h b/include/linux/parse-integer.h new file mode 100644 index 000000000000..bdeb6c06059a --- /dev/null +++ b/include/linux/parse-integer.h @@ -0,0 +1,78 @@ +#ifndef LINUX_PARSE_INTEGER_H +#define LINUX_PARSE_INTEGER_H + +#include <linux/compiler.h> +#include <linux/types.h> + +#define _PARSE_INTEGER_TYPE_SHIFT 8 +enum { + _PARSE_INTEGER_U8, + _PARSE_INTEGER_U16, + _PARSE_INTEGER_U32, + _PARSE_INTEGER_U64, + _PARSE_INTEGER_S8, + _PARSE_INTEGER_S16, + _PARSE_INTEGER_S32, + _PARSE_INTEGER_S64, +}; + +/* + * Various flags that can be ORed with the base to request slightly + * different semantics, to facilitate implementing various old + * interfaces in terms of parse_integer. Not to be used directly. + */ + +/* allow (and skip) leading whitespace */ +#define _PARSE_INTEGER_LEAD_WS 0x08000000 +/* consume trailing whitespace */ +#define _PARSE_INTEGER_TRAIL_WS 0x10000000 +/* consume a single trailing newline */ +#define _PARSE_INTEGER_NEWLINE 0x20000000 +/* return 0 for success instead of #characters consumed */ +#define _PARSE_INTEGER_ZERO_ON_OK 0x40000000 +/* return -EINVAL unless the entire string was consumed */ +#define _PARSE_INTEGER_ALL 0x80000000 + +/* + * This should just be BUILD_BUG(), but due to header dependency hell + * we can't use that. + */ +void __parse_integer_build_bug(void); + +#define parse_integer(s, base_flags, dest) ({ \ + const char *_s = (s); \ + unsigned _btf = (base_flags); \ + typeof(&dest[0]) _dest = (dest); \ + unsigned _t; \ + \ + if (__builtin_types_compatible_p(typeof(_dest), u8*)) \ + _t = _PARSE_INTEGER_U8; \ + else if (__builtin_types_compatible_p(typeof(_dest), u16*)) \ + _t = _PARSE_INTEGER_U16; \ + else if (__builtin_types_compatible_p(typeof(_dest), u32*)) \ + _t = _PARSE_INTEGER_U32; \ + else if (__builtin_types_compatible_p(typeof(_dest), u64*)) \ + _t = _PARSE_INTEGER_U64; \ + else if (__builtin_types_compatible_p(typeof(_dest), s8*)) \ + _t = _PARSE_INTEGER_S8; \ + else if (__builtin_types_compatible_p(typeof(_dest), s16*)) \ + _t = _PARSE_INTEGER_S16; \ + else if (__builtin_types_compatible_p(typeof(_dest), s32*)) \ + _t = _PARSE_INTEGER_S32; \ + else if (__builtin_types_compatible_p(typeof(_dest), s64*)) \ + _t = _PARSE_INTEGER_S64; \ + else if (__builtin_types_compatible_p(typeof(_dest), unsigned long*)) \ + _t = BITS_PER_LONG == 64 ? _PARSE_INTEGER_U64 : _PARSE_INTEGER_U32; \ + else if (__builtin_types_compatible_p(typeof(_dest), long*)) \ + _t = BITS_PER_LONG == 64 ? _PARSE_INTEGER_S64 : _PARSE_INTEGER_S32; \ + else \ + __parse_integer_build_bug(); \ + _btf |= _t << _PARSE_INTEGER_TYPE_SHIFT; \ + __parse_integer(_s, _btf, _dest); \ +}) + +/* internal, do not use directly */ +int __parse_integer(const char *s, unsigned base_type_flags, void *val); +const char *_parse_integer_fixup_radix(const char *s, unsigned int *base); + +#endif /* LINUX_PARSE_INTEGER_H */ diff --git a/lib/Makefile b/lib/Makefile index 6c37933336a0..e69b356fe327 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o obj-y += hexdump.o obj-$(CONFIG_TEST_HEXDUMP) += test-hexdump.o obj-y += kstrtox.o +obj-y += parse-integer.o obj-$(CONFIG_TEST_BPF) += test_bpf.o obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o obj-$(CONFIG_TEST_KASAN) += test_kasan.o diff --git a/lib/kstrtox.c b/lib/kstrtox.c index ec8da78df9be..5b26f283428f 100644 --- a/lib/kstrtox.c +++ b/lib/kstrtox.c @@ -20,22 +20,6 @@ #include <asm/uaccess.h> #include "kstrtox.h" -const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) -{ - if (*base == 0) { - if (s[0] == '0') { - if (_tolower(s[1]) == 'x' && isxdigit(s[2])) - *base = 16; - else - *base = 8; - } else - *base = 10; - } - if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') - s += 2; - return s; -} - /* * Convert non-negative integer string representation in explicitly given radix * to an integer. diff --git a/lib/kstrtox.h b/lib/kstrtox.h index f13eeeaf441d..44d9ce227164 100644 --- a/lib/kstrtox.h +++ b/lib/kstrtox.h @@ -1,8 +1,9 @@ #ifndef _LIB_KSTRTOX_H #define _LIB_KSTRTOX_H +#include <linux/parse-integer.h> + #define KSTRTOX_OVERFLOW (1U << 31) -const char *_parse_integer_fixup_radix(const char *s, unsigned int *base); unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res); #endif diff --git a/lib/parse-integer.c b/lib/parse-integer.c new file mode 100644 index 000000000000..88f60a02c019 --- /dev/null +++ b/lib/parse-integer.c @@ -0,0 +1,166 @@ +#include <linux/bug.h> +#include <linux/ctype.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/math64.h> +#include <linux/parse-integer.h> +#include <linux/string.h> + +const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) +{ + if (*base == 0) { + if (s[0] == '0') { + if (_tolower(s[1]) == 'x' && isxdigit(s[2])) + *base = 16; + else + *base = 8; + } else + *base = 10; + } + if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') + s += 2; + BUG_ON(*base < 2 || *base > 16); + return s; +} + + +static int do_parse_integer(const char *buf, unsigned base, u64 *dest) +{ + const char *s = buf, *s0; + u64 acc = 0; + + s = _parse_integer_fixup_radix(s, &base); + s0 = s; + while (1) { + unsigned int d; + + if ('0' <= *s && *s <= '9') + d = *s - '0'; + else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f') + d = _tolower(*s) - 'a' + 10; + else + break; + if (d >= base) + break; + /* Overflow can't happen early enough. */ + if ((acc >> 60) && acc > div_u64(ULLONG_MAX - d, base)) + return -ERANGE; + acc = acc * base + d; + s++; + } + /* At least one digit has to be converted. */ + if (s == s0) + return -EINVAL; + *dest = acc; + return s - buf; +} + +int __parse_integer(const char *buf, unsigned btf, void *dest) +{ + unsigned base = btf & 0xff; + unsigned type = (btf >> _PARSE_INTEGER_TYPE_SHIFT) & 7; + unsigned flags = btf & 0xff000000; + const char *s = buf; + union { + s64 s; + u64 u; + } val; + int neg = 0; + int rv; + + if (flags & _PARSE_INTEGER_LEAD_WS) + s = skip_spaces(s); + + if (*s == '-') { + /* We don't even allow "-0" for unsigned types. */ + if (type <= _PARSE_INTEGER_U64) + return -EINVAL; + neg = 1; + s++; + } else if (*s == '+') { + s++; + } + + rv = do_parse_integer(s, base, &val.u); + if (rv < 0) + return rv; + s += rv; + + /* + * If we're targetting an unsigned type, proper range checking + * for val.u has already been done. If we're targeting a + * signed type, we may need to apply the minus sign and then + * check that the result has the expected sign. We do allow + * both -0 and +0. + */ + if (type >= _PARSE_INTEGER_S8) { + if (neg) + val.s = -val.u; + else + val.s = val.u; + if ((neg && val.s > 0) || (!neg && val.s < 0)) + return -ERANGE; + } + + if (flags & _PARSE_INTEGER_NEWLINE && *s == '\n') + ++s; + else if (flags & _PARSE_INTEGER_TRAIL_WS) + s = skip_spaces(s); + + if (flags & _PARSE_INTEGER_ALL && *s++ != '\0') + return -EINVAL; + + /* + * So far so good. Do final range check and write to the + * destination if ok. + */ + switch (type) { + case _PARSE_INTEGER_U8: + if ((u8)val.u != val.u) + return -ERANGE; + *(u8*)dest = val.u; + break; + case _PARSE_INTEGER_U16: + if ((u16)val.u != val.u) + return -ERANGE; + *(u16*)dest = val.u; + break; + case _PARSE_INTEGER_U32: + if ((u32)val.u != val.u) + return -ERANGE; + *(u32*)dest = val.u; + break; + case _PARSE_INTEGER_U64: + /* if ((u64)val.u != val.u) */ + /* return -ERANGE; */ + *(u64*)dest = val.u; + break; + case _PARSE_INTEGER_S8: + if ((s8)val.s != val.s) + return -ERANGE; + *(s8*)dest = val.s; + break; + case _PARSE_INTEGER_S16: + if ((s16)val.s != val.s) + return -ERANGE; + *(s16*)dest = val.s; + break; + case _PARSE_INTEGER_S32: + if ((s32)val.s != val.s) + return -ERANGE; + *(s32*)dest = val.s; + break; + case _PARSE_INTEGER_S64: + /* if ((s64)val.s != val.s) */ + /* return -ERANGE; */ + *(s64*)dest = val.s; + break; + default: + BUG(); + } + + if (flags & _PARSE_INTEGER_ZERO_ON_OK) + return 0; + return s - buf; +} +EXPORT_SYMBOL(__parse_integer); -- 2.1.3
Subject: [PATCH 2/2] lib: implement kstrtox using parse_integer
The new parse_integer() interface makes it easy to implement the kstrtox family of functions as simple one-line static inlines. --- include/linux/kernel.h | 125 +--------------------- include/linux/parse-integer.h | 112 ++++++++++++++++++++ lib/kstrtox.c | 238 ------------------------------------------ 3 files changed, 113 insertions(+), 362 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3a5b48e52a9e..27465774e00a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -14,6 +14,7 @@ #include <linux/dynamic_debug.h> #include <asm/byteorder.h> #include <uapi/linux/kernel.h> +#include <linux/parse-integer.h> #define USHRT_MAX ((u16)(~0U)) #define SHRT_MAX ((s16)(USHRT_MAX>>1)) @@ -263,130 +264,6 @@ void do_exit(long error_code) void complete_and_exit(struct completion *, long) __noreturn; -/* Internal, do not use. */ -int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); -int __must_check _kstrtol(const char *s, unsigned int base, long *res); - -int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res); -int __must_check kstrtoll(const char *s, unsigned int base, long long *res); - -/** - * kstrtoul - convert a string to an unsigned long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign, but not a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. -*/ -static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res) -{ - /* - * We want to shortcut function call, but - * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0. - */ - if (sizeof(unsigned long) == sizeof(unsigned long long) && - __alignof__(unsigned long) == __alignof__(unsigned long long)) - return kstrtoull(s, base, (unsigned long long *)res); - else - return _kstrtoul(s, base, res); -} - -/** - * kstrtol - convert a string to a long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign or a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -static inline int __must_check kstrtol(const char *s, unsigned int base, long *res) -{ - /* - * We want to shortcut function call, but - * __builtin_types_compatible_p(long, long long) = 0. - */ - if (sizeof(long) == sizeof(long long) && - __alignof__(long) == __alignof__(long long)) - return kstrtoll(s, base, (long long *)res); - else - return _kstrtol(s, base, res); -} - -int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res); -int __must_check kstrtoint(const char *s, unsigned int base, int *res); - -static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res) -{ - return kstrtoull(s, base, res); -} - -static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res) -{ - return kstrtoll(s, base, res); -} - -static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res) -{ - return kstrtouint(s, base, res); -} - -static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res) -{ - return kstrtoint(s, base, res); -} - -int __must_check kstrtou16(const char *s, unsigned int base, u16 *res); -int __must_check kstrtos16(const char *s, unsigned int base, s16 *res); -int __must_check kstrtou8(const char *s, unsigned int base, u8 *res); -int __must_check kstrtos8(const char *s, unsigned int base, s8 *res); - -int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); -int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); -int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); -int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res); -int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res); -int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res); -int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res); -int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res); -int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res); -int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res); - -static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res) -{ - return kstrtoull_from_user(s, count, base, res); -} - -static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res) -{ - return kstrtoll_from_user(s, count, base, res); -} - -static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res) -{ - return kstrtouint_from_user(s, count, base, res); -} - -static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res) -{ - return kstrtoint_from_user(s, count, base, res); -} - /* Obsolete, do not use. Use kstrto<foo> instead */ extern unsigned long simple_strtoul(const char *,char **,unsigned int); diff --git a/include/linux/parse-integer.h b/include/linux/parse-integer.h index bdeb6c06059a..3deebaa3e547 100644 --- a/include/linux/parse-integer.h +++ b/include/linux/parse-integer.h @@ -33,6 +33,10 @@ enum { /* return -EINVAL unless the entire string was consumed */ #define _PARSE_INTEGER_ALL 0x80000000 +/* The kstrtox family can be implemented using this combination. */ +#define _PARSE_INTEGER_KSTRTOX \ + (_PARSE_INTEGER_NEWLINE | _PARSE_INTEGER_ZERO_ON_OK | _PARSE_INTEGER_ALL) + /* * This should just be BUILD_BUG(), but due to header dependency hell * we can't use that. @@ -75,4 +79,112 @@ void __parse_integer_build_bug(void); int __parse_integer(const char *s, unsigned base_type_flags, void *val); const char *_parse_integer_fixup_radix(const char *s, unsigned int *base); +/* + * Convert integer string representation terminated by \n\0 or \0 to an integer. + * + * Return 0 on success or -E. + * + * See parse_integer(). + */ +static inline int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtoll(const char *s, unsigned int base, long long *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtol(const char *s, unsigned int base, long *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtoint(const char *s, unsigned int base, int *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res) +{ + return kstrtoull(s, base, res); +} + +static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res) +{ + return kstrtoll(s, base, res); +} + +static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res) +{ + return kstrtouint(s, base, res); +} + +static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res) +{ + return kstrtoint(s, base, res); +} + +static inline int __must_check kstrtou16(const char *s, unsigned int base, u16 *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtos16(const char *s, unsigned int base, s16 *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtou8(const char *s, unsigned int base, u8 *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +static inline int __must_check kstrtos8(const char *s, unsigned int base, s8 *res) +{ + return parse_integer(s, base | _PARSE_INTEGER_KSTRTOX, res); +} + +int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); +int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); +int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); +int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res); +int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res); +int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res); +int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res); +int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res); +int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res); +int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res); + +static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res) +{ + return kstrtoull_from_user(s, count, base, res); +} + +static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res) +{ + return kstrtoll_from_user(s, count, base, res); +} + +static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res) +{ + return kstrtouint_from_user(s, count, base, res); +} + +static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res) +{ + return kstrtoint_from_user(s, count, base, res); +} + #endif /* LINUX_PARSE_INTEGER_H */ diff --git a/lib/kstrtox.c b/lib/kstrtox.c index 5b26f283428f..1698b286d954 100644 --- a/lib/kstrtox.c +++ b/lib/kstrtox.c @@ -67,244 +67,6 @@ unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long return rv; } -static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) -{ - unsigned long long _res; - unsigned int rv; - - s = _parse_integer_fixup_radix(s, &base); - rv = _parse_integer(s, base, &_res); - if (rv & KSTRTOX_OVERFLOW) - return -ERANGE; - if (rv == 0) - return -EINVAL; - s += rv; - if (*s == '\n') - s++; - if (*s) - return -EINVAL; - *res = _res; - return 0; -} - -/** - * kstrtoull - convert a string to an unsigned long long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign, but not a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtoull(const char *s, unsigned int base, unsigned long long *res) -{ - if (s[0] == '+') - s++; - return _kstrtoull(s, base, res); -} -EXPORT_SYMBOL(kstrtoull); - -/** - * kstrtoll - convert a string to a long long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign or a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtoll(const char *s, unsigned int base, long long *res) -{ - unsigned long long tmp; - int rv; - - if (s[0] == '-') { - rv = _kstrtoull(s + 1, base, &tmp); - if (rv < 0) - return rv; - if ((long long)(-tmp) >= 0) - return -ERANGE; - *res = -tmp; - } else { - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if ((long long)tmp < 0) - return -ERANGE; - *res = tmp; - } - return 0; -} -EXPORT_SYMBOL(kstrtoll); - -/* Internal, do not use. */ -int _kstrtoul(const char *s, unsigned int base, unsigned long *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(unsigned long)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(_kstrtoul); - -/* Internal, do not use. */ -int _kstrtol(const char *s, unsigned int base, long *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(long)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(_kstrtol); - -/** - * kstrtouint - convert a string to an unsigned int - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign, but not a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtouint(const char *s, unsigned int base, unsigned int *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(unsigned int)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtouint); - -/** - * kstrtoint - convert a string to an int - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign or a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtoint(const char *s, unsigned int base, int *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(int)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtoint); - -int kstrtou16(const char *s, unsigned int base, u16 *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(u16)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtou16); - -int kstrtos16(const char *s, unsigned int base, s16 *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(s16)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtos16); - -int kstrtou8(const char *s, unsigned int base, u8 *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(u8)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtou8); - -int kstrtos8(const char *s, unsigned int base, s8 *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(s8)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtos8); - #define kstrto_from_user(f, g, type) \ int f(const char __user *s, size_t count, unsigned int base, type *res) \ { \ -- 2.1.3
| |