aboutsummaryrefslogtreecommitdiff
path: root/stdio-common
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common')
-rw-r--r--stdio-common/Makefile3
-rw-r--r--stdio-common/printf-parsemb.c2
-rw-r--r--stdio-common/tst-printf-binary-main.c130
-rw-r--r--stdio-common/tst-printf-binary.c25
-rw-r--r--stdio-common/tst-printf.c2
-rw-r--r--stdio-common/tst-printf.sh4
-rw-r--r--stdio-common/vfprintf-internal.c48
7 files changed, 193 insertions, 21 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 803f16dae0..bbb3a2ca56 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -70,7 +70,8 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
tst-vfprintf-width-prec-alloc \
tst-printf-fp-free \
tst-printf-fp-leak \
- test-strerr
+ test-strerr \
+ tst-printf-binary
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c
index 6e64a6bb98..8bc5567758 100644
--- a/stdio-common/printf-parsemb.c
+++ b/stdio-common/printf-parsemb.c
@@ -328,6 +328,8 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
case L'o':
case L'X':
case L'x':
+ case L'B':
+ case L'b':
#if LONG_MAX != LONG_LONG_MAX
if (spec->info.is_long_double)
spec->data_arg_type = PA_INT|PA_FLAG_LONG_LONG;
diff --git a/stdio-common/tst-printf-binary-main.c b/stdio-common/tst-printf-binary-main.c
new file mode 100644
index 0000000000..02698f65ba
--- /dev/null
+++ b/stdio-common/tst-printf-binary-main.c
@@ -0,0 +1,130 @@
+/* Test binary printf formats.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+
+/* GCC does not know the %b or %B formats before GCC 12. */
+DIAG_PUSH_NEEDS_COMMENT;
+#if !__GNUC_PREREQ (12, 0)
+DIAG_IGNORE_NEEDS_COMMENT (11, "-Wformat");
+DIAG_IGNORE_NEEDS_COMMENT (11, "-Wformat-extra-args");
+#endif
+
+#define CHECK_PRINTF(EXPECTED, FMT, ...) \
+ do \
+ { \
+ int ret = SNPRINTF (buf, sizeof buf / sizeof buf[0], L_(FMT), \
+ __VA_ARGS__); \
+ TEST_COMPARE_STRING_MACRO (buf, L_(EXPECTED)); \
+ TEST_COMPARE (ret, STRLEN (L_(EXPECTED))); \
+ } \
+ while (0)
+
+static int
+do_test (void)
+{
+ CHAR buf[1024];
+ CHECK_PRINTF ("0", "%b", 0u);
+ CHECK_PRINTF ("0", "%B", 0u);
+ CHECK_PRINTF ("0", "%#b", 0u);
+ CHECK_PRINTF ("0", "%#B", 0u);
+ CHECK_PRINTF ("1", "%b", 1u);
+ CHECK_PRINTF ("1", "%B", 1u);
+ CHECK_PRINTF ("10", "%b", 2u);
+ CHECK_PRINTF ("10", "%B", 2u);
+ CHECK_PRINTF ("11", "%b", 3u);
+ CHECK_PRINTF ("11", "%B", 3u);
+ CHECK_PRINTF ("10000111011001010100001100100001", "%b", 0x87654321);
+ CHECK_PRINTF ("10000111011001010100001100100001", "%B", 0x87654321);
+ CHECK_PRINTF ("100001100100001", "%hb", (int) 0x87654321);
+ CHECK_PRINTF ("100001100100001", "%hB", (int) 0x87654321);
+ CHECK_PRINTF ("100001", "%hhb", (int) 0x87654321);
+ CHECK_PRINTF ("100001", "%hhB", (int) 0x87654321);
+ CHECK_PRINTF ("10000111011001010100001100100001", "%lb", 0x87654321ul);
+ CHECK_PRINTF ("10000111011001010100001100100001", "%lB", 0x87654321ul);
+ CHECK_PRINTF ("11111110110111001011101010011001"
+ "10000111011001010100001100100001", "%llb",
+ 0xfedcba9987654321ull);
+ CHECK_PRINTF ("11111110110111001011101010011001"
+ "10000111011001010100001100100001", "%llB",
+ 0xfedcba9987654321ull);
+#if LONG_WIDTH >= 64
+ CHECK_PRINTF ("11111110110111001011101010011001"
+ "10000111011001010100001100100001", "%lb",
+ 0xfedcba9987654321ul);
+ CHECK_PRINTF ("11111110110111001011101010011001"
+ "10000111011001010100001100100001", "%lB",
+ 0xfedcba9987654321ul);
+#endif
+ CHECK_PRINTF (" 1010", "%5b", 10u);
+ CHECK_PRINTF (" 1010", "%5B", 10u);
+ CHECK_PRINTF ("01010", "%05b", 10u);
+ CHECK_PRINTF ("01010", "%05B", 10u);
+ CHECK_PRINTF ("1011 ", "%-5b", 11u);
+ CHECK_PRINTF ("1011 ", "%-5B", 11u);
+ CHECK_PRINTF ("0b10011", "%#b", 19u);
+ CHECK_PRINTF ("0B10011", "%#B", 19u);
+ CHECK_PRINTF (" 0b10011", "%#10b", 19u);
+ CHECK_PRINTF (" 0B10011", "%#10B", 19u);
+ CHECK_PRINTF ("0b00010011", "%0#10b", 19u);
+ CHECK_PRINTF ("0B00010011", "%0#10B", 19u);
+ CHECK_PRINTF ("0b00010011", "%#010b", 19u);
+ CHECK_PRINTF ("0B00010011", "%#010B", 19u);
+ CHECK_PRINTF ("0b10011 ", "%#-10b", 19u);
+ CHECK_PRINTF ("0B10011 ", "%#-10B", 19u);
+ CHECK_PRINTF ("00010011", "%.8b", 19u);
+ CHECK_PRINTF ("00010011", "%.8B", 19u);
+ CHECK_PRINTF ("0b00010011", "%#.8b", 19u);
+ CHECK_PRINTF ("0B00010011", "%#.8B", 19u);
+ CHECK_PRINTF (" 00010011", "%15.8b", 19u);
+ CHECK_PRINTF (" 00010011", "%15.8B", 19u);
+ CHECK_PRINTF ("00010011 ", "%-15.8b", 19u);
+ CHECK_PRINTF ("00010011 ", "%-15.8B", 19u);
+ CHECK_PRINTF (" 0b00010011", "%#15.8b", 19u);
+ CHECK_PRINTF (" 0B00010011", "%#15.8B", 19u);
+ CHECK_PRINTF ("0b00010011 ", "%-#15.8b", 19u);
+ CHECK_PRINTF ("0B00010011 ", "%-#15.8B", 19u);
+ /* GCC diagnoses ignored flags. */
+ DIAG_PUSH_NEEDS_COMMENT;
+ DIAG_IGNORE_NEEDS_COMMENT (12, "-Wformat");
+ /* '0' flag ignored with '-'. */
+ CHECK_PRINTF ("1011 ", "%0-5b", 11u);
+ CHECK_PRINTF ("1011 ", "%0-5B", 11u);
+ CHECK_PRINTF ("0b10011 ", "%#0-10b", 19u);
+ CHECK_PRINTF ("0B10011 ", "%#0-10B", 19u);
+ /* '0' flag ignored with precision. */
+ CHECK_PRINTF (" 00010011", "%015.8b", 19u);
+ CHECK_PRINTF (" 00010011", "%015.8B", 19u);
+ CHECK_PRINTF (" 0b00010011", "%0#15.8b", 19u);
+ CHECK_PRINTF (" 0B00010011", "%0#15.8B", 19u);
+ DIAG_POP_NEEDS_COMMENT;
+ /* Test positional argument handling. */
+ CHECK_PRINTF ("test 1011 test2 100010001000100010001000100010001",
+ "%2$s %1$b %4$s %3$llb", 11u, "test", 0x111111111ull, "test2");
+ return 0;
+}
+
+DIAG_POP_NEEDS_COMMENT;
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-printf-binary.c b/stdio-common/tst-printf-binary.c
new file mode 100644
index 0000000000..bb044b571d
--- /dev/null
+++ b/stdio-common/tst-printf-binary.c
@@ -0,0 +1,25 @@
+/* Test binary printf formats. Narrow string version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#define SNPRINTF snprintf
+#define TEST_COMPARE_STRING_MACRO TEST_COMPARE_STRING
+#define STRLEN strlen
+#define CHAR char
+#define L_(C) C
+
+#include <tst-printf-binary-main.c>
diff --git a/stdio-common/tst-printf.c b/stdio-common/tst-printf.c
index b4241330cb..78007abf15 100644
--- a/stdio-common/tst-printf.c
+++ b/stdio-common/tst-printf.c
@@ -91,7 +91,7 @@ I am ready for my first lesson today.";
fmtst2chk("%0*.*x");
#ifndef BSD
- printf("bad format:\t\"%b\"\n");
+ printf("bad format:\t\"%v\"\n");
printf("nil pointer (padded):\t\"%10p\"\n", (void *) NULL);
#endif
diff --git a/stdio-common/tst-printf.sh b/stdio-common/tst-printf.sh
index c2aee1f1f3..591ab19bfe 100644
--- a/stdio-common/tst-printf.sh
+++ b/stdio-common/tst-printf.sh
@@ -39,7 +39,7 @@ cat <<'EOF' |
%0*x: `0012'
%*.*x: `0012'
%0*.*x: `0012'
-bad format: "%b"
+bad format: "%v"
nil pointer (padded): " (nil)"
decimal negative: "-2345"
octal negative: "37777773327"
@@ -153,7 +153,7 @@ cat <<'EOF' |
%0*x: `0012'
%*.*x: `0012'
%0*.*x: `0012'
-bad format: "%b"
+bad format: "%v"
nil pointer (padded): " (nil)"
decimal negative: "-2345"
octal negative: "37777773327"
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index 355ba582e6..e717f50073 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -390,7 +390,7 @@ static const uint8_t jump_table[] =
/* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8,
/* '8' */ 8, /* '9' */ 8, 0, 0,
0, 0, 0, 0,
- 0, /* 'A' */ 26, 0, /* 'C' */ 25,
+ 0, /* 'A' */ 26, /* 'B' */ 30, /* 'C' */ 25,
0, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19,
0, /* 'I' */ 29, 0, 0,
/* 'L' */ 12, 0, 0, 0,
@@ -398,7 +398,7 @@ static const uint8_t jump_table[] =
0, 0, 0, 0,
/* 'X' */ 18, 0, /* 'Z' */ 13, 0,
0, 0, 0, 0,
- 0, /* 'a' */ 26, 0, /* 'c' */ 20,
+ 0, /* 'a' */ 26, /* 'b' */ 30, /* 'c' */ 20,
/* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
/* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0,
/* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
@@ -444,7 +444,7 @@ static const uint8_t jump_table[] =
#define STEP0_3_TABLE \
/* Step 0: at the beginning. */ \
- static JUMP_TABLE_TYPE step0_jumps[30] = \
+ static JUMP_TABLE_TYPE step0_jumps[31] = \
{ \
REF (form_unknown), \
REF (flag_space), /* for ' ' */ \
@@ -476,9 +476,10 @@ static const uint8_t jump_table[] =
REF (mod_ptrdiff_t), /* for 't' */ \
REF (mod_intmax_t), /* for 'j' */ \
REF (flag_i18n), /* for 'I' */ \
+ REF (form_binary), /* for 'B', 'b' */ \
}; \
/* Step 1: after processing width. */ \
- static JUMP_TABLE_TYPE step1_jumps[30] = \
+ static JUMP_TABLE_TYPE step1_jumps[31] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -509,10 +510,11 @@ static const uint8_t jump_table[] =
REF (form_floathex), /* for 'A', 'a' */ \
REF (mod_ptrdiff_t), /* for 't' */ \
REF (mod_intmax_t), /* for 'j' */ \
- REF (form_unknown) /* for 'I' */ \
+ REF (form_unknown), /* for 'I' */ \
+ REF (form_binary), /* for 'B', 'b' */ \
}; \
/* Step 2: after processing precision. */ \
- static JUMP_TABLE_TYPE step2_jumps[30] = \
+ static JUMP_TABLE_TYPE step2_jumps[31] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -543,10 +545,11 @@ static const uint8_t jump_table[] =
REF (form_floathex), /* for 'A', 'a' */ \
REF (mod_ptrdiff_t), /* for 't' */ \
REF (mod_intmax_t), /* for 'j' */ \
- REF (form_unknown) /* for 'I' */ \
+ REF (form_unknown), /* for 'I' */ \
+ REF (form_binary), /* for 'B', 'b' */ \
}; \
/* Step 3a: after processing first 'h' modifier. */ \
- static JUMP_TABLE_TYPE step3a_jumps[30] = \
+ static JUMP_TABLE_TYPE step3a_jumps[31] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -577,10 +580,11 @@ static const uint8_t jump_table[] =
REF (form_unknown), /* for 'A', 'a' */ \
REF (form_unknown), /* for 't' */ \
REF (form_unknown), /* for 'j' */ \
- REF (form_unknown) /* for 'I' */ \
+ REF (form_unknown), /* for 'I' */ \
+ REF (form_binary), /* for 'B', 'b' */ \
}; \
/* Step 3b: after processing first 'l' modifier. */ \
- static JUMP_TABLE_TYPE step3b_jumps[30] = \
+ static JUMP_TABLE_TYPE step3b_jumps[31] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -611,12 +615,13 @@ static const uint8_t jump_table[] =
REF (form_floathex), /* for 'A', 'a' */ \
REF (form_unknown), /* for 't' */ \
REF (form_unknown), /* for 'j' */ \
- REF (form_unknown) /* for 'I' */ \
+ REF (form_unknown), /* for 'I' */ \
+ REF (form_binary), /* for 'B', 'b' */ \
}
#define STEP4_TABLE \
/* Step 4: processing format specifier. */ \
- static JUMP_TABLE_TYPE step4_jumps[30] = \
+ static JUMP_TABLE_TYPE step4_jumps[31] = \
{ \
REF (form_unknown), \
REF (form_unknown), /* for ' ' */ \
@@ -647,7 +652,8 @@ static const uint8_t jump_table[] =
REF (form_floathex), /* for 'A', 'a' */ \
REF (form_unknown), /* for 't' */ \
REF (form_unknown), /* for 'j' */ \
- REF (form_unknown) /* for 'I' */ \
+ REF (form_unknown), /* for 'I' */ \
+ REF (form_binary), /* for 'B', 'b' */ \
}
/* Before invoking this macro, process_arg_int etc. macros have to be
@@ -706,6 +712,14 @@ static const uint8_t jump_table[] =
LABEL (form_hexa): \
/* Unsigned hexadecimal integer. */ \
base = 16; \
+ goto LABEL (unsigned_number); \
+ /* NOTREACHED */ \
+ \
+ LABEL (form_binary): \
+ /* Unsigned binary integer. */ \
+ base = 2; \
+ goto LABEL (unsigned_number); \
+ /* NOTREACHED */ \
\
LABEL (unsigned_number): /* Unsigned number of base BASE. */ \
\
@@ -803,8 +817,8 @@ static const uint8_t jump_table[] =
{ \
width -= workend - string + prec; \
\
- if (number.word != 0 && alt && base == 16) \
- /* Account for 0X hex marker. */ \
+ if (number.word != 0 && alt && (base == 16 || base == 2)) \
+ /* Account for 0X, 0x, 0B or 0b hex or binary marker. */ \
width -= 2; \
\
if (is_negative || showsign || space) \
@@ -823,7 +837,7 @@ static const uint8_t jump_table[] =
else if (space) \
outchar (L_(' ')); \
\
- if (number.word != 0 && alt && base == 16) \
+ if (number.word != 0 && alt && (base == 16 || base == 2)) \
{ \
outchar (L_('0')); \
outchar (spec); \
@@ -854,7 +868,7 @@ static const uint8_t jump_table[] =
--width; \
} \
\
- if (number.word != 0 && alt && base == 16) \
+ if (number.word != 0 && alt && (base == 16 || base == 2)) \
{ \
outchar (L_('0')); \
outchar (spec); \