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
ret_ERANGE(void)32 static 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
handle_errors(unsigned long long v,char ** endp)38 static 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
bb_strtoull(const char * arg,char ** endp,int base)54 unsigned 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
bb_strtoll(const char * arg,char ** endp,int base)72 long 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
bb_strtoul(const char * arg,char ** endp,int base)93 unsigned 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
bb_strtol(const char * arg,char ** endp,int base)107 long 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
bb_strtou(const char * arg,char ** endp,int base)126 unsigned 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
bb_strtoi(const char * arg,char ** endp,int base)141 int 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