forked from enlightenment/efl
Eina: implement strtod in C locale and remove linkl against msvcr100.
Summary: This fixes compilation on Windows More precisely edje_cc could not compile emotion edc files, so it was a runtime problem because of msvcr100 link. Add more tests than before Test Plan: compilation Reviewers: raster Subscribers: zmike, stefan_schmidt, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D7926
This commit is contained in:
parent
5861aad185
commit
8a7cb97e02
|
@ -804,7 +804,7 @@ EFL_SELECT_WINDOWS_VERSION
|
|||
|
||||
### 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
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
* 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
|
||||
|
@ -24,6 +28,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <Evil.h>
|
||||
|
@ -453,14 +459,208 @@ eina_convert_atofp(const char *src, int length, Eina_F32p32 *fp)
|
|||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -85,7 +85,6 @@ static int _eina_main_count = 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
|
||||
|
@ -286,12 +285,6 @@ eina_init(void)
|
|||
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();
|
||||
|
@ -355,12 +348,6 @@ eina_init(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
locale_t
|
||||
_eina_c_locale_get(void)
|
||||
{
|
||||
return _eina_c_locale;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
eina_shutdown(void)
|
||||
{
|
||||
|
@ -372,12 +359,6 @@ 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);
|
||||
|
|
|
@ -51,16 +51,15 @@ if target_machine.system() == 'windows'
|
|||
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
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <Eina.h>
|
||||
|
||||
|
@ -161,22 +162,96 @@ _eina_convert_fp_check(double d, Eina_F32p32 fp, int length)
|
|||
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
|
||||
|
||||
|
|
Loading…
Reference in New Issue