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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8a45707d was fdf97f6, checked in by Vojtech Horky <vojtechhorky@…>, 12 years ago

Libposix functions are without posix_ prefix

Prior this commit, libposix headers declared all functions as posix_*
and used macros to rename e.g. strncpy to posix_strncpy in all (ported)
sources.

After this change, libposix headers look as normal POSIX compliant headers
(well, almost) and no renaming is done in the source codei (of the ported
applications). Instead, the renaming is done at object files level to
bypass weird problems that are bound to happen if you use macros.

The scheme is following. libposix headers use special macro to declare
the names. When included from outside, the functions have their normal
(standard) names. When included from the libposix sources, posix_ prefix
is added. Thus, when libposix is compiled and linked, it contains the
posix_* naming while compiling of ported software uses the normal
non-prefixed versions. This way the posix_* can use HelenOS libc without
any problem. Before linking, the posix_* prefix is removed from all
symbols and special prefix helenos_libc_ is added to all functions
that exists in our (HelenOS) libc and its name clashes with the POSIX
one.

The following happens, for example, to the open() function that exists in
both libposix and in libc.

  • Headers and sources of libc are left intact.
  • Copy of libc.a is made and to all clashing functions is added the helenos_libc prefix. This library is called libc4posix.a.
  • POSIX_DEF(open)(const char *) is used in libposix headers. This macro expands to plain open when included from the "outside world". But it expands to posix_open when included from libposix sources.
  • Libposix is compiled and linked, containing posix_open() that internally calls open() [the original one from libc].
  • Libposix is transformed - all open() are replaced with prefix variant: helenos_libc_open() and all posix_open() are replaced with open(). The transformed library is stored as libposixaslibc.a

Binutils and PCC are then linked with libc4posix and libposixaslibc
libraries instead of libc and libposix as was done previously.

WARNING: it looks that binutils, PCC and MSIM still works but not all
architectures were tested.

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