summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2018-01-15 14:58:02 (GMT)
committerGitHub <noreply@github.com>2018-01-15 14:58:02 (GMT)
commitcb064fc2321ce8673fe365e9ef60445a27657f54 (patch)
tree06356d6625f022636e22ed5e8646a3f2e36afac4 /Python
parent7ed7aead9503102d2ed316175f198104e0cd674c (diff)
downloadcpython-cb064fc2321ce8673fe365e9ef60445a27657f54.zip
cpython-cb064fc2321ce8673fe365e9ef60445a27657f54.tar.gz
cpython-cb064fc2321ce8673fe365e9ef60445a27657f54.tar.bz2
bpo-31900: Fix localeconv() encoding for LC_NUMERIC (#4174)
* Add _Py_GetLocaleconvNumeric() function: decode decimal_point and thousands_sep fields of localeconv() from the LC_NUMERIC encoding, rather than decoding from the LC_CTYPE encoding. * Modify locale.localeconv() and "n" formatter of str.format() (for int, float and complex to use _Py_GetLocaleconvNumeric() internally.
Diffstat (limited to 'Python')
-rw-r--r--Python/fileutils.c77
-rw-r--r--Python/formatter_unicode.c15
2 files changed, 81 insertions, 11 deletions
diff --git a/Python/fileutils.c b/Python/fileutils.c
index a50075e..9a1435c 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -1746,3 +1746,80 @@ error:
return -1;
}
#endif
+
+
+int
+_Py_GetLocaleconvNumeric(PyObject **decimal_point, PyObject **thousands_sep,
+ const char **grouping)
+{
+ int res = -1;
+
+ struct lconv *lc = localeconv();
+
+ int change_locale = 0;
+ if (decimal_point != NULL &&
+ (strlen(lc->decimal_point) > 1 || ((unsigned char)lc->decimal_point[0]) > 127))
+ {
+ change_locale = 1;
+ }
+ if (thousands_sep != NULL &&
+ (strlen(lc->thousands_sep) > 1 || ((unsigned char)lc->thousands_sep[0]) > 127))
+ {
+ change_locale = 1;
+ }
+
+ /* Keep a copy of the LC_CTYPE locale */
+ char *oldloc = NULL, *loc = NULL;
+ if (change_locale) {
+ oldloc = setlocale(LC_CTYPE, NULL);
+ if (!oldloc) {
+ PyErr_SetString(PyExc_RuntimeWarning, "faild to get LC_CTYPE locale");
+ return -1;
+ }
+
+ oldloc = _PyMem_Strdup(oldloc);
+ if (!oldloc) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ loc = setlocale(LC_NUMERIC, NULL);
+ if (loc != NULL && strcmp(loc, oldloc) == 0) {
+ loc = NULL;
+ }
+
+ if (loc != NULL) {
+ /* Only set the locale temporarilty the LC_CTYPE locale
+ if LC_NUMERIC locale is different than LC_CTYPE locale and
+ decimal_point and/or thousands_sep are non-ASCII or longer than
+ 1 byte */
+ setlocale(LC_CTYPE, loc);
+ }
+ }
+
+ if (decimal_point != NULL) {
+ *decimal_point = PyUnicode_DecodeLocale(lc->decimal_point, NULL);
+ if (*decimal_point == NULL) {
+ goto error;
+ }
+ }
+ if (thousands_sep != NULL) {
+ *thousands_sep = PyUnicode_DecodeLocale(lc->thousands_sep, NULL);
+ if (*thousands_sep == NULL) {
+ goto error;
+ }
+ }
+
+ if (grouping != NULL) {
+ *grouping = lc->grouping;
+ }
+
+ res = 0;
+
+error:
+ if (loc != NULL) {
+ setlocale(LC_CTYPE, oldloc);
+ }
+ PyMem_Free(oldloc);
+ return res;
+}
diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c
index 397ae7f..71e673d 100644
--- a/Python/formatter_unicode.c
+++ b/Python/formatter_unicode.c
@@ -704,18 +704,11 @@ get_locale_info(enum LocaleType type, LocaleInfo *locale_info)
{
switch (type) {
case LT_CURRENT_LOCALE: {
- struct lconv *locale_data = localeconv();
- locale_info->decimal_point = PyUnicode_DecodeLocale(
- locale_data->decimal_point,
- NULL);
- if (locale_info->decimal_point == NULL)
+ if (_Py_GetLocaleconvNumeric(&locale_info->decimal_point,
+ &locale_info->thousands_sep,
+ &locale_info->grouping) < 0) {
return -1;
- locale_info->thousands_sep = PyUnicode_DecodeLocale(
- locale_data->thousands_sep,
- NULL);
- if (locale_info->thousands_sep == NULL)
- return -1;
- locale_info->grouping = locale_data->grouping;
+ }
break;
}
case LT_DEFAULT_LOCALE: