### Checks for libraries
-EFL_ADD_LIBS([EVIL], [-lpsapi -lole32 -lws2_32 -lsecur32 -luuid -lmsvcr100])
+EFL_ADD_LIBS([EVIL], [-lpsapi -lole32 -lws2_32 -lsecur32 -luuid])
### Checks for header files
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
+ *
+ * The code of eina_convert_strtod_c() is based on code published
+ * under the public domain license, which can be found here:
+ * https://gist.github.com/mattn/1890186
*/
#ifdef HAVE_CONFIG_H
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
#ifdef _WIN32
# include <Evil.h>
return EINA_TRUE;
}
+/*
+ * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strtod-strtod-l-wcstod-wcstod-l?view=vs-2017
+ *
+ * src should be one of the following form :
+ *
+ * [whitespace] [sign] {digits [radix digits] | radix digits} [{e | E} [sign] digits]
+ * [whitespace] [sign] {INF | INFINITY}
+ * [whitespace] [sign] NAN [sequence]
+ *
+ * No hexadecimal form supported
+ * no sequence supported after NAN
+ */
EAPI double
eina_convert_strtod_c(const char *nptr, char **endptr)
{
-#ifdef _WIN32
- return _strtod_l(nptr, endptr, _eina_c_locale_get());
-#else
- return strtod_l(nptr, endptr, _eina_c_locale_get());
-#endif
+ const char *iter;
+ const char *a;
+ double val;
+ unsigned long long integer_part;
+ int minus;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(nptr, 0.0);
+
+ a = iter = nptr;
+
+ /* ignore leading whitespaces */
+ while (isspace(*iter))
+ iter++;
+
+ /* signed or not */
+ minus = 1;
+ if (*iter == '-')
+ {
+ minus = -1;
+ iter++;
+ }
+ else if (*iter == '+')
+ iter++;
+
+ if (tolower(*iter) == 'i')
+ {
+ if ((tolower(*(iter + 1)) == 'n') &&
+ (tolower(*(iter + 2)) == 'f'))
+ iter += 3;
+ else
+ goto on_error;
+ if (tolower(*(iter + 3)) == 'i')
+ {
+ if ((tolower(*(iter + 4)) == 'n') &&
+ (tolower(*(iter + 5)) == 'i') &&
+ (tolower(*(iter + 6)) == 't') &&
+ (tolower(*(iter + 7)) == 'y'))
+ iter += 5;
+ else
+ goto on_error;
+ }
+ if (endptr)
+ *endptr = (char *)iter;
+ return (minus == -1) ? -INFINITY : INFINITY;
+ }
+
+ if (tolower(*iter) == 'n')
+ {
+ if ((tolower(*(iter + 1)) == 'a') &&
+ (tolower(*(iter + 2)) == 'n'))
+ iter += 3;
+ else
+ goto on_error;
+ if (endptr)
+ *endptr = (char *)iter;
+ return (minus == -1) ? -NAN : NAN;
+ }
+
+ integer_part = 0;
+
+ /* (optional) integer part before dot */
+ if (isdigit(*iter))
+ {
+ for (; isdigit(*iter); iter++)
+ integer_part = integer_part * 10ULL + (unsigned long long)(*iter - '0');
+ a = iter;
+ }
+ else if (*iter != '.')
+ {
+ val = 0.0;
+ goto on_success;
+ }
+
+ val = (double)integer_part;
+
+ /* (optional) decimal part after dot */
+ if (*iter == '.')
+ {
+ unsigned long long decimal_part;
+ unsigned long long pow10;
+ int count;
+
+ iter++;
+
+ decimal_part = 0;
+ count = 0;
+ pow10 = 1;
+
+ if (isdigit(*iter))
+ {
+ for (; isdigit(*iter); iter++, count++)
+ {
+ if (count < 19)
+ {
+ decimal_part = decimal_part * 10ULL + + (unsigned long long)(*iter - '0');
+ pow10 *= 10ULL;
+ }
+ }
+ }
+ val += (double)decimal_part / (double)pow10;
+ a = iter;
+ }
+
+ /* (optional) exponent */
+ if ((*iter == 'e') || (*iter == 'E'))
+ {
+ double scale = 1.0;
+ unsigned int expo_part;
+ int minus_e;
+
+ iter++;
+
+ /* signed or not */
+ minus_e = 1;
+ if (*iter == '-')
+ {
+ minus_e = -1;
+ iter++;
+ }
+ else if (*iter == '+')
+ iter++;
+
+ /* exponential part */
+ expo_part = 0;
+ if (isdigit(*iter))
+ {
+ while (*iter == 0)
+ iter++;
+
+ for (; isdigit(*iter); iter++)
+ {
+ expo_part = expo_part * 10U + (unsigned int)(*iter - '0');
+ }
+ }
+ else if (!isdigit(*(a - 1)))
+ {
+ a = nptr;
+ goto on_success;
+ }
+ else if (*iter == 0)
+ goto on_success;
+
+ if ((val == 2.2250738585072011) && ((minus_e * (int)expo_part) == -308))
+ {
+ val *= 1.0e-308;
+ a = iter;
+ errno = ERANGE;
+ goto on_success;
+ }
+
+ if ((val == 2.2250738585072012) && ((minus_e * (int)expo_part) <= -308))
+ {
+ val *= 1.0e-308;
+ a = iter;
+ goto on_success;
+ }
+
+ a = iter;
+
+ while (expo_part >= 8U)
+ {
+ scale *= 1E8;
+ expo_part -= 8U;
+ }
+ while (expo_part > 0U)
+ {
+ scale *= 10.0;
+ expo_part--;
+ }
+
+ val = (minus_e == -1) ? (val / scale) : (val * scale);
+ }
+ else if ((iter > nptr) && !isdigit(*(iter - 1)))
+ {
+ a = nptr;
+ goto on_success;
+ }
+
+ on_success:
+ if (endptr)
+ *endptr = (char *)a;
+ return minus * val;
+
+ on_error:
+ if (endptr)
+ *endptr = (char *)nptr;
+ return 0.0;
}
/**
static int _eina_main_thread_count = 0;
#endif
static int _eina_log_dom = -1;
-static locale_t _eina_c_locale;
#ifdef ERR
#undef ERR
if (EINA_LIKELY(_eina_main_count > 0))
return ++_eina_main_count;
-#ifdef _WIN32
- _eina_c_locale = _create_locale(LC_ALL, "C");
-#else
- _eina_c_locale = newlocale(LC_ALL_MASK, "C", NULL);
-#endif
-
srand(time(NULL));
while (eina_seed == 0)
eina_seed = rand();
return 1;
}
-locale_t
-_eina_c_locale_get(void)
-{
- return _eina_c_locale;
-}
-
EAPI int
eina_shutdown(void)
{
_eina_main_count--;
if (EINA_UNLIKELY(_eina_main_count == 0))
{
-#ifdef _WIN32
- _free_locale(_eina_c_locale);
-#else
- freelocale(_eina_c_locale);
-#endif
-
eina_log_timing(_eina_log_dom,
EINA_LOG_STATE_START,
EINA_LOG_STATE_SHUTDOWN);
ws2_32 = cc.find_library('ws2_32')
secur32 = cc.find_library('secur32')
uuid = cc.find_library('uuid')
- msvcr100 = cc.find_library('msvcr100')
evil_lib = library('evil', evil_src,
- dependencies : [psapi, ole32, ws2_32, secur32, uuid, msvcr100],
+ dependencies : [psapi, ole32, ws2_32, secur32, uuid],
include_directories : [config_dir, include_directories('regex')],
)
evil = declare_dependency(
include_directories: [config_dir, include_directories('regex'), include_directories('.')],
- dependencies : [psapi, ole32, ws2_32, secur32, uuid, msvcr100],
+ dependencies : [psapi, ole32, ws2_32, secur32, uuid],
link_with: evil_lib,
)
else
#include <math.h>
#include <float.h>
#include <limits.h>
+#include <locale.h>
#include <Eina.h>
EFL_END_TEST
static void
-_eina_convert_strtod_c_check(const char *str, double expected_result)
+_eina_convert_strtod_c_check(const char *str)
{
- double result = eina_convert_strtod_c(str, NULL);
+ double d1;
+ double d2;
+ char *e1;
+ char *e2;
+
+ e1 = NULL;
+ d1 = eina_convert_strtod_c(str, &e1);
+
+ e2 = NULL;
+ d2 = strtod(str, &e2);
+
+ switch(fpclassify(d2))
+ {
+ case FP_NAN:
+ fail_if(fpclassify(d1) != FP_NAN);
+ break;
+ case FP_INFINITE:
+ fail_if(fpclassify(d1) != FP_INFINITE);
+ break;
+ default:
+ fail_if((fpclassify(d1) != FP_ZERO) &&
+ (fpclassify(d1) != FP_SUBNORMAL) &&
+ (fpclassify(d1) != FP_NORMAL));
+ if (!EINA_DBL_EQ(d1,d2) || (e1 != e2))
+ {
+ printf(" FP_NORMAL\n");
+ printf(" ERR: %s, %s\n", str, strerror(errno));
+ printf(" E1 **%.6f**, **%g**, %s\n", d1, d1, e1 ? e1 : "");
+ printf(" E2 **%.6f**, **%g**, %s\n", d2, d2, e2 ? e2 : "");
+ if (!EINA_DBL_EQ(d1,d2)) printf("different value\n");
+ if (e1 != e2) printf("different end position\n");
+ }
+
+ fail_if(!EINA_DBL_EQ(d1,d2) || (e1 != e2));
+ break;
+ }
- fail_if(result != expected_result);
}
EFL_START_TEST(eina_convert_strtod_c_simple)
{
- _eina_convert_strtod_c_check("0.0", 0.0);
- _eina_convert_strtod_c_check("0.5", 0.5);
- _eina_convert_strtod_c_check("1.0", 1.0);
- _eina_convert_strtod_c_check("-0.5", -0.5);
- _eina_convert_strtod_c_check("-1.0", -1.0);
- _eina_convert_strtod_c_check("3.45e-2", 0.0345);
- _eina_convert_strtod_c_check("3.45e+2", 345.0);
+ char *old;
+
+ old = setlocale(LC_ALL, "C");
+ _eina_convert_strtod_c_check("0");
+ _eina_convert_strtod_c_check("-0");
+ _eina_convert_strtod_c_check(".1");
+ _eina_convert_strtod_c_check(" .");
+ _eina_convert_strtod_c_check(" 1.2e3");
+ _eina_convert_strtod_c_check(" +1.2e3");
+ _eina_convert_strtod_c_check("1.2e3");
+ _eina_convert_strtod_c_check("+1.2e3");
+ _eina_convert_strtod_c_check("+1.e3");
+ _eina_convert_strtod_c_check("-1.2e3");
+ _eina_convert_strtod_c_check("-1.2e3.5");
+ _eina_convert_strtod_c_check("-1.2e");
+ _eina_convert_strtod_c_check("--1.2e3.5");
+ _eina_convert_strtod_c_check("--1-.2e3.5");
+ _eina_convert_strtod_c_check("-a");
+ _eina_convert_strtod_c_check("a");
+ _eina_convert_strtod_c_check(".1e");
+ _eina_convert_strtod_c_check(".1e0");
+ _eina_convert_strtod_c_check(".1e3");
+ _eina_convert_strtod_c_check(".1e-3");
+ _eina_convert_strtod_c_check(".1e-");
+ _eina_convert_strtod_c_check(" .e-");
+ _eina_convert_strtod_c_check(" .e");
+ _eina_convert_strtod_c_check(" e");
+ _eina_convert_strtod_c_check(" e0");
+ _eina_convert_strtod_c_check(" ee");
+ _eina_convert_strtod_c_check(" -e");
+ _eina_convert_strtod_c_check(" .9");
+ _eina_convert_strtod_c_check(" ..9");
+ _eina_convert_strtod_c_check("009");
+ _eina_convert_strtod_c_check("0.09e02");
+ /* http://thread.gmane.org/gmane.editors.vim.devel/19268/ */
+ _eina_convert_strtod_c_check("0.9999999999999999999999999999999999");
+ _eina_convert_strtod_c_check("2.2250738585072010e-308"); // BUG
+ /* PHP (slashdot.jp): http://opensource.slashdot.jp/story/11/01/08/0527259/PHP%E3%81%AE%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E5%87%A6%E7%90%86%E3%81%AB%E7%84%A1%E9%99%90%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%83%90%E3%82%B0 */
+ _eina_convert_strtod_c_check("2.2250738585072011e-308");
+ /* Gauche: http://blog.practical-scheme.net/gauche/20110203-bitten-by-floating-point-numbers-again */
+ _eina_convert_strtod_c_check("2.2250738585072012e-308");
+ _eina_convert_strtod_c_check("2.2250738585072013e-308");
+ _eina_convert_strtod_c_check("2.2250738585072014e-308");
+ _eina_convert_strtod_c_check(" NaNfoo");
+ _eina_convert_strtod_c_check(" -INFfoo");
+ _eina_convert_strtod_c_check(" InFiNiTyfoo");
+ setlocale(LC_ALL, old);
}
EFL_END_TEST