msvcrt: portable printf integer conversions

Jesse Allen the3dfxdude at gmail.com
Tue Feb 14 00:02:08 CST 2006


I've been trying to get some functionality to the %I64 printf size specifier.  
My last patch was rejected because it was non-portible.  Therefore, I've 
written an internal function, pf_integer_conv, to handle the conversion of 
integers only -- not floats.  The patch tries to not impact the current printf 
infrastructure as much as possible, therefore it only forwards %I64 sizes.  
However, it could be possible to foward all integer types as I wrote it to 
handle them all, and this is probably the way to go.

There are a couple of problems I have discovered in our printf.  One is that
if flags->Precision is zero, then it is unused.  But according to man 3 printf,
precision can be explicitly defined as zero.  Therefore, we do not handle
"zero" precision.  The next problem is when we rebuild our format string 
to handle the integer and floats, and call printf from libc to handle it.  It
happens to print to a fixed buffer of 40 without checking.  If we ever get 
called to print a number with a field length greater than 40 or whatever large
combination, libc will happily print beyond the end of the buffer.  These
are problems in the current infrastructure and will need to be addressed.

Any comments?  I'd like to have a better idea on restructuring the printf to 
handle number conversions before we move forward.  I still need to work on
floating point too, as of yet.


Jesse
-------------- next part --------------
--- dlls/msvcrt/wcs.c-original	2005-09-24 19:23:47.000000000 -0700
+++ dlls/msvcrt/wcs.c	2005-09-25 16:31:51.000000000 -0700
@@ -388,6 +388,85 @@
     *p++ = 0;
 }
 
+static void pf_integer_conv( char *buf, pf_flags *flags, LONGLONG x )
+{
+    char *digits;
+
+    int i, j, k;
+    char tmp[40];
+    char sign;
+
+    unsigned int base;
+
+    base = 10;
+    if( flags->Format == 'o' )
+        base = 8;
+    else if( flags->Format == 'x' || flags->Format == 'X' )
+        base = 16;
+
+    if( flags->Format == 'X' )
+        digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    else
+        digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+    sign = 0;
+    if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
+    {
+        x = -x;
+        sign = '-';
+    }
+    else if( flags->Sign )
+        sign = flags->Sign;
+
+    i = 0;
+    if( x == 0 && flags->Precision )
+        tmp[i++] = '0';
+    else
+        while( x != 0 )
+        {
+            j = (ULONGLONG) x % base;
+            x = (ULONGLONG) x / base;
+            tmp[i++] = digits[j];
+        }
+    k = flags->Precision - i;
+    while( k-- > 0 )
+        tmp[i++] = '0';
+    if( flags->Alternate )
+    {
+        if( base == 16 )
+        {
+            tmp[i++] = digits[33];
+            tmp[i++] = '0';
+        }
+        if( base == 8 && tmp[i-1] != '0' )
+            tmp[i++] = '0';
+    }
+    if( sign )
+        tmp[i++] = sign;
+    if( !flags->LeftAlign )
+    {
+        k = flags->FieldLength - i;
+        while( k-- > 0 )
+            if( flags->PadZero && !flags->LeftAlign && !flags->Precision )
+                tmp[i++] = '0';
+            else
+                tmp[i++] = ' ';
+    }
+
+    j = 0;
+    while( i-- > 0 )
+        buf[j++] = tmp[i];
+    if( flags->LeftAlign && flags->FieldLength )
+    {
+        k = flags->FieldLength - j;
+        while( k-- > 0 )
+            buf[j++] = ' ';
+    }
+    buf[j] = '\0';
+
+    return;
+}
+
 /*********************************************************************
  *  pf_vsnprintf  (INTERNAL)
  *
@@ -493,6 +572,24 @@
                     flags.IntegerLength = *p;
                 p++;
             }
+            else if ( *p == 'I' )
+            {
+                if( *(p+1) == '6' && *(p+2) == '4' )
+                {
+                    flags.IntegerDouble++;
+                    p += 3;
+                }
+                else if( *(p+1) == '3' && *(p+2) == '2' )
+                {
+                    FIXME("%%I32 unhandled\n");
+                    p += 3;
+                }
+                else
+                {
+                    FIXME("%%I unhandled\n");
+                    p++;
+                }
+            }
             else if( *p == 'w' )
                 flags.WideString = *p++;
             else if( *p == 'F' )
@@ -580,7 +677,9 @@
 
             pf_rebuild_format_string( fmt, &flags );
 
-            if( pf_is_double_format( flags.Format ) )
+            if( flags.IntegerDouble )
+                pf_integer_conv( number, &flags, va_arg(valist, LONGLONG) );
+            else if( pf_is_double_format( flags.Format ) )
                 sprintf( number, fmt, va_arg(valist, double) );
             else
                 sprintf( number, fmt, va_arg(valist, int) );


More information about the wine-devel mailing list