@@ -358,7 +358,8 @@ parse_internal_render_format_spec(PyObject *obj,
358
358
}
359
359
}
360
360
361
- if (format -> type == 'n'
361
+ if ((format -> type == 'n' || format -> type == 'd' || format -> type == 'b'
362
+ || format -> type == 'o' || format -> type == 'x' || format -> type == 'X' )
362
363
&& format -> frac_thousands_separator != LT_NO_LOCALE )
363
364
{
364
365
invalid_thousands_separator_type (format -> frac_thousands_separator ,
@@ -979,12 +980,6 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
979
980
from a hard-code pseudo-locale */
980
981
LocaleInfo locale = LocaleInfo_STATIC_INIT ;
981
982
982
- /* no precision allowed on integers */
983
- if (format -> precision != -1 ) {
984
- PyErr_SetString (PyExc_ValueError ,
985
- "Precision not allowed in integer format specifier" );
986
- goto done ;
987
- }
988
983
/* no negative zero coercion on integers */
989
984
if (format -> no_neg_0 ) {
990
985
PyErr_SetString (PyExc_ValueError ,
@@ -1063,6 +1058,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
1063
1058
1064
1059
if (format -> sign != '+' && format -> sign != ' '
1065
1060
&& format -> width == -1
1061
+ && format -> precision == -1
1066
1062
&& format -> type != 'X' && format -> type != 'n'
1067
1063
&& !format -> thousands_separators
1068
1064
&& PyLong_CheckExact (value ))
@@ -1077,9 +1073,109 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
1077
1073
n_prefix = leading_chars_to_skip ;
1078
1074
1079
1075
/* Do the hard part, converting to a string in a given base */
1080
- tmp = _PyLong_Format (value , base );
1081
- if (tmp == NULL )
1082
- goto done ;
1076
+ if (format -> precision != -1 ) {
1077
+ /* Use two's complement for 'b', 'o' and 'x' formatting types */
1078
+ if (format -> type == 'b' || format -> type == 'x'
1079
+ || format -> type == 'o' || format -> type == 'X' )
1080
+ {
1081
+ int64_t shift = Py_MAX (1 , format -> precision );
1082
+
1083
+ if (format -> type == 'x' || format -> type == 'X' ) {
1084
+ shift *= 4 ;
1085
+ }
1086
+ else if (format -> type == 'o' ) {
1087
+ shift *= 3 ;
1088
+ }
1089
+
1090
+ PyObject * mod = _PyLong_Lshift (PyLong_FromLong (1 ), shift );
1091
+ PyObject * mod2 = _PyLong_Rshift (mod , 1 );
1092
+ PyObject * value2 = value ;
1093
+
1094
+ if (mod == NULL || mod2 == NULL ) {
1095
+ Py_XDECREF (mod );
1096
+ Py_XDECREF (mod2 );
1097
+ goto done ;
1098
+ }
1099
+ if (PyLong_IsNegative (value )) {
1100
+ value2 = PyNumber_Negative (mod2 );
1101
+ if (value2 == NULL ) {
1102
+ Py_DECREF (mod2 );
1103
+ goto done ;
1104
+ }
1105
+ Py_SETREF (mod2 , value2 );
1106
+ if (PyObject_RichCompareBool (value , mod2 , Py_LT )) {
1107
+ Py_DECREF (mod2 );
1108
+ PyErr_Format (PyExc_OverflowError ,
1109
+ "Expected integer in range [-2**%ld, 2**%ld)" ,
1110
+ shift - 1 , shift - 1 );
1111
+ goto done ;
1112
+ }
1113
+ Py_DECREF (mod2 );
1114
+ value2 = PyNumber_Add (value , mod );
1115
+ Py_DECREF (mod );
1116
+ if (value2 == NULL ) {
1117
+ goto done ;
1118
+ }
1119
+ }
1120
+ else {
1121
+ if (PyObject_RichCompareBool (value2 , mod2 , Py_GE )) {
1122
+ Py_DECREF (mod );
1123
+ Py_DECREF (mod2 );
1124
+ PyErr_Format (PyExc_OverflowError ,
1125
+ "Expected integer in range [-2**%ld, 2**%ld)" ,
1126
+ shift - 1 , shift - 1 );
1127
+ goto done ;
1128
+ }
1129
+ Py_DECREF (mod );
1130
+ Py_DECREF (mod2 );
1131
+ Py_INCREF (value2 );
1132
+ }
1133
+ tmp = _PyLong_Format (value2 , base );
1134
+ Py_DECREF (value2 );
1135
+ }
1136
+ else {
1137
+ tmp = _PyLong_Format (value , base );
1138
+ }
1139
+
1140
+ /* Prepend enough leading zeros (after the sign) */
1141
+
1142
+ int sign = PyUnicode_READ_CHAR (tmp , leading_chars_to_skip ) == '-' ;
1143
+ Py_ssize_t tmp2_len = format -> precision + leading_chars_to_skip + sign ;
1144
+ Py_ssize_t tmp_len = PyUnicode_GET_LENGTH (tmp );
1145
+ Py_ssize_t gap = tmp2_len - tmp_len ;
1146
+
1147
+ if (gap > 0 ) {
1148
+ PyObject * tmp2 = PyUnicode_New (tmp2_len , 127 );
1149
+
1150
+ if (PyUnicode_CopyCharacters (tmp2 , leading_chars_to_skip + gap + sign ,
1151
+ tmp , leading_chars_to_skip + sign ,
1152
+ tmp2_len - leading_chars_to_skip - sign ) == -1 ) {
1153
+ Py_DECREF (tmp2 );
1154
+ goto done ;
1155
+ }
1156
+ if (PyUnicode_Fill (tmp2 , leading_chars_to_skip + sign , gap , '0' ) == -1 ) {
1157
+ Py_DECREF (tmp2 );
1158
+ goto done ;
1159
+ }
1160
+ if (sign && PyUnicode_WriteChar (tmp2 , leading_chars_to_skip , '-' ) == -1 ) {
1161
+ Py_DECREF (tmp2 );
1162
+ goto done ;
1163
+ }
1164
+ if (leading_chars_to_skip
1165
+ && PyUnicode_CopyCharacters (tmp2 , 0 , tmp , 0 ,
1166
+ leading_chars_to_skip ) == -1 ) {
1167
+ Py_DECREF (tmp2 );
1168
+ goto done ;
1169
+ }
1170
+ Py_SETREF (tmp , tmp2 );
1171
+ }
1172
+ }
1173
+ else {
1174
+ tmp = _PyLong_Format (value , base );
1175
+ if (tmp == NULL ) {
1176
+ goto done ;
1177
+ }
1178
+ }
1083
1179
1084
1180
inumeric_chars = 0 ;
1085
1181
n_digits = PyUnicode_GET_LENGTH (tmp );
0 commit comments