[PATCH 1/2] less: fully implement -R and print color escapes

FriendlyNeighborhoodShane shane.880088.supw at gmail.com
Thu Apr 14 19:19:02 UTC 2022


Emit NORMAL at newlines, like less, to deal with malformed input.
---
Fits a little akwardly into the output flow with a break and continue,
but it works.

 miscutils/less.c | 54 +++++++++++++++++++++++++++---------------------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/miscutils/less.c b/miscutils/less.c
index 8a0525cb7..392a3ef3c 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -139,7 +139,7 @@
 //usage:     "\n	-S	Truncate long lines"
 //usage:	)
 //usage:	IF_FEATURE_LESS_RAW(
-//usage:     "\n	-R	Remove color escape codes in input"
+//usage:     "\n	-R	Keep ANSI color escape codes in input"
 //usage:	)
 //usage:     "\n	-~	Suppress ~s displayed past EOF"
 
@@ -229,9 +229,6 @@ struct globals {
 	regex_t pattern;
 	smallint pattern_valid;
 #endif
-#if ENABLE_FEATURE_LESS_RAW
-	smallint in_escape;
-#endif
 #if ENABLE_FEATURE_LESS_ASK_TERMINAL
 	smallint winsize_err;
 #endif
@@ -541,26 +538,6 @@ static void read_lines(void)
 				*--p = '\0';
 				continue;
 			}
-#if ENABLE_FEATURE_LESS_RAW
-			if (option_mask32 & FLAG_R) {
-				if (c == '\033')
-					goto discard;
-				if (G.in_escape) {
-					if (isdigit(c)
-					 || c == '['
-					 || c == ';'
-					 || c == 'm'
-					) {
- discard:
-						G.in_escape = (c != 'm');
-						readpos++;
-						continue;
-					}
-					/* Hmm, unexpected end of "ESC [ N ; N m" sequence */
-					G.in_escape = 0;
-				}
-			}
-#endif
 			{
 				size_t new_last_line_pos = last_line_pos + 1;
 				if (c == '\t') {
@@ -780,6 +757,7 @@ static const char ctrlconv[] ALIGN1 =
 	 * '\n' is a former NUL - we subst it with @, not J */
 	"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x40\x4b\x4c\x4d\x4e\x4f"
 	"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f";
+static const char colctrl[] ALIGN1 = "\x1b[0123456789;m";
 
 static void print_lineno(const char *line)
 {
@@ -864,13 +842,32 @@ static void print_found(const char *line)
 void print_found(const char *line);
 #endif
 
+static size_t count_colctrl(const char *str) {
+	size_t n = strspn(str, colctrl);
+	// must end with m, need at least '<ESC>[m'
+	if (n < 3 || *(str+n-1) != 'm')
+		return 0;
+	return n;
+}
+
 static void print_ascii(const char *str)
 {
 	char buf[width+1];
 	char *p;
 	size_t n;
+#if ENABLE_FEATURE_LESS_RAW
+	size_t esc = 0;
+#endif
 
 	while (*str) {
+#if ENABLE_FEATURE_LESS_RAW
+		if (esc) {
+			printf("%.*s", (int) esc, str);
+			str += esc;
+			esc = 0;
+			continue;
+		}
+#endif
 		n = strcspn(str, controls);
 		if (n) {
 			if (!str[n]) break;
@@ -886,6 +883,14 @@ static void print_ascii(const char *str)
 			/* VT100's CSI, aka Meta-ESC. Who's inventor? */
 			/* I want to know who committed this sin */
 				*p++ = '{';
+#if ENABLE_FEATURE_LESS_RAW
+			else if ((option_mask32 & FLAG_R)
+					 && *str == '\033'
+					 // need at least '<ESC>[m'
+					 && (esc = count_colctrl(str))) {
+				break;
+			}
+#endif
 			else
 				*p++ = ctrlconv[(unsigned char)*str];
 			str++;
@@ -894,6 +899,7 @@ static void print_ascii(const char *str)
 		print_hilite(buf);
 	}
 	puts(str);
+	printf(NORMAL);
 }
 
 /* Print the buffer */
-- 
2.35.2



More information about the busybox mailing list