xref: /linux/fs/bcachefs/printbuf.c (revision 560661d4ae067276c14bf0dc89fdd0228f993150)
1401ec4dbSKent Overstreet // SPDX-License-Identifier: LGPL-2.1+
2401ec4dbSKent Overstreet /* Copyright (C) 2022 Kent Overstreet */
3401ec4dbSKent Overstreet 
4*560661d4SKent Overstreet #include <linux/bitmap.h>
5401ec4dbSKent Overstreet #include <linux/err.h>
6401ec4dbSKent Overstreet #include <linux/export.h>
7401ec4dbSKent Overstreet #include <linux/kernel.h>
8401ec4dbSKent Overstreet #include <linux/slab.h>
9401ec4dbSKent Overstreet #include <linux/string_helpers.h>
10401ec4dbSKent Overstreet 
11401ec4dbSKent Overstreet #include "printbuf.h"
12401ec4dbSKent Overstreet 
13401ec4dbSKent Overstreet static inline unsigned printbuf_linelen(struct printbuf *buf)
14401ec4dbSKent Overstreet {
15401ec4dbSKent Overstreet 	return buf->pos - buf->last_newline;
16401ec4dbSKent Overstreet }
17401ec4dbSKent Overstreet 
18401ec4dbSKent Overstreet int bch2_printbuf_make_room(struct printbuf *out, unsigned extra)
19401ec4dbSKent Overstreet {
20401ec4dbSKent Overstreet 	unsigned new_size;
21401ec4dbSKent Overstreet 	char *buf;
22401ec4dbSKent Overstreet 
23401ec4dbSKent Overstreet 	if (!out->heap_allocated)
24401ec4dbSKent Overstreet 		return 0;
25401ec4dbSKent Overstreet 
26401ec4dbSKent Overstreet 	/* Reserved space for terminating nul: */
27401ec4dbSKent Overstreet 	extra += 1;
28401ec4dbSKent Overstreet 
29401ec4dbSKent Overstreet 	if (out->pos + extra < out->size)
30401ec4dbSKent Overstreet 		return 0;
31401ec4dbSKent Overstreet 
32401ec4dbSKent Overstreet 	new_size = roundup_pow_of_two(out->size + extra);
33401ec4dbSKent Overstreet 
34401ec4dbSKent Overstreet 	/*
35401ec4dbSKent Overstreet 	 * Note: output buffer must be freeable with kfree(), it's not required
36401ec4dbSKent Overstreet 	 * that the user use printbuf_exit().
37401ec4dbSKent Overstreet 	 */
38401ec4dbSKent Overstreet 	buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT);
39401ec4dbSKent Overstreet 
40401ec4dbSKent Overstreet 	if (!buf) {
41401ec4dbSKent Overstreet 		out->allocation_failure = true;
42401ec4dbSKent Overstreet 		return -ENOMEM;
43401ec4dbSKent Overstreet 	}
44401ec4dbSKent Overstreet 
45401ec4dbSKent Overstreet 	out->buf	= buf;
46401ec4dbSKent Overstreet 	out->size	= new_size;
47401ec4dbSKent Overstreet 	return 0;
48401ec4dbSKent Overstreet }
49401ec4dbSKent Overstreet 
50401ec4dbSKent Overstreet void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
51401ec4dbSKent Overstreet {
52401ec4dbSKent Overstreet 	int len;
53401ec4dbSKent Overstreet 
54401ec4dbSKent Overstreet 	do {
55401ec4dbSKent Overstreet 		va_list args2;
56401ec4dbSKent Overstreet 
57401ec4dbSKent Overstreet 		va_copy(args2, args);
58401ec4dbSKent Overstreet 		len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args2);
59401ec4dbSKent Overstreet 	} while (len + 1 >= printbuf_remaining(out) &&
60401ec4dbSKent Overstreet 		 !bch2_printbuf_make_room(out, len + 1));
61401ec4dbSKent Overstreet 
62401ec4dbSKent Overstreet 	len = min_t(size_t, len,
63401ec4dbSKent Overstreet 		  printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
64401ec4dbSKent Overstreet 	out->pos += len;
65401ec4dbSKent Overstreet }
66401ec4dbSKent Overstreet 
67401ec4dbSKent Overstreet void bch2_prt_printf(struct printbuf *out, const char *fmt, ...)
68401ec4dbSKent Overstreet {
69401ec4dbSKent Overstreet 	va_list args;
70401ec4dbSKent Overstreet 	int len;
71401ec4dbSKent Overstreet 
72401ec4dbSKent Overstreet 	do {
73401ec4dbSKent Overstreet 		va_start(args, fmt);
74401ec4dbSKent Overstreet 		len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args);
75401ec4dbSKent Overstreet 		va_end(args);
76401ec4dbSKent Overstreet 	} while (len + 1 >= printbuf_remaining(out) &&
77401ec4dbSKent Overstreet 		 !bch2_printbuf_make_room(out, len + 1));
78401ec4dbSKent Overstreet 
79401ec4dbSKent Overstreet 	len = min_t(size_t, len,
80401ec4dbSKent Overstreet 		  printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
81401ec4dbSKent Overstreet 	out->pos += len;
82401ec4dbSKent Overstreet }
83401ec4dbSKent Overstreet 
84401ec4dbSKent Overstreet /**
8596dea3d5SKent Overstreet  * bch2_printbuf_str() - returns printbuf's buf as a C string, guaranteed to be
8696dea3d5SKent Overstreet  * null terminated
8796dea3d5SKent Overstreet  * @buf:	printbuf to terminate
8896dea3d5SKent Overstreet  * Returns:	Printbuf contents, as a nul terminated C string
89401ec4dbSKent Overstreet  */
90401ec4dbSKent Overstreet const char *bch2_printbuf_str(const struct printbuf *buf)
91401ec4dbSKent Overstreet {
92401ec4dbSKent Overstreet 	/*
93401ec4dbSKent Overstreet 	 * If we've written to a printbuf then it's guaranteed to be a null
94401ec4dbSKent Overstreet 	 * terminated string - but if we haven't, then we might not have
95401ec4dbSKent Overstreet 	 * allocated a buffer at all:
96401ec4dbSKent Overstreet 	 */
97401ec4dbSKent Overstreet 	return buf->pos
98401ec4dbSKent Overstreet 		? buf->buf
99401ec4dbSKent Overstreet 		: "";
100401ec4dbSKent Overstreet }
101401ec4dbSKent Overstreet 
102401ec4dbSKent Overstreet /**
10396dea3d5SKent Overstreet  * bch2_printbuf_exit() - exit a printbuf, freeing memory it owns and poisoning it
104401ec4dbSKent Overstreet  * against accidental use.
10596dea3d5SKent Overstreet  * @buf:	printbuf to exit
106401ec4dbSKent Overstreet  */
107401ec4dbSKent Overstreet void bch2_printbuf_exit(struct printbuf *buf)
108401ec4dbSKent Overstreet {
109401ec4dbSKent Overstreet 	if (buf->heap_allocated) {
110401ec4dbSKent Overstreet 		kfree(buf->buf);
111401ec4dbSKent Overstreet 		buf->buf = ERR_PTR(-EINTR); /* poison value */
112401ec4dbSKent Overstreet 	}
113401ec4dbSKent Overstreet }
114401ec4dbSKent Overstreet 
115401ec4dbSKent Overstreet void bch2_printbuf_tabstops_reset(struct printbuf *buf)
116401ec4dbSKent Overstreet {
117401ec4dbSKent Overstreet 	buf->nr_tabstops = 0;
118401ec4dbSKent Overstreet }
119401ec4dbSKent Overstreet 
120401ec4dbSKent Overstreet void bch2_printbuf_tabstop_pop(struct printbuf *buf)
121401ec4dbSKent Overstreet {
122401ec4dbSKent Overstreet 	if (buf->nr_tabstops)
123401ec4dbSKent Overstreet 		--buf->nr_tabstops;
124401ec4dbSKent Overstreet }
125401ec4dbSKent Overstreet 
126401ec4dbSKent Overstreet /*
12796dea3d5SKent Overstreet  * bch2_printbuf_tabstop_set() - add a tabstop, n spaces from the previous tabstop
128401ec4dbSKent Overstreet  *
129401ec4dbSKent Overstreet  * @buf: printbuf to control
130401ec4dbSKent Overstreet  * @spaces: number of spaces from previous tabpstop
131401ec4dbSKent Overstreet  *
132401ec4dbSKent Overstreet  * In the future this function may allocate memory if setting more than
133401ec4dbSKent Overstreet  * PRINTBUF_INLINE_TABSTOPS or setting tabstops more than 255 spaces from start
134401ec4dbSKent Overstreet  * of line.
135401ec4dbSKent Overstreet  */
136401ec4dbSKent Overstreet int bch2_printbuf_tabstop_push(struct printbuf *buf, unsigned spaces)
137401ec4dbSKent Overstreet {
138401ec4dbSKent Overstreet 	unsigned prev_tabstop = buf->nr_tabstops
139401ec4dbSKent Overstreet 		? buf->_tabstops[buf->nr_tabstops - 1]
140401ec4dbSKent Overstreet 		: 0;
141401ec4dbSKent Overstreet 
142401ec4dbSKent Overstreet 	if (WARN_ON(buf->nr_tabstops >= ARRAY_SIZE(buf->_tabstops)))
143401ec4dbSKent Overstreet 		return -EINVAL;
144401ec4dbSKent Overstreet 
145401ec4dbSKent Overstreet 	buf->_tabstops[buf->nr_tabstops++] = prev_tabstop + spaces;
146401ec4dbSKent Overstreet 	buf->has_indent_or_tabstops = true;
147401ec4dbSKent Overstreet 	return 0;
148401ec4dbSKent Overstreet }
149401ec4dbSKent Overstreet 
150401ec4dbSKent Overstreet /**
15196dea3d5SKent Overstreet  * bch2_printbuf_indent_add() - add to the current indent level
152401ec4dbSKent Overstreet  *
153401ec4dbSKent Overstreet  * @buf: printbuf to control
154401ec4dbSKent Overstreet  * @spaces: number of spaces to add to the current indent level
155401ec4dbSKent Overstreet  *
156401ec4dbSKent Overstreet  * Subsequent lines, and the current line if the output position is at the start
157401ec4dbSKent Overstreet  * of the current line, will be indented by @spaces more spaces.
158401ec4dbSKent Overstreet  */
159401ec4dbSKent Overstreet void bch2_printbuf_indent_add(struct printbuf *buf, unsigned spaces)
160401ec4dbSKent Overstreet {
161401ec4dbSKent Overstreet 	if (WARN_ON_ONCE(buf->indent + spaces < buf->indent))
162401ec4dbSKent Overstreet 		spaces = 0;
163401ec4dbSKent Overstreet 
164401ec4dbSKent Overstreet 	buf->indent += spaces;
165401ec4dbSKent Overstreet 	prt_chars(buf, ' ', spaces);
166401ec4dbSKent Overstreet 
167401ec4dbSKent Overstreet 	buf->has_indent_or_tabstops = true;
168401ec4dbSKent Overstreet }
169401ec4dbSKent Overstreet 
170401ec4dbSKent Overstreet /**
17196dea3d5SKent Overstreet  * bch2_printbuf_indent_sub() - subtract from the current indent level
172401ec4dbSKent Overstreet  *
173401ec4dbSKent Overstreet  * @buf: printbuf to control
174401ec4dbSKent Overstreet  * @spaces: number of spaces to subtract from the current indent level
175401ec4dbSKent Overstreet  *
176401ec4dbSKent Overstreet  * Subsequent lines, and the current line if the output position is at the start
177401ec4dbSKent Overstreet  * of the current line, will be indented by @spaces less spaces.
178401ec4dbSKent Overstreet  */
179401ec4dbSKent Overstreet void bch2_printbuf_indent_sub(struct printbuf *buf, unsigned spaces)
180401ec4dbSKent Overstreet {
181401ec4dbSKent Overstreet 	if (WARN_ON_ONCE(spaces > buf->indent))
182401ec4dbSKent Overstreet 		spaces = buf->indent;
183401ec4dbSKent Overstreet 
184401ec4dbSKent Overstreet 	if (buf->last_newline + buf->indent == buf->pos) {
185401ec4dbSKent Overstreet 		buf->pos -= spaces;
186401ec4dbSKent Overstreet 		printbuf_nul_terminate(buf);
187401ec4dbSKent Overstreet 	}
188401ec4dbSKent Overstreet 	buf->indent -= spaces;
189401ec4dbSKent Overstreet 
190401ec4dbSKent Overstreet 	if (!buf->indent && !buf->nr_tabstops)
191401ec4dbSKent Overstreet 		buf->has_indent_or_tabstops = false;
192401ec4dbSKent Overstreet }
193401ec4dbSKent Overstreet 
194401ec4dbSKent Overstreet void bch2_prt_newline(struct printbuf *buf)
195401ec4dbSKent Overstreet {
196401ec4dbSKent Overstreet 	unsigned i;
197401ec4dbSKent Overstreet 
198401ec4dbSKent Overstreet 	bch2_printbuf_make_room(buf, 1 + buf->indent);
199401ec4dbSKent Overstreet 
200401ec4dbSKent Overstreet 	__prt_char(buf, '\n');
201401ec4dbSKent Overstreet 
202401ec4dbSKent Overstreet 	buf->last_newline	= buf->pos;
203401ec4dbSKent Overstreet 
204401ec4dbSKent Overstreet 	for (i = 0; i < buf->indent; i++)
205401ec4dbSKent Overstreet 		__prt_char(buf, ' ');
206401ec4dbSKent Overstreet 
207401ec4dbSKent Overstreet 	printbuf_nul_terminate(buf);
208401ec4dbSKent Overstreet 
209401ec4dbSKent Overstreet 	buf->last_field		= buf->pos;
210401ec4dbSKent Overstreet 	buf->cur_tabstop	= 0;
211401ec4dbSKent Overstreet }
212401ec4dbSKent Overstreet 
213401ec4dbSKent Overstreet /*
214401ec4dbSKent Overstreet  * Returns spaces from start of line, if set, or 0 if unset:
215401ec4dbSKent Overstreet  */
216401ec4dbSKent Overstreet static inline unsigned cur_tabstop(struct printbuf *buf)
217401ec4dbSKent Overstreet {
218401ec4dbSKent Overstreet 	return buf->cur_tabstop < buf->nr_tabstops
219401ec4dbSKent Overstreet 		? buf->_tabstops[buf->cur_tabstop]
220401ec4dbSKent Overstreet 		: 0;
221401ec4dbSKent Overstreet }
222401ec4dbSKent Overstreet 
223401ec4dbSKent Overstreet static void __prt_tab(struct printbuf *out)
224401ec4dbSKent Overstreet {
225401ec4dbSKent Overstreet 	int spaces = max_t(int, 0, cur_tabstop(out) - printbuf_linelen(out));
226401ec4dbSKent Overstreet 
227401ec4dbSKent Overstreet 	prt_chars(out, ' ', spaces);
228401ec4dbSKent Overstreet 
229401ec4dbSKent Overstreet 	out->last_field = out->pos;
230401ec4dbSKent Overstreet 	out->cur_tabstop++;
231401ec4dbSKent Overstreet }
232401ec4dbSKent Overstreet 
233401ec4dbSKent Overstreet /**
23496dea3d5SKent Overstreet  * bch2_prt_tab() - Advance printbuf to the next tabstop
23596dea3d5SKent Overstreet  * @out:	printbuf to control
236401ec4dbSKent Overstreet  *
237401ec4dbSKent Overstreet  * Advance output to the next tabstop by printing spaces.
238401ec4dbSKent Overstreet  */
239401ec4dbSKent Overstreet void bch2_prt_tab(struct printbuf *out)
240401ec4dbSKent Overstreet {
241401ec4dbSKent Overstreet 	if (WARN_ON(!cur_tabstop(out)))
242401ec4dbSKent Overstreet 		return;
243401ec4dbSKent Overstreet 
244401ec4dbSKent Overstreet 	__prt_tab(out);
245401ec4dbSKent Overstreet }
246401ec4dbSKent Overstreet 
247401ec4dbSKent Overstreet static void __prt_tab_rjust(struct printbuf *buf)
248401ec4dbSKent Overstreet {
249401ec4dbSKent Overstreet 	unsigned move = buf->pos - buf->last_field;
250401ec4dbSKent Overstreet 	int pad = (int) cur_tabstop(buf) - (int) printbuf_linelen(buf);
251401ec4dbSKent Overstreet 
252401ec4dbSKent Overstreet 	if (pad > 0) {
253401ec4dbSKent Overstreet 		bch2_printbuf_make_room(buf, pad);
254401ec4dbSKent Overstreet 
255401ec4dbSKent Overstreet 		if (buf->last_field + pad < buf->size)
256401ec4dbSKent Overstreet 			memmove(buf->buf + buf->last_field + pad,
257401ec4dbSKent Overstreet 				buf->buf + buf->last_field,
258401ec4dbSKent Overstreet 				min(move, buf->size - 1 - buf->last_field - pad));
259401ec4dbSKent Overstreet 
260401ec4dbSKent Overstreet 		if (buf->last_field < buf->size)
261401ec4dbSKent Overstreet 			memset(buf->buf + buf->last_field, ' ',
262401ec4dbSKent Overstreet 			       min((unsigned) pad, buf->size - buf->last_field));
263401ec4dbSKent Overstreet 
264401ec4dbSKent Overstreet 		buf->pos += pad;
265401ec4dbSKent Overstreet 		printbuf_nul_terminate(buf);
266401ec4dbSKent Overstreet 	}
267401ec4dbSKent Overstreet 
268401ec4dbSKent Overstreet 	buf->last_field = buf->pos;
269401ec4dbSKent Overstreet 	buf->cur_tabstop++;
270401ec4dbSKent Overstreet }
271401ec4dbSKent Overstreet 
272401ec4dbSKent Overstreet /**
27396dea3d5SKent Overstreet  * bch2_prt_tab_rjust - Advance printbuf to the next tabstop, right justifying
274401ec4dbSKent Overstreet  * previous output
275401ec4dbSKent Overstreet  *
276401ec4dbSKent Overstreet  * @buf: printbuf to control
277401ec4dbSKent Overstreet  *
278401ec4dbSKent Overstreet  * Advance output to the next tabstop by inserting spaces immediately after the
279401ec4dbSKent Overstreet  * previous tabstop, right justifying previously outputted text.
280401ec4dbSKent Overstreet  */
281401ec4dbSKent Overstreet void bch2_prt_tab_rjust(struct printbuf *buf)
282401ec4dbSKent Overstreet {
283401ec4dbSKent Overstreet 	if (WARN_ON(!cur_tabstop(buf)))
284401ec4dbSKent Overstreet 		return;
285401ec4dbSKent Overstreet 
286401ec4dbSKent Overstreet 	__prt_tab_rjust(buf);
287401ec4dbSKent Overstreet }
288401ec4dbSKent Overstreet 
289401ec4dbSKent Overstreet /**
29096dea3d5SKent Overstreet  * bch2_prt_bytes_indented() - Print an array of chars, handling embedded control characters
291401ec4dbSKent Overstreet  *
29296dea3d5SKent Overstreet  * @out:	output printbuf
293401ec4dbSKent Overstreet  * @str:	string to print
294401ec4dbSKent Overstreet  * @count:	number of bytes to print
295401ec4dbSKent Overstreet  *
296401ec4dbSKent Overstreet  * The following contol characters are handled as so:
297401ec4dbSKent Overstreet  *   \n: prt_newline	newline that obeys current indent level
298401ec4dbSKent Overstreet  *   \t: prt_tab	advance to next tabstop
299401ec4dbSKent Overstreet  *   \r: prt_tab_rjust	advance to next tabstop, with right justification
300401ec4dbSKent Overstreet  */
301401ec4dbSKent Overstreet void bch2_prt_bytes_indented(struct printbuf *out, const char *str, unsigned count)
302401ec4dbSKent Overstreet {
303401ec4dbSKent Overstreet 	const char *unprinted_start = str;
304401ec4dbSKent Overstreet 	const char *end = str + count;
305401ec4dbSKent Overstreet 
306401ec4dbSKent Overstreet 	if (!out->has_indent_or_tabstops || out->suppress_indent_tabstop_handling) {
307401ec4dbSKent Overstreet 		prt_bytes(out, str, count);
308401ec4dbSKent Overstreet 		return;
309401ec4dbSKent Overstreet 	}
310401ec4dbSKent Overstreet 
311401ec4dbSKent Overstreet 	while (str != end) {
312401ec4dbSKent Overstreet 		switch (*str) {
313401ec4dbSKent Overstreet 		case '\n':
314401ec4dbSKent Overstreet 			prt_bytes(out, unprinted_start, str - unprinted_start);
315401ec4dbSKent Overstreet 			unprinted_start = str + 1;
316401ec4dbSKent Overstreet 			bch2_prt_newline(out);
317401ec4dbSKent Overstreet 			break;
318401ec4dbSKent Overstreet 		case '\t':
319401ec4dbSKent Overstreet 			if (likely(cur_tabstop(out))) {
320401ec4dbSKent Overstreet 				prt_bytes(out, unprinted_start, str - unprinted_start);
321401ec4dbSKent Overstreet 				unprinted_start = str + 1;
322401ec4dbSKent Overstreet 				__prt_tab(out);
323401ec4dbSKent Overstreet 			}
324401ec4dbSKent Overstreet 			break;
325401ec4dbSKent Overstreet 		case '\r':
326401ec4dbSKent Overstreet 			if (likely(cur_tabstop(out))) {
327401ec4dbSKent Overstreet 				prt_bytes(out, unprinted_start, str - unprinted_start);
328401ec4dbSKent Overstreet 				unprinted_start = str + 1;
329401ec4dbSKent Overstreet 				__prt_tab_rjust(out);
330401ec4dbSKent Overstreet 			}
331401ec4dbSKent Overstreet 			break;
332401ec4dbSKent Overstreet 		}
333401ec4dbSKent Overstreet 
334401ec4dbSKent Overstreet 		str++;
335401ec4dbSKent Overstreet 	}
336401ec4dbSKent Overstreet 
337401ec4dbSKent Overstreet 	prt_bytes(out, unprinted_start, str - unprinted_start);
338401ec4dbSKent Overstreet }
339401ec4dbSKent Overstreet 
340401ec4dbSKent Overstreet /**
34196dea3d5SKent Overstreet  * bch2_prt_human_readable_u64() - Print out a u64 in human readable units
34296dea3d5SKent Overstreet  * @out:	output printbuf
34396dea3d5SKent Overstreet  * @v:		integer to print
344401ec4dbSKent Overstreet  *
34596dea3d5SKent Overstreet  * Units of 2^10 (default) or 10^3 are controlled via @out->si_units
346401ec4dbSKent Overstreet  */
34796dea3d5SKent Overstreet void bch2_prt_human_readable_u64(struct printbuf *out, u64 v)
348401ec4dbSKent Overstreet {
34996dea3d5SKent Overstreet 	bch2_printbuf_make_room(out, 10);
35096dea3d5SKent Overstreet 	out->pos += string_get_size(v, 1, !out->si_units,
35196dea3d5SKent Overstreet 				    out->buf + out->pos,
35296dea3d5SKent Overstreet 				    printbuf_remaining_size(out));
353401ec4dbSKent Overstreet }
354401ec4dbSKent Overstreet 
355401ec4dbSKent Overstreet /**
35696dea3d5SKent Overstreet  * bch2_prt_human_readable_s64() - Print out a s64 in human readable units
35796dea3d5SKent Overstreet  * @out:	output printbuf
35896dea3d5SKent Overstreet  * @v:		integer to print
359401ec4dbSKent Overstreet  *
36096dea3d5SKent Overstreet  * Units of 2^10 (default) or 10^3 are controlled via @out->si_units
361401ec4dbSKent Overstreet  */
36296dea3d5SKent Overstreet void bch2_prt_human_readable_s64(struct printbuf *out, s64 v)
363401ec4dbSKent Overstreet {
364401ec4dbSKent Overstreet 	if (v < 0)
36596dea3d5SKent Overstreet 		prt_char(out, '-');
36696dea3d5SKent Overstreet 	bch2_prt_human_readable_u64(out, abs(v));
367401ec4dbSKent Overstreet }
368401ec4dbSKent Overstreet 
369401ec4dbSKent Overstreet /**
37096dea3d5SKent Overstreet  * bch2_prt_units_u64() - Print out a u64 according to printbuf unit options
37196dea3d5SKent Overstreet  * @out:	output printbuf
37296dea3d5SKent Overstreet  * @v:		integer to print
373401ec4dbSKent Overstreet  *
374401ec4dbSKent Overstreet  * Units are either raw (default), or human reabable units (controlled via
375401ec4dbSKent Overstreet  * @buf->human_readable_units)
376401ec4dbSKent Overstreet  */
377401ec4dbSKent Overstreet void bch2_prt_units_u64(struct printbuf *out, u64 v)
378401ec4dbSKent Overstreet {
379401ec4dbSKent Overstreet 	if (out->human_readable_units)
380401ec4dbSKent Overstreet 		bch2_prt_human_readable_u64(out, v);
381401ec4dbSKent Overstreet 	else
382401ec4dbSKent Overstreet 		bch2_prt_printf(out, "%llu", v);
383401ec4dbSKent Overstreet }
384401ec4dbSKent Overstreet 
385401ec4dbSKent Overstreet /**
38696dea3d5SKent Overstreet  * bch2_prt_units_s64() - Print out a s64 according to printbuf unit options
38796dea3d5SKent Overstreet  * @out:	output printbuf
38896dea3d5SKent Overstreet  * @v:		integer to print
389401ec4dbSKent Overstreet  *
390401ec4dbSKent Overstreet  * Units are either raw (default), or human reabable units (controlled via
391401ec4dbSKent Overstreet  * @buf->human_readable_units)
392401ec4dbSKent Overstreet  */
393401ec4dbSKent Overstreet void bch2_prt_units_s64(struct printbuf *out, s64 v)
394401ec4dbSKent Overstreet {
395401ec4dbSKent Overstreet 	if (v < 0)
396401ec4dbSKent Overstreet 		prt_char(out, '-');
397401ec4dbSKent Overstreet 	bch2_prt_units_u64(out, abs(v));
398401ec4dbSKent Overstreet }
399401ec4dbSKent Overstreet 
400401ec4dbSKent Overstreet void bch2_prt_string_option(struct printbuf *out,
401401ec4dbSKent Overstreet 			    const char * const list[],
402401ec4dbSKent Overstreet 			    size_t selected)
403401ec4dbSKent Overstreet {
404401ec4dbSKent Overstreet 	size_t i;
405401ec4dbSKent Overstreet 
406401ec4dbSKent Overstreet 	for (i = 0; list[i]; i++)
407401ec4dbSKent Overstreet 		bch2_prt_printf(out, i == selected ? "[%s] " : "%s ", list[i]);
408401ec4dbSKent Overstreet }
409401ec4dbSKent Overstreet 
410401ec4dbSKent Overstreet void bch2_prt_bitflags(struct printbuf *out,
411401ec4dbSKent Overstreet 		       const char * const list[], u64 flags)
412401ec4dbSKent Overstreet {
413401ec4dbSKent Overstreet 	unsigned bit, nr = 0;
414401ec4dbSKent Overstreet 	bool first = true;
415401ec4dbSKent Overstreet 
416401ec4dbSKent Overstreet 	while (list[nr])
417401ec4dbSKent Overstreet 		nr++;
418401ec4dbSKent Overstreet 
41948f866e9SKent Overstreet 	while (flags && (bit = __ffs64(flags)) < nr) {
420401ec4dbSKent Overstreet 		if (!first)
421401ec4dbSKent Overstreet 			bch2_prt_printf(out, ",");
422401ec4dbSKent Overstreet 		first = false;
423401ec4dbSKent Overstreet 		bch2_prt_printf(out, "%s", list[bit]);
42448f866e9SKent Overstreet 		flags ^= BIT_ULL(bit);
425401ec4dbSKent Overstreet 	}
426401ec4dbSKent Overstreet }
427*560661d4SKent Overstreet 
428*560661d4SKent Overstreet void bch2_prt_bitflags_vector(struct printbuf *out,
429*560661d4SKent Overstreet 			      const char * const list[],
430*560661d4SKent Overstreet 			      unsigned long *v, unsigned nr)
431*560661d4SKent Overstreet {
432*560661d4SKent Overstreet 	bool first = true;
433*560661d4SKent Overstreet 	unsigned i;
434*560661d4SKent Overstreet 
435*560661d4SKent Overstreet 	for (i = 0; i < nr; i++)
436*560661d4SKent Overstreet 		if (!list[i]) {
437*560661d4SKent Overstreet 			nr = i - 1;
438*560661d4SKent Overstreet 			break;
439*560661d4SKent Overstreet 		}
440*560661d4SKent Overstreet 
441*560661d4SKent Overstreet 	for_each_set_bit(i, v, nr) {
442*560661d4SKent Overstreet 		if (!first)
443*560661d4SKent Overstreet 			bch2_prt_printf(out, ",");
444*560661d4SKent Overstreet 		first = false;
445*560661d4SKent Overstreet 		bch2_prt_printf(out, "%s", list[i]);
446*560661d4SKent Overstreet 	}
447*560661d4SKent Overstreet }
448