modules/up/src/Core/util/strtol.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- __set_errno
- L_
- ISSPACE
- ISALPHA
- TOUPPER
- L_
- ISSPACE
- ISALPHA
- TOUPPER
- INTERNAL
- INTERNAL1
- WEAKNAME
- INTERNAL
- INTERNAL
- PARAMS
- PARAMS
- strtol
1 /* strtol - Convert string representation of a number into an integer value.
2 Copyright (C) 1991, 92, 94, 95, 96, 97 Free Software Foundation, Inc.
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 not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #ifdef _LIBC
25 # define USE_NUMBER_GROUPING
26 # define STDC_HEADERS
27 # define HAVE_LIMITS_H
28 #endif
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <limits.h>
33 #ifndef errno
34 extern int errno;
35 #endif
36 #ifndef __set_errno
37 # define __set_errno(Val) errno = (Val)
/* [<][>][^][v][top][bottom][index][help] */
38 #endif
39
40 #ifdef HAVE_LIMITS_H
41 # include <limits.h>
42 #endif
43
44 #ifdef STDC_HEADERS
45 # include <stddef.h>
46 # include <stdlib.h>
47 # include <string.h>
48 #else
49 # ifndef NULL
50 # define NULL 0
51 # endif
52 #endif
53
54 #ifdef USE_NUMBER_GROUPING
55 # include "../locale/localeinfo.h"
56 #endif
57
58 /* Nonzero if we are defining `strtoul' or `strtouq', operating on
59 unsigned integers. */
60 #ifndef UNSIGNED
61 # define UNSIGNED 0
62 # define INT LONG int
63 #else
64 # define INT unsigned LONG int
65 #endif
66
67 /* Determine the name. */
68 #if UNSIGNED
69 # ifdef USE_WIDE_CHAR
70 # ifdef QUAD
71 # define strtol wcstouq
72 # else
73 # define strtol wcstoul
74 # endif
75 # else
76 # ifdef QUAD
77 # define strtol strtouq
78 # else
79 # define strtol strtoul
80 # endif
81 # endif
82 #else
83 # ifdef USE_WIDE_CHAR
84 # ifdef QUAD
85 # define strtol wcstoq
86 # else
87 # define strtol wcstol
88 # endif
89 # else
90 # ifdef QUAD
91 # define strtol strtoq
92 # endif
93 # endif
94 #endif
95
96 /* If QUAD is defined, we are defining `strtoq' or `strtouq',
97 operating on `long long int's. */
98 #ifdef QUAD
99 # define LONG long long
100 # undef LONG_MIN
101 # define LONG_MIN LONG_LONG_MIN
102 # undef LONG_MAX
103 # define LONG_MAX LONG_LONG_MAX
104 # undef ULONG_MAX
105 # define ULONG_MAX ULONG_LONG_MAX
106 # if __GNUC__ == 2 && __GNUC_MINOR__ < 7
107 /* Work around gcc bug with using this constant. */
108 static const unsigned long long int maxquad = ULONG_LONG_MAX;
109 # undef ULONG_MAX
110 # define ULONG_MAX maxquad
111 # endif
112 #else
113 # define LONG long
114
115 #ifndef ULONG_MAX
116 # define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
117 #endif
118 #ifndef LONG_MAX
119 # define LONG_MAX ((long int) (ULONG_MAX >> 1))
120 #endif
121 #endif
122
123 #ifdef USE_WIDE_CHAR
124 # include <wchar.h>
125 # include <wctype.h>
126 # define L_(Ch) L##Ch
/* [<][>][^][v][top][bottom][index][help] */
127 # define UCHAR_TYPE wint_t
128 # define STRING_TYPE wchar_t
129 # define ISSPACE(Ch) iswspace (Ch)
/* [<][>][^][v][top][bottom][index][help] */
130 # define ISALPHA(Ch) iswalpha (Ch)
/* [<][>][^][v][top][bottom][index][help] */
131 # define TOUPPER(Ch) towupper (Ch)
/* [<][>][^][v][top][bottom][index][help] */
132 #else
133 # define L_(Ch) Ch
/* [<][>][^][v][top][bottom][index][help] */
134 # define UCHAR_TYPE unsigned char
135 # define STRING_TYPE char
136 # define ISSPACE(Ch) isspace (Ch)
/* [<][>][^][v][top][bottom][index][help] */
137 # define ISALPHA(Ch) isalpha (Ch)
/* [<][>][^][v][top][bottom][index][help] */
138 # define TOUPPER(Ch) toupper (Ch)
/* [<][>][^][v][top][bottom][index][help] */
139 #endif
140
141 #ifdef __STDC__
142 # define INTERNAL(X) INTERNAL1(X)
/* [<][>][^][v][top][bottom][index][help] */
143 # define INTERNAL1(X) __##X##_internal
/* [<][>][^][v][top][bottom][index][help] */
144 # define WEAKNAME(X) WEAKNAME1(X)
/* [<][>][^][v][top][bottom][index][help] */
145 #else
146 # define INTERNAL(X) __/**/X/**/_internal
/* [<][>][^][v][top][bottom][index][help] */
147 #endif
148
149 #ifdef USE_NUMBER_GROUPING
150 /* This file defines a function to check for correct grouping. */
151 # include "grouping.h"
152 #endif
153
154
155 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
156 If BASE is 0 the base is determined by the presence of a leading
157 zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
158 If BASE is < 2 or > 36, it is reset to 10.
159 If ENDPTR is not NULL, a pointer to the character after the last
160 one converted is stored in *ENDPTR. */
161
162 INT
163 INTERNAL (strtol) (nptr, endptr, base, group)
/* [<][>][^][v][top][bottom][index][help] */
164 const STRING_TYPE *nptr;
165 STRING_TYPE **endptr;
166 int base;
167 int group;
168 {
169 int negative;
170 register unsigned LONG int cutoff;
171 register unsigned int cutlim;
172 register unsigned LONG int i;
173 register const STRING_TYPE *s;
174 register UCHAR_TYPE c;
175 const STRING_TYPE *save, *end;
176 int overflow;
177
178 #ifdef USE_NUMBER_GROUPING
179 /* The thousands character of the current locale. */
180 wchar_t thousands;
181 /* The numeric grouping specification of the current locale,
182 in the format described in <locale.h>. */
183 const char *grouping;
184
185 if (group)
186 {
187 grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
188 if (*grouping <= 0 || *grouping == CHAR_MAX)
189 grouping = NULL;
190 else
191 {
192 /* Figure out the thousands separator character. */
193 if (mbtowc (&thousands, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
194 strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
195 thousands = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
196 if (thousands == L'\0')
197 grouping = NULL;
198 }
199 }
200 else
201 grouping = NULL;
202 #endif
203
204 if (base < 0 || base == 1 || base > 36)
205 {
206 __set_errno (EINVAL);
207 return 0;
208 }
209
210 save = s = nptr;
211
212 /* Skip white space. */
213 while (ISSPACE (*s))
214 ++s;
215 if (*s == L_('\0'))
216 goto noconv;
217
218 /* Check for a sign. */
219 if (*s == L_('-'))
220 {
221 negative = 1;
222 ++s;
223 }
224 else if (*s == L_('+'))
225 {
226 negative = 0;
227 ++s;
228 }
229 else
230 negative = 0;
231
232 if (base == 16 && s[0] == L_('0') && TOUPPER (s[1]) == L_('X'))
233 s += 2;
234
235 /* If BASE is zero, figure it out ourselves. */
236 if (base == 0)
237 if (*s == L_('0'))
238 {
239 if (TOUPPER (s[1]) == L_('X'))
240 {
241 s += 2;
242 base = 16;
243 }
244 else
245 base = 8;
246 }
247 else
248 base = 10;
249
250 /* Save the pointer so we can check later if anything happened. */
251 save = s;
252
253 #ifdef USE_NUMBER_GROUPING
254 if (group)
255 {
256 /* Find the end of the digit string and check its grouping. */
257 end = s;
258 for (c = *end; c != L_('\0'); c = *++end)
259 if ((wchar_t) c != thousands
260 && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
261 && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
262 break;
263 if (*s == thousands)
264 end = s;
265 else
266 end = correctly_grouped_prefix (s, end, thousands, grouping);
267 }
268 else
269 #endif
270 end = NULL;
271
272 cutoff = ULONG_MAX / (unsigned LONG int) base;
273 cutlim = ULONG_MAX % (unsigned LONG int) base;
274
275 overflow = 0;
276 i = 0;
277 for (c = *s; c != L_('\0'); c = *++s)
278 {
279 if (s == end)
280 break;
281 if (c >= L_('0') && c <= L_('9'))
282 c -= L_('0');
283 else if (ISALPHA (c))
284 c = TOUPPER (c) - L_('A') + 10;
285 else
286 break;
287 if ((int) c >= base)
288 break;
289 /* Check for overflow. */
290 if (i > cutoff || (i == cutoff && c > cutlim))
291 overflow = 1;
292 else
293 {
294 i *= (unsigned LONG int) base;
295 i += c;
296 }
297 }
298
299 /* Check if anything actually happened. */
300 if (s == save)
301 goto noconv;
302
303 /* Store in ENDPTR the address of one character
304 past the last character we converted. */
305 if (endptr != NULL)
306 *endptr = (STRING_TYPE *) s;
307
308 #if !UNSIGNED
309 /* Check for a value that is within the range of
310 `unsigned LONG int', but outside the range of `LONG int'. */
311 if (overflow == 0
312 && i > (negative
313 ? -((unsigned LONG int) (LONG_MIN + 1)) + 1
314 : (unsigned LONG int) LONG_MAX))
315 overflow = 1;
316 #endif
317
318 if (overflow)
319 {
320 __set_errno (ERANGE);
321 #if UNSIGNED
322 return ULONG_MAX;
323 #else
324 return negative ? LONG_MIN : LONG_MAX;
325 #endif
326 }
327
328 /* Return the result of the appropriate sign. */
329 return (negative ? -i : i);
330
331 noconv:
332 /* We must handle a special case here: the base is 0 or 16 and the
333 first two characters are '0' and 'x', but the rest are no
334 hexadecimal digits. This is no error case. We return 0 and
335 ENDPTR points to the `x`. */
336 if (endptr != NULL)
337 if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
338 && save[-2] == L_('0'))
339 *endptr = (STRING_TYPE *) &save[-1];
340 else
341 /* There was no number to convert. */
342 *endptr = (STRING_TYPE *) nptr;
343
344 return 0L;
345 }
346
347 /* External user entry point. */
348
349 #if _LIBC - 0 == 0
350 # undef PARAMS
351 # if defined (__STDC__) && __STDC__
352 # define PARAMS(Args) Args
/* [<][>][^][v][top][bottom][index][help] */
353 # else
354 # define PARAMS(Args) ()
/* [<][>][^][v][top][bottom][index][help] */
355 # endif
356
357 /* Prototype. */
358 INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base));
359 #endif
360
361
362 INT
363 #ifdef weak_function
364 weak_function
365 #endif
366 strtol (nptr, endptr, base)
/* [<][>][^][v][top][bottom][index][help] */
367 const STRING_TYPE *nptr;
368 STRING_TYPE **endptr;
369 int base;
370 {
371 return INTERNAL (strtol) (nptr, endptr, base, 0);
372 }