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:
Vincent Torri 2019-02-28 13:21:56 +01:00 committed by Stefan Schmidt
parent 5861aad185
commit 8a7cb97e02
5 changed files with 293 additions and 38 deletions

View File

@ -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

View File

@ -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;
}
/**

View File

@ -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);

View File

@ -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

View File

@ -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