This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 096eaab879a35cef4126ecb01a36a62345230639
Author: Marco Casaroli <[email protected]>
AuthorDate: Thu Nov 5 15:52:16 2026 +0100

    libs/libc/stream: Add an option for %b and %B of C23 in printf().
    
    printf() took %b and %B as unknown conversions.  Add the option
    LIBC_PRINTF_C23, on in the Full profile, and off in the Minimal and
    Default profiles.  With the option off they stay unknown conversions: the
    rest of the format prints as text and no argument is read.
    
    The conversion prints the integer in binary, with the prefix 0b or 0B for
    the # flag.  The conversion buffer has room for all bits of the integer
    when the option is on.
    
    Part of https://github.com/apache/nuttx/issues/21467
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 libs/libc/stdio/Kconfig            |  8 +++++++
 libs/libc/stream/lib_libvsprintf.c | 43 +++++++++++++++++++++++++++++++++++---
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/libs/libc/stdio/Kconfig b/libs/libc/stdio/Kconfig
index 342063804da..2fd24d14401 100644
--- a/libs/libc/stdio/Kconfig
+++ b/libs/libc/stdio/Kconfig
@@ -139,6 +139,14 @@ config LIBC_PRINTF_HEXFLOAT
                does not need LIBC_FLOATINGPOINT and it pulls in no soft-float 
code.
                Without it, printf() reads the argument and prints "?".
 
+config LIBC_PRINTF_C23
+       bool "Enable the C23 conversions in printf"
+       default LIBC_PRINTF_FULL
+       ---help---
+               Enables %b and %B, the binary output of an integer.  Without it,
+               they are unknown conversions: printf() prints the rest of the 
format
+               as text and reads no more arguments.
+
 config LIBC_FLOATINGPOINT
        bool "Enable floating point in printf"
        default LIBC_PRINTF_FULL || (!DEFAULT_SMALL && ARCH_FPU && 
!LIBC_PRINTF_MINIMAL)
diff --git a/libs/libc/stream/lib_libvsprintf.c 
b/libs/libc/stream/lib_libvsprintf.c
index c65400f0199..0b8b6f18de7 100644
--- a/libs/libc/stream/lib_libvsprintf.c
+++ b/libs/libc/stream/lib_libvsprintf.c
@@ -104,6 +104,18 @@
 #define FL_FLTEXP          0x4000
 #define FL_FLTFIX          0x8000
 
+/* %b and %B: only an integer conversion has this bit.  A flag that is 0 lets
+ * the compiler remove the code of its feature.
+ */
+
+#ifdef CONFIG_LIBC_PRINTF_C23
+#  define FL_ALTBIN        0x8000
+#  define fmt_isbinary(c)  (((c) | 0x20) == 'b')
+#else
+#  define FL_ALTBIN        0
+#  define fmt_isbinary(c)  0
+#endif
+
 /* The # flag.  FL_ALT stays for the prefix of %p.  A flag that is 0 lets the
  * compiler remove the code of its feature.
  */
@@ -513,7 +525,11 @@ static int vsprintf_internal(FAR struct lib_outstream_s 
*stream,
   int prec;
   union
   {
+#ifdef CONFIG_LIBC_PRINTF_C23
+    char __buf[sizeof(ultoa_uint_t) * CHAR_BIT]; /* -1 in binary */
+#else
     char __buf[22]; /* Size for -1 in octal, without '\0' */
+#endif
 #ifdef CONFIG_LIBC_FLOATINGPOINT
     struct dtoa_s __dtoa;
 #endif
@@ -920,7 +936,7 @@ set_star:
               type = FL_IS_LDOUBLE(flags) ? TYPE_LONG_DOUBLE : TYPE_DOUBLE;
             }
           else if (c == 'i' || c == 'd' || c == 'u' || c == 'p' ||
-                   c == 'o' || c == 'x' || c == 'X')
+                   c == 'o' || c == 'x' || c == 'X' || fmt_isbinary(c))
             {
               if ((flags & FL_LONG) == 0)
                 {
@@ -1641,7 +1657,8 @@ str_lpad:
               c = __ultoa_invert(x, buf, 10) - buf;
             }
         }
-      else if (c != 'u' && c != 'o' && c != 'p' && (c | 0x20) != 'x')
+      else if (c != 'u' && c != 'o' && c != 'p' && (c | 0x20) != 'x' &&
+               !fmt_isbinary(c))
         {
           /* An unknown conversion, or the end of the format.  The size of
            * the argument is not known, so read no more arguments.  Print the
@@ -1816,6 +1833,25 @@ str_lpad:
                 base = 16;
                 break;
 
+#ifdef CONFIG_LIBC_PRINTF_C23
+              case 'B':
+                if ((flags & FL_ALT_FORM) != 0)
+                  {
+                    flags |= FL_ALTUPP;
+                  }
+
+                /* FALLTHROUGH */
+
+              case 'b':
+                if ((flags & FL_ALT_FORM) != 0)
+                  {
+                    flags |= FL_ALTHEX | FL_ALTBIN;
+                  }
+
+                base = 2;
+                break;
+#endif
+
               default: /* 'X' */
                 if ((flags & FL_ALT_FORM) != 0)
                   {
@@ -1914,8 +1950,9 @@ str_lpad:
           stream_putc('0', stream);
           if (FL_ALT_IS_HEX(flags))
             {
+              ch = (flags & FL_ALTBIN) != 0 ? 'b' : 'x';
               stream_putc(FL_ALT_FORM != 0 && (flags & FL_ALTUPP) != 0 ?
-                          'X' : 'x', stream);
+                          ch - 0x20 : ch, stream);
             }
         }
       else if ((flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) != 0)

Reply via email to