1 /* strtol.c - convert a string to an unsigned long int.
3 Copyright 1997, 2008 Karl Berry.
4 Copyright 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
5 Modified by Karl Berry for kpathsea.
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with this library; if not, see <http://www.gnu.org/licenses/>. */
25 # define USE_NUMBER_GROUPING
27 # define HAVE_LIMITS_H
49 #ifdef USE_NUMBER_GROUPING
50 # include "../locale/localeinfo.h"
53 /* Nonzero if we are defining `strtoul' or `strtouq', operating on
59 # define strtol strtoul
60 # define INT unsigned LONG int
63 /* If QUAD is defined, we are defining `strtoq' or `strtouq',
64 operating on `long long int's. */
67 # define strtoul strtouq
69 # define strtol strtoq
71 # define LONG long long
73 # define LONG_MIN LONG_LONG_MIN
75 # define LONG_MAX LONG_LONG_MAX
77 # define ULONG_MAX ULONG_LONG_MAX
78 # if __GNUC__ == 2 && __GNUC_MINOR__ < 7
79 /* Work around gcc bug with using this constant. */
80 static const unsigned long long int maxquad = ULONG_LONG_MAX;
82 # define ULONG_MAX maxquad
89 # define INTERNAL(x) INTERNAL1(x)
90 # define INTERNAL1(x) __##x##_internal
92 # define INTERNAL(x) __/**/x/**/_internal
95 #ifdef USE_NUMBER_GROUPING
96 /* This file defines a function to check for correct grouping. */
97 # include "grouping.h"
101 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
102 If BASE is 0 the base is determined by the presence of a leading
103 zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
104 If BASE is < 2 or > 36, it is reset to 10.
105 If ENDPTR is not NULL, a pointer to the character after the last
106 one converted is stored in *ENDPTR. */
109 INTERNAL (strtol) (nptr, endptr, base, group)
116 register unsigned LONG int cutoff;
117 register unsigned int cutlim;
118 register unsigned LONG int i;
119 register const char *s;
120 register unsigned char c;
121 const char *save, *end;
124 #ifdef USE_NUMBER_GROUPING
125 /* The thousands character of the current locale. */
127 /* The numeric grouping specification of the current locale,
128 in the format described in <locale.h>. */
129 const char *grouping;
133 grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
134 if (*grouping <= 0 || *grouping == CHAR_MAX)
138 /* Figure out the thousands separator character. */
139 if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
140 strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
141 thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
142 if (thousands == L'\0')
150 if (base < 0 || base == 1 || base > 36)
155 /* Skip white space. */
161 /* Check for a sign. */
175 if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
178 /* If BASE is zero, figure it out ourselves. */
182 if (toupper (s[1]) == 'X')
193 /* Save the pointer so we can check later if anything happened. */
196 #ifdef USE_NUMBER_GROUPING
199 /* Find the end of the digit string and check its grouping. */
201 for (c = *end; c != '\0'; c = *++end)
202 if (c != thousands && !isdigit (c) &&
203 (!isalpha (c) || toupper (c) - 'A' + 10 >= base))
208 end = correctly_grouped_prefix (s, end, thousands, grouping);
214 cutoff = ULONG_MAX / (unsigned LONG int) base;
215 cutlim = ULONG_MAX % (unsigned LONG int) base;
219 for (c = *s; c != '\0'; c = *++s)
225 else if (isalpha (c))
226 c = toupper (c) - 'A' + 10;
231 /* Check for overflow. */
232 if (i > cutoff || (i == cutoff && c > cutlim))
236 i *= (unsigned LONG int) base;
241 /* Check if anything actually happened. */
245 /* Store in ENDPTR the address of one character
246 past the last character we converted. */
248 *endptr = (char *) s;
251 /* Check for a value that is within the range of
252 `unsigned LONG int', but outside the range of `LONG int'. */
254 -(unsigned LONG int) LONG_MIN : (unsigned LONG int) LONG_MAX))
264 return negative ? LONG_MIN : LONG_MAX;
268 /* Return the result of the appropriate sign. */
269 return (negative ? -i : i);
272 /* There was no number to convert. */
274 *endptr = (char *) nptr;
278 /* External user entry point. */
285 strtol (nptr, endptr, base)
290 return INTERNAL (strtol) (nptr, endptr, base, 0);