From 1ea33e7be32d753af124da079b6808fb6cee9720 Mon Sep 17 00:00:00 2001 From: Thassilo Schulze Date: Fri, 28 Jun 2024 16:11:06 +0200 Subject: [PATCH] lib/*: Turn `\n` into `\r\n` See the TODOs in the diff Signed-off-by: Thassilo Schulze Reviewed-by: Michalis Pappas Reviewed-by: Simon Kuenzer Approved-by: Simon Kuenzer GitHub-Closes: #1479 --- lib/devfs/stdout.c | 39 +++++++++++++++++++++++++++- lib/nolibc/scanf.c | 42 ++++++++++++++++++++++++++++-- lib/nolibc/stdio.c | 46 ++++++++++++++++++++++++++++++--- lib/posix-tty/serial.c | 40 ++++++++++++++++++++++++++-- lib/syscall_shim/uk_prsyscall.c | 11 ++++++-- lib/ukdebug/print.c | 44 +++++++++++++++++++++++++++++-- 6 files changed, 209 insertions(+), 13 deletions(-) diff --git a/lib/devfs/stdout.c b/lib/devfs/stdout.c index 600a04dfa..091f45952 100644 --- a/lib/devfs/stdout.c +++ b/lib/devfs/stdout.c @@ -44,9 +44,46 @@ #ifdef CONFIG_LIBDEVFS_DEV_STDOUT #define DEV_STDOUT_NAME "stdout" +/* TODO: Some consoles require both a newline and a carriage return to + * go to the start of the next line. This kind of behavior should be in + * a single place in posix-tty. We keep this workaround until we have feature + * in posix-tty that handles newline characters correctly. + */ +static inline __ssz _console_out(const char *buf, __sz len) +{ + const char *next_nl = NULL; + __sz l = len; + __sz off = 0; + __ssz rc = 0; + + if (unlikely(!len)) + return 0; + if (unlikely(!buf)) + return -EINVAL; + + while (l > 0) { + next_nl = memchr(buf, '\n', l); + if (next_nl) { + off = next_nl - buf; + if ((rc = uk_console_out(buf, off)) < 0) + return rc; + if ((rc = uk_console_out("\r\n", 2)) < 0) + return rc; + buf = next_nl + 1; + l -= off + 1; + } else { + if ((rc = uk_console_out(buf, l)) < 0) + return rc; + break; + } + } + + return len; +} + static int __write_fn(void *dst __unused, void *src, size_t *cnt) { - int ret = uk_console_out(src, *cnt); + int ret = _console_out(src, *cnt); if (ret < 0) /* TODO: remove -1 when vfscore switches to negative diff --git a/lib/nolibc/scanf.c b/lib/nolibc/scanf.c index 0ccc5db7f..c6077d86e 100644 --- a/lib/nolibc/scanf.c +++ b/lib/nolibc/scanf.c @@ -11,6 +11,44 @@ #if CONFIG_LIBUKCONSOLE #include +#include + +/* TODO: Some consoles require both a newline and a carriage return to + * go to the start of the next line. This kind of behavior should be in + * a single place in posix-tty. We keep this workaround until we have feature + * in posix-tty that handles newline characters correctly. + */ +static inline __ssz _console_out(const char *buf, __sz len) +{ + const char *next_nl = NULL; + __sz l = len; + __sz off = 0; + __ssz rc = 0; + + if (unlikely(!len)) + return 0; + if (unlikely(!buf)) + return -EINVAL; + + while (l > 0) { + next_nl = memchr(buf, '\n', l); + if (next_nl) { + off = next_nl - buf; + if ((rc = uk_console_out(buf, off)) < 0) + return rc; + if ((rc = uk_console_out("\r\n", 2)) < 0) + return rc; + buf = next_nl + 1; + l -= off + 1; + } else { + if ((rc = uk_console_out(buf, l)) < 0) + return rc; + break; + } + } + + return len; +} #endif /* CONFIG_LIBUKCONSOLE */ static int @@ -45,14 +83,14 @@ uk_scanf(void *buffer __maybe_unused, size_t *cnt) /* DELETE control character */ if (buf - 1 != buffer) { /* If this is not the first byte */ - uk_console_out("\b \b", 3); + _console_out("\b \b", 3); buf -= 1; if (bytes_total > 0) bytes_total--; } buf -= 1; } else { - uk_console_out(buf - bytes_read, bytes_read); + _console_out(buf - bytes_read, bytes_read); bytes_total += bytes_read; } diff --git a/lib/nolibc/stdio.c b/lib/nolibc/stdio.c index 8bf69c369..ab1f89169 100644 --- a/lib/nolibc/stdio.c +++ b/lib/nolibc/stdio.c @@ -67,8 +67,46 @@ #include #include + #if CONFIG_LIBUKCONSOLE #include + +/* TODO: Some consoles require both a newline and a carriage return to + * go to the start of the next line. This kind of behavior should be in + * a single place in posix-tty. We keep this workaround until we have feature + * in posix-tty that handles newline characters correctly. + */ +static inline __ssz _console_out(const char *buf, __sz len) +{ + const char *next_nl = NULL; + __sz l = len; + __sz off = 0; + __ssz rc = 0; + + if (unlikely(!len)) + return 0; + if (unlikely(!buf)) + return -EINVAL; + + while (l > 0) { + next_nl = memchr(buf, '\n', l); + if (next_nl) { + off = next_nl - buf; + if ((rc = uk_console_out(buf, off)) < 0) + return rc; + if ((rc = uk_console_out("\r\n", 2)) < 0) + return rc; + buf = next_nl + 1; + l -= off + 1; + } else { + if ((rc = uk_console_out(buf, l)) < 0) + return rc; + break; + } + } + + return len; +} #endif /* CONFIG_LIBUKCONSOLE */ /* 64 bits + 0-Byte at end */ @@ -451,7 +489,7 @@ int vfprintf(FILE *fp __maybe_unused, const char *fmt __maybe_unused, */ if (fp == stdout || fp == stderr) #if CONFIG_LIBUKCONSOLE - ret = uk_console_out(buf, ret); + ret = _console_out(buf, ret); #else /* !CONFIG_LIBUKCONSOLE */ ret = strlen(buf); #endif /* !CONFIG_LIBUKCONSOLE */ @@ -503,7 +541,7 @@ int fputc(int _c __maybe_unused, FILE *fp __maybe_unused) unsigned char c = _c; if (fp == stdout || fp == stderr) - ret = uk_console_out((char *)&c, 1); + ret = _console_out((char *)&c, 1); if (ret == 1) return _c; @@ -530,11 +568,11 @@ fputs_internal(const char *restrict s __maybe_unused, len = strlen(s); if (stream == stdout || stream == stderr) - ret = uk_console_out(s, len); + ret = _console_out(s, len); else return EOF; - /* If uk_console_out wasn't able to write all characters, assume + /* If _console_out wasn't able to write all characters, assume * that an error happened and there is no point in retrying. */ if ((size_t)ret != len) diff --git a/lib/posix-tty/serial.c b/lib/posix-tty/serial.c index 97d2f7f4e..3c0dfac13 100644 --- a/lib/posix-tty/serial.c +++ b/lib/posix-tty/serial.c @@ -50,6 +50,42 @@ static const char SERIAL_TERMIOS_CONTROL_CHARS[KNCCS] = { [VWERASE] = 027, }; +/* TODO: Some consoles require both a newline and a carriage return to + * go to the start of the next line. This kind of behavior should be in + * a single place in posix-tty. We keep this workaround until we have feature + * in posix-tty that handles newline characters correctly. + */ +static inline __ssz _console_out(const char *buf, __sz len) +{ + const char *next_nl = NULL; + __sz l = len; + __sz off = 0; + __ssz rc = 0; + + if (unlikely(!len)) + return 0; + if (unlikely(!buf)) + return -EINVAL; + + while (l > 0) { + next_nl = memchr(buf, '\n', l); + if (next_nl) { + off = next_nl - buf; + if ((rc = uk_console_out(buf, off)) < 0) + return rc; + if ((rc = uk_console_out("\r\n", 2)) < 0) + return rc; + buf = next_nl + 1; + l -= off + 1; + } else { + if ((rc = uk_console_out(buf, l)) < 0) + return rc; + break; + } + } + + return len; +} static ssize_t serial_read(const struct uk_file *f, const struct iovec *iov, int iovcnt, @@ -86,7 +122,7 @@ static ssize_t serial_read(const struct uk_file *f, *last = '\n'; /* Echo the input to the console (NOT stdout!) */ - uk_console_out(buf, bytes_read); + _console_out(buf, bytes_read); if (*last == '\n') break; @@ -118,7 +154,7 @@ static ssize_t serial_write(const struct uk_file *f __maybe_unused, if (unlikely(!buf && len)) return -EFAULT; - bytes_written = uk_console_out(buf, len); + bytes_written = _console_out(buf, len); if (unlikely(bytes_written < 0)) return bytes_written; diff --git a/lib/syscall_shim/uk_prsyscall.c b/lib/syscall_shim/uk_prsyscall.c index 8dbe1d46d..f98ae94c9 100644 --- a/lib/syscall_shim/uk_prsyscall.c +++ b/lib/syscall_shim/uk_prsyscall.c @@ -1277,11 +1277,18 @@ static void pr_syscall(struct uk_streambuf *sb, int fmtf, break; } + /* TODO: Some consoles require both a newline and a carriage return to + * go to the start of the next line. There should be a dedicated TTY + * layer to take care of this. Once that layer exists, stop printing + * a CRLF sequence if `UK_PRSYSCALL_FMTF_NEWLINE` is set and print a + * single newline character instead. + */ + /* Try to fix the line ending if content got truncated */ if (uk_streambuf_istruncated(sb)) { /* reserve an extra byte for the newline ending if configured */ __sz needed_len = 3 - + ((fmtf & UK_PRSYSCALL_FMTF_NEWLINE) ? 1 : 0); + + ((fmtf & UK_PRSYSCALL_FMTF_NEWLINE) ? 2 : 0); if (uk_streambuf_buflen(sb) > needed_len + 1) { sb->seek = uk_streambuf_seek(sb) - needed_len; uk_streambuf_strcpy(sb, "..."); @@ -1289,7 +1296,7 @@ static void pr_syscall(struct uk_streambuf *sb, int fmtf, } if (fmtf & UK_PRSYSCALL_FMTF_NEWLINE) - uk_streambuf_strcpy(sb, "\n"); + uk_streambuf_strcpy(sb, "\r\n"); } int uk_snprsyscall(char *buf, __sz maxlen, int fmtf, long syscall_num, diff --git a/lib/ukdebug/print.c b/lib/ukdebug/print.c index 9df40ce29..48659c182 100644 --- a/lib/ukdebug/print.c +++ b/lib/ukdebug/print.c @@ -51,6 +51,7 @@ #if CONFIG_LIBUKCONSOLE #include +#include #endif /* CONFIG_LIBUKCONSOLE */ #if CONFIG_LIBUKDEBUG_ANSI_COLOR @@ -105,11 +106,50 @@ struct _vprint_console { int prevlvl; }; +#if CONFIG_LIBUKCONSOLE +/* TODO: Some consoles require both a newline and a carriage return to + * go to the start of the next line. This kind of behavior should be in + * a single place in posix-tty. We keep this workaround until we have feature + * in posix-tty that handles newline characters correctly. + */ +static inline __ssz _console_out(const char *buf, __sz len) +{ + const char *next_nl = NULL; + __sz l = len; + __sz off = 0; + __ssz rc = 0; + + if (unlikely(!len)) + return 0; + if (unlikely(!buf)) + return -EINVAL; + + while (l > 0) { + next_nl = memchr(buf, '\n', l); + if (next_nl) { + off = next_nl - buf; + if ((rc = uk_console_out(buf, off)) < 0) + return rc; + if ((rc = uk_console_out("\r\n", 2)) < 0) + return rc; + buf = next_nl + 1; + l -= off + 1; + } else { + if ((rc = uk_console_out(buf, l)) < 0) + return rc; + break; + } + } + + return len; +} +#endif /* CONFIG_LIBUKCONSOLE */ + /* Console state for kernel output */ #if CONFIG_LIBUKDEBUG_REDIR_PRINTD || CONFIG_LIBUKDEBUG_PRINTK static struct _vprint_console kern = { #if CONFIG_LIBUKCONSOLE - .cout = uk_console_out, + .cout = _console_out, #else .cout = NULL, #endif /* CONFIG_LIBUKCONSOLE */ @@ -122,7 +162,7 @@ static struct _vprint_console kern = { #if !CONFIG_LIBUKDEBUG_REDIR_PRINTD static struct _vprint_console debug = { #if CONFIG_LIBUKCONSOLE - .cout = uk_console_out, + .cout = _console_out, #else .cout = NULL, #endif /* CONFIG_LIBUKCONSOLE */ -- 2.39.5