From patchwork Mon Jun 20 00:42:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kent Overstreet X-Patchwork-Id: 12886899 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9F6EDCCA47A for ; Mon, 20 Jun 2022 00:42:53 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 0CD986B007E; Sun, 19 Jun 2022 20:42:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 057676B0080; Sun, 19 Jun 2022 20:42:52 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id DC3946B0081; Sun, 19 Jun 2022 20:42:52 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id CE8E26B007E for ; Sun, 19 Jun 2022 20:42:52 -0400 (EDT) Received: from smtpin16.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 9E1D633B28 for ; Mon, 20 Jun 2022 00:42:52 +0000 (UTC) X-FDA: 79596764184.16.3FE9765 Received: from mail-qk1-f175.google.com (mail-qk1-f175.google.com [209.85.222.175]) by imf21.hostedemail.com (Postfix) with ESMTP id 49AC61C0004 for ; Mon, 20 Jun 2022 00:42:52 +0000 (UTC) Received: by mail-qk1-f175.google.com with SMTP id o73so6881336qke.7 for ; Sun, 19 Jun 2022 17:42:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=K9eoCaahKKF8GPcnHNvxh314XQP7M2mbXnjspgXSnVM=; b=kzWZ14UhWQpr2qaOlYS9QzrKiCUW6Xki1/EC5YcTuk5f5Mk9/O4KLB0qiX8Ne65In/ CmjidGpj819sto9/TLGGZUjJKfvvwrmOFdiMD/9uWzMgdeK7tfjDZkqutc+4PAEotN2v s7GlrUlWfy8+xJ2pmBRxTpwR8JDtUYuzd47cbQL8pc/+33zJ6IRYXnIm/5CsjhSY6HQn F/0au4BW21jw3kHihRksYnCPYw/0rff3z+YAT4juNJkTsUJAf8rLZp/RPy/fVltfOyFs C0LLJvdJYnIPwGuJxVS4z0qr1Ce8p79jMu0IOjuO1gZptsD5LxffMCQzXk8MpOtyklAH Vd7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=K9eoCaahKKF8GPcnHNvxh314XQP7M2mbXnjspgXSnVM=; b=kOAUT2tWwZmUvCF0DDcXz9uYng7eJnc+xAkaUMlRDr+ZD1v5ASNNGB7q+y5o8/gIdf Wo1PKvo3LEVdDx9Ux6yerYEioB3RyaIlDDbfBoUtnbfdOGnUIn4Gjl0jRuGW2l/ISJmc uxOvXEE4P85cP+nN2f2I9tIkxKDCsEg++IFvX0WnDwEfkn46w0CXcw/peHwOR5GMpuak dfqTuDBLVtXqpM+zywuXN21mRthVTCPZP4hrXoWzbzxMvFYG545CXx/kTUMHH3LFwkgR 6ZmkheUKK3Mo9gApJiSOlbj6+4iED/C1GIYFwGgSWDYfwSg3ZLTtQ+Dy/geCWB6A2tDG c+7g== X-Gm-Message-State: AJIora+JsHNbjwZD7CNerOIOpbcgKiexc7WaeSzMDeAxOFuC7wHGbhzt 4LWvIKhqxlr8z0MaZToXNQ== X-Google-Smtp-Source: AGRyM1sMZcU2iV/7Pecfr7pTe2lv/4b97s6iQX0qqt/h/ZDOAxOF/7yxG51Ro60SoZQ5zTofSHExNw== X-Received: by 2002:a37:9fc9:0:b0:6a6:c16b:e634 with SMTP id i192-20020a379fc9000000b006a6c16be634mr14842818qke.230.1655685771574; Sun, 19 Jun 2022 17:42:51 -0700 (PDT) Received: from localhost (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id u3-20020a05620a454300b006a69ee117b6sm11144854qkp.97.2022.06.19.17.42.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Jun 2022 17:42:50 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, pmladek@suse.com Cc: Kent Overstreet , rostedt@goodmis.org, enozhatsky@chromium.org, linux@rasmusvillemoes.dk, willy@infradead.org Subject: [PATCH v4 08/34] lib/printbuf: Tabstops, indenting Date: Sun, 19 Jun 2022 20:42:07 -0400 Message-Id: <20220620004233.3805-9-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220620004233.3805-1-kent.overstreet@gmail.com> References: <20220620004233.3805-1-kent.overstreet@gmail.com> MIME-Version: 1.0 ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1655685772; a=rsa-sha256; cv=none; b=sMF4AgzfoCfK7zFPbfY3F6b5M23xAgzX8DKbeqk+86vSDe7VCVT9Vn8m1QpaicutaarbLt dkQNEIO9VI2YNuazHpkak2sUjJv6D5qMflDzJiPKHL0Ml3llAbUcBIp8h26C5O+6DpT8pI dETShBk5l/nfCXjowENFMlY6jdzoiVM= ARC-Authentication-Results: i=1; imf21.hostedemail.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=kzWZ14Uh; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf21.hostedemail.com: domain of kent.overstreet@gmail.com designates 209.85.222.175 as permitted sender) smtp.mailfrom=kent.overstreet@gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1655685772; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=K9eoCaahKKF8GPcnHNvxh314XQP7M2mbXnjspgXSnVM=; b=mSgE+bAVTqAO79rFrATgsyQxrOAIeUT0TatfIwVG0KyslGteDLdwxblc/LNaaoGaS/o74D ttyaqLmdf0tc4PpKeFHtazUWzIqyDMz8gjXKqLakHtbVt8FV7meW/z3ya1Lls48LZD3H7C GngxMpjCEGrhgdbDQ5iTiHUf+jG5jHw= X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: 49AC61C0004 X-Stat-Signature: 6ukthk3c9w37gmq1o7hsgdab9he7epfi X-Rspam-User: Authentication-Results: imf21.hostedemail.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=kzWZ14Uh; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf21.hostedemail.com: domain of kent.overstreet@gmail.com designates 209.85.222.175 as permitted sender) smtp.mailfrom=kent.overstreet@gmail.com X-HE-Tag: 1655685772-806600 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: 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 382863afa7..1e43c47891 100644 --- a/include/linux/printbuf.h +++ b/include/linux/printbuf.h @@ -36,6 +36,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 does 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 tabstop. + * prt_tab_rjust() will also advance the current line of text up to the next + * 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. */ #include @@ -45,18 +62,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]; }; int printbuf_make_room(struct printbuf *, unsigned); const char *printbuf_str(const struct printbuf *); void printbuf_exit(struct printbuf *); +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 = true }) @@ -187,6 +215,8 @@ static inline void printbuf_reset(struct printbuf *buf) { buf->pos = 0; buf->allocation_failure = 0; + buf->indent = 0; + buf->tabstop = 0; } /** diff --git a/lib/printbuf.c b/lib/printbuf.c index 8c70128e31..a7f80f63ca 100644 --- a/lib/printbuf.c +++ b/lib/printbuf.c @@ -12,6 +12,11 @@ #include #include +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; @@ -69,3 +74,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 = buf->pos; + + for (i = 0; i < buf->indent; i++) + __prt_char(buf, ' '); + + printbuf_nul_terminate(buf); + + buf->last_field = buf->pos; + buf->tabstop = 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 = 0; + + buf->indent += 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 = buf->indent; + + if (buf->last_newline + buf->indent == buf->pos) { + buf->pos -= spaces; + printbuf_nul_terminate(buf); + } + buf->indent -= 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 = max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linelen(out)); + + BUG_ON(out->tabstop > ARRAY_SIZE(out->tabstops)); + + 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 + * + * @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) +{ + BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + + if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) { + unsigned move = buf->pos - buf->last_field; + unsigned shift = 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 += shift; + printbuf_nul_terminate(buf); + } + + buf->last_field = buf->pos; + buf->tabstop++; +} +EXPORT_SYMBOL(prt_tab_rjust);