Thu Mar 16 00:04:41 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[glibc.git] / stdlib / strtol.c
blob1c63afb6fe5112b3c96d9e75677c8328db3de128
1 /* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA. */
20 #include <ctype.h>
21 #include <limits.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include "../locale/localeinfo.h"
28 /* Nonzero if we are defining `strtoul' or `strtouq', operating on
29 unsigned integers. */
30 #ifndef UNSIGNED
31 #define UNSIGNED 0
32 #define INT LONG int
33 #else
34 #define strtol strtoul
35 #define INT unsigned LONG int
36 #endif
38 /* If QUAD is defined, we are defining `strtoq' or `strtouq',
39 operating on `long long int's. */
40 #ifdef QUAD
41 #if UNSIGNED
42 #define strtoul strtouq
43 #else
44 #define strtol strtoq
45 #endif
46 #define LONG long long
47 #undef LONG_MIN
48 #define LONG_MIN LONG_LONG_MIN
49 #undef LONG_MAX
50 #define LONG_MAX LONG_LONG_MAX
51 #undef ULONG_MAX
52 #define ULONG_MAX ULONG_LONG_MAX
53 #if __GNUC__ == 2 && __GNUC_MINOR__ < 7
54 /* Work around gcc bug with using this constant. */
55 static const unsigned long long int maxquad = ULONG_LONG_MAX;
56 #undef ULONG_MAX
57 #define ULONG_MAX maxquad
58 #endif
59 #else
60 #define LONG long
61 #endif
64 #define INTERNAL(x) INTERNAL1(x)
65 #define INTERNAL1(x) __##x##_internal
67 /* This file defines a function to check for correct grouping. */
68 #include "grouping.h"
71 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
72 If BASE is 0 the base is determined by the presence of a leading
73 zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
74 If BASE is < 2 or > 36, it is reset to 10.
75 If ENDPTR is not NULL, a pointer to the character after the last
76 one converted is stored in *ENDPTR. */
78 INT
79 INTERNAL (strtol) (nptr, endptr, base, group)
80 const char *nptr;
81 char **endptr;
82 int base;
83 int group;
85 int negative;
86 register unsigned LONG int cutoff;
87 register unsigned int cutlim;
88 register unsigned LONG int i;
89 register const char *s;
90 register unsigned char c;
91 const char *save, *end;
92 int overflow;
94 /* The thousands character of the current locale. */
95 wchar_t thousands;
96 /* The numeric grouping specification of the current locale,
97 in the format described in <locale.h>. */
98 const char *grouping;
100 if (group)
102 grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
103 if (*grouping <= 0 || *grouping == CHAR_MAX)
104 grouping = NULL;
105 else
107 /* Figure out the thousands separator character. */
108 if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
109 strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
110 thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
111 if (thousands == L'\0')
112 grouping = NULL;
115 else
116 grouping = NULL;
119 if (base < 0 || base == 1 || base > 36)
120 base = 10;
122 s = nptr;
124 /* Skip white space. */
125 while (isspace (*s))
126 ++s;
127 if (*s == '\0')
128 goto noconv;
130 /* Check for a sign. */
131 if (*s == '-')
133 negative = 1;
134 ++s;
136 else if (*s == '+')
138 negative = 0;
139 ++s;
141 else
142 negative = 0;
144 if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
145 s += 2;
147 /* If BASE is zero, figure it out ourselves. */
148 if (base == 0)
149 if (*s == '0')
151 if (toupper (s[1]) == 'X')
153 s += 2;
154 base = 16;
156 else
157 base = 8;
159 else
160 base = 10;
162 /* Save the pointer so we can check later if anything happened. */
163 save = s;
165 if (group)
167 /* Find the end of the digit string and check its grouping. */
168 end = s;
169 for (c = *end; c != '\0'; c = *++end)
170 if (c != thousands && !isdigit (c) &&
171 (!isalpha (c) || toupper (c) - 'A' + 10 >= base))
172 break;
173 if (*s == thousands)
174 end = s;
175 else
176 end = correctly_grouped_prefix (s, end, thousands, grouping);
179 cutoff = ULONG_MAX / (unsigned LONG int) base;
180 cutlim = ULONG_MAX % (unsigned LONG int) base;
182 overflow = 0;
183 i = 0;
184 for (c = *s; c != '\0'; c = *++s)
186 if (group && s == end)
187 break;
188 if (isdigit (c))
189 c -= '0';
190 else if (isalpha (c))
191 c = toupper (c) - 'A' + 10;
192 else
193 break;
194 if (c >= base)
195 break;
196 /* Check for overflow. */
197 if (i > cutoff || (i == cutoff && c > cutlim))
198 overflow = 1;
199 else
201 i *= (unsigned LONG int) base;
202 i += c;
206 /* Check if anything actually happened. */
207 if (s == save)
208 goto noconv;
210 /* Store in ENDPTR the address of one character
211 past the last character we converted. */
212 if (endptr != NULL)
213 *endptr = (char *) s;
215 #if !UNSIGNED
216 /* Check for a value that is within the range of
217 `unsigned LONG int', but outside the range of `LONG int'. */
218 if (i > (negative ?
219 -(unsigned LONG int) LONG_MIN : (unsigned LONG int) LONG_MAX))
220 overflow = 1;
221 #endif
223 if (overflow)
225 errno = ERANGE;
226 #if UNSIGNED
227 return ULONG_MAX;
228 #else
229 return negative ? LONG_MIN : LONG_MAX;
230 #endif
233 /* Return the result of the appropriate sign. */
234 return (negative ? -i : i);
236 noconv:
237 /* There was no number to convert. */
238 if (endptr != NULL)
239 *endptr = (char *) nptr;
240 return 0L;
243 /* External user entry point. */
245 weak_symbol (strtol)
248 strtol (nptr, endptr, base)
249 const char *nptr;
250 char **endptr;
251 int base;
253 return INTERNAL (strtol) (nptr, endptr, base, 0);