You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
5.8 KiB
238 lines
5.8 KiB
/* |
|
* 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 *sh, 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) { |
|
z_shell_op_cursor_horiz_move(sh, terminal_offset); |
|
} |
|
|
|
|
|
/* Skipping whitespace. */ |
|
while (isspace((int) *(str + offset)) != 0) { |
|
++offset; |
|
} |
|
|
|
while (true) { |
|
size_t idx = 0; |
|
bool newline_found = false; |
|
|
|
length = z_shell_strlen(str) - offset; |
|
|
|
if (length <= |
|
sh->ctx->vt100_ctx.cons.terminal_wid - terminal_offset) { |
|
for (idx = 0; idx < length; idx++) { |
|
if (*(str + offset + idx) == '\n') { |
|
z_transport_buffer_flush(sh); |
|
z_shell_write(sh, str + offset, idx); |
|
offset += idx + 1; |
|
z_cursor_next_line_move(sh); |
|
z_shell_op_cursor_horiz_move(sh, |
|
terminal_offset); |
|
newline_found = true; |
|
break; |
|
} |
|
} |
|
|
|
/* If we found a newline, continue processing the remaining text */ |
|
if (newline_found) { |
|
continue; |
|
} |
|
|
|
/* String will fit in one line. */ |
|
z_shell_raw_fprintf(sh->fprintf_ctx, str + offset); |
|
|
|
break; |
|
} |
|
|
|
/* String is longer than terminal line so text needs to |
|
* divide in the way to not divide words. |
|
*/ |
|
length = sh->ctx->vt100_ctx.cons.terminal_wid |
|
- terminal_offset; |
|
|
|
while (true) { |
|
/* Determining line break. */ |
|
if (isspace((int) (*(str + offset + idx))) != 0) { |
|
length = idx; |
|
if (*(str + offset + idx) == '\n') { |
|
break; |
|
} |
|
} |
|
|
|
if ((idx + terminal_offset) >= |
|
sh->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. |
|
*/ |
|
z_transport_buffer_flush(sh); |
|
z_shell_write(sh, str + offset, length); |
|
offset += length; |
|
|
|
/* Calculating text offset to ensure that next line will |
|
* not begin with a space. |
|
*/ |
|
while (isspace((int) (*(str + offset))) != 0) { |
|
++offset; |
|
} |
|
|
|
z_cursor_next_line_move(sh); |
|
z_shell_op_cursor_horiz_move(sh, terminal_offset); |
|
|
|
} |
|
z_cursor_next_line_move(sh); |
|
} |
|
|
|
static void formatted_structured_help_print(const struct shell *sh, const char *item_name, |
|
const char *item_help, size_t terminal_offset) |
|
{ |
|
const struct shell_cmd_help *structured = (const struct shell_cmd_help *)item_help; |
|
|
|
if (structured->description) { |
|
formatted_text_print(sh, structured->description, terminal_offset, false); |
|
} |
|
|
|
if (structured->usage) { |
|
z_shell_op_cursor_horiz_move(sh, terminal_offset); |
|
z_shell_fprintf(sh, SHELL_NORMAL, "Usage: %s ", item_name); |
|
formatted_text_print(sh, structured->usage, terminal_offset + 7, false); |
|
} |
|
} |
|
|
|
static void help_item_print(const struct shell *sh, const char *item_name, |
|
uint16_t item_name_width, const char *item_help) |
|
{ |
|
static const uint8_t tabulator[] = " "; |
|
static const char sub_cmd_sep[] = ": "; /* subcommands separator */ |
|
const uint16_t offset = 2 * strlen(tabulator) + item_name_width + strlen(sub_cmd_sep); |
|
|
|
if ((item_name == NULL) || (item_name[0] == '\0')) { |
|
return; |
|
} |
|
|
|
if (!IS_ENABLED(CONFIG_NEWLIB_LIBC) && |
|
!IS_ENABLED(CONFIG_ARCH_POSIX)) { |
|
/* print option name */ |
|
z_shell_fprintf(sh, SHELL_NORMAL, "%s%-*s", tabulator, |
|
item_name_width, item_name); |
|
} else { |
|
uint16_t tmp = item_name_width - strlen(item_name); |
|
char space = ' '; |
|
|
|
z_shell_fprintf(sh, SHELL_NORMAL, "%s%s", tabulator, |
|
item_name); |
|
|
|
if (item_help) { |
|
for (uint16_t i = 0; i < tmp; i++) { |
|
z_shell_write(sh, &space, 1); |
|
} |
|
} |
|
} |
|
|
|
if (item_help == NULL) { |
|
z_cursor_next_line_move(sh); |
|
return; |
|
} else { |
|
z_shell_fprintf(sh, SHELL_NORMAL, "%s: ", tabulator); |
|
} |
|
/* print option help */ |
|
if (shell_help_is_structured(item_help)) { |
|
formatted_structured_help_print(sh, item_name, item_help, offset); |
|
} else { |
|
formatted_text_print(sh, item_help, offset, false); |
|
} |
|
} |
|
|
|
/* Function prints all subcommands of the parent command together with their |
|
* help string |
|
*/ |
|
void z_shell_help_subcmd_print(const struct shell *sh, |
|
const struct shell_static_entry *parent, |
|
const char *description) |
|
{ |
|
const struct shell_static_entry *entry = NULL; |
|
struct shell_static_entry dloc; |
|
uint16_t longest = 0U; |
|
size_t idx = 0; |
|
|
|
/* Searching for the longest subcommand to print. */ |
|
while ((entry = z_shell_cmd_get(parent, idx++, &dloc)) != NULL) { |
|
longest = Z_MAX(longest, z_shell_strlen(entry->syntax)); |
|
} |
|
|
|
/* No help to print */ |
|
if (longest == 0) { |
|
return; |
|
} |
|
|
|
if (description != NULL) { |
|
z_shell_fprintf(sh, SHELL_NORMAL, description); |
|
} |
|
|
|
/* Printing subcommands and help string (if exists). */ |
|
idx = 0; |
|
|
|
while ((entry = z_shell_cmd_get(parent, idx++, &dloc)) != NULL) { |
|
help_item_print(sh, entry->syntax, longest, entry->help); |
|
} |
|
} |
|
|
|
void z_shell_help_cmd_print(const struct shell *sh, |
|
const struct shell_static_entry *cmd) |
|
{ |
|
static const char cmd_sep[] = " - "; /* commands separator */ |
|
uint16_t field_width; |
|
|
|
field_width = z_shell_strlen(cmd->syntax) + z_shell_strlen(cmd_sep); |
|
|
|
z_shell_fprintf(sh, SHELL_NORMAL, "%s%s", cmd->syntax, cmd_sep); |
|
|
|
if (shell_help_is_structured(cmd->help)) { |
|
formatted_structured_help_print(sh, cmd->syntax, cmd->help, field_width); |
|
} else { |
|
formatted_text_print(sh, cmd->help, field_width, false); |
|
} |
|
} |
|
|
|
bool z_shell_help_request(const char *str) |
|
{ |
|
if (!IS_ENABLED(CONFIG_SHELL_HELP_OPT_PARSE)) { |
|
return false; |
|
} |
|
|
|
if (!strcmp(str, "-h") || !strcmp(str, "--help")) { |
|
return true; |
|
} |
|
|
|
return false; |
|
}
|
|
|