Module Name: src
Committed By: rillig
Date: Sat Feb 17 10:23:30 UTC 2024
Modified Files:
src/common/lib/libutil: snprintb.c
Log Message:
snprintb: convert macros to local functions
Let the compiler decide whether to inline the functions; allow stepping
through the code in a debugger.
To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/common/lib/libutil/snprintb.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/common/lib/libutil/snprintb.c
diff -u src/common/lib/libutil/snprintb.c:1.34 src/common/lib/libutil/snprintb.c:1.35
--- src/common/lib/libutil/snprintb.c:1.34 Fri Feb 16 21:25:46 2024
+++ src/common/lib/libutil/snprintb.c Sat Feb 17 10:23:30 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: snprintb.c,v 1.34 2024/02/16 21:25:46 rillig Exp $ */
+/* $NetBSD: snprintb.c,v 1.35 2024/02/17 10:23:30 rillig Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
# include <sys/cdefs.h>
# if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: snprintb.c,v 1.34 2024/02/16 21:25:46 rillig Exp $");
+__RCSID("$NetBSD: snprintb.c,v 1.35 2024/02/17 10:23:30 rillig Exp $");
# endif
# include <sys/types.h>
@@ -51,7 +51,7 @@ __RCSID("$NetBSD: snprintb.c,v 1.34 2024
# include <errno.h>
# else /* ! _KERNEL */
# include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: snprintb.c,v 1.34 2024/02/16 21:25:46 rillig Exp $");
+__KERNEL_RCSID(0, "$NetBSD: snprintb.c,v 1.35 2024/02/17 10:23:30 rillig Exp $");
# include <sys/param.h>
# include <sys/inttypes.h>
# include <sys/systm.h>
@@ -59,14 +59,204 @@ __KERNEL_RCSID(0, "$NetBSD: snprintb.c,v
# endif /* ! _KERNEL */
# ifndef HAVE_SNPRINTB_M
+typedef struct {
+ char *const buf;
+ size_t const bufsize;
+ const char *bitfmt;
+ uint64_t const val;
+ size_t const line_max;
+
+ const char *const num_fmt;
+ unsigned const val_len;
+ unsigned total_len;
+ unsigned line_len;
+
+ const char *cur_bitfmt;
+ int restart;
+
+ const char *sep_bitfmt;
+ unsigned sep_line_len;
+ char sep;
+} state;
+
+static void
+store(state *s, char c)
+{
+ if (s->total_len < s->bufsize)
+ s->buf[s->total_len] = c;
+ s->total_len++;
+ s->line_len++;
+}
+
+static void
+backup(state *s)
+{
+ if (s->sep_line_len > 0) {
+ s->total_len -= s->line_len - s->sep_line_len;
+ s->sep_line_len = 0;
+ s->restart = 1;
+ s->bitfmt = s->sep_bitfmt;
+ }
+ store(s, '>');
+ store(s, '\0');
+ if (s->total_len < s->bufsize)
+ snprintf(s->buf + s->total_len, s->bufsize - s->total_len,
+ s->num_fmt, (uintmax_t)s->val);
+ s->total_len += s->val_len;
+ s->line_len = s->val_len;
+}
+
+static void
+put_sep(state *s)
+{
+ if (s->line_max > 0 && s->line_len >= s->line_max) {
+ backup(s);
+ store(s, '<');
+ } else {
+ if (s->line_max > 0 && s->sep != '<') {
+ s->sep_line_len = s->line_len;
+ s->sep_bitfmt = s->cur_bitfmt;
+ }
+ store(s, s->sep);
+ s->restart = 0;
+ }
+}
+
+static void
+put_chr(state *s, char c)
+{
+ if (s->line_max > 0 && s->line_len >= s->line_max - 1) {
+ backup(s);
+ if (s->restart == 0)
+ store(s, c);
+ else
+ s->sep = '<';
+ } else {
+ store(s, c);
+ s->restart = 0;
+ }
+}
+
+static void
+put_bitfmt(state *s)
+{
+ while (*s->bitfmt++ != 0) {
+ put_chr(s, s->bitfmt[-1]);
+ if (s->restart)
+ break;
+ }
+}
+
+static int
+put_num(state *s, const char *fmt, uintmax_t v)
+{
+ char *bp = s->total_len < s->bufsize ? s->buf + s->total_len : NULL;
+ size_t n = s->total_len < s->bufsize ? s->bufsize - s->total_len : 0;
+ int fmt_len = snprintf(bp, n, fmt, v);
+ if (fmt_len >= 0) {
+ s->total_len += fmt_len;
+ s->line_len += fmt_len;
+ }
+ return fmt_len;
+}
+
+static void
+old_style(state *s)
+{
+ for (uint8_t bit; (bit = *s->bitfmt) != 0;) {
+ s->cur_bitfmt = s->bitfmt++;
+ if (s->val & (1U << (bit - 1))) {
+ put_sep(s);
+ if (s->restart)
+ continue;
+ s->sep = ',';
+ for (; *s->bitfmt > ' '; ++s->bitfmt) {
+ put_chr(s, *s->bitfmt);
+ if (s->restart)
+ break;
+ }
+ } else
+ for (; *s->bitfmt > ' '; ++s->bitfmt)
+ continue;
+ }
+}
+
+static int
+new_style(state *s)
+{
+ uint64_t field = s->val;
+ int matched = 1;
+ while (*s->bitfmt != '\0') {
+ uint8_t kind = *s->bitfmt++;
+ uint8_t bit = *s->bitfmt++;
+ switch (kind) {
+ case 'b':
+ if (((s->val >> bit) & 1) == 0)
+ goto skip;
+ s->cur_bitfmt = s->bitfmt - 2;
+ put_sep(s);
+ if (s->restart)
+ break;
+ put_bitfmt(s);
+ if (s->restart == 0)
+ s->sep = ',';
+ break;
+ case 'f':
+ case 'F':
+ matched = 0;
+ s->cur_bitfmt = s->bitfmt - 2;
+ uint8_t field_width = *s->bitfmt++;
+ field = (s->val >> bit) &
+ (((uint64_t)1 << field_width) - 1);
+ put_sep(s);
+ if (s->restart == 0)
+ s->sep = ',';
+ if (kind == 'F')
+ goto skip;
+ if (s->restart == 0)
+ put_bitfmt(s);
+ if (s->restart == 0)
+ put_chr(s, '=');
+ if (s->restart == 0) {
+ if (put_num(s, s->num_fmt, field) < 0)
+ return -1;
+ if (s->line_max > 0
+ && s->line_len > s->line_max)
+ put_chr(s, '#');
+ }
+ break;
+ case '=':
+ case ':':
+ /* Here "bit" is actually a value instead. */
+ if (field != bit)
+ goto skip;
+ matched = 1;
+ if (kind == '=')
+ put_chr(s, '=');
+ put_bitfmt(s);
+ break;
+ case '*':
+ s->bitfmt--;
+ if (!matched) {
+ matched = 1;
+ if (put_num(s, s->bitfmt, field) < 0)
+ return -1;
+ }
+ /*FALLTHROUGH*/
+ default:
+ skip:
+ while (*s->bitfmt++ != '\0')
+ continue;
+ break;
+ }
+ }
+ return 0;
+}
+
int
snprintb_m(char *buf, size_t bufsize, const char *bitfmt, uint64_t val,
size_t line_max)
{
- const char *num_fmt, *cur_bitfmt, *sep_bitfmt = NULL;
- char sep;
- int restart = 0;
-
#ifdef _KERNEL
/*
* For safety; no other *s*printf() do this, but in the kernel
@@ -75,9 +265,12 @@ snprintb_m(char *buf, size_t bufsize, co
(void)memset(buf, 0, bufsize);
#endif /* _KERNEL */
- int old_style = *bitfmt != '\177';
- if (!old_style)
+
+ int old = *bitfmt != '\177';
+ if (!old)
bitfmt++;
+
+ const char *num_fmt;
switch (*bitfmt++) {
case 8:
num_fmt = "%#jo";
@@ -96,182 +289,37 @@ snprintb_m(char *buf, size_t bufsize, co
if (val_len < 0)
goto internal;
- size_t total_len = val_len, line_len = val_len, sep_line_len = 0;
+ state s = {
+ .buf = buf,
+ .bufsize = bufsize,
+ .bitfmt = bitfmt,
+ .val = val,
+ .line_max = line_max,
+
+ .num_fmt = num_fmt,
+ .val_len = val_len,
+ .total_len = val_len,
+ .line_len = val_len,
+
+ .sep = '<',
+ };
+
+ if (old)
+ old_style(&s);
+ else if (new_style(&s) < 0)
+ goto internal;
-#define STORE(c) do { \
- if (total_len < bufsize) \
- buf[total_len] = (c); \
- total_len++; \
- line_len++; \
- } while (0)
-
-#define BACKUP() do { \
- if (sep_line_len > 0) { \
- total_len -= line_len - sep_line_len; \
- sep_line_len = 0; \
- restart = 1; \
- bitfmt = sep_bitfmt; \
- } \
- STORE('>'); \
- STORE('\0'); \
- if (total_len < bufsize) \
- snprintf(buf + total_len, bufsize - total_len, \
- num_fmt, (uintmax_t)val); \
- total_len += val_len; \
- line_len = val_len; \
- } while (0)
-
-#define PUTSEP() do { \
- if (line_max > 0 && line_len >= line_max) { \
- BACKUP(); \
- STORE('<'); \
- } else { \
- if (line_max > 0 && sep != '<') { \
- sep_line_len = line_len; \
- sep_bitfmt = cur_bitfmt; \
- } \
- STORE(sep); \
- restart = 0; \
- } \
- } while (0)
-
-#define PUTCHR(c) do { \
- if (line_max > 0 && line_len >= line_max - 1) { \
- BACKUP(); \
- if (restart == 0) \
- STORE(c); \
- else \
- sep = '<'; \
- } else { \
- STORE(c); \
- restart = 0; \
- } \
- } while (0)
-
-#define PUTS(s) do { \
- while ((*(s)++) != 0) { \
- PUTCHR((s)[-1]); \
- if (restart) \
- break; \
- } \
- } while (0)
-
-#define FMTSTR(sb, f) do { \
- char *bp = total_len < bufsize ? buf + total_len : NULL; \
- size_t n = total_len < bufsize ? bufsize - total_len : 0; \
- int fmt_len = snprintf(bp, n, sb, (uintmax_t)f); \
- if (fmt_len < 0) \
- goto internal; \
- total_len += fmt_len; \
- line_len += fmt_len; \
- } while (0)
-
- sep = '<';
- if (old_style) {
- /* old-style format, 32-bit, 1-origin. */
- for (uint8_t bit; (bit = *bitfmt) != 0;) {
- cur_bitfmt = bitfmt++;
- if (val & (1U << (bit - 1))) {
- PUTSEP();
- if (restart)
- continue;
- sep = ',';
- for (; *bitfmt > ' '; ++bitfmt) {
- PUTCHR(*bitfmt);
- if (restart)
- break;
- }
- } else
- for (; *bitfmt > ' '; ++bitfmt)
- continue;
- }
- } else {
- /* new-style format, 64-bit, 0-origin; also does fields. */
- uint64_t field = val;
- int matched = 1;
- while (*bitfmt != '\0') {
- uint8_t kind = *bitfmt++;
- uint8_t bit = *bitfmt++;
- switch (kind) {
- case 'b':
- if (((val >> bit) & 1) == 0)
- goto skip;
- cur_bitfmt = bitfmt - 2;
- PUTSEP();
- if (restart)
- break;
- PUTS(bitfmt);
- if (restart == 0)
- sep = ',';
- break;
- case 'f':
- case 'F':
- matched = 0;
- cur_bitfmt = bitfmt - 2;
- uint8_t field_width = *bitfmt++;
- field = (val >> bit) &
- (((uint64_t)1 << field_width) - 1);
- PUTSEP();
- if (restart == 0)
- sep = ',';
- if (kind == 'F') { /* just extract */
- /* duplicate PUTS() effect on bitfmt */
- while (*bitfmt++ != '\0')
- continue;
- break;
- }
- if (restart == 0)
- PUTS(bitfmt);
- if (restart == 0)
- PUTCHR('=');
- if (restart == 0) {
- FMTSTR(num_fmt, field);
- if (line_max > 0
- && line_len > line_max)
- PUTCHR('#');
- }
- break;
- case '=':
- case ':':
- /*
- * Here "bit" is actually a value instead,
- * to be compared against the last field.
- * This only works for values in [0..255],
- * of course.
- */
- if (field != bit)
- goto skip;
- matched = 1;
- if (kind == '=')
- PUTCHR('=');
- PUTS(bitfmt);
- break;
- case '*':
- bitfmt--;
- if (!matched) {
- matched = 1;
- FMTSTR(bitfmt, field);
- }
- /*FALLTHROUGH*/
- default:
- skip:
- while (*bitfmt++ != '\0')
- continue;
- break;
- }
- }
- }
- if (sep != '<')
- STORE('>');
- if (line_max > 0) {
- STORE('\0');
- if (bufsize >= 2 && total_len > bufsize - 2)
- buf[bufsize - 2] = '\0';
+ if (s.sep != '<')
+ store(&s, '>');
+ if (s.line_max > 0) {
+ store(&s, '\0');
+ if (s.bufsize >= 2 && s.total_len > s.bufsize - 2)
+ s.buf[s.bufsize - 2] = '\0';
}
- STORE('\0');
- if (bufsize >= 1 && total_len > bufsize - 1)
- buf[bufsize - 1] = '\0';
- return (int)(total_len - 1);
+ store(&s, '\0');
+ if (s.bufsize >= 1 && s.total_len > s.bufsize - 1)
+ s.buf[s.bufsize - 1] = '\0';
+ return (int)(s.total_len - 1);
internal:
#ifndef _KERNEL
errno = EINVAL;