140266059SGregory Neil Shapiro /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers. 340266059SGregory Neil Shapiro * All rights reserved. 440266059SGregory Neil Shapiro * Copyright (c) 1992 540266059SGregory Neil Shapiro * The Regents of the University of California. All rights reserved. 640266059SGregory Neil Shapiro * 740266059SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 840266059SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 940266059SGregory Neil Shapiro * the sendmail distribution. 1040266059SGregory Neil Shapiro */ 1140266059SGregory Neil Shapiro 1240266059SGregory Neil Shapiro #include <sm/gen.h> 134313cc83SGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: strto.c,v 1.19 2013-11-22 20:51:43 ca Exp $") 1440266059SGregory Neil Shapiro 1540266059SGregory Neil Shapiro #include <sys/param.h> 1640266059SGregory Neil Shapiro #include <sys/types.h> 1740266059SGregory Neil Shapiro #include <stdlib.h> 1840266059SGregory Neil Shapiro #include <ctype.h> 1940266059SGregory Neil Shapiro #include <errno.h> 2040266059SGregory Neil Shapiro #include <sm/limits.h> 2140266059SGregory Neil Shapiro #include <sm/conf.h> 2240266059SGregory Neil Shapiro #include <sm/string.h> 2340266059SGregory Neil Shapiro 2440266059SGregory Neil Shapiro /* 2540266059SGregory Neil Shapiro ** SM_STRTOLL -- Convert a string to a (signed) long long integer. 2640266059SGregory Neil Shapiro ** 2740266059SGregory Neil Shapiro ** Ignores `locale' stuff. Assumes that the upper and lower case 2840266059SGregory Neil Shapiro ** alphabets and digits are each contiguous. 2940266059SGregory Neil Shapiro ** 3040266059SGregory Neil Shapiro ** Parameters: 3140266059SGregory Neil Shapiro ** nptr -- string containing number 3240266059SGregory Neil Shapiro ** endptr -- location of first invalid character 3340266059SGregory Neil Shapiro ** base -- numeric base that 'nptr' number is based in 3440266059SGregory Neil Shapiro ** 3540266059SGregory Neil Shapiro ** Returns: 3640266059SGregory Neil Shapiro ** Failure: on underflow LLONG_MIN is returned; on overflow 3740266059SGregory Neil Shapiro ** LLONG_MAX is returned and errno is set. 3840266059SGregory Neil Shapiro ** When 'endptr' == '\0' then the entire string 'nptr' 3940266059SGregory Neil Shapiro ** was valid. 4040266059SGregory Neil Shapiro ** Success: returns the converted number 4140266059SGregory Neil Shapiro */ 4240266059SGregory Neil Shapiro 4340266059SGregory Neil Shapiro LONGLONG_T 4440266059SGregory Neil Shapiro sm_strtoll(nptr, endptr, base) 4540266059SGregory Neil Shapiro const char *nptr; 4640266059SGregory Neil Shapiro char **endptr; 4740266059SGregory Neil Shapiro register int base; 4840266059SGregory Neil Shapiro { 4940266059SGregory Neil Shapiro register bool neg; 5040266059SGregory Neil Shapiro register const char *s; 5140266059SGregory Neil Shapiro register LONGLONG_T acc, cutoff; 5240266059SGregory Neil Shapiro register int c; 5340266059SGregory Neil Shapiro register int any, cutlim; 5440266059SGregory Neil Shapiro 5540266059SGregory Neil Shapiro /* 5640266059SGregory Neil Shapiro ** Skip white space and pick up leading +/- sign if any. 5740266059SGregory Neil Shapiro ** If base is 0, allow 0x for hex and 0 for octal, else 5840266059SGregory Neil Shapiro ** assume decimal; if base is already 16, allow 0x. 5940266059SGregory Neil Shapiro */ 6040266059SGregory Neil Shapiro 6140266059SGregory Neil Shapiro s = nptr; 6240266059SGregory Neil Shapiro do 6340266059SGregory Neil Shapiro { 6440266059SGregory Neil Shapiro c = (unsigned char) *s++; 6540266059SGregory Neil Shapiro } while (isascii(c) && isspace(c)); 6640266059SGregory Neil Shapiro if (c == '-') 6740266059SGregory Neil Shapiro { 6840266059SGregory Neil Shapiro neg = true; 6940266059SGregory Neil Shapiro c = *s++; 7040266059SGregory Neil Shapiro } 7140266059SGregory Neil Shapiro else 7240266059SGregory Neil Shapiro { 7340266059SGregory Neil Shapiro neg = false; 7440266059SGregory Neil Shapiro if (c == '+') 7540266059SGregory Neil Shapiro c = *s++; 7640266059SGregory Neil Shapiro } 7740266059SGregory Neil Shapiro if ((base == 0 || base == 16) && 7840266059SGregory Neil Shapiro c == '0' && (*s == 'x' || *s == 'X')) 7940266059SGregory Neil Shapiro { 8040266059SGregory Neil Shapiro c = s[1]; 8140266059SGregory Neil Shapiro s += 2; 8240266059SGregory Neil Shapiro base = 16; 8340266059SGregory Neil Shapiro } 8440266059SGregory Neil Shapiro if (base == 0) 8540266059SGregory Neil Shapiro base = c == '0' ? 8 : 10; 8640266059SGregory Neil Shapiro 8740266059SGregory Neil Shapiro /* 8840266059SGregory Neil Shapiro ** Compute the cutoff value between legal numbers and illegal 8940266059SGregory Neil Shapiro ** numbers. That is the largest legal value, divided by the 9040266059SGregory Neil Shapiro ** base. An input number that is greater than this value, if 9140266059SGregory Neil Shapiro ** followed by a legal input character, is too big. One that 9240266059SGregory Neil Shapiro ** is equal to this value may be valid or not; the limit 9340266059SGregory Neil Shapiro ** between valid and invalid numbers is then based on the last 9440266059SGregory Neil Shapiro ** digit. For instance, if the range for long-long's is 9540266059SGregory Neil Shapiro ** [-9223372036854775808..9223372036854775807] and the input base 9640266059SGregory Neil Shapiro ** is 10, cutoff will be set to 922337203685477580 and cutlim to 9740266059SGregory Neil Shapiro ** either 7 (!neg) or 8 (neg), meaning that if we have 9840266059SGregory Neil Shapiro ** accumulated a value > 922337203685477580, or equal but the 9940266059SGregory Neil Shapiro ** next digit is > 7 (or 8), the number is too big, and we will 10040266059SGregory Neil Shapiro ** return a range error. 10140266059SGregory Neil Shapiro ** 10240266059SGregory Neil Shapiro ** Set any if any `digits' consumed; make it negative to indicate 10340266059SGregory Neil Shapiro ** overflow. 10440266059SGregory Neil Shapiro */ 10540266059SGregory Neil Shapiro 10640266059SGregory Neil Shapiro cutoff = neg ? LLONG_MIN : LLONG_MAX; 10740266059SGregory Neil Shapiro cutlim = cutoff % base; 10840266059SGregory Neil Shapiro cutoff /= base; 10940266059SGregory Neil Shapiro if (neg) 11040266059SGregory Neil Shapiro { 11140266059SGregory Neil Shapiro if (cutlim > 0) 11240266059SGregory Neil Shapiro { 11340266059SGregory Neil Shapiro cutlim -= base; 11440266059SGregory Neil Shapiro cutoff += 1; 11540266059SGregory Neil Shapiro } 11640266059SGregory Neil Shapiro cutlim = -cutlim; 11740266059SGregory Neil Shapiro } 11840266059SGregory Neil Shapiro for (acc = 0, any = 0;; c = (unsigned char) *s++) 11940266059SGregory Neil Shapiro { 12040266059SGregory Neil Shapiro if (isascii(c) && isdigit(c)) 12140266059SGregory Neil Shapiro c -= '0'; 12240266059SGregory Neil Shapiro else if (isascii(c) && isalpha(c)) 12340266059SGregory Neil Shapiro c -= isupper(c) ? 'A' - 10 : 'a' - 10; 12440266059SGregory Neil Shapiro else 12540266059SGregory Neil Shapiro break; 12640266059SGregory Neil Shapiro if (c >= base) 12740266059SGregory Neil Shapiro break; 12840266059SGregory Neil Shapiro if (any < 0) 12940266059SGregory Neil Shapiro continue; 13040266059SGregory Neil Shapiro if (neg) 13140266059SGregory Neil Shapiro { 13240266059SGregory Neil Shapiro if (acc < cutoff || (acc == cutoff && c > cutlim)) 13340266059SGregory Neil Shapiro { 13440266059SGregory Neil Shapiro any = -1; 13540266059SGregory Neil Shapiro acc = LLONG_MIN; 13640266059SGregory Neil Shapiro errno = ERANGE; 13740266059SGregory Neil Shapiro } 13840266059SGregory Neil Shapiro else 13940266059SGregory Neil Shapiro { 14040266059SGregory Neil Shapiro any = 1; 14140266059SGregory Neil Shapiro acc *= base; 14240266059SGregory Neil Shapiro acc -= c; 14340266059SGregory Neil Shapiro } 14440266059SGregory Neil Shapiro } 14540266059SGregory Neil Shapiro else 14640266059SGregory Neil Shapiro { 14740266059SGregory Neil Shapiro if (acc > cutoff || (acc == cutoff && c > cutlim)) 14840266059SGregory Neil Shapiro { 14940266059SGregory Neil Shapiro any = -1; 15040266059SGregory Neil Shapiro acc = LLONG_MAX; 15140266059SGregory Neil Shapiro errno = ERANGE; 15240266059SGregory Neil Shapiro } 15340266059SGregory Neil Shapiro else 15440266059SGregory Neil Shapiro { 15540266059SGregory Neil Shapiro any = 1; 15640266059SGregory Neil Shapiro acc *= base; 15740266059SGregory Neil Shapiro acc += c; 15840266059SGregory Neil Shapiro } 15940266059SGregory Neil Shapiro } 16040266059SGregory Neil Shapiro } 161*5b0945b5SGregory Neil Shapiro if (endptr != NULL) 16240266059SGregory Neil Shapiro *endptr = (char *) (any ? s - 1 : nptr); 16340266059SGregory Neil Shapiro return acc; 16440266059SGregory Neil Shapiro } 16540266059SGregory Neil Shapiro 16640266059SGregory Neil Shapiro /* 16740266059SGregory Neil Shapiro ** SM_STRTOULL -- Convert a string to an unsigned long long integer. 16840266059SGregory Neil Shapiro ** 16940266059SGregory Neil Shapiro ** Ignores `locale' stuff. Assumes that the upper and lower case 17040266059SGregory Neil Shapiro ** alphabets and digits are each contiguous. 17140266059SGregory Neil Shapiro ** 17240266059SGregory Neil Shapiro ** Parameters: 17340266059SGregory Neil Shapiro ** nptr -- string containing (unsigned) number 17440266059SGregory Neil Shapiro ** endptr -- location of first invalid character 17540266059SGregory Neil Shapiro ** base -- numeric base that 'nptr' number is based in 17640266059SGregory Neil Shapiro ** 17740266059SGregory Neil Shapiro ** Returns: 17840266059SGregory Neil Shapiro ** Failure: on overflow ULLONG_MAX is returned and errno is set. 17940266059SGregory Neil Shapiro ** When 'endptr' == '\0' then the entire string 'nptr' 18040266059SGregory Neil Shapiro ** was valid. 18140266059SGregory Neil Shapiro ** Success: returns the converted number 18240266059SGregory Neil Shapiro */ 18340266059SGregory Neil Shapiro 18440266059SGregory Neil Shapiro ULONGLONG_T 18540266059SGregory Neil Shapiro sm_strtoull(nptr, endptr, base) 18640266059SGregory Neil Shapiro const char *nptr; 18740266059SGregory Neil Shapiro char **endptr; 18840266059SGregory Neil Shapiro register int base; 18940266059SGregory Neil Shapiro { 19040266059SGregory Neil Shapiro register const char *s; 19140266059SGregory Neil Shapiro register ULONGLONG_T acc, cutoff; 19240266059SGregory Neil Shapiro register int c; 19340266059SGregory Neil Shapiro register bool neg; 19440266059SGregory Neil Shapiro register int any, cutlim; 19540266059SGregory Neil Shapiro 19640266059SGregory Neil Shapiro /* See sm_strtoll for comments as to the logic used. */ 19740266059SGregory Neil Shapiro s = nptr; 19840266059SGregory Neil Shapiro do 19940266059SGregory Neil Shapiro { 20040266059SGregory Neil Shapiro c = (unsigned char) *s++; 20140266059SGregory Neil Shapiro } while (isascii(c) && isspace(c)); 20240266059SGregory Neil Shapiro neg = (c == '-'); 20340266059SGregory Neil Shapiro if (neg) 20440266059SGregory Neil Shapiro { 20540266059SGregory Neil Shapiro c = *s++; 20640266059SGregory Neil Shapiro } 20740266059SGregory Neil Shapiro else 20840266059SGregory Neil Shapiro { 20940266059SGregory Neil Shapiro if (c == '+') 21040266059SGregory Neil Shapiro c = *s++; 21140266059SGregory Neil Shapiro } 21240266059SGregory Neil Shapiro if ((base == 0 || base == 16) && 21340266059SGregory Neil Shapiro c == '0' && (*s == 'x' || *s == 'X')) 21440266059SGregory Neil Shapiro { 21540266059SGregory Neil Shapiro c = s[1]; 21640266059SGregory Neil Shapiro s += 2; 21740266059SGregory Neil Shapiro base = 16; 21840266059SGregory Neil Shapiro } 21940266059SGregory Neil Shapiro if (base == 0) 22040266059SGregory Neil Shapiro base = c == '0' ? 8 : 10; 22140266059SGregory Neil Shapiro 22240266059SGregory Neil Shapiro cutoff = ULLONG_MAX / (ULONGLONG_T)base; 22340266059SGregory Neil Shapiro cutlim = ULLONG_MAX % (ULONGLONG_T)base; 22440266059SGregory Neil Shapiro for (acc = 0, any = 0;; c = (unsigned char) *s++) 22540266059SGregory Neil Shapiro { 22640266059SGregory Neil Shapiro if (isascii(c) && isdigit(c)) 22740266059SGregory Neil Shapiro c -= '0'; 22840266059SGregory Neil Shapiro else if (isascii(c) && isalpha(c)) 22940266059SGregory Neil Shapiro c -= isupper(c) ? 'A' - 10 : 'a' - 10; 23040266059SGregory Neil Shapiro else 23140266059SGregory Neil Shapiro break; 23240266059SGregory Neil Shapiro if (c >= base) 23340266059SGregory Neil Shapiro break; 23440266059SGregory Neil Shapiro if (any < 0) 23540266059SGregory Neil Shapiro continue; 23640266059SGregory Neil Shapiro if (acc > cutoff || (acc == cutoff && c > cutlim)) 23740266059SGregory Neil Shapiro { 23840266059SGregory Neil Shapiro any = -1; 23940266059SGregory Neil Shapiro acc = ULLONG_MAX; 24040266059SGregory Neil Shapiro errno = ERANGE; 24140266059SGregory Neil Shapiro } 24240266059SGregory Neil Shapiro else 24340266059SGregory Neil Shapiro { 24440266059SGregory Neil Shapiro any = 1; 24540266059SGregory Neil Shapiro acc *= (ULONGLONG_T)base; 24640266059SGregory Neil Shapiro acc += c; 24740266059SGregory Neil Shapiro } 24840266059SGregory Neil Shapiro } 24940266059SGregory Neil Shapiro if (neg && any > 0) 25040266059SGregory Neil Shapiro acc = -((LONGLONG_T) acc); 251*5b0945b5SGregory Neil Shapiro if (endptr != NULL) 25240266059SGregory Neil Shapiro *endptr = (char *) (any ? s - 1 : nptr); 25340266059SGregory Neil Shapiro return acc; 25440266059SGregory Neil Shapiro } 255