blob: 2185017b02533ef81e4f9f8844edf8c30a161a63 [file] [log] [blame]
Denis Vlasenko3ece72d2006-11-27 15:12:16 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Denis Vlasenko3ece72d2006-11-27 15:12:16 +00008 */
Denis Vlasenko3ece72d2006-11-27 15:12:16 +00009#include "libbb.h"
10
11/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
Denis Vlasenko49a5eba2008-07-23 08:41:08 +000012 * errno = EINVAL if value was not '\0' terminated, but otherwise ok
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000013 * 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 )
Denis Vlasenko666da5e2006-12-26 18:17:42 +000019 * return value is all-ones in this case.
Denis Vlasenkof19817d2008-07-18 18:17:10 +000020 *
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);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000030 */
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
Denys Vlasenkoba658722011-12-22 13:00:32 +010038static unsigned long long handle_errors(unsigned long long v, char **endp)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000039{
Denys Vlasenkoba658722011-12-22 13:00:32 +010040 char next_ch = **endp;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000041
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000042 /* errno is already set to ERANGE by strtoXXX if value overflowed */
Denys Vlasenkoba658722011-12-22 13:00:32 +010043 if (next_ch) {
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000044 /* "1234abcg" or out-of-range? */
Denys Vlasenkoba658722011-12-22 13:00:32 +010045 if (isalnum(next_ch) || errno)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000046 return ret_ERANGE();
47 /* good number, just suspicious terminator */
48 errno = EINVAL;
49 }
50 return v;
51}
52
53
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000054unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000055{
Denis Vlasenkodf381882006-11-28 10:54:16 +000056 unsigned long long v;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000057 char *endptr;
58
Denys Vlasenkoba658722011-12-22 13:00:32 +010059 if (!endp) endp = &endptr;
60 *endp = (char*) arg;
61
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000062 /* 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;
Denys Vlasenkoba658722011-12-22 13:00:32 +010068 v = strtoull(arg, endp, base);
69 return handle_errors(v, endp);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000070}
71
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000072long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000073{
Denis Vlasenkodf381882006-11-28 10:54:16 +000074 unsigned long long v;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000075 char *endptr;
Denys Vlasenkoba658722011-12-22 13:00:32 +010076 char first;
77
78 if (!endp) endp = &endptr;
79 *endp = (char*) arg;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000080
Denis Vlasenkof19817d2008-07-18 18:17:10 +000081 /* 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! :( */
Denys Vlasenko93ef5dd2018-10-30 23:24:18 +010084 first = (arg[0] != '-' ? arg[0] : arg[1]);
Denis Vlasenkof19817d2008-07-18 18:17:10 +000085 if (!isalnum(first)) return ret_ERANGE();
86
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000087 errno = 0;
Denys Vlasenkoba658722011-12-22 13:00:32 +010088 v = strtoll(arg, endp, base);
89 return handle_errors(v, endp);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000090}
91
92#if ULONG_MAX != ULLONG_MAX
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000093unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000094{
Denis Vlasenkodf381882006-11-28 10:54:16 +000095 unsigned long v;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +000096 char *endptr;
97
Denys Vlasenkoba658722011-12-22 13:00:32 +010098 if (!endp) endp = &endptr;
99 *endp = (char*) arg;
100
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000101 if (!isalnum(arg[0])) return ret_ERANGE();
102 errno = 0;
Denys Vlasenkoba658722011-12-22 13:00:32 +0100103 v = strtoul(arg, endp, base);
104 return handle_errors(v, endp);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000105}
106
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000107long FAST_FUNC bb_strtol(const char *arg, char **endp, int base)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000108{
Denis Vlasenkodf381882006-11-28 10:54:16 +0000109 long v;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000110 char *endptr;
Denys Vlasenkoba658722011-12-22 13:00:32 +0100111 char first;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000112
Denys Vlasenkoba658722011-12-22 13:00:32 +0100113 if (!endp) endp = &endptr;
114 *endp = (char*) arg;
115
116 first = (arg[0] != '-' ? arg[0] : arg[1]);
Denis Vlasenkof19817d2008-07-18 18:17:10 +0000117 if (!isalnum(first)) return ret_ERANGE();
118
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000119 errno = 0;
Denys Vlasenkoba658722011-12-22 13:00:32 +0100120 v = strtol(arg, endp, base);
121 return handle_errors(v, endp);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000122}
123#endif
124
125#if UINT_MAX != ULONG_MAX
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000126unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000127{
128 unsigned long v;
129 char *endptr;
130
Denys Vlasenkoba658722011-12-22 13:00:32 +0100131 if (!endp) endp = &endptr;
132 *endp = (char*) arg;
133
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000134 if (!isalnum(arg[0])) return ret_ERANGE();
135 errno = 0;
Denys Vlasenkoba658722011-12-22 13:00:32 +0100136 v = strtoul(arg, endp, base);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000137 if (v > UINT_MAX) return ret_ERANGE();
Denys Vlasenkoba658722011-12-22 13:00:32 +0100138 return handle_errors(v, endp);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000139}
140
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000141int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base)
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000142{
143 long v;
144 char *endptr;
Denys Vlasenkoba658722011-12-22 13:00:32 +0100145 char first;
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000146
Denys Vlasenkoba658722011-12-22 13:00:32 +0100147 if (!endp) endp = &endptr;
148 *endp = (char*) arg;
149
150 first = (arg[0] != '-' ? arg[0] : arg[1]);
Denis Vlasenkof19817d2008-07-18 18:17:10 +0000151 if (!isalnum(first)) return ret_ERANGE();
152
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000153 errno = 0;
Denys Vlasenkoba658722011-12-22 13:00:32 +0100154 v = strtol(arg, endp, base);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000155 if (v > INT_MAX) return ret_ERANGE();
156 if (v < INT_MIN) return ret_ERANGE();
Denys Vlasenkoba658722011-12-22 13:00:32 +0100157 return handle_errors(v, endp);
Denis Vlasenko3ece72d2006-11-27 15:12:16 +0000158}
159#endif