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

Joel Sherrill joel at rtems.org
Tue Nov 22 13:44:57 UTC 2022


On Tue, Nov 22, 2022, 6:02 AM <chrisj at rtems.org> wrote:

> 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;
> +    }
> +  }
>

Does this lose the default values if the environment variables are not set?

 #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
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20221122/689f9c4a/attachment-0001.htm>


More information about the devel mailing list