From nobody Sat Apr 11 21:09:18 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F05A0C19F2A for ; Mon, 8 Aug 2022 02:41:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243581AbiHHCl5 (ORCPT ); Sun, 7 Aug 2022 22:41:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32768 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235536AbiHHClj (ORCPT ); Sun, 7 Aug 2022 22:41:39 -0400 Received: from casper.infradead.org (casper.infradead.org [IPv6:2001:8b0:10b:1236::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1FE8621B4 for ; Sun, 7 Aug 2022 19:41:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc: Content-Type:Content-ID:Content-Description; bh=oEg9AsCOZDOluYzZVESlodsCM31B8LHTgFU/mz1O/dw=; b=immJNjPThnAPBDU9T21B8lJXu7 5qJsOClID5bGeO/98Rhe3D7yJlmZkx6zLOewvA5JdShAy9zRzYvu2AQUgZZiYzwhFhMdr3qocjlYG 9unXn04o6NqSqHTc46e6LfZ+eg3HdrEf9Wnj4dtzQ1g4FOve28IsxZNSHably9eTfAjOvTlndTbxT K2df1ctq6jc+58HBj24GZMY1oFuBhlR2Xf4T0fG/KOLFCf2+2N7R3Bn64snoDjMSWqmdmFtLvBfTE dHTxFZE/X+rKFYqQP5WJN5Pp4xG2z2Z0r5FrDQfghOzJyHXe5hrHWo6LEcwFCcVav6GIYrHDzYBkD GtLZ+A+w==; Received: from willy by casper.infradead.org with local (Exim 4.94.2 #2 (Red Hat Linux)) id 1oKshx-00DVRc-6z; Mon, 08 Aug 2022 02:41:33 +0000 From: "Matthew Wilcox (Oracle)" To: linux-kernel@vger.kernel.org, pmladek@suse.com, Kent Overstreet Subject: [PATCH v5 07/32] lib/printbuf: Tabstops, indenting Date: Mon, 8 Aug 2022 03:41:03 +0100 Message-Id: <20220808024128.3219082-8-willy@infradead.org> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220808024128.3219082-1-willy@infradead.org> References: <20220808024128.3219082-1-willy@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Kent Overstreet This patch adds two new features to printbuf for structured formatting: - Indent level: the indent level, as a number of spaces, may be increased with pr_indent_add() and decreased with pr_indent_sub(). Subsequent lines, when started with pr_newline() (not "\n", although that may change) will then be intended according to the current indent level. This helps with pretty-printers that structure a large amonut of data across multiple lines and multiple functions. - Tabstops: Tabstops may be set by assigning to the printbuf->tabstops array. Then, pr_tab() may be used to advance to the next tabstop, printing as many spaces as required - leaving previous output left justified to the previous tabstop. pr_tab_rjust() advances to the next tabstop but inserts the spaces just after the previous tabstop - right justifying the previously-outputted text to the next tabstop. Signed-off-by: Kent Overstreet --- include/linux/printbuf.h | 30 ++++++++++ lib/printbuf.c | 125 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h index 71f631c49f4e..c1a482b6c0a8 100644 --- a/include/linux/printbuf.h +++ b/include/linux/printbuf.h @@ -40,6 +40,23 @@ * memory allocation failure we usually don't want to bail out and unwind = - we * want to print what we've got, on a best-effort basis. But code that doe= s want * to return -ENOMEM may check printbuf.allocation_failure. + * + * Indenting, tabstops: + * + * To aid is writing multi-line pretty printers spread across multiple + * functions, printbufs track the current indent level. + * + * printbuf_indent_push() and printbuf_indent_pop() increase and decrease = the current indent + * level, respectively. + * + * To use tabstops, set printbuf->tabstops[]; they are in units of spaces,= from + * start of line. Once set, prt_tab() will output spaces up to the next ta= bstop. + * prt_tab_rjust() will also advance the current line of text up to the ne= xt + * tabstop, but it does so by shifting text since the previous tabstop up = to the + * next tabstop - right justifying it. + * + * Make sure you use prt_newline() instead of \n in the format string for = indent + * level and tabstops to work corretly. */ =20 #include @@ -49,18 +66,29 @@ struct printbuf { char *buf; unsigned size; unsigned pos; + unsigned last_newline; + unsigned last_field; + unsigned indent; /* * If nonzero, allocations will be done with GFP_ATOMIC: */ u8 atomic; bool allocation_failure:1; bool heap_allocated:1; + u8 tabstop; + u8 tabstops[4]; }; =20 int printbuf_make_room(struct printbuf *, unsigned); const char *printbuf_str(const struct printbuf *); void printbuf_exit(struct printbuf *); =20 +void prt_newline(struct printbuf *); +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 *); + /* Initializer for a heap allocated printbuf: */ #define PRINTBUF ((struct printbuf) { .heap_allocated =3D true }) =20 @@ -191,6 +219,8 @@ static inline void printbuf_reset(struct printbuf *buf) { buf->pos =3D 0; buf->allocation_failure =3D 0; + buf->indent =3D 0; + buf->tabstop =3D 0; } =20 /** diff --git a/lib/printbuf.c b/lib/printbuf.c index e3e5a791b244..395c681e3acb 100644 --- a/lib/printbuf.c +++ b/lib/printbuf.c @@ -12,6 +12,11 @@ #include #include =20 +static inline size_t printbuf_linelen(struct printbuf *buf) +{ + return buf->pos - buf->last_newline; +} + int printbuf_make_room(struct printbuf *out, unsigned extra) { unsigned new_size; @@ -74,3 +79,123 @@ void printbuf_exit(struct printbuf *buf) } } EXPORT_SYMBOL(printbuf_exit); + +void prt_newline(struct printbuf *buf) +{ + unsigned i; + + printbuf_make_room(buf, 1 + buf->indent); + + __prt_char(buf, '\n'); + + buf->last_newline =3D buf->pos; + + for (i =3D 0; i < buf->indent; i++) + __prt_char(buf, ' '); + + printbuf_nul_terminate(buf); + + buf->last_field =3D buf->pos; + buf->tabstop =3D 0; +} +EXPORT_SYMBOL(prt_newline); + +/** + * printbuf_indent_add - add to the current indent level + * + * @buf: printbuf to control + * @spaces: number of spaces to add to the current indent level + * + * Subsequent lines, and the current line if the output position is at the= start + * of the current line, will be indented by @spaces more spaces. + */ +void printbuf_indent_add(struct printbuf *buf, unsigned spaces) +{ + if (WARN_ON_ONCE(buf->indent + spaces < buf->indent)) + spaces =3D 0; + + buf->indent +=3D spaces; + while (spaces--) + prt_char(buf, ' '); +} +EXPORT_SYMBOL(printbuf_indent_add); + +/** + * printbuf_indent_sub - subtract from the current indent level + * + * @buf: printbuf to control + * @spaces: number of spaces to subtract from the current indent level + * + * Subsequent lines, and the current line if the output position is at the= start + * of the current line, will be indented by @spaces less spaces. + */ +void printbuf_indent_sub(struct printbuf *buf, unsigned spaces) +{ + if (WARN_ON_ONCE(spaces > buf->indent)) + spaces =3D buf->indent; + + if (buf->last_newline + buf->indent =3D=3D buf->pos) { + buf->pos -=3D spaces; + printbuf_nul_terminate(buf); + } + buf->indent -=3D 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) +{ + int spaces =3D max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linel= en(out)); + + BUG_ON(out->tabstop > ARRAY_SIZE(out->tabstops)); + + prt_chars(out, ' ', spaces); + + out->last_field =3D out->pos; + out->tabstop++; +} +EXPORT_SYMBOL(prt_tab); + +/** + * 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 afte= r the + * previous tabstop, right justifying previously outputted text. + */ +void prt_tab_rjust(struct printbuf *buf) +{ + BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + + if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) { + unsigned move =3D buf->pos - buf->last_field; + unsigned shift =3D buf->tabstops[buf->tabstop] - + printbuf_linelen(buf); + + printbuf_make_room(buf, shift); + + if (buf->last_field + shift < buf->size) + memmove(buf->buf + buf->last_field + shift, + buf->buf + buf->last_field, + min(move, buf->size - 1 - buf->last_field - shift)); + + if (buf->last_field < buf->size) + memset(buf->buf + buf->last_field, ' ', + min(shift, buf->size - buf->last_field)); + + buf->pos +=3D shift; + printbuf_nul_terminate(buf); + } + + buf->last_field =3D buf->pos; + buf->tabstop++; +} +EXPORT_SYMBOL(prt_tab_rjust); --=20 2.35.1