1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 /*
33 * This file is based on /usr/src/lib/libc/port/gen/strtod.c and
34 * /usr/src/lib/libc/sparc/fp/string_decim.c
35 */
36
37 #pragma weak _wcstod = wcstod
38 #pragma weak _wstod = wstod
39
40 #include "lint.h"
41 #include <errno.h>
42 #include <stdio.h>
43 #include <values.h>
44 #include <floatingpoint.h>
45 #include <stddef.h>
46 #include <wctype.h>
47 #include "base_conversion.h" /* from usr/src/lib/libc/inc */
48 #include <locale.h>
49 #include "libc.h"
50 #include "xpg6.h"
51
52 static void wstring_to_decimal(const wchar_t **, int, decimal_record *, int *);
53
54 double
wcstod(const wchar_t * cp,wchar_t ** ptr)55 wcstod(const wchar_t *cp, wchar_t **ptr)
56 {
57 double x;
58 decimal_mode mr;
59 decimal_record dr;
60 fp_exception_field_type fs;
61 int form;
62
63 wstring_to_decimal(&cp, __xpg6 & _C99SUSv3_recognize_hexfp, &dr, &form);
64 if (ptr != NULL)
65 *ptr = (wchar_t *)cp;
66 if (form == 0)
67 return (0.0); /* Shameful kluge for SVID's sake. */
68 #if defined(__i386) || defined(__amd64)
69 mr.rd = __xgetRD();
70 #elif defined(__sparc)
71 mr.rd = _QgetRD();
72 #else
73 #error Unknown architecture!
74 #endif
75 if (form < 0)
76 __hex_to_double(&dr, mr.rd, &x, &fs);
77 else
78 decimal_to_double(&x, &mr, &dr, &fs);
79 if (fs & ((1 << fp_overflow) | (1 << fp_underflow)))
80 errno = ERANGE;
81 return (x);
82 }
83
84 float
wcstof(const wchar_t * cp,wchar_t ** ptr)85 wcstof(const wchar_t *cp, wchar_t **ptr)
86 {
87 float x;
88 decimal_mode mr;
89 decimal_record dr;
90 fp_exception_field_type fs;
91 int form;
92
93 wstring_to_decimal(&cp, 1, &dr, &form);
94 if (ptr != NULL)
95 *ptr = (wchar_t *)cp;
96 if (form == 0)
97 return (0.0f);
98 #if defined(__i386) || defined(__amd64)
99 mr.rd = __xgetRD();
100 #elif defined(__sparc)
101 mr.rd = _QgetRD();
102 #else
103 #error Unknown architecture!
104 #endif
105 if (form < 0)
106 __hex_to_single(&dr, mr.rd, &x, &fs);
107 else
108 decimal_to_single(&x, &mr, &dr, &fs);
109 if (fs & ((1 << fp_overflow) | (1 << fp_underflow)))
110 errno = ERANGE;
111 return (x);
112 }
113
114 long double
wcstold(const wchar_t * cp,wchar_t ** ptr)115 wcstold(const wchar_t *cp, wchar_t **ptr)
116 {
117 long double x;
118 decimal_mode mr;
119 decimal_record dr;
120 fp_exception_field_type fs;
121 int form;
122
123 wstring_to_decimal(&cp, 1, &dr, &form);
124 if (ptr != NULL)
125 *ptr = (wchar_t *)cp;
126 if (form == 0)
127 return (0.0L);
128 #if defined(__i386) || defined(__amd64)
129 mr.rd = __xgetRD();
130 if (form < 0)
131 __hex_to_extended(&dr, mr.rd, (extended *)&x, &fs);
132 else
133 decimal_to_extended((extended *)&x, &mr, &dr, &fs);
134 #elif defined(__sparc)
135 mr.rd = _QgetRD();
136 if (form < 0)
137 __hex_to_quadruple(&dr, mr.rd, &x, &fs);
138 else
139 decimal_to_quadruple(&x, &mr, &dr, &fs);
140 #else
141 #error Unknown architecture!
142 #endif
143 if (fs & ((1 << fp_overflow) | (1 << fp_underflow)))
144 errno = ERANGE;
145 return (x);
146 }
147
148 double
wstod(const wchar_t * cp,wchar_t ** ptr)149 wstod(const wchar_t *cp, wchar_t **ptr)
150 {
151 return (wcstod(cp, ptr));
152 }
153
154 static const char *infstring = "INFINITY";
155 static const char *nanstring = "NAN";
156
157 /*
158 * The following macro is applied to wchar_t arguments solely for the
159 * purpose of comparing the result with one of the characters in the
160 * strings above.
161 */
162 #define UCASE(c) (((L'a' <= c) && (c <= L'z'))? c - 32 : c)
163
164 /*
165 * The following macro yields an expression that is true whenever
166 * the argument is a valid nonzero digit for the form being parsed.
167 */
168 #define NZDIGIT(c) ((L'1' <= c && c <= L'9') || (form < 0 && \
169 ((L'a' <= c && c <= L'f') || (L'A' <= c && c <= L'F'))))
170
171 /*
172 * wstring_to_decimal is modelled on string_to_decimal, the majority
173 * of which can be found in the common file char_to_decimal.h. The
174 * significant differences are:
175 *
176 * 1. This code recognizes only C99 (hex fp strings and restricted
177 * characters in parentheses following "nan") vs. C90 modes, no
178 * Fortran conventions.
179 *
180 * 2. *pform is an int rather than an enum decimal_string_form. On
181 * return, *pform == 0 if no valid token was found, *pform < 0
182 * if a C99 hex fp string was found, and *pform > 0 if a decimal
183 * string was found.
184 */
185 static void
wstring_to_decimal(const wchar_t ** ppc,int c99,decimal_record * pd,int * pform)186 wstring_to_decimal(const wchar_t **ppc, int c99, decimal_record *pd,
187 int *pform)
188 {
189 const wchar_t *cp = *ppc; /* last character seen */
190 const wchar_t *good = cp - 1; /* last character accepted */
191 wchar_t current; /* always equal to *cp */
192 int sigfound;
193 int ids = 0;
194 int i, agree;
195 int nzbp = 0; /* number of zeros before point */
196 int nzap = 0; /* number of zeros after point */
197 char decpt;
198 int nfast, nfastlimit;
199 char *pfast;
200 int e, esign;
201 int expshift = 0;
202 int form;
203
204 /*
205 * This routine assumes that the radix point is a single
206 * ASCII character, so that following this assignment, the
207 * condition (current == decpt) will correctly detect it.
208 */
209 decpt = *(localeconv()->decimal_point);
210
211 /* input is invalid until we find something */
212 pd->fpclass = fp_signaling;
213 pd->sign = 0;
214 pd->exponent = 0;
215 pd->ds[0] = '\0';
216 pd->more = 0;
217 pd->ndigits = 0;
218 *pform = form = 0;
219
220 /* skip white space */
221 current = *cp;
222 while (iswspace((wint_t)current))
223 current = *++cp;
224
225 /* look for optional leading sign */
226 if (current == L'+') {
227 current = *++cp;
228 } else if (current == L'-') {
229 pd->sign = 1;
230 current = *++cp;
231 }
232
233 sigfound = -1; /* -1 = no digits found yet */
234
235 /*
236 * Admissible first non-white-space, non-sign characters are
237 * 0-9, i, I, n, N, or the radix point.
238 */
239 if (L'1' <= current && current <= L'9') {
240 pd->fpclass = fp_normal;
241 form = 1;
242 good = cp;
243 sigfound = 1; /* 1 = significant digits found */
244 pd->ds[ids++] = (char)current;
245 current = *++cp;
246 } else {
247 switch (current) {
248 case L'0':
249 /*
250 * Accept the leading zero and set pd->fpclass
251 * accordingly, but don't set sigfound until we
252 * determine that this isn't a "fake" hex string
253 * (i.e., 0x.p...).
254 */
255 good = cp;
256 pd->fpclass = fp_zero;
257 if (c99) {
258 /* look for a hex fp string */
259 current = *++cp;
260 if (current == L'X' || current == L'x') {
261 /* assume hex fp form */
262 form = -1;
263 expshift = 2;
264 current = *++cp;
265 /*
266 * Only a digit or radix point can
267 * follow "0x".
268 */
269 if (NZDIGIT(current)) {
270 pd->fpclass = fp_normal;
271 good = cp;
272 sigfound = 1;
273 pd->ds[ids++] = (char)current;
274 current = *++cp;
275 break;
276 } else if (current == (wchar_t)decpt) {
277 current = *++cp;
278 goto afterpoint;
279 } else if (current != L'0') {
280 /* not hex fp after all */
281 form = 1;
282 expshift = 0;
283 goto done;
284 }
285 } else {
286 form = 1;
287 }
288 } else {
289 form = 1;
290 }
291
292 /* skip all leading zeros */
293 while (current == L'0')
294 current = *++cp;
295 good = cp - 1;
296 sigfound = 0; /* 0 = only zeros found so far */
297 break;
298
299 case L'i':
300 case L'I':
301 /* look for inf or infinity */
302 current = *++cp;
303 agree = 1;
304 while (agree <= 7 &&
305 UCASE(current) == (wchar_t)infstring[agree]) {
306 current = *++cp;
307 agree++;
308 }
309 if (agree >= 3) {
310 /* found valid infinity */
311 pd->fpclass = fp_infinity;
312 form = 1;
313 good = (agree < 8)? cp + 2 - agree : cp - 1;
314 __inf_read = 1;
315 }
316 goto done;
317
318 case L'n':
319 case L'N':
320 /* look for nan or nan(string) */
321 current = *++cp;
322 agree = 1;
323 while (agree <= 2 &&
324 UCASE(current) == (wchar_t)nanstring[agree]) {
325 current = *++cp;
326 agree++;
327 }
328 if (agree == 3) {
329 /* found valid NaN */
330 pd->fpclass = fp_quiet;
331 form = 1;
332 good = cp - 1;
333 __nan_read = 1;
334 if (current == L'(') {
335 /* accept parenthesized string */
336 if (c99) {
337 do {
338 current = *++cp;
339 } while (iswalnum(current) ||
340 current == L'_');
341 } else {
342 do {
343 current = *++cp;
344 } while (current &&
345 current != L')');
346 }
347 if (current == L')')
348 good = cp;
349 }
350 }
351 goto done;
352
353 default:
354 if (current == (wchar_t)decpt) {
355 /*
356 * Don't accept the radix point just yet;
357 * we need to see at least one digit.
358 */
359 current = *++cp;
360 goto afterpoint;
361 }
362 goto done;
363 }
364 }
365
366 nextnumber:
367 /*
368 * Admissible characters after the first digit are a valid
369 * digit, an exponent delimiter (E or e for decimal form,
370 * P or p for hex form), or the radix point. (Note that we
371 * can't get here unless we've already found a digit.)
372 */
373 if (NZDIGIT(current)) {
374 /*
375 * Found another nonzero digit. If there's enough room
376 * in pd->ds, store any intervening zeros we've found so far
377 * and then store this digit. Otherwise, stop storing
378 * digits in pd->ds and set pd->more.
379 */
380 if (ids + nzbp + 2 < DECIMAL_STRING_LENGTH) {
381 for (i = 0; i < nzbp; i++)
382 pd->ds[ids++] = '0';
383 pd->ds[ids++] = (char)current;
384 } else {
385 pd->exponent += (nzbp + 1) << expshift;
386 pd->more = 1;
387 if (ids < DECIMAL_STRING_LENGTH) {
388 pd->ds[ids] = '\0';
389 pd->ndigits = ids;
390 /* don't store any more digits */
391 ids = DECIMAL_STRING_LENGTH;
392 }
393 }
394 pd->fpclass = fp_normal;
395 sigfound = 1;
396 nzbp = 0;
397 current = *++cp;
398
399 /*
400 * Use an optimized loop to grab a consecutive sequence
401 * of nonzero digits quickly.
402 */
403 nfastlimit = DECIMAL_STRING_LENGTH - 3 - ids;
404 for (nfast = 0, pfast = &(pd->ds[ids]);
405 nfast < nfastlimit && NZDIGIT(current);
406 nfast++) {
407 *pfast++ = (char)current;
408 current = *++cp;
409 }
410 ids += nfast;
411 if (current == L'0')
412 goto nextnumberzero; /* common case */
413 /* advance good to the last accepted digit */
414 good = cp - 1;
415 goto nextnumber;
416 } else {
417 switch (current) {
418 case L'0':
419 nextnumberzero:
420 /*
421 * Count zeros before the radix point. Later we
422 * will either put these zeros into pd->ds or add
423 * nzbp to pd->exponent to account for them.
424 */
425 while (current == L'0') {
426 nzbp++;
427 current = *++cp;
428 }
429 good = cp - 1;
430 goto nextnumber;
431
432 case L'E':
433 case L'e':
434 if (form < 0)
435 goto done;
436 goto exponent;
437
438 case L'P':
439 case L'p':
440 if (form > 0)
441 goto done;
442 goto exponent;
443
444 default:
445 if (current == decpt) {
446 /* accept the radix point */
447 good = cp;
448 current = *++cp;
449 goto afterpoint;
450 }
451 goto done;
452 }
453 }
454
455 afterpoint:
456 /*
457 * Admissible characters after the radix point are a valid digit
458 * or an exponent delimiter. (Note that it is possible to get
459 * here even though we haven't found any digits yet.)
460 */
461 if (NZDIGIT(current)) {
462 if (form == 0)
463 form = 1;
464 if (sigfound < 1) {
465 /* no significant digits found until now */
466 pd->fpclass = fp_normal;
467 sigfound = 1;
468 pd->ds[ids++] = (char)current;
469 pd->exponent = (-(nzap + 1)) << expshift;
470 } else {
471 /* significant digits have been found */
472 if (ids + nzbp + nzap + 2 < DECIMAL_STRING_LENGTH) {
473 for (i = 0; i < nzbp + nzap; i++)
474 pd->ds[ids++] = '0';
475 pd->ds[ids++] = (char)current;
476 pd->exponent -= (nzap + 1) << expshift;
477 } else {
478 pd->exponent += nzbp << expshift;
479 pd->more = 1;
480 if (ids < DECIMAL_STRING_LENGTH) {
481 pd->ds[ids] = '\0';
482 pd->ndigits = ids;
483 /* don't store any more digits */
484 ids = DECIMAL_STRING_LENGTH;
485 }
486 }
487 }
488 nzbp = 0;
489 nzap = 0;
490 current = *++cp;
491
492 /*
493 * Use an optimized loop to grab a consecutive sequence
494 * of nonzero digits quickly.
495 */
496 nfastlimit = DECIMAL_STRING_LENGTH - 3 - ids;
497 for (nfast = 0, pfast = &(pd->ds[ids]);
498 nfast < nfastlimit && NZDIGIT(current);
499 nfast++) {
500 *pfast++ = (char)current;
501 current = *++cp;
502 }
503 ids += nfast;
504 pd->exponent -= nfast << expshift;
505 if (current == L'0')
506 goto zeroafterpoint;
507 /* advance good to the last accepted digit */
508 good = cp - 1;
509 goto afterpoint;
510 } else {
511 switch (current) {
512 case L'0':
513 if (form == 0)
514 form = 1;
515 if (sigfound == -1) {
516 pd->fpclass = fp_zero;
517 sigfound = 0;
518 }
519 zeroafterpoint:
520 /*
521 * Count zeros after the radix point. If we find
522 * any more nonzero digits later, we will put these
523 * zeros into pd->ds and decrease pd->exponent by
524 * nzap.
525 */
526 while (current == L'0') {
527 nzap++;
528 current = *++cp;
529 }
530 good = cp - 1;
531 goto afterpoint;
532
533 case L'E':
534 case L'e':
535 /* don't accept exponent without preceding digits */
536 if (sigfound == -1 || form < 0)
537 goto done;
538 break;
539
540 case L'P':
541 case L'p':
542 /* don't accept exponent without preceding digits */
543 if (sigfound == -1 || form > 0)
544 goto done;
545 break;
546
547 default:
548 goto done;
549 }
550 }
551
552 exponent:
553 e = 0;
554 esign = 0;
555
556 /* look for optional exponent sign */
557 current = *++cp;
558 if (current == L'+') {
559 current = *++cp;
560 } else if (current == L'-') {
561 esign = 1;
562 current = *++cp;
563 }
564
565 /*
566 * Accumulate explicit exponent. Note that if we don't find at
567 * least one digit, good won't be updated and e will remain 0.
568 * Also, we keep e from getting too large so we don't overflow
569 * the range of int (but notice that the threshold is large
570 * enough that any larger e would cause the result to underflow
571 * or overflow anyway).
572 */
573 while (L'0' <= current && current <= L'9') {
574 good = cp;
575 if (e <= 1000000)
576 e = 10 * e + current - L'0';
577 current = *++cp;
578 }
579 if (esign)
580 pd->exponent -= e;
581 else
582 pd->exponent += e;
583
584 done:
585 /*
586 * If we found any zeros before the radix point that were not
587 * accounted for earlier, adjust the exponent. (This is only
588 * relevant when pd->fpclass == fp_normal, but it's harmless
589 * in all other cases.)
590 */
591 pd->exponent += nzbp << expshift;
592
593 /* terminate pd->ds if we haven't already */
594 if (ids < DECIMAL_STRING_LENGTH) {
595 pd->ds[ids] = '\0';
596 pd->ndigits = ids;
597 }
598
599 /*
600 * If we accepted any characters, advance *ppc to point to the
601 * first character we didn't accept; otherwise, pass back a
602 * signaling nan.
603 */
604 if (good >= *ppc) {
605 *ppc = good + 1;
606 } else {
607 pd->fpclass = fp_signaling;
608 pd->sign = 0;
609 form = 0;
610 }
611
612 *pform = form;
613 }
614