1193323Sed/* 2193323Sed * Copyright (c) 1990, 1993 3193323Sed * The Regents of the University of California. All rights reserved. 4193323Sed * 5193323Sed * Copyright (c) 2011 The FreeBSD Foundation 6193323Sed * All rights reserved. 7193323Sed * Portions of this software were developed by David Chisnall 8193323Sed * under sponsorship from the FreeBSD Foundation. 9193323Sed * 10193323Sed * Redistribution and use in source and binary forms, with or without 11193323Sed * modification, are permitted provided that the following conditions 12193323Sed * are met: 13193323Sed * 1. Redistributions of source code must retain the above copyright 14193323Sed * notice, this list of conditions and the following disclaimer. 15193323Sed * 2. Redistributions in binary form must reproduce the above copyright 16193323Sed * notice, this list of conditions and the following disclaimer in the 17193323Sed * documentation and/or other materials provided with the distribution. 18249423Sdim * 4. Neither the name of the University nor the names of its contributors 19249423Sdim * may be used to endorse or promote products derived from this software 20198090Srdivacky * without specific prior written permission. 21198090Srdivacky * 22193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32193323Sed * SUCH DAMAGE. 33193323Sed */ 34193323Sed 35193323Sed#include <sys/cdefs.h> 36193323Sed__FBSDID("$FreeBSD$"); 37193323Sed 38193323Sed#include <ctype.h> 39193323Sed#include <errno.h> 40193323Sed#include <limits.h> 41193323Sed#include <wchar.h> 42193323Sed#include <wctype.h> 43193323Sed#include "xlocale_private.h" 44249423Sdim 45193323Sed/* 46249423Sdim * Convert a wide character string to an unsigned long integer. 47193323Sed */ 48249423Sdimunsigned long 49193323Sedwcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, 50249423Sdim int base, locale_t locale) 51193323Sed{ 52249423Sdim const wchar_t *s; 53193323Sed unsigned long acc; 54193323Sed wchar_t c; 55193323Sed unsigned long cutoff; 56193323Sed int neg, any, cutlim; 57193323Sed FIX_LOCALE(locale); 58193323Sed 59193323Sed /* 60249423Sdim * See strtol for comments as to the logic used. 61193323Sed */ 62193323Sed s = nptr; 63193323Sed do { 64249423Sdim c = *s++; 65193323Sed } while (iswspace_l(c, locale)); 66193323Sed if (c == L'-') { 67193323Sed neg = 1; 68249423Sdim c = *s++; 69193323Sed } else { 70249423Sdim neg = 0; 71249423Sdim if (c == L'+') 72249423Sdim c = *s++; 73193323Sed } 74193323Sed if ((base == 0 || base == 16) && 75249423Sdim c == L'0' && (*s == L'x' || *s == L'X')) { 76249423Sdim c = s[1]; 77249423Sdim s += 2; 78193323Sed base = 16; 79193323Sed } 80249423Sdim if (base == 0) 81193323Sed base = c == L'0' ? 8 : 10; 82193323Sed acc = any = 0; 83249423Sdim if (base < 2 || base > 36) 84249423Sdim goto noconv; 85193323Sed 86193323Sed cutoff = ULONG_MAX / base; 87193323Sed cutlim = ULONG_MAX % base; 88249423Sdim for ( ; ; c = *s++) { 89234353Sdim#ifdef notyet 90234353Sdim if (iswdigit_l(c, locale)) 91193323Sed c = digittoint_l(c, locale); 92193323Sed else 93193323Sed#endif 94193323Sed if (c >= L'0' && c <= L'9') 95193323Sed c -= L'0'; 96193323Sed else if (c >= L'A' && c <= L'Z') 97193323Sed c -= L'A' - 10; 98193323Sed else if (c >= L'a' && c <= L'z') 99193323Sed c -= L'a' - 10; 100249423Sdim else 101193323Sed break; 102249423Sdim if (c >= base) 103193323Sed break; 104193323Sed if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 105249423Sdim any = -1; 106249423Sdim else { 107249423Sdim any = 1; 108193323Sed acc *= base; 109193323Sed acc += c; 110249423Sdim } 111193323Sed } 112193323Sed if (any < 0) { 113193323Sed acc = ULONG_MAX; 114193323Sed errno = ERANGE; 115193323Sed } else if (!any) { 116193323Sednoconv: 117249423Sdim errno = EINVAL; 118193323Sed } else if (neg) 119193323Sed acc = -acc; 120193323Sed if (endptr != NULL) 121249423Sdim *endptr = (wchar_t *)(any ? s - 1 : nptr); 122193323Sed return (acc); 123193323Sed} 124193323Sedunsigned long 125193323Sedwcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) 126193323Sed{ 127193323Sed return wcstoul_l(nptr, endptr, base, __get_locale()); 128249423Sdim} 129193323Sed