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