source: trunk/third/sendmail/libsm/strto.c @ 19204

Revision 19204, 5.4 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1992
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 */
11
12#include <sm/gen.h>
13SM_IDSTR(id, "@(#)$Id: strto.c,v 1.1.1.1 2003-04-08 15:06:42 zacheiss Exp $")
14
15#include <sys/param.h>
16#include <sys/types.h>
17#include <stdlib.h>
18#include <ctype.h>
19#include <errno.h>
20#include <sm/limits.h>
21#include <sm/conf.h>
22#include <sm/string.h>
23
24/*
25**  SM_STRTOLL --  Convert a string to a (signed) long long integer.
26**
27**  Ignores `locale' stuff.  Assumes that the upper and lower case
28**  alphabets and digits are each contiguous.
29**
30**      Parameters:
31**              nptr -- string containing number
32**              endptr -- location of first invalid character
33**              base -- numeric base that 'nptr' number is based in
34**
35**      Returns:
36**              Failure: on underflow LLONG_MIN is returned; on overflow
37**                      LLONG_MAX is returned and errno is set.
38**                      When 'endptr' == '\0' then the entire string 'nptr'
39**                      was valid.
40**              Success: returns the converted number
41*/
42
43LONGLONG_T
44sm_strtoll(nptr, endptr, base)
45        const char *nptr;
46        char **endptr;
47        register int base;
48{
49        register bool neg;
50        register const char *s;
51        register LONGLONG_T acc, cutoff;
52        register int c;
53        register int any, cutlim;
54
55        /*
56        **  Skip white space and pick up leading +/- sign if any.
57        **  If base is 0, allow 0x for hex and 0 for octal, else
58        **  assume decimal; if base is already 16, allow 0x.
59        */
60
61        s = nptr;
62        do
63        {
64                c = (unsigned char) *s++;
65        } while (isascii(c) && isspace(c));
66        if (c == '-')
67        {
68                neg = true;
69                c = *s++;
70        }
71        else
72        {
73                neg = false;
74                if (c == '+')
75                        c = *s++;
76        }
77        if ((base == 0 || base == 16) &&
78            c == '0' && (*s == 'x' || *s == 'X'))
79        {
80                c = s[1];
81                s += 2;
82                base = 16;
83        }
84        if (base == 0)
85                base = c == '0' ? 8 : 10;
86
87        /*
88        **  Compute the cutoff value between legal numbers and illegal
89        **  numbers.  That is the largest legal value, divided by the
90        **  base.  An input number that is greater than this value, if
91        **  followed by a legal input character, is too big.  One that
92        **  is equal to this value may be valid or not; the limit
93        **  between valid and invalid numbers is then based on the last
94        **  digit.  For instance, if the range for long-long's is
95        **  [-9223372036854775808..9223372036854775807] and the input base
96        **  is 10, cutoff will be set to 922337203685477580 and cutlim to
97        **  either 7 (!neg) or 8 (neg), meaning that if we have
98        **  accumulated a value > 922337203685477580, or equal but the
99        **  next digit is > 7 (or 8), the number is too big, and we will
100        **  return a range error.
101        **
102        **  Set any if any `digits' consumed; make it negative to indicate
103        **  overflow.
104        */
105
106        cutoff = neg ? LLONG_MIN : LLONG_MAX;
107        cutlim = cutoff % base;
108        cutoff /= base;
109        if (neg)
110        {
111                if (cutlim > 0)
112                {
113                        cutlim -= base;
114                        cutoff += 1;
115                }
116                cutlim = -cutlim;
117        }
118        for (acc = 0, any = 0;; c = (unsigned char) *s++)
119        {
120                if (isascii(c) && isdigit(c))
121                        c -= '0';
122                else if (isascii(c) && isalpha(c))
123                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
124                else
125                        break;
126                if (c >= base)
127                        break;
128                if (any < 0)
129                        continue;
130                if (neg)
131                {
132                        if (acc < cutoff || (acc == cutoff && c > cutlim))
133                        {
134                                any = -1;
135                                acc = LLONG_MIN;
136                                errno = ERANGE;
137                        }
138                        else
139                        {
140                                any = 1;
141                                acc *= base;
142                                acc -= c;
143                        }
144                }
145                else
146                {
147                        if (acc > cutoff || (acc == cutoff && c > cutlim))
148                        {
149                                any = -1;
150                                acc = LLONG_MAX;
151                                errno = ERANGE;
152                        }
153                        else
154                        {
155                                any = 1;
156                                acc *= base;
157                                acc += c;
158                        }
159                }
160        }
161        if (endptr != 0)
162                *endptr = (char *) (any ? s - 1 : nptr);
163        return acc;
164}
165
166/*
167**  SM_STRTOULL --  Convert a string to an unsigned long long integer.
168**
169**  Ignores `locale' stuff.  Assumes that the upper and lower case
170**  alphabets and digits are each contiguous.
171**
172**      Parameters:
173**              nptr -- string containing (unsigned) number
174**              endptr -- location of first invalid character
175**              base -- numeric base that 'nptr' number is based in
176**
177**      Returns:
178**              Failure: on overflow ULLONG_MAX is returned and errno is set.
179**                      When 'endptr' == '\0' then the entire string 'nptr'
180**                      was valid.
181**              Success: returns the converted number
182*/
183
184ULONGLONG_T
185sm_strtoull(nptr, endptr, base)
186        const char *nptr;
187        char **endptr;
188        register int base;
189{
190        register const char *s;
191        register ULONGLONG_T acc, cutoff;
192        register int c;
193        register bool neg;
194        register int any, cutlim;
195
196        /* See sm_strtoll for comments as to the logic used. */
197        s = nptr;
198        do
199        {
200                c = (unsigned char) *s++;
201        } while (isascii(c) && isspace(c));
202        neg = (c == '-');
203        if (neg)
204        {
205                c = *s++;
206        }
207        else
208        {
209                if (c == '+')
210                        c = *s++;
211        }
212        if ((base == 0 || base == 16) &&
213            c == '0' && (*s == 'x' || *s == 'X'))
214        {
215                c = s[1];
216                s += 2;
217                base = 16;
218        }
219        if (base == 0)
220                base = c == '0' ? 8 : 10;
221
222        cutoff = ULLONG_MAX / (ULONGLONG_T)base;
223        cutlim = ULLONG_MAX % (ULONGLONG_T)base;
224        for (acc = 0, any = 0;; c = (unsigned char) *s++)
225        {
226                if (isascii(c) && isdigit(c))
227                        c -= '0';
228                else if (isascii(c) && isalpha(c))
229                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
230                else
231                        break;
232                if (c >= base)
233                        break;
234                if (any < 0)
235                        continue;
236                if (acc > cutoff || (acc == cutoff && c > cutlim))
237                {
238                        any = -1;
239                        acc = ULLONG_MAX;
240                        errno = ERANGE;
241                }
242                else
243                {
244                        any = 1;
245                        acc *= (ULONGLONG_T)base;
246                        acc += c;
247                }
248        }
249        if (neg && any > 0)
250                acc = -((LONGLONG_T) acc);
251        if (endptr != 0)
252                *endptr = (char *) (any ? s - 1 : nptr);
253        return acc;
254}
Note: See TracBrowser for help on using the repository browser.