If !GROUP, set END to null. In loop, test only END, not GROUP.
[kopensolaris-gnu/glibc.git] / stdlib / strtol.c
1 /* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
2
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
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
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"
26
27
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
37
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
62
63
64 #define INTERNAL(x) INTERNAL1(x)
65 #define INTERNAL1(x) __##x##_internal
66
67 /* This file defines a function to check for correct grouping.  */
68 #include "grouping.h"
69
70
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.  */
77
78 INT
79 INTERNAL (strtol) (nptr, endptr, base, group)
80      const char *nptr;
81      char **endptr;
82      int base;
83      int group;
84 {
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;
93
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;
99
100   if (group)
101     {
102       grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
103       if (*grouping <= 0 || *grouping == CHAR_MAX)
104         grouping = NULL;
105       else
106         {
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;
113         }
114     }
115   else
116     grouping = NULL;
117
118
119   if (base < 0 || base == 1 || base > 36)
120     base = 10;
121
122   s = nptr;
123
124   /* Skip white space.  */
125   while (isspace (*s))
126     ++s;
127   if (*s == '\0')
128     goto noconv;
129
130   /* Check for a sign.  */
131   if (*s == '-')
132     {
133       negative = 1;
134       ++s;
135     }
136   else if (*s == '+')
137     {
138       negative = 0;
139       ++s;
140     }
141   else
142     negative = 0;
143
144   if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
145     s += 2;
146
147   /* If BASE is zero, figure it out ourselves.  */
148   if (base == 0)
149     if (*s == '0')
150       {
151         if (toupper (s[1]) == 'X')
152           {
153             s += 2;
154             base = 16;
155           }
156         else
157           base = 8;
158       }
159     else
160       base = 10;
161
162   /* Save the pointer so we can check later if anything happened.  */
163   save = s;
164
165   if (group)
166     {
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);
177     }
178   else
179     end = NULL;
180
181   cutoff = ULONG_MAX / (unsigned LONG int) base;
182   cutlim = ULONG_MAX % (unsigned LONG int) base;
183
184   overflow = 0;
185   i = 0;
186   for (c = *s; c != '\0'; c = *++s)
187     {
188       if (s == end)
189         break;
190       if (isdigit (c))
191         c -= '0';
192       else if (isalpha (c))
193         c = toupper (c) - 'A' + 10;
194       else
195         break;
196       if (c >= base)
197         break;
198       /* Check for overflow.  */
199       if (i > cutoff || (i == cutoff && c > cutlim))
200         overflow = 1;
201       else
202         {
203           i *= (unsigned LONG int) base;
204           i += c;
205         }
206     }
207
208   /* Check if anything actually happened.  */
209   if (s == save)
210     goto noconv;
211
212   /* Store in ENDPTR the address of one character
213      past the last character we converted.  */
214   if (endptr != NULL)
215     *endptr = (char *) s;
216
217 #if     !UNSIGNED
218   /* Check for a value that is within the range of
219      `unsigned LONG int', but outside the range of `LONG int'.  */
220   if (i > (negative ?
221            -(unsigned LONG int) LONG_MIN : (unsigned LONG int) LONG_MAX))
222     overflow = 1;
223 #endif
224
225   if (overflow)
226     {
227       errno = ERANGE;
228 #if     UNSIGNED
229       return ULONG_MAX;
230 #else
231       return negative ? LONG_MIN : LONG_MAX;
232 #endif
233     }
234
235   /* Return the result of the appropriate sign.  */
236   return (negative ? -i : i);
237
238 noconv:
239   /* There was no number to convert.  */
240   if (endptr != NULL)
241     *endptr = (char *) nptr;
242   return 0L;
243 }
244 \f
245 /* External user entry point.  */
246
247 weak_symbol (strtol)
248
249 INT
250 strtol (nptr, endptr, base)
251      const char *nptr;
252      char **endptr;
253      int base;
254 {
255   return INTERNAL (strtol) (nptr, endptr, base, 0);
256 }