summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2016-12-03 18:47:04 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2016-12-03 18:47:04 +0900
commita0fbc46ccd3e129532b05a9fe4f13f42a3c349b2 (patch)
treef3196f462149109c467e6ad6b1bf677d03e48112
parent802e396466142698af401f9700bfa61e67024074 (diff)
downloadmruby-a0fbc46ccd3e129532b05a9fe4f13f42a3c349b2.tar.gz
mruby-a0fbc46ccd3e129532b05a9fe4f13f42a3c349b2.zip
Import locale insensitive strtod() from Ruby1.8; fix #3270
The function was renamed to `mrb_float_read(const char*, char**)`.
-rw-r--r--include/mruby/value.h5
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c4
-rw-r--r--mrbgems/mruby-compiler/core/parse.y2
-rw-r--r--src/string.c242
4 files changed, 245 insertions, 8 deletions
diff --git a/include/mruby/value.h b/include/mruby/value.h
index 61110e3dd..54d197f8f 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -62,12 +62,12 @@ struct mrb_state;
# define MRB_PRIx PRIx32
#endif
+
+MRB_API double mrb_float_read(const char*, char**);
#ifdef MRB_USE_FLOAT
typedef float mrb_float;
-# define str_to_mrb_float(buf) strtof(buf, NULL)
#else
typedef double mrb_float;
-# define str_to_mrb_float(buf) strtod(buf, NULL)
#endif
#if defined _MSC_VER && _MSC_VER < 1900
@@ -85,7 +85,6 @@ MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...);
# define isnan _isnan
# define isinf(n) (!_finite(n) && !_isnan(n))
# define signbit(n) (_copysign(1.0, (n)) < 0.0)
-# define strtof (float)strtod
static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000;
# define INFINITY (*(float *)&IEEE754_INFINITY_BITS_SINGLE)
# define NAN ((float)(INFINITY - INFINITY))
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 414ca2627..b2cd12225 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -2211,7 +2211,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_FLOAT:
if (val) {
char *p = (char*)tree;
- mrb_float f = str_to_mrb_float(p);
+ mrb_float f = mrb_float_read(p, NULL);
int off = new_lit(s, mrb_float_value(s->mrb, f));
genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
@@ -2227,7 +2227,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_FLOAT:
{
char *p = (char*)tree;
- mrb_float f = str_to_mrb_float(p);
+ mrb_float f = mrb_float_read(p, NULL);
int off = new_lit(s, mrb_float_value(s->mrb, -f));
genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index e81d191d9..19cb88e5b 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -4912,7 +4912,7 @@ parser_yylex(parser_state *p)
char *endp;
errno = 0;
- d = strtod(tok(p), &endp);
+ d = mrb_float_read(tok(p), &endp);
if (d == 0 && endp == tok(p)) {
yywarning_s(p, "corrupted float value %s", tok(p));
}
diff --git a/src/string.c b/src/string.c
index f47294291..e3a268f78 100644
--- a/src/string.c
+++ b/src/string.c
@@ -2286,7 +2286,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck)
if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
return 0.0;
}
- d = strtod(p, &end);
+ d = mrb_float_read(p, &end);
if (p == end) {
if (badcheck) {
bad:
@@ -2324,7 +2324,7 @@ bad:
return 0.0;
}
- d = strtod(p, &end);
+ d = mrb_float_read(p, &end);
if (badcheck) {
if (!end || p == end) goto bad;
while (*end && ISSPACE(*end)) end++;
@@ -2749,3 +2749,241 @@ mrb_init_string(mrb_state *mrb)
mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE());
}
+
+/*
+ * 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: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $
+ */
+
+#include <ctype.h>
+#include <errno.h>
+extern int errno;
+
+#ifndef __STDC__
+# ifdef __GNUC__
+# define const __const__
+# else
+# define const
+# endif
+#endif
+
+static const 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 const 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
+};
+
+double
+mrb_float_read(const char *string, char **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;
+ const double *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;
+}