Use strtod_l when available

Using strtod_l and newlocale is a nicer way to have provide
a C-locale-only strtod. Since these APIs are not available
everywhere, keep the old code as a fallback.
This commit is contained in:
Matthias Clasen 2017-09-17 11:17:13 -04:00 committed by Behdad Esfahbod
parent ac5acc4538
commit a8ae2eafc8
2 changed files with 40 additions and 0 deletions

View file

@ -76,6 +76,9 @@ if test "x$have_dlsym" = "xyes"; then
fi
AM_CONDITIONAL(CAIRO_HAS_DLSYM, test "x$have_dlsym" = "xyes")
AC_CHECK_HEADERS(xlocale.h)
AC_CHECK_FUNCS(newlocale strtod_l)
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [

View file

@ -43,6 +43,10 @@
#include <stdio.h>
#include <errno.h>
#include <locale.h>
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#endif
COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
@ -789,6 +793,38 @@ _cairo_get_locale_decimal_point (void)
}
#endif
#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
static locale_t C_locale;
static locale_t
get_C_locale (void)
{
locale_t C;
retry:
C = (locale_t) _cairo_atomic_ptr_get (&C_locale);
if (unlikely (!C)) {
C = newlocale (LC_ALL_MASK, "C", NULL);
if (!_cairo_atomic_ptr_cmpxchg (&C_locale, NULL, C)) {
freelocale (C_locale);
goto retry;
}
}
return C;
}
double
_cairo_strtod (const char *nptr, char **endptr)
{
return strtod_l (nptr, endptr, get_C_locale ());
}
#else
/* strtod replacement that ignores locale and only accepts decimal points */
double
_cairo_strtod (const char *nptr, char **endptr)
@ -844,6 +880,7 @@ _cairo_strtod (const char *nptr, char **endptr)
return value;
}
#endif
/**
* _cairo_fopen: