1/*- 2 * Copyright (c) 2002 Tim J. Robbins 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: src/lib/libc/locale/wcstod.c,v 1.4 2004/04/07 09:47:56 tjr Exp $"); 29 30#include "xlocale_private.h" 31 32#include <stdlib.h> 33#include <wchar.h> 34#include <wctype.h> 35#include <_simple.h> 36 37/* 38 * __wcs_end_offset calculates the offset to the end within the wide character 39 * string, assuming numbers and letters are single bytes in multibyte 40 * representation, get the actual decimal string for localeconv_l. If the 41 * decimal point was within the string, compensate for the fact that the 42 * (possible more than one byte) decimal point one takes one wide character. 43 */ 44__private_extern__ size_t 45__wcs_end_offset(const char * __restrict buf, const char * __restrict end, locale_t loc) 46{ 47 const char *decimalpoint = localeconv_l(loc)->decimal_point; 48 size_t n = end - buf; 49 char *p; 50 51 if ((p = strnstr(buf, decimalpoint, n)) != NULL) 52 n -= strlen(decimalpoint) - 1; 53 return n; 54} 55 56/* 57 * Convert a string to a double-precision number. 58 * 59 * This is the wide-character counterpart of strtod(). So that we do not 60 * have to duplicate the code of strtod() here, we convert the supplied 61 * wide character string to multibyte and call strtod() on the result. 62 * This assumes that the multibyte encoding is compatible with ASCII 63 * for at least the digits and letters. The radix character can be more 64 * than one byte. 65 */ 66 67double 68wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, 69 locale_t loc) 70{ 71 static const mbstate_t initial; 72 mbstate_t mbs; 73 double val; 74 char *buf, *end; 75 size_t len; 76 locale_t ctype; 77 _SIMPLE_STRING b; 78 char mb[MB_CUR_MAX + 1]; 79 const wchar_t *nptr0 = nptr; 80 const wchar_t *first; 81 82 NORMALIZE_LOCALE(loc); 83 ctype = __numeric_ctype(loc); 84 85 while (iswspace_l(*nptr, ctype)) 86 nptr++; 87 88 if ((b = _simple_salloc()) == NULL) 89 return (0.0); 90 91 first = nptr; 92 mbs = initial; 93 while (*nptr && (len = wcrtomb_l(mb, *nptr, &mbs, ctype)) != (size_t)-1) { 94 mb[len] = 0; 95 if (_simple_sappend(b, mb) < 0) { /* no memory */ 96 _simple_sfree(b); 97 return (0.0); 98 } 99 nptr++; 100 } 101 102 /* Let strtod() do most of the work for us. */ 103 buf = _simple_string(b); 104 val = strtod_l(buf, &end, loc); 105 106 /* 107 * We only know where the number ended in the _multibyte_ 108 * representation of the string. If the caller wants to know 109 * where it ended, count multibyte characters to find the 110 * corresponding position in the wide char string. 111 */ 112 if (endptr != NULL) 113 /* XXX Assume each wide char is one byte. */ 114 *endptr = (end == buf) ? (wchar_t *)nptr0 : ((wchar_t *)first + __wcs_end_offset(buf, end, loc)); 115 116 _simple_sfree(b); 117 118 return (val); 119} 120 121double 122wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) 123{ 124 return wcstod_l(nptr, endptr, __current_locale()); 125} 126