[Concept,07/16] console: Support paging with single characters

Message ID 20250822142153.3404275-8-sjg@u-boot.org
State New
Headers
Series Introduce a pager for the console |

Commit Message

Simon Glass Aug. 22, 2025, 2:21 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

A single character may result in a stall waiting for user input, which
means that it may request that a string be output. So when the pager is
active we never actually use the devices' putc() methods. Add a special
case so they don't go to wrack and ruin.

As before, the pager is only supported with CONFIG_CONSOLE_MUX enabled.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/console.c    | 22 +++++++++++++++-------
 test/common/pager.c | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 7 deletions(-)
  

Patch

diff --git a/common/console.c b/common/console.c
index 9bc506f0464..7bafe98375a 100644
--- a/common/console.c
+++ b/common/console.c
@@ -322,14 +322,22 @@  static int console_tstc(int file)
 	return 0;
 }
 
+static void console_puts_pager(int file, const char *s);
+
 static void console_putc_pager(int file, const char c)
 {
-	int i;
-	struct stdio_dev *dev;
+	if (IS_ENABLED(CONFIG_CONSOLE_PAGER) && gd_pager()) {
+		char str[2] = {c, '\0'};
 
-	for_each_console_dev(i, file, dev) {
-		if (dev->putc != NULL)
-			dev->putc(dev, c);
+		console_puts_pager(file, str);
+	} else {
+		int i;
+		struct stdio_dev *dev;
+
+		for_each_console_dev(i, file, dev) {
+			if (dev->putc != NULL)
+				dev->putc(dev, c);
+		}
 	}
 }
 
@@ -757,8 +765,8 @@  void putc(const char c)
 		return pre_console_putc(c);
 
 	if (gd->flags & GD_FLG_DEVINIT) {
-		/* Send to the standard output */
-		fputc(stdout, c);
+		/* Send to the standard output through pager system */
+		console_putc_pager(stdout, c);
 	} else {
 		/* Send directly to the handler */
 		pre_console_putc(c);
diff --git a/test/common/pager.c b/test/common/pager.c
index 2512652ea01..c1c2d40f648 100644
--- a/test/common/pager.c
+++ b/test/common/pager.c
@@ -425,3 +425,43 @@  static int pager_test_bypass_mode(struct unit_test_state *uts)
 	return 0;
 }
 COMMON_TEST(pager_test_bypass_mode, 0);
+
+/* Test that single character output via putc goes through pager */
+static int pager_test_putc(struct unit_test_state *uts)
+{
+	struct pager *pag;
+	const char *result;
+
+	/* Init pager */
+	ut_assertok(pager_init(&pag, 20, 1024));
+	pager_set_bypass(pag, true);
+
+	/*
+	 * Test that individual characters can be posted via pager API
+	 * This verifies that console_putc_pager() routes through the pager
+	 * system
+	 */
+	result = pager_post(pag, true, "A");
+	ut_asserteq_ptr("A", result); /* Bypass mode returns original pointer */
+
+	result = pager_post(pag, true, "\n");
+	ut_asserteq_ptr("\n", result);
+
+	result = pager_post(pag, true, "B");
+	ut_asserteq_ptr("B", result);
+
+	/* Disable bypass to test normal functionality with single chars */
+	pager_set_bypass(pag, false);
+
+	result = pager_post(pag, true, "X");
+	ut_assertnonnull(result);
+	ut_asserteq_str("X", result);
+
+	result = pager_next(pag, true, 0);
+	ut_assertnull(result);
+
+	pager_uninit(pag);
+
+	return 0;
+}
+COMMON_TEST(pager_test_putc, 0);