diff --git a/dlls/ntdll/printf.c b/dlls/ntdll/printf.c index 96c258e91bf..2542c1deb71 100644 --- a/dlls/ntdll/printf.c +++ b/dlls/ntdll/printf.c @@ -55,7 +55,7 @@ typedef struct pf_flags_t { char Sign, LeftAlign, Alternate, PadZero; int FieldLength, Precision; - char IntegerLength, IntegerDouble; + char IntegerLength, IntegerDouble, IntegerNative; char WideString; char Format; } pf_flags; @@ -211,8 +211,15 @@ static inline int pf_output_format_W( pf_output *out, LPCWSTR str, { int r = 0; - if( len < 0 ) - len = wcslen( str ); + if (len < 0) + { + /* Do not search past the length specified by the precision. */ + if (flags->Precision >= 0) + { + for (len = 0; len < flags->Precision; len++) if (!str[len]) break; + } + else len = wcslen( str ); + } if (flags->Precision >= 0 && flags->Precision < len) len = flags->Precision; @@ -233,8 +240,15 @@ static inline int pf_output_format_A( pf_output *out, LPCSTR str, { int r = 0; - if( len < 0 ) - len = strlen( str ); + if (len < 0) + { + /* Do not search past the length specified by the precision. */ + if (flags->Precision >= 0) + { + for (len = 0; len < flags->Precision; len++) if (!str[len]) break; + } + else len = strlen( str ); + } if (flags->Precision >= 0 && flags->Precision < len) len = flags->Precision; @@ -270,80 +284,20 @@ static int pf_handle_string_format( pf_output *out, const void* str, int len, return pf_output_format_W( out, str, len, flags); } -static inline BOOL pf_is_integer_format( char fmt ) -{ - static const char float_fmts[] = "diouxX"; - if (!fmt) - return FALSE; - return strchr( float_fmts, fmt ) != 0; -} - -static inline BOOL pf_is_double_format( char fmt ) -{ - static const char float_fmts[] = "aeEfgG"; - if (!fmt) - return FALSE; - return strchr( float_fmts, fmt ) != 0; -} - -static inline BOOL pf_is_valid_format( char fmt ) -{ - static const char float_fmts[] = "acCdeEfgGinouxX"; - if (!fmt) - return FALSE; - return strchr( float_fmts, fmt ) != 0; -} - -static void pf_rebuild_format_string( char *p, pf_flags *flags ) -{ - *p++ = '%'; - if( flags->Sign ) - *p++ = flags->Sign; - if( flags->LeftAlign ) - *p++ = flags->LeftAlign; - if( flags->Alternate ) - *p++ = flags->Alternate; - if( flags->PadZero ) - *p++ = flags->PadZero; - if( flags->FieldLength ) - { - sprintf(p, "%d", flags->FieldLength); - p += strlen(p); - } - if( flags->Precision >= 0 ) - { - sprintf(p, ".%d", flags->Precision); - p += strlen(p); - } - *p++ = flags->Format; - *p++ = 0; -} - /* pf_integer_conv: prints x to buf, including alternate formats and additional precision digits, but not field characters or the sign */ -static void pf_integer_conv( char *buf, int buf_len, pf_flags *flags, - LONGLONG x ) +static void pf_integer_conv( char *buf, pf_flags *flags, LONGLONG x ) { unsigned int base; const char *digits; - int i, j, k; - char number[40], *tmp = number; - if( buf_len > sizeof number ) - { - if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, buf_len ))) - { - buf[0] = '\0'; - return; - } - } - - base = 10; if( flags->Format == 'o' ) base = 8; else if( flags->Format == 'x' || flags->Format == 'X' ) base = 16; + else + base = 10; if( flags->Format == 'X' ) digits = "0123456789ABCDEFX"; @@ -356,82 +310,44 @@ static void pf_integer_conv( char *buf, int buf_len, pf_flags *flags, flags->Sign = '-'; } - /* Do conversion (backwards) */ i = 0; - if( x == 0 && flags->Precision ) - tmp[i++] = '0'; + if( x == 0 ) + { + flags->Alternate = 0; + if( flags->Precision ) + buf[i++] = '0'; + } else while( x != 0 ) { j = (ULONGLONG) x % base; x = (ULONGLONG) x / base; - tmp[i++] = digits[j]; + buf[i++] = digits[j]; } k = flags->Precision - i; while( k-- > 0 ) - tmp[i++] = '0'; + buf[i++] = '0'; if( flags->Alternate ) { if( base == 16 ) { - tmp[i++] = digits[16]; - tmp[i++] = '0'; + buf[i++] = digits[16]; + buf[i++] = '0'; } - else if( base == 8 && tmp[i-1] != '0' ) - tmp[i++] = '0'; + else if( base == 8 && buf[i-1] != '0' ) + buf[i++] = '0'; } - /* Reverse for buf */ - j = 0; - while( i-- > 0 ) - buf[j++] = tmp[i]; - buf[j] = '\0'; - /* Adjust precision so pf_fill won't truncate the number later */ - flags->Precision = strlen( buf ); + flags->Precision = i; - if( tmp != number ) - RtlFreeHeap( GetProcessHeap(), 0, tmp ); - - return; -} - -/* pf_fixup_exponent: convert a string containing a 2 digit exponent - to 3 digits, accounting for padding, in place. Needed to match - the native printf's which always use 3 digits. */ -static void pf_fixup_exponent( char *buf ) -{ - char* tmp = buf; - - while (tmp[0] && NTDLL_tolower(tmp[0]) != 'e') - tmp++; - - if (tmp[0] && (tmp[1] == '+' || tmp[1] == '-') && - isdigit(tmp[2]) && isdigit(tmp[3])) - { - char final; - - if (isdigit(tmp[4])) - return; /* Exponent already 3 digits */ - - /* We have a 2 digit exponent. Prepend '0' to make it 3 */ - tmp += 2; - final = tmp[2]; - tmp[2] = tmp[1]; - tmp[1] = tmp[0]; - tmp[0] = '0'; - if (final == '\0') - { - /* We didn't expand into trailing space, so this string isn't left - * justified. Terminate the string and strip a ' ' at the start of - * the string if there is one (as there may be if the string is - * right justified). - */ - tmp[3] = '\0'; - if (buf[0] == ' ') - memmove(buf, buf + 1, (tmp - buf) + 3); - } - /* Otherwise, we expanded into trailing space -> nothing to do */ + buf[i] = '\0'; + j = 0; + while(--i > j) { + char tmp = buf[j]; + buf[j] = buf[i]; + buf[i] = tmp; + j++; } } @@ -546,7 +462,12 @@ static int pf_vsnprintf( pf_output *out, const WCHAR *format, __ms_va_list valis /* deal with integer width modifier */ while( *p ) { - if( *p == 'h' || *p == 'l' || *p == 'L' ) + if (*p == 'l' && *(p+1) == 'l') + { + flags.IntegerDouble++; + p += 2; + } + else if( *p == 'h' || *p == 'l' || *p == 'L' ) { flags.IntegerLength = *p; p++; @@ -573,6 +494,13 @@ static int pf_vsnprintf( pf_output *out, const WCHAR *format, __ms_va_list valis } else if( *p == 'w' ) flags.WideString = *p++; + else if ((*p == 'z' || *p == 't') && p[1] && strchr("diouxX", p[1])) + flags.IntegerNative = *p++; + else if (*p == 'j') + { + flags.IntegerDouble++; + p++; + } else if( *p == 'F' ) p++; /* ignore */ else @@ -605,12 +533,13 @@ static int pf_vsnprintf( pf_output *out, const WCHAR *format, __ms_va_list valis { char pointer[32]; void *ptr = va_arg( valist, void * ); - + int prec = flags.Precision; + flags.Format = 'X'; + flags.PadZero = '0'; + flags.Precision = 2*sizeof(void*); + pf_integer_conv( pointer, &flags, (ULONG_PTR)ptr ); flags.PadZero = 0; - if( flags.Alternate ) - sprintf(pointer, "0X%0*lX", 2 * (int)sizeof(ptr), (ULONG_PTR)ptr); - else - sprintf(pointer, "%0*lX", 2 * (int)sizeof(ptr), (ULONG_PTR)ptr); + flags.Precision = prec; r = pf_output_format_A( out, pointer, -1, &flags ); } @@ -620,63 +549,33 @@ static int pf_vsnprintf( pf_output *out, const WCHAR *format, __ms_va_list valis int *x = va_arg(valist, int *); *x = out->used; } - - /* deal with 64-bit integers */ - else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble ) + else if( flags.Format && strchr("diouxX", flags.Format )) { char number[40], *x = number; + int max_len; - /* Estimate largest possible required buffer size: - * Chooses the larger of the field or precision - * Includes extra bytes: 1 byte for null, 1 byte for sign, - 4 bytes for exponent, 2 bytes for alternate formats, 1 byte - for a decimal, and 1 byte for an additional float digit. */ - int x_len = ((flags.FieldLength > flags.Precision) ? - flags.FieldLength : flags.Precision) + 10; + /* 0 padding is added after '0x' if Alternate flag is in use */ + if((flags.Format=='x' || flags.Format=='X') && flags.PadZero && flags.Alternate + && !flags.LeftAlign && flags.Precision= sizeof number) - if (!(x = RtlAllocateHeap( GetProcessHeap(), 0, x_len ))) - return -1; + max_len = (flags.FieldLength>flags.Precision ? flags.FieldLength : flags.Precision) + 10; + if(max_len > ARRAY_SIZE(number)) + if (!(x = RtlAllocateHeap( GetProcessHeap(), 0, max_len ))) return -1; - pf_integer_conv( x, x_len, &flags, va_arg(valist, LONGLONG) ); + if(flags.IntegerDouble || (flags.IntegerNative && sizeof(void*) == 8)) + pf_integer_conv( x, &flags, va_arg(valist, LONGLONG) ); + else if(flags.Format=='d' || flags.Format=='i') + pf_integer_conv( x, &flags, flags.IntegerLength!='h' ? + va_arg(valist, int) : (short)va_arg(valist, int) ); + else + pf_integer_conv( x, &flags, flags.IntegerLength!='h' ? + (unsigned int)va_arg(valist, int) : (unsigned short)va_arg(valist, int) ); r = pf_output_format_A( out, x, -1, &flags ); if( x != number ) RtlFreeHeap( GetProcessHeap(), 0, x ); } - - /* deal with integers and floats using libc's printf */ - else if( pf_is_valid_format( flags.Format ) ) - { - char fmt[20], number[40], *x = number; - - /* Estimate largest possible required buffer size: - * Chooses the larger of the field or precision - * Includes extra bytes: 1 byte for null, 1 byte for sign, - 4 bytes for exponent, 2 bytes for alternate formats, 1 byte - for a decimal, and 1 byte for an additional float digit. */ - int x_len = ((flags.FieldLength > flags.Precision) ? - flags.FieldLength : flags.Precision) + 10; - - if( x_len >= sizeof number) - if (!(x = RtlAllocateHeap( GetProcessHeap(), 0, x_len ))) - return -1; - - pf_rebuild_format_string( fmt, &flags ); - - if( pf_is_double_format( flags.Format ) ) - { - sprintf( x, fmt, va_arg(valist, double) ); - if (NTDLL_tolower(flags.Format) == 'e' || NTDLL_tolower(flags.Format) == 'g') - pf_fixup_exponent( x ); - } - else - sprintf( x, fmt, va_arg(valist, int) ); - - r = pf_output_stringA( out, x, -1 ); - if( x != number ) - RtlFreeHeap( GetProcessHeap(), 0, x ); - } else continue;