|
|
|
@ -32,14 +32,20 @@ invalid_comma_type(Py_UCS4 presentation_type) |
|
|
|
{ |
|
|
|
if (presentation_type > 32 && presentation_type < 128) |
|
|
|
PyErr_Format(PyExc_ValueError, |
|
|
|
"Cannot specify ',' with '%c'.", |
|
|
|
"Cannot specify ',' or '_' with '%c'.", |
|
|
|
(char)presentation_type); |
|
|
|
else |
|
|
|
PyErr_Format(PyExc_ValueError, |
|
|
|
"Cannot specify ',' with '\\x%x'.", |
|
|
|
"Cannot specify ',' or '_' with '\\x%x'.", |
|
|
|
(unsigned int)presentation_type); |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
invalid_comma_and_underscore() |
|
|
|
{ |
|
|
|
PyErr_Format(PyExc_ValueError, "Cannot specify both ',' and '_'."); |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
get_integer consumes 0 or more decimal digit characters from an |
|
|
|
input string, updates *result with the corresponding positive |
|
|
|
@ -108,6 +114,12 @@ is_sign_element(Py_UCS4 c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Locale type codes. LT_NO_LOCALE must be zero. */ |
|
|
|
#define LT_NO_LOCALE 0 |
|
|
|
#define LT_DEFAULT_LOCALE 1 |
|
|
|
#define LT_UNDERSCORE_LOCALE 2 |
|
|
|
#define LT_UNDER_FOUR_LOCALE 3 |
|
|
|
#define LT_CURRENT_LOCALE 4 |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
Py_UCS4 fill_char; |
|
|
|
@ -223,9 +235,22 @@ parse_internal_render_format_spec(PyObject *format_spec, |
|
|
|
|
|
|
|
/* Comma signifies add thousands separators */ |
|
|
|
if (end-pos && READ_spec(pos) == ',') { |
|
|
|
format->thousands_separators = 1; |
|
|
|
format->thousands_separators = LT_DEFAULT_LOCALE; |
|
|
|
++pos; |
|
|
|
} |
|
|
|
/* Underscore signifies add thousands separators */ |
|
|
|
if (end-pos && READ_spec(pos) == '_') { |
|
|
|
if (format->thousands_separators != 0) { |
|
|
|
invalid_comma_and_underscore(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
format->thousands_separators = LT_UNDERSCORE_LOCALE; |
|
|
|
++pos; |
|
|
|
} |
|
|
|
if (end-pos && READ_spec(pos) == ',') { |
|
|
|
invalid_comma_and_underscore(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Parse field precision */ |
|
|
|
if (end-pos && READ_spec(pos) == '.') { |
|
|
|
@ -275,6 +300,16 @@ parse_internal_render_format_spec(PyObject *format_spec, |
|
|
|
case '\0': |
|
|
|
/* These are allowed. See PEP 378.*/ |
|
|
|
break; |
|
|
|
case 'b': |
|
|
|
case 'o': |
|
|
|
case 'x': |
|
|
|
case 'X': |
|
|
|
/* Underscores are allowed in bin/oct/hex. See PEP 515. */ |
|
|
|
if (format->thousands_separators == LT_UNDERSCORE_LOCALE) { |
|
|
|
/* Every four digits, not every three, in bin/oct/hex. */ |
|
|
|
format->thousands_separators = LT_UNDER_FOUR_LOCALE; |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
invalid_comma_type(format->type); |
|
|
|
return 0; |
|
|
|
@ -351,11 +386,6 @@ fill_padding(_PyUnicodeWriter *writer, |
|
|
|
/*********** common routines for numeric formatting *********************/ |
|
|
|
/************************************************************************/ |
|
|
|
|
|
|
|
/* Locale type codes. */ |
|
|
|
#define LT_CURRENT_LOCALE 0 |
|
|
|
#define LT_DEFAULT_LOCALE 1 |
|
|
|
#define LT_NO_LOCALE 2 |
|
|
|
|
|
|
|
/* Locale info needed for formatting integers and the part of floats |
|
|
|
before and including the decimal. Note that locales only support |
|
|
|
8-bit chars, not unicode. */ |
|
|
|
@ -667,8 +697,8 @@ static const char no_grouping[1] = {CHAR_MAX}; |
|
|
|
|
|
|
|
/* Find the decimal point character(s?), thousands_separator(s?), and |
|
|
|
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. */ |
|
|
|
LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE or |
|
|
|
LT_UNDERSCORE_LOCALE/LT_UNDER_FOUR_LOCALE, or none if LT_NO_LOCALE. */ |
|
|
|
static int |
|
|
|
get_locale_info(int type, LocaleInfo *locale_info) |
|
|
|
{ |
|
|
|
@ -691,16 +721,22 @@ get_locale_info(int type, LocaleInfo *locale_info) |
|
|
|
break; |
|
|
|
} |
|
|
|
case LT_DEFAULT_LOCALE: |
|
|
|
case LT_UNDERSCORE_LOCALE: |
|
|
|
case LT_UNDER_FOUR_LOCALE: |
|
|
|
locale_info->decimal_point = PyUnicode_FromOrdinal('.'); |
|
|
|
locale_info->thousands_sep = PyUnicode_FromOrdinal(','); |
|
|
|
locale_info->thousands_sep = PyUnicode_FromOrdinal( |
|
|
|
type == LT_DEFAULT_LOCALE ? ',' : '_'); |
|
|
|
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 |
|
|
|
if (type != LT_UNDER_FOUR_LOCALE) |
|
|
|
locale_info->grouping = "\3"; /* Group every 3 characters. The |
|
|
|
(implicit) trailing 0 means repeat |
|
|
|
infinitely. */ |
|
|
|
else |
|
|
|
locale_info->grouping = "\4"; /* Bin/oct/hex group every four. */ |
|
|
|
break; |
|
|
|
case LT_NO_LOCALE: |
|
|
|
locale_info->decimal_point = PyUnicode_FromOrdinal('.'); |
|
|
|
@ -952,9 +988,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format, |
|
|
|
|
|
|
|
/* Determine the grouping, separator, and decimal point, if any. */ |
|
|
|
if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : |
|
|
|
(format->thousands_separators ? |
|
|
|
LT_DEFAULT_LOCALE : |
|
|
|
LT_NO_LOCALE), |
|
|
|
format->thousands_separators, |
|
|
|
&locale) == -1) |
|
|
|
goto done; |
|
|
|
|
|
|
|
@ -1099,9 +1133,7 @@ format_float_internal(PyObject *value, |
|
|
|
|
|
|
|
/* Determine the grouping, separator, and decimal point, if any. */ |
|
|
|
if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : |
|
|
|
(format->thousands_separators ? |
|
|
|
LT_DEFAULT_LOCALE : |
|
|
|
LT_NO_LOCALE), |
|
|
|
format->thousands_separators, |
|
|
|
&locale) == -1) |
|
|
|
goto done; |
|
|
|
|
|
|
|
@ -1277,9 +1309,7 @@ format_complex_internal(PyObject *value, |
|
|
|
|
|
|
|
/* Determine the grouping, separator, and decimal point, if any. */ |
|
|
|
if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : |
|
|
|
(format->thousands_separators ? |
|
|
|
LT_DEFAULT_LOCALE : |
|
|
|
LT_NO_LOCALE), |
|
|
|
format->thousands_separators, |
|
|
|
&locale) == -1) |
|
|
|
goto done; |
|
|
|
|
|
|
|
|