[Toybox] [PATCH] Make more(1) usable.

enh enh at google.com
Sat Apr 4 12:48:19 PDT 2015


actually, it looks like we're already hard-coding some escape
sequences? more(1) doesn't need anything that isn't in ANSI, so here's
an alternative patch that fixes the same bugs as the other patch but
also has a reverse-video prompt:

diff --git a/toys/pending/more.c b/toys/pending/more.c
index eb48fa7..59392ff 100644
--- a/toys/pending/more.c
+++ b/toys/pending/more.c
@@ -32,19 +32,45 @@ static void signal_handler(int sig)
   _exit(sig | 128);
 }

+static void show_file_header(const char *name)
+{
+  printf(":::::::::::::::::::::::\n%s\n:::::::::::::::::::::::\n", name);
+}
+
+static int prompt(FILE *cin, const char* fmt, ...)
+{
+  int input_key;
+  va_list ap;
+
+  printf("\33[7m"); // Reverse video before printing the prompt.
+
+  va_start(ap, fmt);
+  vfprintf(stdout, fmt, ap);
+  va_end(ap);
+
+  while (1) {
+    fflush(NULL);
+    input_key = tolower(getc(cin));
+    printf("\33[0m\33[1K\r"); // Reset all attributes, erase to start of line.
+    if (strchr(" \nrq", input_key)) {
+      return input_key;
+    }
+    printf("\33[7m(Enter:Next line Space:Next page Q:Quit R:Show the rest)");
+  }
+}
+
 static void do_cat_operation(int fd, char *name)
 {
   char *buf = NULL;

-  if(toys.optc > 1) printf(":::::::::::::::::::::::\n"
-      "%s\n:::::::::::::::::::::::\n",name);
+  if (toys.optc > 1) show_file_header(name);
   for (; (buf = get_line(fd)); free(buf)) printf("%s\n", buf);
 }

 void more_main()
 {
-  int ch, lines, input_key = 0, disp_more, more_msg_len;
-  unsigned rows = 24, cols = 80;
+  int ch, input_key = 0, show_prompt;
+  unsigned rows = 24, cols = 80, row = 0, col = 0;
   struct stat st;
   struct termios newf;
   FILE *fp, *cin;
@@ -55,7 +81,8 @@ void more_main()
   }

   TT.cin_fd = fileno(cin);
-  tcgetattr(TT.cin_fd,&TT.inf);
+  tcgetattr(TT.cin_fd, &TT.inf);
+
   //Prepare terminal for input
   memcpy(&newf, &TT.inf, sizeof(struct termios));
   newf.c_lflag &= ~(ICANON | ECHO);
@@ -71,46 +98,46 @@ void more_main()
         perror_msg("'%s'", *toys.optargs);
         continue;
     }
-    st.st_size = disp_more = more_msg_len = lines = 0;
+    st.st_size = show_prompt = col = row = 0;
     fstat(fileno(fp), &st);
     terminal_size(&cols, &rows);
     rows--;
-    if(toys.optc > 1) {
-      printf(":::::::::::::::::::::::\n"
-          "%s\n:::::::::::::::::::::::\n",*toys.optargs);
-      rows -= 3;
+
+    if (toys.optc > 1) {
+      show_file_header(*toys.optargs);
+      row += 3;
     }

     while ((ch = getc(fp)) != EOF) {
-      if (input_key != 'r' && disp_more) {
-        more_msg_len = printf("--More-- ");
-        if (st.st_size)
-          more_msg_len += printf("(%d%% of %lld bytes)",
-              (int) (100 * ( (double) ftell(fp) / (double) st.st_size)),
+      if (input_key != 'r' && show_prompt) {
+        if (st.st_size)
+          input_key = prompt(cin, "--More--(%d%% of %lld bytes)",
+              (int) (100 * ( (double) ftell(fp) / (double) st.st_size)),
               (long long)st.st_size);
-        fflush(NULL);
-
-        while (1) {
-          input_key = getc(cin);
-          input_key = tolower(input_key);
-          printf("\r%*s\r", more_msg_len, ""); // Remove previous msg
-          if (input_key == ' ' || input_key == '\n' || input_key == 'q'
-              || input_key == 'r') break;
-          more_msg_len = printf("(Enter:Next line Space:Next page
Q:Quit R:Show the rest)");
-        }
-        more_msg_len = lines = disp_more = 0;
+        else
+          input_key = prompt(cin, "--More--");
         if (input_key == 'q') goto stop;
+
+        col = row = show_prompt = 0;
         terminal_size(&cols, &rows);
         rows--;
       }

-      if (ch == '\n')
-        if (++lines >= rows || input_key == '\n') disp_more = 1;
       putchar(ch);
+      if (ch == '\t') col = (col | 0x7) + 1; else col++;
+      if (col == cols) putchar(ch = '\n');
+      if (ch == '\n') {
+        col = 0;
+        if (++row >= rows || input_key == '\n') show_prompt = 1;
+      }
     }
     fclose(fp);
-    fflush(NULL);
-  } while (*toys.optargs && *++toys.optargs);
+
+    if (*toys.optargs && *++toys.optargs) {
+      input_key = prompt(cin, "--More--(Next file: %s)", *toys.optargs);
+      if (input_key == 'q') goto stop;
+    }
+  } while (*toys.optargs);

 stop:
   tcsetattr(TT.cin_fd, TCSANOW, &TT.inf);


On Sat, Apr 4, 2015 at 12:00 PM, enh <enh at google.com> wrote:
> Yes, I know, "don't use pending". Sadly, more(1) is pretty useless
> without this. It gets confused by long lines or tabs.
>
> This patch also adds the missing prompt between multiple files.
>
> diff --git a/toys/pending/more.c b/toys/pending/more.c
> index eb48fa7..f663cdc 100644
> --- a/toys/pending/more.c
> +++ b/toys/pending/more.c
> @@ -32,19 +32,38 @@ static void signal_handler(int sig)
>    _exit(sig | 128);
>  }
>
> +static void show_file_header(const char *name)
> +{
> +  printf(":::::::::::::::::::::::\n%s\n:::::::::::::::::::::::\n", name);
> +}
> +
> +static int await_user_response(FILE *cin, int prompt_len)
> +{
> +  int input_key;
> +
> +  while (1) {
> +    fflush(NULL);
> +    input_key = tolower(getc(cin));
> +    printf("\r%*s\r", prompt_len, ""); // Remove previous msg
> +    if (strchr(" \nrq", input_key)) {
> +      return input_key;
> +    }
> +    prompt_len =
> +        printf("(Enter:Next line Space:Next page Q:Quit R:Show the rest)");
> +  }
> +}
>  static void do_cat_operation(int fd, char *name)
>  {
>    char *buf = NULL;
>
> -  if(toys.optc > 1) printf(":::::::::::::::::::::::\n"
> -      "%s\n:::::::::::::::::::::::\n",name);
> +  if (toys.optc > 1) show_file_header(name);
>    for (; (buf = get_line(fd)); free(buf)) printf("%s\n", buf);
>  }
>
>  void more_main()
>  {
> -  int ch, lines, input_key = 0, disp_more, more_msg_len;
> -  unsigned rows = 24, cols = 80;
> +  int ch, input_key = 0, show_prompt, more_msg_len;
> +  unsigned rows = 24, cols = 80, row = 0, col = 0;
>    struct stat st;
>    struct termios newf;
>    FILE *fp, *cin;
> @@ -55,7 +74,8 @@ void more_main()
>    }
>
>    TT.cin_fd = fileno(cin);
> -  tcgetattr(TT.cin_fd,&TT.inf);
> +  tcgetattr(TT.cin_fd, &TT.inf);
> +
>    //Prepare terminal for input
>    memcpy(&newf, &TT.inf, sizeof(struct termios));
>    newf.c_lflag &= ~(ICANON | ECHO);
> @@ -71,46 +91,48 @@ void more_main()
>          perror_msg("'%s'", *toys.optargs);
>          continue;
>      }
> -    st.st_size = disp_more = more_msg_len = lines = 0;
> +    st.st_size = show_prompt = more_msg_len = col = row = 0;
>      fstat(fileno(fp), &st);
>      terminal_size(&cols, &rows);
>      rows--;
> -    if(toys.optc > 1) {
> -      printf(":::::::::::::::::::::::\n"
> -          "%s\n:::::::::::::::::::::::\n",*toys.optargs);
> -      rows -= 3;
> +
> +    if (toys.optc > 1) {
> +      show_file_header(*toys.optargs);
> +      row += 3;
>      }
>
>      while ((ch = getc(fp)) != EOF) {
> -      if (input_key != 'r' && disp_more) {
> -        more_msg_len = printf("--More-- ");
> +      if (input_key != 'r' && show_prompt) {
> +        more_msg_len = printf("--More--");
>          if (st.st_size)
>            more_msg_len += printf("(%d%% of %lld bytes)",
>                (int) (100 * ( (double) ftell(fp) / (double) st.st_size)),
>                (long long)st.st_size);
> -        fflush(NULL);
> -
> -        while (1) {
> -          input_key = getc(cin);
> -          input_key = tolower(input_key);
> -          printf("\r%*s\r", more_msg_len, ""); // Remove previous msg
> -          if (input_key == ' ' || input_key == '\n' || input_key == 'q'
> -              || input_key == 'r') break;
> -          more_msg_len = printf("(Enter:Next line Space:Next page
> Q:Quit R:Show the rest)");
> -        }
> -        more_msg_len = lines = disp_more = 0;
> +
> +        input_key = await_user_response(cin, more_msg_len);
>          if (input_key == 'q') goto stop;
> +
> +        more_msg_len = col = row = show_prompt = 0;
>          terminal_size(&cols, &rows);
>          rows--;
>        }
>
> -      if (ch == '\n')
> -        if (++lines >= rows || input_key == '\n') disp_more = 1;
>        putchar(ch);
> +      if (ch == '\t') col = (col | 0x7) + 1; else col++;
> +      if (col == cols) putchar(ch = '\n');
> +      if (ch == '\n') {
> +        col = 0;
> +        if (++row >= rows || input_key == '\n') show_prompt = 1;
> +      }
>      }
>      fclose(fp);
> -    fflush(NULL);
> -  } while (*toys.optargs && *++toys.optargs);
> +
> +    if (*toys.optargs && *++toys.optargs) {
> +      more_msg_len = printf("--More--(Next file: %s)", *toys.optargs);
> +      input_key = await_user_response(cin, more_msg_len);
> +      if (input_key == 'q') goto stop;
> +    }
> +  } while (*toys.optargs);
>
>  stop:
>    tcsetattr(TT.cin_fd, TCSANOW, &TT.inf);



-- 
Elliott Hughes - http://who/enh - http://jessies.org/~enh/
Android native code/tools questions? Mail me/drop by/add me as a reviewer.

 1428176899.0


More information about the Toybox mailing list