strto.c revision 261363
1/* 2 * Copyright (c) 2000-2001 Proofpoint, 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.19 2013/11/22 20:51:43 ca 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} 255