merge with 1.9.2i
[gnulib.git] / lib / strtol.c
1 /* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ctype.h>
20 #include <errno.h>
21
22 #if HAVE_LIMITS_H
23 #include <limits.h>
24 #endif
25 #ifndef ULONG_MAX
26 #define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
27 #define LONG_MIN (-LONG_MAX-1)
28 #define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
29 #endif
30
31 #if STDC_HEADERS
32 #include <stddef.h>
33 #include <stdlib.h>
34 #else
35 #define NULL 0
36 extern int errno;
37 #endif
38
39 #if !__STDC__
40 #define const
41 #endif
42
43 #ifndef UNSIGNED
44 #define UNSIGNED        0
45 #endif
46
47 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
48    If BASE is 0 the base is determined by the presence of a leading
49    zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
50    If BASE is < 2 or > 36, it is reset to 10.
51    If ENDPTR is not NULL, a pointer to the character after the last
52    one converted is stored in *ENDPTR.  */
53 #if     UNSIGNED
54 unsigned long int
55 #define strtol  strtoul
56 #else
57 long int
58 #endif
59 strtol (nptr, endptr, base)
60      const char *nptr;
61      char **endptr;
62      int base;
63 {
64   int negative;
65   register unsigned long int cutoff;
66   register unsigned int cutlim;
67   register unsigned long int i;
68   register const char *s;
69   register unsigned char c;
70   const char *save;
71   int overflow;
72
73   if (base < 0 || base == 1 || base > 36)
74     base = 10;
75
76   s = nptr;
77
78   /* Skip white space.  */
79   while (isspace (*s))
80     ++s;
81   if (*s == '\0')
82     goto noconv;
83
84   /* Check for a sign.  */
85   if (*s == '-')
86     {
87       negative = 1;
88       ++s;
89     }
90   else if (*s == '+')
91     {
92       negative = 0;
93       ++s;
94     }
95   else
96     negative = 0;
97
98   if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
99     s += 2;
100
101   /* If BASE is zero, figure it out ourselves.  */
102   if (base == 0)
103     {
104       if (*s == '0')
105         {
106           if (toupper (s[1]) == 'X')
107             {
108               s += 2;
109               base = 16;
110             }
111           else
112             base = 8;
113         }
114       else
115         base = 10;
116     }
117
118   /* Save the pointer so we can check later if anything happened.  */
119   save = s;
120
121   cutoff = ULONG_MAX / (unsigned long int) base;
122   cutlim = ULONG_MAX % (unsigned long int) base;
123
124   overflow = 0;
125   i = 0;
126   for (c = *s; c != '\0'; c = *++s)
127     {
128       if (isdigit (c))
129         c -= '0';
130       else if (isalpha (c))
131         c = toupper (c) - 'A' + 10;
132       else
133         break;
134       if (c >= base)
135         break;
136       /* Check for overflow.  */
137       if (i > cutoff || (i == cutoff && c > cutlim))
138         overflow = 1;
139       else
140         {
141           i *= (unsigned long int) base;
142           i += c;
143         }
144     }
145
146   /* Check if anything actually happened.  */
147   if (s == save)
148     goto noconv;
149
150   /* Store in ENDPTR the address of one character
151      past the last character we converted.  */
152   if (endptr != NULL)
153     *endptr = (char *) s;
154
155 #if     !UNSIGNED
156   /* Check for a value that is within the range of
157      `unsigned long int', but outside the range of `long int'.  */
158   if (i > (negative ?
159            - (unsigned long int) LONG_MIN : (unsigned long int) LONG_MAX))
160     overflow = 1;
161 #endif
162
163   if (overflow)
164     {
165       errno = ERANGE;
166 #if     UNSIGNED
167       return ULONG_MAX;
168 #else
169       return negative ? LONG_MIN : LONG_MAX;
170 #endif
171     }
172
173   /* Return the result of the appropriate sign.  */
174   return (negative ? - i : i);
175
176 noconv:;
177   /* There was no number to convert.  */
178   if (endptr != NULL)
179     *endptr = (char *) nptr;
180   return 0L;
181 }