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