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