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 <_ansi.h>
136 #include <errno.h>
137 #include <stdlib.h>
138 #include <string.h>
139 #include <wchar.h>
140 #include <wctype.h>
141 #include <locale.h>
142 #include <math.h>
143 #include "../locale/setlocale.h"
144 
145 #ifndef _REENT_ONLY
146 
147 double
wcstod_l(const wchar_t * nptr,wchar_t ** endptr,locale_t loc)148 wcstod_l (const wchar_t *nptr, wchar_t **endptr,
149 	   locale_t loc)
150 {
151         static const mbstate_t initial;
152         mbstate_t mbs;
153         double val;
154         char *buf, *end;
155         const wchar_t *wcp;
156         size_t len;
157 
158         while (iswspace_l(*nptr, loc))
159                 nptr++;
160 
161         /*
162          * Convert the supplied numeric wide char. string to multibyte.
163          *
164          * We could attempt to find the end of the numeric portion of the
165          * wide char. string to avoid converting unneeded characters but
166          * choose not to bother; optimising the uncommon case where
167          * the input string contains a lot of text after the number
168          * duplicates a lot of strtod()'s functionality and slows down the
169          * most common cases.
170          */
171         wcp = nptr;
172         mbs = initial;
173         if ((len = _wcsnrtombs_l(NULL, &wcp, (size_t) -1, 0, &mbs, loc))
174 	    == (size_t) -1) {
175                 if (endptr != NULL)
176                         *endptr = (wchar_t *)nptr;
177                 return (0.0);
178         }
179         if ((buf = malloc(len + 1)) == NULL)
180                 return (0.0);
181         mbs = initial;
182         _wcsnrtombs_l(buf, &wcp, (size_t) -1, len + 1, &mbs, loc);
183 
184         /* Let strtod() do most of the work for us. */
185         val = strtod_l(buf, &end, loc);
186 
187         /*
188          * We only know where the number ended in the _multibyte_
189          * representation of the string. If the caller wants to know
190          * where it ended, count multibyte characters to find the
191          * corresponding position in the wide char string.
192          */
193         if (endptr != NULL) {
194 		const char *decimal_point = __get_numeric_locale(loc)->decimal_point;
195 		/* The only valid multibyte char in a float converted by
196 		   strtod/wcstod is the radix char.  What we do here is,
197 		   figure out if the radix char was in the valid leading
198 		   float sequence in the incoming string.  If so, the
199 		   multibyte float string is strlen(radix char) - 1 bytes
200 		   longer than the incoming wide char string has characters.
201 		   To fix endptr, reposition end as if the radix char was
202 		   just one byte long.  The resulting difference (end - buf)
203 		   is then equivalent to the number of valid wide characters
204 		   in the input string. */
205 		len = strlen (decimal_point);
206 		if (len > 1) {
207 			char *d = strstr (buf, decimal_point);
208 			if (d && d < end)
209 				end -= len - 1;
210 		}
211                 *endptr = (wchar_t *)nptr + (end - buf);
212 	}
213 
214         free(buf);
215 
216         return (val);
217 }
218 
219 float
wcstof_l(const wchar_t * nptr,wchar_t ** endptr,locale_t loc)220 wcstof_l (const wchar_t *nptr, wchar_t **endptr,
221 	   locale_t loc)
222 {
223         static const mbstate_t initial;
224         mbstate_t mbs;
225         float val;
226         char *buf, *end;
227         const wchar_t *wcp;
228         size_t len;
229 
230         while (iswspace_l(*nptr, loc))
231                 nptr++;
232 
233         /*
234          * Convert the supplied numeric wide char. string to multibyte.
235          *
236          * We could attempt to find the end of the numeric portion of the
237          * wide char. string to avoid converting unneeded characters but
238          * choose not to bother; optimising the uncommon case where
239          * the input string contains a lot of text after the number
240          * duplicates a lot of strtod()'s functionality and slows down the
241          * most common cases.
242          */
243         wcp = nptr;
244         mbs = initial;
245         if ((len = _wcsnrtombs_l(NULL, &wcp, (size_t) -1, 0, &mbs, loc))
246 	    == (size_t) -1) {
247                 if (endptr != NULL)
248                         *endptr = (wchar_t *)nptr;
249                 return (0.0);
250         }
251         if ((buf = malloc(len + 1)) == NULL)
252                 return (0.0);
253         mbs = initial;
254         _wcsnrtombs_l(buf, &wcp, (size_t) -1, len + 1, &mbs, loc);
255 
256         /* Let strtod() do most of the work for us. */
257         val = strtof_l(buf, &end, loc);
258 
259         /*
260          * We only know where the number ended in the _multibyte_
261          * representation of the string. If the caller wants to know
262          * where it ended, count multibyte characters to find the
263          * corresponding position in the wide char string.
264          */
265         if (endptr != NULL) {
266 		const char *decimal_point = __get_numeric_locale(loc)->decimal_point;
267 		/* The only valid multibyte char in a float converted by
268 		   strtod/wcstod is the radix char.  What we do here is,
269 		   figure out if the radix char was in the valid leading
270 		   float sequence in the incoming string.  If so, the
271 		   multibyte float string is strlen(radix char) - 1 bytes
272 		   longer than the incoming wide char string has characters.
273 		   To fix endptr, reposition end as if the radix char was
274 		   just one byte long.  The resulting difference (end - buf)
275 		   is then equivalent to the number of valid wide characters
276 		   in the input string. */
277 		len = strlen (decimal_point);
278 		if (len > 1) {
279 			char *d = strstr (buf, decimal_point);
280 			if (d && d < end)
281 				end -= len - 1;
282 		}
283                 *endptr = (wchar_t *)nptr + (end - buf);
284 	}
285 
286         free(buf);
287 
288         return (val);
289 }
290 
291 double
wcstod(const wchar_t * __restrict nptr,wchar_t ** __restrict endptr)292 wcstod (const wchar_t *__restrict nptr, wchar_t **__restrict endptr)
293 {
294   return wcstod_l (nptr, endptr, __get_current_locale ());
295 }
296 
297 float
wcstof(const wchar_t * __restrict nptr,wchar_t ** __restrict endptr)298 wcstof (const wchar_t *__restrict nptr,
299 	wchar_t **__restrict endptr)
300 {
301   return wcstof_l (nptr, endptr, __get_current_locale ());
302 }
303 
304 #endif
305