forked from enlightenment/efl
eina: add locale-independent eina_convert_strtod_c function
strtod's behavior is changed by system locale. http://man7.org/linux/man-pages/man3/strtod.3.html https://en.wikipedia.org/wiki/Decimal_separator Because of this, strtod(0.5) returns 0.0 in some locales. When a given value string is locale-independent, strtod has to be replaced to eina_convert_strtod_c function. Internally, it calls strtod_l function with "C" locale. @feature Reviewed-by: Cedric BAIL <cedric.bail@free.fr> Reviewed-by: Vincent Torri <vincent.torri@gmail.com> Differential Revision: https://phab.enlightenment.org/D6644
This commit is contained in:
parent
3a89ea15b9
commit
bef1c5cc43
|
@ -453,6 +453,16 @@ eina_convert_atofp(const char *src, int length, Eina_F32p32 *fp)
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -333,6 +333,22 @@ EAPI Eina_Bool eina_convert_atofp(const char *src,
|
||||||
int length,
|
int length,
|
||||||
Eina_F32p32 *fp) EINA_ARG_NONNULL(1, 3);
|
Eina_F32p32 *fp) EINA_ARG_NONNULL(1, 3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a string to a floating point number.
|
||||||
|
*
|
||||||
|
* @param[in] nptr a string to convert. It shouldn't be NULL.
|
||||||
|
* @param[out] endptr If endptr is not NULL, a pointer to the character after the last
|
||||||
|
* character used in the conversion is stored in the location referenced
|
||||||
|
* by endptr.
|
||||||
|
* @return a double type floating point number.
|
||||||
|
*
|
||||||
|
* This function returns converted floating point number with locale-independency.
|
||||||
|
* Actually, it use "C" locale for strtod_l function internally. If you need strtod
|
||||||
|
* without locale-dependency, this function can replace strtod.
|
||||||
|
* For more information, please refer documents of strtod, strtod_l.
|
||||||
|
*/
|
||||||
|
EAPI double eina_convert_strtod_c(const char *nptr, char **endptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -85,6 +85,7 @@ static int _eina_main_count = 0;
|
||||||
static int _eina_main_thread_count = 0;
|
static int _eina_main_thread_count = 0;
|
||||||
#endif
|
#endif
|
||||||
static int _eina_log_dom = -1;
|
static int _eina_log_dom = -1;
|
||||||
|
static locale_t _eina_c_locale;
|
||||||
|
|
||||||
#ifdef ERR
|
#ifdef ERR
|
||||||
#undef ERR
|
#undef ERR
|
||||||
|
@ -285,6 +286,12 @@ eina_init(void)
|
||||||
if (EINA_LIKELY(_eina_main_count > 0))
|
if (EINA_LIKELY(_eina_main_count > 0))
|
||||||
return ++_eina_main_count;
|
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));
|
srand(time(NULL));
|
||||||
while (eina_seed == 0)
|
while (eina_seed == 0)
|
||||||
eina_seed = rand();
|
eina_seed = rand();
|
||||||
|
@ -348,6 +355,12 @@ eina_init(void)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locale_t
|
||||||
|
_eina_c_locale_get(void)
|
||||||
|
{
|
||||||
|
return _eina_c_locale;
|
||||||
|
}
|
||||||
|
|
||||||
EAPI int
|
EAPI int
|
||||||
eina_shutdown(void)
|
eina_shutdown(void)
|
||||||
{
|
{
|
||||||
|
@ -359,6 +372,12 @@ eina_shutdown(void)
|
||||||
_eina_main_count--;
|
_eina_main_count--;
|
||||||
if (EINA_UNLIKELY(_eina_main_count == 0))
|
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_timing(_eina_log_dom,
|
||||||
EINA_LOG_STATE_START,
|
EINA_LOG_STATE_START,
|
||||||
EINA_LOG_STATE_SHUTDOWN);
|
EINA_LOG_STATE_SHUTDOWN);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define EINA_PRIVATE_H_
|
#define EINA_PRIVATE_H_
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <Evil.h>
|
# include <Evil.h>
|
||||||
|
@ -151,6 +152,11 @@ Eina_Stringshare *eina_file_sanitize(const char *path);
|
||||||
|
|
||||||
void eina_freeq_main_set(Eina_FreeQ *fq);
|
void eina_freeq_main_set(Eina_FreeQ *fq);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef _locale_t locale_t;
|
||||||
|
#endif
|
||||||
|
locale_t _eina_c_locale_get(void);
|
||||||
|
|
||||||
#include "eina_inline_private.h"
|
#include "eina_inline_private.h"
|
||||||
|
|
||||||
#endif /* EINA_PRIVATE_H_ */
|
#endif /* EINA_PRIVATE_H_ */
|
||||||
|
|
|
@ -160,10 +160,31 @@ _eina_convert_fp_check(double d, Eina_F32p32 fp, int length)
|
||||||
}
|
}
|
||||||
EFL_END_TEST
|
EFL_END_TEST
|
||||||
|
|
||||||
|
static void
|
||||||
|
_eina_convert_strtod_c_check(const char *str, double expected_result)
|
||||||
|
{
|
||||||
|
double result = eina_convert_strtod_c(str, NULL);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
EFL_END_TEST
|
||||||
|
|
||||||
void
|
void
|
||||||
eina_test_convert(TCase *tc)
|
eina_test_convert(TCase *tc)
|
||||||
{
|
{
|
||||||
tcase_add_test(tc, eina_convert_simple);
|
tcase_add_test(tc, eina_convert_simple);
|
||||||
tcase_add_test(tc, eina_convert_double);
|
tcase_add_test(tc, eina_convert_double);
|
||||||
tcase_add_test(tc, eina_convert_fp);
|
tcase_add_test(tc, eina_convert_fp);
|
||||||
|
tcase_add_test(tc, eina_convert_strtod_c_simple);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue