[PATCH] libmisc/shell: Support terminal size as env variables

chrisj at rtems.org chrisj at rtems.org
Tue Nov 22 12:02:18 UTC 2022


From: Chris Johns <chrisj at rtems.org>

Closes #4763
---
 cpukit/libmisc/shell/main_edit.c | 17 +++++-
 cpukit/libmisc/shell/main_help.c | 94 ++++++++++++++++++++------------
 cpukit/libmisc/shell/shell.c     | 83 +++++++++++++++++++++++++++-
 3 files changed, 154 insertions(+), 40 deletions(-)

diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c
index 4cc742719a..16c44f2a11 100644
--- a/cpukit/libmisc/shell/main_edit.c
+++ b/cpukit/libmisc/shell/main_edit.c
@@ -755,8 +755,21 @@ static void get_console_size(struct env *env) {
   env->cols = ws.ws_col;
   env->lines = ws.ws_row - 1;
 #elif defined(__rtems__)
-  env->cols = 80;
-  env->lines = 25;
+  char* e;
+  e = getenv("LINES");
+  if (e != NULL) {
+    int lines = strtol(e, 0, 10);
+    if (lines > 0) {
+      env->lines = lines - 1;
+    }
+  }
+  e = getenv("COLUMNS");
+  if (e != NULL) {
+    int cols = strtol(e, 0, 10);
+    if (cols > 0) {
+      env->cols = cols - 1;
+    }
+  }
 #else
   struct term *term = gettib()->proc->term;
   env->cols = term->cols;
diff --git a/cpukit/libmisc/shell/main_help.c b/cpukit/libmisc/shell/main_help.c
index 564bc30a9c..e6d939d08f 100644
--- a/cpukit/libmisc/shell/main_help.c
+++ b/cpukit/libmisc/shell/main_help.c
@@ -22,23 +22,34 @@
 #include "internal.h"
 #include <string.h>
 
+static int rtems_shell_help_pause(int line, int lines) {
+  if (lines && line >= lines - 1) {
+    printf("\rPress any key to continue...");
+    (void) getchar();
+    printf("\r%*c\r", 29, ' ');
+    line = 0;
+  }
+  return line;
+}
+
 /*
  * show the help for one command.
  */
 static int rtems_shell_help_cmd(
-  const rtems_shell_cmd_t *shell_cmd
+  const rtems_shell_cmd_t *shell_cmd, int indent, int line,
+  int cols, int lines
 )
 {
   const char * pc;
-  int    col,line;
+  int    col;
 
   if (!rtems_shell_can_see_cmd(shell_cmd)) {
     return 0;
   }
 
-  printf("%-12.12s - ",shell_cmd->name);
-  col = 14;
-  line = 1;
+  printf("%-*s - ", indent, shell_cmd->name);
+  indent += 3;
+  col = indent;
   if (shell_cmd->alias) {
     printf("is an <alias> for command '%s'",shell_cmd->alias->name);
   } else if (shell_cmd->usage) {
@@ -48,8 +59,10 @@ static int rtems_shell_help_cmd(
         case '\r':
           break;
         case '\n':
-          putchar('\n');
-          col = 0;
+          if (*(pc + 1) != '\0') {
+            putchar('\n');
+            col = 0;
+          }
           break;
         default:
           putchar(*pc);
@@ -57,19 +70,21 @@ static int rtems_shell_help_cmd(
           break;
       }
       pc++;
-      if (col>78) { /* What daring... 78?*/
+      if (col > (cols - 3)) {
         if (*pc) {
           putchar('\n');
           col = 0;
         }
       }
-      if (!col && *pc) {
-        printf("            ");
-        col = 12;line++;
+      if (col == 0 && *pc) {
+        line = rtems_shell_help_pause(line + 1, lines);
+        printf("%*c", indent, ' ');
+        col = indent;
       }
     }
   }
   puts("");
+  line = rtems_shell_help_pause(line + 1, lines);
   return line;
 }
 
@@ -83,15 +98,27 @@ static int rtems_shell_help(
   char * argv[]
 )
 {
-  int col,line,lines,arg;
-  char* lines_env;
+  int col,line,cols,lines,arg,indent;
+  char *lines_env, *cols_env;
   rtems_shell_topic_t *topic;
+  rtems_shell_cmd_t *shell_cmd;
 
+  lines = 16;
+  cols = 80;
   lines_env = getenv("SHELL_LINES");
-  if (lines_env)
+  if (lines_env) {
     lines = strtol(lines_env, 0, 0);
-  else
-    lines = 16;
+  } else {
+    lines_env = getenv("LINES");
+    if (lines_env) {
+      lines = strtol(lines_env, 0, 0);
+    }
+  }
+
+  cols_env = getenv("COLUMNS");
+  if (cols_env) {
+    cols = strtol(cols_env, 0, 0);
+  }
 
   if (argc<2) {
     printf("help: The topics are\n");
@@ -101,7 +128,7 @@ static int rtems_shell_help(
       if (!col){
         col = printf("  %s",topic->topic);
       } else {
-        if ((col+strlen(topic->topic)+2)>78){
+        if ((col+strlen(topic->topic)+2)>(cols - 2)){
           printf("\n");
           col = printf("  %s",topic->topic);
         } else {
@@ -113,18 +140,19 @@ static int rtems_shell_help(
     printf("\n");
     return 1;
   }
+  indent = 0;
+  shell_cmd = rtems_shell_first_cmd;
+  while (shell_cmd) {
+    size_t len = strlen(shell_cmd->name);
+    if (len > indent) {
+      indent = len;
+    }
+    shell_cmd = shell_cmd->next;
+  }
   line = 0;
   for (arg = 1;arg<argc;arg++) {
     const char *cur = argv[arg];
-    rtems_shell_cmd_t *shell_cmd;
-
-    if (lines && (line > lines)) {
-      printf("Press any key to continue...");
-      (void) getchar(); /* we only want to know a character was pressed */
-      printf("\n");
-      line = 0;
-    }
-    topic  =  rtems_shell_lookup_topic(cur);
+    topic = rtems_shell_lookup_topic(cur);
     if (topic == NULL) {
       if ((shell_cmd = rtems_shell_lookup_cmd(cur)) == NULL) {
         if (strcmp(cur, "all") != 0) {
@@ -132,11 +160,11 @@ static int rtems_shell_help(
             "help: topic or cmd '%s' not found. Try <help> alone for a list\n",
             cur
           );
-          line++;
+          line = rtems_shell_help_pause(line + 1, lines);
           continue;
         }
       } else {
-        line+= rtems_shell_help_cmd(shell_cmd);
+        line = rtems_shell_help_cmd(shell_cmd, indent, line, cols, lines);
         continue;
       }
     }
@@ -144,18 +172,12 @@ static int rtems_shell_help(
     line++;
     shell_cmd = rtems_shell_first_cmd;
     while (shell_cmd) {
-      if (topic == NULL || !strcmp(topic->topic,shell_cmd->topic))
-        line+= rtems_shell_help_cmd(shell_cmd);
-      if (lines && (line > lines)) {
-        printf("Press any key to continue...");
-        (void) getchar();
-        printf("\n");
-        line = 0;
+      if (topic == NULL || !strcmp(topic->topic,shell_cmd->topic)) {
+        line = rtems_shell_help_cmd(shell_cmd, indent, line, cols, lines);
       }
       shell_cmd = shell_cmd->next;
     }
   }
-  puts("");
   return 0;
 }
 
diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c
index 64f90be121..cd83aa56d1 100644
--- a/cpukit/libmisc/shell/shell.c
+++ b/cpukit/libmisc/shell/shell.c
@@ -1,6 +1,6 @@
 /**
  * @file
- * 
+ *
  * @brief Instantatiate a new terminal shell.
  */
 
@@ -805,6 +805,83 @@ void rtems_shell_print_env(
 }
 #endif
 
+/*
+ * Direct method to get the size of an XTERM window.
+ *
+ * If you do not use an XTERM the env variables are not define.
+ */
+static void rtems_shell_winsize( void )
+{
+  const int fd = fileno(stdin);
+  struct winsize ws;
+  char buf[64];
+  bool ok = false;
+  int lines = 0;
+  int cols = 0;
+  int r;
+  r = ioctl(fd, TIOCGWINSZ, &ws);
+  if (r == 0) {
+    ok = true;
+    lines = ws.ws_row;
+    cols = ws.ws_col;
+  } else if (isatty(fd)) {
+    struct termios cterm;
+    if (tcgetattr(fd, &cterm) >= 0) {
+      struct termios term = cterm;
+      term.c_cc[VMIN] = 0;
+      term.c_cc[VTIME] = 0;
+      if (tcsetattr (fd, TCSADRAIN, &term) >= 0) {
+        int msec = 50;
+        int len = 0;
+        int i = 0;
+        memset(&buf[0], 0, sizeof(buf));
+        /*
+         * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous
+         *
+         * CSI 1 8 t
+         */
+        fputs("\033[18t", stdout);
+        fflush(stdout);
+        while (msec-- > 0 && len < sizeof(buf)) {
+          char ch[2];
+          if (read(fd, &ch[0], 1) == 1) {
+            buf[len++] = ch[0];
+            msec = 50;
+          } else {
+            usleep(1000);
+          }
+        }
+        while (i < len) {
+          static const char resp[] = "\033[8;";
+          if (memcmp(resp, &buf[i], sizeof(resp) - 1) == 0) {
+            i += sizeof(resp) - 1;
+            while (i < len && buf[i] != ';') {
+              lines *= 10;
+              lines += buf[i++] - '0';
+            }
+            cols = 0;
+            ++i;
+            while (i < len && buf[i] != 't') {
+              cols *= 10;
+              cols += buf[i++] - '0';
+            }
+          } else {
+            i++;
+          }
+          ok = true;
+        }
+      }
+      tcsetattr (fd, TCSADRAIN, &cterm);
+    }
+  }
+  if (ok) {
+    snprintf(buf, sizeof(buf) - 1, "%d", lines);
+    setenv("LINES", buf, 1);
+    snprintf(buf, sizeof(buf) - 1, "%d", cols);
+    setenv("COLUMNS", buf, 1);
+  }
+}
+
 static rtems_task rtems_shell_task(rtems_task_argument task_argument)
 {
   rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument;
@@ -984,7 +1061,9 @@ static bool shell_main_loop(
           memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE);
           if (!rtems_shell_make_args(cmd_argv, &argc, argv,
                                      RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
-            int exit_code = rtems_shell_execute_cmd(argv[0], argc, argv);
+            int exit_code;
+            rtems_shell_winsize();
+            exit_code = rtems_shell_execute_cmd(argv[0], argc, argv);
             if (shell_env->exit_code != NULL)
               *shell_env->exit_code = exit_code;
             if (exit_code != 0 && shell_env->exit_on_error)
-- 
2.19.1



More information about the devel mailing list