From 8425e679c149096a5d0a97990f6ebdbdd55ca522 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 22 Nov 2022 21:05:48 +1100 Subject: libmisc/shell: Support terminal size as env variables 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, 155 insertions(+), 39 deletions(-) (limited to 'cpukit') diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c index 4cc742719a..99871204b7 100644 --- a/cpukit/libmisc/shell/main_edit.c +++ b/cpukit/libmisc/shell/main_edit.c @@ -755,8 +755,23 @@ 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; + char* e; env->lines = 25; + env->lines = 80; + 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; + } + } #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 +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 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 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 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) -- cgit v1.2.3