xref: /linux/fs/bcachefs/printbuf.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1401ec4dbSKent Overstreet // SPDX-License-Identifier: LGPL-2.1+
2401ec4dbSKent Overstreet /* Copyright (C) 2022 Kent Overstreet */
3401ec4dbSKent Overstreet 
4560661d4SKent 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 
__printbuf_linelen(struct printbuf * buf,unsigned pos)132dcb605eSKent Overstreet static inline unsigned __printbuf_linelen(struct printbuf *buf, unsigned pos)
142dcb605eSKent Overstreet {
152dcb605eSKent Overstreet 	return pos - buf->last_newline;
162dcb605eSKent Overstreet }
172dcb605eSKent Overstreet 
printbuf_linelen(struct printbuf * buf)18401ec4dbSKent Overstreet static inline unsigned printbuf_linelen(struct printbuf *buf)
19401ec4dbSKent Overstreet {
202dcb605eSKent Overstreet 	return __printbuf_linelen(buf, buf->pos);
212dcb605eSKent Overstreet }
222dcb605eSKent Overstreet 
232dcb605eSKent Overstreet /*
242dcb605eSKent Overstreet  * Returns spaces from start of line, if set, or 0 if unset:
252dcb605eSKent Overstreet  */
cur_tabstop(struct printbuf * buf)262dcb605eSKent Overstreet static inline unsigned cur_tabstop(struct printbuf *buf)
272dcb605eSKent Overstreet {
282dcb605eSKent Overstreet 	return buf->cur_tabstop < buf->nr_tabstops
292dcb605eSKent Overstreet 		? buf->_tabstops[buf->cur_tabstop]
302dcb605eSKent Overstreet 		: 0;
31401ec4dbSKent Overstreet }
32401ec4dbSKent Overstreet 
bch2_printbuf_make_room(struct printbuf * out,unsigned extra)33401ec4dbSKent Overstreet int bch2_printbuf_make_room(struct printbuf *out, unsigned extra)
34401ec4dbSKent Overstreet {
35401ec4dbSKent Overstreet 	/* Reserved space for terminating nul: */
36401ec4dbSKent Overstreet 	extra += 1;
37401ec4dbSKent Overstreet 
38acce32a5SKent Overstreet 	if (out->pos + extra <= out->size)
39401ec4dbSKent Overstreet 		return 0;
40401ec4dbSKent Overstreet 
41acce32a5SKent Overstreet 	if (!out->heap_allocated) {
42acce32a5SKent Overstreet 		out->overflow = true;
43acce32a5SKent Overstreet 		return 0;
44acce32a5SKent Overstreet 	}
45acce32a5SKent Overstreet 
46acce32a5SKent Overstreet 	unsigned new_size = roundup_pow_of_two(out->size + extra);
47401ec4dbSKent Overstreet 
48d293ece1SKent Overstreet 	/* Sanity check... */
49d293ece1SKent Overstreet 	if (new_size > PAGE_SIZE << MAX_PAGE_ORDER) {
50d293ece1SKent Overstreet 		out->allocation_failure = true;
51d293ece1SKent Overstreet 		out->overflow = true;
52d293ece1SKent Overstreet 		return -ENOMEM;
53d293ece1SKent Overstreet 	}
54d293ece1SKent Overstreet 
55401ec4dbSKent Overstreet 	/*
56401ec4dbSKent Overstreet 	 * Note: output buffer must be freeable with kfree(), it's not required
57401ec4dbSKent Overstreet 	 * that the user use printbuf_exit().
58401ec4dbSKent Overstreet 	 */
59acce32a5SKent Overstreet 	char *buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT);
60401ec4dbSKent Overstreet 
61401ec4dbSKent Overstreet 	if (!buf) {
62401ec4dbSKent Overstreet 		out->allocation_failure = true;
63acce32a5SKent Overstreet 		out->overflow = true;
64401ec4dbSKent Overstreet 		return -ENOMEM;
65401ec4dbSKent Overstreet 	}
66401ec4dbSKent Overstreet 
67401ec4dbSKent Overstreet 	out->buf	= buf;
68401ec4dbSKent Overstreet 	out->size	= new_size;
69401ec4dbSKent Overstreet 	return 0;
70401ec4dbSKent Overstreet }
71401ec4dbSKent Overstreet 
printbuf_advance_pos(struct printbuf * out,unsigned len)72acce32a5SKent Overstreet static void printbuf_advance_pos(struct printbuf *out, unsigned len)
73acce32a5SKent Overstreet {
74acce32a5SKent Overstreet 	out->pos += min(len, printbuf_remaining(out));
75acce32a5SKent Overstreet }
76acce32a5SKent Overstreet 
printbuf_insert_spaces(struct printbuf * out,unsigned pos,unsigned nr)772dcb605eSKent Overstreet static void printbuf_insert_spaces(struct printbuf *out, unsigned pos, unsigned nr)
782dcb605eSKent Overstreet {
792dcb605eSKent Overstreet 	unsigned move = out->pos - pos;
802dcb605eSKent Overstreet 
812dcb605eSKent Overstreet 	bch2_printbuf_make_room(out, nr);
822dcb605eSKent Overstreet 
832dcb605eSKent Overstreet 	if (pos + nr < out->size)
842dcb605eSKent Overstreet 		memmove(out->buf + pos + nr,
852dcb605eSKent Overstreet 			out->buf + pos,
862dcb605eSKent Overstreet 			min(move, out->size - 1 - pos - nr));
872dcb605eSKent Overstreet 
882dcb605eSKent Overstreet 	if (pos < out->size)
892dcb605eSKent Overstreet 		memset(out->buf + pos, ' ', min(nr, out->size - pos));
902dcb605eSKent Overstreet 
912dcb605eSKent Overstreet 	printbuf_advance_pos(out, nr);
922dcb605eSKent Overstreet 	printbuf_nul_terminate_reserved(out);
932dcb605eSKent Overstreet }
942dcb605eSKent Overstreet 
__printbuf_do_indent(struct printbuf * out,unsigned pos)952dcb605eSKent Overstreet static void __printbuf_do_indent(struct printbuf *out, unsigned pos)
962dcb605eSKent Overstreet {
972dcb605eSKent Overstreet 	while (true) {
982dcb605eSKent Overstreet 		int pad;
992dcb605eSKent Overstreet 		unsigned len = out->pos - pos;
1002dcb605eSKent Overstreet 		char *p = out->buf + pos;
1012dcb605eSKent Overstreet 		char *n = memscan(p, '\n', len);
1022dcb605eSKent Overstreet 		if (cur_tabstop(out)) {
1032dcb605eSKent Overstreet 			n = min(n, (char *) memscan(p, '\r', len));
1042dcb605eSKent Overstreet 			n = min(n, (char *) memscan(p, '\t', len));
1052dcb605eSKent Overstreet 		}
1062dcb605eSKent Overstreet 
1072dcb605eSKent Overstreet 		pos = n - out->buf;
1082dcb605eSKent Overstreet 		if (pos == out->pos)
1092dcb605eSKent Overstreet 			break;
1102dcb605eSKent Overstreet 
1112dcb605eSKent Overstreet 		switch (*n) {
1122dcb605eSKent Overstreet 		case '\n':
1132dcb605eSKent Overstreet 			pos++;
1142dcb605eSKent Overstreet 			out->last_newline = pos;
1152dcb605eSKent Overstreet 
1162dcb605eSKent Overstreet 			printbuf_insert_spaces(out, pos, out->indent);
1172dcb605eSKent Overstreet 
1182dcb605eSKent Overstreet 			pos = min(pos + out->indent, out->pos);
1192dcb605eSKent Overstreet 			out->last_field = pos;
1202dcb605eSKent Overstreet 			out->cur_tabstop = 0;
1212dcb605eSKent Overstreet 			break;
1222dcb605eSKent Overstreet 		case '\r':
1232dcb605eSKent Overstreet 			memmove(n, n + 1, out->pos - pos);
1242dcb605eSKent Overstreet 			--out->pos;
1252dcb605eSKent Overstreet 			pad = (int) cur_tabstop(out) - (int) __printbuf_linelen(out, pos);
1262dcb605eSKent Overstreet 			if (pad > 0) {
1272dcb605eSKent Overstreet 				printbuf_insert_spaces(out, out->last_field, pad);
1282dcb605eSKent Overstreet 				pos += pad;
1292dcb605eSKent Overstreet 			}
1302dcb605eSKent Overstreet 
1312dcb605eSKent Overstreet 			out->last_field = pos;
1322dcb605eSKent Overstreet 			out->cur_tabstop++;
1332dcb605eSKent Overstreet 			break;
1342dcb605eSKent Overstreet 		case '\t':
1352dcb605eSKent Overstreet 			pad = (int) cur_tabstop(out) - (int) __printbuf_linelen(out, pos) - 1;
1362dcb605eSKent Overstreet 			if (pad > 0) {
1372dcb605eSKent Overstreet 				*n = ' ';
1382dcb605eSKent Overstreet 				printbuf_insert_spaces(out, pos, pad - 1);
1392dcb605eSKent Overstreet 				pos += pad;
1402dcb605eSKent Overstreet 			} else {
1412dcb605eSKent Overstreet 				memmove(n, n + 1, out->pos - pos);
1422dcb605eSKent Overstreet 				--out->pos;
1432dcb605eSKent Overstreet 			}
1442dcb605eSKent Overstreet 
1452dcb605eSKent Overstreet 			out->last_field = pos;
1462dcb605eSKent Overstreet 			out->cur_tabstop++;
1472dcb605eSKent Overstreet 			break;
1482dcb605eSKent Overstreet 		}
1492dcb605eSKent Overstreet 	}
1502dcb605eSKent Overstreet }
1512dcb605eSKent Overstreet 
printbuf_do_indent(struct printbuf * out,unsigned pos)1522dcb605eSKent Overstreet static inline void printbuf_do_indent(struct printbuf *out, unsigned pos)
1532dcb605eSKent Overstreet {
1542dcb605eSKent Overstreet 	if (out->has_indent_or_tabstops && !out->suppress_indent_tabstop_handling)
1552dcb605eSKent Overstreet 		__printbuf_do_indent(out, pos);
1562dcb605eSKent Overstreet }
1572dcb605eSKent Overstreet 
bch2_prt_vprintf(struct printbuf * out,const char * fmt,va_list args)158401ec4dbSKent Overstreet void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
159401ec4dbSKent Overstreet {
160401ec4dbSKent Overstreet 	int len;
161401ec4dbSKent Overstreet 
162401ec4dbSKent Overstreet 	do {
163401ec4dbSKent Overstreet 		va_list args2;
164401ec4dbSKent Overstreet 
165401ec4dbSKent Overstreet 		va_copy(args2, args);
166acce32a5SKent Overstreet 		len = vsnprintf(out->buf + out->pos, printbuf_remaining_size(out), fmt, args2);
167816054f4SKent Overstreet 		va_end(args2);
168acce32a5SKent Overstreet 	} while (len > printbuf_remaining(out) &&
169acce32a5SKent Overstreet 		 !bch2_printbuf_make_room(out, len));
170401ec4dbSKent Overstreet 
1712dcb605eSKent Overstreet 	unsigned indent_pos = out->pos;
172acce32a5SKent Overstreet 	printbuf_advance_pos(out, len);
1732dcb605eSKent Overstreet 	printbuf_do_indent(out, indent_pos);
174401ec4dbSKent Overstreet }
175401ec4dbSKent Overstreet 
bch2_prt_printf(struct printbuf * out,const char * fmt,...)176401ec4dbSKent Overstreet void bch2_prt_printf(struct printbuf *out, const char *fmt, ...)
177401ec4dbSKent Overstreet {
178401ec4dbSKent Overstreet 	va_list args;
179401ec4dbSKent Overstreet 	int len;
180401ec4dbSKent Overstreet 
181401ec4dbSKent Overstreet 	do {
182401ec4dbSKent Overstreet 		va_start(args, fmt);
183acce32a5SKent Overstreet 		len = vsnprintf(out->buf + out->pos, printbuf_remaining_size(out), fmt, args);
184401ec4dbSKent Overstreet 		va_end(args);
185acce32a5SKent Overstreet 	} while (len > printbuf_remaining(out) &&
186acce32a5SKent Overstreet 		 !bch2_printbuf_make_room(out, len));
187401ec4dbSKent Overstreet 
1882dcb605eSKent Overstreet 	unsigned indent_pos = out->pos;
189acce32a5SKent Overstreet 	printbuf_advance_pos(out, len);
1902dcb605eSKent Overstreet 	printbuf_do_indent(out, indent_pos);
191401ec4dbSKent Overstreet }
192401ec4dbSKent Overstreet 
193401ec4dbSKent Overstreet /**
19496dea3d5SKent Overstreet  * bch2_printbuf_str() - returns printbuf's buf as a C string, guaranteed to be
19596dea3d5SKent Overstreet  * null terminated
19696dea3d5SKent Overstreet  * @buf:	printbuf to terminate
19796dea3d5SKent Overstreet  * Returns:	Printbuf contents, as a nul terminated C string
198401ec4dbSKent Overstreet  */
bch2_printbuf_str(const struct printbuf * buf)199401ec4dbSKent Overstreet const char *bch2_printbuf_str(const struct printbuf *buf)
200401ec4dbSKent Overstreet {
201401ec4dbSKent Overstreet 	/*
202401ec4dbSKent Overstreet 	 * If we've written to a printbuf then it's guaranteed to be a null
203401ec4dbSKent Overstreet 	 * terminated string - but if we haven't, then we might not have
204401ec4dbSKent Overstreet 	 * allocated a buffer at all:
205401ec4dbSKent Overstreet 	 */
206401ec4dbSKent Overstreet 	return buf->pos
207401ec4dbSKent Overstreet 		? buf->buf
208401ec4dbSKent Overstreet 		: "";
209401ec4dbSKent Overstreet }
210401ec4dbSKent Overstreet 
211401ec4dbSKent Overstreet /**
21296dea3d5SKent Overstreet  * bch2_printbuf_exit() - exit a printbuf, freeing memory it owns and poisoning it
213401ec4dbSKent Overstreet  * against accidental use.
21496dea3d5SKent Overstreet  * @buf:	printbuf to exit
215401ec4dbSKent Overstreet  */
bch2_printbuf_exit(struct printbuf * buf)216401ec4dbSKent Overstreet void bch2_printbuf_exit(struct printbuf *buf)
217401ec4dbSKent Overstreet {
218401ec4dbSKent Overstreet 	if (buf->heap_allocated) {
219401ec4dbSKent Overstreet 		kfree(buf->buf);
220401ec4dbSKent Overstreet 		buf->buf = ERR_PTR(-EINTR); /* poison value */
221401ec4dbSKent Overstreet 	}
222401ec4dbSKent Overstreet }
223401ec4dbSKent Overstreet 
bch2_printbuf_tabstops_reset(struct printbuf * buf)224401ec4dbSKent Overstreet void bch2_printbuf_tabstops_reset(struct printbuf *buf)
225401ec4dbSKent Overstreet {
226401ec4dbSKent Overstreet 	buf->nr_tabstops = 0;
227401ec4dbSKent Overstreet }
228401ec4dbSKent Overstreet 
bch2_printbuf_tabstop_pop(struct printbuf * buf)229401ec4dbSKent Overstreet void bch2_printbuf_tabstop_pop(struct printbuf *buf)
230401ec4dbSKent Overstreet {
231401ec4dbSKent Overstreet 	if (buf->nr_tabstops)
232401ec4dbSKent Overstreet 		--buf->nr_tabstops;
233401ec4dbSKent Overstreet }
234401ec4dbSKent Overstreet 
235401ec4dbSKent Overstreet /*
23696dea3d5SKent Overstreet  * bch2_printbuf_tabstop_set() - add a tabstop, n spaces from the previous tabstop
237401ec4dbSKent Overstreet  *
238401ec4dbSKent Overstreet  * @buf: printbuf to control
239401ec4dbSKent Overstreet  * @spaces: number of spaces from previous tabpstop
240401ec4dbSKent Overstreet  *
241401ec4dbSKent Overstreet  * In the future this function may allocate memory if setting more than
242401ec4dbSKent Overstreet  * PRINTBUF_INLINE_TABSTOPS or setting tabstops more than 255 spaces from start
243401ec4dbSKent Overstreet  * of line.
244401ec4dbSKent Overstreet  */
bch2_printbuf_tabstop_push(struct printbuf * buf,unsigned spaces)245401ec4dbSKent Overstreet int bch2_printbuf_tabstop_push(struct printbuf *buf, unsigned spaces)
246401ec4dbSKent Overstreet {
247401ec4dbSKent Overstreet 	unsigned prev_tabstop = buf->nr_tabstops
248401ec4dbSKent Overstreet 		? buf->_tabstops[buf->nr_tabstops - 1]
249401ec4dbSKent Overstreet 		: 0;
250401ec4dbSKent Overstreet 
251401ec4dbSKent Overstreet 	if (WARN_ON(buf->nr_tabstops >= ARRAY_SIZE(buf->_tabstops)))
252401ec4dbSKent Overstreet 		return -EINVAL;
253401ec4dbSKent Overstreet 
254401ec4dbSKent Overstreet 	buf->_tabstops[buf->nr_tabstops++] = prev_tabstop + spaces;
255401ec4dbSKent Overstreet 	buf->has_indent_or_tabstops = true;
256401ec4dbSKent Overstreet 	return 0;
257401ec4dbSKent Overstreet }
258401ec4dbSKent Overstreet 
259401ec4dbSKent Overstreet /**
26096dea3d5SKent Overstreet  * bch2_printbuf_indent_add() - add to the current indent level
261401ec4dbSKent Overstreet  *
262401ec4dbSKent Overstreet  * @buf: printbuf to control
263401ec4dbSKent Overstreet  * @spaces: number of spaces to add to the current indent level
264401ec4dbSKent Overstreet  *
265401ec4dbSKent Overstreet  * Subsequent lines, and the current line if the output position is at the start
266401ec4dbSKent Overstreet  * of the current line, will be indented by @spaces more spaces.
267401ec4dbSKent Overstreet  */
bch2_printbuf_indent_add(struct printbuf * buf,unsigned spaces)268401ec4dbSKent Overstreet void bch2_printbuf_indent_add(struct printbuf *buf, unsigned spaces)
269401ec4dbSKent Overstreet {
270401ec4dbSKent Overstreet 	if (WARN_ON_ONCE(buf->indent + spaces < buf->indent))
271401ec4dbSKent Overstreet 		spaces = 0;
272401ec4dbSKent Overstreet 
273401ec4dbSKent Overstreet 	buf->indent += spaces;
274401ec4dbSKent Overstreet 	prt_chars(buf, ' ', spaces);
275401ec4dbSKent Overstreet 
276401ec4dbSKent Overstreet 	buf->has_indent_or_tabstops = true;
277401ec4dbSKent Overstreet }
278401ec4dbSKent Overstreet 
279401ec4dbSKent Overstreet /**
28096dea3d5SKent Overstreet  * bch2_printbuf_indent_sub() - subtract from the current indent level
281401ec4dbSKent Overstreet  *
282401ec4dbSKent Overstreet  * @buf: printbuf to control
283401ec4dbSKent Overstreet  * @spaces: number of spaces to subtract from the current indent level
284401ec4dbSKent Overstreet  *
285401ec4dbSKent Overstreet  * Subsequent lines, and the current line if the output position is at the start
286401ec4dbSKent Overstreet  * of the current line, will be indented by @spaces less spaces.
287401ec4dbSKent Overstreet  */
bch2_printbuf_indent_sub(struct printbuf * buf,unsigned spaces)288401ec4dbSKent Overstreet void bch2_printbuf_indent_sub(struct printbuf *buf, unsigned spaces)
289401ec4dbSKent Overstreet {
290401ec4dbSKent Overstreet 	if (WARN_ON_ONCE(spaces > buf->indent))
291401ec4dbSKent Overstreet 		spaces = buf->indent;
292401ec4dbSKent Overstreet 
293401ec4dbSKent Overstreet 	if (buf->last_newline + buf->indent == buf->pos) {
294401ec4dbSKent Overstreet 		buf->pos -= spaces;
295401ec4dbSKent Overstreet 		printbuf_nul_terminate(buf);
296401ec4dbSKent Overstreet 	}
297401ec4dbSKent Overstreet 	buf->indent -= spaces;
298401ec4dbSKent Overstreet 
299401ec4dbSKent Overstreet 	if (!buf->indent && !buf->nr_tabstops)
300401ec4dbSKent Overstreet 		buf->has_indent_or_tabstops = false;
301401ec4dbSKent Overstreet }
302401ec4dbSKent Overstreet 
bch2_prt_newline(struct printbuf * buf)303401ec4dbSKent Overstreet void bch2_prt_newline(struct printbuf *buf)
304401ec4dbSKent Overstreet {
305401ec4dbSKent Overstreet 	bch2_printbuf_make_room(buf, 1 + buf->indent);
306401ec4dbSKent Overstreet 
307acce32a5SKent Overstreet 	__prt_char_reserved(buf, '\n');
308401ec4dbSKent Overstreet 
309401ec4dbSKent Overstreet 	buf->last_newline	= buf->pos;
310401ec4dbSKent Overstreet 
311acce32a5SKent Overstreet 	__prt_chars_reserved(buf, ' ', buf->indent);
312401ec4dbSKent Overstreet 
313acce32a5SKent Overstreet 	printbuf_nul_terminate_reserved(buf);
314401ec4dbSKent Overstreet 
315401ec4dbSKent Overstreet 	buf->last_field		= buf->pos;
316401ec4dbSKent Overstreet 	buf->cur_tabstop	= 0;
317401ec4dbSKent Overstreet }
318401ec4dbSKent Overstreet 
bch2_printbuf_strip_trailing_newline(struct printbuf * out)319*3811f48aSKent Overstreet void bch2_printbuf_strip_trailing_newline(struct printbuf *out)
320*3811f48aSKent Overstreet {
321*3811f48aSKent Overstreet 	for (int p = out->pos - 1; p >= 0; --p) {
322*3811f48aSKent Overstreet 		if (out->buf[p] == '\n') {
323*3811f48aSKent Overstreet 			out->pos = p;
324*3811f48aSKent Overstreet 			break;
325*3811f48aSKent Overstreet 		}
326*3811f48aSKent Overstreet 		if (out->buf[p] != ' ')
327*3811f48aSKent Overstreet 			break;
328*3811f48aSKent Overstreet 	}
329*3811f48aSKent Overstreet 
330*3811f48aSKent Overstreet 	printbuf_nul_terminate_reserved(out);
331*3811f48aSKent Overstreet }
332*3811f48aSKent Overstreet 
__prt_tab(struct printbuf * out)333401ec4dbSKent Overstreet static void __prt_tab(struct printbuf *out)
334401ec4dbSKent Overstreet {
335401ec4dbSKent Overstreet 	int spaces = max_t(int, 0, cur_tabstop(out) - printbuf_linelen(out));
336401ec4dbSKent Overstreet 
337401ec4dbSKent Overstreet 	prt_chars(out, ' ', spaces);
338401ec4dbSKent Overstreet 
339401ec4dbSKent Overstreet 	out->last_field = out->pos;
340401ec4dbSKent Overstreet 	out->cur_tabstop++;
341401ec4dbSKent Overstreet }
342401ec4dbSKent Overstreet 
343401ec4dbSKent Overstreet /**
34496dea3d5SKent Overstreet  * bch2_prt_tab() - Advance printbuf to the next tabstop
34596dea3d5SKent Overstreet  * @out:	printbuf to control
346401ec4dbSKent Overstreet  *
347401ec4dbSKent Overstreet  * Advance output to the next tabstop by printing spaces.
348401ec4dbSKent Overstreet  */
bch2_prt_tab(struct printbuf * out)349401ec4dbSKent Overstreet void bch2_prt_tab(struct printbuf *out)
350401ec4dbSKent Overstreet {
351401ec4dbSKent Overstreet 	if (WARN_ON(!cur_tabstop(out)))
352401ec4dbSKent Overstreet 		return;
353401ec4dbSKent Overstreet 
354401ec4dbSKent Overstreet 	__prt_tab(out);
355401ec4dbSKent Overstreet }
356401ec4dbSKent Overstreet 
__prt_tab_rjust(struct printbuf * buf)357401ec4dbSKent Overstreet static void __prt_tab_rjust(struct printbuf *buf)
358401ec4dbSKent Overstreet {
359401ec4dbSKent Overstreet 	int pad = (int) cur_tabstop(buf) - (int) printbuf_linelen(buf);
3602dcb605eSKent Overstreet 	if (pad > 0)
3612dcb605eSKent Overstreet 		printbuf_insert_spaces(buf, buf->last_field, pad);
362401ec4dbSKent Overstreet 
363401ec4dbSKent Overstreet 	buf->last_field = buf->pos;
364401ec4dbSKent Overstreet 	buf->cur_tabstop++;
365401ec4dbSKent Overstreet }
366401ec4dbSKent Overstreet 
367401ec4dbSKent Overstreet /**
36896dea3d5SKent Overstreet  * bch2_prt_tab_rjust - Advance printbuf to the next tabstop, right justifying
369401ec4dbSKent Overstreet  * previous output
370401ec4dbSKent Overstreet  *
371401ec4dbSKent Overstreet  * @buf: printbuf to control
372401ec4dbSKent Overstreet  *
373401ec4dbSKent Overstreet  * Advance output to the next tabstop by inserting spaces immediately after the
374401ec4dbSKent Overstreet  * previous tabstop, right justifying previously outputted text.
375401ec4dbSKent Overstreet  */
bch2_prt_tab_rjust(struct printbuf * buf)376401ec4dbSKent Overstreet void bch2_prt_tab_rjust(struct printbuf *buf)
377401ec4dbSKent Overstreet {
378401ec4dbSKent Overstreet 	if (WARN_ON(!cur_tabstop(buf)))
379401ec4dbSKent Overstreet 		return;
380401ec4dbSKent Overstreet 
381401ec4dbSKent Overstreet 	__prt_tab_rjust(buf);
382401ec4dbSKent Overstreet }
383401ec4dbSKent Overstreet 
384401ec4dbSKent Overstreet /**
38596dea3d5SKent Overstreet  * bch2_prt_bytes_indented() - Print an array of chars, handling embedded control characters
386401ec4dbSKent Overstreet  *
38796dea3d5SKent Overstreet  * @out:	output printbuf
388401ec4dbSKent Overstreet  * @str:	string to print
389401ec4dbSKent Overstreet  * @count:	number of bytes to print
390401ec4dbSKent Overstreet  *
391401ec4dbSKent Overstreet  * The following contol characters are handled as so:
392401ec4dbSKent Overstreet  *   \n: prt_newline	newline that obeys current indent level
393401ec4dbSKent Overstreet  *   \t: prt_tab	advance to next tabstop
394401ec4dbSKent Overstreet  *   \r: prt_tab_rjust	advance to next tabstop, with right justification
395401ec4dbSKent Overstreet  */
bch2_prt_bytes_indented(struct printbuf * out,const char * str,unsigned count)396401ec4dbSKent Overstreet void bch2_prt_bytes_indented(struct printbuf *out, const char *str, unsigned count)
397401ec4dbSKent Overstreet {
3982dcb605eSKent Overstreet 	unsigned indent_pos = out->pos;
399401ec4dbSKent Overstreet 	prt_bytes(out, str, count);
4002dcb605eSKent Overstreet 	printbuf_do_indent(out, indent_pos);
401401ec4dbSKent Overstreet }
402401ec4dbSKent Overstreet 
403401ec4dbSKent Overstreet /**
40496dea3d5SKent Overstreet  * bch2_prt_human_readable_u64() - Print out a u64 in human readable units
40596dea3d5SKent Overstreet  * @out:	output printbuf
40696dea3d5SKent Overstreet  * @v:		integer to print
407401ec4dbSKent Overstreet  *
40896dea3d5SKent Overstreet  * Units of 2^10 (default) or 10^3 are controlled via @out->si_units
409401ec4dbSKent Overstreet  */
bch2_prt_human_readable_u64(struct printbuf * out,u64 v)41096dea3d5SKent Overstreet void bch2_prt_human_readable_u64(struct printbuf *out, u64 v)
411401ec4dbSKent Overstreet {
41296dea3d5SKent Overstreet 	bch2_printbuf_make_room(out, 10);
413acce32a5SKent Overstreet 	unsigned len = string_get_size(v, 1, !out->si_units,
41496dea3d5SKent Overstreet 				       out->buf + out->pos,
41596dea3d5SKent Overstreet 				       printbuf_remaining_size(out));
416acce32a5SKent Overstreet 	printbuf_advance_pos(out, len);
417401ec4dbSKent Overstreet }
418401ec4dbSKent Overstreet 
419401ec4dbSKent Overstreet /**
42096dea3d5SKent Overstreet  * bch2_prt_human_readable_s64() - Print out a s64 in human readable units
42196dea3d5SKent Overstreet  * @out:	output printbuf
42296dea3d5SKent Overstreet  * @v:		integer to print
423401ec4dbSKent Overstreet  *
42496dea3d5SKent Overstreet  * Units of 2^10 (default) or 10^3 are controlled via @out->si_units
425401ec4dbSKent Overstreet  */
bch2_prt_human_readable_s64(struct printbuf * out,s64 v)42696dea3d5SKent Overstreet void bch2_prt_human_readable_s64(struct printbuf *out, s64 v)
427401ec4dbSKent Overstreet {
428401ec4dbSKent Overstreet 	if (v < 0)
42996dea3d5SKent Overstreet 		prt_char(out, '-');
43096dea3d5SKent Overstreet 	bch2_prt_human_readable_u64(out, abs(v));
431401ec4dbSKent Overstreet }
432401ec4dbSKent Overstreet 
433401ec4dbSKent Overstreet /**
43496dea3d5SKent Overstreet  * bch2_prt_units_u64() - Print out a u64 according to printbuf unit options
43596dea3d5SKent Overstreet  * @out:	output printbuf
43696dea3d5SKent Overstreet  * @v:		integer to print
437401ec4dbSKent Overstreet  *
438401ec4dbSKent Overstreet  * Units are either raw (default), or human reabable units (controlled via
439401ec4dbSKent Overstreet  * @buf->human_readable_units)
440401ec4dbSKent Overstreet  */
bch2_prt_units_u64(struct printbuf * out,u64 v)441401ec4dbSKent Overstreet void bch2_prt_units_u64(struct printbuf *out, u64 v)
442401ec4dbSKent Overstreet {
443401ec4dbSKent Overstreet 	if (out->human_readable_units)
444401ec4dbSKent Overstreet 		bch2_prt_human_readable_u64(out, v);
445401ec4dbSKent Overstreet 	else
446401ec4dbSKent Overstreet 		bch2_prt_printf(out, "%llu", v);
447401ec4dbSKent Overstreet }
448401ec4dbSKent Overstreet 
449401ec4dbSKent Overstreet /**
45096dea3d5SKent Overstreet  * bch2_prt_units_s64() - Print out a s64 according to printbuf unit options
45196dea3d5SKent Overstreet  * @out:	output printbuf
45296dea3d5SKent Overstreet  * @v:		integer to print
453401ec4dbSKent Overstreet  *
454401ec4dbSKent Overstreet  * Units are either raw (default), or human reabable units (controlled via
455401ec4dbSKent Overstreet  * @buf->human_readable_units)
456401ec4dbSKent Overstreet  */
bch2_prt_units_s64(struct printbuf * out,s64 v)457401ec4dbSKent Overstreet void bch2_prt_units_s64(struct printbuf *out, s64 v)
458401ec4dbSKent Overstreet {
459401ec4dbSKent Overstreet 	if (v < 0)
460401ec4dbSKent Overstreet 		prt_char(out, '-');
461401ec4dbSKent Overstreet 	bch2_prt_units_u64(out, abs(v));
462401ec4dbSKent Overstreet }
463401ec4dbSKent Overstreet 
bch2_prt_string_option(struct printbuf * out,const char * const list[],size_t selected)464401ec4dbSKent Overstreet void bch2_prt_string_option(struct printbuf *out,
465401ec4dbSKent Overstreet 			    const char * const list[],
466401ec4dbSKent Overstreet 			    size_t selected)
467401ec4dbSKent Overstreet {
468acce32a5SKent Overstreet 	for (size_t i = 0; list[i]; i++)
469401ec4dbSKent Overstreet 		bch2_prt_printf(out, i == selected ? "[%s] " : "%s ", list[i]);
470401ec4dbSKent Overstreet }
471401ec4dbSKent Overstreet 
bch2_prt_bitflags(struct printbuf * out,const char * const list[],u64 flags)472401ec4dbSKent Overstreet void bch2_prt_bitflags(struct printbuf *out,
473401ec4dbSKent Overstreet 		       const char * const list[], u64 flags)
474401ec4dbSKent Overstreet {
475401ec4dbSKent Overstreet 	unsigned bit, nr = 0;
476401ec4dbSKent Overstreet 	bool first = true;
477401ec4dbSKent Overstreet 
478401ec4dbSKent Overstreet 	while (list[nr])
479401ec4dbSKent Overstreet 		nr++;
480401ec4dbSKent Overstreet 
48148f866e9SKent Overstreet 	while (flags && (bit = __ffs64(flags)) < nr) {
482401ec4dbSKent Overstreet 		if (!first)
483401ec4dbSKent Overstreet 			bch2_prt_printf(out, ",");
484401ec4dbSKent Overstreet 		first = false;
485401ec4dbSKent Overstreet 		bch2_prt_printf(out, "%s", list[bit]);
48648f866e9SKent Overstreet 		flags ^= BIT_ULL(bit);
487401ec4dbSKent Overstreet 	}
488401ec4dbSKent Overstreet }
489560661d4SKent Overstreet 
bch2_prt_bitflags_vector(struct printbuf * out,const char * const list[],unsigned long * v,unsigned nr)490560661d4SKent Overstreet void bch2_prt_bitflags_vector(struct printbuf *out,
491560661d4SKent Overstreet 			      const char * const list[],
492560661d4SKent Overstreet 			      unsigned long *v, unsigned nr)
493560661d4SKent Overstreet {
494560661d4SKent Overstreet 	bool first = true;
495560661d4SKent Overstreet 	unsigned i;
496560661d4SKent Overstreet 
497560661d4SKent Overstreet 	for (i = 0; i < nr; i++)
498560661d4SKent Overstreet 		if (!list[i]) {
499560661d4SKent Overstreet 			nr = i - 1;
500560661d4SKent Overstreet 			break;
501560661d4SKent Overstreet 		}
502560661d4SKent Overstreet 
503560661d4SKent Overstreet 	for_each_set_bit(i, v, nr) {
504560661d4SKent Overstreet 		if (!first)
505560661d4SKent Overstreet 			bch2_prt_printf(out, ",");
506560661d4SKent Overstreet 		first = false;
507560661d4SKent Overstreet 		bch2_prt_printf(out, "%s", list[i]);
508560661d4SKent Overstreet 	}
509560661d4SKent Overstreet }
510