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