1.\" $NetBSD: snprintb.3,v 1.39 2024/04/08 21:28:35 rillig Exp $ 2.\" 3.\" Copyright (c) 1998, 2024 The NetBSD Foundation, Inc. 4.\" All rights reserved. 5.\" 6.\" This code is derived from software contributed to The NetBSD Foundation 7.\" by Jeremy Cooper. 8.\" 9.\" Redistribution and use in source and binary forms, with or without 10.\" modification, are permitted provided that the following conditions 11.\" are met: 12.\" 1. Redistributions of source code must retain the above copyright 13.\" notice, this list of conditions and the following disclaimer. 14.\" 2. Redistributions in binary form must reproduce the above copyright 15.\" notice, this list of conditions and the following disclaimer in the 16.\" documentation and/or other materials provided with the distribution. 17.\" 18.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28.\" POSSIBILITY OF SUCH DAMAGE. 29.\" 30.Dd April 8, 2024 31.Dt SNPRINTB 3 32.Os 33.Sh NAME 34.Nm snprintb , 35.Nm snprintb_m 36.Nd bitmask output conversion 37.Sh LIBRARY 38.Lb libutil 39.Sh SYNOPSIS 40.In util.h 41.Ft int 42.Fn "snprintb" "char *buf" "size_t bufsize" "const char *fmt" "uint64_t val" 43.Ft int 44.Fn "snprintb_m" "char *buf" "size_t bufsize" "const char *fmt" "uint64_t val" \ 45"size_t max" 46.Sh DESCRIPTION 47The 48.Fn snprintb 49function formats a bitmask into a mnemonic form suitable for printing. 50.Pp 51It formats the integer 52.Fa val 53into the buffer 54.Fa buf , 55of size 56.Fa bufsize , 57interpreting the bits within that integer as flags or groups of bits. 58The buffer is always 59.Tn NUL Ns -terminated. 60If the buffer 61.Fa buf 62is too small to hold the formatted output, 63.Fn snprintb 64will fill as much as it can, and return the number of bytes 65that it would have written if the buffer were long enough excluding the 66terminating 67.Tn NUL . 68If 69.Fa bufsize 70is zero, nothing is written and 71.Fa buf 72may be a null pointer. 73.Pp 74The 75.Fn snprintb_m 76function accepts an additional 77.Fa max 78argument. 79If this argument is zero, the 80.Fn snprintb_m 81function behaves exactly like the 82.Fn snprintb 83function. 84If the 85.Fa max 86argument has a non-zero value, it represents the maximum length of a 87formatted string. 88If the formatted string would require more than 89.Fa max 90characters, the 91.Fn snprintb_m 92function returns multiple formatted strings in the output buffer 93.Fa buf . 94Each string is 95.Tn NUL Ns -terminated , 96and the last string is followed by an 97additional 98.Tn NUL 99character 100.Pq or, if you prefer, a zero-length string . 101.Pp 102The decoding directive in 103.Fa fmt 104describes how the bitfield is to be interpreted and displayed. 105It follows two possible formats, referred to as 106.Dq old 107and 108.Dq new . 109The 110.Dq old 111format is limited to describing single bits in a 32-bit value, 112the bit positions are 1-based. 113The 114.Dq new 115format supports multi-bit fields and 64-bit values, 116the bit positions are 0-based. 117.Pp 118If the first character of 119.Fa fmt 120is 121.Pq in C escape-character format 122.Ql \e177 123or 124.Ql \ex7f , 125the remainder of the 126.Fa fmt 127argument follows the 128.Dq new 129format. 130.Pp 131The next character 132.Po the first for the 133.Dq old 134format 135.Pc 136specifies the numeral base in which to print the numbers in the output. 137The possible values are 138.Ql \e010 139or 140.Ql \ex08 141for octal, 142.Ql \e012 143or 144.Ql \ex0a 145for decimal, and 146.Ql \e020 147or 148.Ql \ex10 149for hexadecimal. 150.Pp 151The remaining characters in the 152.Fa fmt 153argument represent the formatting conversions, 154according to the 155.Dq old 156or 157.Dq new 158format. 159. 160.Ss Old Format 161.Pp 162In the 163.Dq old 164format, each conversion specifies a bit position 165and a description that is printed if the corresponding bit is set. 166.Pp 167The bit position is a 1-based single-byte binary value, 168ranging from 169.Ql \e001 170or 171.Ql \ex01 172(1) for the least significant bit up to 173.Ql \e040 174or 175.Ql \ex20 176(32) for the most significant bit. 177.Pp 178The description is delimited by the next character whose value is 32 or less 179.Po see 180.Xr ascii 7 181.Pc , 182or by the end of the format string itself. 183. 184.Ss New Format 185.Pp 186In the 187.Dq new 188format, 189each conversion begins with a conversion type, 190followed by type-specific parameters, each encoded as a single byte, 191followed by a 192.Tn NUL Ns -terminated description. 193The bit positions are 0-based, 194ranging from 195.Ql \e000 196or 197.Ql \ex00 198(0) for the least significant bit to 199.Ql \e077 200or 201.Ql \ex3f 202(63) for the most significant bit. 203. 204.Bl -tag -width Cm 205. 206.It Cm b Ar bit Ar descr 207Prints the description from 208.Ar descr 209if the bit at the position 210.Ar bit 211is set. 212. 213.It Cm f Ar lsb Ar width Ar descr 214Prints the description from 215.Ar descr , 216a delimiting 217.Sq \&= 218and the numerical value of the multi-bit field 219whose least significant bit is at 220.Ar lsb 221and that spans 222.Ar width 223bits. 224To print individual values of the field, see the 225.Sq Cm \&= 226and 227.Sq Cm \&* 228conversions below. 229. 230.It Cm \&= Ar cmp Ar descr 231Compares the field value from the previous 232.Sq Cm f 233conversion to the single-byte value 234.Ar cmp , 235ranging from 236.Ql \e000 237or 238.Ql \ex00 239(0) to 240.Ql \e377 241or 242.Ql \exff 243(255). 244If they are equal, prints 245.Ql \&= 246followed by the description from 247.Ar descr . 248This conversion may be repeated. 249. 250.It Cm F Ar lsb Ar width Op Ar descr 251Describes a multi-bit field like 252.Sq Cm f , 253but just extracts the value for use with the 254.Sq Cm \&: 255and 256.Sq Cm \&* 257conversions below. 258The description from 259.Ar descr 260is ignored, 261it is only present for uniformity with the other conversions. 262. 263.It Cm \&: Ar cmp Ar descr 264Compares the field value from the previous 265.Sq Cm F 266conversion to the single-byte value 267.Ar cmp , 268ranging from 269.Ql \e000 270or 271.Ql \ex00 272(0) to 273.Ql \e377 274or 275.Ql \exff 276(255). 277If they are equal, prints the description from 278.Ar descr . 279This conversion may be repeated. 280. 281.It Cm * Ar fmt 282If none of the previous 283.Sq Cm \&= 284or 285.Sq Cm \&: 286conversions matched, prints the format string 287.Ar fmt 288via 289.Xr snprintf 3 . 290The format string 291.Ar fmt 292may contain a single 293.Vt uintmax_t 294conversion specification to print the field value that did not match. 295.El 296.Pp 297The new format is terminated by an additional 298.Tn NUL 299character at the end, following that delimiting the last conversion. 300This 301.Tn NUL 302is supplied by the compiler to terminate the string literal and 303doesn't need to be written explicitly. 304.Sh RETURN VALUES 305The 306.Fn snprintb 307and 308.Fn snprintb_m 309functions return the number of bytes that they would have written to the buffer 310if there was adequate space, excluding the final terminating NUL, or \-1 in 311case an error occurred. 312For 313.Fn snprintb_m , 314the NUL characters terminating each individual string are included in the 315total number of bytes. 316.Sh EXAMPLES 317Two examples of the old formatting style: 318.Bd -literal -offset indent 319snprintb(buf, bufsize, "\e010\e002BITTWO\e001BITONE", 3) 320\(rA "03<BITTWO,BITONE>" 321 322snprintb(buf, bufsize, 323 "\ex10" 324 "\ex10" "NOTBOOT" 325 "\ex0f" "FPP" 326 "\ex0e" "SDVMA" 327 "\ex0c" "VIDEO" 328 "\ex0b" "LORES" 329 "\ex0a" "FPA" 330 "\ex09" "DIAG" 331 "\ex07" "CACHE" 332 "\ex06" "IOCACHE" 333 "\ex05" "LOOPBACK" 334 "\ex04" "DBGCACHE", 335 0xe860) 336\(rA "0xe860<NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE>" 337.Ed 338.Pp 339An example of the new formatting style: 340.Bd -literal -offset indent 341snprintb(buf, bufsize, 342 "\e177\e020" 343 "b\e000" "LSB\e0" 344 "b\e001" "BITONE\e0" 345 "f\e004\e004" "NIBBLE2\e0" 346 "f\e020\e004" "BURST\e0" 347 "=\ex04" "FOUR\e0" 348 "=\ex0f" "FIFTEEN\e0" 349 "b\e037" "MSB\e0", 350 0x800f0701) 351\(rA "0x800f0701<LSB,NIBBLE2=0,BURST=0xf=FIFTEEN,MSB>" 352.Ed 353.Pp 354The same example using snprintb_m: 355.Bd -literal -offset indent 356snprintb_m(buf, bufsize, 357 "\e177\e020" 358 "b\e000" "LSB\e0" 359 "b\e001" "BITONE\e0" 360 "f\e004\e004" "NIBBLE2\e0" 361 "f\e020\e004" "BURST\e0" 362 "=\ex04" "FOUR\e0" 363 "=\ex0f" "FIFTEEN\e0" 364 "b\e037" "MSB\e0", 365 0x800f0701, 34) 366\(rA "0x800f0701<LSB,NIBBLE2=0>\e0" 367 "0x800f0701<BURST=0xf=FIFTEEN,MSB>\e0" 368 "" 369.Ed 370.Pp 371A more complex example from 372.In sys/mman.h 373that uses both the single-bit 374.Sq Cm b 375formatting as well as the multi-bit field 376.Sq Cm F 377formatting with a default 378.Sq Cm \&* : 379.Bd -literal -offset indent 380#define MAP_FMT "\e177\e020" \e 381 "b\e0" "SHARED\e0" \e 382 "b\e1" "PRIVATE\e0" \e 383 "b\e2" "COPY\e0" \e 384 "b\e4" "FIXED\e0" \e 385 "b\e5" "RENAME\e0" \e 386 "b\e6" "NORESERVE\e0" \e 387 "b\e7" "INHERIT\e0" \e 388 "b\e11" "HASSEMAPHORE\e0" \e 389 "b\e12" "TRYFIXED\e0" \e 390 "b\e13" "WIRED\e0" \e 391 "F\e14\e1\e0" \e 392 ":\e0" "FILE\e0" \e 393 ":\e1" "ANONYMOUS\e0" \e 394 "b\e15" "STACK\e0" \e 395 "F\e30\e010\e0" \e 396 ":\e000" "ALIGN=NONE\e0" \e 397 ":\e012" "ALIGN=1KB\e0" \e 398 ":\e013" "ALIGN=2KB\e0" \e 399 ":\e014" "ALIGN=4KB\e0" \e 400 ":\e015" "ALIGN=8KB\e0" \e 401 ":\e016" "ALIGN=16KB\e0" \e 402 ":\e017" "ALIGN=32KB\e0" \e 403 ":\e020" "ALIGN=64KB\e0" \e 404 ":\e021" "ALIGN=128KB\e0" \e 405 ":\e022" "ALIGN=256KB\e0" \e 406 ":\e023" "ALIGN=512KB\e0" \e 407 ":\e024" "ALIGN=1MB\e0" \e 408 ":\e025" "ALIGN=2MB\e0" \e 409 ":\e026" "ALIGN=4MB\e0" \e 410 ":\e027" "ALIGN=8MB\e0" \e 411 ":\e030" "ALIGN=16MB\e0" \e 412 ":\e034" "ALIGN=256MB\e0" \e 413 ":\e040" "ALIGN=4GB\e0" \e 414 ":\e044" "ALIGN=64GB\e0" \e 415 ":\e050" "ALIGN=1TB\e0" \e 416 ":\e054" "ALIGN=16TB\e0" \e 417 ":\e060" "ALIGN=256TB\e0" \e 418 ":\e064" "ALIGN=4PB\e0" \e 419 ":\e070" "ALIGN=64PB\e0" \e 420 ":\e074" "ALIGN=1EB\e0" \e 421 "*" "ALIGN=2^%ju\e0" 422 423snprintb(buf, bufsize, MAP_FMT, 0x0d001234) 424\(rA "0xd001234<COPY,FIXED,RENAME,HASSEMAPHORE,ANONYMOUS,ALIGN=8KB>" 425 426snprintb(buf, bufsize, MAP_FMT, 0x2e000000) 427\(rA "0x2e000000<FILE,ALIGN=2^46>" 428.Ed 429.Sh ERRORS 430.Fn snprintb 431will fail if: 432.Bl -tag -width Er 433.It Bq Er EINVAL 434The leading character 435.Po for the 436.Dq old 437format 438.Pc 439or the second character 440.Po for the 441.Dq new 442format 443.Pc 444does not describe a supported numeral base, 445or a bit number in the 446.Ar fmt 447argument is out of bounds, 448or the sequence of conversions in the 449.Ar fmt 450argument is invalid, 451or 452.Fn snprintf 453failed. 454.El 455.Sh SEE ALSO 456.Xr snprintf 3 457.Sh HISTORY 458The 459.Fn snprintb 460function was originally implemented as a non-standard 461.Li %b 462format string for the kernel 463.Fn printf 464function in 465.Nx 1.5 466and earlier releases. 467It was called 468.Fn bitmask_snprintf 469in 470.Nx 5.0 471and earlier releases. 472.Sh AUTHORS 473The 474.Dq new 475format was the invention of 476.An Chris Torek . 477.Sh CAVEATS 478When using hexadecimal character escapes for bit positions or field widths, 479if a following description starts with one of the letters A to F, 480that letter is considered part of the character escape. 481In such a situation, the character escape and the description must be 482put into separate string literals, as in 483.Li \[dq]\ex0f\[dq] \[dq]FIFTEEN\[dq] . 484