source: mainline/uspace/lib/posix/stdlib/strtol.c@ 6b4c64a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6b4c64a was 2b83add, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Add string to int conversion functions and implement some in stdlib.h

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Zarevucky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libposix
30 * @{
31 */
32/** @file
33 */
34
35#define LIBPOSIX_INTERNAL
36
37#include "../internal/common.h"
38#include "../stdlib.h"
39#include <errno.h> // FIXME: use POSIX errno
40#include "../limits.h"
41#include "../ctype.h"
42
43// TODO: documentation
44
45static inline bool is_digit_in_base(int c, int base)
46{
47 if (base <= 10) {
48 return c >= '0' && c < '0' + base;
49 } else {
50 return isdigit(c) ||
51 (tolower(c) >= 'a' && tolower(c) < ('a' + base - 10));
52 }
53}
54
55static inline int get_digit_in_base(int c, int base)
56{
57 if (c <= '9') {
58 return c - '0';
59 } else {
60 return 10 + tolower(c) - 'a';
61 }
62}
63
64static inline unsigned long long internal_strtol(
65 const char *restrict nptr, char **restrict endptr, int base,
66 const long long min_value, const unsigned long long max_value,
67 bool *restrict out_negative)
68{
69 if (nptr == NULL) {
70 errno = EINVAL;
71 return 0;
72 }
73
74 if (base < 0 || base == 1 || base > 36) {
75 errno = EINVAL;
76 return 0;
77 }
78
79 unsigned long long real_max_value = max_value;
80
81 /* Current index in the input string. */
82 int i = 0;
83 bool negative = false;
84
85 /* Skip whitespace. */
86 while (isspace(nptr[i])) {
87 i++;
88 }
89
90 /* Parse sign. */
91 switch (nptr[i]) {
92 case '-':
93 negative = true;
94 real_max_value = -min_value;
95 /* fallthrough */
96 case '+':
97 i++;
98 }
99
100 /* Figure out the base. */
101 switch (base) {
102 case 0:
103 if (nptr[i] == '0') {
104 if (tolower(nptr[i + 1]) == 'x') {
105 base = 16;
106 i += 2;
107 } else {
108 base = 8;
109 }
110 } else {
111 base = 10;
112 }
113 break;
114 case 16:
115 if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
116 i += 2;
117 }
118 break;
119 }
120
121 if (!is_digit_in_base(nptr[i], base)) {
122 /* No digits to parse, invalid input. */
123
124 errno = EINVAL;
125 if (endptr != NULL) {
126 *endptr = (char *) nptr;
127 }
128 return 0;
129 }
130
131 /* Maximal value to which a digit can be added without a risk
132 * of overflow.
133 */
134 unsigned long long max_safe_value = (real_max_value - base + 1) / base;
135
136 unsigned long long result = 0;
137
138 if (real_max_value == 0) {
139 /* Special case when a negative number is parsed as
140 * unsigned integer. Only -0 is accepted.
141 */
142
143 while (is_digit_in_base(nptr[i], base)) {
144 if (nptr[i] != '0') {
145 errno = ERANGE;
146 result = max_value;
147 }
148 i++;
149 }
150 }
151
152 while (is_digit_in_base(nptr[i], base)) {
153 int digit = get_digit_in_base(nptr[i], base);
154
155 if (result > max_safe_value) {
156 /* corner case, check for overflow */
157
158 unsigned long long
159 boundary = (real_max_value - digit) / base;
160
161 if (result > boundary) {
162 /* overflow */
163 errno = ERANGE;
164 result = max_value;
165 break;
166 }
167 }
168
169 result = result * base + digit;
170 i++;
171 }
172
173 if (endptr != NULL) {
174 /* Move the pointer to the end of the number,
175 * in case it isn't there already.
176 */
177 while (is_digit_in_base(nptr[i], base)) {
178 i++;
179 }
180
181 *endptr = (char *) &nptr[i];
182 }
183 if (out_negative != NULL) {
184 *out_negative = negative;
185 }
186 return result;
187}
188
189int posix_atoi(const char *nptr)
190{
191 bool neg = false;
192 unsigned long long result =
193 internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
194
195 return (int) (neg ? -result : result);
196}
197
198long posix_atol(const char *nptr)
199{
200 bool neg = false;
201 unsigned long long result =
202 internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
203
204 return (long) (neg ? -result : result);
205}
206
207long long posix_atoll(const char *nptr)
208{
209 bool neg = false;
210 unsigned long long result =
211 internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
212
213 return (long long) (neg ? -result : result);
214}
215
216long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
217{
218 bool neg = false;
219 unsigned long long result =
220 internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
221
222 return (long) (neg ? -result : result);
223}
224
225long long posix_strtoll(
226 const char *restrict nptr, char **restrict endptr, int base)
227{
228 bool neg = false;
229 unsigned long long result =
230 internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
231
232 return (long long) (neg ? -result : result);
233}
234
235unsigned long posix_strtoul(
236 const char *restrict nptr, char **restrict endptr, int base)
237{
238 unsigned long long result =
239 internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
240
241 return (unsigned long) result;
242}
243
244unsigned long long posix_strtoull(
245 const char *restrict nptr, char **restrict endptr, int base)
246{
247 return internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
248}
249
250
251/** @}
252 */
253
Note: See TracBrowser for help on using the repository browser.