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

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

Modify strtol implementation to use intmax_t. Add strtoimax() and strtoumax().

  • Property mode set to 100644
File size: 10.4 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 Backend for integer conversions.
33 */
34
35#define LIBPOSIX_INTERNAL
36
37#include "../internal/common.h"
38#include "../stdlib.h"
39
40#include "../ctype.h"
41#include "../errno.h"
42#include "../inttypes.h"
43#include "../limits.h"
44
45#define intmax_t posix_intmax_t
46#define uintmax_t posix_uintmax_t
47
48/**
49 * Decides whether a digit belongs to a particular base.
50 *
51 * @param c Character representation of the digit.
52 * @param base Base against which the digit shall be tested.
53 * @return True if the digit belongs to the base, false otherwise.
54 */
55static inline bool is_digit_in_base(int c, int base)
56{
57 if (base <= 10) {
58 return c >= '0' && c < '0' + base;
59 } else {
60 return isdigit(c) ||
61 (tolower(c) >= 'a' && tolower(c) < ('a' + base - 10));
62 }
63}
64
65/**
66 * Derive a digit from its character representation.
67 *
68 * @param c Character representation of the digit.
69 * @return Digit value represented by an integer.
70 */
71static inline int digit_value(int c)
72{
73 if (c <= '9') {
74 return c - '0';
75 } else {
76 return 10 + tolower(c) - 'a';
77 }
78}
79
80/**
81 * Generic function for parsing an integer from it's string representation.
82 * Different variants differ in lower and upper bounds.
83 * The parsed string returned by this function is always positive, sign
84 * information is provided via a dedicated parameter.
85 *
86 * @param nptr Input string.
87 * @param endptr If non-NULL, *endptr is set to the position of the first
88 * unrecognized character. If no digit has been parsed, value of
89 * nptr is stored there (regardless of any skipped characters at the
90 * beginning).
91 * @param base Expected base of the string representation. If 0, base is
92 * determined to be decimal, octal or hexadecimal using the same rules
93 * as C syntax. Otherwise, value must be between 2 and 36, inclusive.
94 * @param min_value Lower bound for the resulting conversion.
95 * @param max_value Upper bound for the resulting conversion.
96 * @param out_negative Either NULL for unsigned conversion or a pointer to the
97 * bool variable into which shall be placed the negativity of the resulting
98 * converted value.
99 * @return The absolute value of the parsed value, or the closest in-range value
100 * if the parsed value is out of range. If the input is invalid, zero is
101 * returned and errno is set to EINVAL.
102 */
103static inline uintmax_t internal_strtol(
104 const char *restrict nptr, char **restrict endptr, int base,
105 const intmax_t min_value, const uintmax_t max_value,
106 bool *restrict out_negative)
107{
108 if (nptr == NULL) {
109 errno = EINVAL;
110 return 0;
111 }
112
113 if (base < 0 || base == 1 || base > 36) {
114 errno = EINVAL;
115 return 0;
116 }
117
118 /* The maximal absolute value that can be returned in this run.
119 * Depends on sign.
120 */
121 uintmax_t real_max_value = max_value;
122
123 /* Current index in the input string. */
124 size_t i = 0;
125 bool negative = false;
126
127 /* Skip whitespace. */
128 while (isspace(nptr[i])) {
129 i++;
130 }
131
132 /* Parse sign. */
133 switch (nptr[i]) {
134 case '-':
135 negative = true;
136
137 /* The strange computation is are there to avoid a corner case
138 * where -min_value can't be represented in intmax_t.
139 * (I'm not exactly sure what the semantics are in such a
140 * case, but this should be safe for any case.)
141 */
142 real_max_value = (min_value == 0)
143 ? 0
144 :(((uintmax_t) -(min_value + 1)) + 1);
145
146 /* fallthrough */
147 case '+':
148 i++;
149 }
150
151 /* Figure out the base. */
152 switch (base) {
153 case 0:
154 if (nptr[i] == '0') {
155 if (tolower(nptr[i + 1]) == 'x') {
156 /* 0x... is hex. */
157 base = 16;
158 i += 2;
159 } else {
160 /* 0... is octal. */
161 base = 8;
162 }
163 } else {
164 /* Anything else is decimal by default. */
165 base = 10;
166 }
167 break;
168 case 16:
169 /* Allow hex number to be prefixed with "0x". */
170 if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
171 i += 2;
172 }
173 break;
174 }
175
176 if (!is_digit_in_base(nptr[i], base)) {
177 /* No digits to parse, invalid input. */
178
179 errno = EINVAL;
180 if (endptr != NULL) {
181 *endptr = (char *) nptr;
182 }
183 return 0;
184 }
185
186 /* Maximal value to which a digit can be added without a risk
187 * of overflow.
188 */
189 uintmax_t max_safe_value = (real_max_value - base + 1) / base;
190
191 uintmax_t result = 0;
192
193 if (real_max_value == 0) {
194 /* Special case when a negative number is parsed as
195 * unsigned integer. Only -0 is accepted.
196 */
197
198 while (is_digit_in_base(nptr[i], base)) {
199 if (nptr[i] != '0') {
200 errno = ERANGE;
201 result = 0;
202 }
203 i++;
204 }
205 }
206
207 while (is_digit_in_base(nptr[i], base)) {
208 int digit = digit_value(nptr[i]);
209
210 if (result > max_safe_value) {
211 /* corner case, check for overflow */
212
213 uintmax_t boundary = (real_max_value - digit) / base;
214
215 if (result > boundary) {
216 /* overflow */
217 errno = ERANGE;
218 result = real_max_value;
219 break;
220 }
221 }
222
223 result = result * base + digit;
224 i++;
225 }
226
227 if (endptr != NULL) {
228 /* Move the pointer to the end of the number,
229 * in case it isn't there already.
230 */
231 while (is_digit_in_base(nptr[i], base)) {
232 i++;
233 }
234
235 *endptr = (char *) &nptr[i];
236 }
237 if (out_negative != NULL) {
238 *out_negative = negative;
239 }
240 return result;
241}
242
243/**
244 * Convert a string to an integer.
245 *
246 * @param nptr Input string.
247 * @return Result of the conversion.
248 */
249int posix_atoi(const char *nptr)
250{
251 bool neg = false;
252 uintmax_t result =
253 internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
254
255 return (neg ? ((int) -result) : (int) result);
256}
257
258/**
259 * Convert a string to a long integer.
260 *
261 * @param nptr Input string.
262 * @return Result of the conversion.
263 */
264long posix_atol(const char *nptr)
265{
266 bool neg = false;
267 uintmax_t result =
268 internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
269
270 return (neg ? ((long) -result) : (long) result);
271}
272
273/**
274 * Convert a string to a long long integer.
275 *
276 * @param nptr Input string.
277 * @return Result of the conversion.
278 */
279long long posix_atoll(const char *nptr)
280{
281 bool neg = false;
282 uintmax_t result =
283 internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
284
285 return (neg ? ((long long) -result) : (long long) result);
286}
287
288/**
289 * Convert a string to a long integer.
290 *
291 * @param nptr Input string.
292 * @param endptr Pointer to the final part of the string which
293 * was not used for conversion.
294 * @param base Expected base of the string representation.
295 * @return Result of the conversion.
296 */
297long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
298{
299 bool neg = false;
300 uintmax_t result =
301 internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
302
303 return (neg ? ((long) -result) : ((long) result));
304}
305
306/**
307 * Convert a string to a long long integer.
308 *
309 * @param nptr Input string.
310 * @param endptr Pointer to the final part of the string which
311 * was not used for conversion.
312 * @param base Expected base of the string representation.
313 * @return Result of the conversion.
314 */
315long long posix_strtoll(
316 const char *restrict nptr, char **restrict endptr, int base)
317{
318 bool neg = false;
319 uintmax_t result =
320 internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
321
322 return (neg ? ((long long) -result) : (long long) result);
323}
324
325/**
326 * Convert a string to a largest signed integer type.
327 *
328 * @param nptr Input string.
329 * @param endptr Pointer to the final part of the string which
330 * was not used for conversion.
331 * @param base Expected base of the string representation.
332 * @return Result of the conversion.
333 */
334intmax_t posix_strtoimax(
335 const char *restrict nptr, char **restrict endptr, int base)
336{
337 bool neg = false;
338 uintmax_t result =
339 internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
340
341 return (neg ? ((intmax_t) -result) : (intmax_t) result);
342}
343
344/**
345 * Convert a string to an unsigned long integer.
346 *
347 * @param nptr Input string.
348 * @param endptr Pointer to the final part of the string which
349 * was not used for conversion.
350 * @param base Expected base of the string representation.
351 * @return Result of the conversion.
352 */
353unsigned long posix_strtoul(
354 const char *restrict nptr, char **restrict endptr, int base)
355{
356 uintmax_t result =
357 internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
358
359 return (unsigned long) result;
360}
361
362/**
363 * Convert a string to an unsigned long long integer.
364 *
365 * @param nptr Input string.
366 * @param endptr Pointer to the final part of the string which
367 * was not used for conversion.
368 * @param base Expected base of the string representation.
369 * @return Result of the conversion.
370 */
371unsigned long long posix_strtoull(
372 const char *restrict nptr, char **restrict endptr, int base)
373{
374 uintmax_t result =
375 internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
376
377 return (unsigned long long) result;
378}
379
380/**
381 * Convert a string to a largest unsigned integer type.
382 *
383 * @param nptr Input string.
384 * @param endptr Pointer to the final part of the string which
385 * was not used for conversion.
386 * @param base Expected base of the string representation.
387 * @return Result of the conversion.
388 */
389uintmax_t posix_strtoumax(
390 const char *restrict nptr, char **restrict endptr, int base)
391{
392 uintmax_t result =
393 internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
394
395 return result;
396}
397
398/** @}
399 */
Note: See TracBrowser for help on using the repository browser.