Add %b and %B support to the printf/wprintf family.

Coming to C23 via WG14 N2630, and already in glibc.

We're still missing clang support for %b and %B in format string checking,
but it's probably easier to fix this first. (Apparently GCC already has
support because of glibc.)

Test: treehugger
Change-Id: Ie8bfe4630d00c50e1d047d6756a7f799205356db
diff --git a/docs/status.md b/docs/status.md
index de1eed1..d509e41 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -51,6 +51,12 @@
 
 Current libc symbols: https://android.googlesource.com/platform/bionic/+/master/libc/libc.map.txt
 
+New libc functions in U (API level 34):
+  * `close_range` and `copy_file_range` (Linux-specific GNU extensions).
+
+New libc behavior in U (API level 34):
+  * Support for `%b` and `%B` in the printf and wprintf family.
+
 New libc functions in T (API level 33):
   * `backtrace`, `backtrace_symbols`, `backtrace_symbols_fd` (`<execinfo.h>`).
   * New system call wrappers: `preadv2`, `preadv64v2`, `pwritev2`,
diff --git a/libc/stdio/printf_common.h b/libc/stdio/printf_common.h
index 4dc5ca1..e761835 100644
--- a/libc/stdio/printf_common.h
+++ b/libc/stdio/printf_common.h
@@ -524,6 +524,8 @@
       case 'u':
       case 'X':
       case 'x':
+      case 'B':
+      case 'b':
         ADDUARG();
         break;
       default: /* "%?" prints ?, unless ? is NUL */
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index d99d09c..d83a5bf 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -81,8 +81,8 @@
   char* dtoaresult = nullptr;
 
   uintmax_t _umax;             /* integer arguments %[diouxX] */
-  enum { OCT, DEC, HEX } base; /* base for %[diouxX] conversion */
-  int dprec;                   /* a copy of prec if %[diouxX], 0 otherwise */
+  enum { BIN, OCT, DEC, HEX } base; /* base for %[bBdiouxX] conversion */
+  int dprec;                   /* a copy of prec if %[bBdiouxX], 0 otherwise */
   int realsz;                  /* field size expanded by dprec */
   int size;                    /* size of converted field or string */
   const char* xdigs;           /* digits for %[xX] conversion */
@@ -304,6 +304,12 @@
       case 'z':
         flags |= SIZEINT;
         goto rflag;
+      case 'B':
+      case 'b':
+        _umax = UARG();
+        base = BIN;
+        if (flags & ALT && _umax != 0) ox[1] = ch;
+        goto nosign;
       case 'C':
         flags |= LONGINT;
         __BIONIC_FALLTHROUGH;
@@ -550,6 +556,13 @@
            * a variable; hence this switch.
            */
           switch (base) {
+            case BIN:
+              do {
+                *--cp = to_char(_umax & 1);
+                _umax >>= 1;
+              } while (_umax);
+              break;
+
             case OCT:
               do {
                 *--cp = to_char(_umax & 7);
@@ -599,7 +612,7 @@
      * first be prefixed by any sign or other prefix; otherwise,
      * it should be blank padded before the prefix is emitted.
      * After any left-hand padding and prefixing, emit zeroes
-     * required by a decimal %[diouxX] precision, then print the
+     * required by a decimal %[bBdiouxX] precision, then print the
      * string proper, then emit zeroes required by any leftover
      * floating precision; finally, if LADJUST, pad with blanks.
      *
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index dd51eec..9819a73 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -81,8 +81,8 @@
   char* dtoaresult = nullptr;
 
   uintmax_t _umax;             /* integer arguments %[diouxX] */
-  enum { OCT, DEC, HEX } base; /* base for %[diouxX] conversion */
-  int dprec;                   /* a copy of prec if %[diouxX], 0 otherwise */
+  enum { BIN, OCT, DEC, HEX } base; /* base for %[bBdiouxX] conversion */
+  int dprec;                   /* a copy of prec if %[bBdiouxX], 0 otherwise */
   int realsz;                  /* field size expanded by dprec */
   int size;                    /* size of converted field or string */
   const char* xdigs;           /* digits for %[xX] conversion */
@@ -293,6 +293,12 @@
       case 'z':
         flags |= SIZEINT;
         goto rflag;
+      case 'B':
+      case 'b':
+        _umax = UARG();
+        base = BIN;
+        if (flags & ALT && _umax != 0) ox[1] = ch;
+        goto nosign;
       case 'C':
         flags |= LONGINT;
         __BIONIC_FALLTHROUGH;
@@ -539,6 +545,13 @@
            * a variable; hence this switch.
            */
           switch (base) {
+            case BIN:
+              do {
+                *--cp = to_char(_umax & 1);
+                _umax >>= 1;
+              } while (_umax);
+              break;
+
             case OCT:
               do {
                 *--cp = to_char(_umax & 7);
@@ -588,7 +601,7 @@
      * first be prefixed by any sign or other prefix; otherwise,
      * it should be blank padded before the prefix is emitted.
      * After any left-hand padding and prefixing, emit zeroes
-     * required by a decimal %[diouxX] precision, then print the
+     * required by a decimal %[bBdiouxX] precision, then print the
      * string proper, then emit zeroes required by any leftover
      * floating precision; finally, if LADJUST, pad with blanks.
      *
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 5bc6567..5e4e068 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -365,13 +365,13 @@
 
 TEST_F(STDIO_DEATHTEST, snprintf_n) {
 #if defined(__BIONIC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat"
   // http://b/14492135 and http://b/31832608.
   char buf[32];
   int i = 1234;
   EXPECT_DEATH(snprintf(buf, sizeof(buf), "a %n b", &i), "%n not allowed on Android");
-#pragma GCC diagnostic pop
+#pragma clang diagnostic pop
 #else
   GTEST_SKIP() << "glibc does allow %n";
 #endif
@@ -2963,3 +2963,75 @@
   std::unique_ptr<FILE, decltype(&fclose)> fp{fopen("/dev/null", "we"), fclose};
   ASSERT_EQ(too_big_for_an_int, fwrite(&buf[0], 1, too_big_for_an_int, fp.get()));
 }
+
+TEST(STDIO_TEST, snprintf_b) {
+  // Our clang doesn't know about %b/%B yet.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+  char buf[BUFSIZ];
+  EXPECT_EQ(5, snprintf(buf, sizeof(buf), "<%b>", 5));
+  EXPECT_STREQ("<101>", buf);
+  EXPECT_EQ(10, snprintf(buf, sizeof(buf), "<%08b>", 5));
+  EXPECT_STREQ("<00000101>", buf);
+  EXPECT_EQ(34, snprintf(buf, sizeof(buf), "<%b>", 0xaaaaaaaa));
+  EXPECT_STREQ("<10101010101010101010101010101010>", buf);
+  EXPECT_EQ(36, snprintf(buf, sizeof(buf), "<%#b>", 0xaaaaaaaa));
+  EXPECT_STREQ("<0b10101010101010101010101010101010>", buf);
+  EXPECT_EQ(3, snprintf(buf, sizeof(buf), "<%#b>", 0));
+  EXPECT_STREQ("<0>", buf);
+#pragma clang diagnostic pop
+}
+
+TEST(STDIO_TEST, snprintf_B) {
+  // Our clang doesn't know about %b/%B yet.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+  char buf[BUFSIZ];
+  EXPECT_EQ(5, snprintf(buf, sizeof(buf), "<%B>", 5));
+  EXPECT_STREQ("<101>", buf);
+  EXPECT_EQ(10, snprintf(buf, sizeof(buf), "<%08B>", 5));
+  EXPECT_STREQ("<00000101>", buf);
+  EXPECT_EQ(34, snprintf(buf, sizeof(buf), "<%B>", 0xaaaaaaaa));
+  EXPECT_STREQ("<10101010101010101010101010101010>", buf);
+  EXPECT_EQ(36, snprintf(buf, sizeof(buf), "<%#B>", 0xaaaaaaaa));
+  EXPECT_STREQ("<0B10101010101010101010101010101010>", buf);
+  EXPECT_EQ(3, snprintf(buf, sizeof(buf), "<%#B>", 0));
+  EXPECT_STREQ("<0>", buf);
+#pragma clang diagnostic pop
+}
+
+TEST(STDIO_TEST, swprintf_b) {
+  // Our clang doesn't know about %b/%B yet.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+  wchar_t buf[BUFSIZ];
+  EXPECT_EQ(5, swprintf(buf, sizeof(buf), L"<%b>", 5));
+  EXPECT_EQ(std::wstring(L"<101>"), buf);
+  EXPECT_EQ(10, swprintf(buf, sizeof(buf), L"<%08b>", 5));
+  EXPECT_EQ(std::wstring(L"<00000101>"), buf);
+  EXPECT_EQ(34, swprintf(buf, sizeof(buf), L"<%b>", 0xaaaaaaaa));
+  EXPECT_EQ(std::wstring(L"<10101010101010101010101010101010>"), buf);
+  EXPECT_EQ(36, swprintf(buf, sizeof(buf), L"<%#b>", 0xaaaaaaaa));
+  EXPECT_EQ(std::wstring(L"<0b10101010101010101010101010101010>"), buf);
+  EXPECT_EQ(3, swprintf(buf, sizeof(buf), L"<%#b>", 0));
+  EXPECT_EQ(std::wstring(L"<0>"), buf);
+#pragma clang diagnostic pop
+}
+
+TEST(STDIO_TEST, swprintf_B) {
+  // Our clang doesn't know about %b/%B yet.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+  wchar_t buf[BUFSIZ];
+  EXPECT_EQ(5, swprintf(buf, sizeof(buf), L"<%B>", 5));
+  EXPECT_EQ(std::wstring(L"<101>"), buf);
+  EXPECT_EQ(10, swprintf(buf, sizeof(buf), L"<%08B>", 5));
+  EXPECT_EQ(std::wstring(L"<00000101>"), buf);
+  EXPECT_EQ(34, swprintf(buf, sizeof(buf), L"<%B>", 0xaaaaaaaa));
+  EXPECT_EQ(std::wstring(L"<10101010101010101010101010101010>"), buf);
+  EXPECT_EQ(36, swprintf(buf, sizeof(buf), L"<%#B>", 0xaaaaaaaa));
+  EXPECT_EQ(std::wstring(L"<0B10101010101010101010101010101010>"), buf);
+  EXPECT_EQ(3, swprintf(buf, sizeof(buf), L"<%#B>", 0));
+  EXPECT_EQ(std::wstring(L"<0>"), buf);
+#pragma clang diagnostic pop
+}