busybox/libbb/bb_strtonum.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Utility routines.
   4 *
   5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
   6 *
   7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9#include "libbb.h"
  10
  11/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
  12 * errno = EINVAL if value was not '\0' terminated, but otherwise ok
  13 *    Return value is still valid, caller should just check whether end[0]
  14 *    is a valid terminating char for particular case. OTOH, if caller
  15 *    requires '\0' terminated input, [s]he can just check errno == 0.
  16 * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
  17 * errno = ERANGE if value is out of range, missing, etc.
  18 * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
  19 *    return value is all-ones in this case.
  20 *
  21 * Test code:
  22 * char *endptr;
  23 * const char *minus = "-";
  24 * errno = 0;
  25 * bb_strtoi(minus, &endptr, 0); // must set ERANGE
  26 * printf("minus:%p endptr:%p errno:%d EINVAL:%d\n", minus, endptr, errno, EINVAL);
  27 * errno = 0;
  28 * bb_strtoi("-0-", &endptr, 0); // must set EINVAL and point to second '-'
  29 * printf("endptr[0]:%c errno:%d EINVAL:%d\n", endptr[0], errno, EINVAL);
  30 */
  31
  32static unsigned long long ret_ERANGE(void)
  33{
  34        errno = ERANGE; /* this ain't as small as it looks (on glibc) */
  35        return ULLONG_MAX;
  36}
  37
  38static unsigned long long handle_errors(unsigned long long v, char **endp)
  39{
  40        char next_ch = **endp;
  41
  42        /* errno is already set to ERANGE by strtoXXX if value overflowed */
  43        if (next_ch) {
  44                /* "1234abcg" or out-of-range? */
  45                if (isalnum(next_ch) || errno)
  46                        return ret_ERANGE();
  47                /* good number, just suspicious terminator */
  48                errno = EINVAL;
  49        }
  50        return v;
  51}
  52
  53
  54unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base)
  55{
  56        unsigned long long v;
  57        char *endptr;
  58
  59        if (!endp) endp = &endptr;
  60        *endp = (char*) arg;
  61
  62        /* strtoul("  -4200000000") returns 94967296, errno 0 (!) */
  63        /* I don't think that this is right. Preventing this... */
  64        if (!isalnum(arg[0])) return ret_ERANGE();
  65
  66        /* not 100% correct for lib func, but convenient for the caller */
  67        errno = 0;
  68        v = strtoull(arg, endp, base);
  69        return handle_errors(v, endp);
  70}
  71
  72long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base)
  73{
  74        unsigned long long v;
  75        char *endptr;
  76        char first;
  77
  78        if (!endp) endp = &endptr;
  79        *endp = (char*) arg;
  80
  81        /* Check for the weird "feature":
  82         * a "-" string is apparently a valid "number" for strto[u]l[l]!
  83         * It returns zero and errno is 0! :( */
  84        first = (arg[0] != '-' ? arg[0] : arg[1]);
  85        if (!isalnum(first)) return ret_ERANGE();
  86
  87        errno = 0;
  88        v = strtoll(arg, endp, base);
  89        return handle_errors(v, endp);
  90}
  91
  92#if ULONG_MAX != ULLONG_MAX
  93unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base)
  94{
  95        unsigned long v;
  96        char *endptr;
  97
  98        if (!endp) endp = &endptr;
  99        *endp = (char*) arg;
 100
 101        if (!isalnum(arg[0])) return ret_ERANGE();
 102        errno = 0;
 103        v = strtoul(arg, endp, base);
 104        return handle_errors(v, endp);
 105}
 106
 107long FAST_FUNC bb_strtol(const char *arg, char **endp, int base)
 108{
 109        long v;
 110        char *endptr;
 111        char first;
 112
 113        if (!endp) endp = &endptr;
 114        *endp = (char*) arg;
 115
 116        first = (arg[0] != '-' ? arg[0] : arg[1]);
 117        if (!isalnum(first)) return ret_ERANGE();
 118
 119        errno = 0;
 120        v = strtol(arg, endp, base);
 121        return handle_errors(v, endp);
 122}
 123#endif
 124
 125#if UINT_MAX != ULONG_MAX
 126unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base)
 127{
 128        unsigned long v;
 129        char *endptr;
 130
 131        if (!endp) endp = &endptr;
 132        *endp = (char*) arg;
 133
 134        if (!isalnum(arg[0])) return ret_ERANGE();
 135        errno = 0;
 136        v = strtoul(arg, endp, base);
 137        if (v > UINT_MAX) return ret_ERANGE();
 138        return handle_errors(v, endp);
 139}
 140
 141int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base)
 142{
 143        long v;
 144        char *endptr;
 145        char first;
 146
 147        if (!endp) endp = &endptr;
 148        *endp = (char*) arg;
 149
 150        first = (arg[0] != '-' ? arg[0] : arg[1]);
 151        if (!isalnum(first)) return ret_ERANGE();
 152
 153        errno = 0;
 154        v = strtol(arg, endp, base);
 155        if (v > INT_MAX) return ret_ERANGE();
 156        if (v < INT_MIN) return ret_ERANGE();
 157        return handle_errors(v, endp);
 158}
 159#endif
 160