]> git.ozlabs.org Git - yaboot.git/blob - lib/strtol.c
yaboot-1.3.17
[yaboot.git] / lib / strtol.c
1 /* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
2
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
17    not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18    Cambridge, MA 02139, USA.  */
19
20 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
21    If BASE is 0 the base is determined by the presence of a leading
22    zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
23    If BASE is < 2 or > 36, it is reset to 10.
24    If ENDPTR is not NULL, a pointer to the character after the last
25    one converted is stored in *ENDPTR.  */
26
27 #include "ctype.h"
28
29 int strtol (nptr, endptr, base)
30 const char *nptr;
31 char **endptr;
32 int base;
33 {
34     int negative;
35     register unsigned int cutoff;
36     register unsigned int cutlim;
37     register unsigned int i;
38     register const char *s;
39     register unsigned char c;
40     const char *save, *end;
41     int overflow;
42
43     if (base < 0 || base == 1 || base > 36)
44         base = 10;
45
46     save = s = nptr;
47
48     /* Skip white space.  */
49     while (((unsigned char) *s) <= 32 && *s)
50         ++s;
51     if (*s == '\0')
52         goto noconv;
53
54     /* Check for a sign.  */
55     if (*s == '-') {
56         negative = 1;
57         ++s;
58     } else if (*s == '+') {
59         negative = 0;
60         ++s;
61     } else
62         negative = 0;
63
64     if ((base == 16 && s[0] == '0' && (s[1] == 'X')) || (s[1] == 'x'))
65         s += 2;
66
67     /* If BASE is zero, figure it out ourselves.  */
68     if (base == 0) {
69         if (*s == '0') {
70             if (s[1] == 'X' || s[1] == 'x') {
71                 s += 2;
72                 base = 16;
73             } else
74                 base = 8;
75         } else
76             base = 10;
77     }
78
79     /* Save the pointer so we can check later if anything happened.  */
80     save = s;
81
82     end = 0;
83
84     cutoff = 0x7FFFFFFF / (unsigned int) base;
85     cutlim = 0x7FFFFFFF % (unsigned int) base;
86
87     overflow = 0;
88     i = 0;
89     for (c = *s; c != '\0'; c = *++s) {
90         if (s == end)
91             break;
92         if (c >= '0' && c <= '9')
93             c -= '0';
94         else if (c >= 'A' && c <= 'Z')
95             c = c - 'A' + 10;
96         else if (c >= 'a' && c <= 'z')
97             c = c - 'a' + 10;
98         else
99             break;
100         if (c >= base)
101             break;
102         /* Check for overflow.  */
103         if (i > cutoff || (i == cutoff && c > cutlim))
104             overflow = 1;
105         else {
106             i *= (unsigned int) base;
107             i += c;
108         }
109     }
110
111     /* Check if anything actually happened.  */
112     if (s == save)
113         goto noconv;
114
115     /* Store in ENDPTR the address of one character
116        past the last character we converted.  */
117     if (endptr)
118         *endptr = (char *) s;
119
120     if (overflow)
121         return negative ? (int) 0x80000000 : (int) 0x7FFFFFFF;
122
123     /* Return the result of the appropriate sign.  */
124     return (negative ? -i : i);
125
126   noconv:
127     /* We must handle a special case here: the base is 0 or 16 and the
128        first two characters and '0' and 'x', but the rest are no
129        hexadecimal digits.  This is no error case.  We return 0 and
130        ENDPTR points to the `x`.  */
131     if (endptr) {
132         if (save - nptr >= 2 && tolower (save[-1]) == 'x' && save[-2] == '0')
133             *endptr = (char *) &save[-1];
134         else
135             /*  There was no number to convert.  */
136             *endptr = (char *) nptr;
137     }
138
139     return 0L;
140 }