@@ -147,6 +147,13 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
147147#endif
148148 }
149149
150+ /* If the next character is #, we're in alternate mode. This only
151+ applies to integers. */
152+ if (end - ptr >= 1 && ptr [0 ] == '#' ) {
153+ format -> alternate = 1 ;
154+ ++ ptr ;
155+ }
156+
150157 /* The special case for 0-padding (backwards compat) */
151158 if (format -> fill_char == '\0' && end - ptr >= 1 && ptr [0 ] == '0' ) {
152159 format -> fill_char = '0' ;
@@ -156,13 +163,6 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
156163 ++ ptr ;
157164 }
158165
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-
166166 /* XXX add error checking */
167167 specified_width = get_integer (& ptr , end , & format -> width );
168168
@@ -211,9 +211,10 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
211211/************************************************************************/
212212
213213/* describes the layout for an integer, see the comment in
214- _calc_integer_widths () for details */
214+ calc_number_widths () for details */
215215typedef struct {
216216 Py_ssize_t n_lpadding ;
217+ Py_ssize_t n_prefix ;
217218 Py_ssize_t n_spadding ;
218219 Py_ssize_t n_rpadding ;
219220 char lsign ;
@@ -234,6 +235,7 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
234235 const InternalFormatSpec * format )
235236{
236237 r -> n_lpadding = 0 ;
238+ r -> n_prefix = 0 ;
237239 r -> n_spadding = 0 ;
238240 r -> n_rpadding = 0 ;
239241 r -> lsign = '\0' ;
@@ -288,21 +290,25 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
288290 }
289291 }
290292
293+ r -> n_prefix = n_prefix ;
294+
291295 /* now the number of padding characters */
292296 if (format -> width == -1 ) {
293297 /* no padding at all, nothing to do */
294298 }
295299 else {
296300 /* see if any padding is needed */
297- if (r -> n_lsign + n_digits + r -> n_rsign >= format -> width ) {
301+ if (r -> n_lsign + n_digits + r -> n_rsign +
302+ r -> n_prefix >= format -> width ) {
298303 /* no padding needed, we're already bigger than the
299304 requested width */
300305 }
301306 else {
302307 /* determine which of left, space, or right padding is
303308 needed */
304309 Py_ssize_t padding = format -> width -
305- (r -> n_lsign + n_digits + r -> n_rsign );
310+ (r -> n_lsign + r -> n_prefix +
311+ n_digits + r -> n_rsign );
306312 if (format -> align == '<' )
307313 r -> n_rpadding = padding ;
308314 else if (format -> align == '>' )
@@ -317,18 +323,19 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
317323 r -> n_lpadding = padding ;
318324 }
319325 }
320- r -> n_total = r -> n_lpadding + r -> n_lsign + r -> n_spadding +
321- n_digits + r -> n_rsign + r -> n_rpadding ;
326+ r -> n_total = r -> n_lpadding + r -> n_lsign + r -> n_prefix +
327+ r -> n_spadding + n_digits + r -> n_rsign + r -> n_rpadding ;
322328}
323329
324330/* fill in the non-digit parts of a numbers's string representation,
325- as determined in _calc_integer_widths (). returns the pointer to
331+ as determined in calc_number_widths (). returns the pointer to
326332 where the digits go. */
327333static STRINGLIB_CHAR *
328334fill_non_digits (STRINGLIB_CHAR * p_buf , const NumberFieldWidths * spec ,
329- Py_ssize_t n_digits , STRINGLIB_CHAR fill_char )
335+ STRINGLIB_CHAR * prefix , Py_ssize_t n_digits ,
336+ STRINGLIB_CHAR fill_char )
330337{
331- STRINGLIB_CHAR * p_digits ;
338+ STRINGLIB_CHAR * p_digits ;
332339
333340 if (spec -> n_lpadding ) {
334341 STRINGLIB_FILL (p_buf , fill_char , spec -> n_lpadding );
@@ -337,6 +344,12 @@ fill_non_digits(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec,
337344 if (spec -> n_lsign == 1 ) {
338345 * p_buf ++ = spec -> lsign ;
339346 }
347+ if (spec -> n_prefix ) {
348+ memmove (p_buf ,
349+ prefix ,
350+ spec -> n_prefix * sizeof (STRINGLIB_CHAR ));
351+ p_buf += spec -> n_prefix ;
352+ }
340353 if (spec -> n_spadding ) {
341354 STRINGLIB_FILL (p_buf , fill_char , spec -> n_spadding );
342355 p_buf += spec -> n_spadding ;
@@ -477,6 +490,8 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
477490 Py_ssize_t n_grouping_chars = 0 ; /* Count of additional chars to
478491 allocate, used for 'n'
479492 formatting. */
493+ Py_ssize_t n_prefix = 0 ; /* Count of prefix chars, (e.g., '0x') */
494+ STRINGLIB_CHAR * prefix = NULL ;
480495 NumberFieldWidths spec ;
481496 long x ;
482497
@@ -534,19 +549,16 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
534549 switch (format -> type ) {
535550 case 'b' :
536551 base = 2 ;
537- if (!format -> alternate )
538- leading_chars_to_skip = 2 ; /* 0b */
552+ leading_chars_to_skip = 2 ; /* 0b */
539553 break ;
540554 case 'o' :
541555 base = 8 ;
542- if (!format -> alternate )
543- leading_chars_to_skip = 2 ; /* 0o */
556+ leading_chars_to_skip = 2 ; /* 0o */
544557 break ;
545558 case 'x' :
546559 case 'X' :
547560 base = 16 ;
548- if (!format -> alternate )
549- leading_chars_to_skip = 2 ; /* 0x */
561+ leading_chars_to_skip = 2 ; /* 0x */
550562 break ;
551563 default : /* shouldn't be needed, but stops a compiler warning */
552564 case 'd' :
@@ -555,6 +567,11 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
555567 break ;
556568 }
557569
570+ /* The number of prefix chars is the same as the leading
571+ chars to skip */
572+ if (format -> alternate )
573+ n_prefix = leading_chars_to_skip ;
574+
558575 /* Do the hard part, converting to a string in a given base */
559576 tmp = tostring (value , base );
560577 if (tmp == NULL )
@@ -563,6 +580,8 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
563580 pnumeric_chars = STRINGLIB_STR (tmp );
564581 n_digits = STRINGLIB_LEN (tmp );
565582
583+ prefix = pnumeric_chars ;
584+
566585 /* Remember not to modify what pnumeric_chars points to. it
567586 might be interned. Only modify it after we copy it into a
568587 newly allocated output buffer. */
@@ -571,6 +590,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
571590 and skip it */
572591 sign = pnumeric_chars [0 ];
573592 if (sign == '-' ) {
593+ ++ prefix ;
574594 ++ leading_chars_to_skip ;
575595 }
576596
@@ -586,43 +606,61 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
586606 0 , & n_grouping_chars , 0 );
587607
588608 /* Calculate the widths of the various leading and trailing parts */
589- calc_number_widths (& spec , sign , 0 , n_digits + n_grouping_chars , format );
609+ calc_number_widths (& spec , sign , n_prefix , n_digits + n_grouping_chars ,
610+ format );
590611
591612 /* Allocate a new string to hold the result */
592613 result = STRINGLIB_NEW (NULL , spec .n_total );
593614 if (!result )
594615 goto done ;
595616 p = STRINGLIB_STR (result );
596617
618+ /* XXX There is too much magic here regarding the internals of
619+ spec and the location of the prefix and digits. It would be
620+ better if calc_number_widths returned a number of logical
621+ offsets into the buffer, and those were used. Maybe in a
622+ future code cleanup. */
623+
597624 /* Fill in the digit parts */
598- n_leading_chars = spec .n_lpadding + spec .n_lsign + spec .n_spadding ;
625+ n_leading_chars = spec .n_lpadding + spec .n_lsign +
626+ spec .n_prefix + spec .n_spadding ;
599627 memmove (p + n_leading_chars ,
600628 pnumeric_chars ,
601629 n_digits * sizeof (STRINGLIB_CHAR ));
602630
603- /* If type is 'X', convert to uppercase */
631+ /* If type is 'X', convert the filled in digits to uppercase */
604632 if (format -> type == 'X' ) {
605633 Py_ssize_t t ;
606634 for (t = 0 ; t < n_digits ; ++ t )
607635 p [t + n_leading_chars ] = STRINGLIB_TOUPPER (p [t + n_leading_chars ]);
608636 }
609637
610- /* Insert the grouping, if any, after the uppercasing of 'X' , so we can
611- ensure that grouping chars won't be affected. */
638+ /* Insert the grouping, if any, after the uppercasing of the digits , so
639+ we can ensure that grouping chars won't be affected. */
612640 if (n_grouping_chars ) {
613641 /* We know this can't fail, since we've already
614642 reserved enough space. */
615643 STRINGLIB_CHAR * pstart = p + n_leading_chars ;
616644 int r = STRINGLIB_GROUPING (pstart , n_digits , n_digits ,
617- spec .n_total + n_grouping_chars - n_leading_chars ,
618- NULL , 0 );
645+ spec .n_total + n_grouping_chars - n_leading_chars ,
646+ NULL , 0 );
619647 assert (r );
620648 }
621649
622650 /* Fill in the non-digit parts (padding, sign, etc.) */
623- fill_non_digits (p , & spec , n_digits + n_grouping_chars ,
651+ fill_non_digits (p , & spec , prefix , n_digits + n_grouping_chars ,
624652 format -> fill_char == '\0' ? ' ' : format -> fill_char );
625653
654+ /* If type is 'X', uppercase the prefix. This has to be done after the
655+ prefix is filled in by fill_non_digits */
656+ if (format -> type == 'X' ) {
657+ Py_ssize_t t ;
658+ for (t = 0 ; t < n_prefix ; ++ t )
659+ p [t + spec .n_lpadding + spec .n_lsign ] =
660+ STRINGLIB_TOUPPER (p [t + spec .n_lpadding + spec .n_lsign ]);
661+ }
662+
663+
626664done :
627665 Py_XDECREF (tmp );
628666 return result ;
@@ -768,7 +806,7 @@ format_float_internal(PyObject *value,
768806 goto done ;
769807
770808 /* Fill in the non-digit parts (padding, sign, etc.) */
771- fill_non_digits (STRINGLIB_STR (result ), & spec , n_digits ,
809+ fill_non_digits (STRINGLIB_STR (result ), & spec , NULL , n_digits ,
772810 format -> fill_char == '\0' ? ' ' : format -> fill_char );
773811
774812 /* fill in the digit parts */
0 commit comments