8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sendmail / libsm / strto.c
blob78a9dffcab9c030b85e2cdbbdebab3a88a8641cd
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.
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.
12 #pragma ident "%Z%%M% %I% %E% SMI"
14 #include <sm/gen.h>
15 SM_IDSTR(id, "@(#)$Id: strto.c,v 1.18 2001/12/30 04:59:37 gshapiro Exp $")
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <sm/limits.h>
23 #include <sm/conf.h>
24 #include <sm/string.h>
27 ** SM_STRTOLL -- Convert a string to a (signed) long long integer.
29 ** Ignores `locale' stuff. Assumes that the upper and lower case
30 ** alphabets and digits are each contiguous.
32 ** Parameters:
33 ** nptr -- string containing number
34 ** endptr -- location of first invalid character
35 ** base -- numeric base that 'nptr' number is based in
37 ** Returns:
38 ** Failure: on underflow LLONG_MIN is returned; on overflow
39 ** LLONG_MAX is returned and errno is set.
40 ** When 'endptr' == '\0' then the entire string 'nptr'
41 ** was valid.
42 ** Success: returns the converted number
45 LONGLONG_T
46 sm_strtoll(nptr, endptr, base)
47 const char *nptr;
48 char **endptr;
49 register int base;
51 register bool neg;
52 register const char *s;
53 register LONGLONG_T acc, cutoff;
54 register int c;
55 register int any, cutlim;
58 ** Skip white space and pick up leading +/- sign if any.
59 ** If base is 0, allow 0x for hex and 0 for octal, else
60 ** assume decimal; if base is already 16, allow 0x.
63 s = nptr;
66 c = (unsigned char) *s++;
67 } while (isascii(c) && isspace(c));
68 if (c == '-')
70 neg = true;
71 c = *s++;
73 else
75 neg = false;
76 if (c == '+')
77 c = *s++;
79 if ((base == 0 || base == 16) &&
80 c == '0' && (*s == 'x' || *s == 'X'))
82 c = s[1];
83 s += 2;
84 base = 16;
86 if (base == 0)
87 base = c == '0' ? 8 : 10;
90 ** Compute the cutoff value between legal numbers and illegal
91 ** numbers. That is the largest legal value, divided by the
92 ** base. An input number that is greater than this value, if
93 ** followed by a legal input character, is too big. One that
94 ** is equal to this value may be valid or not; the limit
95 ** between valid and invalid numbers is then based on the last
96 ** digit. For instance, if the range for long-long's is
97 ** [-9223372036854775808..9223372036854775807] and the input base
98 ** is 10, cutoff will be set to 922337203685477580 and cutlim to
99 ** either 7 (!neg) or 8 (neg), meaning that if we have
100 ** accumulated a value > 922337203685477580, or equal but the
101 ** next digit is > 7 (or 8), the number is too big, and we will
102 ** return a range error.
104 ** Set any if any `digits' consumed; make it negative to indicate
105 ** overflow.
108 cutoff = neg ? LLONG_MIN : LLONG_MAX;
109 cutlim = cutoff % base;
110 cutoff /= base;
111 if (neg)
113 if (cutlim > 0)
115 cutlim -= base;
116 cutoff += 1;
118 cutlim = -cutlim;
120 for (acc = 0, any = 0;; c = (unsigned char) *s++)
122 if (isascii(c) && isdigit(c))
123 c -= '0';
124 else if (isascii(c) && isalpha(c))
125 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
126 else
127 break;
128 if (c >= base)
129 break;
130 if (any < 0)
131 continue;
132 if (neg)
134 if (acc < cutoff || (acc == cutoff && c > cutlim))
136 any = -1;
137 acc = LLONG_MIN;
138 errno = ERANGE;
140 else
142 any = 1;
143 acc *= base;
144 acc -= c;
147 else
149 if (acc > cutoff || (acc == cutoff && c > cutlim))
151 any = -1;
152 acc = LLONG_MAX;
153 errno = ERANGE;
155 else
157 any = 1;
158 acc *= base;
159 acc += c;
163 if (endptr != 0)
164 *endptr = (char *) (any ? s - 1 : nptr);
165 return acc;
169 ** SM_STRTOULL -- Convert a string to an unsigned long long integer.
171 ** Ignores `locale' stuff. Assumes that the upper and lower case
172 ** alphabets and digits are each contiguous.
174 ** Parameters:
175 ** nptr -- string containing (unsigned) number
176 ** endptr -- location of first invalid character
177 ** base -- numeric base that 'nptr' number is based in
179 ** Returns:
180 ** Failure: on overflow ULLONG_MAX is returned and errno is set.
181 ** When 'endptr' == '\0' then the entire string 'nptr'
182 ** was valid.
183 ** Success: returns the converted number
186 ULONGLONG_T
187 sm_strtoull(nptr, endptr, base)
188 const char *nptr;
189 char **endptr;
190 register int base;
192 register const char *s;
193 register ULONGLONG_T acc, cutoff;
194 register int c;
195 register bool neg;
196 register int any, cutlim;
198 /* See sm_strtoll for comments as to the logic used. */
199 s = nptr;
202 c = (unsigned char) *s++;
203 } while (isascii(c) && isspace(c));
204 neg = (c == '-');
205 if (neg)
207 c = *s++;
209 else
211 if (c == '+')
212 c = *s++;
214 if ((base == 0 || base == 16) &&
215 c == '0' && (*s == 'x' || *s == 'X'))
217 c = s[1];
218 s += 2;
219 base = 16;
221 if (base == 0)
222 base = c == '0' ? 8 : 10;
224 cutoff = ULLONG_MAX / (ULONGLONG_T)base;
225 cutlim = ULLONG_MAX % (ULONGLONG_T)base;
226 for (acc = 0, any = 0;; c = (unsigned char) *s++)
228 if (isascii(c) && isdigit(c))
229 c -= '0';
230 else if (isascii(c) && isalpha(c))
231 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
232 else
233 break;
234 if (c >= base)
235 break;
236 if (any < 0)
237 continue;
238 if (acc > cutoff || (acc == cutoff && c > cutlim))
240 any = -1;
241 acc = ULLONG_MAX;
242 errno = ERANGE;
244 else
246 any = 1;
247 acc *= (ULONGLONG_T)base;
248 acc += c;
251 if (neg && any > 0)
252 acc = -((LONGLONG_T) acc);
253 if (endptr != 0)
254 *endptr = (char *) (any ? s - 1 : nptr);
255 return acc;