Sync to mingw pformat.c cvs 1.9. git-svn-id: svn+ssh://svn.code.sf.net/p/mingw-w64/code/trunk@3945 4407c894-4637-0410-b4f5-ada5f102cad1
diff --git a/mingw-w64-crt/stdio/mingw_pformat.c b/mingw-w64-crt/stdio/mingw_pformat.c index 591cbeb..5f29b76 100644 --- a/mingw-w64-crt/stdio/mingw_pformat.c +++ b/mingw-w64-crt/stdio/mingw_pformat.c
@@ -5,7 +5,7 @@ /* pformat.c * - * $Id: pformat.c,v 1.4 2008/12/31 15:34:09 keithmarshall Exp $ + * $Id: pformat.c,v 1.9 2011/01/07 22:57:00 keithmarshall Exp $ * * Provides a core implementation of the formatting capabilities * common to the entire `printf()' family of functions; it conforms @@ -156,6 +156,13 @@ * for which `_TWO_DIGIT_EXPONENT' will be undefined. */ # ifndef _TWO_DIGIT_EXPONENT + /* + * This hack works around the lack of the `_set_output_format()' + * feature, when supporting versions of the MSVC runtime library + * prior to msvcr80.dll; it simply enforces Microsoft's original + * convention, for all cases where the feature is unsupported. + */ +# define _get_output_format() 0 # define _TWO_DIGIT_EXPONENT 1 # endif /* @@ -727,7 +734,7 @@ * his `__gdtoa()' function in a manner to provide extended precision * replacements for `ecvt()' and `fcvt()'. */ - unsigned int k, e = 0; char *ep; + int k; unsigned int e = 0; char *ep; static FPI fpi = { 64, 1-16383-64+1, 32766-16383-64+1, FPI_Round_near, 0 }; /* Classify the argument into an appropriate `__gdtoa()' category... @@ -770,7 +777,7 @@ /* Finally, get the raw digit string, and radix point position index. */ - return __gdtoa( &fpi, e, &x.__pformat_fpreg_bits, (int *) &k, mode, nd, dp, &ep ); + return __gdtoa( &fpi, e, &x.__pformat_fpreg_bits, &k, mode, nd, dp, &ep ); } static __inline__ __attribute__((__always_inline__)) @@ -854,8 +861,7 @@ /* TODO: end of conditional to be removed. */ #endif -/* Can't be inlined, as it uses alloca. */ -static +static __inline__ void __pformat_emit_radix_point( __pformat_t *stream ) { /* Helper to place a localised representation of the radix point @@ -1469,7 +1475,7 @@ /* taking the rightmost digit in each pass... */ int c = value.__pformat_fpreg_mantissa & 0xF; - if( c == (int) value.__pformat_fpreg_mantissa ) + if( c == value.__pformat_fpreg_mantissa ) { /* inserting the radix point, when we reach the last, * (i.e. the most significant digit), unless we found no @@ -1550,7 +1556,7 @@ * consistency with `%e', `%f' and `%g' styles. */ int min_width = p - buf; - int expo = value.__pformat_fpreg_exponent; + int exponent = value.__pformat_fpreg_exponent; /* If we have not yet queued sufficient digits to fulfil the * requested precision, then we must adjust the minimum width @@ -1564,7 +1570,7 @@ * sign, radix indicator and at least one exponent digit... */ min_width += stream->flags & PFORMAT_SIGNED ? 6 : 5; - while( (expo = expo / 10) != 0 ) + while( (exponent = exponent / 10) != 0 ) { /* and increase as required, if additional exponent digits * are needed, also saving the exponent field width adjustment, @@ -1655,74 +1661,6 @@ } static -void __pformat_xdouble( double x, __pformat_t *stream ) -{ - /* Handler for `%a' and `%A' format specifiers, (with argument - * value specified as `double' type). - */ - unsigned sign_bit = 0; - __pformat_fpreg_t z; z.__pformat_fpreg_double_t = x; - - /* First check for NaN; it is emitted unsigned... - */ - if( isnan( x ) ) - __pformat_emit_inf_or_nan( sign_bit, "NaN", stream ); - - else - { /* Capture the sign bit up-front, so we can show it correctly - * even when the argument value is zero or infinite. - */ - if( (sign_bit = (z.__pformat_fpreg_bitmap[3] & 0x8000)) != 0 ) - stream->flags |= PFORMAT_NEGATIVE; - - /* Check for infinity, (positive or negative)... - */ - if( isinf( x ) ) - /* - * displaying the appropriately signed indicator, - * when appropriate. - */ - __pformat_emit_inf_or_nan( sign_bit, "Inf", stream ); - - else - { /* The argument value is a representable number... - * first move its exponent into the appropriate field... - */ - z.__pformat_fpreg_bitmap[4] = (z.__pformat_fpreg_bitmap[3] >> 4) & 0x7FF; - - /* Realign the mantissa, leaving space for a - * normalised most significant digit... - */ - z.__pformat_fpreg_mantissa <<= 8; - z.__pformat_fpreg_bitmap[3] = (z.__pformat_fpreg_bitmap[3] & 0x0FFF); - - /* Check for zero value... - */ - if( z.__pformat_fpreg_exponent || z.__pformat_fpreg_mantissa ) - { - /* and only when the value is non-zero, - * eliminate the bias from the exponent... - */ - z.__pformat_fpreg_exponent -= 0x3FF; - - /* Check for a possible denormalised value... - */ - if( z.__pformat_fpreg_exponent > -126 ) - /* - * and normalise when it isn't. - */ - z.__pformat_fpreg_bitmap[3] += 0x1000; - } - - /* Finally, hand the adjusted representation off to the generalised - * hexadecimal floating point format handler... - */ - __pformat_emit_xfloat( z, stream ); - } - } -} - -static void __pformat_xldouble( long double x, __pformat_t *stream ) { /* Handler for `%La' and `%LA' format specifiers, (with argument @@ -1757,9 +1695,28 @@ * extract the effective value of the biased exponent... */ z.__pformat_fpreg_exponent &= 0x7FFF; - if( z.__pformat_fpreg_exponent || z.__pformat_fpreg_mantissa ) - /* - * and if the argument value itself is non-zero, + if( z.__pformat_fpreg_exponent == 0 ) + { + /* A biased exponent value of zero means either a + * true zero value, if the mantissa field also has + * a zero value, otherwise... + */ + if( z.__pformat_fpreg_mantissa != 0 ) + { + /* ...this mantissa represents a subnormal value; + * adjust the exponent, while shifting the mantissa + * to the left, until its leading bit is 1. + */ + z.__pformat_fpreg_exponent = 1-0x3FFF; + while( (z.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0 ) + { + z.__pformat_fpreg_mantissa <<= 1; + --z.__pformat_fpreg_exponent; + } + } + } + else + /* This argument represents a non-zero normal number; * eliminate the bias from the exponent... */ z.__pformat_fpreg_exponent -= 0x3FFF; @@ -1875,8 +1832,8 @@ /* considering any `long' type modifier as a reference to * `wchar_t' data, (which is promoted to an `int' argument)... */ - argval.__pformat_ullong_t = (wchar_t)(va_arg( argv, int )); - __pformat_wputchars( (wchar_t *)(&argval), 1, &stream ); + wchar_t argval = (wchar_t)(va_arg( argv, int )); + __pformat_wputchars( &argval, 1, &stream ); } else @@ -2015,9 +1972,22 @@ case 'p': /* - * Pointer argument; format as hexadecimal, with `0x' prefix... + * Pointer argument; format as hexadecimal, subject to... */ - stream.flags |= PFORMAT_HASHED; + if( (state == PFORMAT_INIT) && (stream.flags == flags) ) + { + /* Here, the user didn't specify any particular + * formatting attributes. We must choose a default + * which will be compatible with Microsoft's (broken) + * scanf() implementation, (i.e. matching the default + * used by MSVCRT's printf(), which appears to resemble + * "%0.8X" for 32-bit pointers); in particular, we MUST + * NOT adopt a GNU-like format resembling "%#x", because + * Microsoft's scanf() will choke on the "0x" prefix. + */ + stream.flags |= PFORMAT_ZEROFILL; + stream.precision = 2 * sizeof( uintptr_t ); + } argval.__pformat_ullong_t = va_arg( argv, uintptr_t ); __pformat_xint( 'x', argval, &stream ); goto format_scan; @@ -2128,7 +2098,7 @@ else /* or just a `double'. */ - __pformat_xdouble( va_arg( argv, double ), &stream ); + __pformat_xldouble( (long double)(va_arg( argv, double )), &stream ); goto format_scan; @@ -2515,3 +2485,5 @@ return stream.count; } +/* $RCSfile: pformat.c,v $Revision: 1.9 $: end of file */ +