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;

Reply via email to