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