tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Enhancements to snprintb(3)
A few days ago, I suggested that snprintb(3) could be enhanced to
produce multiple strings, each of which was not longer than some
user-provided maximum length. My initial thought was to make multiple
calls to snprintb(3), and update an argument with the set of bits that
were processed. (Thinking that once all bits were processed, we could
simply stop calling.)
That approach actually doesn't work well, since there's nothing in the
rules that prevents the formatting string to reference a bit more than
once, and in any order. Additionally, with the new-format, bits and
bit-fields can be referenced multiple times, and can overlap each other
with impugnity.
An alternate suggestion was made to simply return multiple strings from
a single call to snprintb_m(3) (the _m suffix for "multiple"). The
attached diffs implement this type of change, and includes updates to
the man page, a bump in libutil's shared library version, and related
updates to the src/distrib/ set-lists. I'd appreciate any feedback or
other comments.
I'd like to commit this early next week (like Monday or Tuesday), since
I've got some updates to usr.sbin/cpuctl that depend on this.
-------------------------------------------------------------------------
| Paul Goyette | PGP DSS Key fingerprint: | E-mail addresses: |
| Customer Service | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com |
| Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net |
| Kernel Developer | | pgoyette at netbsd.org |
-------------------------------------------------------------------------
Index: snprintb.c
===================================================================
RCS file: /cvsroot/src/common/lib/libutil/snprintb.c,v
retrieving revision 1.4
diff -u -p -r1.4 snprintb.c
--- snprintb.c 18 Jan 2009 12:05:49 -0000 1.4
+++ snprintb.c 6 May 2009 20:49:41 -0000
@@ -59,11 +59,14 @@ __KERNEL_RCSID(0, "$NetBSD: snprintb.c,v
# endif
int
-snprintb(char *buf, size_t buflen, const char *bitfmt, uint64_t val)
+snprintb_m(char *buf, size_t buflen, const char *bitfmt, uint64_t val,
+ size_t l_max)
{
- char *bp = buf;
+ char *bp = buf, *s_bp = NULL;
+ const char *c_fmt, *s_fmt = NULL, *cur_fmt;
const char *sbase;
- int bit, ch, len, sep, flen;
+ int bit, ch, t_len, s_len = 0, l_len, f_len, v_len, sep;
+ int restart = 0;
uint64_t field;
#ifdef _KERNEL
@@ -89,12 +92,18 @@ snprintb(char *buf, size_t buflen, const
goto internal;
}
- len = snprintf(bp, buflen, sbase, val);
- if (len < 0)
+ /* Reserve space for trailing blank line if needed */
+ if (l_max > 0)
+ buflen--;
+
+ t_len = snprintf(bp, buflen, sbase, val);
+ if (t_len < 0)
goto internal;
- if ((size_t)len < buflen)
- bp += len;
+ v_len = l_len = t_len;
+
+ if ((size_t)t_len < buflen)
+ bp += t_len;
else
bp += buflen - 1;
@@ -105,8 +114,55 @@ snprintb(char *buf, size_t buflen, const
if ((val == 0) && (ch != '\177'))
goto terminate;
-#define PUTC(c) if ((size_t)(++len) < buflen) *bp++ = (c)
-#define PUTS(s) while ((ch = *(s)++) != 0) PUTC(ch)
+#define STORE(c) { l_len++; \
+ if ((size_t)(++t_len) < buflen) \
+ *bp++ = (c); \
+ } while ( /* CONSTCOND */ 0)
+
+#define BACKUP { if (s_bp != NULL) {
\
+ bp = s_bp; s_bp = NULL; \
+ t_len -= l_len - s_len; \
+ restart = 1; \
+ bitfmt = s_fmt; \
+ } \
+ STORE('>'); STORE('\0'); \
+ if ((size_t)t_len < buflen) \
+ snprintf(bp, buflen - t_len, sbase, val); \
+ t_len += v_len; l_len = v_len; bp += v_len; \
+ } while ( /* CONSTCOND */ 0)
+
+#define PUTSEP
\
+ if (l_max > 0 && (size_t)l_len >= l_max) { \
+ BACKUP; \
+ STORE('<'); \
+ } else { \
+ /* Remember separator location */ \
+ if ( l_max > 0 && sep != '<') { \
+ s_len = l_len; \
+ s_bp = bp; \
+ s_fmt = cur_fmt; \
+ } \
+ STORE(sep); \
+ restart = 0; \
+ } \
+
+#define PUTCHR(c)
\
+ if (l_max > 0 && (size_t)l_len >= (l_max - 1)) { \
+ BACKUP; \
+ if (restart == 0) { \
+ STORE(c); \
+ } else \
+ sep = '<'; \
+ } else { \
+ STORE(c); \
+ restart = 0; \
+ } \
+
+#define PUTS(s) while ((ch = *(s)++) != 0) { \
+ PUTCHR(ch); \
+ if (restart) \
+ break; \
+ }
/*
* Chris Torek's new bitmask format is identified by a leading \177
@@ -114,12 +170,18 @@ snprintb(char *buf, size_t buflen, const
sep = '<';
if (ch != '\177') {
/* old (standard) format. */
- for (;(bit = *bitfmt++) != 0;) {
+ for (;(bit = *bitfmt) != 0;) {
+ cur_fmt = bitfmt++;
if (val & (1 << (bit - 1))) {
- PUTC(sep);
- for (; (ch = *bitfmt) > ' '; ++bitfmt)
- PUTC(ch);
+ PUTSEP;
+ if (restart)
+ continue;
sep = ',';
+ for (; (ch = *bitfmt) > ' '; ++bitfmt) {
+ PUTCHR(ch);
+ if (restart)
+ break;
+ }
} else
for (; *bitfmt > ' '; ++bitfmt)
continue;
@@ -127,33 +189,50 @@ snprintb(char *buf, size_t buflen, const
} else {
/* new quad-capable format; also does fields. */
field = val;
- while ((ch = *bitfmt++) != '\0') {
+ while (c_fmt = bitfmt, (ch = *bitfmt++) != '\0') {
bit = *bitfmt++; /* now 0-origin */
switch (ch) {
case 'b':
if (((u_int)(val >> bit) & 1) == 0)
goto skip;
- PUTC(sep);
+ cur_fmt = c_fmt;
+ PUTSEP;
+ if (restart)
+ break;
PUTS(bitfmt);
- sep = ',';
+ if (restart == 0)
+ sep = ',';
break;
case 'f':
case 'F':
- flen = *bitfmt++; /* field length */
+ cur_fmt = c_fmt;
+ f_len = *bitfmt++; /* field length */
field = (val >> bit) &
- (((uint64_t)1 << flen) - 1);
+ (((uint64_t)1 << f_len) - 1);
if (ch == 'F') /* just extract */
break;
- PUTC(sep);
- sep = ',';
- PUTS(bitfmt);
- PUTC('=');
- flen = snprintf(bp, buflen - len, sbase, field);
- if (flen < 0)
- goto internal;
- len += flen;
- if ((size_t)len < buflen)
- bp += flen;
+ PUTSEP;
+ if (restart == 0) {
+ sep = ',';
+ PUTS(bitfmt);
+ }
+ if (restart == 0) {
+ PUTCHR('=');
+ }
+ if (restart == 0) {
+ f_len = snprintf(bp, buflen - t_len,
+ sbase, field);
+ if (f_len < 0)
+ goto internal;
+ t_len += f_len;
+ l_len += f_len;
+ if ((size_t)t_len < buflen)
+ bp += f_len;
+ if (l_max > 0 &&
+ (size_t)l_len > l_max) {
+ PUTCHR('#');
+ }
+ }
break;
case '=':
case ':':
@@ -166,7 +245,7 @@ snprintb(char *buf, size_t buflen, const
if ((int)field != bit)
goto skip;
if (ch == '=') {
- PUTC('=');
+ PUTCHR('=');
}
PUTS(bitfmt);
break;
@@ -178,16 +257,26 @@ snprintb(char *buf, size_t buflen, const
}
}
}
- if (sep != '<') {
- PUTC('>');
- }
+ l_len++;
+ if ((size_t)(++t_len) < buflen)
+ *bp++ = '>';
terminate:
- *bp = '\0';
- return len;
+ *bp++ = '\0';
+ if (l_max != 0) {
+ t_len++;
+ *bp = '\0';
+ }
+ return t_len;
internal:
#ifndef _KERNEL
errno = EINVAL;
#endif
return -1;
}
+
+int
+snprintb(char *buf, size_t buflen, const char *bitfmt, uint64_t val)
+{
+ return snprintb_m(buf, buflen, bitfmt, val, 0);
+}
#endif
Index: md.amd64
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/md.amd64,v
retrieving revision 1.45
diff -u -p -r1.45 md.amd64
--- md.amd64 2 May 2009 02:20:20 -0000 1.45
+++ md.amd64 6 May 2009 20:49:41 -0000
@@ -201,7 +201,7 @@
./usr/lib/i386/libusbhid.so.1 base-compat-shlib
compat,pic
./usr/lib/i386/libusbhid.so.1.0 base-compat-shlib
compat,pic
./usr/lib/i386/libutil.so.7 base-compat-shlib
compat,pic
-./usr/lib/i386/libutil.so.7.16 base-compat-shlib
compat,pic
+./usr/lib/i386/libutil.so.7.17 base-compat-shlib
compat,pic
./usr/lib/i386/libwrap.so.1 base-compat-shlib
compat,pic
./usr/lib/i386/libwrap.so.1.0 base-compat-shlib
compat,pic
./usr/lib/i386/libz.so.1 base-compat-shlib
compat,pic
Index: shl.mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/shl.mi,v
retrieving revision 1.469
diff -u -p -r1.469 shl.mi
--- shl.mi 2 May 2009 01:15:54 -0000 1.469
+++ shl.mi 6 May 2009 20:49:42 -0000
@@ -27,7 +27,7 @@
./lib/libradius.so.3.0 base-sys-shlib
dynamicroot
./lib/libtermcap.so.0.6 base-sys-shlib
dynamicroot
./lib/libtermlib.so.0.6 base-sys-shlib
dynamicroot
-./lib/libutil.so.7.16 base-sys-shlib
dynamicroot
+./lib/libutil.so.7.17 base-sys-shlib
dynamicroot
./lib/libz.so.1.0 base-sys-shlib
dynamicroot
./usr/lib/i18n/libBIG5.so.5.0 base-i18n-shlib
./usr/lib/i18n/libDECHanyu.so.5.0 base-i18n-shlib
@@ -153,7 +153,7 @@
./usr/lib/libtermlib.so.0.6 base-sys-shlib
./usr/lib/libukfs.so.1.0 base-sys-shlib
./usr/lib/libusbhid.so.1.0 base-sys-shlib
-./usr/lib/libutil.so.7.16 base-sys-shlib
+./usr/lib/libutil.so.7.17 base-sys-shlib
./usr/lib/libwrap.so.1.0 base-net-shlib
./usr/lib/libz.so.1.0 base-sys-shlib
./usr/lib/security/pam_afslog.so.2 base-sys-shlib
kerberos,pam
Index: mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v
retrieving revision 1.1252
diff -u -p -r1.1252 mi
--- mi 4 May 2009 21:33:00 -0000 1.1252
+++ mi 6 May 2009 20:49:45 -0000
@@ -7471,6 +7471,7 @@
./usr/share/man/cat3/sl_init.0 comp-c-catman .cat
./usr/share/man/cat3/sleep.0 comp-c-catman .cat
./usr/share/man/cat3/snprintb.0 comp-c-catman
.cat
+./usr/share/man/cat3/snprintb_m.0 comp-c-catman .cat
./usr/share/man/cat3/snprintf.0 comp-c-catman
.cat
./usr/share/man/cat3/sockaddr_snprintf.0 comp-c-catman .cat
./usr/share/man/cat3/sockatmark.0 comp-c-catman .cat
@@ -12783,6 +12784,7 @@
./usr/share/man/html3/sl_init.html comp-c-htmlman html
./usr/share/man/html3/sleep.html comp-c-htmlman html
./usr/share/man/html3/snprintb.html comp-c-htmlman html
+./usr/share/man/html3/snprintb_m.html comp-c-htmlman html
./usr/share/man/html3/snprintf.html comp-c-htmlman html
./usr/share/man/html3/sockaddr_snprintf.html comp-c-htmlman html
./usr/share/man/html3/sockatmark.html comp-c-htmlman html
@@ -18134,6 +18136,7 @@
./usr/share/man/man3/sl_init.3 comp-c-man .man
./usr/share/man/man3/sleep.3 comp-c-man .man
./usr/share/man/man3/snprintb.3 comp-c-man
.man
+./usr/share/man/man3/snprintb_m.3 comp-c-man .man
./usr/share/man/man3/snprintf.3 comp-c-man
.man
./usr/share/man/man3/sockaddr_snprintf.3 comp-c-man .man
./usr/share/man/man3/sockatmark.3 comp-c-man .man
Index: mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.1135
diff -u -p -r1.1135 mi
--- mi 1 May 2009 22:59:53 -0000 1.1135
+++ mi 6 May 2009 20:49:47 -0000
@@ -1360,6 +1360,7 @@
./usr/share/man/cat4/scsi.0 man-sys-catman .cat
./usr/share/man/cat4/scsibus.0 man-sys-catman .cat
./usr/share/man/cat4/sd.0 man-sys-catman .cat
+./usr/share/man/cat4/sdtemp.0 man-sys-catman .cat
./usr/share/man/cat4/se.0 man-sys-catman .cat
./usr/share/man/cat4/sea.0 man-sys-catman .cat
./usr/share/man/cat4/sec.0 man-sys-catman .cat
@@ -3888,6 +3889,7 @@
./usr/share/man/html4/scsi.html man-sys-htmlman
html
./usr/share/man/html4/scsibus.html man-sys-htmlman html
./usr/share/man/html4/sd.html man-sys-htmlman html
+./usr/share/man/html4/sdtemp.html man-sys-htmlman html
./usr/share/man/html4/se.html man-sys-htmlman html
./usr/share/man/html4/sea.html man-sys-htmlman html
./usr/share/man/html4/sec.html man-sys-htmlman html
@@ -6328,6 +6330,7 @@
./usr/share/man/man4/scsi.4 man-sys-man .man
./usr/share/man/man4/scsibus.4 man-sys-man .man
./usr/share/man/man4/sd.4 man-sys-man .man
+./usr/share/man/man4/sdtemp.4 man-sys-man .man
./usr/share/man/man4/se.4 man-sys-man .man
./usr/share/man/man4/sea.4 man-sys-man .man
./usr/share/man/man4/sec.4 man-sys-man .man
Index: util.h
===================================================================
RCS file: /cvsroot/src/include/util.h,v
retrieving revision 1.50
diff -u -p -r1.50 util.h
--- util.h 11 Jan 2009 03:04:12 -0000 1.50
+++ util.h 6 May 2009 20:49:48 -0000
@@ -115,6 +115,7 @@ void pw_prompt(void);
int pw_setprefix(const char *);
int raise_default_signal(int);
int secure_path(const char *);
+int snprintb_m(char *, size_t, const char *, uint64_t, size_t);
int snprintb(char *, size_t, const char *, uint64_t);
int sockaddr_snprintf(char *, size_t, const char *,
const struct sockaddr *);
Index: Makefile
===================================================================
RCS file: /cvsroot/src/lib/libutil/Makefile,v
retrieving revision 1.60
diff -u -p -r1.60 Makefile
--- Makefile 18 Jan 2009 12:13:32 -0000 1.60
+++ Makefile 6 May 2009 20:49:48 -0000
@@ -77,5 +77,6 @@ MLINKS+=efun.3 efopen.3
MLINKS+=efun.3 evasprintf.3
MLINKS+=stat_flags.3 string_to_flags.3
MLINKS+=stat_flags.3 flags_to_string.3
+MLINKS+=snprintb.3 snprintb_m.3
.include <bsd.lib.mk>
Index: shlib_version
===================================================================
RCS file: /cvsroot/src/lib/libutil/shlib_version,v
retrieving revision 1.46
diff -u -p -r1.46 shlib_version
--- shlib_version 11 Jan 2009 02:57:18 -0000 1.46
+++ shlib_version 6 May 2009 20:49:49 -0000
@@ -2,4 +2,4 @@
# Remember to update distrib/sets/lists/base/shl.* when changing
#
major=7
-minor=16
+minor=17
Index: snprintb.3
===================================================================
RCS file: /cvsroot/src/lib/libutil/snprintb.3,v
retrieving revision 1.13
diff -u -p -r1.13 snprintb.3
--- snprintb.3 5 May 2009 13:12:25 -0000 1.13
+++ snprintb.3 6 May 2009 20:49:50 -0000
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 5, 2009
+.Dd May 7, 2009
.Dt SNPRINTB 3
.Os
.Sh NAME
@@ -38,7 +38,10 @@
.Sh SYNOPSIS
.In util.h
.Ft int
-.Fn "snprintb" "char *buf" "size_t buflen" "const char *fmt" "uint_t val"
+.Fn "snprintb" "char *buf" "size_t buflen" "const char *fmt" "uint64_t val"
+.Ft int
+.Fn "snprintb_m" "char *buf" "size_t buflen" "const char *fmt" "uint64_t val" \
+"size_t max"
.Sh DESCRIPTION
The
.Fn snprintb
@@ -181,12 +184,43 @@ character.
By convention, the format string has an additional NUL character at
the end, following that delimiting the last bit-position\(endescription
pair.
+.Pp
+The
+.Fn snprintb_m
+function accepts an additional
+.Fa max
+argument.
+If this argument is zero, the
+.Fn snprintb_m
+function returns exactly the same results in the
+.Fa buf
+as the
+.Fn snprintb
+function.
+If the
+.Fa max
+argument is present and has a non-zero value, it represents the maximum
+length of a formatted string.
+If the formatted string would require more than
+.Fa max
+characters, the
+.Fn snprintb_m
+function returns multiple formatted strings in the output buffer
+.Fa buf .
+Each string is NUL-terminated, and the last string is followed by an
+additional NUL character (or, if you prefer, a zero-length string).
.Sh RETURN VALUES
The
.Fn snprintb
-function returns the number of bytes that would have written to the buffer
-if there was adequate space, excluding the terminating NUL, or \-1 in case
-an error occurred.
+and
+.Fn snprintb_m
+functions return the number of bytes that would have written to the buffer
+if there was adequate space, excluding the final terminating NUL, or \-1 in
+case an error occurred.
+For
+.Fn snprintb_m ,
+the NUL characters terminating each individual string are included in the
+total number of bytes.
.Sh EXAMPLES
Two examples of the old formatting style:
.Bd -literal -offset indent
Home |
Main Index |
Thread Index |
Old Index