strtoq.c revision 28640
1139823Simp/*-
21541Srgrimes * Copyright (c) 1992, 1993
3180305Srwatson *	The Regents of the University of California.  All rights reserved.
4180305Srwatson *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3150477Speter * SUCH DAMAGE.
321541Srgrimes */
331541Srgrimes
341541Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3596972Stanimurastatic char sccsid[] = "@(#)strtoq.c	8.1 (Berkeley) 6/4/93";
36130387Srwatson#endif /* LIBC_SCCS and not lint */
37180390Srwatson
3829024Sbde#include <sys/types.h>
39130387Srwatson
4096972Stanimura#include <limits.h>
411541Srgrimes#include <errno.h>
421541Srgrimes#include <ctype.h>
43180390Srwatson#include <stdlib.h>
4497093Sbde
451541Srgrimes/*
46183550Szec * Convert a string to a quad integer.
471541Srgrimes *
48185571Sbz * Ignores `locale' stuff.  Assumes that the upper and lower case
491541Srgrimes * alphabets and digits are each contiguous.
501541Srgrimes */
518876Srgrimesquad_t
521541Srgrimesstrtoq(nptr, endptr, base)
531541Srgrimes	const char *nptr;
541541Srgrimes	char **endptr;
551541Srgrimes	register int base;
561541Srgrimes{
571541Srgrimes	register const char *s;
581541Srgrimes	register u_quad_t acc;
59130514Srwatson	register unsigned char c;
60195699Srwatson	register u_quad_t qbase, cutoff;
6124936Sphk	register int neg, any, cutlim;
62227309Sed
63227309Sed	/*
641541Srgrimes	 * Skip white space and pick up leading +/- sign if any.
65180390Srwatson	 * If base is 0, allow 0x for hex and 0 for octal, else
66180390Srwatson	 * assume decimal; if base is already 16, allow 0x.
67180390Srwatson	 */
68180390Srwatson	s = nptr;
69180390Srwatson	do {
70180390Srwatson		c = *s++;
71180390Srwatson	} while (isspace(c));
72180390Srwatson	if (c == '-') {
731541Srgrimes		neg = 1;
74180305Srwatson		c = *s++;
75180305Srwatson	} else {
761541Srgrimes		neg = 0;
771541Srgrimes		if (c == '+')
78180305Srwatson			c = *s++;
791541Srgrimes	}
80180305Srwatson	if ((base == 0 || base == 16) &&
811541Srgrimes	    c == '0' && (*s == 'x' || *s == 'X')) {
821541Srgrimes		c = s[1];
831541Srgrimes		s += 2;
84180391Srwatson		base = 16;
85180391Srwatson	}
86180391Srwatson	if (base == 0)
87180391Srwatson		base = c == '0' ? 8 : 10;
881541Srgrimes
89180391Srwatson	/*
90180391Srwatson	 * Compute the cutoff value between legal numbers and illegal
913443Sphk	 * numbers.  That is the largest legal value, divided by the
923443Sphk	 * base.  An input number that is greater than this value, if
931541Srgrimes	 * followed by a legal input character, is too big.  One that
941541Srgrimes	 * is equal to this value may be valid or not; the limit
951541Srgrimes	 * between valid and invalid numbers is then based on the last
961541Srgrimes	 * digit.  For instance, if the range for quads is
97130514Srwatson	 * [-9223372036854775808..9223372036854775807] and the input base
98181803Sbz	 * is 10, cutoff will be set to 922337203685477580 and cutlim to
99130514Srwatson	 * either 7 (neg==0) or 8 (neg==1), meaning that if we have
1001541Srgrimes	 * accumulated a value > 922337203685477580, or equal but the
1011541Srgrimes	 * next digit is > 7 (or 8), the number is too big, and we will
1021541Srgrimes	 * return a range error.
1031541Srgrimes	 *
104180305Srwatson	 * Set any if any `digits' consumed; make it negative to indicate
1051541Srgrimes	 * overflow.
1061541Srgrimes	 */
107180305Srwatson	qbase = (unsigned)base;
1081541Srgrimes	cutoff = neg ? (u_quad_t)-(QUAD_MIN + QUAD_MAX) + QUAD_MAX : QUAD_MAX;
1091541Srgrimes	cutlim = cutoff % qbase;
1101541Srgrimes	cutoff /= qbase;
111157370Srwatson	for (acc = 0, any = 0;; c = *s++) {
112157370Srwatson		if (!isascii(c))
113157370Srwatson			break;
114140775Srwatson		if (isdigit(c))
11524936Sphk			c -= '0';
116140775Srwatson		else if (isalpha(c))
1171541Srgrimes			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
1181541Srgrimes		else
119			break;
120		if (c >= base)
121			break;
122		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
123			any = -1;
124		else {
125			any = 1;
126			acc *= qbase;
127			acc += c;
128		}
129	}
130	if (any < 0) {
131		acc = neg ? QUAD_MIN : QUAD_MAX;
132		errno = ERANGE;
133	} else if (neg)
134		acc = -acc;
135	if (endptr != 0)
136		*endptr = (char *)(any ? s - 1 : nptr);
137	return (acc);
138}
139