]>
Commit | Line | Data |
---|---|---|
2f6d1f1b | 1 | /* Convert string representation of a number into an integer value. |
5290baf0 | 2 | Copyright (C) 1991, 92, 94, 95, 96, 97 Free Software Foundation, Inc. |
f0e44959 UD |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #if HAVE_CONFIG_H | |
e09675dd JM |
21 | # include <config.h> |
22 | #endif | |
23 | ||
4356cfd7 RM |
24 | #ifdef _LIBC |
25 | # define USE_NUMBER_GROUPING | |
26 | # define STDC_HEADERS | |
6c685ebb | 27 | # define HAVE_LIMITS_H |
4356cfd7 RM |
28 | #endif |
29 | ||
28f540f4 | 30 | #include <ctype.h> |
28f540f4 | 31 | #include <errno.h> |
6c685ebb JM |
32 | #ifndef errno |
33 | extern int errno; | |
34 | #endif | |
c4029823 | 35 | #ifndef __set_errno |
f0e44959 | 36 | # define __set_errno(Val) errno = (Val) |
c4029823 | 37 | #endif |
6c685ebb | 38 | |
b25c5d66 | 39 | #ifdef HAVE_LIMITS_H |
6c685ebb JM |
40 | # include <limits.h> |
41 | #endif | |
28f540f4 | 42 | |
e09675dd JM |
43 | #ifdef STDC_HEADERS |
44 | # include <stddef.h> | |
45 | # include <stdlib.h> | |
84724245 | 46 | # include <string.h> |
e09675dd JM |
47 | #else |
48 | # ifndef NULL | |
49 | # define NULL 0 | |
50 | # endif | |
51 | #endif | |
52 | ||
e09675dd JM |
53 | #ifdef USE_NUMBER_GROUPING |
54 | # include "../locale/localeinfo.h" | |
55 | #endif | |
f0bf9cb9 | 56 | |
2f6d1f1b | 57 | /* Nonzero if we are defining `strtoul' or `strtoull', operating on |
f0bf9cb9 RM |
58 | unsigned integers. */ |
59 | #ifndef UNSIGNED | |
e09675dd JM |
60 | # define UNSIGNED 0 |
61 | # define INT LONG int | |
f0bf9cb9 | 62 | #else |
e09675dd | 63 | # define INT unsigned LONG int |
28f540f4 RM |
64 | #endif |
65 | ||
75cd5204 | 66 | /* Determine the name. */ |
0501d603 UD |
67 | #ifdef USE_IN_EXTENDED_LOCALE_MODEL |
68 | # if UNSIGNED | |
69 | # ifdef USE_WIDE_CHAR | |
70 | # ifdef QUAD | |
71 | # define strtol __wcstoull_l | |
72 | # else | |
73 | # define strtol __wcstoul_l | |
74 | # endif | |
75cd5204 | 75 | # else |
0501d603 UD |
76 | # ifdef QUAD |
77 | # define strtol __strtoull_l | |
78 | # else | |
79 | # define strtol __strtoul_l | |
80 | # endif | |
75cd5204 RM |
81 | # endif |
82 | # else | |
0501d603 UD |
83 | # ifdef USE_WIDE_CHAR |
84 | # ifdef QUAD | |
85 | # define strtol __wcstoll_l | |
86 | # else | |
87 | # define strtol __wcstol_l | |
88 | # endif | |
75cd5204 | 89 | # else |
0501d603 UD |
90 | # ifdef QUAD |
91 | # define strtol __strtoll_l | |
92 | # else | |
93 | # define strtol __strtol_l | |
94 | # endif | |
75cd5204 RM |
95 | # endif |
96 | # endif | |
97 | #else | |
0501d603 UD |
98 | # if UNSIGNED |
99 | # ifdef USE_WIDE_CHAR | |
100 | # ifdef QUAD | |
101 | # define strtol wcstoull | |
102 | # else | |
103 | # define strtol wcstoul | |
104 | # endif | |
75cd5204 | 105 | # else |
0501d603 UD |
106 | # ifdef QUAD |
107 | # define strtol strtoull | |
108 | # else | |
109 | # define strtol strtoul | |
110 | # endif | |
75cd5204 RM |
111 | # endif |
112 | # else | |
0501d603 UD |
113 | # ifdef USE_WIDE_CHAR |
114 | # ifdef QUAD | |
115 | # define strtol wcstoll | |
116 | # else | |
117 | # define strtol wcstol | |
118 | # endif | |
119 | # else | |
120 | # ifdef QUAD | |
121 | # define strtol strtoll | |
122 | # endif | |
75cd5204 RM |
123 | # endif |
124 | # endif | |
125 | #endif | |
126 | ||
2f6d1f1b | 127 | /* If QUAD is defined, we are defining `strtoll' or `strtoull', |
28f540f4 RM |
128 | operating on `long long int's. */ |
129 | #ifdef QUAD | |
e09675dd JM |
130 | # define LONG long long |
131 | # undef LONG_MIN | |
132 | # define LONG_MIN LONG_LONG_MIN | |
133 | # undef LONG_MAX | |
134 | # define LONG_MAX LONG_LONG_MAX | |
135 | # undef ULONG_MAX | |
136 | # define ULONG_MAX ULONG_LONG_MAX | |
137 | # if __GNUC__ == 2 && __GNUC_MINOR__ < 7 | |
138 | /* Work around gcc bug with using this constant. */ | |
139 | static const unsigned long long int maxquad = ULONG_LONG_MAX; | |
140 | # undef ULONG_MAX | |
141 | # define ULONG_MAX maxquad | |
142 | # endif | |
28f540f4 | 143 | #else |
e09675dd | 144 | # define LONG long |
b8fe19fa RM |
145 | |
146 | #ifndef ULONG_MAX | |
147 | # define ULONG_MAX ((unsigned long) ~(unsigned long) 0) | |
148 | #endif | |
149 | #ifndef LONG_MAX | |
150 | # define LONG_MAX ((long int) (ULONG_MAX >> 1)) | |
151 | #endif | |
28f540f4 | 152 | #endif |
e09675dd | 153 | |
0501d603 UD |
154 | |
155 | /* We use this code also for the extended locale handling where the | |
156 | function gets as an additional argument the locale which has to be | |
157 | used. To access the values we have to redefine the _NL_CURRENT | |
158 | macro. */ | |
159 | #ifdef USE_IN_EXTENDED_LOCALE_MODEL | |
160 | # undef _NL_CURRENT | |
161 | # define _NL_CURRENT(category, item) \ | |
162 | (current->values[_NL_ITEM_INDEX (item)].string) | |
163 | # define LOCALE_PARAM , loc | |
164 | # define LOCALE_PARAM_DECL __locale_t loc; | |
165 | #else | |
166 | # define LOCALE_PARAM | |
167 | # define LOCALE_PARAM_DECL | |
168 | #endif | |
169 | ||
170 | ||
75cd5204 RM |
171 | #ifdef USE_WIDE_CHAR |
172 | # include <wchar.h> | |
173 | # include <wctype.h> | |
f0e44959 | 174 | # define L_(Ch) L##Ch |
75cd5204 RM |
175 | # define UCHAR_TYPE wint_t |
176 | # define STRING_TYPE wchar_t | |
0501d603 UD |
177 | # ifdef USE_IN_EXTENDED_LOCALE_MODEL |
178 | # define ISSPACE(Ch) __iswspace_l ((Ch), loc) | |
179 | # define ISALPHA(Ch) __iswalpha_l ((Ch), loc) | |
180 | # define TOUPPER(Ch) __towupper_l ((Ch), loc) | |
181 | # else | |
182 | # define ISSPACE(Ch) iswspace (Ch) | |
183 | # define ISALPHA(Ch) iswalpha (Ch) | |
184 | # define TOUPPER(Ch) towupper (Ch) | |
185 | # endif | |
186 | # else | |
2604afb1 UD |
187 | # if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) |
188 | # define IN_CTYPE_DOMAIN(c) 1 | |
189 | # else | |
190 | # define IN_CTYPE_DOMAIN(c) isascii(c) | |
191 | # endif | |
0501d603 UD |
192 | # define L_(Ch) Ch |
193 | # define UCHAR_TYPE unsigned char | |
194 | # define STRING_TYPE char | |
195 | # ifdef USE_IN_EXTENDED_LOCALE_MODEL | |
196 | # define ISSPACE(Ch) __isspace_l ((Ch), loc) | |
197 | # define ISALPHA(Ch) __isalpha_l ((Ch), loc) | |
198 | # define TOUPPER(Ch) __toupper_l ((Ch), loc) | |
199 | # else | |
2604afb1 UD |
200 | # define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch)) |
201 | # define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch)) | |
202 | # define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch)) | |
0501d603 | 203 | # endif |
75cd5204 RM |
204 | #endif |
205 | ||
e09675dd | 206 | #ifdef __STDC__ |
f0e44959 UD |
207 | # define INTERNAL(X) INTERNAL1(X) |
208 | # define INTERNAL1(X) __##X##_internal | |
209 | # define WEAKNAME(X) WEAKNAME1(X) | |
28f540f4 | 210 | #else |
f0e44959 | 211 | # define INTERNAL(X) __/**/X/**/_internal |
28f540f4 RM |
212 | #endif |
213 | ||
e09675dd | 214 | #ifdef USE_NUMBER_GROUPING |
f0bf9cb9 | 215 | /* This file defines a function to check for correct grouping. */ |
e09675dd JM |
216 | # include "grouping.h" |
217 | #endif | |
f0bf9cb9 RM |
218 | |
219 | ||
0501d603 | 220 | |
28f540f4 RM |
221 | /* Convert NPTR to an `unsigned long int' or `long int' in base BASE. |
222 | If BASE is 0 the base is determined by the presence of a leading | |
223 | zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. | |
224 | If BASE is < 2 or > 36, it is reset to 10. | |
225 | If ENDPTR is not NULL, a pointer to the character after the last | |
226 | one converted is stored in *ENDPTR. */ | |
f0bf9cb9 RM |
227 | |
228 | INT | |
0501d603 | 229 | INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM) |
75cd5204 RM |
230 | const STRING_TYPE *nptr; |
231 | STRING_TYPE **endptr; | |
28f540f4 | 232 | int base; |
f0bf9cb9 | 233 | int group; |
0501d603 | 234 | LOCALE_PARAM_DECL |
28f540f4 RM |
235 | { |
236 | int negative; | |
237 | register unsigned LONG int cutoff; | |
238 | register unsigned int cutlim; | |
239 | register unsigned LONG int i; | |
75cd5204 RM |
240 | register const STRING_TYPE *s; |
241 | register UCHAR_TYPE c; | |
242 | const STRING_TYPE *save, *end; | |
28f540f4 RM |
243 | int overflow; |
244 | ||
e09675dd | 245 | #ifdef USE_NUMBER_GROUPING |
0501d603 UD |
246 | # ifdef USE_IN_EXTENDED_LOCALE_MODEL |
247 | struct locale_data *current = loc->__locales[LC_NUMERIC]; | |
248 | # endif | |
f0bf9cb9 RM |
249 | /* The thousands character of the current locale. */ |
250 | wchar_t thousands; | |
251 | /* The numeric grouping specification of the current locale, | |
252 | in the format described in <locale.h>. */ | |
253 | const char *grouping; | |
254 | ||
255 | if (group) | |
256 | { | |
257 | grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); | |
258 | if (*grouping <= 0 || *grouping == CHAR_MAX) | |
259 | grouping = NULL; | |
260 | else | |
261 | { | |
262 | /* Figure out the thousands separator character. */ | |
263 | if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP), | |
264 | strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0) | |
265 | thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); | |
266 | if (thousands == L'\0') | |
267 | grouping = NULL; | |
268 | } | |
269 | } | |
270 | else | |
271 | grouping = NULL; | |
e09675dd | 272 | #endif |
f0bf9cb9 | 273 | |
28f540f4 | 274 | if (base < 0 || base == 1 || base > 36) |
2c6fe0bd UD |
275 | { |
276 | __set_errno (EINVAL); | |
277 | return 0; | |
278 | } | |
28f540f4 | 279 | |
da128169 | 280 | save = s = nptr; |
28f540f4 RM |
281 | |
282 | /* Skip white space. */ | |
75cd5204 | 283 | while (ISSPACE (*s)) |
28f540f4 | 284 | ++s; |
75cd5204 | 285 | if (*s == L_('\0')) |
28f540f4 RM |
286 | goto noconv; |
287 | ||
288 | /* Check for a sign. */ | |
75cd5204 | 289 | if (*s == L_('-')) |
28f540f4 RM |
290 | { |
291 | negative = 1; | |
292 | ++s; | |
293 | } | |
75cd5204 | 294 | else if (*s == L_('+')) |
28f540f4 RM |
295 | { |
296 | negative = 0; | |
297 | ++s; | |
298 | } | |
299 | else | |
300 | negative = 0; | |
301 | ||
75cd5204 | 302 | if (base == 16 && s[0] == L_('0') && TOUPPER (s[1]) == L_('X')) |
28f540f4 RM |
303 | s += 2; |
304 | ||
305 | /* If BASE is zero, figure it out ourselves. */ | |
306 | if (base == 0) | |
75cd5204 | 307 | if (*s == L_('0')) |
28f540f4 | 308 | { |
75cd5204 | 309 | if (TOUPPER (s[1]) == L_('X')) |
28f540f4 RM |
310 | { |
311 | s += 2; | |
312 | base = 16; | |
313 | } | |
314 | else | |
315 | base = 8; | |
316 | } | |
317 | else | |
318 | base = 10; | |
319 | ||
320 | /* Save the pointer so we can check later if anything happened. */ | |
321 | save = s; | |
322 | ||
e09675dd | 323 | #ifdef USE_NUMBER_GROUPING |
f0bf9cb9 RM |
324 | if (group) |
325 | { | |
326 | /* Find the end of the digit string and check its grouping. */ | |
327 | end = s; | |
75cd5204 | 328 | for (c = *end; c != L_('\0'); c = *++end) |
503054c0 RM |
329 | if ((wchar_t) c != thousands |
330 | && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9')) | |
331 | && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base)) | |
f0bf9cb9 RM |
332 | break; |
333 | if (*s == thousands) | |
334 | end = s; | |
335 | else | |
336 | end = correctly_grouped_prefix (s, end, thousands, grouping); | |
337 | } | |
be69ea41 | 338 | else |
e09675dd | 339 | #endif |
be69ea41 | 340 | end = NULL; |
f0bf9cb9 | 341 | |
28f540f4 RM |
342 | cutoff = ULONG_MAX / (unsigned LONG int) base; |
343 | cutlim = ULONG_MAX % (unsigned LONG int) base; | |
344 | ||
345 | overflow = 0; | |
346 | i = 0; | |
75cd5204 | 347 | for (c = *s; c != L_('\0'); c = *++s) |
28f540f4 | 348 | { |
be69ea41 | 349 | if (s == end) |
f0bf9cb9 | 350 | break; |
75cd5204 RM |
351 | if (c >= L_('0') && c <= L_('9')) |
352 | c -= L_('0'); | |
353 | else if (ISALPHA (c)) | |
354 | c = TOUPPER (c) - L_('A') + 10; | |
28f540f4 RM |
355 | else |
356 | break; | |
503054c0 | 357 | if ((int) c >= base) |
28f540f4 RM |
358 | break; |
359 | /* Check for overflow. */ | |
360 | if (i > cutoff || (i == cutoff && c > cutlim)) | |
361 | overflow = 1; | |
362 | else | |
363 | { | |
364 | i *= (unsigned LONG int) base; | |
365 | i += c; | |
366 | } | |
367 | } | |
368 | ||
369 | /* Check if anything actually happened. */ | |
370 | if (s == save) | |
371 | goto noconv; | |
372 | ||
373 | /* Store in ENDPTR the address of one character | |
374 | past the last character we converted. */ | |
375 | if (endptr != NULL) | |
75cd5204 | 376 | *endptr = (STRING_TYPE *) s; |
28f540f4 | 377 | |
e09675dd | 378 | #if !UNSIGNED |
28f540f4 RM |
379 | /* Check for a value that is within the range of |
380 | `unsigned LONG int', but outside the range of `LONG int'. */ | |
b8fe19fa RM |
381 | if (overflow == 0 |
382 | && i > (negative | |
383 | ? -((unsigned LONG int) (LONG_MIN + 1)) + 1 | |
384 | : (unsigned LONG int) LONG_MAX)) | |
28f540f4 RM |
385 | overflow = 1; |
386 | #endif | |
387 | ||
388 | if (overflow) | |
389 | { | |
c4029823 | 390 | __set_errno (ERANGE); |
e09675dd | 391 | #if UNSIGNED |
28f540f4 RM |
392 | return ULONG_MAX; |
393 | #else | |
394 | return negative ? LONG_MIN : LONG_MAX; | |
395 | #endif | |
396 | } | |
397 | ||
398 | /* Return the result of the appropriate sign. */ | |
399 | return (negative ? -i : i); | |
400 | ||
401 | noconv: | |
da128169 | 402 | /* We must handle a special case here: the base is 0 or 16 and the |
0200214b | 403 | first two characters are '0' and 'x', but the rest are no |
da128169 RM |
404 | hexadecimal digits. This is no error case. We return 0 and |
405 | ENDPTR points to the `x`. */ | |
28f540f4 | 406 | if (endptr != NULL) |
75cd5204 RM |
407 | if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X') |
408 | && save[-2] == L_('0')) | |
409 | *endptr = (STRING_TYPE *) &save[-1]; | |
da128169 RM |
410 | else |
411 | /* There was no number to convert. */ | |
75cd5204 | 412 | *endptr = (STRING_TYPE *) nptr; |
da128169 | 413 | |
28f540f4 RM |
414 | return 0L; |
415 | } | |
f0bf9cb9 RM |
416 | \f |
417 | /* External user entry point. */ | |
f0e44959 UD |
418 | |
419 | #if _LIBC - 0 == 0 | |
420 | # undef PARAMS | |
421 | # if defined (__STDC__) && __STDC__ | |
422 | # define PARAMS(Args) Args | |
423 | # else | |
424 | # define PARAMS(Args) () | |
425 | # endif | |
426 | ||
427 | /* Prototype. */ | |
428 | INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base)); | |
429 | #endif | |
430 | ||
431 | ||
f0bf9cb9 | 432 | INT |
af5b3bc3 RM |
433 | #ifdef weak_function |
434 | weak_function | |
435 | #endif | |
0501d603 | 436 | strtol (nptr, endptr, base LOCALE_PARAM) |
75cd5204 RM |
437 | const STRING_TYPE *nptr; |
438 | STRING_TYPE **endptr; | |
f0bf9cb9 | 439 | int base; |
0501d603 | 440 | LOCALE_PARAM_DECL |
f0bf9cb9 | 441 | { |
0501d603 | 442 | return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM); |
f0bf9cb9 | 443 | } |