zephyr/subsys/shell/shell_help.c

212 lines
4.9 KiB
C

/*
* 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);
}