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