1 /* vi: set sw=4 ts=4: */
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
12 /* On exit: errno = 0 only if there was non-empty, '\0' terminated value
13 * errno = EINVAL if value was not '\0' terminated, but otherwise ok
14 * Return value is still valid, caller should just check whether end[0]
15 * is a valid terminating char for particular case. OTOH, if caller
16 * requires '\0' terminated input, [s]he can just check errno == 0.
17 * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
18 * errno = ERANGE if value is out of range, missing, etc.
19 * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
20 * return value is all-ones in this case.
24 * const char *minus = "-";
26 * bb_strtoi(minus, &endptr, 0); // must set ERANGE
27 * printf("minus:%p endptr:%p errno:%d EINVAL:%d\n", minus, endptr, errno, EINVAL);
29 * bb_strtoi("-0-", &endptr, 0); // must set EINVAL and point to second '-'
30 * printf("endptr[0]:%c errno:%d EINVAL:%d\n", endptr[0], errno, EINVAL);
33 static unsigned long long ret_ERANGE(void)
35 errno
= ERANGE
; /* this ain't as small as it looks (on glibc) */
39 static unsigned long long handle_errors(unsigned long long v
, char **endp
)
41 char next_ch
= **endp
;
43 /* errno is already set to ERANGE by strtoXXX if value overflowed */
45 /* "1234abcg" or out-of-range? */
46 if (isalnum(next_ch
) || errno
)
48 /* good number, just suspicious terminator */
55 unsigned long long FAST_FUNC
bb_strtoull(const char *arg
, char **endp
, int base
)
60 if (!endp
) endp
= &endptr
;
63 /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */
64 /* I don't think that this is right. Preventing this... */
65 //if (!isalnum(arg[0])) return ret_ERANGE();
66 char first
= (arg
[0] != '-' ? arg
[0] : arg
[1]);
67 if (!isalnum(first
)) return ret_ERANGE();
69 /* not 100% correct for lib func, but convenient for the caller */
71 v
= strtoull(arg
, endp
, base
);
72 return handle_errors(v
, endp
);
75 long long FAST_FUNC
bb_strtoll(const char *arg
, char **endp
, int base
)
81 if (!endp
) endp
= &endptr
;
84 /* Check for the weird "feature":
85 * a "-" string is apparently a valid "number" for strto[u]l[l]!
86 * It returns zero and errno is 0! :( */
87 first
= (arg
[0] != '-' ? arg
[0] : arg
[1]);
88 if (!isalnum(first
)) return ret_ERANGE();
91 v
= strtoll(arg
, endp
, base
);
92 return handle_errors(v
, endp
);
95 #if ULONG_MAX != ULLONG_MAX
96 unsigned long FAST_FUNC
bb_strtoul(const char *arg
, char **endp
, int base
)
101 if (!endp
) endp
= &endptr
;
104 if (!isalnum(arg
[0])) return ret_ERANGE();
107 v
= strtoul(arg
, endp
, base
);
108 return handle_errors(v
, endp
);
111 long FAST_FUNC
bb_strtol(const char *arg
, char **endp
, int base
)
117 if (!endp
) endp
= &endptr
;
120 first
= (arg
[0] != '-' ? arg
[0] : arg
[1]);
121 if (!isalnum(first
)) return ret_ERANGE();
124 v
= strtol(arg
, endp
, base
);
125 return handle_errors(v
, endp
);
129 #if UINT_MAX != ULONG_MAX
130 unsigned FAST_FUNC
bb_strtou(const char *arg
, char **endp
, int base
)
135 if (!endp
) endp
= &endptr
;
138 if (!isalnum(arg
[0])) return ret_ERANGE();
141 v
= strtoul(arg
, endp
, base
);
142 if (v
> UINT_MAX
) return ret_ERANGE();
143 return handle_errors(v
, endp
);
146 int FAST_FUNC
bb_strtoi(const char *arg
, char **endp
, int base
)
152 if (!endp
) endp
= &endptr
;
155 first
= (arg
[0] != '-' ? arg
[0] : arg
[1]);
156 if (!isalnum(first
)) return ret_ERANGE();
159 v
= strtol(arg
, endp
, base
);
160 if (v
> INT_MAX
) return ret_ERANGE();
161 if (v
< INT_MIN
) return ret_ERANGE();
162 return handle_errors(v
, endp
);