summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-08-11 20:36:59 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2022-10-03 23:51:09 -0400
commitc45f754ba21cddc13624aad75f93744569107c57 (patch)
treea9f42d89a27bfe63e3a79981c5f21ee8e7cc7268
parenta6b4106e33f5b1e930b9d1d8cb1af50905ac6036 (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.h6
-rw-r--r--lib/printbuf.c99
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