wcstod.c revision 1.4.8.1 1 1.4.8.1 riz /* $NetBSD: wcstod.c,v 1.4.8.1 2006/04/28 21:54:19 riz Exp $ */
2 1.1 yamt
3 1.1 yamt /*-
4 1.4.8.1 riz * Copyright (c) 2002 Tim J. Robbins
5 1.1 yamt * All rights reserved.
6 1.1 yamt *
7 1.1 yamt * Redistribution and use in source and binary forms, with or without
8 1.1 yamt * modification, are permitted provided that the following conditions
9 1.1 yamt * are met:
10 1.1 yamt * 1. Redistributions of source code must retain the above copyright
11 1.1 yamt * notice, this list of conditions and the following disclaimer.
12 1.1 yamt * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 yamt * notice, this list of conditions and the following disclaimer in the
14 1.1 yamt * documentation and/or other materials provided with the distribution.
15 1.1 yamt *
16 1.1 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 yamt * SUCH DAMAGE.
27 1.1 yamt *
28 1.4.8.1 riz * Original version ID:
29 1.4.8.1 riz * FreeBSD: /repoman/r/ncvs/src/lib/libc/locale/wcstod.c,v 1.4 2004/04/07 09:47:56 tjr Exp
30 1.1 yamt */
31 1.1 yamt
32 1.1 yamt #include <sys/cdefs.h>
33 1.4.8.1 riz #if defined(LIBC_SCCS) && !defined(lint)
34 1.4.8.1 riz __RCSID("$NetBSD: wcstod.c,v 1.4.8.1 2006/04/28 21:54:19 riz Exp $");
35 1.4.8.1 riz #endif /* LIBC_SCCS and not lint */
36 1.4.8.1 riz
37 1.1 yamt #include <assert.h>
38 1.1 yamt #include <errno.h>
39 1.1 yamt #include <stdlib.h>
40 1.3 erh #include <string.h>
41 1.1 yamt #include <wchar.h>
42 1.1 yamt #include <wctype.h>
43 1.1 yamt
44 1.4.8.1 riz /*
45 1.4.8.1 riz * Convert a string to a double-precision number.
46 1.4.8.1 riz *
47 1.4.8.1 riz * This is the wide-character counterpart of strtod(). So that we do not
48 1.4.8.1 riz * have to duplicate the code of strtod() here, we convert the supplied
49 1.4.8.1 riz * wide character string to multibyte and call strtod() on the result.
50 1.4.8.1 riz * This assumes that the multibyte encoding is compatible with ASCII
51 1.4.8.1 riz * for at least the digits, radix character and letters.
52 1.4.8.1 riz */
53 1.1 yamt double
54 1.4.8.1 riz wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
55 1.1 yamt {
56 1.4.8.1 riz const wchar_t *src, *start;
57 1.4.8.1 riz double val;
58 1.4.8.1 riz char *buf, *end;
59 1.4.8.1 riz size_t bufsiz, len;
60 1.1 yamt
61 1.4.8.1 riz _DIAGASSERT(nptr != NULL);
62 1.4.8.1 riz /* endptr may be null */
63 1.1 yamt
64 1.1 yamt src = nptr;
65 1.4.8.1 riz while (iswspace((wint_t)*src) != 0)
66 1.4.8.1 riz ++src;
67 1.4.8.1 riz if (*src == L'\0')
68 1.4.8.1 riz goto no_convert;
69 1.1 yamt
70 1.1 yamt /*
71 1.4.8.1 riz * Convert the supplied numeric wide char. string to multibyte.
72 1.1 yamt *
73 1.4.8.1 riz * We could attempt to find the end of the numeric portion of the
74 1.4.8.1 riz * wide char. string to avoid converting unneeded characters but
75 1.4.8.1 riz * choose not to bother; optimising the uncommon case where
76 1.4.8.1 riz * the input string contains a lot of text after the number
77 1.4.8.1 riz * duplicates a lot of strtod()'s functionality and slows down the
78 1.4.8.1 riz * most common cases.
79 1.1 yamt */
80 1.4.8.1 riz start = src;
81 1.4.8.1 riz len = wcstombs(NULL, src, 0);
82 1.4.8.1 riz if (len == (size_t)-1)
83 1.4.8.1 riz /* errno = EILSEQ */
84 1.4.8.1 riz goto no_convert;
85 1.4.8.1 riz
86 1.4.8.1 riz _DIAGASSERT(len > 0);
87 1.4.8.1 riz
88 1.4.8.1 riz bufsiz = len;
89 1.4.8.1 riz buf = (void *)malloc(bufsiz + 1);
90 1.4.8.1 riz if (buf == NULL)
91 1.4.8.1 riz /* errno = ENOMEM */
92 1.4.8.1 riz goto no_convert;
93 1.4.8.1 riz
94 1.4.8.1 riz len = wcstombs(buf, src, bufsiz + 1);
95 1.4.8.1 riz
96 1.4.8.1 riz _DIAGASSERT(len == bufsiz);
97 1.4.8.1 riz _DIAGASSERT(buf[len] == '\0');
98 1.4.8.1 riz
99 1.4.8.1 riz /* Let strtod() do most of the work for us. */
100 1.4.8.1 riz val = strtod(buf, &end);
101 1.4.8.1 riz if (buf == end) {
102 1.1 yamt free(buf);
103 1.4.8.1 riz goto no_convert;
104 1.4.8.1 riz }
105 1.1 yamt
106 1.4.8.1 riz /*
107 1.4.8.1 riz * We only know where the number ended in the _multibyte_
108 1.4.8.1 riz * representation of the string. If the caller wants to know
109 1.4.8.1 riz * where it ended, count multibyte characters to find the
110 1.4.8.1 riz * corresponding position in the wide char string.
111 1.4.8.1 riz */
112 1.4.8.1 riz if (endptr != NULL)
113 1.4.8.1 riz /* XXX Assume each wide char is one byte. */
114 1.4.8.1 riz *endptr = __UNCONST(start + (size_t)(end - buf));
115 1.1 yamt
116 1.4.8.1 riz free(buf);
117 1.1 yamt
118 1.4.8.1 riz return val;
119 1.1 yamt
120 1.4.8.1 riz no_convert:
121 1.4.8.1 riz if (endptr != NULL)
122 1.4.8.1 riz *endptr = __UNCONST(nptr);
123 1.1 yamt return 0;
124 1.1 yamt }
125