1 /* $NetBSD: snprintb.c,v 1.5 2009/05/13 02:50:31 pgoyette Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 * snprintb: print an interpreted bitmask to a buffer
32 * => returns the length of the buffer that would be required to print the
33 * string minus the terminating NUL.
38 # if HAVE_NBTOOL_CONFIG_H
39 # include "nbtool_config.h"
42 # include <sys/cdefs.h>
43 # if defined(LIBC_SCCS) && !defined(lint)
44 __RCSID("$NetBSD: snprintb.c,v 1.5 2009/05/13 02:50:31 pgoyette Exp $");
47 # include <sys/types.h>
48 # include <sys/inttypes.h>
53 # include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: snprintb.c,v 1.5 2009/05/13 02:50:31 pgoyette Exp $");
55 # include <sys/param.h>
56 # include <sys/inttypes.h>
57 # include <sys/systm.h>
58 # include <lib/libkern/libkern.h>
62 snprintb_m(char *buf
, size_t buflen
, const char *bitfmt
, uint64_t val
,
65 char *bp
= buf
, *s_bp
= NULL
;
66 const char *c_fmt
, *s_fmt
= NULL
, *cur_fmt
;
68 int bit
, ch
, t_len
, s_len
= 0, l_len
, f_len
, v_len
, sep
;
74 * For safety; no other *s*printf() do this, but in the kernel
75 * we don't usually check the return value
77 (void)memset(buf
, 0, buflen
);
81 switch (ch
!= '\177' ? ch
: *bitfmt
++) {
95 /* Reserve space for trailing blank line if needed */
99 t_len
= snprintf(bp
, buflen
, sbase
, val
);
103 v_len
= l_len
= t_len
;
105 if ((size_t)t_len
< buflen
)
111 * If the value we printed was 0 and we're using the old-style format,
114 if ((val
== 0) && (ch
!= '\177'))
117 #define STORE(c) { l_len++; \
118 if ((size_t)(++t_len) < buflen) \
120 } while ( /* CONSTCOND */ 0)
122 #define BACKUP { if (s_bp != NULL) { \
123 bp = s_bp; s_bp = NULL; \
124 t_len -= l_len - s_len; \
128 STORE('>'); STORE('\0'); \
129 if ((size_t)t_len < buflen) \
130 snprintf(bp, buflen - t_len, sbase, val); \
131 t_len += v_len; l_len = v_len; bp += v_len; \
132 } while ( /* CONSTCOND */ 0)
135 if (l_max > 0 && (size_t)l_len >= l_max) { \
139 /* Remember separator location */ \
140 if ( l_max > 0 && sep != '<') { \
150 if (l_max > 0 && (size_t)l_len >= (l_max - 1)) { \
152 if (restart == 0) { \
161 #define PUTS(s) while ((ch = *(s)++) != 0) { \
168 * Chris Torek's new bitmask format is identified by a leading \177
172 /* old (standard) format. */
173 for (;(bit
= *bitfmt
) != 0;) {
175 if (val
& (1 << (bit
- 1))) {
180 for (; (ch
= *bitfmt
) > ' '; ++bitfmt
) {
186 for (; *bitfmt
> ' '; ++bitfmt
)
190 /* new quad-capable format; also does fields. */
192 while (c_fmt
= bitfmt
, (ch
= *bitfmt
++) != '\0') {
193 bit
= *bitfmt
++; /* now 0-origin */
196 if (((u_int
)(val
>> bit
) & 1) == 0)
209 f_len
= *bitfmt
++; /* field length */
210 field
= (val
>> bit
) &
211 (((uint64_t)1 << f_len
) - 1);
212 if (ch
== 'F') /* just extract */
223 f_len
= snprintf(bp
, buflen
- t_len
,
229 if ((size_t)t_len
< buflen
)
232 (size_t)l_len
> l_max
) {
240 * Here "bit" is actually a value instead,
241 * to be compared against the last field.
242 * This only works for values in [0..255],
245 if ((int)field
!= bit
)
254 while (*bitfmt
++ != '\0')
261 if ((size_t)(++t_len
) < buflen
)
278 snprintb(char *buf
, size_t buflen
, const char *bitfmt
, uint64_t val
)
280 return snprintb_m(buf
, buflen
, bitfmt
, val
, 0);