138494Sobrien/* 2310490Scy * Copyright (c) 1990, 1993 338494Sobrien * The Regents of the University of California. All rights reserved. 438494Sobrien * 538494Sobrien * Copyright (c) 2011 The FreeBSD Foundation 638494Sobrien * All rights reserved. 738494Sobrien * Portions of this software were developed by David Chisnall 838494Sobrien * under sponsorship from the FreeBSD Foundation. 938494Sobrien * 1038494Sobrien * Redistribution and use in source and binary forms, with or without 1138494Sobrien * modification, are permitted provided that the following conditions 1238494Sobrien * are met: 1338494Sobrien * 1. Redistributions of source code must retain the above copyright 1438494Sobrien * notice, this list of conditions and the following disclaimer. 1538494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1638494Sobrien * notice, this list of conditions and the following disclaimer in the 1738494Sobrien * documentation and/or other materials provided with the distribution. 1838494Sobrien * 4. Neither the name of the University nor the names of its contributors 19310490Scy * may be used to endorse or promote products derived from this software 2038494Sobrien * without specific prior written permission. 2138494Sobrien * 2238494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2338494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2438494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2538494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2638494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2738494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2838494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2938494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3038494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3138494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3238494Sobrien * SUCH DAMAGE. 3338494Sobrien */ 3438494Sobrien 3538494Sobrien#if defined(LIBC_SCCS) && !defined(lint) 36174294Sobrienstatic char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; 3738494Sobrien#endif /* LIBC_SCCS and not lint */ 3838494Sobrien#include <sys/cdefs.h> 3938494Sobrien__FBSDID("$FreeBSD$"); 4038494Sobrien 4138494Sobrien#include "stand.h" 4238494Sobrien#include <limits.h> 4338494Sobrien 4438494Sobrien/* 4538494Sobrien * Convert a string to an unsigned long integer. 4638494Sobrien * 4738494Sobrien * Assumes that the upper and lower case 4838494Sobrien * alphabets and digits are each contiguous. 4938494Sobrien */ 5038494Sobrienunsigned long 5138494Sobrienstrtoul(const char * __restrict nptr, char ** __restrict endptr, int base) 5238494Sobrien{ 5338494Sobrien const char *s; 5438494Sobrien unsigned long acc; 5538494Sobrien char c; 56174294Sobrien unsigned long cutoff; 5738494Sobrien int neg, any, cutlim; 5838494Sobrien 5938494Sobrien /* 6038494Sobrien * See strtol for comments as to the logic used. 6138494Sobrien */ 6238494Sobrien s = nptr; 6338494Sobrien do { 6438494Sobrien c = *s++; 6538494Sobrien } while (isspace((unsigned char)c)); 6638494Sobrien if (c == '-') { 6738494Sobrien neg = 1; 6838494Sobrien c = *s++; 6938494Sobrien } else { 7038494Sobrien neg = 0; 7138494Sobrien if (c == '+') 7238494Sobrien c = *s++; 73174294Sobrien } 7438494Sobrien if ((base == 0 || base == 16) && 7538494Sobrien c == '0' && (*s == 'x' || *s == 'X') && 7638494Sobrien ((s[1] >= '0' && s[1] <= '9') || 7738494Sobrien (s[1] >= 'A' && s[1] <= 'F') || 7838494Sobrien (s[1] >= 'a' && s[1] <= 'f'))) { 7938494Sobrien c = s[1]; 8038494Sobrien s += 2; 8138494Sobrien base = 16; 8238494Sobrien } 8338494Sobrien if (base == 0) 8438494Sobrien base = c == '0' ? 8 : 10; 8538494Sobrien acc = any = 0; 8638494Sobrien if (base < 2 || base > 36) 8738494Sobrien goto noconv; 8838494Sobrien 8938494Sobrien cutoff = ULONG_MAX / base; 9038494Sobrien cutlim = ULONG_MAX % base; 9138494Sobrien for ( ; ; c = *s++) { 92174294Sobrien if (c >= '0' && c <= '9') 93310490Scy c -= '0'; 9438494Sobrien else if (c >= 'A' && c <= 'Z') 9538494Sobrien c -= 'A' - 10; 9638494Sobrien else if (c >= 'a' && c <= 'z') 9738494Sobrien c -= 'a' - 10; 9838494Sobrien else 9938494Sobrien break; 10038494Sobrien if (c >= base) 10138494Sobrien break; 10238494Sobrien if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 10338494Sobrien any = -1; 10438494Sobrien else { 10538494Sobrien any = 1; 10638494Sobrien acc *= base; 10738494Sobrien acc += c; 10838494Sobrien } 10938494Sobrien } 11038494Sobrien if (any < 0) { 11138494Sobrien acc = ULONG_MAX; 11238494Sobrien errno = ERANGE; 11338494Sobrien } else if (!any) { 11438494Sobriennoconv: 11538494Sobrien errno = EINVAL; 11638494Sobrien } else if (neg) 11738494Sobrien acc = -acc; 11838494Sobrien if (endptr != NULL) 11938494Sobrien *endptr = (char *)(any ? s - 1 : nptr); 12038494Sobrien return (acc); 12138494Sobrien} 12238494Sobrien