1872b698pfg/*-
2872b698pfg * SPDX-License-Identifier: BSD-3-Clause
3872b698pfg *
4be22b15rgrimes * Copyright (c) 1990, 1993
5be22b15rgrimes *	The Regents of the University of California.  All rights reserved.
6be22b15rgrimes *
70f6ef69theraven * Copyright (c) 2011 The FreeBSD Foundation
80f6ef69theraven * All rights reserved.
90f6ef69theraven * Portions of this software were developed by David Chisnall
100f6ef69theraven * under sponsorship from the FreeBSD Foundation.
110f6ef69theraven *
12be22b15rgrimes * Redistribution and use in source and binary forms, with or without
13be22b15rgrimes * modification, are permitted provided that the following conditions
14be22b15rgrimes * are met:
15be22b15rgrimes * 1. Redistributions of source code must retain the above copyright
16be22b15rgrimes *    notice, this list of conditions and the following disclaimer.
17be22b15rgrimes * 2. Redistributions in binary form must reproduce the above copyright
18be22b15rgrimes *    notice, this list of conditions and the following disclaimer in the
19be22b15rgrimes *    documentation and/or other materials provided with the distribution.
20a027d64emaste * 3. Neither the name of the University nor the names of its contributors
21be22b15rgrimes *    may be used to endorse or promote products derived from this software
22be22b15rgrimes *    without specific prior written permission.
23be22b15rgrimes *
24be22b15rgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25be22b15rgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26be22b15rgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27be22b15rgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28be22b15rgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29be22b15rgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30be22b15rgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31be22b15rgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32be22b15rgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33be22b15rgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34be22b15rgrimes * SUCH DAMAGE.
35be22b15rgrimes */
36be22b15rgrimes
37be22b15rgrimes#if defined(LIBC_SCCS) && !defined(lint)
38be22b15rgrimesstatic char sccsid[] = "@(#)strtoul.c	8.1 (Berkeley) 6/4/93";
39be22b15rgrimes#endif /* LIBC_SCCS and not lint */
40d90536eobrien#include <sys/cdefs.h>
41d90536eobrien__FBSDID("$FreeBSD$");
42be22b15rgrimes
43be22b15rgrimes#include <limits.h>
44be22b15rgrimes#include <ctype.h>
45be22b15rgrimes#include <errno.h>
46be22b15rgrimes#include <stdlib.h>
470f6ef69theraven#include "xlocale_private.h"
48be22b15rgrimes
49be22b15rgrimes/*
50be22b15rgrimes * Convert a string to an unsigned long integer.
51be22b15rgrimes *
52cd61d5aache * Assumes that the upper and lower case
53be22b15rgrimes * alphabets and digits are each contiguous.
54be22b15rgrimes */
55be22b15rgrimesunsigned long
560f6ef69theravenstrtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale)
57be22b15rgrimes{
58950bfdfache	const char *s;
59950bfdfache	unsigned long acc;
60153ef07ache	char c;
61950bfdfache	unsigned long cutoff;
62153ef07ache	int neg, any, cutlim;
630f6ef69theraven	FIX_LOCALE(locale);
64be22b15rgrimes
65be22b15rgrimes	/*
66be22b15rgrimes	 * See strtol for comments as to the logic used.
67be22b15rgrimes	 */
68cd61d5aache	s = nptr;
69be22b15rgrimes	do {
70be22b15rgrimes		c = *s++;
710f6ef69theraven	} while (isspace_l((unsigned char)c, locale));
72be22b15rgrimes	if (c == '-') {
73be22b15rgrimes		neg = 1;
74be22b15rgrimes		c = *s++;
75cd61d5aache	} else {
76cd61d5aache		neg = 0;
77cd61d5aache		if (c == '+')
78cd61d5aache			c = *s++;
79cd61d5aache	}
80be22b15rgrimes	if ((base == 0 || base == 16) &&
81b05ac67ache	    c == '0' && (*s == 'x' || *s == 'X') &&
825c490b0ache	    ((s[1] >= '0' && s[1] <= '9') ||
835c490b0ache	    (s[1] >= 'A' && s[1] <= 'F') ||
845c490b0ache	    (s[1] >= 'a' && s[1] <= 'f'))) {
85be22b15rgrimes		c = s[1];
86be22b15rgrimes		s += 2;
87be22b15rgrimes		base = 16;
88be22b15rgrimes	}
89be22b15rgrimes	if (base == 0)
90be22b15rgrimes		base = c == '0' ? 8 : 10;
9148c9c31ache	acc = any = 0;
92b43213cfenner	if (base < 2 || base > 36)
93cd61d5aache		goto noconv;
94cd61d5aache
95cd61d5aache	cutoff = ULONG_MAX / base;
96cd61d5aache	cutlim = ULONG_MAX % base;
9748c9c31ache	for ( ; ; c = *s++) {
98153ef07ache		if (c >= '0' && c <= '9')
99153ef07ache			c -= '0';
100153ef07ache		else if (c >= 'A' && c <= 'Z')
101153ef07ache			c -= 'A' - 10;
102153ef07ache		else if (c >= 'a' && c <= 'z')
103153ef07ache			c -= 'a' - 10;
104be22b15rgrimes		else
105be22b15rgrimes			break;
106153ef07ache		if (c >= base)
107be22b15rgrimes			break;
108153ef07ache		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
109be22b15rgrimes			any = -1;
110be22b15rgrimes		else {
111be22b15rgrimes			any = 1;
112be22b15rgrimes			acc *= base;
113153ef07ache			acc += c;
114be22b15rgrimes		}
115be22b15rgrimes	}
116be22b15rgrimes	if (any < 0) {
117be22b15rgrimes		acc = ULONG_MAX;
118be22b15rgrimes		errno = ERANGE;
119cd61d5aache	} else if (!any) {
120cd61d5aachenoconv:
121cd61d5aache		errno = EINVAL;
122be22b15rgrimes	} else if (neg)
123be22b15rgrimes		acc = -acc;
124cd61d5aache	if (endptr != NULL)
125be22b15rgrimes		*endptr = (char *)(any ? s - 1 : nptr);
126be22b15rgrimes	return (acc);
127be22b15rgrimes}
1280f6ef69theravenunsigned long
1290f6ef69theravenstrtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
1300f6ef69theraven{
1310f6ef69theraven	return strtoul_l(nptr, endptr, base, __get_locale());
1320f6ef69theraven}
133