1 // SPDX-License-Identifier: LGPL-2.1+
2 /* Copyright (C) 2022 Kent Overstreet */
5 #include <linux/export.h>
6 #include <linux/kernel.h>
7 #include <linux/slab.h>
8 #include <linux/string_helpers.h>
12 static inline unsigned printbuf_linelen(struct printbuf *buf)
14 return buf->pos - buf->last_newline;
17 int bch2_printbuf_make_room(struct printbuf *out, unsigned extra)
22 if (!out->heap_allocated)
25 /* Reserved space for terminating nul: */
28 if (out->pos + extra < out->size)
31 new_size = roundup_pow_of_two(out->size + extra);
34 * Note: output buffer must be freeable with kfree(), it's not required
35 * that the user use printbuf_exit().
37 buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT);
40 out->allocation_failure = true;
49 void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
57 len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args2);
58 } while (len + 1 >= printbuf_remaining(out) &&
59 !bch2_printbuf_make_room(out, len + 1));
61 len = min_t(size_t, len,
62 printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
66 void bch2_prt_printf(struct printbuf *out, const char *fmt, ...)
73 len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args);
75 } while (len + 1 >= printbuf_remaining(out) &&
76 !bch2_printbuf_make_room(out, len + 1));
78 len = min_t(size_t, len,
79 printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
84 * printbuf_str - returns printbuf's buf as a C string, guaranteed to be null
87 const char *bch2_printbuf_str(const struct printbuf *buf)
90 * If we've written to a printbuf then it's guaranteed to be a null
91 * terminated string - but if we haven't, then we might not have
92 * allocated a buffer at all:
100 * printbuf_exit - exit a printbuf, freeing memory it owns and poisoning it
101 * against accidental use.
103 void bch2_printbuf_exit(struct printbuf *buf)
105 if (buf->heap_allocated) {
107 buf->buf = ERR_PTR(-EINTR); /* poison value */
111 void bch2_printbuf_tabstops_reset(struct printbuf *buf)
113 buf->nr_tabstops = 0;
116 void bch2_printbuf_tabstop_pop(struct printbuf *buf)
118 if (buf->nr_tabstops)
123 * printbuf_tabstop_set - add a tabstop, n spaces from the previous tabstop
125 * @buf: printbuf to control
126 * @spaces: number of spaces from previous tabpstop
128 * In the future this function may allocate memory if setting more than
129 * PRINTBUF_INLINE_TABSTOPS or setting tabstops more than 255 spaces from start
132 int bch2_printbuf_tabstop_push(struct printbuf *buf, unsigned spaces)
134 unsigned prev_tabstop = buf->nr_tabstops
135 ? buf->_tabstops[buf->nr_tabstops - 1]
138 if (WARN_ON(buf->nr_tabstops >= ARRAY_SIZE(buf->_tabstops)))
141 buf->_tabstops[buf->nr_tabstops++] = prev_tabstop + spaces;
142 buf->has_indent_or_tabstops = true;
147 * printbuf_indent_add - add to the current indent level
149 * @buf: printbuf to control
150 * @spaces: number of spaces to add to the current indent level
152 * Subsequent lines, and the current line if the output position is at the start
153 * of the current line, will be indented by @spaces more spaces.
155 void bch2_printbuf_indent_add(struct printbuf *buf, unsigned spaces)
157 if (WARN_ON_ONCE(buf->indent + spaces < buf->indent))
160 buf->indent += spaces;
161 prt_chars(buf, ' ', spaces);
163 buf->has_indent_or_tabstops = true;
167 * printbuf_indent_sub - subtract from the current indent level
169 * @buf: printbuf to control
170 * @spaces: number of spaces to subtract from the current indent level
172 * Subsequent lines, and the current line if the output position is at the start
173 * of the current line, will be indented by @spaces less spaces.
175 void bch2_printbuf_indent_sub(struct printbuf *buf, unsigned spaces)
177 if (WARN_ON_ONCE(spaces > buf->indent))
178 spaces = buf->indent;
180 if (buf->last_newline + buf->indent == buf->pos) {
182 printbuf_nul_terminate(buf);
184 buf->indent -= spaces;
186 if (!buf->indent && !buf->nr_tabstops)
187 buf->has_indent_or_tabstops = false;
190 void bch2_prt_newline(struct printbuf *buf)
194 bch2_printbuf_make_room(buf, 1 + buf->indent);
196 __prt_char(buf, '\n');
198 buf->last_newline = buf->pos;
200 for (i = 0; i < buf->indent; i++)
201 __prt_char(buf, ' ');
203 printbuf_nul_terminate(buf);
205 buf->last_field = buf->pos;
206 buf->cur_tabstop = 0;
210 * Returns spaces from start of line, if set, or 0 if unset:
212 static inline unsigned cur_tabstop(struct printbuf *buf)
214 return buf->cur_tabstop < buf->nr_tabstops
215 ? buf->_tabstops[buf->cur_tabstop]
219 static void __prt_tab(struct printbuf *out)
221 int spaces = max_t(int, 0, cur_tabstop(out) - printbuf_linelen(out));
223 prt_chars(out, ' ', spaces);
225 out->last_field = out->pos;
230 * prt_tab - Advance printbuf to the next tabstop
232 * @buf: printbuf to control
234 * Advance output to the next tabstop by printing spaces.
236 void bch2_prt_tab(struct printbuf *out)
238 if (WARN_ON(!cur_tabstop(out)))
244 static void __prt_tab_rjust(struct printbuf *buf)
246 unsigned move = buf->pos - buf->last_field;
247 int pad = (int) cur_tabstop(buf) - (int) printbuf_linelen(buf);
250 bch2_printbuf_make_room(buf, pad);
252 if (buf->last_field + pad < buf->size)
253 memmove(buf->buf + buf->last_field + pad,
254 buf->buf + buf->last_field,
255 min(move, buf->size - 1 - buf->last_field - pad));
257 if (buf->last_field < buf->size)
258 memset(buf->buf + buf->last_field, ' ',
259 min((unsigned) pad, buf->size - buf->last_field));
262 printbuf_nul_terminate(buf);
265 buf->last_field = buf->pos;
270 * prt_tab_rjust - Advance printbuf to the next tabstop, right justifying
273 * @buf: printbuf to control
275 * Advance output to the next tabstop by inserting spaces immediately after the
276 * previous tabstop, right justifying previously outputted text.
278 void bch2_prt_tab_rjust(struct printbuf *buf)
280 if (WARN_ON(!cur_tabstop(buf)))
283 __prt_tab_rjust(buf);
287 * prt_bytes_indented - Print an array of chars, handling embedded control characters
289 * @out: printbuf to output to
290 * @str: string to print
291 * @count: number of bytes to print
293 * The following contol characters are handled as so:
294 * \n: prt_newline newline that obeys current indent level
295 * \t: prt_tab advance to next tabstop
296 * \r: prt_tab_rjust advance to next tabstop, with right justification
298 void bch2_prt_bytes_indented(struct printbuf *out, const char *str, unsigned count)
300 const char *unprinted_start = str;
301 const char *end = str + count;
303 if (!out->has_indent_or_tabstops || out->suppress_indent_tabstop_handling) {
304 prt_bytes(out, str, count);
311 prt_bytes(out, unprinted_start, str - unprinted_start);
312 unprinted_start = str + 1;
313 bch2_prt_newline(out);
316 if (likely(cur_tabstop(out))) {
317 prt_bytes(out, unprinted_start, str - unprinted_start);
318 unprinted_start = str + 1;
323 if (likely(cur_tabstop(out))) {
324 prt_bytes(out, unprinted_start, str - unprinted_start);
325 unprinted_start = str + 1;
326 __prt_tab_rjust(out);
334 prt_bytes(out, unprinted_start, str - unprinted_start);
338 * prt_human_readable_u64 - Print out a u64 in human readable units
340 * Units of 2^10 (default) or 10^3 are controlled via @buf->si_units
342 void bch2_prt_human_readable_u64(struct printbuf *buf, u64 v)
344 bch2_printbuf_make_room(buf, 10);
345 buf->pos += string_get_size(v, 1, !buf->si_units,
347 printbuf_remaining_size(buf));
351 * prt_human_readable_s64 - Print out a s64 in human readable units
353 * Units of 2^10 (default) or 10^3 are controlled via @buf->si_units
355 void bch2_prt_human_readable_s64(struct printbuf *buf, s64 v)
359 bch2_prt_human_readable_u64(buf, abs(v));
363 * prt_units_u64 - Print out a u64 according to printbuf unit options
365 * Units are either raw (default), or human reabable units (controlled via
366 * @buf->human_readable_units)
368 void bch2_prt_units_u64(struct printbuf *out, u64 v)
370 if (out->human_readable_units)
371 bch2_prt_human_readable_u64(out, v);
373 bch2_prt_printf(out, "%llu", v);
377 * prt_units_s64 - Print out a s64 according to printbuf unit options
379 * Units are either raw (default), or human reabable units (controlled via
380 * @buf->human_readable_units)
382 void bch2_prt_units_s64(struct printbuf *out, s64 v)
386 bch2_prt_units_u64(out, abs(v));
389 void bch2_prt_string_option(struct printbuf *out,
390 const char * const list[],
395 for (i = 0; list[i]; i++)
396 bch2_prt_printf(out, i == selected ? "[%s] " : "%s ", list[i]);
399 void bch2_prt_bitflags(struct printbuf *out,
400 const char * const list[], u64 flags)
402 unsigned bit, nr = 0;
408 while (flags && (bit = __ffs(flags)) < nr) {
410 bch2_prt_printf(out, ",");
412 bch2_prt_printf(out, "%s", list[bit]);