diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-08-11 20:36:59 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2022-10-03 23:51:09 -0400 |
commit | c45f754ba21cddc13624aad75f93744569107c57 (patch) | |
tree | a9f42d89a27bfe63e3a79981c5f21ee8e7cc7268 | |
parent | a6b4106e33f5b1e930b9d1d8cb1af50905ac6036 (diff) |
lib/printbuf: prt_str_indented()
This adds a new helper, prt_str_indented(), which handles embedded
control characters by calling prt_newline(), prt_tab(), and
prt_tab_rjust() as needed.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | include/linux/printbuf.h | 6 | ||||
-rw-r--r-- | lib/printbuf.c | 99 |
2 files changed, 88 insertions, 17 deletions
diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h index 861c5d75f852..eb2edb86b22c 100644 --- a/include/linux/printbuf.h +++ b/include/linux/printbuf.h @@ -99,6 +99,7 @@ void printbuf_indent_add(struct printbuf *, unsigned); void printbuf_indent_sub(struct printbuf *, unsigned); void prt_tab(struct printbuf *); void prt_tab_rjust(struct printbuf *); +void prt_bytes_indented(struct printbuf *, const char *, unsigned); void prt_human_readable_u64(struct printbuf *, u64); void prt_human_readable_s64(struct printbuf *, s64); void prt_units_u64(struct printbuf *, u64); @@ -211,6 +212,11 @@ static inline void prt_str(struct printbuf *out, const char *str) prt_bytes(out, str, strlen(str)); } +static inline void prt_str_indented(struct printbuf *out, const char *str) +{ + prt_bytes_indented(out, str, strlen(str)); +} + static inline void prt_hex_byte(struct printbuf *out, u8 byte) { printbuf_make_room(out, 2); diff --git a/lib/printbuf.c b/lib/printbuf.c index 047470025748..3fbb74754b48 100644 --- a/lib/printbuf.c +++ b/lib/printbuf.c @@ -143,39 +143,40 @@ void printbuf_indent_sub(struct printbuf *buf, unsigned spaces) } EXPORT_SYMBOL(printbuf_indent_sub); -/** - * prt_tab - Advance printbuf to the next tabstop - * - * @buf: printbuf to control - * - * Advance output to the next tabstop by printing spaces. - */ -void prt_tab(struct printbuf *out) +static inline bool tabstop_is_set(struct printbuf *buf) { - int spaces = max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linelen(out)); + return buf->tabstop < ARRAY_SIZE(buf->tabstops) && + buf->tabstops[buf->tabstop]; +} - BUG_ON(out->tabstop > ARRAY_SIZE(out->tabstops)); +static void __prt_tab(struct printbuf *out) +{ + int spaces = max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linelen(out)); prt_chars(out, ' ', spaces); out->last_field = out->pos; out->tabstop++; } -EXPORT_SYMBOL(prt_tab); /** - * prt_tab_rjust - Advance printbuf to the next tabstop, right justifying - * previous output + * prt_tab - Advance printbuf to the next tabstop * * @buf: printbuf to control * - * Advance output to the next tabstop by inserting spaces immediately after the - * previous tabstop, right justifying previously outputted text. + * Advance output to the next tabstop by printing spaces. */ -void prt_tab_rjust(struct printbuf *buf) +void prt_tab(struct printbuf *out) { - BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + if (WARN_ON(!tabstop_is_set(out))) + return; + + __prt_tab(out); +} +EXPORT_SYMBOL(prt_tab); +static void __prt_tab_rjust(struct printbuf *buf) +{ if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) { unsigned move = buf->pos - buf->last_field; unsigned shift = buf->tabstops[buf->tabstop] - @@ -199,9 +200,73 @@ void prt_tab_rjust(struct printbuf *buf) buf->last_field = buf->pos; buf->tabstop++; } + +/** + * prt_tab_rjust - Advance printbuf to the next tabstop, right justifying + * previous output + * + * @buf: printbuf to control + * + * Advance output to the next tabstop by inserting spaces immediately after the + * previous tabstop, right justifying previously outputted text. + */ +void prt_tab_rjust(struct printbuf *buf) +{ + if (WARN_ON(!tabstop_is_set(buf))) + return; + + __prt_tab_rjust(buf); +} EXPORT_SYMBOL(prt_tab_rjust); /** + * prt_bytes_indented - Print an array of chars, handling embedded control characters + * + * @out: printbuf to output to + * @str: string to print + * @count: number of bytes to print + * + * The following contol characters are handled as so: + * \n: prt_newline newline that obeys current indent level + * \t: prt_tab advance to next tabstop + * \r: prt_tab_rjust advance to next tabstop, with right justification + */ +void prt_bytes_indented(struct printbuf *out, const char *str, unsigned count) +{ + const char *unprinted_start = str; + const char *end = str + count; + + while (str != end) { + switch (*str) { + case '\n': + prt_bytes(out, unprinted_start, str - unprinted_start); + unprinted_start = str + 1; + prt_newline(out); + break; + case '\t': + if (likely(tabstop_is_set(out))) { + prt_bytes(out, unprinted_start, str - unprinted_start); + unprinted_start = str + 1; + __prt_tab(out); + } + break; + case '\r': + if (likely(tabstop_is_set(out))) { + prt_bytes(out, unprinted_start, str - unprinted_start); + unprinted_start = str + 1; + __prt_tab_rjust(out); + } + break; + } + + str++; + } + + prt_bytes(out, unprinted_start, str - unprinted_start); +} +EXPORT_SYMBOL(prt_bytes_indented); + +/** * prt_human_readable_u64 - Print out a u64 in human readable units * * Units of 2^10 (default) or 10^3 are controlled via @buf->si_units |