Implement C23 binary format specifiers: - Add %b and %B format support - Support # flag for 0b/0B prefixes - Add 128-bit binary conversion __bigint_to_stringb - Include scanf parsing support - Support modifiers like field width, padding, etc
Signed-off-by: Peter Damianov <[email protected]> --- mingw-w64-crt/stdio/mingw_pformat.c | 39 +++++++++++++++++++++++++---- mingw-w64-crt/stdio/mingw_sformat.c | 4 +++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mingw-w64-crt/stdio/mingw_pformat.c b/mingw-w64-crt/stdio/mingw_pformat.c index 3df14704b..a0b5ef0f6 100644 --- a/mingw-w64-crt/stdio/mingw_pformat.c +++ b/mingw-w64-crt/stdio/mingw_pformat.c @@ -163,6 +163,12 @@ typedef union ATTRIB_GCC_STRUCT __uI128 { #define PFORMAT_XMASK 0x0000000F #define PFORMAT_XSHIFT 0x00000004 +/* `%b' and `%B' format digit extraction mask, and shift count... + * (These are constant, and do not propagate through the flags). + */ +#define PFORMAT_BMASK 0x00000001 +#define PFORMAT_BSHIFT 0x00000001 + /* The radix point character, used in floating point formats, is * localised on the basis of the active LC_NUMERIC locale category. * It is stored locally, as a `wchar_t' entity, which is converted @@ -361,6 +367,23 @@ void __bigint_to_stringx(const uint32_t *digits, const uint32_t digitlen, char * buff[bufflen - 1] = '\0'; } +/* LSB first, binary version */ +static +void __bigint_to_stringb(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen){ + const uint32_t digitsize = sizeof(*digits) * 8; + const uint64_t bits = digitsize * digitlen; + uint32_t pos = bufflen - 2; + + for(uint32_t i = 0; i < bits; i++){ + buff[pos] = (digits[i / digitsize] & (1 << (i % digitsize))) ? '1' : '0'; + if(!pos) break; /* sanity check */ + pos--; + } + if(pos < bufflen - 1) + memset(buff,'0', pos + 1); + buff[bufflen - 1] = '\0'; +} + /* LSB first, octet version */ static void __bigint_to_stringo(const uint32_t *digits, const uint32_t digitlen, char *buff, const uint32_t bufflen){ @@ -883,7 +906,7 @@ while( value.__pformat_ullong_t ) static void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream ) { - /* Handler for `%o', `%p', `%x' and `%X' conversions. + /* Handler for `%o', `%p', `%x', `%X', `%b' and `%B' conversions. * * These can be implemented using a simple `mask and shift' strategy; * set up the mask and shift values appropriate to the conversion format, @@ -891,7 +914,8 @@ void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream ) * digits of the formatted value, in preparation for output. */ int width; - int shift = (fmt == 'o') ? PFORMAT_OSHIFT : PFORMAT_XSHIFT; + int shift = (fmt == 'o') ? PFORMAT_OSHIFT : + (fmt == 'b' || fmt == 'B') ? PFORMAT_BSHIFT : PFORMAT_XSHIFT; int bufflen = __pformat_int_bufsiz(2, shift, stream); char *buf = NULL; #ifdef __ENABLE_PRINTF128 @@ -904,6 +928,8 @@ void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream ) tmp_buf = alloca(bufflen); if(fmt == 'o'){ __bigint_to_stringo(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen); + } else if(fmt == 'b' || fmt == 'B'){ + __bigint_to_stringb(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen); } else { __bigint_to_stringx(value.__pformat_u128_t.t128_2.digits32,4,tmp_buf,bufflen, !(fmt & PFORMAT_XCASE)); } @@ -913,7 +939,8 @@ void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream ) for(int32_t i = strlen(tmp_buf); i >= 0; i--) *p++ = tmp_buf[i]; #else - int mask = (fmt == 'o') ? PFORMAT_OMASK : PFORMAT_XMASK; + int mask = (fmt == 'o') ? PFORMAT_OMASK : + (fmt == 'b' || fmt == 'B') ? PFORMAT_BMASK : PFORMAT_XMASK; while( value.__pformat_ullong_t ) { /* Encode the specified non-zero input value as a sequence of digits, @@ -975,7 +1002,7 @@ void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream ) if( ((width = stream->width) > 0) && (fmt != 'o') && (stream->flags & PFORMAT_HASHED) ) /* - * For `%#x' or `%#X' formats, (which have the `#' flag set), + * For `%#x', `%#X', `%#b' or `%#B' formats, (which have the `#' flag set), * further reduce the padding width to accommodate the radix * indicating prefix. */ @@ -2514,8 +2541,10 @@ __pformat (int flags, void *dest, int max, const APICHAR *fmt, va_list argv) case 'u': case 'x': case 'X': + case 'b': + case 'B': /* - * Unsigned integer values; octal, decimal or hexadecimal format... + * Unsigned integer values; octal, decimal, hexadecimal or binary format... */ stream.flags &= ~PFORMAT_POSITIVE; #if __ENABLE_PRINTF128 diff --git a/mingw-w64-crt/stdio/mingw_sformat.c b/mingw-w64-crt/stdio/mingw_sformat.c index 81757cb1e..0b1a59792 100644 --- a/mingw-w64-crt/stdio/mingw_sformat.c +++ b/mingw-w64-crt/stdio/mingw_sformat.c @@ -927,6 +927,7 @@ __mingw_sformat (_IFP *s, const char *format, va_list argp) case 'o': case 'p': case 'u': case 'x': case 'X': + case 'b': case 'B': switch (fc) { case 'd': @@ -954,6 +955,9 @@ __mingw_sformat (_IFP *s, const char *format, va_list argp) case 'x': case 'X': base = 16; break; + case 'b': case 'B': + base = 2; + break; } if ((c = in_ch (s, &read_in)) == EOF) -- 2.47.3 _______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
