1103097Stjr/*- 2103097Stjr * Copyright (c) 1990, 1993 3103097Stjr * The Regents of the University of California. All rights reserved. 4103097Stjr * 5227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation 6227753Stheraven * All rights reserved. 7227753Stheraven * Portions of this software were developed by David Chisnall 8227753Stheraven * under sponsorship from the FreeBSD Foundation. 9227753Stheraven * 10103097Stjr * Redistribution and use in source and binary forms, with or without 11103097Stjr * modification, are permitted provided that the following conditions 12103097Stjr * are met: 13103097Stjr * 1. Redistributions of source code must retain the above copyright 14103097Stjr * notice, this list of conditions and the following disclaimer. 15103097Stjr * 2. Redistributions in binary form must reproduce the above copyright 16103097Stjr * notice, this list of conditions and the following disclaimer in the 17103097Stjr * documentation and/or other materials provided with the distribution. 18103097Stjr * 4. Neither the name of the University nor the names of its contributors 19103097Stjr * may be used to endorse or promote products derived from this software 20103097Stjr * without specific prior written permission. 21103097Stjr * 22103097Stjr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23103097Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24103097Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25103097Stjr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26103097Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27103097Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28103097Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103097Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30103097Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31103097Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32103097Stjr * SUCH DAMAGE. 33103097Stjr */ 34103097Stjr 35103097Stjr#include <sys/cdefs.h> 36103097Stjr__FBSDID("$FreeBSD$"); 37103097Stjr 38103097Stjr#include <ctype.h> 39103097Stjr#include <errno.h> 40103097Stjr#include <limits.h> 41103097Stjr#include <wchar.h> 42103097Stjr#include <wctype.h> 43227753Stheraven#include "xlocale_private.h" 44103097Stjr 45103097Stjr/* 46103097Stjr * Convert a string to a long integer. 47103097Stjr */ 48103097Stjrlong 49227753Stheravenwcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int 50227753Stheraven base, locale_t locale) 51103097Stjr{ 52103097Stjr const wchar_t *s; 53103097Stjr unsigned long acc; 54103097Stjr wchar_t c; 55103097Stjr unsigned long cutoff; 56103097Stjr int neg, any, cutlim; 57227753Stheraven FIX_LOCALE(locale); 58103097Stjr 59103097Stjr /* 60103097Stjr * See strtol for comments as to the logic used. 61103097Stjr */ 62103097Stjr s = nptr; 63103097Stjr do { 64103097Stjr c = *s++; 65227753Stheraven } while (iswspace_l(c, locale)); 66103097Stjr if (c == '-') { 67103097Stjr neg = 1; 68103097Stjr c = *s++; 69103097Stjr } else { 70103097Stjr neg = 0; 71103097Stjr if (c == L'+') 72103097Stjr c = *s++; 73103097Stjr } 74103097Stjr if ((base == 0 || base == 16) && 75103097Stjr c == L'0' && (*s == L'x' || *s == L'X')) { 76103097Stjr c = s[1]; 77103097Stjr s += 2; 78103097Stjr base = 16; 79103097Stjr } 80103097Stjr if (base == 0) 81103097Stjr base = c == L'0' ? 8 : 10; 82103097Stjr acc = any = 0; 83103097Stjr if (base < 2 || base > 36) 84103097Stjr goto noconv; 85103097Stjr 86103097Stjr cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX 87103097Stjr : LONG_MAX; 88103097Stjr cutlim = cutoff % base; 89103097Stjr cutoff /= base; 90103097Stjr for ( ; ; c = *s++) { 91103097Stjr#ifdef notyet 92227753Stheraven if (iswdigit_l(c, locale)) 93227753Stheraven c = digittoint_l(c, locale); 94103097Stjr else 95103097Stjr#endif 96103097Stjr if (c >= L'0' && c <= L'9') 97103097Stjr c -= L'0'; 98103097Stjr else if (c >= L'A' && c <= L'Z') 99103097Stjr c -= L'A' - 10; 100103097Stjr else if (c >= L'a' && c <= L'z') 101103097Stjr c -= L'a' - 10; 102103097Stjr else 103103097Stjr break; 104103097Stjr if (c >= base) 105103097Stjr break; 106103097Stjr if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 107103097Stjr any = -1; 108103097Stjr else { 109103097Stjr any = 1; 110103097Stjr acc *= base; 111103097Stjr acc += c; 112103097Stjr } 113103097Stjr } 114103097Stjr if (any < 0) { 115103097Stjr acc = neg ? LONG_MIN : LONG_MAX; 116103097Stjr errno = ERANGE; 117103097Stjr } else if (!any) { 118103097Stjrnoconv: 119103097Stjr errno = EINVAL; 120103097Stjr } else if (neg) 121103097Stjr acc = -acc; 122103097Stjr if (endptr != NULL) 123103097Stjr *endptr = (wchar_t *)(any ? s - 1 : nptr); 124103097Stjr return (acc); 125103097Stjr} 126227753Stheravenlong 127227753Stheravenwcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) 128227753Stheraven{ 129227753Stheraven return wcstol_l(nptr, endptr, base, __get_locale()); 130227753Stheraven} 131