Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Dec 2025 16:30:29 +0000
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: d2cb9cab8457 - main - printf.9: Support more than 32 bits in %b
Message-ID:  <69457da5.aadf.1e1de424@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by tuexen:

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

commit d2cb9cab8457b2a84898f0ac86f7b45e907f872c
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2025-12-19 16:26:37 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
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) {


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69457da5.aadf.1e1de424>