]>
Commit | Line | Data |
---|---|---|
cce855bc JA |
1 | /* strtol - Convert string representation of a number into an integer value. |
2 | Copyright (C) 1997 Free Software Foundation, Inc. | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify it | |
5 | under the terms of the GNU General Public License as published by the | |
6 | Free Software Foundation; either version 2, or (at your option) any | |
7 | later version. | |
8 | ||
9 | This program 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 | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software Foundation, | |
16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
17 | ||
18 | #include <config.h> | |
19 | ||
20 | #if !defined (HAVE_STRTOL) | |
21 | ||
22 | #include <ctype.h> | |
23 | #include <errno.h> | |
24 | ||
25 | #ifndef errno | |
26 | extern int errno; | |
27 | #endif | |
28 | ||
29 | #ifndef __set_errno | |
30 | # define __set_errno(Val) errno = (Val) | |
31 | #endif | |
32 | ||
33 | #ifdef HAVE_LIMITS_H | |
34 | # include <limits.h> | |
35 | #endif | |
36 | ||
b72432fd | 37 | #include <stdc.h> |
cce855bc JA |
38 | #include <bashansi.h> |
39 | ||
40 | #ifndef NULL | |
41 | # define NULL 0 | |
42 | #endif | |
43 | ||
44 | /* Nonzero if we are defining `strtoul', operating on unsigned integers. */ | |
45 | #ifndef UNSIGNED | |
46 | # define UNSIGNED 0 | |
47 | # define RETTYPE long | |
48 | #else | |
49 | # define RETTYPE unsigned long | |
50 | #endif | |
51 | ||
52 | /* Determine the name. */ | |
53 | #if UNSIGNED | |
54 | # define strtol strtoul | |
55 | #endif | |
56 | ||
57 | #ifndef CHAR_BIT | |
58 | # define CHAR_BIT 8 | |
59 | #endif | |
60 | ||
61 | #ifndef ULONG_MAX | |
62 | # define ULONG_MAX ((unsigned long) ~(unsigned long) 0) | |
63 | # define ULONG_MIN ((unsigned long) 0 - ULONG_MAX) | |
64 | #endif | |
65 | ||
66 | #ifndef LONG_MAX | |
67 | # define LONG_MAX ((long) (ULONG_MAX >> 1)) | |
68 | # define LONG_MIN ((long) (0 - LONG_MAX)) | |
69 | #endif | |
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 | RETTYPE | |
79 | strtol (nptr, endptr, base) | |
80 | const char *nptr; | |
81 | char **endptr; | |
82 | int base; | |
83 | { | |
84 | int negative; | |
85 | register unsigned long cutoff, i; | |
86 | register unsigned int cutlim; | |
87 | register const char *s; | |
88 | register unsigned char c; | |
89 | const char *save, *end; | |
90 | int overflow; | |
91 | ||
92 | if (base < 0 || base == 1 || base > 36) | |
93 | base = 10; | |
94 | ||
95 | save = s = nptr; | |
96 | ||
97 | /* Skip white space. */ | |
98 | while (isspace (*s)) | |
99 | ++s; | |
100 | if (*s == '\0') | |
101 | goto noconv; | |
102 | ||
103 | /* Check for a sign. */ | |
104 | if (*s == '-' || *s == '+') | |
105 | { | |
106 | negative = (*s == '-'); | |
107 | ++s; | |
108 | } | |
109 | else | |
110 | negative = 0; | |
111 | ||
112 | if (base == 16 && *s == '0' && toupper (s[1]) == 'X') | |
113 | s += 2; | |
114 | ||
115 | /* If BASE is zero, figure it out ourselves. */ | |
116 | if (base == 0) | |
117 | if (*s == '0') | |
118 | { | |
119 | if (toupper (s[1]) == 'X') | |
120 | { | |
121 | s += 2; | |
122 | base = 16; | |
123 | } | |
124 | else | |
125 | base = 8; | |
126 | } | |
127 | else | |
128 | base = 10; | |
129 | ||
130 | /* Save the pointer so we can check later if anything happened. */ | |
131 | save = s; | |
132 | ||
133 | end = NULL; | |
134 | ||
135 | cutoff = ULONG_MAX / (unsigned long int) base; | |
136 | cutlim = ULONG_MAX % (unsigned long int) base; | |
137 | ||
138 | overflow = 0; | |
139 | i = 0; | |
140 | for (c = *s; c != '\0'; c = *++s) | |
141 | { | |
142 | if (s == end) | |
143 | break; | |
144 | ||
145 | if (c >= '0' && c <= '9') | |
146 | c -= '0'; | |
147 | else if (isalpha (c)) | |
148 | c = toupper (c) - 'A' + 10; | |
149 | else | |
150 | break; | |
151 | ||
152 | if ((int) c >= base) | |
153 | break; | |
154 | ||
155 | /* Check for overflow. */ | |
156 | if (i > cutoff || (i == cutoff && c > cutlim)) | |
157 | overflow = 1; | |
158 | else | |
159 | { | |
160 | i *= (unsigned long int) base; | |
161 | i += c; | |
162 | } | |
163 | } | |
164 | ||
165 | /* Check if anything actually happened. */ | |
166 | if (s == save) | |
167 | goto noconv; | |
168 | ||
169 | /* Store in ENDPTR the address of one character | |
170 | past the last character we converted. */ | |
171 | if (endptr != NULL) | |
172 | *endptr = (char *) s; | |
173 | ||
174 | #if !UNSIGNED | |
175 | /* Check for a value that is within the range of | |
176 | `unsigned long int', but outside the range of `long int'. */ | |
177 | if (overflow == 0 | |
178 | && i > (negative | |
179 | ? -((unsigned long) (LONG_MIN + 1)) + 1 | |
180 | : (unsigned long) LONG_MAX)) | |
181 | overflow = 1; | |
182 | #endif | |
183 | ||
184 | if (overflow) | |
185 | { | |
186 | __set_errno (ERANGE); | |
187 | #if UNSIGNED | |
188 | return ULONG_MAX; | |
189 | #else | |
190 | return negative ? LONG_MIN : LONG_MAX; | |
191 | #endif | |
192 | } | |
193 | ||
194 | /* Return the result with the appropriate sign. */ | |
195 | return (negative ? -i : i); | |
196 | ||
197 | noconv: | |
198 | /* We must handle a special case here: the base is 0 or 16 and the | |
199 | first two characters are '0' and 'x', but the rest are no | |
200 | hexadecimal digits. This is no error case. We return 0 and | |
201 | ENDPTR points to the `x'. */ | |
202 | if (endptr != NULL) | |
203 | { | |
204 | if (save - nptr >= 2 && toupper (save[-1]) == 'X' && save[-2] == '0') | |
205 | *endptr = (char *) &save[-1]; | |
206 | else | |
28ef6c31 JA |
207 | /* There was no number to convert. */ |
208 | *endptr = (char *) nptr; | |
cce855bc JA |
209 | } |
210 | ||
211 | return 0L; | |
212 | } | |
213 | ||
214 | #endif /* !HAVE_STRTOL */ |