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 "ansidecl.h"
20: #include <ctype.h>
21: #include <limits.h>
22: #include <stddef.h>
23: #include <stdlib.h>
24: /* errno.h is needed on SunOS 4.1.2 */
25: #include <errno.h>
26:
27: #ifndef UNSIGNED
28: #define UNSIGNED 0
29: #endif
30:
31: /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
32: If BASE is 0 the base is determined by the presence of a leading
33: zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
34: If BASE is < 2 or > 36, it is reset to 10.
35: If ENDPTR is not NULL, a pointer to the character after the last
36: one converted is stored in *ENDPTR. */
37: #if UNSIGNED
38: unsigned long int
39: #define strtol strtoul
40: #else
41: long int
42: #endif
43: DEFUN(strtol, (nptr, endptr, base),
44: CONST char *nptr AND char **endptr AND int base)
45: {
46: int negative;
47: register unsigned long int cutoff;
48: register unsigned int cutlim;
49: register unsigned long int i;
50: register CONST char *s;
51: register unsigned char c;
52: CONST char *save;
53: int overflow;
54:
55: if (base < 0 || base == 1 || base > 36)
56: base = 10;
57:
58: s = nptr;
59:
60: /* Skip white space. */
61: while (isspace(*s))
62: ++s;
63: if (*s == '\0')
64: goto noconv;
65:
66: /* Check for a sign. */
67: if (*s == '-')
68: {
69: negative = 1;
70: ++s;
71: }
72: else if (*s == '+')
73: {
74: negative = 0;
75: ++s;
76: }
77: else
78: negative = 0;
79:
80: if (base == 16 && s[0] == '0' && toupper(s[1]) == 'X')
81: s += 2;
82:
83: /* If BASE is zero, figure it out ourselves. */
84: if (base == 0)
85: if (*s == '0')
86: {
87: if (toupper(s[1]) == 'X')
88: {
89: s += 2;
90: base = 16;
91: }
92: else
93: base = 8;
94: }
95: else
96: base = 10;
97:
98: /* Save the pointer so we can check later if anything happened. */
99: save = s;
100:
101: cutoff = ULONG_MAX / (unsigned long int) base;
102: cutlim = ULONG_MAX % (unsigned long int) base;
103:
104: overflow = 0;
105: i = 0;
106: for (c = *s; c != '\0'; c = *++s)
107: {
108: if (isdigit(c))
109: c -= '0';
110: else if (isalpha(c))
111: c = toupper(c) - 'A' + 10;
112: else
113: break;
114: if (c >= base)
115: break;
116: /* Check for overflow. */
117: if (i > cutoff || (i == cutoff && c > cutlim))
118: overflow = 1;
119: else
120: {
121: i *= (unsigned long int) base;
122: i += c;
123: }
124: }
125:
126: /* Check if anything actually happened. */
127: if (s == save)
128: goto noconv;
129:
130: /* Store in ENDPTR the address of one character
131: past the last character we converted. */
132: if (endptr != NULL)
133: *endptr = (char *) s;
134:
135: #if !UNSIGNED
136: /* Check for a value that is within the range of
137: `unsigned long int', but outside the range of `long int'. */
138: if (i > (negative ?
139: - (unsigned long int) LONG_MIN : (unsigned long int) LONG_MAX))
140: overflow = 1;
141: #endif
142:
143: if (overflow)
144: {
145: errno = ERANGE;
146: #if UNSIGNED
147: return ULONG_MAX;
148: #else
149: return negative ? LONG_MIN : LONG_MAX;
150: #endif
151: }
152:
153: /* Return the result of the appropriate sign. */
154: return (negative ? - i : i);
155:
156: noconv:
157: /* There was no number to convert. */
158: if (endptr != NULL)
159: *endptr = (char *) nptr;
160: return 0L;
161: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>