1 /* $NetBSD: snprintb.c,v 1.16 2014/08/02 11:19:01 ryo 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.16 2014/08/02 11:19:01 ryo Exp $");
47 # include <sys/types.h>
48 # include <inttypes.h>
52 # else /* ! _KERNEL */
53 # include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: snprintb.c,v 1.16 2014/08/02 11:19:01 ryo Exp $");
55 # include <sys/param.h>
56 # include <sys/inttypes.h>
57 # include <sys/systm.h>
58 # include <lib/libkern/libkern.h>
59 # endif /* ! _KERNEL */
61 # ifndef HAVE_SNPRINTB_M
63 snprintb_m(char *buf
, size_t buflen
, const char *bitfmt
, uint64_t val
,
66 char *bp
= buf
, *s_bp
= NULL
;
67 const char *c_fmt
, *s_fmt
= NULL
, *cur_fmt
;
69 int bit
, ch
, t_len
, s_len
= 0, l_len
, f_len
, v_len
, sep
;
75 * For safety; no other *s*printf() do this, but in the kernel
76 * we don't usually check the return value
78 (void)memset(buf
, 0, buflen
);
82 switch (ch
!= '\177' ? ch
: *bitfmt
++) {
96 /* Reserve space for trailing blank line if needed */
100 t_len
= snprintf(bp
, buflen
, sbase
, val
);
104 v_len
= l_len
= t_len
;
106 if ((size_t)t_len
< buflen
)
112 * If the value we printed was 0 and we're using the old-style format,
115 if ((val
== 0) && (ch
!= '\177'))
118 #define STORE(c) do { l_len++; \
119 if ((size_t)(++t_len) < buflen) \
121 } while ( /* CONSTCOND */ 0)
123 #define BACKUP do { if (s_bp != NULL) { \
124 bp = s_bp; s_bp = NULL; \
125 t_len -= l_len - s_len; \
129 STORE('>'); STORE('\0'); \
130 if ((size_t)t_len < buflen) \
131 snprintf(bp, buflen - t_len, sbase, val); \
132 t_len += v_len; l_len = v_len; bp += v_len; \
133 } while ( /* CONSTCOND */ 0)
135 #define PUTSEP do { \
136 if (l_max > 0 && (size_t)l_len >= l_max) { \
140 /* Remember separator location */ \
141 if (l_max > 0 && sep != '<') { \
149 } while ( /* CONSTCOND */ 0)
151 #define PUTCHR(c) do { \
152 if (l_max > 0 && (size_t)l_len >= (l_max - 1)) {\
162 } while ( /* CONSTCOND */ 0)
164 #define PUTS(s) while ((ch = *(s)++) != 0) { \
171 * Chris Torek's new bitmask format is identified by a leading \177
175 /* old (standard) format. */
176 for (;(bit
= *bitfmt
) != 0;) {
178 if (val
& (1 << (bit
- 1))) {
183 for (; (ch
= *bitfmt
) > ' '; ++bitfmt
) {
189 for (; *bitfmt
> ' '; ++bitfmt
)
193 /* new quad-capable format; also does fields. */
195 while (c_fmt
= bitfmt
, (ch
= *bitfmt
++) != '\0') {
196 bit
= *bitfmt
++; /* now 0-origin */
199 if (((unsigned int)(val
>> bit
) & 1) == 0)
212 f_len
= *bitfmt
++; /* field length */
213 field
= (val
>> bit
) &
214 (((uint64_t)1 << f_len
) - 1);
218 if (ch
== 'F') /* just extract */
225 f_len
= snprintf(bp
, buflen
- t_len
,
231 if ((size_t)t_len
< buflen
)
233 if (l_max
> 0 && (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
)
253 while (*bitfmt
++ != '\0')
260 if (sep
!= '<' && (size_t)(++t_len
) < buflen
)
277 snprintb(char *buf
, size_t buflen
, const char *bitfmt
, uint64_t val
)
279 return snprintb_m(buf
, buflen
, bitfmt
, val
, 0);
281 # endif /* ! HAVE_SNPRINTB_M */
282 #endif /* ! _STANDALONE */