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 Lesser General Public License as
6 published by the Free Software Foundation; either version 3 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 Lesser 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.,
17 59 Temple Place, Suite 330, Boston, MA 02111, 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 }
162