118334Speter/*-
218334Speter * Copyright (c) 1990, 1993
318334Speter *	The Regents of the University of California.  All rights reserved.
490075Sobrien *
5169689Skan * This code is derived from software contributed to Berkeley by
618334Speter * Chris Torek.
790075Sobrien *
818334Speter * Redistribution and use in source and binary forms, with or without
990075Sobrien * modification, are permitted provided that the following conditions
1090075Sobrien * are met:
1190075Sobrien * 1. Redistributions of source code must retain the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer.
1318334Speter * 2. Redistributions in binary form must reproduce the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1690075Sobrien * 4. Neither the name of the University nor the names of its contributors
1790075Sobrien *    may be used to endorse or promote products derived from this software
1818334Speter *    without specific prior written permission.
1918334Speter *
2090075Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2318334Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2418334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2650397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2918334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3090075Sobrien * SUCH DAMAGE.
3190075Sobrien */
3218334Speter
3318334Speter#include <sys/cdefs.h>
34132718Skan__FBSDID("$FreeBSD: releng/11.0/sys/libkern/strtouq.c 298069 2016-04-15 16:10:11Z pfg $");
3518334Speter
36117395Skan#include <sys/param.h>
37117395Skan#include <sys/systm.h>
38117395Skan#include <sys/ctype.h>
3918334Speter#include <sys/limits.h>
4018334Speter
4118334Speter/*
4290075Sobrien * Convert a string to an unsigned quad integer.
43117395Skan *
44117395Skan * Ignores `locale' stuff.  Assumes that the upper and lower case
45117395Skan * alphabets and digits are each contiguous.
46117395Skan */
47117395Skanu_quad_t
48117395Skanstrtouq(const char *nptr, char **endptr, int base)
4918334Speter{
5018334Speter	const char *s = nptr;
5118334Speter	u_quad_t acc;
52132718Skan	unsigned char c;
5318334Speter	u_quad_t qbase, cutoff;
5418334Speter	int neg, any, cutlim;
5518334Speter
5690075Sobrien	/*
5718334Speter	 * See strtoq for comments as to the logic used.
58117395Skan	 */
59117395Skan	do {
60117395Skan		c = *s++;
61117395Skan	} while (isspace(c));
6290075Sobrien	if (c == '-') {
6390075Sobrien		neg = 1;
6418334Speter		c = *s++;
6590075Sobrien	} else {
6690075Sobrien		neg = 0;
6790075Sobrien		if (c == '+')
6890075Sobrien			c = *s++;
6990075Sobrien	}
7090075Sobrien	if ((base == 0 || base == 16) &&
7190075Sobrien	    c == '0' && (*s == 'x' || *s == 'X')) {
7290075Sobrien		c = s[1];
7318334Speter		s += 2;
7418334Speter		base = 16;
7518334Speter	}
7618334Speter	if (base == 0)
7718334Speter		base = c == '0' ? 8 : 10;
7890075Sobrien	qbase = (unsigned)base;
7990075Sobrien	cutoff = (u_quad_t)UQUAD_MAX / qbase;
8090075Sobrien	cutlim = (u_quad_t)UQUAD_MAX % qbase;
8190075Sobrien	for (acc = 0, any = 0;; c = *s++) {
8290075Sobrien		if (!isascii(c))
8318334Speter			break;
8418334Speter		if (isdigit(c))
8518334Speter			c -= '0';
86117395Skan		else if (isalpha(c))
8718334Speter			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
8818334Speter		else
89117395Skan			break;
9090075Sobrien		if (c >= base)
9190075Sobrien			break;
9290075Sobrien		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
9318334Speter			any = -1;
9490075Sobrien		else {
9590075Sobrien			any = 1;
9618334Speter			acc *= qbase;
9790075Sobrien			acc += c;
9890075Sobrien		}
99	}
100	if (any < 0) {
101		acc = UQUAD_MAX;
102	} else if (neg)
103		acc = -acc;
104	if (endptr != NULL)
105		*endptr = __DECONST(char *, any ? s - 1 : nptr);
106	return (acc);
107}
108