154495Sbostic /*- 254495Sbostic * Copyright (c) 1992 The Regents of the University of California. 354495Sbostic * All rights reserved. 454495Sbostic * 554495Sbostic * %sccs.include.redist.c% 654495Sbostic */ 754495Sbostic 854495Sbostic #if defined(LIBC_SCCS) && !defined(lint) 9*58777Storek static char sccsid[] = "@(#)strtoq.c 5.2 (Berkeley) 03/23/93"; 1054495Sbostic #endif /* LIBC_SCCS and not lint */ 1154495Sbostic 1254495Sbostic #include <sys/types.h> 1354495Sbostic 1454495Sbostic #include <limits.h> 1554495Sbostic #include <errno.h> 1654495Sbostic #include <ctype.h> 1754495Sbostic #include <stdlib.h> 1854495Sbostic 1954495Sbostic /* 2054495Sbostic * Convert a string to a quad integer. 2154495Sbostic * 2254495Sbostic * Ignores `locale' stuff. Assumes that the upper and lower case 2354495Sbostic * alphabets and digits are each contiguous. 2454495Sbostic */ 2554495Sbostic quad_t 2654495Sbostic strtoq(nptr, endptr, base) 2754495Sbostic const char *nptr; 2854495Sbostic char **endptr; 2954495Sbostic register int base; 3054495Sbostic { 3154495Sbostic register const char *s; 3254495Sbostic register u_quad_t acc; 3354495Sbostic register int c; 3454495Sbostic register u_quad_t qbase, cutoff; 3554495Sbostic register int neg, any, cutlim; 3654495Sbostic 3754495Sbostic /* 3854495Sbostic * Skip white space and pick up leading +/- sign if any. 3954495Sbostic * If base is 0, allow 0x for hex and 0 for octal, else 4054495Sbostic * assume decimal; if base is already 16, allow 0x. 4154495Sbostic */ 4254495Sbostic s = nptr; 4354495Sbostic do { 4454495Sbostic c = *s++; 4554495Sbostic } while (isspace(c)); 4654495Sbostic if (c == '-') { 4754495Sbostic neg = 1; 4854495Sbostic c = *s++; 4954495Sbostic } else { 5054495Sbostic neg = 0; 5154495Sbostic if (c == '+') 5254495Sbostic c = *s++; 5354495Sbostic } 5454495Sbostic if ((base == 0 || base == 16) && 5554495Sbostic c == '0' && (*s == 'x' || *s == 'X')) { 5654495Sbostic c = s[1]; 5754495Sbostic s += 2; 5854495Sbostic base = 16; 5954495Sbostic } 6054495Sbostic if (base == 0) 6154495Sbostic base = c == '0' ? 8 : 10; 6254495Sbostic 6354495Sbostic /* 6454495Sbostic * Compute the cutoff value between legal numbers and illegal 6554495Sbostic * numbers. That is the largest legal value, divided by the 6654495Sbostic * base. An input number that is greater than this value, if 6754495Sbostic * followed by a legal input character, is too big. One that 6854495Sbostic * is equal to this value may be valid or not; the limit 6954495Sbostic * between valid and invalid numbers is then based on the last 7054495Sbostic * digit. For instance, if the range for quads is 7154495Sbostic * [-9223372036854775808..9223372036854775807] and the input base 7254495Sbostic * is 10, cutoff will be set to 922337203685477580 and cutlim to 7354495Sbostic * either 7 (neg==0) or 8 (neg==1), meaning that if we have 7454495Sbostic * accumulated a value > 922337203685477580, or equal but the 7554495Sbostic * next digit is > 7 (or 8), the number is too big, and we will 7654495Sbostic * return a range error. 7754495Sbostic * 7854495Sbostic * Set any if any `digits' consumed; make it negative to indicate 7954495Sbostic * overflow. 8054495Sbostic */ 8154495Sbostic qbase = (unsigned)base; 8254495Sbostic cutoff = neg ? -(u_quad_t)QUAD_MIN : QUAD_MAX; 8354495Sbostic cutlim = cutoff % qbase; 8454495Sbostic cutoff /= qbase; 8554495Sbostic for (acc = 0, any = 0;; c = *s++) { 8654495Sbostic if (isdigit(c)) 8754495Sbostic c -= '0'; 8854495Sbostic else if (isalpha(c)) 8954495Sbostic c -= isupper(c) ? 'A' - 10 : 'a' - 10; 9054495Sbostic else 9154495Sbostic break; 9254495Sbostic if (c >= base) 9354495Sbostic break; 9454495Sbostic if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 9554495Sbostic any = -1; 9654495Sbostic else { 9754495Sbostic any = 1; 9854495Sbostic acc *= qbase; 9954495Sbostic acc += c; 10054495Sbostic } 10154495Sbostic } 10254495Sbostic if (any < 0) { 10354495Sbostic acc = neg ? QUAD_MIN : QUAD_MAX; 10454495Sbostic errno = ERANGE; 10554495Sbostic } else if (neg) 10654495Sbostic acc = -acc; 10754495Sbostic if (endptr != 0) 108*58777Storek *endptr = (char *)(any ? s - 1 : nptr); 10954495Sbostic return (acc); 11054495Sbostic } 111