| /* |
| * Copyright (c) 2018 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <ctype.h> |
| #include "shell_ops.h" |
| #include "shell_help.h" |
| #include "shell_utils.h" |
| |
| |
| /* Function prints a string on terminal screen with requested margin. |
| * It takes care to not divide words. |
| * shell Pointer to shell instance. |
| * p_str Pointer to string to be printed. |
| * terminal_offset Requested left margin. |
| * offset_first_line Add margin to the first printed line. |
| */ |
| static void formatted_text_print(const struct shell *shell, const char *str, |
| size_t terminal_offset, bool offset_first_line) |
| { |
| size_t offset = 0; |
| size_t length; |
| |
| if (str == NULL) { |
| return; |
| } |
| |
| if (offset_first_line) { |
| shell_op_cursor_horiz_move(shell, terminal_offset); |
| } |
| |
| |
| /* Skipping whitespace. */ |
| while (isspace((int) *(str + offset))) { |
| ++offset; |
| } |
| |
| while (true) { |
| size_t idx = 0; |
| |
| length = shell_strlen(str) - offset; |
| |
| if (length <= |
| shell->ctx->vt100_ctx.cons.terminal_wid - terminal_offset) { |
| for (idx = 0; idx < length; idx++) { |
| if (*(str + offset + idx) == '\n') { |
| transport_buffer_flush(shell); |
| shell_write(shell, str + offset, idx); |
| offset += idx + 1; |
| cursor_next_line_move(shell); |
| shell_op_cursor_horiz_move(shell, |
| terminal_offset); |
| break; |
| } |
| } |
| |
| /* String will fit in one line. */ |
| shell_raw_fprintf(shell->fprintf_ctx, str + offset); |
| |
| break; |
| } |
| |
| /* String is longer than terminal line so text needs to |
| * divide in the way to not divide words. |
| */ |
| length = shell->ctx->vt100_ctx.cons.terminal_wid |
| - terminal_offset; |
| |
| while (true) { |
| /* Determining line break. */ |
| if (isspace((int) (*(str + offset + idx)))) { |
| length = idx; |
| if (*(str + offset + idx) == '\n') { |
| break; |
| } |
| } |
| |
| if ((idx + terminal_offset) >= |
| shell->ctx->vt100_ctx.cons.terminal_wid) { |
| /* End of line reached. */ |
| break; |
| } |
| |
| ++idx; |
| } |
| |
| /* Writing one line, fprintf IO buffer must be flushed |
| * before calling shell_write. |
| */ |
| transport_buffer_flush(shell); |
| shell_write(shell, str + offset, length); |
| offset += length; |
| |
| /* Calculating text offset to ensure that next line will |
| * not begin with a space. |
| */ |
| while (isspace((int) (*(str + offset)))) { |
| ++offset; |
| } |
| |
| cursor_next_line_move(shell); |
| shell_op_cursor_horiz_move(shell, terminal_offset); |
| |
| } |
| cursor_next_line_move(shell); |
| } |
| |
| static void help_item_print(const struct shell *shell, const char *item_name, |
| u16_t item_name_width, const char *item_help) |
| { |
| static const u8_t tabulator[] = " "; |
| const u16_t offset = 2 * strlen(tabulator) + item_name_width + 1; |
| |
| if (item_name == NULL) { |
| return; |
| } |
| |
| if (!IS_ENABLED(CONFIG_NEWLIB_LIBC) && !IS_ENABLED(CONFIG_ARCH_POSIX)) { |
| /* print option name */ |
| shell_internal_fprintf(shell, SHELL_NORMAL, "%s%-*s%s:", |
| tabulator, |
| item_name_width, item_name, |
| tabulator); |
| } else { |
| u16_t tmp = item_name_width - strlen(item_name); |
| char space = ' '; |
| |
| shell_internal_fprintf(shell, SHELL_NORMAL, "%s%s", tabulator, |
| item_name); |
| for (u16_t i = 0; i < tmp; i++) { |
| shell_write(shell, &space, 1); |
| } |
| shell_internal_fprintf(shell, SHELL_NORMAL, "%s:", tabulator); |
| } |
| |
| if (item_help == NULL) { |
| cursor_next_line_move(shell); |
| return; |
| } |
| /* print option help */ |
| formatted_text_print(shell, item_help, offset, false); |
| } |
| |
| /* Function is printing command help, its subcommands name and subcommands |
| * help string. |
| */ |
| void shell_help_subcmd_print(const struct shell *shell) |
| { |
| const struct shell_static_entry *entry = NULL; |
| struct shell_static_entry static_entry; |
| u16_t longest_syntax = 0U; |
| size_t cmd_idx = 0; |
| |
| /* Checking if there are any subcommands available. */ |
| if (!shell->ctx->active_cmd.subcmd) { |
| return; |
| } |
| |
| /* Searching for the longest subcommand to print. */ |
| do { |
| shell_cmd_get(shell, shell->ctx->active_cmd.subcmd, |
| !SHELL_CMD_ROOT_LVL, |
| cmd_idx++, &entry, &static_entry); |
| |
| if (!entry) { |
| break; |
| } |
| |
| u16_t len = shell_strlen(entry->syntax); |
| |
| longest_syntax = longest_syntax > len ? longest_syntax : len; |
| } while (cmd_idx != 0); /* too many commands */ |
| |
| if (cmd_idx == 1) { |
| return; |
| } |
| |
| shell_internal_fprintf(shell, SHELL_NORMAL, "Subcommands:\n"); |
| |
| /* Printing subcommands and help string (if exists). */ |
| cmd_idx = 0; |
| |
| while (true) { |
| shell_cmd_get(shell, shell->ctx->active_cmd.subcmd, |
| !SHELL_CMD_ROOT_LVL, |
| cmd_idx++, &entry, &static_entry); |
| |
| if (entry == NULL) { |
| break; |
| } |
| |
| help_item_print(shell, entry->syntax, longest_syntax, |
| entry->help); |
| } |
| } |
| |
| void shell_help_cmd_print(const struct shell *shell) |
| { |
| static const char cmd_sep[] = " - "; /* commands separator */ |
| |
| u16_t field_width = shell_strlen(shell->ctx->active_cmd.syntax) + |
| shell_strlen(cmd_sep); |
| |
| shell_internal_fprintf(shell, SHELL_NORMAL, "%s%s", |
| shell->ctx->active_cmd.syntax, cmd_sep); |
| |
| formatted_text_print(shell, shell->ctx->active_cmd.help, |
| field_width, false); |
| } |
| |