Create an immortal C locale

This adds a function fish_c_locale() which returns an immortal locale_t
corresponding to the C locale, and switches builtin_printf to use wcstod_l.
This commit is contained in:
ridiculousfish 2018-07-28 17:56:42 -07:00
parent 09541e9524
commit 42c648ab35
3 changed files with 10 additions and 9 deletions

View file

@ -271,19 +271,11 @@ template <>
long double raw_string_to_scalar_type(const wchar_t *s, wchar_t **end) { long double raw_string_to_scalar_type(const wchar_t *s, wchar_t **end) {
double val = wcstod(s, end); double val = wcstod(s, end);
if (**end == L'\0') return val; if (**end == L'\0') return val;
// The conversion using the user's locale failed. That may be due to the string not being a // The conversion using the user's locale failed. That may be due to the string not being a
// valid floating point value. It could also be due to the locale using different separator // valid floating point value. It could also be due to the locale using different separator
// characters than the normal english convention. So try again by forcing the use of a locale // characters than the normal english convention. So try again by forcing the use of a locale
// that employs the english convention for writing floating point numbers. // that employs the english convention for writing floating point numbers.
// return wcstod_l(s, end, fish_c_locale());
// TODO: switch to the wcstod_l() function to avoid changing the global locale.
char *saved_locale = strdup(setlocale(LC_NUMERIC, NULL));
setlocale(LC_NUMERIC, "C");
val = wcstod(s, end);
setlocale(LC_NUMERIC, saved_locale);
free(saved_locale);
return val;
} }
template <typename T> template <typename T>

View file

@ -517,6 +517,11 @@ int fish_wcswidth(const wchar_t *str) { return fish_wcswidth(str, wcslen(str));
/// See fallback.h for the normal definitions. /// See fallback.h for the normal definitions.
int fish_wcswidth(const wcstring &str) { return fish_wcswidth(str.c_str(), str.size()); } int fish_wcswidth(const wcstring &str) { return fish_wcswidth(str.c_str(), str.size()); }
locale_t fish_c_locale() {
static locale_t loc = newlocale(LC_ALL_MASK, "C", NULL);
return loc;
}
/// Like fish_wcstol(), but fails on a value outside the range of an int. /// Like fish_wcstol(), but fails on a value outside the range of an int.
/// ///
/// This is needed because BSD and GNU implementations differ in several ways that make it really /// This is needed because BSD and GNU implementations differ in several ways that make it really

View file

@ -7,6 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <xlocale.h>
#include <string> #include <string>
#include "common.h" #include "common.h"
@ -117,6 +118,9 @@ int fish_iswgraph(wint_t wc);
int fish_wcswidth(const wchar_t *str); int fish_wcswidth(const wchar_t *str);
int fish_wcswidth(const wcstring &str); int fish_wcswidth(const wcstring &str);
// returns an immortal locale_t corresponding to the C locale.
locale_t fish_c_locale();
int fish_wcstoi(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10); int fish_wcstoi(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
long fish_wcstol(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10); long fish_wcstol(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
long long fish_wcstoll(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10); long long fish_wcstoll(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);