[CRT]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sun, 7 Nov 2010 10:06:00 +0000 (10:06 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sun, 7 Nov 2010 10:06:00 +0000 (10:06 +0000)
In streamout(): fix a number of formatting bugs, round floats, fix issue with large unsigned values that were treated as signed, simplify some code.

svn path=/trunk/; revision=49516

reactos/lib/sdk/crt/printf/streamout.c

index 9ea3742..53bfeba 100644 (file)
@@ -145,7 +145,7 @@ format_float(
     }
 
     /* CHECKME: Windows seems to handle a max of 17 digits(?) */
-    num_digits = precision <= 17 ? precision : 17;
+    num_digits = precision <= 17 ? precision: 17;
 
     /* Handle sign */
     if (fpval < 0)
@@ -173,20 +173,19 @@ format_float(
     }
     else
     {
-        val64 = (__int64)fpval;
-        fpval -= val64;
         fpval *= pow(10., precision);
+        val64 = (__int64)(fpval + 0.5);
         
-        while (num_digits--)
+        while (num_digits-- > 0)
         {
-            *--(*string) = digits[(__int64)fpval % 10];
-            fpval /= 10;
+            *--(*string) = digits[val64 % 10];
+            val64 /= 10;
         }
     }
 
     *--(*string) = _T('.');
 
-    /* Gather digits in reverse order */
+    /* Digits before the decimal point */
     do
     {
         *--(*string) = digits[val64 % base];
@@ -286,7 +285,7 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
     int base, len, prefixlen, fieldwidth, precision, padding;
     int written = 1, written_all = 0;
     unsigned int flags;
-    __int64 val64;
+    unsigned __int64 val64;
 
     buffer[BUFFER_SIZE] = '\0';
 
@@ -297,8 +296,9 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
         /* Check for end of format string */
         if (chr == _T('\0')) break;
 
-        /* Check for 'normal' character */
-        if (chr != _T('%'))
+        /* Check for 'normal' character or double % */
+        if ((chr != _T('%')) || 
+            (chr = *format++) == _T('%'))
         {
             /* Write the character to the stream */
             if ((written = streamout_char(stream, chr)) == -1) return -1;
@@ -306,26 +306,17 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
             continue;
         }
 
-        /* Check for escaped % character */
-        if (*format == _T('%'))
-        {
-            /* Write % to the stream */
-            if ((written = streamout_char(stream, _T('%'))) == -1) return -1;
-            written_all += written;
-            continue;
-        }
-
         /* Handle flags */
         flags = 0;
         while (1)
         {
-            chr = *format++;
                  if (chr == _T('-')) flags |= FLAG_ALIGN_LEFT;
             else if (chr == _T('+')) flags |= FLAG_FORCE_SIGN;
             else if (chr == _T(' ')) flags |= FLAG_FORCE_SIGNSP;
             else if (chr == _T('0')) flags |= FLAG_PAD_ZERO;
             else if (chr == _T('#')) flags |= FLAG_SPECIAL;
             else break;
+            chr = *format++;
         }
 
         /* Handle field width modifier */
@@ -505,13 +496,14 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
                 /* Use external function, one for kernel one for user mode */
                 format_float(chr, flags, precision, &string, &prefix, &argptr);
                 len = _tcslen(string);
+                precision = 0;
                 break;
 
             case _T('d'):
             case _T('i'):
-                val64 = va_arg_f(argptr, flags);
+                val64 = (__int64)va_arg_f(argptr, flags);
 
-                if (val64 < 0)
+                if ((__int64)val64 < 0)
                 {
                     val64 = -val64;
                     prefix = _T("-");
@@ -526,12 +518,9 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
             case _T('o'):
                 base = 8;
                 if (flags & FLAG_SPECIAL) prefix = _T("0");
+                goto case_unsigned;
                 /* Fall through */
 
-            case _T('u'):
-                val64 = (unsigned __int64)va_arg_fu(argptr, flags);
-                goto case_number;
-
             case _T('p'):
                 precision = 2 * sizeof(void*);
                 flags &= ~FLAG_PAD_ZERO;
@@ -543,27 +532,31 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
                 /* Fall through */
 
             case _T('x'):
-                val64 = (unsigned __int64)va_arg_fu(argptr, flags);
                 base = 16;
                 if (flags & FLAG_SPECIAL)
                 {
                     prefix = &digits[16];
                 }
 
+            case _T('u'):
+            case_unsigned:
+                val64 = va_arg_fu(argptr, flags);
+
             case_number:
 #ifdef _UNICODE
                 flags |= FLAG_WIDECHAR;
 #else
                 flags &= ~FLAG_WIDECHAR;
 #endif
+                if (precision < 0) precision = 1;
+
                 /* Gather digits in reverse order */
-                do
+                while (val64)
                 {
                     *--string = digits[val64 % base];
                     val64 /= base;
                     precision--;
                 }
-                while (val64);
 
                 len = _tcslen(string);
                 break;
@@ -578,11 +571,12 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
         prefixlen = prefix ? _tcslen(prefix) : 0;
         if (precision < 0) precision = 0;
         padding = fieldwidth - len - prefixlen - precision;
+        if (padding < 0) padding = 0;
 
         /* Optional left space padding */
         if ((flags & (FLAG_ALIGN_LEFT | FLAG_PAD_ZERO)) == 0)
         {
-            while (padding-- > 0)
+            for (; padding > 0; padding--)
             {
                 if ((written = streamout_char(stream, _T(' '))) == -1) return -2;
                 written_all += written;