1 /*
2 FUNCTION
3         <<wcstod>>, <<wcstof>>, <<wcstold>>, <<wcstod_l>>, <<wcstof_l>>, <<wcstold_l>>---wide char string to double or float
4 
5 INDEX
6 	wcstod
7 
8 INDEX
9 	wcstof
10 
11 INDEX
12 	wcstold
13 
14 INDEX
15 	wcstod_l
16 
17 INDEX
18 	wcstof_l
19 
20 INDEX
21 	wcstold_l
22 
23 INDEX
24 	_wcstod_r
25 
26 INDEX
27 	_wcstof_r
28 
29 SYNOPSIS
30         #include <stdlib.h>
31         double wcstod(const wchar_t *__restrict <[str]>,
32 		      wchar_t **__restrict <[tail]>);
33         float wcstof(const wchar_t *__restrict <[str]>,
34 		     wchar_t **__restrict <[tail]>);
35         long double wcstold(const wchar_t *__restrict <[str]>,
36 			    wchar_t **__restrict <[tail]>);
37 
38         #include <stdlib.h>
39         double wcstod_l(const wchar_t *__restrict <[str]>,
40 			wchar_t **__restrict <[tail]>, locale_t <[locale]>);
41         float wcstof_l(const wchar_t *__restrict <[str]>,
42 		       wchar_t **__restrict <[tail]>, locale_t <[locale]>);
43         long double wcstold_l(const wchar_t *__restrict <[str]>,
44 			      wchar_t **__restrict <[tail]>,
45 			      locale_t <[locale]>);
46 
47         double _wcstod_r(void *<[reent]>,
48                          const wchar_t *<[str]>, wchar_t **<[tail]>);
49         float _wcstof_r(void *<[reent]>,
50                          const wchar_t *<[str]>, wchar_t **<[tail]>);
51 
52 DESCRIPTION
53 	<<wcstod>>, <<wcstof>>, <<wcstold>> parse the wide-character string
54 	<[str]>, producing a substring which can be converted to a double,
55 	float, or long double value.  The substring converted is the longest
56 	initial subsequence of <[str]>, beginning with the first non-whitespace
57 	character, that has one of these formats:
58 	.[+|-]<[digits]>[.[<[digits]>]][(e|E)[+|-]<[digits]>]
59 	.[+|-].<[digits]>[(e|E)[+|-]<[digits]>]
60 	.[+|-](i|I)(n|N)(f|F)[(i|I)(n|N)(i|I)(t|T)(y|Y)]
61 	.[+|-](n|N)(a|A)(n|N)[<(>[<[hexdigits]>]<)>]
62 	.[+|-]0(x|X)<[hexdigits]>[.[<[hexdigits]>]][(p|P)[+|-]<[digits]>]
63 	.[+|-]0(x|X).<[hexdigits]>[(p|P)[+|-]<[digits]>]
64 	The substring contains no characters if <[str]> is empty, consists
65 	entirely of whitespace, or if the first non-whitespace
66 	character is something other than <<+>>, <<->>, <<.>>, or a
67 	digit, and cannot be parsed as infinity or NaN. If the platform
68 	does not support NaN, then NaN is treated as an empty substring.
69 	If the substring is empty, no conversion is done, and
70 	the value of <[str]> is stored in <<*<[tail]>>>.  Otherwise,
71 	the substring is converted, and a pointer to the final string
72 	(which will contain at least the terminating null character of
73 	<[str]>) is stored in <<*<[tail]>>>.  If you want no
74 	assignment to <<*<[tail]>>>, pass a null pointer as <[tail]>.
75 
76 	This implementation returns the nearest machine number to the
77 	input decimal string.  Ties are broken by using the IEEE
78 	round-even rule.  However, <<wcstof>> is currently subject to
79 	double rounding errors.
80 
81 	<<wcstod_l>>, <<wcstof_l>>, <<wcstold_l>> are like <<wcstod>>,
82 	<<wcstof>>, <<wcstold>> but perform the conversion based on the
83 	locale specified by the locale object locale.  If <[locale]> is
84 	LC_GLOBAL_LOCALE or not a valid locale object, the behaviour is
85 	undefined.
86 
87 	The alternate functions <<_wcstod_r>> and <<_wcstof_r>> are
88 	reentrant versions of <<wcstod>> and <<wcstof>>, respectively.
89 	The extra argument <[reent]> is a pointer to a reentrancy structure.
90 
91 RETURNS
92 	Return the converted substring value, if any.  If
93 	no conversion could be performed, 0 is returned.  If the
94 	correct value is out of the range of representable values,
95 	plus or minus <<HUGE_VAL>> is returned, and <<ERANGE>> is
96 	stored in errno. If the correct value would cause underflow, 0
97 	is returned and <<ERANGE>> is stored in errno.
98 
99 PORTABILITY
100 <<wcstod>> is ANSI.
101 <<wcstof>>, <<wcstold>> are C99.
102 <<wcstod_l>>, <<wcstof_l>>, <<wcstold_l>> are GNU extensions.
103 
104 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
105 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
106 */
107 
108 /*-
109  * Copyright (c) 2002 Tim J. Robbins
110  * All rights reserved.
111  *
112  * Redistribution and use in source and binary forms, with or without
113  * modification, are permitted provided that the following conditions
114  * are met:
115  * 1. Redistributions of source code must retain the above copyright
116  *    notice, this list of conditions and the following disclaimer.
117  * 2. Redistributions in binary form must reproduce the above copyright
118  *    notice, this list of conditions and the following disclaimer in the
119  *    documentation and/or other materials provided with the distribution.
120  *
121  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
122  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
123  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
124  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
125  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
126  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
127  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
128  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
129  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
130  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
131  * SUCH DAMAGE.
132  */
133 
134 #define _GNU_SOURCE
135 #include <errno.h>
136 #include <stdlib.h>
137 #include <string.h>
138 #include <wchar.h>
139 #include <wctype.h>
140 #include <locale.h>
141 #include <math.h>
142 #include "../locale/setlocale.h"
143 
144 #ifndef _REENT_ONLY
145 
146 double
wcstod_l(const wchar_t * nptr,wchar_t ** endptr,locale_t loc)147 wcstod_l (const wchar_t *nptr, wchar_t **endptr,
148 	   locale_t loc)
149 {
150         static const mbstate_t initial;
151         mbstate_t mbs;
152         double val;
153         char *buf, *end;
154         const wchar_t *wcp;
155         size_t len;
156 
157         while (iswspace_l(*nptr, loc))
158                 nptr++;
159 
160         /*
161          * Convert the supplied numeric wide char. string to multibyte.
162          *
163          * We could attempt to find the end of the numeric portion of the
164          * wide char. string to avoid converting unneeded characters but
165          * choose not to bother; optimising the uncommon case where
166          * the input string contains a lot of text after the number
167          * duplicates a lot of strtod()'s functionality and slows down the
168          * most common cases.
169          */
170         wcp = nptr;
171         mbs = initial;
172         if ((len = _wcsnrtombs_l(NULL, &wcp, (size_t) -1, 0, &mbs, loc))
173 	    == (size_t) -1) {
174                 if (endptr != NULL)
175                         *endptr = (wchar_t *)nptr;
176                 return (0.0);
177         }
178         if ((buf = malloc(len + 1)) == NULL)
179                 return (0.0);
180         mbs = initial;
181         _wcsnrtombs_l(buf, &wcp, (size_t) -1, len + 1, &mbs, loc);
182 
183         /* Let strtod() do most of the work for us. */
184         val = strtod_l(buf, &end, loc);
185 
186         /*
187          * We only know where the number ended in the _multibyte_
188          * representation of the string. If the caller wants to know
189          * where it ended, count multibyte characters to find the
190          * corresponding position in the wide char string.
191          */
192         if (endptr != NULL) {
193 		const char *decimal_point = __get_numeric_locale(loc)->decimal_point;
194 		/* The only valid multibyte char in a float converted by
195 		   strtod/wcstod is the radix char.  What we do here is,
196 		   figure out if the radix char was in the valid leading
197 		   float sequence in the incoming string.  If so, the
198 		   multibyte float string is strlen(radix char) - 1 bytes
199 		   longer than the incoming wide char string has characters.
200 		   To fix endptr, reposition end as if the radix char was
201 		   just one byte long.  The resulting difference (end - buf)
202 		   is then equivalent to the number of valid wide characters
203 		   in the input string. */
204 		len = strlen (decimal_point);
205 		if (len > 1) {
206 			char *d = strstr (buf, decimal_point);
207 			if (d && d < end)
208 				end -= len - 1;
209 		}
210                 *endptr = (wchar_t *)nptr + (end - buf);
211 	}
212 
213         free(buf);
214 
215         return (val);
216 }
217 
218 float
wcstof_l(const wchar_t * nptr,wchar_t ** endptr,locale_t loc)219 wcstof_l (const wchar_t *nptr, wchar_t **endptr,
220 	   locale_t loc)
221 {
222         static const mbstate_t initial;
223         mbstate_t mbs;
224         float val;
225         char *buf, *end;
226         const wchar_t *wcp;
227         size_t len;
228 
229         while (iswspace_l(*nptr, loc))
230                 nptr++;
231 
232         /*
233          * Convert the supplied numeric wide char. string to multibyte.
234          *
235          * We could attempt to find the end of the numeric portion of the
236          * wide char. string to avoid converting unneeded characters but
237          * choose not to bother; optimising the uncommon case where
238          * the input string contains a lot of text after the number
239          * duplicates a lot of strtod()'s functionality and slows down the
240          * most common cases.
241          */
242         wcp = nptr;
243         mbs = initial;
244         if ((len = _wcsnrtombs_l(NULL, &wcp, (size_t) -1, 0, &mbs, loc))
245 	    == (size_t) -1) {
246                 if (endptr != NULL)
247                         *endptr = (wchar_t *)nptr;
248                 return (0.0);
249         }
250         if ((buf = malloc(len + 1)) == NULL)
251                 return (0.0);
252         mbs = initial;
253         _wcsnrtombs_l(buf, &wcp, (size_t) -1, len + 1, &mbs, loc);
254 
255         /* Let strtod() do most of the work for us. */
256         val = strtof_l(buf, &end, loc);
257 
258         /*
259          * We only know where the number ended in the _multibyte_
260          * representation of the string. If the caller wants to know
261          * where it ended, count multibyte characters to find the
262          * corresponding position in the wide char string.
263          */
264         if (endptr != NULL) {
265 		const char *decimal_point = __get_numeric_locale(loc)->decimal_point;
266 		/* The only valid multibyte char in a float converted by
267 		   strtod/wcstod is the radix char.  What we do here is,
268 		   figure out if the radix char was in the valid leading
269 		   float sequence in the incoming string.  If so, the
270 		   multibyte float string is strlen(radix char) - 1 bytes
271 		   longer than the incoming wide char string has characters.
272 		   To fix endptr, reposition end as if the radix char was
273 		   just one byte long.  The resulting difference (end - buf)
274 		   is then equivalent to the number of valid wide characters
275 		   in the input string. */
276 		len = strlen (decimal_point);
277 		if (len > 1) {
278 			char *d = strstr (buf, decimal_point);
279 			if (d && d < end)
280 				end -= len - 1;
281 		}
282                 *endptr = (wchar_t *)nptr + (end - buf);
283 	}
284 
285         free(buf);
286 
287         return (val);
288 }
289 
290 double
wcstod(const wchar_t * __restrict nptr,wchar_t ** __restrict endptr)291 wcstod (const wchar_t *__restrict nptr, wchar_t **__restrict endptr)
292 {
293   return wcstod_l (nptr, endptr, __get_current_locale ());
294 }
295 
296 float
wcstof(const wchar_t * __restrict nptr,wchar_t ** __restrict endptr)297 wcstof (const wchar_t *__restrict nptr,
298 	wchar_t **__restrict endptr)
299 {
300   return wcstof_l (nptr, endptr, __get_current_locale ());
301 }
302 
303 #endif
304