[Concept,11/13] console: Add err_putsn() for length-based error output

Message ID 20260204001002.2638622-12-sjg@u-boot.org
State New
Headers
Series Add putsn() for length-based console output |

Commit Message

Simon Glass Feb. 4, 2026, 12:09 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add err_putsn() to output errors with a specified length, which is more
efficient when the length is already known (e.g., from snprintf()).

Create console_putsn_select() which uses device putsn() methods when
CONFIG_CONSOLE_PUTSN is enabled, falling back to puts() otherwise.

Refactor err_puts() to call err_putsn() and update err_printf() to use
the length returned by vscnprintf().

Co-developed-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 common/console.c  | 59 +++++++++++++++++++++++++++++++++++++++--------
 include/console.h | 15 ++++++++++++
 2 files changed, 64 insertions(+), 10 deletions(-)
  

Patch

diff --git a/common/console.c b/common/console.c
index f9669a0e028..96e8977ce06 100644
--- a/common/console.c
+++ b/common/console.c
@@ -291,30 +291,56 @@  static void console_putc_pager(int file, const char c)
 }
 
 /**
- * console_puts_select() - Output a string to all console devices
+ * console_putsn_select() - Output a string with length to console devices
  *
  * @file: File number to output to (e,g, stdout, see stdio.h)
  * @serial_only: true to output only to serial, false to output to everything
  *	else
  * @s: String to output
+ * @len: Length of string to output
  */
-static void console_puts_select(int file, bool serial_only, const char *s)
+static void console_putsn_select(int file, bool serial_only, const char *s,
+				 int len)
 {
+	struct stdio_dev *sdev;
 	int i;
 	struct stdio_dev *dev;
 
 	for_each_console_dev(i, file, dev) {
 		bool is_serial = console_dev_is_serial(dev);
 
-		if (dev->puts && serial_only == is_serial)
-			dev->puts(dev, s);
+		if (serial_only == is_serial) {
+			sdev = dev;
+			if (CONFIG_IS_ENABLED(CONSOLE_PUTSN) && sdev->putsn)
+				sdev->putsn(sdev, s, len);
+			else if (sdev->puts)
+				sdev->puts(sdev, s);
+		}
 	}
 }
 
-void err_puts(bool serial_only, const char *s)
+/**
+ * console_puts_select() - Output a string to all console devices
+ *
+ * @file: File number to output to (e,g, stdout, see stdio.h)
+ * @serial_only: true to output only to serial, false to output to everything
+ *	else
+ * @s: String to output
+ */
+static void console_puts_select(int file, bool serial_only, const char *s)
+{
+	console_putsn_select(file, serial_only, s, strlen(s));
+}
+
+void err_putsn(bool serial_only, const char *s, int len)
 {
 	if (gd->flags & GD_FLG_DEVINIT)
-		console_puts_select(stderr, serial_only, s);
+		console_putsn_select(stderr, serial_only, s, len);
+}
+
+void err_puts(bool serial_only, const char *s)
+{
+	err_putsn(serial_only, s, strlen(s));
 }
 
 int err_printf(bool serial_only, const char *fmt, ...)
@@ -330,7 +356,7 @@  int err_printf(bool serial_only, const char *fmt, ...)
 	 */
 	ret = vscnprintf(buf, sizeof(buf), fmt, args);
 	va_end(args);
-	err_puts(serial_only, buf);
+	err_putsn(serial_only, buf, ret);
 
 	return ret;
 }
@@ -472,11 +498,24 @@  static inline void console_putc_pager(int file, const char c)
 	stdio_devices[file]->putc(stdio_devices[file], c);
 }
 
-void console_puts_select(int file, bool serial_only, const char *s)
+static inline void console_putsn_select(int file, bool serial_only,
+					const char *s, int len)
 {
+	struct stdio_dev *sdev;
+
 	if ((gd->flags & GD_FLG_DEVINIT) &&
-	    serial_only == console_dev_is_serial(stdio_devices[file]))
-		stdio_devices[file]->puts(stdio_devices[file], s);
+	    serial_only == console_dev_is_serial(stdio_devices[file])) {
+		sdev = stdio_devices[file];
+		if (CONFIG_IS_ENABLED(CONSOLE_PUTSN) && sdev->putsn)
+			sdev->putsn(sdev, s, len);
+		else
+			sdev->puts(sdev, s);
+	}
+}
+
+void console_puts_select(int file, bool serial_only, const char *s)
+{
+	console_putsn_select(file, serial_only, s, strlen(s));
 }
 
 static inline void console_puts_pager(int file, const char *s)
diff --git a/include/console.h b/include/console.h
index 83b8d4f642c..486131f8bf7 100644
--- a/include/console.h
+++ b/include/console.h
@@ -158,6 +158,21 @@  static inline bool console_record_isempty(void)
  */
 int console_announce_r(void);
 
+/**
+ * err_putsn() - Output a string with length to selected console devices
+ *
+ * This writes to stderr only. It is useful for outputting errors when the
+ * length is already known.
+ *
+ * Outputs exactly @len characters from @s, regardless of any nul characters.
+ *
+ * @serial_only: true to output only to serial, false to output to everything
+ *	else
+ * @s: String to output (need not be nul-terminated)
+ * @len: Number of characters to output
+ */
+void err_putsn(bool serial_only, const char *s, int len);
+
 /**
  * err_puts() - Output a string to selected console devices
  *