@@ -1214,34 +1214,34 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
12141214 from a hard-code pseudo-locale */
12151215 LocaleInfo locale = LocaleInfo_STATIC_INIT ;
12161216
1217- /* no precision allowed on integers */
1218- if (format -> precision != -1 ) {
1219- PyErr_SetString (PyExc_ValueError ,
1220- "Precision not allowed in integer format specifier" );
1221- goto done ;
1222- }
1223- /* no negative zero coercion on integers */
1224- if (format -> no_neg_0 ) {
1225- PyErr_SetString (PyExc_ValueError ,
1226- "Negative zero coercion (z) not allowed in integer"
1227- " format specifier" );
1228- goto done ;
1229- }
1230-
12311217 /* special case for character formatting */
12321218 if (format -> type == 'c' ) {
12331219 /* error to specify a sign */
12341220 if (format -> sign != '\0' ) {
12351221 PyErr_SetString (PyExc_ValueError ,
12361222 "Sign not allowed with integer"
1237- " format specifier 'c'" );
1223+ " presentation type 'c'" );
12381224 goto done ;
12391225 }
12401226 /* error to request alternate format */
12411227 if (format -> alternate ) {
12421228 PyErr_SetString (PyExc_ValueError ,
12431229 "Alternate form (#) not allowed with integer"
1244- " format specifier 'c'" );
1230+ " presentation type 'c'" );
1231+ goto done ;
1232+ }
1233+ /* error to request precision */
1234+ if (format -> precision != -1 ) {
1235+ PyErr_SetString (PyExc_ValueError ,
1236+ "Precision (.) not allowed with integer"
1237+ " presentation type 'c'" );
1238+ goto done ;
1239+ }
1240+ /* error to request two's complement */
1241+ if (format -> no_neg_0 ) {
1242+ PyErr_SetString (PyExc_ValueError ,
1243+ "Two's complement (z) not allowed with integer"
1244+ " presentation type 'c'" );
12451245 goto done ;
12461246 }
12471247
@@ -1269,35 +1269,80 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
12691269 }
12701270 else {
12711271 int base ;
1272- int leading_chars_to_skip = 0 ; /* Number of characters added by
1273- PyNumber_ToBase that we want to
1274- skip over. */
1272+ int log2_base ;
1273+ int leading_chars_to_skip ; /* Number of characters added by
1274+ PyNumber_ToBase that we want to
1275+ skip over. */
1276+
1277+ if (format -> precision == -1 ) {
1278+ /* precision not requested */
1279+
1280+ if (format -> no_neg_0 ) {
1281+ /* two's complement format only allowed with precision */
1282+ PyErr_SetString (PyExc_ValueError ,
1283+ "Two's complement (z) requires precision (.)"
1284+ " format specifier" );
1285+ goto done ;
1286+ }
1287+ } else {
1288+ /* precision requested */
1289+
1290+ if (format -> no_neg_0 && !(format -> type == 'b' || format -> type == 'o'
1291+ || format -> type == 'x' || format -> type == 'X' ))
1292+ {
1293+ /* two's complement format only allowed for bases that
1294+ are powers of two */
1295+
1296+ /* It is easier to specify which bases are allowed than
1297+ to single out 'c', 'd', 'n', and '' as forbidden,
1298+ because with '' (which is implemented the same as 'n')
1299+ the error message would have to take into account
1300+ whether the user literally specified 'n' or '' */
1301+ PyErr_SetString (PyExc_ValueError ,
1302+ "Two's complement (z) only allowed"
1303+ " with integer presentation types"
1304+ " 'b', 'o', 'x', and 'X'" );
1305+ goto done ;
1306+ }
1307+
1308+ /* finally check the precision length is sane */
1309+ if (format -> precision > INT_MAX ) {
1310+ PyErr_SetString (PyExc_ValueError , "precision too big" );
1311+ goto done ;
1312+ }
1313+ }
12751314
12761315 /* Compute the base and how many characters will be added by
12771316 PyNumber_ToBase */
12781317 switch (format -> type ) {
12791318 case 'b' :
12801319 base = 2 ;
1320+ log2_base = 1 ;
12811321 leading_chars_to_skip = 2 ; /* 0b */
12821322 break ;
12831323 case 'o' :
12841324 base = 8 ;
1325+ log2_base = 3 ;
12851326 leading_chars_to_skip = 2 ; /* 0o */
12861327 break ;
12871328 case 'x' :
12881329 case 'X' :
12891330 base = 16 ;
1331+ log2_base = 4 ;
12901332 leading_chars_to_skip = 2 ; /* 0x */
12911333 break ;
12921334 default : /* shouldn't be needed, but stops a compiler warning */
12931335 case 'd' :
12941336 case 'n' :
12951337 base = 10 ;
1338+ log2_base = -1 ; /* unused */
1339+ leading_chars_to_skip = 0 ;
12961340 break ;
12971341 }
12981342
12991343 if (format -> sign != '+' && format -> sign != ' '
13001344 && format -> width == -1
1345+ && format -> precision == -1
13011346 && format -> type != 'X' && format -> type != 'n'
13021347 && !format -> thousands_separators
13031348 && PyLong_CheckExact (value ))
@@ -1311,8 +1356,40 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
13111356 if (format -> alternate )
13121357 n_prefix = leading_chars_to_skip ;
13131358
1314- /* Do the hard part, converting to a string in a given base */
1315- tmp = _PyLong_Format (value , base );
1359+ if (format -> no_neg_0 ) {
1360+ /* perform the reduction of value modulo (base ** precision) */
1361+ int64_t shift_by ;
1362+ PyObject * one ;
1363+ PyObject * modulus ;
1364+ PyObject * reduced_value ;
1365+
1366+ shift_by = log2_base * format -> precision ;
1367+
1368+ one = PyLong_FromLong (1 );
1369+ if (one == NULL ) {
1370+ goto done ;
1371+ }
1372+
1373+ modulus = _PyLong_Lshift (one , shift_by );
1374+ Py_DECREF (one );
1375+ if (modulus == NULL ) {
1376+ goto done ;
1377+ }
1378+
1379+ reduced_value = PyNumber_Remainder (value , modulus );
1380+ Py_DECREF (modulus );
1381+ if (reduced_value == NULL ) {
1382+ goto done ;
1383+ }
1384+
1385+ /* Do the hard part, converting to a string in a given base */
1386+ tmp = _PyLong_Format (reduced_value , base );
1387+ Py_DECREF (reduced_value );
1388+ } else {
1389+ /* Do the hard part, converting to a string in a given base */
1390+ tmp = _PyLong_Format (value , base );
1391+ }
1392+
13161393 if (tmp == NULL )
13171394 goto done ;
13181395
@@ -1332,6 +1409,41 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
13321409 /* Skip over the leading chars (0x, 0b, etc.) */
13331410 n_digits -= leading_chars_to_skip ;
13341411 inumeric_chars += leading_chars_to_skip ;
1412+
1413+ if (format -> precision != -1 && n_digits < format -> precision ) {
1414+ /* prepend leading zeros (after sign and prefix if they exist) */
1415+ PyObject * tmp2 ;
1416+
1417+ Py_ssize_t zeros_needed = format -> precision - n_digits ;
1418+ Py_ssize_t tmp2_len = leading_chars_to_skip + format -> precision ;
1419+
1420+ tmp2 = PyUnicode_New (tmp2_len , 127 );
1421+ if (tmp2 == NULL )
1422+ goto done ;
1423+
1424+ if (PyUnicode_CopyCharacters (tmp2 , 0 , tmp , 0 ,
1425+ leading_chars_to_skip ) < 0 )
1426+ {
1427+ Py_DECREF (tmp2 );
1428+ goto done ;
1429+ }
1430+ if (PyUnicode_Fill (tmp2 , leading_chars_to_skip ,
1431+ zeros_needed , '0' ) < 0 )
1432+ {
1433+ Py_DECREF (tmp2 );
1434+ goto done ;
1435+ }
1436+ if (PyUnicode_CopyCharacters (tmp2 ,
1437+ leading_chars_to_skip + zeros_needed ,
1438+ tmp , leading_chars_to_skip , n_digits
1439+ ) < 0 )
1440+ {
1441+ Py_DECREF (tmp2 );
1442+ goto done ;
1443+ }
1444+ Py_SETREF (tmp , tmp2 );
1445+ n_digits = format -> precision ;
1446+ }
13351447 }
13361448
13371449 /* Determine the grouping, separator, and decimal point, if any. */
0 commit comments