@@ -979,34 +979,34 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
979979 from a hard-code pseudo-locale */
980980 LocaleInfo locale = LocaleInfo_STATIC_INIT ;
981981
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- /* no negative zero coercion on integers */
989- if (format -> no_neg_0 ) {
990- PyErr_SetString (PyExc_ValueError ,
991- "Negative zero coercion (z) not allowed in integer"
992- " format specifier" );
993- goto done ;
994- }
995-
996982 /* special case for character formatting */
997983 if (format -> type == 'c' ) {
998984 /* error to specify a sign */
999985 if (format -> sign != '\0' ) {
1000986 PyErr_SetString (PyExc_ValueError ,
1001987 "Sign not allowed with integer"
1002- " format specifier 'c'" );
988+ " presentation type 'c'" );
1003989 goto done ;
1004990 }
1005991 /* error to request alternate format */
1006992 if (format -> alternate ) {
1007993 PyErr_SetString (PyExc_ValueError ,
1008994 "Alternate form (#) not allowed with integer"
1009- " format specifier 'c'" );
995+ " presentation type 'c'" );
996+ goto done ;
997+ }
998+ /* error to request precision */
999+ if (format -> precision != -1 ) {
1000+ PyErr_SetString (PyExc_ValueError ,
1001+ "Precision (.) not allowed with integer"
1002+ " presentation type 'c'" );
1003+ goto done ;
1004+ }
1005+ /* error to request two's complement */
1006+ if (format -> no_neg_0 ) {
1007+ PyErr_SetString (PyExc_ValueError ,
1008+ "Two's complement (z) not allowed with integer"
1009+ " presentation type 'c'" );
10101010 goto done ;
10111011 }
10121012
@@ -1034,35 +1034,80 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
10341034 }
10351035 else {
10361036 int base ;
1037- int leading_chars_to_skip = 0 ; /* Number of characters added by
1038- PyNumber_ToBase that we want to
1039- skip over. */
1037+ int log2_base ;
1038+ int leading_chars_to_skip ; /* Number of characters added by
1039+ PyNumber_ToBase that we want to
1040+ skip over. */
1041+
1042+ if (format -> precision == -1 ) {
1043+ /* precision not requested */
1044+
1045+ if (format -> no_neg_0 ) {
1046+ /* two's complement format only allowed with precision */
1047+ PyErr_SetString (PyExc_ValueError ,
1048+ "Two's complement (z) requires precision (.)"
1049+ " format specifier" );
1050+ goto done ;
1051+ }
1052+ } else {
1053+ /* precision requested */
1054+
1055+ if (format -> no_neg_0 && !(format -> type == 'b' || format -> type == 'o'
1056+ || format -> type == 'x' || format -> type == 'X' ))
1057+ {
1058+ /* two's complement format only allowed for bases that
1059+ are powers of two */
1060+
1061+ /* It is easier to specify which bases are allowed than
1062+ to single out 'c', 'd', 'n', and '' as forbidden,
1063+ because with '' (which is implemented the same as 'n')
1064+ the error message would have to take into account
1065+ whether the user literally specified 'n' or '' */
1066+ PyErr_SetString (PyExc_ValueError ,
1067+ "Two's complement (z) only allowed"
1068+ " with integer presentation types"
1069+ " 'b', 'o', 'x', and 'X'" );
1070+ goto done ;
1071+ }
1072+
1073+ /* finally check the precision length is sane */
1074+ if (format -> precision > INT_MAX ) {
1075+ PyErr_SetString (PyExc_ValueError , "precision too big" );
1076+ goto done ;
1077+ }
1078+ }
10401079
10411080 /* Compute the base and how many characters will be added by
10421081 PyNumber_ToBase */
10431082 switch (format -> type ) {
10441083 case 'b' :
10451084 base = 2 ;
1085+ log2_base = 1 ;
10461086 leading_chars_to_skip = 2 ; /* 0b */
10471087 break ;
10481088 case 'o' :
10491089 base = 8 ;
1090+ log2_base = 3 ;
10501091 leading_chars_to_skip = 2 ; /* 0o */
10511092 break ;
10521093 case 'x' :
10531094 case 'X' :
10541095 base = 16 ;
1096+ log2_base = 4 ;
10551097 leading_chars_to_skip = 2 ; /* 0x */
10561098 break ;
10571099 default : /* shouldn't be needed, but stops a compiler warning */
10581100 case 'd' :
10591101 case 'n' :
10601102 base = 10 ;
1103+ log2_base = -1 ; /* unused */
1104+ leading_chars_to_skip = 0 ;
10611105 break ;
10621106 }
10631107
10641108 if (format -> sign != '+' && format -> sign != ' '
10651109 && format -> width == -1
1110+ && format -> precision == -1
10661111 && format -> type != 'X' && format -> type != 'n'
10671112 && !format -> thousands_separators
10681113 && PyLong_CheckExact (value ))
@@ -1076,8 +1121,40 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
10761121 if (format -> alternate )
10771122 n_prefix = leading_chars_to_skip ;
10781123
1079- /* Do the hard part, converting to a string in a given base */
1080- tmp = _PyLong_Format (value , base );
1124+ if (format -> no_neg_0 ) {
1125+ /* perform the reduction of value modulo (base ** precision) */
1126+ int64_t shift_by ;
1127+ PyObject * one ;
1128+ PyObject * modulus ;
1129+ PyObject * reduced_value ;
1130+
1131+ shift_by = log2_base * format -> precision ;
1132+
1133+ one = PyLong_FromLong (1 );
1134+ if (one == NULL ) {
1135+ goto done ;
1136+ }
1137+
1138+ modulus = _PyLong_Lshift (one , shift_by );
1139+ Py_DECREF (one );
1140+ if (modulus == NULL ) {
1141+ goto done ;
1142+ }
1143+
1144+ reduced_value = PyNumber_Remainder (value , modulus );
1145+ Py_DECREF (modulus );
1146+ if (reduced_value == NULL ) {
1147+ goto done ;
1148+ }
1149+
1150+ /* Do the hard part, converting to a string in a given base */
1151+ tmp = _PyLong_Format (reduced_value , base );
1152+ Py_DECREF (reduced_value );
1153+ } else {
1154+ /* Do the hard part, converting to a string in a given base */
1155+ tmp = _PyLong_Format (value , base );
1156+ }
1157+
10811158 if (tmp == NULL )
10821159 goto done ;
10831160
@@ -1097,6 +1174,41 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
10971174 /* Skip over the leading chars (0x, 0b, etc.) */
10981175 n_digits -= leading_chars_to_skip ;
10991176 inumeric_chars += leading_chars_to_skip ;
1177+
1178+ if (format -> precision != -1 && n_digits < format -> precision ) {
1179+ /* prepend leading zeros (after sign and prefix if they exist) */
1180+ PyObject * tmp2 ;
1181+
1182+ Py_ssize_t zeros_needed = format -> precision - n_digits ;
1183+ Py_ssize_t tmp2_len = leading_chars_to_skip + format -> precision ;
1184+
1185+ tmp2 = PyUnicode_New (tmp2_len , 127 );
1186+ if (tmp2 == NULL )
1187+ goto done ;
1188+
1189+ if (PyUnicode_CopyCharacters (tmp2 , 0 , tmp , 0 ,
1190+ leading_chars_to_skip ) < 0 )
1191+ {
1192+ Py_DECREF (tmp2 );
1193+ goto done ;
1194+ }
1195+ if (PyUnicode_Fill (tmp2 , leading_chars_to_skip ,
1196+ zeros_needed , '0' ) < 0 )
1197+ {
1198+ Py_DECREF (tmp2 );
1199+ goto done ;
1200+ }
1201+ if (PyUnicode_CopyCharacters (tmp2 ,
1202+ leading_chars_to_skip + zeros_needed ,
1203+ tmp , leading_chars_to_skip , n_digits
1204+ ) < 0 )
1205+ {
1206+ Py_DECREF (tmp2 );
1207+ goto done ;
1208+ }
1209+ Py_SETREF (tmp , tmp2 );
1210+ n_digits = format -> precision ;
1211+ }
11001212 }
11011213
11021214 /* Determine the grouping, separator, and decimal point, if any. */
0 commit comments