linux/lib/kstrtox.c
<<
>>
Prefs
   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/export.h>
  19#include <linux/types.h>
  20#include <asm/uaccess.h>
  21#include "kstrtox.h"
  22
  23const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
  24{
  25        if (*base == 0) {
  26                if (s[0] == '0') {
  27                        if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
  28                                *base = 16;
  29                        else
  30                                *base = 8;
  31                } else
  32                        *base = 10;
  33        }
  34        if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
  35                s += 2;
  36        return s;
  37}
  38
  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 */
  47unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p)
  48{
  49        unsigned long long res;
  50        unsigned int rv;
  51        int overflow;
  52
  53        res = 0;
  54        rv = 0;
  55        overflow = 0;
  56        while (*s) {
  57                unsigned int val;
  58
  59                if ('0' <= *s && *s <= '9')
  60                        val = *s - '0';
  61                else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
  62                        val = _tolower(*s) - 'a' + 10;
  63                else
  64                        break;
  65
  66                if (val >= base)
  67                        break;
  68                /*
  69                 * Check for overflow only if we are within range of
  70                 * it in the max base we support (16)
  71                 */
  72                if (unlikely(res & (~0ull << 60))) {
  73                        if (res > div_u64(ULLONG_MAX - val, base))
  74                                overflow = 1;
  75                }
  76                res = res * base + val;
  77                rv++;
  78                s++;
  79        }
  80        *p = res;
  81        if (overflow)
  82                rv |= KSTRTOX_OVERFLOW;
  83        return rv;
  84}
  85
  86static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
  87{
  88        unsigned long long _res;
  89        unsigned int rv;
  90
  91        s = _parse_integer_fixup_radix(s, &base);
  92        rv = _parse_integer(s, base, &_res);
  93        if (rv & KSTRTOX_OVERFLOW)
  94                return -ERANGE;
  95        rv &= ~KSTRTOX_OVERFLOW;
  96        if (rv == 0)
  97                return -EINVAL;
  98        s += rv;
  99        if (*s == '\n')
 100                s++;
 101        if (*s)
 102                return -EINVAL;
 103        *res = _res;
 104        return 0;
 105}
 106
 107int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
 108{
 109        if (s[0] == '+')
 110                s++;
 111        return _kstrtoull(s, base, res);
 112}
 113EXPORT_SYMBOL(kstrtoull);
 114
 115int kstrtoll(const char *s, unsigned int base, long long *res)
 116{
 117        unsigned long long tmp;
 118        int rv;
 119
 120        if (s[0] == '-') {
 121                rv = _kstrtoull(s + 1, base, &tmp);
 122                if (rv < 0)
 123                        return rv;
 124                if ((long long)(-tmp) >= 0)
 125                        return -ERANGE;
 126                *res = -tmp;
 127        } else {
 128                rv = kstrtoull(s, base, &tmp);
 129                if (rv < 0)
 130                        return rv;
 131                if ((long long)tmp < 0)
 132                        return -ERANGE;
 133                *res = tmp;
 134        }
 135        return 0;
 136}
 137EXPORT_SYMBOL(kstrtoll);
 138
 139/* Internal, do not use. */
 140int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
 141{
 142        unsigned long long tmp;
 143        int rv;
 144
 145        rv = kstrtoull(s, base, &tmp);
 146        if (rv < 0)
 147                return rv;
 148        if (tmp != (unsigned long long)(unsigned long)tmp)
 149                return -ERANGE;
 150        *res = tmp;
 151        return 0;
 152}
 153EXPORT_SYMBOL(_kstrtoul);
 154
 155/* Internal, do not use. */
 156int _kstrtol(const char *s, unsigned int base, long *res)
 157{
 158        long long tmp;
 159        int rv;
 160
 161        rv = kstrtoll(s, base, &tmp);
 162        if (rv < 0)
 163                return rv;
 164        if (tmp != (long long)(long)tmp)
 165                return -ERANGE;
 166        *res = tmp;
 167        return 0;
 168}
 169EXPORT_SYMBOL(_kstrtol);
 170
 171int kstrtouint(const char *s, unsigned int base, unsigned int *res)
 172{
 173        unsigned long long tmp;
 174        int rv;
 175
 176        rv = kstrtoull(s, base, &tmp);
 177        if (rv < 0)
 178                return rv;
 179        if (tmp != (unsigned long long)(unsigned int)tmp)
 180                return -ERANGE;
 181        *res = tmp;
 182        return 0;
 183}
 184EXPORT_SYMBOL(kstrtouint);
 185
 186int kstrtoint(const char *s, unsigned int base, int *res)
 187{
 188        long long tmp;
 189        int rv;
 190
 191        rv = kstrtoll(s, base, &tmp);
 192        if (rv < 0)
 193                return rv;
 194        if (tmp != (long long)(int)tmp)
 195                return -ERANGE;
 196        *res = tmp;
 197        return 0;
 198}
 199EXPORT_SYMBOL(kstrtoint);
 200
 201int kstrtou16(const char *s, unsigned int base, u16 *res)
 202{
 203        unsigned long long tmp;
 204        int rv;
 205
 206        rv = kstrtoull(s, base, &tmp);
 207        if (rv < 0)
 208                return rv;
 209        if (tmp != (unsigned long long)(u16)tmp)
 210                return -ERANGE;
 211        *res = tmp;
 212        return 0;
 213}
 214EXPORT_SYMBOL(kstrtou16);
 215
 216int kstrtos16(const char *s, unsigned int base, s16 *res)
 217{
 218        long long tmp;
 219        int rv;
 220
 221        rv = kstrtoll(s, base, &tmp);
 222        if (rv < 0)
 223                return rv;
 224        if (tmp != (long long)(s16)tmp)
 225                return -ERANGE;
 226        *res = tmp;
 227        return 0;
 228}
 229EXPORT_SYMBOL(kstrtos16);
 230
 231int kstrtou8(const char *s, unsigned int base, u8 *res)
 232{
 233        unsigned long long tmp;
 234        int rv;
 235
 236        rv = kstrtoull(s, base, &tmp);
 237        if (rv < 0)
 238                return rv;
 239        if (tmp != (unsigned long long)(u8)tmp)
 240                return -ERANGE;
 241        *res = tmp;
 242        return 0;
 243}
 244EXPORT_SYMBOL(kstrtou8);
 245
 246int kstrtos8(const char *s, unsigned int base, s8 *res)
 247{
 248        long long tmp;
 249        int rv;
 250
 251        rv = kstrtoll(s, base, &tmp);
 252        if (rv < 0)
 253                return rv;
 254        if (tmp != (long long)(s8)tmp)
 255                return -ERANGE;
 256        *res = tmp;
 257        return 0;
 258}
 259EXPORT_SYMBOL(kstrtos8);
 260
 261#define kstrto_from_user(f, g, type)                                    \
 262int f(const char __user *s, size_t count, unsigned int base, type *res) \
 263{                                                                       \
 264        /* sign, base 2 representation, newline, terminator */          \
 265        char buf[1 + sizeof(type) * 8 + 1 + 1];                         \
 266                                                                        \
 267        count = min(count, sizeof(buf) - 1);                            \
 268        if (copy_from_user(buf, s, count))                              \
 269                return -EFAULT;                                         \
 270        buf[count] = '\0';                                              \
 271        return g(buf, base, res);                                       \
 272}                                                                       \
 273EXPORT_SYMBOL(f)
 274
 275kstrto_from_user(kstrtoull_from_user,   kstrtoull,      unsigned long long);
 276kstrto_from_user(kstrtoll_from_user,    kstrtoll,       long long);
 277kstrto_from_user(kstrtoul_from_user,    kstrtoul,       unsigned long);
 278kstrto_from_user(kstrtol_from_user,     kstrtol,        long);
 279kstrto_from_user(kstrtouint_from_user,  kstrtouint,     unsigned int);
 280kstrto_from_user(kstrtoint_from_user,   kstrtoint,      int);
 281kstrto_from_user(kstrtou16_from_user,   kstrtou16,      u16);
 282kstrto_from_user(kstrtos16_from_user,   kstrtos16,      s16);
 283kstrto_from_user(kstrtou8_from_user,    kstrtou8,       u8);
 284kstrto_from_user(kstrtos8_from_user,    kstrtos8,       s8);
 285
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.