1103793Stjr/*- 2103793Stjr * Copyright (c) 1992, 1993 3103793Stjr * The Regents of the University of California. All rights reserved. 4103793Stjr * 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 * 10103793Stjr * Redistribution and use in source and binary forms, with or without 11103793Stjr * modification, are permitted provided that the following conditions 12103793Stjr * are met: 13103793Stjr * 1. Redistributions of source code must retain the above copyright 14103793Stjr * notice, this list of conditions and the following disclaimer. 15103793Stjr * 2. Redistributions in binary form must reproduce the above copyright 16103793Stjr * notice, this list of conditions and the following disclaimer in the 17103793Stjr * documentation and/or other materials provided with the distribution. 18103793Stjr * 4. Neither the name of the University nor the names of its contributors 19103793Stjr * may be used to endorse or promote products derived from this software 20103793Stjr * without specific prior written permission. 21103793Stjr * 22103793Stjr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23103793Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24103793Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25103793Stjr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26103793Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27103793Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28103793Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103793Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30103793Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31103793Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32103793Stjr * SUCH DAMAGE. 33103793Stjr */ 34103793Stjr 35103793Stjr#include <sys/cdefs.h> 36103793Stjr#if 0 37103793Stjr#if defined(LIBC_SCCS) && !defined(lint) 38103793Stjrstatic char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93"; 39103793Stjr#endif /* LIBC_SCCS and not lint */ 40103793Stjr__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.19 2002/09/06 11:23:59 tjr Exp "); 41103793Stjr#endif 42103793Stjr__FBSDID("$FreeBSD$"); 43103793Stjr 44103793Stjr#include <errno.h> 45103793Stjr#include <limits.h> 46103793Stjr#include <stdlib.h> 47103793Stjr#include <wchar.h> 48103793Stjr#include <wctype.h> 49227753Stheraven#include "xlocale_private.h" 50103793Stjr 51103793Stjr/* 52103793Stjr * Convert a wide character string to a long long integer. 53103793Stjr */ 54103793Stjrlong long 55227753Stheravenwcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, 56227753Stheraven int base, locale_t locale) 57103793Stjr{ 58103793Stjr const wchar_t *s; 59103793Stjr unsigned long long acc; 60103793Stjr wchar_t c; 61103793Stjr unsigned long long cutoff; 62103793Stjr int neg, any, cutlim; 63227753Stheraven FIX_LOCALE(locale); 64103793Stjr 65103793Stjr /* 66103793Stjr * See strtoll for comments as to the logic used. 67103793Stjr */ 68103793Stjr s = nptr; 69103793Stjr do { 70103793Stjr c = *s++; 71227753Stheraven } while (iswspace_l(c, locale)); 72103793Stjr if (c == L'-') { 73103793Stjr neg = 1; 74103793Stjr c = *s++; 75103793Stjr } else { 76103793Stjr neg = 0; 77103793Stjr if (c == L'+') 78103793Stjr c = *s++; 79103793Stjr } 80103793Stjr if ((base == 0 || base == 16) && 81103793Stjr c == L'0' && (*s == L'x' || *s == L'X')) { 82103793Stjr c = s[1]; 83103793Stjr s += 2; 84103793Stjr base = 16; 85103793Stjr } 86103793Stjr if (base == 0) 87103793Stjr base = c == L'0' ? 8 : 10; 88103793Stjr acc = any = 0; 89103793Stjr if (base < 2 || base > 36) 90103793Stjr goto noconv; 91103793Stjr 92103793Stjr cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX 93103793Stjr : LLONG_MAX; 94103793Stjr cutlim = cutoff % base; 95103793Stjr cutoff /= base; 96103793Stjr for ( ; ; c = *s++) { 97103793Stjr#ifdef notyet 98227753Stheraven if (iswdigit_l(c, locale)) 99227753Stheraven c = digittoint_l(c, locale); 100103793Stjr else 101103793Stjr#endif 102103793Stjr if (c >= L'0' && c <= L'9') 103103793Stjr c -= L'0'; 104103793Stjr else if (c >= L'A' && c <= L'Z') 105103793Stjr c -= L'A' - 10; 106103793Stjr else if (c >= L'a' && c <= L'z') 107103793Stjr c -= L'a' - 10; 108103793Stjr else 109103793Stjr break; 110103793Stjr if (c >= base) 111103793Stjr break; 112103793Stjr if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 113103793Stjr any = -1; 114103793Stjr else { 115103793Stjr any = 1; 116103793Stjr acc *= base; 117103793Stjr acc += c; 118103793Stjr } 119103793Stjr } 120103793Stjr if (any < 0) { 121103793Stjr acc = neg ? LLONG_MIN : LLONG_MAX; 122103793Stjr errno = ERANGE; 123103793Stjr } else if (!any) { 124103793Stjrnoconv: 125103793Stjr errno = EINVAL; 126103793Stjr } else if (neg) 127103793Stjr acc = -acc; 128103793Stjr if (endptr != NULL) 129103793Stjr *endptr = (wchar_t *)(any ? s - 1 : nptr); 130103793Stjr return (acc); 131103793Stjr} 132227753Stheravenlong long 133227753Stheravenwcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) 134227753Stheraven{ 135227753Stheraven return wcstoll_l(nptr, endptr, base, __get_locale()); 136227753Stheraven} 137