@@ -89,6 +89,7 @@ is_sign_element(STRINGLIB_CHAR c)
8989typedef struct {
9090 STRINGLIB_CHAR fill_char ;
9191 STRINGLIB_CHAR align ;
92+ int alternate ;
9293 STRINGLIB_CHAR sign ;
9394 Py_ssize_t width ;
9495 Py_ssize_t precision ;
@@ -117,6 +118,7 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
117118
118119 format -> fill_char = '\0' ;
119120 format -> align = '\0' ;
121+ format -> alternate = 0 ;
120122 format -> sign = '\0' ;
121123 format -> width = -1 ;
122124 format -> precision = -1 ;
@@ -154,6 +156,13 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
154156 ++ ptr ;
155157 }
156158
159+ /* If the next character is #, we're in alternate mode. This only
160+ applies to integers. */
161+ if (end - ptr >= 1 && ptr [0 ] == '#' ) {
162+ format -> alternate = 1 ;
163+ ++ ptr ;
164+ }
165+
157166 /* XXX add error checking */
158167 specified_width = get_integer (& ptr , end , & format -> width );
159168
@@ -221,7 +230,8 @@ typedef struct {
221230 and more efficient enough to justify a little obfuscation? */
222231static void
223232calc_number_widths (NumberFieldWidths * r , STRINGLIB_CHAR actual_sign ,
224- Py_ssize_t n_digits , const InternalFormatSpec * format )
233+ Py_ssize_t n_prefix , Py_ssize_t n_digits ,
234+ const InternalFormatSpec * format )
225235{
226236 r -> n_lpadding = 0 ;
227237 r -> n_spadding = 0 ;
@@ -232,13 +242,15 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
232242 r -> n_rsign = 0 ;
233243
234244 /* the output will look like:
235- | |
236- | <lpadding> <lsign> <spadding> <digits> <rsign> <rpadding> |
237- | |
245+ | |
246+ | <lpadding> <lsign> <prefix> < spadding> <digits> <rsign> <rpadding> |
247+ | |
238248
239249 lsign and rsign are computed from format->sign and the actual
240250 sign of the number
241251
252+ prefix is given (it's for the '0x' prefix)
253+
242254 digits is already known
243255
244256 the total width is either given, or computed from the
@@ -363,6 +375,14 @@ format_string_internal(PyObject *value, const InternalFormatSpec *format)
363375 goto done ;
364376 }
365377
378+ /* alternate is not allowed on strings */
379+ if (format -> alternate ) {
380+ PyErr_SetString (PyExc_ValueError ,
381+ "Alternate form (#) not allowed in string format "
382+ "specifier" );
383+ goto done ;
384+ }
385+
366386 /* '=' alignment not allowed on strings */
367387 if (format -> align == '=' ) {
368388 PyErr_SetString (PyExc_ValueError ,
@@ -505,31 +525,33 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
505525 }
506526 else {
507527 int base ;
508- int leading_chars_to_skip ; /* Number of characters added by
509- PyNumber_ToBase that we want to
510- skip over. */
528+ int leading_chars_to_skip = 0 ; /* Number of characters added by
529+ PyNumber_ToBase that we want to
530+ skip over. */
511531
512532 /* Compute the base and how many characters will be added by
513533 PyNumber_ToBase */
514534 switch (format -> type ) {
515535 case 'b' :
516536 base = 2 ;
517- leading_chars_to_skip = 2 ; /* 0b */
537+ if (!format -> alternate )
538+ leading_chars_to_skip = 2 ; /* 0b */
518539 break ;
519540 case 'o' :
520541 base = 8 ;
521- leading_chars_to_skip = 2 ; /* 0o */
542+ if (!format -> alternate )
543+ leading_chars_to_skip = 2 ; /* 0o */
522544 break ;
523545 case 'x' :
524546 case 'X' :
525547 base = 16 ;
526- leading_chars_to_skip = 2 ; /* 0x */
548+ if (!format -> alternate )
549+ leading_chars_to_skip = 2 ; /* 0x */
527550 break ;
528551 default : /* shouldn't be needed, but stops a compiler warning */
529552 case 'd' :
530553 case 'n' :
531554 base = 10 ;
532- leading_chars_to_skip = 0 ;
533555 break ;
534556 }
535557
@@ -564,7 +586,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
564586 0 , & n_grouping_chars , 0 );
565587
566588 /* Calculate the widths of the various leading and trailing parts */
567- calc_number_widths (& spec , sign , n_digits + n_grouping_chars , format );
589+ calc_number_widths (& spec , sign , 0 , n_digits + n_grouping_chars , format );
568590
569591 /* Allocate a new string to hold the result */
570592 result = STRINGLIB_NEW (NULL , spec .n_total );
@@ -670,6 +692,14 @@ format_float_internal(PyObject *value,
670692 Py_UNICODE unicodebuf [FLOAT_FORMATBUFLEN ];
671693#endif
672694
695+ /* alternate is not allowed on floats. */
696+ if (format -> alternate ) {
697+ PyErr_SetString (PyExc_ValueError ,
698+ "Alternate form (#) not allowed in float format "
699+ "specifier" );
700+ goto done ;
701+ }
702+
673703 /* first, do the conversion as 8-bit chars, using the platform's
674704 snprintf. then, if needed, convert to unicode. */
675705
@@ -730,7 +760,7 @@ format_float_internal(PyObject *value,
730760 -- n_digits ;
731761 }
732762
733- calc_number_widths (& spec , sign , n_digits , format );
763+ calc_number_widths (& spec , sign , 0 , n_digits , format );
734764
735765 /* allocate a string with enough space */
736766 result = STRINGLIB_NEW (NULL , spec .n_total );
0 commit comments