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