diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-27 15:12:16 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-27 15:12:16 +0000 |
commit | 3ece72dc3f95d195924c760f9ee5059e35908564 (patch) | |
tree | 89ab0d32e2758a2c233076c25421a852834a997e /libbb/bb_strtonum.c | |
parent | 459903bd4e270ab4884ba9577516f9b2753898b0 (diff) | |
download | busybox-w32-3ece72dc3f95d195924c760f9ee5059e35908564.tar.gz busybox-w32-3ece72dc3f95d195924c760f9ee5059e35908564.tar.bz2 busybox-w32-3ece72dc3f95d195924c760f9ee5059e35908564.zip |
svn add bb_strtonum.c :(
Diffstat (limited to 'libbb/bb_strtonum.c')
-rw-r--r-- | libbb/bb_strtonum.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/libbb/bb_strtonum.c b/libbb/bb_strtonum.c new file mode 100644 index 000000000..7e28eeb86 --- /dev/null +++ b/libbb/bb_strtonum.c | |||
@@ -0,0 +1,147 @@ | |||
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 tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | /* On exit: errno = 0 only if there was non-empty, '\0' terminated value | ||
13 | * errno = EINVAL if value was not '\0' terminated, but othervise 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 | */ | ||
21 | |||
22 | static unsigned long long ret_ERANGE(void) | ||
23 | { | ||
24 | errno = ERANGE; /* this ain't as small as it looks (on glibc) */ | ||
25 | return ULLONG_MAX; | ||
26 | } | ||
27 | |||
28 | static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) | ||
29 | { | ||
30 | if (endp) *endp = endptr; | ||
31 | |||
32 | /* Check for the weird "feature": | ||
33 | * a "-" string is apparently a valid "number" for strto[u]l[l]! | ||
34 | * It returns zero and errno is 0! :( */ | ||
35 | if (endptr[-1] == '-') | ||
36 | return ret_ERANGE(); | ||
37 | |||
38 | /* errno is already set to ERANGE by strtoXXX if value overflowed */ | ||
39 | if (endptr[0]) { | ||
40 | /* "1234abcg" or out-of-range? */ | ||
41 | if (isalnum(endptr[0]) || errno) | ||
42 | return ret_ERANGE(); | ||
43 | /* good number, just suspicious terminator */ | ||
44 | errno = EINVAL; | ||
45 | } | ||
46 | return v; | ||
47 | } | ||
48 | |||
49 | |||
50 | unsigned long long bb_strtoull(const char *arg, char **endp, int base) | ||
51 | { | ||
52 | char *endptr; | ||
53 | |||
54 | /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */ | ||
55 | /* I don't think that this is right. Preventing this... */ | ||
56 | if (!isalnum(arg[0])) return ret_ERANGE(); | ||
57 | |||
58 | /* not 100% correct for lib func, but convenient for the caller */ | ||
59 | errno = 0; | ||
60 | return handle_errors(strtoull(arg, &endptr, base), endp, endptr); | ||
61 | } | ||
62 | |||
63 | long long bb_strtoll(const char *arg, char **endp, int base) | ||
64 | { | ||
65 | char *endptr; | ||
66 | |||
67 | if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE(); | ||
68 | errno = 0; | ||
69 | return handle_errors(strtoll(arg, &endptr, base), endp, endptr); | ||
70 | } | ||
71 | |||
72 | #if ULONG_MAX != ULLONG_MAX | ||
73 | unsigned long bb_strtoul(const char *arg, char **endp, int base) | ||
74 | { | ||
75 | char *endptr; | ||
76 | |||
77 | if (!isalnum(arg[0])) return ret_ERANGE(); | ||
78 | errno = 0; | ||
79 | return handle_errors(strtoul(arg, &endptr, base), endp, endptr); | ||
80 | } | ||
81 | |||
82 | long bb_strtol(const char *arg, char **endp, int base) | ||
83 | { | ||
84 | char *endptr; | ||
85 | |||
86 | if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE(); | ||
87 | errno = 0; | ||
88 | return handle_errors(strtol(arg, &endptr, base), endp, endptr); | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | #if UINT_MAX != ULONG_MAX | ||
93 | unsigned bb_strtou(const char *arg, char **endp, int base) | ||
94 | { | ||
95 | unsigned long v; | ||
96 | char *endptr; | ||
97 | |||
98 | if (!isalnum(arg[0])) return ret_ERANGE(); | ||
99 | errno = 0; | ||
100 | v = strtoul(arg, &endptr, base); | ||
101 | if (v > UINT_MAX) return ret_ERANGE(); | ||
102 | return handle_errors(v, endp, endptr); | ||
103 | } | ||
104 | |||
105 | int bb_strtoi(const char *arg, char **endp, int base) | ||
106 | { | ||
107 | long v; | ||
108 | char *endptr; | ||
109 | |||
110 | if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE(); | ||
111 | errno = 0; | ||
112 | v = strtol(arg, &endptr, base); | ||
113 | if (v > INT_MAX) return ret_ERANGE(); | ||
114 | if (v < INT_MIN) return ret_ERANGE(); | ||
115 | return handle_errors(v, endp, endptr); | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | /* Floating point */ | ||
120 | |||
121 | #if 0 | ||
122 | |||
123 | #include <math.h> /* just for HUGE_VAL */ | ||
124 | #define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9) | ||
125 | double bb_strtod(const char *arg, char **endp) | ||
126 | { | ||
127 | double v; | ||
128 | char *endptr; | ||
129 | |||
130 | if (arg[0] != '-' && NOT_DIGIT(arg[0])) goto err; | ||
131 | errno = 0; | ||
132 | v = strtod(arg, &endptr); | ||
133 | if (endp) *endp = endptr; | ||
134 | if (endptr[0]) { | ||
135 | /* "1234abcg" or out-of-range? */ | ||
136 | if (isalnum(endptr[0]) || errno) { | ||
137 | err: | ||
138 | errno = ERANGE; | ||
139 | return HUGE_VAL; | ||
140 | } | ||
141 | /* good number, just suspicious terminator */ | ||
142 | errno = EINVAL; | ||
143 | } | ||
144 | return v; | ||
145 | } | ||
146 | |||
147 | #endif | ||