aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc1
-rw-r--r--src/library.js92
-rw-r--r--system/lib/libc.symbols6
-rw-r--r--system/lib/libc/stdlib/strtod.c305
-rwxr-xr-xtests/runner.py4
-rw-r--r--tools/shared.py2
6 files changed, 317 insertions, 93 deletions
diff --git a/emcc b/emcc
index d54b30f7..fa62acb1 100755
--- a/emcc
+++ b/emcc
@@ -1081,6 +1081,7 @@ try:
os.path.join('libc', 'gen', 'verrx.c'),
os.path.join('libc', 'gen', 'vwarn.c'),
os.path.join('libc', 'gen', 'vwarnx.c'),
+ os.path.join('libc', 'stdlib', 'strtod.c'),
];
for src in libc_files:
diff --git a/src/library.js b/src/library.js
index 075f9750..c40921ae 100644
--- a/src/library.js
+++ b/src/library.js
@@ -3738,93 +3738,6 @@ LibraryManager.library = {
return ret;
},
- strtod__deps: ['isspace', 'isdigit'],
- strtod: function(str, endptr) {
- var origin = str;
-
- // Skip space.
- while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
-
- // Check for a plus/minus sign.
- var multiplier = 1;
- if ({{{ makeGetValue('str', 0, 'i8') }}} == '-'.charCodeAt(0)) {
- multiplier = -1;
- str++;
- } else if ({{{ makeGetValue('str', 0, 'i8') }}} == '+'.charCodeAt(0)) {
- str++;
- }
-
- var chr;
- var ret = 0;
-
- // Get whole part.
- var whole = false;
- while(1) {
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (!_isdigit(chr)) break;
- whole = true;
- ret = ret*10 + chr - '0'.charCodeAt(0);
- str++;
- }
-
- // Get fractional part.
- var fraction = false;
- if ({{{ makeGetValue('str', 0, 'i8') }}} == '.'.charCodeAt(0)) {
- str++;
- var mul = 1/10;
- while(1) {
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (!_isdigit(chr)) break;
- fraction = true;
- ret += mul*(chr - '0'.charCodeAt(0));
- mul /= 10;
- str++;
- }
- }
-
- if (!whole && !fraction) {
- if (endptr) {
- {{{ makeSetValue('endptr', 0, 'origin', '*') }}}
- }
- return 0;
- }
-
- // Get exponent part.
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (chr == 'e'.charCodeAt(0) || chr == 'E'.charCodeAt(0)) {
- str++;
- var exponent = 0;
- var expNegative = false;
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- if (chr == '-'.charCodeAt(0)) {
- expNegative = true;
- str++;
- } else if (chr == '+'.charCodeAt(0)) {
- str++;
- }
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- while(1) {
- if (!_isdigit(chr)) break;
- exponent = exponent*10 + chr - '0'.charCodeAt(0);
- str++;
- chr = {{{ makeGetValue('str', 0, 'i8') }}};
- }
- if (expNegative) exponent = -exponent;
- ret *= Math.pow(10, exponent);
- }
-
- // Set end pointer.
- if (endptr) {
- {{{ makeSetValue('endptr', 0, 'str', '*') }}}
- }
-
- return ret * multiplier;
- },
- strtod_l: 'strtod', // no locale support yet
- strtold: 'strtod', // XXX add real support for long double
- strtold_l: 'strtold', // no locale support yet
- strtof: 'strtod', // use stdtod to handle strtof
-
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
// Skip space.
@@ -3983,11 +3896,6 @@ LibraryManager.library = {
},
strtoull_l: 'strtoull', // no locale support yet
- atof__deps: ['strtod'],
- atof: function(ptr) {
- return _strtod(ptr, null);
- },
-
atoi__deps: ['strtol'],
atoi: function(ptr) {
return _strtol(ptr, null, 10);
diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols
index 416c63c8..1342d938 100644
--- a/system/lib/libc.symbols
+++ b/system/lib/libc.symbols
@@ -67,3 +67,9 @@ _vwarn
_vwarnx
_verr
_verrx
+strtod
+strtold
+strtof
+strtod_l
+strtold_l
+atof
diff --git a/system/lib/libc/stdlib/strtod.c b/system/lib/libc/stdlib/strtod.c
new file mode 100644
index 00000000..53191337
--- /dev/null
+++ b/system/lib/libc/stdlib/strtod.c
@@ -0,0 +1,305 @@
+/*
+ * strtod.c --
+ *
+ * Source code for the "strtod" library procedure.
+ *
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies. The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ *
+ * RCS: @(#) $Id$
+ *
+ * Taken from http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/missing/strtod.c
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+extern int errno;
+
+#ifndef __STDC__
+# ifdef __GNUC__
+# define const __const__
+# else
+# define const
+# endif
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+static int maxExponent = 511; /* Largest possible base 10 exponent. Any
+ * exponent larger than this will already
+ * produce underflow or overflow, so there's
+ * no need to worry about additional digits.
+ */
+static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
+ 10., /* is 10^2^i. Used to convert decimal */
+ 100., /* exponents into floating-point numbers. */
+ 1.0e4,
+ 1.0e8,
+ 1.0e16,
+ 1.0e32,
+ 1.0e64,
+ 1.0e128,
+ 1.0e256
+};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtod --
+ *
+ * This procedure converts a floating-point number from an ASCII
+ * decimal representation to internal double-precision format.
+ *
+ * Results:
+ * The return value is the double-precision floating-point
+ * representation of the characters in string. If endPtr isn't
+ * NULL, then *endPtr is filled in with the address of the
+ * next character after the last one that was part of the
+ * floating-point number.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+double
+strtod(string, endPtr)
+ const char *string; /* A decimal ASCII floating-point number,
+ * optionally preceded by white space.
+ * Must have form "-I.FE-X", where I is the
+ * integer part of the mantissa, F is the
+ * fractional part of the mantissa, and X
+ * is the exponent. Either of the signs
+ * may be "+", "-", or omitted. Either I
+ * or F may be omitted, or both. The decimal
+ * point isn't necessary unless F is present.
+ * The "E" may actually be an "e". E and X
+ * may both be omitted (but not just one).
+ */
+ char **endPtr; /* If non-NULL, store terminating character's
+ * address here. */
+{
+ int sign, expSign = FALSE;
+ double fraction, dblExp, *d;
+ register const char *p;
+ register int c;
+ int exp = 0; /* Exponent read from "EX" field. */
+ int fracExp = 0; /* Exponent that derives from the fractional
+ * part. Under normal circumstatnces, it is
+ * the negative of the number of digits in F.
+ * However, if I is very long, the last digits
+ * of I get dropped (otherwise a long I with a
+ * large negative exponent could cause an
+ * unnecessary overflow on I alone). In this
+ * case, fracExp is incremented one for each
+ * dropped digit. */
+ int mantSize; /* Number of digits in mantissa. */
+ int decPt; /* Number of mantissa digits BEFORE decimal
+ * point. */
+ const char *pExp; /* Temporarily holds location of exponent
+ * in string. */
+
+ /*
+ * Strip off leading blanks and check for a sign.
+ */
+
+ p = string;
+ while (isspace(*p)) {
+ p += 1;
+ }
+ if (*p == '-') {
+ sign = TRUE;
+ p += 1;
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ sign = FALSE;
+ }
+
+ /*
+ * Count the number of digits in the mantissa (including the decimal
+ * point), and also locate the decimal point.
+ */
+
+ decPt = -1;
+ for (mantSize = 0; ; mantSize += 1)
+ {
+ c = *p;
+ if (!isdigit(c)) {
+ if ((c != '.') || (decPt >= 0)) {
+ break;
+ }
+ decPt = mantSize;
+ }
+ p += 1;
+ }
+
+ /*
+ * Now suck up the digits in the mantissa. Use two integers to
+ * collect 9 digits each (this is faster than using floating-point).
+ * If the mantissa has more than 18 digits, ignore the extras, since
+ * they can't affect the value anyway.
+ */
+
+ pExp = p;
+ p -= mantSize;
+ if (decPt < 0) {
+ decPt = mantSize;
+ } else {
+ mantSize -= 1; /* One of the digits was the point. */
+ }
+ if (mantSize > 18) {
+ fracExp = decPt - 18;
+ mantSize = 18;
+ } else {
+ fracExp = decPt - mantSize;
+ }
+ if (mantSize == 0) {
+ fraction = 0.0;
+ p = string;
+ goto done;
+ } else {
+ int frac1, frac2;
+ frac1 = 0;
+ for ( ; mantSize > 9; mantSize -= 1)
+ {
+ c = *p;
+ p += 1;
+ if (c == '.') {
+ c = *p;
+ p += 1;
+ }
+ frac1 = 10*frac1 + (c - '0');
+ }
+ frac2 = 0;
+ for (; mantSize > 0; mantSize -= 1)
+ {
+ c = *p;
+ p += 1;
+ if (c == '.') {
+ c = *p;
+ p += 1;
+ }
+ frac2 = 10*frac2 + (c - '0');
+ }
+ fraction = (1.0e9 * frac1) + frac2;
+ }
+
+ /*
+ * Skim off the exponent.
+ */
+
+ p = pExp;
+ if ((*p == 'E') || (*p == 'e')) {
+ p += 1;
+ if (*p == '-') {
+ expSign = TRUE;
+ p += 1;
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ expSign = FALSE;
+ }
+ while (isdigit(*p)) {
+ exp = exp * 10 + (*p - '0');
+ p += 1;
+ }
+ }
+ if (expSign) {
+ exp = fracExp - exp;
+ } else {
+ exp = fracExp + exp;
+ }
+
+ /*
+ * Generate a floating-point number that represents the exponent.
+ * Do this by processing the exponent one bit at a time to combine
+ * many powers of 2 of 10. Then combine the exponent with the
+ * fraction.
+ */
+
+ if (exp < 0) {
+ expSign = TRUE;
+ exp = -exp;
+ } else {
+ expSign = FALSE;
+ }
+ if (exp > maxExponent) {
+ exp = maxExponent;
+ errno = ERANGE;
+ }
+ dblExp = 1.0;
+ for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
+ if (exp & 01) {
+ dblExp *= *d;
+ }
+ }
+ if (expSign) {
+ fraction /= dblExp;
+ } else {
+ fraction *= dblExp;
+ }
+
+done:
+ if (endPtr != NULL) {
+ *endPtr = (char *) p;
+ }
+
+ if (sign) {
+ return -fraction;
+ }
+ return fraction;
+}
+
+/*
+ * Implementations added for emscripten.
+ */
+// XXX add real support for long double
+long double
+strtold(const char* nptr, char **endptr)
+{
+ return (long double) strtod(nptr, endptr);
+}
+
+// use stdtod to handle strtof
+float
+strtof(const char* nptr, char **endptr)
+{
+ return (float) strtof(nptr, endptr);
+}
+
+// XXX no locale support yet
+double
+strtod_l(const char* nptr, char **endptr, locale_t loc)
+{
+ return strtod(nptr, endptr);
+}
+long double
+strtold_l(const char* nptr, char **endptr, locale_t loc)
+{
+ return strtold(nptr, endptr);
+}
+
+double atof(const char* str)
+{
+ return strtod(str, (char **) NULL);
+}
diff --git a/tests/runner.py b/tests/runner.py
index 7e3c73b0..8fe786ba 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -5054,6 +5054,9 @@ def process(filename):
printf("%g\n", strtod(str, &endptr));
printf("%d\n", endptr - str);
printf("%g\n", strtod("84e+420", &endptr));
+
+ printf("%.12f\n", strtod("1.2345678900000000e+08", NULL));
+
return 0;
}
'''
@@ -5081,6 +5084,7 @@ def process(filename):
1.234e+57
10
inf
+ 123456789.000000000000
'''
self.do_run(src, re.sub(r'\n\s+', '\n', expected))
diff --git a/tools/shared.py b/tools/shared.py
index 6434fb06..e60800a5 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -181,7 +181,7 @@ def check_node_version():
# we re-check sanity when the settings are changed)
# We also re-check sanity and clear the cache when the version changes
-EMSCRIPTEN_VERSION = '1.2.8'
+EMSCRIPTEN_VERSION = '1.2.9'
def check_sanity(force=False):
try: