The branch main has been updated by tuexen:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=d2cb9cab8457b2a84898f0ac86f7b45e907f872c

commit d2cb9cab8457b2a84898f0ac86f7b45e907f872c
Author:     Michael Tuexen <[email protected]>
AuthorDate: 2025-12-19 16:26:37 +0000
Commit:     Michael Tuexen <[email protected]>
CommitDate: 2025-12-19 16:26:37 +0000

    printf.9: Support more than 32 bits in %b
    
    This will be usable after clang has been extended to accept length
    modifiers for %b when compiling kernel code.
    But we need FreeBSD to support it first...
    
    Reviewed by:            markj, Timo Völker
    MFC after:              1 week
    Differential Revision:  https://reviews.freebsd.org/D54286
---
 share/man/man9/printf.9 | 25 ++++++++++++++++++-------
 sys/kern/subr_prf.c     | 40 +++++++++++++++++++++++++++++++---------
 2 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/share/man/man9/printf.9 b/share/man/man9/printf.9
index 8006590b3d2a..5c819acbec09 100644
--- a/share/man/man9/printf.9
+++ b/share/man/man9/printf.9
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd December 18, 2025
+.Dd December 19, 2025
 .Dt PRINTF 9
 .Os
 .Sh NAME
@@ -95,14 +95,15 @@ arguments.
 The base value is the output base (radix) expressed as an octal value;
 for example, \e10 gives octal and \e20 gives hexadecimal.
 The arguments are made up of a sequence of bit identifiers.
-Each bit identifier begins with an
-.Em octal
-value which is the number of the bit (starting from 1) this identifier
-describes.
+Each bit identifier begins with a character specifying the number of the bit
+(starting from 1) this identifier describes.
+The characters from \e01 to \e40 can be used to specify bit numbers in the
+range from 1 to 32 and characters from \e200 to \e377 to specify bit numbers
+in the range from 1 to 128.
 The rest of the identifier is a string of characters containing the name of
 the bit.
-The string is terminated by either the bit number at the start of the next
-bit identifier or
+The identifier is terminated by either the bit number at the start of the next
+bit identifier or by
 .Dv NUL
 for the last bit identifier.
 .Pp
@@ -173,6 +174,16 @@ reg=3<BITTWO,BITONE>
 out: 41:41:5a:5a
 .Ed
 .Pp
+The same output will be generated by the following function:
+.Bd -literal -offset indent
+void
+printf_test(void)
+{
+       printf("reg=%b\en", 3, "\e10\e201BITTWO\e200BITONE");
+       printf("out: %4D\en", "AAZZ", ":");
+}
+.Ed
+.Pp
 The call
 .Bd -literal -offset indent
 log(LOG_DEBUG, "%s%d: been there.\en", sc->sc_name, sc->sc_unit);
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
index e2070ae3f865..bbf81b7a4ffe 100644
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -628,6 +628,18 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, 
int upper)
        return (p);
 }
 
+static inline bool
+isbitpos(char c)
+{
+       return (c != '\0' && (c <= ' ' || (c & 0x80) != 0));
+}
+
+static inline bool
+isprintnospace(char c)
+{
+       return (isprint(c) && c != ' ');
+}
+
 /*
  * Scaled down version of printf(3).
  *
@@ -640,9 +652,12 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, 
int upper)
  *
  * where <base> is the output base expressed as a control character, e.g.
  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
- * the first of which gives the bit number to be inspected (origin 1), and
- * the next characters (up to a control character, i.e. a character <= 32),
- * give the name of the register.  Thus:
+ * the first of which gives the bit number to be inspected and the next
+ * characters (up to the bit number of the next argument or a final NUL
+ * character), give the name of the register.
+ * The bit number can be encoded as a character between 1 and 32 or as a
+ * character between 128 and 255.
+ * Thus:
  *
  *     kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
  *
@@ -650,6 +665,10 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, 
int upper)
  *
  *     reg=3<BITTWO,BITONE>
  *
+ * The same output would be generated by using:
+ *
+ *     kvprintf("reg=%b\n", 3, "\10\201BITTWO\200BITONE");
+ *
  * XXX:  %D  -- Hexdump, takes pointer and separator string:
  *             ("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
  *             ("%*D", len, ptr, " " -> XX XX XX XX ...
@@ -950,15 +969,18 @@ number:
                        if (bconv && num != 0) {
                                /* %b conversion flag format. */
                                tmp = retval;
-                               while (*q) {
-                                       n = *q++;
-                                       if (num & (1 << (n - 1))) {
+                               while (isbitpos(*q)) {
+                                       if ((*q & 0x80) != 0)
+                                               n = *q++ & 0x7f;
+                                       else
+                                               n = *q++ - 1;
+                                       if (num & (1ULL << n)) {
                                                PCHAR(retval != tmp ?
                                                    ',' : '<');
-                                               for (; (n = *q) > ' '; ++q)
-                                                       PCHAR(n);
+                                               for (; isprintnospace(*q); ++q)
+                                                       PCHAR(*q);
                                        } else
-                                               for (; *q > ' '; ++q)
+                                               for (; isprintnospace(*q); ++q)
                                                        continue;
                                }
                                if (retval != tmp) {

Reply via email to