less: optional support of -R
authorDenys Vlasenko <vda.linux@googlemail.com>
Mon, 22 Jan 2018 13:38:51 +0000 (14:38 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 22 Jan 2018 13:38:51 +0000 (14:38 +0100)
Based on patches by Lubomir Rintel <lkundrak@v3.sk>

function                                             old     new   delta
read_lines                                           653     722     +69
less_main                                           2464    2531     +67
packed_usage                                       32202   32239     +37
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 173/0)             Total: 173 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
miscutils/less.c

index d60e6d920b3163c881de971f204a207ea50bf9ee..c3221a49fe48f89345e69fbbce86c595243f88d1 100644 (file)
 //config:      bool "Enable -N (dynamic switching of line numbers)"
 //config:      default y
 //config:      depends on FEATURE_LESS_DASHCMD
+//config:
+//config:config FEATURE_LESS_RAW
+//config:      bool "Enable -R ('raw control characters')"
+//config:      default y
+//config:      depends on FEATURE_LESS_DASHCMD
+//config:      help
+//config:      This is essential for less applet to work with tools that use colors
+//config:      and paging, such as git, systemd tools or nmcli.
+//config:
+//config:config FEATURE_LESS_ENV
+//config:      bool "Take options from $LESS environment variable"
+//config:      default y
+//config:      depends on FEATURE_LESS_DASHCMD
+//config:      help
+//config:      This is essential for less applet to work with tools that use colors
+//config:      and paging, such as git, systemd tools or nmcli.
 
 //applet:IF_LESS(APPLET(less, BB_DIR_USR_BIN, BB_SUID_DROP))
 
 
 //usage:#define less_trivial_usage
 //usage:       "[-E" IF_FEATURE_LESS_REGEXP("I")IF_FEATURE_LESS_FLAGS("Mm")
-//usage:       "N" IF_FEATURE_LESS_TRUNCATE("S") "h~] [FILE]..."
+//usage:       "N" IF_FEATURE_LESS_TRUNCATE("S") IF_FEATURE_LESS_TRUNCATE("R") "h~] [FILE]..."
 //usage:#define less_full_usage "\n\n"
 //usage:       "View FILE (or stdin) one screenful at a time\n"
 //usage:     "\n       -E      Quit once the end of a file is reached"
 //usage:       IF_FEATURE_LESS_TRUNCATE(
 //usage:     "\n       -S      Truncate long lines"
 //usage:       )
+//usage:       IF_FEATURE_LESS_RAW(
+//usage:     "\n       -R      Remove color escape codes in input"
+//usage:       )
 //usage:     "\n       -~      Suppress ~s displayed past EOF"
 
 #include <sched.h>  /* sched_yield() */
@@ -157,6 +176,7 @@ enum {
        FLAG_TILDE = 1 << 4,
        FLAG_I = 1 << 5,
        FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_TRUNCATE,
+       FLAG_R = (1 << 7) * ENABLE_FEATURE_LESS_RAW,
 /* hijack command line options variable for internal state vars */
        LESS_STATE_MATCH_BACKWARDS = 1 << 15,
 };
@@ -207,6 +227,9 @@ 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
@@ -513,6 +536,26 @@ 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') {
@@ -1776,6 +1819,25 @@ int less_main(int argc, char **argv)
        num_files = argc - optind;
        files = argv;
 
+       /* Tools typically pass LESS="FRSXMK".
+        * The options we don't understand are ignored. */
+       if (ENABLE_FEATURE_LESS_ENV) {
+               char *c = getenv("LESS");
+               if (c) while (*c) switch (*c++) {
+               case 'M':
+                       option_mask32 |= FLAG_M;
+                       break;
+               case 'R':
+                       option_mask32 |= FLAG_R;
+                       break;
+               case 'S':
+                       option_mask32 |= FLAG_S;
+                       break;
+               default:
+                       break;
+               }
+       }
+
        /* Another popular pager, most, detects when stdout
         * is not a tty and turns into cat. This makes sense. */
        if (!isatty(STDOUT_FILENO))