[Python-checkins] cpython: Issue #13706: Fix format(int, "n") for locale with non-ASCII thousands separator

victor.stinner python-checkins at python.org
Fri Feb 24 00:49:31 CET 2012


http://hg.python.org/cpython/rev/f89e2f4cda88
changeset:   75231:f89e2f4cda88
user:        Victor Stinner <victor.stinner at haypocalc.com>
date:        Fri Feb 24 00:37:51 2012 +0100
summary:
  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

files:
  Include/unicodeobject.h         |   18 +--
  Lib/test/test_format.py         |   15 ++
  Objects/stringlib/asciilib.h    |    3 -
  Objects/stringlib/localeutil.h  |   71 +++------
  Objects/stringlib/stringdefs.h  |    2 -
  Objects/stringlib/ucs1lib.h     |    3 -
  Objects/stringlib/ucs2lib.h     |    3 -
  Objects/stringlib/ucs4lib.h     |    3 -
  Objects/stringlib/undef.h       |    2 +-
  Objects/stringlib/unicodedefs.h |    2 -
  Objects/unicodeobject.c         |   77 ++++++++--
  Python/formatter_unicode.c      |  142 ++++++++++++-------
  12 files changed, 189 insertions(+), 152 deletions(-)


diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h
--- a/Include/unicodeobject.h
+++ b/Include/unicodeobject.h
@@ -1936,32 +1936,20 @@
     );
 #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
    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_InsertThousandsGrouping(
     PyObject *unicode,
-    int kind,
-    void *buffer,
+    Py_ssize_t index,
     Py_ssize_t n_buffer,
     void *digits,
     Py_ssize_t n_digits,
     Py_ssize_t min_width,
     const char *grouping,
-    const char *thousands_sep);
+    PyObject *thousands_sep,
+    Py_UCS4 *maxchar);
 #endif
 /* === Characters Type APIs =============================================== */
 
diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -1,4 +1,5 @@
 from test.support import verbose, TestFailed
+import locale
 import sys
 import test.support as support
 import unittest
@@ -282,6 +283,20 @@
         self.assertEqual(format(1+2j, "\u2007^8"), "\u2007(1+2j)\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():
     support.run_unittest(FormatTest)
diff --git a/Objects/stringlib/asciilib.h b/Objects/stringlib/asciilib.h
--- a/Objects/stringlib/asciilib.h
+++ b/Objects/stringlib/asciilib.h
@@ -21,12 +21,9 @@
 #define STRINGLIB_RESIZE         not_supported
 #define STRINGLIB_CHECK          PyUnicode_Check
 #define STRINGLIB_CHECK_EXACT    PyUnicode_CheckExact
-#define STRINGLIB_GROUPING       _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
 
 #define STRINGLIB_TOSTR          PyObject_Str
 #define STRINGLIB_TOASCII        PyObject_ASCII
 
 #define _Py_InsertThousandsGrouping _PyUnicode_ascii_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ascii_InsertThousandsGroupingLocale
 
diff --git a/Objects/stringlib/localeutil.h b/Objects/stringlib/localeutil.h
--- a/Objects/stringlib/localeutil.h
+++ b/Objects/stringlib/localeutil.h
@@ -2,8 +2,9 @@
 
 #include <locale.h>
 
-#define MAX(x, y) ((x) < (y) ? (y) : (x))
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#ifndef STRINGLIB_IS_UNICODE
+#   error "localeutil is specific to Unicode"
+#endif
 
 typedef struct {
     const char *grouping;
@@ -46,7 +47,7 @@
    are optional, depending on when we're called. */
 static void
 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 i;
@@ -55,15 +56,8 @@
         *buffer_end -= thousands_sep_len;
 
         /* Copy the thousands_sep chars into the buffer. */
-#if STRINGLIB_IS_UNICODE
-        /* Convert from the char's of the thousands_sep from
-           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
+        memcpy(*buffer_end, thousands_sep,
+               thousands_sep_len * STRINGLIB_SIZEOF_CHAR);
     }
 
     *buffer_end -= n_chars;
@@ -76,7 +70,7 @@
 }
 
 /**
- * _Py_InsertThousandsGrouping:
+ * InsertThousandsGrouping:
  * @buffer: A pointer to the start of a string.
  * @n_buffer: Number of characters in @buffer.
  * @digits: A pointer to the digits we're reading from. If count
@@ -106,13 +100,15 @@
     _insert_thousands_sep().
  **/
 Py_ssize_t
-_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer,
-                            Py_ssize_t n_buffer,
-                            STRINGLIB_CHAR *digits,
-                            Py_ssize_t n_digits,
-                            Py_ssize_t min_width,
-                            const char *grouping,
-                            const char *thousands_sep)
+STRINGLIB(InsertThousandsGrouping)(
+    STRINGLIB_CHAR *buffer,
+    Py_ssize_t n_buffer,
+    STRINGLIB_CHAR *digits,
+    Py_ssize_t n_digits,
+    Py_ssize_t min_width,
+    const char *grouping,
+    STRINGLIB_CHAR *thousands_sep,
+    Py_ssize_t thousands_sep_len)
 {
     Py_ssize_t count = 0;
     Py_ssize_t n_zeros;
@@ -124,7 +120,6 @@
     STRINGLIB_CHAR *digits_end = NULL;
     Py_ssize_t l;
     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
                                         be looked at */
     /* A generator that returns all of the grouping widths, until it
@@ -138,9 +133,9 @@
     }
 
     while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
-        l = MIN(l, MAX(MAX(remaining, min_width), 1));
-        n_zeros = MAX(0, l - remaining);
-        n_chars = MAX(0, MIN(remaining, l));
+        l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1));
+        n_zeros = Py_MAX(0, l - remaining);
+        n_chars = Py_MAX(0, Py_MIN(remaining, l));
 
         /* Use n_zero zero's and n_chars chars */
 
@@ -168,9 +163,9 @@
     if (!loop_broken) {
         /* We left the loop without using a break statement. */
 
-        l = MAX(MAX(remaining, min_width), 1);
-        n_zeros = MAX(0, l - remaining);
-        n_chars = MAX(0, MIN(remaining, l));
+        l = Py_MAX(Py_MAX(remaining, min_width), 1);
+        n_zeros = Py_MAX(0, l - remaining);
+        n_chars = Py_MAX(0, Py_MIN(remaining, l));
 
         /* Use n_zero zero's and n_chars chars */
         count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
@@ -183,25 +178,3 @@
     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);
-}
diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h
--- a/Objects/stringlib/stringdefs.h
+++ b/Objects/stringlib/stringdefs.h
@@ -25,7 +25,5 @@
 #define STRINGLIB_CHECK          PyBytes_Check
 #define STRINGLIB_CHECK_EXACT    PyBytes_CheckExact
 #define STRINGLIB_TOSTR          PyObject_Str
-#define STRINGLIB_GROUPING       _PyBytes_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyBytes_InsertThousandsGroupingLocale
 #define STRINGLIB_TOASCII        PyObject_Repr
 #endif /* !STRINGLIB_STRINGDEFS_H */
diff --git a/Objects/stringlib/ucs1lib.h b/Objects/stringlib/ucs1lib.h
--- a/Objects/stringlib/ucs1lib.h
+++ b/Objects/stringlib/ucs1lib.h
@@ -21,13 +21,10 @@
 #define STRINGLIB_RESIZE         not_supported
 #define STRINGLIB_CHECK          PyUnicode_Check
 #define STRINGLIB_CHECK_EXACT    PyUnicode_CheckExact
-#define STRINGLIB_GROUPING       _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
 
 #define STRINGLIB_TOSTR          PyObject_Str
 #define STRINGLIB_TOASCII        PyObject_ASCII
 
 #define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs1_InsertThousandsGroupingLocale
 
 
diff --git a/Objects/stringlib/ucs2lib.h b/Objects/stringlib/ucs2lib.h
--- a/Objects/stringlib/ucs2lib.h
+++ b/Objects/stringlib/ucs2lib.h
@@ -21,12 +21,9 @@
 #define STRINGLIB_RESIZE         not_supported
 #define STRINGLIB_CHECK          PyUnicode_Check
 #define STRINGLIB_CHECK_EXACT    PyUnicode_CheckExact
-#define STRINGLIB_GROUPING       _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
 
 #define STRINGLIB_TOSTR          PyObject_Str
 #define STRINGLIB_TOASCII        PyObject_ASCII
 
 #define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs2_InsertThousandsGroupingLocale
 
diff --git a/Objects/stringlib/ucs4lib.h b/Objects/stringlib/ucs4lib.h
--- a/Objects/stringlib/ucs4lib.h
+++ b/Objects/stringlib/ucs4lib.h
@@ -21,12 +21,9 @@
 #define STRINGLIB_RESIZE         not_supported
 #define STRINGLIB_CHECK          PyUnicode_Check
 #define STRINGLIB_CHECK_EXACT    PyUnicode_CheckExact
-#define STRINGLIB_GROUPING       _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
 
 #define STRINGLIB_TOSTR          PyObject_Str
 #define STRINGLIB_TOASCII        PyObject_ASCII
 
 #define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping
-#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs4_InsertThousandsGroupingLocale
 
diff --git a/Objects/stringlib/undef.h b/Objects/stringlib/undef.h
--- a/Objects/stringlib/undef.h
+++ b/Objects/stringlib/undef.h
@@ -7,5 +7,5 @@
 #undef  STRINGLIB_NEW
 #undef  STRINGLIB_RESIZE
 #undef  _Py_InsertThousandsGrouping
-#undef  _Py_InsertThousandsGroupingLocale
+#undef STRINGLIB_IS_UNICODE
 
diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h
--- a/Objects/stringlib/unicodedefs.h
+++ b/Objects/stringlib/unicodedefs.h
@@ -24,8 +24,6 @@
 #define STRINGLIB_RESIZE         PyUnicode_Resize
 #define STRINGLIB_CHECK          PyUnicode_Check
 #define STRINGLIB_CHECK_EXACT    PyUnicode_CheckExact
-#define STRINGLIB_GROUPING       _PyUnicode_InsertThousandsGrouping
-#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale
 
 #if PY_VERSION_HEX < 0x03000000
 #define STRINGLIB_TOSTR          PyObject_Unicode
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -9151,34 +9151,75 @@
 }
 
 Py_ssize_t
-_PyUnicode_InsertThousandsGrouping(PyObject *unicode, int kind, void *data,
-                                   Py_ssize_t n_buffer,
-                                   void *digits, Py_ssize_t n_digits,
-                                   Py_ssize_t min_width,
-                                   const char *grouping,
-                                   const char *thousands_sep)
-{
+_PyUnicode_InsertThousandsGrouping(
+    PyObject *unicode, Py_ssize_t index,
+    Py_ssize_t n_buffer,
+    void *digits, Py_ssize_t n_digits,
+    Py_ssize_t min_width,
+    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) {
     case PyUnicode_1BYTE_KIND:
         if (unicode != NULL && PyUnicode_IS_ASCII(unicode))
-            return _PyUnicode_ascii_InsertThousandsGrouping(
+            len = asciilib_InsertThousandsGrouping(
                 (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
-            return _PyUnicode_ucs1_InsertThousandsGrouping(
+            len = ucs1lib_InsertThousandsGrouping(
                 (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:
-        return _PyUnicode_ucs2_InsertThousandsGrouping(
+        len = ucs2lib_InsertThousandsGrouping(
             (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:
-        return _PyUnicode_ucs4_InsertThousandsGrouping(
+        len = ucs4lib_InsertThousandsGrouping(
             (Py_UCS4*)data, n_buffer, (Py_UCS4*)digits, n_digits,
-            min_width, grouping, thousands_sep);
-    }
-    assert(0);
-    return -1;
+            min_width, grouping,
+            thousands_sep_data, thousands_sep_len);
+        break;
+    default:
+        assert(0);
+        return -1;
+    }
+    if (unicode != NULL && thousands_sep_kind != kind)
+        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;
 }
 
 
diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c
--- a/Python/formatter_unicode.c
+++ b/Python/formatter_unicode.c
@@ -346,11 +346,13 @@
    before and including the decimal. Note that locales only support
    8-bit chars, not unicode. */
 typedef struct {
-    char *decimal_point;
-    char *thousands_sep;
-    char *grouping;
+    PyObject *decimal_point;
+    PyObject *thousands_sep;
+    const char *grouping;
 } LocaleInfo;
 
+#define STATIC_LOCALE_INFO_INIT {0, 0, 0}
+
 /* describes the layout for an integer, see the comment in
    calc_number_widths() for details */
 typedef struct {
@@ -415,7 +417,7 @@
                    Py_UCS4 sign_char, PyObject *number, Py_ssize_t n_start,
                    Py_ssize_t n_end, Py_ssize_t n_remainder,
                    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_padding;
@@ -423,7 +425,7 @@
     spec->n_digits = n_end - n_start - n_remainder - (has_decimal?1:0);
     spec->n_lpadding = 0;
     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_spadding = 0;
     spec->n_rpadding = 0;
@@ -484,11 +486,15 @@
            to special case it because the grouping code always wants
            to have at least one character. */
         spec->n_grouped_digits = 0;
-    else
+    else {
+        Py_UCS4 grouping_maxchar;
         spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping(
-            NULL, PyUnicode_1BYTE_KIND, NULL, 0, NULL,
+            NULL, 0,
+            0, NULL,
             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
        space we consume, see if we need any padding. format->width can
@@ -519,6 +525,10 @@
             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 +
         spec->n_spadding + spec->n_grouped_digits + spec->n_decimal +
         spec->n_remainder + spec->n_rpadding;
@@ -587,12 +597,11 @@
         r =
 #endif
             _PyUnicode_InsertThousandsGrouping(
-                out, kind,
-                (char*)data + kind * pos,
+                out, pos,
                 spec->n_grouped_digits,
                 pdigits + kind * d_pos,
                 spec->n_digits, spec->n_min_width,
-                locale->grouping, locale->thousands_sep);
+                locale->grouping, locale->thousands_sep, NULL);
 #ifndef NDEBUG
         assert(r == spec->n_grouped_digits);
 #endif
@@ -615,10 +624,8 @@
     pos += spec->n_grouped_digits;
 
     if (spec->n_decimal) {
-        Py_ssize_t t;
-        for (t = 0; t < spec->n_decimal; ++t)
-            PyUnicode_WRITE(kind, data, pos + t,
-                            locale->decimal_point[t]);
+        if (PyUnicode_CopyCharacters(out, pos, locale->decimal_point, 0, spec->n_decimal) < 0)
+            return -1;
         pos += spec->n_decimal;
         d_pos += 1;
     }
@@ -643,32 +650,60 @@
    grouping description, either for the current locale if type is
    LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or
    none if LT_NO_LOCALE. */
-static void
+static int
 get_locale_info(int type, LocaleInfo *locale_info)
 {
     switch (type) {
     case LT_CURRENT_LOCALE: {
         struct lconv *locale_data = localeconv();
-        locale_info->decimal_point = locale_data->decimal_point;
-        locale_info->thousands_sep = locale_data->thousands_sep;
+        locale_info->decimal_point = PyUnicode_DecodeLocale(
+                                         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;
         break;
     }
     case LT_DEFAULT_LOCALE:
-        locale_info->decimal_point = ".";
-        locale_info->thousands_sep = ",";
+        locale_info->decimal_point = PyUnicode_FromOrdinal('.');
+        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
                                          (implicit) trailing 0 means repeat
                                          infinitely. */
         break;
     case LT_NO_LOCALE:
-        locale_info->decimal_point = ".";
-        locale_info->thousands_sep = "";
+        locale_info->decimal_point = PyUnicode_FromOrdinal('.');
+        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;
         break;
     default:
         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 @@
 
     /* Locale settings, either from the actual locale or
        from a hard-code pseudo-locale */
-    LocaleInfo locale;
+    LocaleInfo locale = STATIC_LOCALE_INFO_INIT;
 
     /* no precision allowed on integers */
     if (format->precision != -1) {
@@ -868,18 +903,17 @@
     }
 
     /* Determine the grouping, separator, and decimal point, if any. */
-    get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
-                    (format->thousands_separators ?
-                     LT_DEFAULT_LOCALE :
-                     LT_NO_LOCALE),
-                    &locale);
+    if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
+                        (format->thousands_separators ?
+                         LT_DEFAULT_LOCALE :
+                         LT_NO_LOCALE),
+                        &locale) == -1)
+        goto done;
 
     /* Calculate how much memory we'll need. */
     n_total = calc_number_widths(&spec, n_prefix, sign_char, tmp, inumeric_chars,
-                                 inumeric_chars + n_digits, n_remainder, 0, &locale, format);
-
-    if (spec.n_lpadding || spec.n_spadding || spec.n_rpadding)
-        maxchar = Py_MAX(maxchar, format->fill_char);
+                                 inumeric_chars + n_digits, n_remainder, 0,
+                                 &locale, format, &maxchar);
 
     /* Allocate the memory. */
     result = PyUnicode_New(n_total, maxchar);
@@ -897,6 +931,7 @@
 
 done:
     Py_XDECREF(tmp);
+    free_locale_info(&locale);
     assert(!result || _PyUnicode_CheckConsistency(result, 1));
     return result;
 }
@@ -938,7 +973,7 @@
 
     /* Locale settings, either from the actual locale or
        from a hard-code pseudo-locale */
-    LocaleInfo locale;
+    LocaleInfo locale = STATIC_LOCALE_INFO_INIT;
 
     if (format->alternate)
         flags |= Py_DTSF_ALT;
@@ -1009,19 +1044,17 @@
     parse_number(unicode_tmp, index, index + n_digits, &n_remainder, &has_decimal);
 
     /* Determine the grouping, separator, and decimal point, if any. */
-    get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
-                    (format->thousands_separators ?
-                     LT_DEFAULT_LOCALE :
-                     LT_NO_LOCALE),
-                    &locale);
+    if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
+                        (format->thousands_separators ?
+                         LT_DEFAULT_LOCALE :
+                         LT_NO_LOCALE),
+                        &locale) == -1)
+        goto done;
 
     /* Calculate how much memory we'll need. */
     n_total = calc_number_widths(&spec, 0, sign_char, unicode_tmp, index,
                                  index + n_digits, n_remainder, has_decimal,
-                                 &locale, format);
-
-    if (spec.n_lpadding || spec.n_spadding || spec.n_rpadding)
-        maxchar = Py_MAX(maxchar, format->fill_char);
+                                 &locale, format, &maxchar);
 
     /* Allocate the memory. */
     result = PyUnicode_New(n_total, maxchar);
@@ -1040,6 +1073,7 @@
 done:
     PyMem_Free(buf);
     Py_DECREF(unicode_tmp);
+    free_locale_info(&locale);
     assert(!result || _PyUnicode_CheckConsistency(result, 1));
     return result;
 }
@@ -1094,7 +1128,7 @@
 
     /* Locale settings, either from the actual locale or
        from a hard-code pseudo-locale */
-    LocaleInfo locale;
+    LocaleInfo locale = STATIC_LOCALE_INFO_INIT;
 
     /* Zero padding is not allowed. */
     if (format->fill_char == '0') {
@@ -1190,11 +1224,12 @@
                  &n_im_remainder, &im_has_decimal);
 
     /* Determine the grouping, separator, and decimal point, if any. */
-    get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
-                    (format->thousands_separators ?
-                     LT_DEFAULT_LOCALE :
-                     LT_NO_LOCALE),
-                    &locale);
+    if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE :
+                        (format->thousands_separators ?
+                         LT_DEFAULT_LOCALE :
+                         LT_NO_LOCALE),
+                        &locale) == -1)
+        goto done;
 
     /* Turn off any padding. We'll do it later after we've composed
        the numbers without padding. */
@@ -1205,7 +1240,8 @@
     /* Calculate how much memory we'll need. */
     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,
-                                    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
      * going to be omitted, in which case we use whatever sign convention was
@@ -1214,7 +1250,8 @@
         tmp_format.sign = '+';
     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,
-                                    im_has_decimal, &locale, &tmp_format);
+                                    im_has_decimal, &locale, &tmp_format,
+                                    &maxchar);
 
     if (skip_re)
         n_re_total = 0;
@@ -1223,9 +1260,7 @@
     calc_padding(n_re_total + n_im_total + 1 + add_parens * 2,
                  format->width, format->align, &lpad, &rpad, &total);
 
-    if (re_spec.n_lpadding || re_spec.n_spadding || re_spec.n_rpadding
-        || im_spec.n_lpadding || im_spec.n_spadding || im_spec.n_rpadding
-        || lpad || rpad)
+    if (lpad || rpad)
         maxchar = Py_MAX(maxchar, format->fill_char);
 
     result = PyUnicode_New(total, maxchar);
@@ -1275,6 +1310,7 @@
     PyMem_Free(im_buf);
     Py_XDECREF(re_unicode_tmp);
     Py_XDECREF(im_unicode_tmp);
+    free_locale_info(&locale);
     assert(!result || _PyUnicode_CheckConsistency(result, 1));
     return result;
 }

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list