Received: by 2002:a05:6358:4e97:b0:b3:742d:4702 with SMTP id ce23csp1869730rwb; Sun, 14 Aug 2022 14:48:19 -0700 (PDT) X-Google-Smtp-Source: AA6agR5FNrOTjUYrOpvZhASZd9UmSOMXxT2eaL4wRXxFHSXGTdYC9Ifs/bUWuIT5o7IdPtY4MZjd X-Received: by 2002:a17:906:9bc4:b0:730:957f:34b3 with SMTP id de4-20020a1709069bc400b00730957f34b3mr8535904ejc.231.1660513699088; Sun, 14 Aug 2022 14:48:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1660513699; cv=none; d=google.com; s=arc-20160816; b=hzo0XFatRi1rm/ep0cs+AQyyEhwBe/n1WAwLHe0xAP9IQ6mS7ukpHaQLZW/O1AOoht /QzOOu2rcKXcYes8VWvr+dRqm0qUVOM0lpHE+qwROG9GdHx/GjGyNDVSAghgt8tRT5E1 H5xtzfEqN8Yz9VL9B8QsIUV4JH044i5p58gPYRCOJ0XG6cT1uUJfILTtWlKW3FnouBrj Ox+AHPL2qrlu1G7WJURF6VlRZUigbiT8ruCCiIrd/InSG1DYQjkYWlItCyyF30DEGGuw BV0EHUyKjxoOT6lwuUY6Q9XaqkPUDybtxA0kYUsScVo3kXHbZo9DeIMe2OczHqDYIiEm 4BTw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=horHSp8tHcZLtXq8o1PrWMkpM2H9e98G2/bBsFsjhns=; b=zWeYHdt/AhZpapfcw88x8qcvHmOgt7fvx1nYd3c+tYkOoI3sNg6IAbq2iHDvEHEj4G WB02TfVwJht/s+i7GLwp1nAFFB4tBSM60qw4RcN7yHXVvxD0Wng9lFypQtDr6Q9VAv7l DFA9Qg5F//xJzbah9Z4qQm12Sume78Rt4JOg0GF5Lu30NtYbaY/IyNgiu2qVOtiuHE/b jnh58n2dWAJEUva/ugjCqyyXlIohHpP2oqhjPOLY6O8v9BA17eM7LV3aBBqfz5/RxWru DdU5DHmhBvS/vC/0TbITktpP8HET75sBRhDOg0dO7cw7XxEzHmQhka9gLSLPMkvYlF+s v53A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=hYfemuQu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id m19-20020a1709060d9300b007309d40276esi5357728eji.538.2022.08.14.14.47.53; Sun, 14 Aug 2022 14:48:19 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=hYfemuQu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240528AbiHNVVa (ORCPT + 99 others); Sun, 14 Aug 2022 17:21:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57156 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240419AbiHNVUw (ORCPT ); Sun, 14 Aug 2022 17:20:52 -0400 Received: from out0.migadu.com (out0.migadu.com [94.23.1.103]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A00CA6322 for ; Sun, 14 Aug 2022 14:20:45 -0700 (PDT) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1660512044; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=horHSp8tHcZLtXq8o1PrWMkpM2H9e98G2/bBsFsjhns=; b=hYfemuQuQ9Mbs8tLfaUQ/ap7vxqE9wtK4W2rabM7rxM9ljh1BzipG7qVOoy965WZugOjjs b3YPTw+WBKmbJ9Qnwq05bWaM5t7RdgXMtSr/t+E1xYnYvTQungGs/uYT33sdHE0ksCQI+9 ZcbsDqf6vbAhvT3qRdHdjdR+3qaHN4M= From: Kent Overstreet To: akpm@linux-foundation.org Cc: linux-kernel@vger.kernel.org, Kent Overstreet Subject: [PATCH 07/32] lib/printbuf: Tabstops, indenting Date: Sun, 14 Aug 2022 17:19:46 -0400 Message-Id: <20220814212011.1727798-8-kent.overstreet@linux.dev> In-Reply-To: <20220814212011.1727798-1-kent.overstreet@linux.dev> References: <20220814212011.1727798-1-kent.overstreet@linux.dev> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT X-Migadu-Auth-User: linux.dev X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 71f631c49f..c1a482b6c0 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 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 @@ -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]; }; 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 }) @@ -191,6 +219,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 e3e5a791b2..395c681e3a 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; @@ -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 = 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); -- 2.36.1