Issue #13706: Fix format(int, "n") for locale with non-ASCII thousands separator
* Decode thousands separator and decimal point using PyUnicode_DecodeLocale() (from the locale encoding), instead of decoding them implicitly from latin1 * Remove _PyUnicode_InsertThousandsGroupingLocale(), it was not used * Change _PyUnicode_InsertThousandsGrouping() API to return the maximum character if unicode is NULL * Replace MIN/MAX macros by Py_MIN/Py_MAX * stringlib/undef.h undefines STRINGLIB_IS_UNICODE * stringlib/localeutil.h only supports Unicode
This commit is contained in:
parent
dcb30cf959
commit
41a863cb81
|
@ -1936,32 +1936,20 @@ PyAPI_FUNC(PyObject *) _PyUnicode_XStrip(
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Using the current locale, insert the thousands grouping
|
|
||||||
into the string pointed to by buffer. For the argument descriptions,
|
|
||||||
see Objects/stringlib/localeutil.h */
|
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
|
||||||
PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGroupingLocale(Py_UNICODE *buffer,
|
|
||||||
Py_ssize_t n_buffer,
|
|
||||||
Py_UNICODE *digits,
|
|
||||||
Py_ssize_t n_digits,
|
|
||||||
Py_ssize_t min_width);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Using explicit passed-in values, insert the thousands grouping
|
/* Using explicit passed-in values, insert the thousands grouping
|
||||||
into the string pointed to by buffer. For the argument descriptions,
|
into the string pointed to by buffer. For the argument descriptions,
|
||||||
see Objects/stringlib/localeutil.h */
|
see Objects/stringlib/localeutil.h */
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping(
|
PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping(
|
||||||
PyObject *unicode,
|
PyObject *unicode,
|
||||||
int kind,
|
Py_ssize_t index,
|
||||||
void *buffer,
|
|
||||||
Py_ssize_t n_buffer,
|
Py_ssize_t n_buffer,
|
||||||
void *digits,
|
void *digits,
|
||||||
Py_ssize_t n_digits,
|
Py_ssize_t n_digits,
|
||||||
Py_ssize_t min_width,
|
Py_ssize_t min_width,
|
||||||
const char *grouping,
|
const char *grouping,
|
||||||
const char *thousands_sep);
|
PyObject *thousands_sep,
|
||||||
|
Py_UCS4 *maxchar);
|
||||||
#endif
|
#endif
|
||||||
/* === Characters Type APIs =============================================== */
|
/* === Characters Type APIs =============================================== */
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from test.support import verbose, TestFailed
|
from test.support import verbose, TestFailed
|
||||||
|
import locale
|
||||||
import sys
|
import sys
|
||||||
import test.support as support
|
import test.support as support
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -282,6 +283,20 @@ class FormatTest(unittest.TestCase):
|
||||||
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
|
self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\u2007")
|
||||||
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")
|
self.assertEqual(format(0j, "\u2007^4"), "\u20070j\u2007")
|
||||||
|
|
||||||
|
def test_locale(self):
|
||||||
|
try:
|
||||||
|
oldloc = locale.setlocale(locale.LC_ALL, '')
|
||||||
|
except locale.Error as err:
|
||||||
|
self.skipTest("Cannot set locale: {}".format(err))
|
||||||
|
try:
|
||||||
|
sep = locale.localeconv()['thousands_sep']
|
||||||
|
text = format(123456789, "n")
|
||||||
|
self.assertIn(sep, text)
|
||||||
|
self.assertEqual(text.replace(sep, ''), '123456789')
|
||||||
|
finally:
|
||||||
|
locale.setlocale(locale.LC_ALL, oldloc)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(FormatTest)
|
support.run_unittest(FormatTest)
|
||||||
|
|
|
@ -21,12 +21,9 @@
|
||||||
#define STRINGLIB_RESIZE not_supported
|
#define STRINGLIB_RESIZE not_supported
|
||||||
#define STRINGLIB_CHECK PyUnicode_Check
|
#define STRINGLIB_CHECK PyUnicode_Check
|
||||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||||
#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
|
|
||||||
#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
#define STRINGLIB_TOSTR PyObject_Str
|
#define STRINGLIB_TOSTR PyObject_Str
|
||||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||||
|
|
||||||
#define _Py_InsertThousandsGrouping _PyUnicode_ascii_InsertThousandsGrouping
|
#define _Py_InsertThousandsGrouping _PyUnicode_ascii_InsertThousandsGrouping
|
||||||
#define _Py_InsertThousandsGroupingLocale _PyUnicode_ascii_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
#ifndef STRINGLIB_IS_UNICODE
|
||||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
# error "localeutil is specific to Unicode"
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *grouping;
|
const char *grouping;
|
||||||
|
@ -46,7 +47,7 @@ STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
|
||||||
are optional, depending on when we're called. */
|
are optional, depending on when we're called. */
|
||||||
static void
|
static void
|
||||||
STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
|
STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
|
||||||
Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep,
|
Py_ssize_t n_chars, Py_ssize_t n_zeros, STRINGLIB_CHAR* thousands_sep,
|
||||||
Py_ssize_t thousands_sep_len)
|
Py_ssize_t thousands_sep_len)
|
||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
@ -55,15 +56,8 @@ STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
|
||||||
*buffer_end -= thousands_sep_len;
|
*buffer_end -= thousands_sep_len;
|
||||||
|
|
||||||
/* Copy the thousands_sep chars into the buffer. */
|
/* Copy the thousands_sep chars into the buffer. */
|
||||||
#if STRINGLIB_IS_UNICODE
|
memcpy(*buffer_end, thousands_sep,
|
||||||
/* Convert from the char's of the thousands_sep from
|
thousands_sep_len * STRINGLIB_SIZEOF_CHAR);
|
||||||
the locale into unicode. */
|
|
||||||
for (i = 0; i < thousands_sep_len; ++i)
|
|
||||||
(*buffer_end)[i] = thousands_sep[i];
|
|
||||||
#else
|
|
||||||
/* No conversion, just memcpy the thousands_sep. */
|
|
||||||
memcpy(*buffer_end, thousands_sep, thousands_sep_len);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*buffer_end -= n_chars;
|
*buffer_end -= n_chars;
|
||||||
|
@ -76,7 +70,7 @@ STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _Py_InsertThousandsGrouping:
|
* InsertThousandsGrouping:
|
||||||
* @buffer: A pointer to the start of a string.
|
* @buffer: A pointer to the start of a string.
|
||||||
* @n_buffer: Number of characters in @buffer.
|
* @n_buffer: Number of characters in @buffer.
|
||||||
* @digits: A pointer to the digits we're reading from. If count
|
* @digits: A pointer to the digits we're reading from. If count
|
||||||
|
@ -106,13 +100,15 @@ STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
|
||||||
_insert_thousands_sep().
|
_insert_thousands_sep().
|
||||||
**/
|
**/
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
|
STRINGLIB(InsertThousandsGrouping)(
|
||||||
Py_ssize_t n_buffer,
|
STRINGLIB_CHAR *buffer,
|
||||||
STRINGLIB_CHAR *digits,
|
Py_ssize_t n_buffer,
|
||||||
Py_ssize_t n_digits,
|
STRINGLIB_CHAR *digits,
|
||||||
Py_ssize_t min_width,
|
Py_ssize_t n_digits,
|
||||||
const char *grouping,
|
Py_ssize_t min_width,
|
||||||
const char *thousands_sep)
|
const char *grouping,
|
||||||
|
STRINGLIB_CHAR *thousands_sep,
|
||||||
|
Py_ssize_t thousands_sep_len)
|
||||||
{
|
{
|
||||||
Py_ssize_t count = 0;
|
Py_ssize_t count = 0;
|
||||||
Py_ssize_t n_zeros;
|
Py_ssize_t n_zeros;
|
||||||
|
@ -124,7 +120,6 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
|
||||||
STRINGLIB_CHAR *digits_end = NULL;
|
STRINGLIB_CHAR *digits_end = NULL;
|
||||||
Py_ssize_t l;
|
Py_ssize_t l;
|
||||||
Py_ssize_t n_chars;
|
Py_ssize_t n_chars;
|
||||||
Py_ssize_t thousands_sep_len = strlen(thousands_sep);
|
|
||||||
Py_ssize_t remaining = n_digits; /* Number of chars remaining to
|
Py_ssize_t remaining = n_digits; /* Number of chars remaining to
|
||||||
be looked at */
|
be looked at */
|
||||||
/* A generator that returns all of the grouping widths, until it
|
/* A generator that returns all of the grouping widths, until it
|
||||||
|
@ -138,9 +133,9 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
|
while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
|
||||||
l = MIN(l, MAX(MAX(remaining, min_width), 1));
|
l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1));
|
||||||
n_zeros = MAX(0, l - remaining);
|
n_zeros = Py_MAX(0, l - remaining);
|
||||||
n_chars = MAX(0, MIN(remaining, l));
|
n_chars = Py_MAX(0, Py_MIN(remaining, l));
|
||||||
|
|
||||||
/* Use n_zero zero's and n_chars chars */
|
/* Use n_zero zero's and n_chars chars */
|
||||||
|
|
||||||
|
@ -168,9 +163,9 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
|
||||||
if (!loop_broken) {
|
if (!loop_broken) {
|
||||||
/* We left the loop without using a break statement. */
|
/* We left the loop without using a break statement. */
|
||||||
|
|
||||||
l = MAX(MAX(remaining, min_width), 1);
|
l = Py_MAX(Py_MAX(remaining, min_width), 1);
|
||||||
n_zeros = MAX(0, l - remaining);
|
n_zeros = Py_MAX(0, l - remaining);
|
||||||
n_chars = MAX(0, MIN(remaining, l));
|
n_chars = Py_MAX(0, Py_MIN(remaining, l));
|
||||||
|
|
||||||
/* Use n_zero zero's and n_chars chars */
|
/* Use n_zero zero's and n_chars chars */
|
||||||
count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
|
count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
|
||||||
|
@ -183,25 +178,3 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* _Py_InsertThousandsGroupingLocale:
|
|
||||||
* @buffer: A pointer to the start of a string.
|
|
||||||
* @n_digits: The number of digits in the string, in which we want
|
|
||||||
* to put the grouping chars.
|
|
||||||
*
|
|
||||||
* Reads thee current locale and calls _Py_InsertThousandsGrouping().
|
|
||||||
**/
|
|
||||||
Py_ssize_t
|
|
||||||
_Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer,
|
|
||||||
Py_ssize_t n_buffer,
|
|
||||||
STRINGLIB_CHAR *digits,
|
|
||||||
Py_ssize_t n_digits,
|
|
||||||
Py_ssize_t min_width)
|
|
||||||
{
|
|
||||||
struct lconv *locale_data = localeconv();
|
|
||||||
const char *grouping = locale_data->grouping;
|
|
||||||
const char *thousands_sep = locale_data->thousands_sep;
|
|
||||||
|
|
||||||
return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits,
|
|
||||||
min_width, grouping, thousands_sep);
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,7 +25,5 @@
|
||||||
#define STRINGLIB_CHECK PyBytes_Check
|
#define STRINGLIB_CHECK PyBytes_Check
|
||||||
#define STRINGLIB_CHECK_EXACT PyBytes_CheckExact
|
#define STRINGLIB_CHECK_EXACT PyBytes_CheckExact
|
||||||
#define STRINGLIB_TOSTR PyObject_Str
|
#define STRINGLIB_TOSTR PyObject_Str
|
||||||
#define STRINGLIB_GROUPING _PyBytes_InsertThousandsGrouping
|
|
||||||
#define STRINGLIB_GROUPING_LOCALE _PyBytes_InsertThousandsGroupingLocale
|
|
||||||
#define STRINGLIB_TOASCII PyObject_Repr
|
#define STRINGLIB_TOASCII PyObject_Repr
|
||||||
#endif /* !STRINGLIB_STRINGDEFS_H */
|
#endif /* !STRINGLIB_STRINGDEFS_H */
|
||||||
|
|
|
@ -21,13 +21,10 @@
|
||||||
#define STRINGLIB_RESIZE not_supported
|
#define STRINGLIB_RESIZE not_supported
|
||||||
#define STRINGLIB_CHECK PyUnicode_Check
|
#define STRINGLIB_CHECK PyUnicode_Check
|
||||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||||
#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
|
|
||||||
#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
#define STRINGLIB_TOSTR PyObject_Str
|
#define STRINGLIB_TOSTR PyObject_Str
|
||||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||||
|
|
||||||
#define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping
|
#define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping
|
||||||
#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs1_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,9 @@
|
||||||
#define STRINGLIB_RESIZE not_supported
|
#define STRINGLIB_RESIZE not_supported
|
||||||
#define STRINGLIB_CHECK PyUnicode_Check
|
#define STRINGLIB_CHECK PyUnicode_Check
|
||||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||||
#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
|
|
||||||
#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
#define STRINGLIB_TOSTR PyObject_Str
|
#define STRINGLIB_TOSTR PyObject_Str
|
||||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||||
|
|
||||||
#define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping
|
#define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping
|
||||||
#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs2_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,9 @@
|
||||||
#define STRINGLIB_RESIZE not_supported
|
#define STRINGLIB_RESIZE not_supported
|
||||||
#define STRINGLIB_CHECK PyUnicode_Check
|
#define STRINGLIB_CHECK PyUnicode_Check
|
||||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||||
#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
|
|
||||||
#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
#define STRINGLIB_TOSTR PyObject_Str
|
#define STRINGLIB_TOSTR PyObject_Str
|
||||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||||
|
|
||||||
#define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping
|
#define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping
|
||||||
#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs4_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
#undef STRINGLIB_NEW
|
#undef STRINGLIB_NEW
|
||||||
#undef STRINGLIB_RESIZE
|
#undef STRINGLIB_RESIZE
|
||||||
#undef _Py_InsertThousandsGrouping
|
#undef _Py_InsertThousandsGrouping
|
||||||
#undef _Py_InsertThousandsGroupingLocale
|
#undef STRINGLIB_IS_UNICODE
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#define STRINGLIB_RESIZE PyUnicode_Resize
|
#define STRINGLIB_RESIZE PyUnicode_Resize
|
||||||
#define STRINGLIB_CHECK PyUnicode_Check
|
#define STRINGLIB_CHECK PyUnicode_Check
|
||||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||||
#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping
|
|
||||||
#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x03000000
|
#if PY_VERSION_HEX < 0x03000000
|
||||||
#define STRINGLIB_TOSTR PyObject_Unicode
|
#define STRINGLIB_TOSTR PyObject_Unicode
|
||||||
|
|
|
@ -9151,34 +9151,75 @@ any_find_slice(int direction, PyObject* s1, PyObject* s2,
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
_PyUnicode_InsertThousandsGrouping(PyObject *unicode, int kind, void *data,
|
_PyUnicode_InsertThousandsGrouping(
|
||||||
Py_ssize_t n_buffer,
|
PyObject *unicode, Py_ssize_t index,
|
||||||
void *digits, Py_ssize_t n_digits,
|
Py_ssize_t n_buffer,
|
||||||
Py_ssize_t min_width,
|
void *digits, Py_ssize_t n_digits,
|
||||||
const char *grouping,
|
Py_ssize_t min_width,
|
||||||
const char *thousands_sep)
|
const char *grouping, PyObject *thousands_sep,
|
||||||
|
Py_UCS4 *maxchar)
|
||||||
{
|
{
|
||||||
|
unsigned int kind, thousands_sep_kind;
|
||||||
|
void *data, *thousands_sep_data;
|
||||||
|
Py_ssize_t thousands_sep_len;
|
||||||
|
Py_ssize_t len;
|
||||||
|
|
||||||
|
if (unicode != NULL) {
|
||||||
|
kind = PyUnicode_KIND(unicode);
|
||||||
|
data = PyUnicode_DATA(unicode) + index * kind;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kind = PyUnicode_1BYTE_KIND;
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
thousands_sep_kind = PyUnicode_KIND(thousands_sep);
|
||||||
|
thousands_sep_data = PyUnicode_DATA(thousands_sep);
|
||||||
|
thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
|
||||||
|
if (unicode != NULL && thousands_sep_kind != kind) {
|
||||||
|
thousands_sep_data = _PyUnicode_AsKind(thousands_sep, kind);
|
||||||
|
if (!thousands_sep_data)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case PyUnicode_1BYTE_KIND:
|
case PyUnicode_1BYTE_KIND:
|
||||||
if (unicode != NULL && PyUnicode_IS_ASCII(unicode))
|
if (unicode != NULL && PyUnicode_IS_ASCII(unicode))
|
||||||
return _PyUnicode_ascii_InsertThousandsGrouping(
|
len = asciilib_InsertThousandsGrouping(
|
||||||
(Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
|
(Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
|
||||||
min_width, grouping, thousands_sep);
|
min_width, grouping,
|
||||||
|
thousands_sep_data, thousands_sep_len);
|
||||||
else
|
else
|
||||||
return _PyUnicode_ucs1_InsertThousandsGrouping(
|
len = ucs1lib_InsertThousandsGrouping(
|
||||||
(Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
|
(Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
|
||||||
min_width, grouping, thousands_sep);
|
min_width, grouping,
|
||||||
|
thousands_sep_data, thousands_sep_len);
|
||||||
|
break;
|
||||||
case PyUnicode_2BYTE_KIND:
|
case PyUnicode_2BYTE_KIND:
|
||||||
return _PyUnicode_ucs2_InsertThousandsGrouping(
|
len = ucs2lib_InsertThousandsGrouping(
|
||||||
(Py_UCS2*)data, n_buffer, (Py_UCS2*)digits, n_digits,
|
(Py_UCS2*)data, n_buffer, (Py_UCS2*)digits, n_digits,
|
||||||
min_width, grouping, thousands_sep);
|
min_width, grouping,
|
||||||
|
thousands_sep_data, thousands_sep_len);
|
||||||
|
break;
|
||||||
case PyUnicode_4BYTE_KIND:
|
case PyUnicode_4BYTE_KIND:
|
||||||
return _PyUnicode_ucs4_InsertThousandsGrouping(
|
len = ucs4lib_InsertThousandsGrouping(
|
||||||
(Py_UCS4*)data, n_buffer, (Py_UCS4*)digits, n_digits,
|
(Py_UCS4*)data, n_buffer, (Py_UCS4*)digits, n_digits,
|
||||||
min_width, grouping, thousands_sep);
|
min_width, grouping,
|
||||||
|
thousands_sep_data, thousands_sep_len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
assert(0);
|
if (unicode != NULL && thousands_sep_kind != kind)
|
||||||
return -1;
|
PyMem_Free(thousands_sep_data);
|
||||||
|
if (unicode == NULL) {
|
||||||
|
*maxchar = 127;
|
||||||
|
if (len != n_digits) {
|
||||||
|
*maxchar = Py_MAX(*maxchar,
|
||||||
|
PyUnicode_MAX_CHAR_VALUE(thousands_sep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -346,11 +346,13 @@ fill_padding(PyObject *s, Py_ssize_t start, Py_ssize_t nchars,
|
||||||
before and including the decimal. Note that locales only support
|
before and including the decimal. Note that locales only support
|
||||||
8-bit chars, not unicode. */
|
8-bit chars, not unicode. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *decimal_point;
|
PyObject *decimal_point;
|
||||||
char *thousands_sep;
|
PyObject *thousands_sep;
|
||||||
char *grouping;
|
const char *grouping;
|
||||||
} LocaleInfo;
|
} LocaleInfo;
|
||||||
|
|
||||||
|
#define STATIC_LOCALE_INFO_INIT {0, 0, 0}
|
||||||
|
|
||||||
/* describes the layout for an integer, see the comment in
|
/* describes the layout for an integer, see the comment in
|
||||||
calc_number_widths() for details */
|
calc_number_widths() for details */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -415,7 +417,7 @@ calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
|
||||||
Py_UCS4 sign_char, PyObject *number, Py_ssize_t n_start,
|
Py_UCS4 sign_char, PyObject *number, Py_ssize_t n_start,
|
||||||
Py_ssize_t n_end, Py_ssize_t n_remainder,
|
Py_ssize_t n_end, Py_ssize_t n_remainder,
|
||||||
int has_decimal, const LocaleInfo *locale,
|
int has_decimal, const LocaleInfo *locale,
|
||||||
const InternalFormatSpec *format)
|
const InternalFormatSpec *format, Py_UCS4 *maxchar)
|
||||||
{
|
{
|
||||||
Py_ssize_t n_non_digit_non_padding;
|
Py_ssize_t n_non_digit_non_padding;
|
||||||
Py_ssize_t n_padding;
|
Py_ssize_t n_padding;
|
||||||
|
@ -423,7 +425,7 @@ calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
|
||||||
spec->n_digits = n_end - n_start - n_remainder - (has_decimal?1:0);
|
spec->n_digits = n_end - n_start - n_remainder - (has_decimal?1:0);
|
||||||
spec->n_lpadding = 0;
|
spec->n_lpadding = 0;
|
||||||
spec->n_prefix = n_prefix;
|
spec->n_prefix = n_prefix;
|
||||||
spec->n_decimal = has_decimal ? strlen(locale->decimal_point) : 0;
|
spec->n_decimal = has_decimal ? PyUnicode_GET_LENGTH(locale->decimal_point) : 0;
|
||||||
spec->n_remainder = n_remainder;
|
spec->n_remainder = n_remainder;
|
||||||
spec->n_spadding = 0;
|
spec->n_spadding = 0;
|
||||||
spec->n_rpadding = 0;
|
spec->n_rpadding = 0;
|
||||||
|
@ -484,11 +486,15 @@ calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
|
||||||
to special case it because the grouping code always wants
|
to special case it because the grouping code always wants
|
||||||
to have at least one character. */
|
to have at least one character. */
|
||||||
spec->n_grouped_digits = 0;
|
spec->n_grouped_digits = 0;
|
||||||
else
|
else {
|
||||||
|
Py_UCS4 grouping_maxchar;
|
||||||
spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping(
|
spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping(
|
||||||
NULL, PyUnicode_1BYTE_KIND, NULL, 0, NULL,
|
NULL, 0,
|
||||||
|
0, NULL,
|
||||||
spec->n_digits, spec->n_min_width,
|
spec->n_digits, spec->n_min_width,
|
||||||
locale->grouping, locale->thousands_sep);
|
locale->grouping, locale->thousands_sep, &grouping_maxchar);
|
||||||
|
*maxchar = Py_MAX(*maxchar, grouping_maxchar);
|
||||||
|
}
|
||||||
|
|
||||||
/* Given the desired width and the total of digit and non-digit
|
/* Given the desired width and the total of digit and non-digit
|
||||||
space we consume, see if we need any padding. format->width can
|
space we consume, see if we need any padding. format->width can
|
||||||
|
@ -519,6 +525,10 @@ calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spec->n_lpadding || spec->n_spadding || spec->n_rpadding)
|
||||||
|
*maxchar = Py_MAX(*maxchar, format->fill_char);
|
||||||
|
|
||||||
return spec->n_lpadding + spec->n_sign + spec->n_prefix +
|
return spec->n_lpadding + spec->n_sign + spec->n_prefix +
|
||||||
spec->n_spadding + spec->n_grouped_digits + spec->n_decimal +
|
spec->n_spadding + spec->n_grouped_digits + spec->n_decimal +
|
||||||
spec->n_remainder + spec->n_rpadding;
|
spec->n_remainder + spec->n_rpadding;
|
||||||
|
@ -587,12 +597,11 @@ fill_number(PyObject *out, Py_ssize_t pos, const NumberFieldWidths *spec,
|
||||||
r =
|
r =
|
||||||
#endif
|
#endif
|
||||||
_PyUnicode_InsertThousandsGrouping(
|
_PyUnicode_InsertThousandsGrouping(
|
||||||
out, kind,
|
out, pos,
|
||||||
(char*)data + kind * pos,
|
|
||||||
spec->n_grouped_digits,
|
spec->n_grouped_digits,
|
||||||
pdigits + kind * d_pos,
|
pdigits + kind * d_pos,
|
||||||
spec->n_digits, spec->n_min_width,
|
spec->n_digits, spec->n_min_width,
|
||||||
locale->grouping, locale->thousands_sep);
|
locale->grouping, locale->thousands_sep, NULL);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert(r == spec->n_grouped_digits);
|
assert(r == spec->n_grouped_digits);
|
||||||
#endif
|
#endif
|
||||||
|
@ -615,10 +624,8 @@ fill_number(PyObject *out, Py_ssize_t pos, const NumberFieldWidths *spec,
|
||||||
pos += spec->n_grouped_digits;
|
pos += spec->n_grouped_digits;
|
||||||
|
|
||||||
if (spec->n_decimal) {
|
if (spec->n_decimal) {
|
||||||
Py_ssize_t t;
|
if (PyUnicode_CopyCharacters(out, pos, locale->decimal_point, 0, spec->n_decimal) < 0)
|
||||||
for (t = 0; t < spec->n_decimal; ++t)
|
return -1;
|
||||||
PyUnicode_WRITE(kind, data, pos + t,
|
|
||||||
locale->decimal_point[t]);
|
|
||||||
pos += spec->n_decimal;
|
pos += spec->n_decimal;
|
||||||
d_pos += 1;
|
d_pos += 1;
|
||||||
}
|
}
|
||||||
|
@ -643,32 +650,60 @@ static char no_grouping[1] = {CHAR_MAX};
|
||||||
grouping description, either for the current locale if type is
|
grouping description, either for the current locale if type is
|
||||||
LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or
|
LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or
|
||||||
none if LT_NO_LOCALE. */
|
none if LT_NO_LOCALE. */
|
||||||
static void
|
static int
|
||||||
get_locale_info(int type, LocaleInfo *locale_info)
|
get_locale_info(int type, LocaleInfo *locale_info)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LT_CURRENT_LOCALE: {
|
case LT_CURRENT_LOCALE: {
|
||||||
struct lconv *locale_data = localeconv();
|
struct lconv *locale_data = localeconv();
|
||||||
locale_info->decimal_point = locale_data->decimal_point;
|
locale_info->decimal_point = PyUnicode_DecodeLocale(
|
||||||
locale_info->thousands_sep = locale_data->thousands_sep;
|
locale_data->decimal_point,
|
||||||
|
NULL);
|
||||||
|
if (locale_info->decimal_point == NULL)
|
||||||
|
return -1;
|
||||||
|
locale_info->thousands_sep = PyUnicode_DecodeLocale(
|
||||||
|
locale_data->thousands_sep,
|
||||||
|
NULL);
|
||||||
|
if (locale_info->thousands_sep == NULL) {
|
||||||
|
Py_DECREF(locale_info->decimal_point);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
locale_info->grouping = locale_data->grouping;
|
locale_info->grouping = locale_data->grouping;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LT_DEFAULT_LOCALE:
|
case LT_DEFAULT_LOCALE:
|
||||||
locale_info->decimal_point = ".";
|
locale_info->decimal_point = PyUnicode_FromOrdinal('.');
|
||||||
locale_info->thousands_sep = ",";
|
locale_info->thousands_sep = PyUnicode_FromOrdinal(',');
|
||||||
|
if (!locale_info->decimal_point || !locale_info->thousands_sep) {
|
||||||
|
Py_XDECREF(locale_info->decimal_point);
|
||||||
|
Py_XDECREF(locale_info->thousands_sep);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
locale_info->grouping = "\3"; /* Group every 3 characters. The
|
locale_info->grouping = "\3"; /* Group every 3 characters. The
|
||||||
(implicit) trailing 0 means repeat
|
(implicit) trailing 0 means repeat
|
||||||
infinitely. */
|
infinitely. */
|
||||||
break;
|
break;
|
||||||
case LT_NO_LOCALE:
|
case LT_NO_LOCALE:
|
||||||
locale_info->decimal_point = ".";
|
locale_info->decimal_point = PyUnicode_FromOrdinal('.');
|
||||||
locale_info->thousands_sep = "";
|
locale_info->thousands_sep = PyUnicode_New(0, 0);
|
||||||
|
if (!locale_info->decimal_point || !locale_info->thousands_sep) {
|
||||||
|
Py_XDECREF(locale_info->decimal_point);
|
||||||
|
Py_XDECREF(locale_info->thousands_sep);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
locale_info->grouping = no_grouping;
|
locale_info->grouping = no_grouping;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_locale_info(LocaleInfo *locale_info)
|
||||||
|
{
|
||||||
|
Py_XDECREF(locale_info->decimal_point);
|
||||||
|
Py_XDECREF(locale_info->thousands_sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -769,7 +804,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
|
||||||
|
|
||||||
/* Locale settings, either from the actual locale or
|
/* Locale settings, either from the actual locale or
|
||||||
from a hard-code pseudo-locale */
|
from a hard-code pseudo-locale */
|
||||||
LocaleInfo locale;
|
LocaleInfo locale = STATIC_LOCALE_INFO_INIT;
|
||||||
|
|
||||||
/* no precision allowed on integers */
|
/* no precision allowed on integers */
|
||||||
if (format->precision != -1) {
|
if (format->precision != -1) {
|
||||||
|
@ -868,18 +903,17 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the grouping, separator, and decimal point, if any. */
|
/* Determine the grouping, separator, and decimal point, if any. */
|
||||||
get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
|
if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
|
||||||
(format->thousands_separators ?
|
(format->thousands_separators ?
|
||||||
LT_DEFAULT_LOCALE :
|
LT_DEFAULT_LOCALE :
|
||||||
LT_NO_LOCALE),
|
LT_NO_LOCALE),
|
||||||
&locale);
|
&locale) == -1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Calculate how much memory we'll need. */
|
/* Calculate how much memory we'll need. */
|
||||||
n_total = calc_number_widths(&spec, n_prefix, sign_char, tmp, inumeric_chars,
|
n_total = calc_number_widths(&spec, n_prefix, sign_char, tmp, inumeric_chars,
|
||||||
inumeric_chars + n_digits, n_remainder, 0, &locale, format);
|
inumeric_chars + n_digits, n_remainder, 0,
|
||||||
|
&locale, format, &maxchar);
|
||||||
if (spec.n_lpadding || spec.n_spadding || spec.n_rpadding)
|
|
||||||
maxchar = Py_MAX(maxchar, format->fill_char);
|
|
||||||
|
|
||||||
/* Allocate the memory. */
|
/* Allocate the memory. */
|
||||||
result = PyUnicode_New(n_total, maxchar);
|
result = PyUnicode_New(n_total, maxchar);
|
||||||
|
@ -897,6 +931,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
|
||||||
|
|
||||||
done:
|
done:
|
||||||
Py_XDECREF(tmp);
|
Py_XDECREF(tmp);
|
||||||
|
free_locale_info(&locale);
|
||||||
assert(!result || _PyUnicode_CheckConsistency(result, 1));
|
assert(!result || _PyUnicode_CheckConsistency(result, 1));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -938,7 +973,7 @@ format_float_internal(PyObject *value,
|
||||||
|
|
||||||
/* Locale settings, either from the actual locale or
|
/* Locale settings, either from the actual locale or
|
||||||
from a hard-code pseudo-locale */
|
from a hard-code pseudo-locale */
|
||||||
LocaleInfo locale;
|
LocaleInfo locale = STATIC_LOCALE_INFO_INIT;
|
||||||
|
|
||||||
if (format->alternate)
|
if (format->alternate)
|
||||||
flags |= Py_DTSF_ALT;
|
flags |= Py_DTSF_ALT;
|
||||||
|
@ -1009,19 +1044,17 @@ format_float_internal(PyObject *value,
|
||||||
parse_number(unicode_tmp, index, index + n_digits, &n_remainder, &has_decimal);
|
parse_number(unicode_tmp, index, index + n_digits, &n_remainder, &has_decimal);
|
||||||
|
|
||||||
/* Determine the grouping, separator, and decimal point, if any. */
|
/* Determine the grouping, separator, and decimal point, if any. */
|
||||||
get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
|
if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
|
||||||
(format->thousands_separators ?
|
(format->thousands_separators ?
|
||||||
LT_DEFAULT_LOCALE :
|
LT_DEFAULT_LOCALE :
|
||||||
LT_NO_LOCALE),
|
LT_NO_LOCALE),
|
||||||
&locale);
|
&locale) == -1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Calculate how much memory we'll need. */
|
/* Calculate how much memory we'll need. */
|
||||||
n_total = calc_number_widths(&spec, 0, sign_char, unicode_tmp, index,
|
n_total = calc_number_widths(&spec, 0, sign_char, unicode_tmp, index,
|
||||||
index + n_digits, n_remainder, has_decimal,
|
index + n_digits, n_remainder, has_decimal,
|
||||||
&locale, format);
|
&locale, format, &maxchar);
|
||||||
|
|
||||||
if (spec.n_lpadding || spec.n_spadding || spec.n_rpadding)
|
|
||||||
maxchar = Py_MAX(maxchar, format->fill_char);
|
|
||||||
|
|
||||||
/* Allocate the memory. */
|
/* Allocate the memory. */
|
||||||
result = PyUnicode_New(n_total, maxchar);
|
result = PyUnicode_New(n_total, maxchar);
|
||||||
|
@ -1040,6 +1073,7 @@ format_float_internal(PyObject *value,
|
||||||
done:
|
done:
|
||||||
PyMem_Free(buf);
|
PyMem_Free(buf);
|
||||||
Py_DECREF(unicode_tmp);
|
Py_DECREF(unicode_tmp);
|
||||||
|
free_locale_info(&locale);
|
||||||
assert(!result || _PyUnicode_CheckConsistency(result, 1));
|
assert(!result || _PyUnicode_CheckConsistency(result, 1));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1094,7 +1128,7 @@ format_complex_internal(PyObject *value,
|
||||||
|
|
||||||
/* Locale settings, either from the actual locale or
|
/* Locale settings, either from the actual locale or
|
||||||
from a hard-code pseudo-locale */
|
from a hard-code pseudo-locale */
|
||||||
LocaleInfo locale;
|
LocaleInfo locale = STATIC_LOCALE_INFO_INIT;
|
||||||
|
|
||||||
/* Zero padding is not allowed. */
|
/* Zero padding is not allowed. */
|
||||||
if (format->fill_char == '0') {
|
if (format->fill_char == '0') {
|
||||||
|
@ -1190,11 +1224,12 @@ format_complex_internal(PyObject *value,
|
||||||
&n_im_remainder, &im_has_decimal);
|
&n_im_remainder, &im_has_decimal);
|
||||||
|
|
||||||
/* Determine the grouping, separator, and decimal point, if any. */
|
/* Determine the grouping, separator, and decimal point, if any. */
|
||||||
get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
|
if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
|
||||||
(format->thousands_separators ?
|
(format->thousands_separators ?
|
||||||
LT_DEFAULT_LOCALE :
|
LT_DEFAULT_LOCALE :
|
||||||
LT_NO_LOCALE),
|
LT_NO_LOCALE),
|
||||||
&locale);
|
&locale) == -1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Turn off any padding. We'll do it later after we've composed
|
/* Turn off any padding. We'll do it later after we've composed
|
||||||
the numbers without padding. */
|
the numbers without padding. */
|
||||||
|
@ -1205,7 +1240,8 @@ format_complex_internal(PyObject *value,
|
||||||
/* Calculate how much memory we'll need. */
|
/* Calculate how much memory we'll need. */
|
||||||
n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, re_unicode_tmp,
|
n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, re_unicode_tmp,
|
||||||
i_re, i_re + n_re_digits, n_re_remainder,
|
i_re, i_re + n_re_digits, n_re_remainder,
|
||||||
re_has_decimal, &locale, &tmp_format);
|
re_has_decimal, &locale, &tmp_format,
|
||||||
|
&maxchar);
|
||||||
|
|
||||||
/* Same formatting, but always include a sign, unless the real part is
|
/* Same formatting, but always include a sign, unless the real part is
|
||||||
* going to be omitted, in which case we use whatever sign convention was
|
* going to be omitted, in which case we use whatever sign convention was
|
||||||
|
@ -1214,7 +1250,8 @@ format_complex_internal(PyObject *value,
|
||||||
tmp_format.sign = '+';
|
tmp_format.sign = '+';
|
||||||
n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, im_unicode_tmp,
|
n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, im_unicode_tmp,
|
||||||
i_im, i_im + n_im_digits, n_im_remainder,
|
i_im, i_im + n_im_digits, n_im_remainder,
|
||||||
im_has_decimal, &locale, &tmp_format);
|
im_has_decimal, &locale, &tmp_format,
|
||||||
|
&maxchar);
|
||||||
|
|
||||||
if (skip_re)
|
if (skip_re)
|
||||||
n_re_total = 0;
|
n_re_total = 0;
|
||||||
|
@ -1223,9 +1260,7 @@ format_complex_internal(PyObject *value,
|
||||||
calc_padding(n_re_total + n_im_total + 1 + add_parens * 2,
|
calc_padding(n_re_total + n_im_total + 1 + add_parens * 2,
|
||||||
format->width, format->align, &lpad, &rpad, &total);
|
format->width, format->align, &lpad, &rpad, &total);
|
||||||
|
|
||||||
if (re_spec.n_lpadding || re_spec.n_spadding || re_spec.n_rpadding
|
if (lpad || rpad)
|
||||||
|| im_spec.n_lpadding || im_spec.n_spadding || im_spec.n_rpadding
|
|
||||||
|| lpad || rpad)
|
|
||||||
maxchar = Py_MAX(maxchar, format->fill_char);
|
maxchar = Py_MAX(maxchar, format->fill_char);
|
||||||
|
|
||||||
result = PyUnicode_New(total, maxchar);
|
result = PyUnicode_New(total, maxchar);
|
||||||
|
@ -1275,6 +1310,7 @@ done:
|
||||||
PyMem_Free(im_buf);
|
PyMem_Free(im_buf);
|
||||||
Py_XDECREF(re_unicode_tmp);
|
Py_XDECREF(re_unicode_tmp);
|
||||||
Py_XDECREF(im_unicode_tmp);
|
Py_XDECREF(im_unicode_tmp);
|
||||||
|
free_locale_info(&locale);
|
||||||
assert(!result || _PyUnicode_CheckConsistency(result, 1));
|
assert(!result || _PyUnicode_CheckConsistency(result, 1));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue