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
This commit is contained in:
Michael Tuexen
2025-12-19 17:26:37 +01:00
parent a79e2278c5
commit d2cb9cab84
2 changed files with 49 additions and 16 deletions
+18 -7
View File
@@ -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);
+31 -9
View File
@@ -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 @@ reswitch: switch (ch = (u_char)*fmt++) {
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) {