about summary refs log tree commit diff
path: root/stdio-common/vfprintf-process-arg.c
diff options
context:
space:
mode:
authorCarlos O'Donell <carlos@redhat.com>2023-01-19 12:50:20 +0100
committerCarlos O'Donell <carlos@redhat.com>2023-02-06 10:20:39 -0500
commitc980549cc6a1c03c23cc2fe3e7b0fe626a0364b0 (patch)
treec6948d04b7c49bb4fe6d5d576764f3bc9f9874fb /stdio-common/vfprintf-process-arg.c
parenta1dcc64c9b6e54ce1aabcd10785f43bf2b445ee4 (diff)
downloadglibc-c980549cc6a1c03c23cc2fe3e7b0fe626a0364b0.tar.gz
glibc-c980549cc6a1c03c23cc2fe3e7b0fe626a0364b0.tar.xz
glibc-c980549cc6a1c03c23cc2fe3e7b0fe626a0364b0.zip
Account for grouping in printf width (bug 30068)
This is a partial fix for mishandling of grouping when formatting
integers.  It properly computes the width in the presence of grouping
characters when the width is larger than the number of significant
digits. The precision related issue is documented in bug 23432.

Co-authored-by: Andreas Schwab <schwab@suse.de>
Diffstat (limited to 'stdio-common/vfprintf-process-arg.c')
-rw-r--r--stdio-common/vfprintf-process-arg.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/stdio-common/vfprintf-process-arg.c b/stdio-common/vfprintf-process-arg.c
index 24c9125f9f..8c0fcbcf78 100644
--- a/stdio-common/vfprintf-process-arg.c
+++ b/stdio-common/vfprintf-process-arg.c
@@ -186,11 +186,17 @@ LABEL (unsigned_number):      /* Unsigned number of base BASE.  */
   bool octal_marker = (prec <= number_length && number.word != 0
                        && alt && base == 8);
 
-  prec = MAX (0, prec - (workend - string));
+  /* At this point prec_inc is the additional bytes required for the
+     specificed precision.  It is 0 if the precision would not have
+     required additional bytes i.e. the number of input digits is more
+     than the precision.  It is greater than zero if the precision is
+     more than the number of digits without grouping (precision only
+     considers digits).  */
+  unsigned int prec_inc = MAX (0, prec - (workend - string));
 
   if (!left)
     {
-      width -= number_length + prec;
+      width -= number_length + prec_inc;
 
       if (number.word != 0 && alt && (base == 16 || base == 2))
         /* Account for 0X, 0x, 0B or 0b hex or binary marker.  */
@@ -221,7 +227,7 @@ LABEL (unsigned_number):      /* Unsigned number of base BASE.  */
           Xprintf_buffer_putc (buf, spec);
         }
 
-      width += prec;
+      width += prec_inc;
       Xprintf_buffer_pad (buf, L_('0'), width);
 
       if (octal_marker)
@@ -237,6 +243,8 @@ LABEL (unsigned_number):      /* Unsigned number of base BASE.  */
     }
   else
     {
+      /* Perform left justification adjustments.  */
+
       if (is_negative)
         {
           Xprintf_buffer_putc (buf, L_('-'));
@@ -263,9 +271,13 @@ LABEL (unsigned_number):      /* Unsigned number of base BASE.  */
       if (octal_marker)
 	--width;
 
-      width -= workend - string + prec;
+      /* Adjust the width by subtracting the number of bytes
+         required to represent the number with grouping characters
+	 (NUMBER_LENGTH) and any additional bytes required for
+	 precision.  */
+      width -= number_length + prec_inc;
 
-      Xprintf_buffer_pad (buf, L_('0'), prec);
+      Xprintf_buffer_pad (buf, L_('0'), prec_inc);
 
       if (octal_marker)
         Xprintf_buffer_putc (buf, L_('0'));