| /* | 
 |  * Copyright (c) 2018 Nordic Semiconductor ASA | 
 |  * | 
 |  * SPDX-License-Identifier: Apache-2.0 | 
 |  */ | 
 |  | 
 | #include <ctype.h> | 
 | #include <stdlib.h> | 
 | #include <atomic.h> | 
 | #include <shell/shell.h> | 
 | #include <shell/shell_dummy.h> | 
 | #include "shell_ops.h" | 
 | #include "shell_help.h" | 
 | #include "shell_utils.h" | 
 | #include "shell_vt100.h" | 
 | #include "shell_wildcard.h" | 
 |  | 
 | /* 2 == 1 char for cmd + 1 char for '\0' */ | 
 | #if (CONFIG_SHELL_CMD_BUFF_SIZE < 2) | 
 | 	#error too small CONFIG_SHELL_CMD_BUFF_SIZE | 
 | #endif | 
 |  | 
 | #if (CONFIG_SHELL_PRINTF_BUFF_SIZE < 1) | 
 | 	#error too small SHELL_PRINTF_BUFF_SIZE | 
 | #endif | 
 |  | 
 | #define SHELL_MSG_CMD_NOT_FOUND		": command not found" | 
 |  | 
 | #define SHELL_INIT_OPTION_PRINTER	(NULL) | 
 |  | 
 |  | 
 | static inline void receive_state_change(const struct shell *shell, | 
 | 					enum shell_receive_state state) | 
 | { | 
 | 	shell->ctx->receive_state = state; | 
 | } | 
 |  | 
 | static void cmd_buffer_clear(const struct shell *shell) | 
 | { | 
 | 	shell->ctx->cmd_buff[0] = '\0'; /* clear command buffer */ | 
 | 	shell->ctx->cmd_buff_pos = 0; | 
 | 	shell->ctx->cmd_buff_len = 0; | 
 | } | 
 |  | 
 | static void shell_internal_help_print(const struct shell *shell) | 
 | { | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_HELP)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	shell_help_cmd_print(shell); | 
 | 	shell_help_subcmd_print(shell); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Prints error message on wrong argument count. | 
 |  *	  Optionally, printing help on wrong argument count. | 
 |  * | 
 |  * @param[in] shell	  Pointer to the shell instance. | 
 |  * @param[in] arg_cnt_ok  Flag indicating valid number of arguments. | 
 |  * | 
 |  * @return 0		  if check passed | 
 |  * @return -EINVAL	  if wrong argument count | 
 |  */ | 
 | static int cmd_precheck(const struct shell *shell, | 
 | 			bool arg_cnt_ok) | 
 | { | 
 | 	if (!arg_cnt_ok) { | 
 | 		shell_internal_fprintf(shell, SHELL_ERROR, | 
 | 				       "%s: wrong parameter count\n", | 
 | 				       shell->ctx->active_cmd.syntax); | 
 |  | 
 | 		if (IS_ENABLED(CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT)) { | 
 | 			shell_internal_help_print(shell); | 
 | 		} | 
 |  | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void state_set(const struct shell *shell, enum shell_state state) | 
 | { | 
 | 	shell->ctx->state = state; | 
 |  | 
 | 	if (state == SHELL_STATE_ACTIVE) { | 
 | 		cmd_buffer_clear(shell); | 
 | 		shell_print_prompt_and_cmd(shell); | 
 | 	} | 
 | } | 
 |  | 
 | static void tab_item_print(const struct shell *shell, const char *option, | 
 | 			   u16_t longest_option) | 
 | { | 
 | 	static const char *tab = "  "; | 
 | 	u16_t columns; | 
 | 	u16_t diff; | 
 |  | 
 | 	/* Function initialization has been requested. */ | 
 | 	if (option == NULL) { | 
 | 		shell->ctx->vt100_ctx.printed_cmd = 0; | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	longest_option += shell_strlen(tab); | 
 |  | 
 | 	columns = (shell->ctx->vt100_ctx.cons.terminal_wid | 
 | 			- shell_strlen(tab)) / longest_option; | 
 | 	diff = longest_option - shell_strlen(option); | 
 |  | 
 | 	if (shell->ctx->vt100_ctx.printed_cmd++ % columns == 0U) { | 
 | 		shell_internal_fprintf(shell, SHELL_OPTION, "\n%s%s", tab, | 
 | 				       option); | 
 | 	} else { | 
 | 		shell_internal_fprintf(shell, SHELL_OPTION, "%s", option); | 
 | 	} | 
 |  | 
 | 	shell_op_cursor_horiz_move(shell, diff); | 
 | } | 
 |  | 
 | static void history_init(const struct shell *shell) | 
 | { | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	shell_history_init(shell->history); | 
 | } | 
 |  | 
 | static void history_purge(const struct shell *shell) | 
 | { | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	shell_history_purge(shell->history); | 
 | } | 
 |  | 
 | static void history_mode_exit(const struct shell *shell) | 
 | { | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	flag_history_exit_set(shell, false); | 
 | 	shell_history_mode_exit(shell->history); | 
 | } | 
 |  | 
 | static void history_put(const struct shell *shell, u8_t *line, size_t length) | 
 | { | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	shell_history_put(shell->history, line, length); | 
 | } | 
 |  | 
 | static void history_handle(const struct shell *shell, bool up) | 
 | { | 
 | 	bool history_mode; | 
 | 	u16_t len; | 
 |  | 
 | 	/*optional feature */ | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	/* Checking if history process has been stopped */ | 
 | 	if (flag_history_exit_get(shell)) { | 
 | 		flag_history_exit_set(shell, false); | 
 | 		shell_history_mode_exit(shell->history); | 
 | 	} | 
 |  | 
 | 	/* Backup command if history is entered */ | 
 | 	if (!shell_history_active(shell->history)) { | 
 | 		if (up) { | 
 | 			u16_t cmd_len = shell_strlen(shell->ctx->cmd_buff); | 
 |  | 
 | 			if (cmd_len) { | 
 | 				strcpy(shell->ctx->temp_buff, | 
 | 				       shell->ctx->cmd_buff); | 
 | 			} else { | 
 | 				shell->ctx->temp_buff[0] = '\0'; | 
 | 			} | 
 | 		} else { | 
 | 			/* Pressing 'down' not in history mode has no effect. */ | 
 | 			return; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* Start by checking if history is not empty. */ | 
 | 	history_mode = shell_history_get(shell->history, up, | 
 | 					 shell->ctx->cmd_buff, &len); | 
 |  | 
 | 	/* On exiting history mode print backed up command. */ | 
 | 	if (!history_mode) { | 
 | 		strcpy(shell->ctx->cmd_buff, shell->ctx->temp_buff); | 
 | 		len = shell_strlen(shell->ctx->cmd_buff); | 
 | 	} | 
 |  | 
 | 	shell_op_cursor_home_move(shell); | 
 | 	clear_eos(shell); | 
 | 	shell_print_cmd(shell); | 
 | 	shell->ctx->cmd_buff_pos = len; | 
 | 	shell->ctx->cmd_buff_len = len; | 
 | 	shell_op_cond_next_line(shell); | 
 | } | 
 |  | 
 | static const struct shell_static_entry *find_cmd( | 
 | 					     const struct shell_cmd_entry *cmd, | 
 | 					     size_t lvl, | 
 | 					     char *cmd_str, | 
 | 					     struct shell_static_entry *d_entry) | 
 | { | 
 | 	const struct shell_static_entry *entry = NULL; | 
 | 	size_t idx = 0; | 
 |  | 
 | 	do { | 
 | 		shell_cmd_get(cmd, lvl, idx++, &entry, d_entry); | 
 | 		if (entry && (strcmp(cmd_str, entry->syntax) == 0)) { | 
 | 			return entry; | 
 | 		} | 
 | 	} while (entry); | 
 |  | 
 | 	return NULL; | 
 | } | 
 |  | 
 | /** @brief Function for getting last valid command in list of arguments. */ | 
 | static const struct shell_static_entry *get_last_command( | 
 | 					     const struct shell *shell, | 
 | 					     size_t argc, | 
 | 					     char *argv[], | 
 | 					     size_t *match_arg, | 
 | 					     struct shell_static_entry *d_entry) | 
 | { | 
 | 	const struct shell_static_entry *prev_entry = NULL; | 
 | 	const struct shell_cmd_entry *prev_cmd = NULL; | 
 | 	const struct shell_static_entry *entry = NULL; | 
 | 	*match_arg = SHELL_CMD_ROOT_LVL; | 
 |  | 
 | 	while (*match_arg < argc) { | 
 |  | 
 | 		if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) { | 
 | 			/* ignore wildcard argument */ | 
 | 			if (shell_wildcard_character_exist(argv[*match_arg])) { | 
 | 				(*match_arg)++; | 
 | 				continue; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		entry = find_cmd(prev_cmd, *match_arg, argv[*match_arg], | 
 | 				 d_entry); | 
 | 		if (entry) { | 
 | 			prev_cmd = entry->subcmd; | 
 | 			prev_entry = entry; | 
 | 			(*match_arg)++; | 
 | 		} else { | 
 | 			break; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return entry; | 
 | } | 
 |  | 
 | static inline u16_t completion_space_get(const struct shell *shell) | 
 | { | 
 | 	u16_t space = (CONFIG_SHELL_CMD_BUFF_SIZE - 1) - | 
 | 			shell->ctx->cmd_buff_len; | 
 | 	return space; | 
 | } | 
 |  | 
 | /* Prepare arguments and return number of space available for completion. */ | 
 | static bool tab_prepare(const struct shell *shell, | 
 | 			const struct shell_static_entry **cmd, | 
 | 			char **argv, size_t *argc, | 
 | 			size_t *complete_arg_idx, | 
 | 			struct shell_static_entry *d_entry) | 
 | { | 
 | 	u16_t compl_space = completion_space_get(shell); | 
 | 	size_t search_argc; | 
 |  | 
 | 	if (compl_space == 0U) { | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	/* Copy command from its beginning to cursor position. */ | 
 | 	memcpy(shell->ctx->temp_buff, shell->ctx->cmd_buff, | 
 | 			shell->ctx->cmd_buff_pos); | 
 | 	shell->ctx->temp_buff[shell->ctx->cmd_buff_pos] = '\0'; | 
 |  | 
 | 	/* Create argument list. */ | 
 | 	(void)shell_make_argv(argc, argv, shell->ctx->temp_buff, | 
 | 			      CONFIG_SHELL_ARGC_MAX); | 
 |  | 
 | 	/* If last command is not completed (followed by space) it is treated | 
 | 	 * as uncompleted one. | 
 | 	 */ | 
 | 	int space = isspace((int)shell->ctx->cmd_buff[ | 
 | 						shell->ctx->cmd_buff_pos - 1]); | 
 |  | 
 | 	/* root command completion */ | 
 | 	if ((*argc == 0) || ((space == 0) && (*argc == 1))) { | 
 | 		*complete_arg_idx = SHELL_CMD_ROOT_LVL; | 
 | 		*cmd = NULL; | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	search_argc = space ? *argc : *argc - 1; | 
 |  | 
 | 	*cmd = get_last_command(shell, search_argc, argv, complete_arg_idx, | 
 | 				d_entry); | 
 |  | 
 | 	/* if search_argc == 0 (empty command line) get_last_command will return | 
 | 	 * NULL tab is allowed, otherwise not. | 
 | 	 */ | 
 | 	if ((*cmd == NULL) && (search_argc != 0)) { | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	return true; | 
 | } | 
 |  | 
 | /* Empty command is identified by null handler and subcommand but contrary | 
 |  * to array termination null command, it has non-null syntax address. | 
 |  */ | 
 | static inline bool is_empty_cmd(const struct shell_static_entry *entry) | 
 | { | 
 | 	return entry->syntax && | 
 | 		(entry->handler == NULL) && (entry->subcmd == NULL); | 
 | } | 
 |  | 
 | static inline bool is_completion_candidate(const char *candidate, | 
 | 					   const char *str, size_t len) | 
 | { | 
 | 	return (strncmp(candidate, str, len) == 0) ? true : false; | 
 | } | 
 |  | 
 | static void find_completion_candidates(const struct shell_static_entry *cmd, | 
 | 				       const char *incompl_cmd, | 
 | 				       size_t *first_idx, size_t *cnt, | 
 | 				       u16_t *longest) | 
 | { | 
 | 	size_t incompl_cmd_len = shell_strlen(incompl_cmd); | 
 | 	const struct shell_static_entry *candidate; | 
 | 	struct shell_static_entry dynamic_entry; | 
 | 	bool found = false; | 
 | 	size_t idx = 0; | 
 |  | 
 | 	*longest = 0U; | 
 | 	*cnt = 0; | 
 |  | 
 | 	while (true) { | 
 | 		bool is_empty; | 
 | 		bool is_candidate; | 
 |  | 
 | 		shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, | 
 | 			      idx, &candidate, &dynamic_entry); | 
 |  | 
 | 		if (!candidate) { | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		is_empty = is_empty_cmd(candidate); | 
 | 		is_candidate = is_completion_candidate(candidate->syntax, | 
 | 						incompl_cmd, incompl_cmd_len); | 
 | 		if (!is_empty && is_candidate) { | 
 | 			size_t slen = strlen(candidate->syntax); | 
 |  | 
 | 			*longest = (slen > *longest) ? slen : *longest; | 
 | 			(*cnt)++; | 
 |  | 
 | 			if (!found) { | 
 | 				*first_idx = idx; | 
 | 			} | 
 |  | 
 | 			found = true; | 
 | 		} | 
 | 		idx++; | 
 | 	} | 
 | } | 
 |  | 
 | static void autocomplete(const struct shell *shell, | 
 | 			 const struct shell_static_entry *cmd, | 
 | 			 const char *arg, | 
 | 			 size_t subcmd_idx) | 
 | { | 
 | 	const struct shell_static_entry *match; | 
 | 	u16_t cmd_len; | 
 | 	u16_t arg_len = shell_strlen(arg); | 
 |  | 
 | 	/* shell->ctx->active_cmd can be safely used outside of command context | 
 | 	 * to save stack | 
 | 	 */ | 
 | 	shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, | 
 | 		      subcmd_idx, &match, &shell->ctx->active_cmd); | 
 | 	cmd_len = shell_strlen(match->syntax); | 
 |  | 
 | 	/* no exact match found */ | 
 | 	if (cmd_len != arg_len) { | 
 | 		shell_op_completion_insert(shell, | 
 | 					   match->syntax + arg_len, | 
 | 					   cmd_len - arg_len); | 
 | 	} | 
 |  | 
 | 	/* Next character in the buffer is not 'space'. */ | 
 | 	if (!isspace((int) shell->ctx->cmd_buff[ | 
 | 					shell->ctx->cmd_buff_pos])) { | 
 | 		if (flag_insert_mode_get(shell)) { | 
 | 			flag_insert_mode_set(shell, false); | 
 | 			shell_op_char_insert(shell, ' '); | 
 | 			flag_insert_mode_set(shell, true); | 
 | 		} else { | 
 | 			shell_op_char_insert(shell, ' '); | 
 | 		} | 
 | 	} else { | 
 | 		/*  case: | 
 | 		 * | | -> cursor | 
 | 		 * cons_name $: valid_cmd valid_sub_cmd| |argument  <tab> | 
 | 		 */ | 
 | 		shell_op_cursor_move(shell, 1); | 
 | 		/* result: | 
 | 		 * cons_name $: valid_cmd valid_sub_cmd |a|rgument | 
 | 		 */ | 
 | 	} | 
 | } | 
 |  | 
 | static size_t str_common(const char *s1, const char *s2, size_t n) | 
 | { | 
 | 	size_t common = 0; | 
 |  | 
 | 	while ((n > 0) && (*s1 == *s2) && (*s1 != '\0')) { | 
 | 		s1++; | 
 | 		s2++; | 
 | 		n--; | 
 | 		common++; | 
 | 	} | 
 |  | 
 | 	return common; | 
 | } | 
 |  | 
 | static void tab_options_print(const struct shell *shell, | 
 | 			      const struct shell_static_entry *cmd, | 
 | 			      const char *str, size_t first, size_t cnt, | 
 | 			      u16_t longest) | 
 | { | 
 | 	const struct shell_static_entry *match; | 
 | 	size_t str_len = shell_strlen(str); | 
 | 	size_t idx = first; | 
 |  | 
 | 	/* Printing all matching commands (options). */ | 
 | 	tab_item_print(shell, SHELL_INIT_OPTION_PRINTER, longest); | 
 |  | 
 | 	while (cnt) { | 
 | 		bool is_empty; | 
 |  | 
 | 		/* shell->ctx->active_cmd can be safely used outside of command | 
 | 		 * context to save stack | 
 | 		 */ | 
 | 		shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, | 
 | 			      idx, &match, &shell->ctx->active_cmd); | 
 | 		idx++; | 
 | 		is_empty = is_empty_cmd(match); | 
 | 		if (is_empty || (str && match->syntax && | 
 | 		    !is_completion_candidate(match->syntax, str, str_len))) { | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		tab_item_print(shell, match->syntax, longest); | 
 | 		cnt--; | 
 | 	} | 
 |  | 
 | 	cursor_next_line_move(shell); | 
 | 	shell_print_prompt_and_cmd(shell); | 
 | } | 
 |  | 
 | static u16_t common_beginning_find(const struct shell_static_entry *cmd, | 
 | 				   const char **str, | 
 | 				   size_t first, size_t cnt, u16_t arg_len) | 
 | { | 
 | 	struct shell_static_entry dynamic_entry; | 
 | 	const struct shell_static_entry *match; | 
 | 	u16_t common = UINT16_MAX; | 
 | 	size_t idx = first + 1; | 
 |  | 
 | 	__ASSERT_NO_MSG(cnt > 1); | 
 |  | 
 | 	shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, | 
 | 		      first, &match, &dynamic_entry); | 
 |  | 
 | 	*str = match->syntax; | 
 |  | 
 | 	while (cnt > 1) { | 
 | 		struct shell_static_entry dynamic_entry2; | 
 | 		const struct shell_static_entry *match2; | 
 | 		int curr_common; | 
 |  | 
 | 		shell_cmd_get(cmd ? cmd->subcmd : NULL, cmd ? 1 : 0, | 
 | 			      idx++, &match2, &dynamic_entry2); | 
 |  | 
 | 		if (match2 == NULL) { | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		curr_common = str_common(match->syntax, match2->syntax, | 
 | 					 UINT16_MAX); | 
 | 		if ((arg_len == 0U) || (curr_common >= arg_len)) { | 
 | 			--cnt; | 
 | 			common = (curr_common < common) ? curr_common : common; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return common; | 
 | } | 
 |  | 
 | static void partial_autocomplete(const struct shell *shell, | 
 | 				 const struct shell_static_entry *cmd, | 
 | 				 const char *arg, | 
 | 				 size_t first, size_t cnt) | 
 | { | 
 | 	const char *completion; | 
 | 	u16_t arg_len = shell_strlen(arg); | 
 | 	u16_t common = common_beginning_find(cmd, &completion, | 
 | 			first, cnt, arg_len); | 
 |  | 
 | 	if (common) { | 
 | 		shell_op_completion_insert(shell, &completion[arg_len], | 
 | 					   common - arg_len); | 
 | 	} | 
 | } | 
 |  | 
 | static int exec_cmd(const struct shell *shell, size_t argc, char **argv, | 
 | 		    const struct shell_static_entry *help_entry) | 
 | { | 
 | 	int ret_val = 0; | 
 |  | 
 | 	if (shell->ctx->active_cmd.handler == NULL) { | 
 | 		if ((help_entry != NULL) && IS_ENABLED(CONFIG_SHELL_HELP)) { | 
 | 			if (help_entry->help == NULL) { | 
 | 				return -ENOEXEC; | 
 | 			} | 
 | 			if (help_entry->help != shell->ctx->active_cmd.help) { | 
 | 				shell->ctx->active_cmd = *help_entry; | 
 | 			} | 
 | 			shell_internal_help_print(shell); | 
 | 			return SHELL_CMD_HELP_PRINTED; | 
 | 		} else { | 
 | 			shell_internal_fprintf(shell, SHELL_ERROR, | 
 | 					       SHELL_MSG_SPECIFY_SUBCOMMAND); | 
 | 			return -ENOEXEC; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (shell->ctx->active_cmd.args.mandatory) { | 
 | 		u8_t mand = shell->ctx->active_cmd.args.mandatory; | 
 | 		u8_t opt = shell->ctx->active_cmd.args.optional; | 
 | 		bool in_range = (argc >= mand) && (argc <= (mand + opt)); | 
 |  | 
 | 		/* Check if argc is within allowed range */ | 
 | 		ret_val = cmd_precheck(shell, in_range); | 
 | 	} | 
 |  | 
 | 	if (!ret_val) { | 
 | 		/* Unlock thread mutex in case command would like to borrow | 
 | 		 * shell context to other thread to avoid mutex deadlock. | 
 | 		 */ | 
 | 		k_mutex_unlock(&shell->ctx->wr_mtx); | 
 | 		flag_cmd_ctx_set(shell, 1); | 
 | 		ret_val = shell->ctx->active_cmd.handler(shell, argc, argv); | 
 | 		flag_cmd_ctx_set(shell, 0); | 
 | 		/* Bring back mutex to shell thread. */ | 
 | 		k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER); | 
 | 	} | 
 |  | 
 | 	return ret_val; | 
 | } | 
 |  | 
 | /* Function is analyzing the command buffer to find matching commands. Next, it | 
 |  * invokes the  last recognized command which has a handler and passes the rest | 
 |  * of command buffer as arguments. | 
 |  */ | 
 | static int execute(const struct shell *shell) | 
 | { | 
 | 	struct shell_static_entry d_entry; /* Memory for dynamic commands. */ | 
 | 	char *argv[CONFIG_SHELL_ARGC_MAX + 1]; /* +1 reserved for NULL */ | 
 | 	const struct shell_static_entry *p_static_entry = NULL; | 
 | 	const struct shell_cmd_entry *p_cmd = NULL; | 
 | 	struct shell_static_entry help_entry; | 
 | 	size_t cmd_lvl = SHELL_CMD_ROOT_LVL; | 
 | 	size_t cmd_with_handler_lvl = 0; | 
 | 	bool wildcard_found = false; | 
 | 	size_t cmd_idx = 0; | 
 | 	size_t argc; | 
 | 	char quote; | 
 |  | 
 | 	shell_op_cursor_end_move(shell); | 
 | 	if (!shell_cursor_in_empty_line(shell)) { | 
 | 		cursor_next_line_move(shell); | 
 | 	} | 
 |  | 
 | 	memset(&shell->ctx->active_cmd, 0, sizeof(shell->ctx->active_cmd)); | 
 |  | 
 | 	shell_cmd_trim(shell); | 
 |  | 
 | 	history_put(shell, shell->ctx->cmd_buff, | 
 | 		    shell->ctx->cmd_buff_len); | 
 |  | 
 | 	if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) { | 
 | 		shell_wildcard_prepare(shell); | 
 | 	} | 
 |  | 
 | 	/* create argument list */ | 
 | 	quote = shell_make_argv(&argc, &argv[0], shell->ctx->cmd_buff, | 
 | 				CONFIG_SHELL_ARGC_MAX); | 
 |  | 
 | 	if (!argc) { | 
 | 		return -ENOEXEC; | 
 | 	} | 
 |  | 
 | 	if (quote != 0) { | 
 | 		shell_internal_fprintf(shell, SHELL_ERROR, | 
 | 				       "not terminated: %c\n", | 
 | 				       quote); | 
 | 		return -ENOEXEC; | 
 | 	} | 
 |  | 
 | 	/* Initialize help variable */ | 
 | 	help_entry.help = NULL; | 
 |  | 
 | 	/* Below loop is analyzing subcommands of found root command. */ | 
 | 	while (true) { | 
 | 		if (cmd_lvl >= argc) { | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		if (IS_ENABLED(CONFIG_SHELL_HELP) && (cmd_lvl > 0) && | 
 | 		    (!strcmp(argv[cmd_lvl], "-h") || | 
 | 		     !strcmp(argv[cmd_lvl], "--help"))) { | 
 | 			/* Command called with help option so it makes no sense | 
 | 			 * to search deeper commands. | 
 | 			 */ | 
 | 			if (help_entry.help) { | 
 | 				shell->ctx->active_cmd = help_entry; | 
 | 				shell_internal_help_print(shell); | 
 | 				return SHELL_CMD_HELP_PRINTED; | 
 | 			} | 
 |  | 
 | 			shell_internal_fprintf(shell, SHELL_ERROR, | 
 | 					       SHELL_MSG_SPECIFY_SUBCOMMAND); | 
 | 			return -ENOEXEC; | 
 | 		} | 
 |  | 
 | 		if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && (cmd_lvl > 0)) { | 
 | 			enum shell_wildcard_status status; | 
 |  | 
 | 			status = shell_wildcard_process(shell, p_cmd, | 
 | 							argv[cmd_lvl]); | 
 | 			/* Wildcard character found but there is no matching | 
 | 			 * command. | 
 | 			 */ | 
 | 			if (status == SHELL_WILDCARD_CMD_NO_MATCH_FOUND) { | 
 | 				break; | 
 | 			} | 
 |  | 
 | 			/* Wildcard character was not found function can process | 
 | 			 * argument. | 
 | 			 */ | 
 | 			if (status != SHELL_WILDCARD_NOT_FOUND) { | 
 | 				++cmd_lvl; | 
 | 				wildcard_found = true; | 
 | 				continue; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		shell_cmd_get(p_cmd, cmd_lvl, cmd_idx++, &p_static_entry, | 
 | 			      &d_entry); | 
 |  | 
 | 		if ((cmd_idx == 0) || (p_static_entry == NULL)) { | 
 | 			if (cmd_lvl == 0) { | 
 | 				shell_internal_fprintf(shell, SHELL_ERROR, | 
 | 						       "%s%s\n", argv[0], | 
 | 						       SHELL_MSG_CMD_NOT_FOUND); | 
 | 				return -ENOEXEC; | 
 | 			} | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		if (strcmp(argv[cmd_lvl], p_static_entry->syntax) == 0) { | 
 | 			/* checking if command has a handler */ | 
 | 			if (p_static_entry->handler != NULL) { | 
 | 				if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && | 
 | 				    (wildcard_found)) { | 
 | 					shell_op_cursor_end_move(shell); | 
 | 					shell_op_cond_next_line(shell); | 
 |  | 
 | 					/* An error occurred, fnmatch  argument | 
 | 					 * cannot be followed by argument with | 
 | 					 * a handler to avoid multiple function | 
 | 					 * calls. | 
 | 					 */ | 
 | 					shell_internal_fprintf(shell, | 
 | 						SHELL_ERROR, | 
 | 						"Error: requested multiple" | 
 | 						" function executions\n"); | 
 |  | 
 | 					return -ENOEXEC; | 
 | 				} | 
 |  | 
 | 				shell->ctx->active_cmd = *p_static_entry; | 
 | 				cmd_with_handler_lvl = cmd_lvl; | 
 | 			} | 
 | 			/* checking if function has a help handler */ | 
 | 			if (p_static_entry->help != NULL) { | 
 | 				help_entry = *p_static_entry; | 
 | 			} | 
 |  | 
 | 			cmd_lvl++; | 
 | 			cmd_idx = 0; | 
 | 			p_cmd = p_static_entry->subcmd; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && wildcard_found) { | 
 | 		shell_wildcard_finalize(shell); | 
 | 		/* cmd_buffer has been overwritten by function finalize function | 
 | 		 * with all expanded commands. Hence shell_make_argv needs to | 
 | 		 * be called again. | 
 | 		 */ | 
 | 		(void)shell_make_argv(&argc, &argv[0], | 
 | 				      shell->ctx->cmd_buff, | 
 | 				      CONFIG_SHELL_ARGC_MAX); | 
 | 	} | 
 |  | 
 | 	/* Executing the deepest found handler. */ | 
 | 	return exec_cmd(shell, argc - cmd_with_handler_lvl, | 
 | 			&argv[cmd_with_handler_lvl], &help_entry); | 
 | } | 
 |  | 
 | static void tab_handle(const struct shell *shell) | 
 | { | 
 | 	/* +1 reserved for NULL in function shell_make_argv */ | 
 | 	char *argv[CONFIG_SHELL_ARGC_MAX + 1]; | 
 | 	/* d_entry - placeholder for dynamic command */ | 
 | 	struct shell_static_entry d_entry; | 
 | 	const struct shell_static_entry *cmd; | 
 | 	size_t first = 0; | 
 | 	size_t arg_idx; | 
 | 	u16_t longest; | 
 | 	size_t argc; | 
 | 	size_t cnt; | 
 |  | 
 | 	bool tab_possible = tab_prepare(shell, &cmd, argv, &argc, | 
 | 					      &arg_idx, &d_entry); | 
 |  | 
 | 	if (tab_possible == false) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	find_completion_candidates(cmd, argv[arg_idx], &first, &cnt, &longest); | 
 |  | 
 | 	if (cnt == 1) { | 
 | 		/* Autocompletion.*/ | 
 | 		autocomplete(shell, cmd, argv[arg_idx], first); | 
 | 	} else if (cnt > 1) { | 
 | 		tab_options_print(shell, cmd, argv[arg_idx], first, cnt, | 
 | 				  longest); | 
 | 		partial_autocomplete(shell, cmd, argv[arg_idx], first, cnt); | 
 | 	} | 
 | } | 
 |  | 
 | static void alt_metakeys_handle(const struct shell *shell, char data) | 
 | { | 
 | 	/* Optional feature */ | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) { | 
 | 		return; | 
 | 	} | 
 | 	if (data == SHELL_VT100_ASCII_ALT_B) { | 
 | 		shell_op_cursor_word_move(shell, -1); | 
 | 	} else if (data == SHELL_VT100_ASCII_ALT_F) { | 
 | 		shell_op_cursor_word_move(shell, 1); | 
 | 	} | 
 | } | 
 |  | 
 | static void ctrl_metakeys_handle(const struct shell *shell, char data) | 
 | { | 
 | 	/* Optional feature */ | 
 | 	if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	switch (data) { | 
 | 	case SHELL_VT100_ASCII_CTRL_A: /* CTRL + A */ | 
 | 		shell_op_cursor_home_move(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_B: /* CTRL + B */ | 
 | 		shell_op_left_arrow(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_C: /* CTRL + C */ | 
 | 		shell_op_cursor_end_move(shell); | 
 | 		if (!shell_cursor_in_empty_line(shell)) { | 
 | 			cursor_next_line_move(shell); | 
 | 		} | 
 | 		flag_history_exit_set(shell, true); | 
 | 		state_set(shell, SHELL_STATE_ACTIVE); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_D: /* CTRL + D */ | 
 | 		shell_op_char_delete(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_E: /* CTRL + E */ | 
 | 		shell_op_cursor_end_move(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_F: /* CTRL + F */ | 
 | 		shell_op_right_arrow(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_K: /* CTRL + K */ | 
 | 		shell_op_delete_from_cursor(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_L: /* CTRL + L */ | 
 | 		SHELL_VT100_CMD(shell, SHELL_VT100_CURSORHOME); | 
 | 		SHELL_VT100_CMD(shell, SHELL_VT100_CLEARSCREEN); | 
 | 		shell_print_prompt_and_cmd(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_U: /* CTRL + U */ | 
 | 		shell_op_cursor_home_move(shell); | 
 | 		cmd_buffer_clear(shell); | 
 | 		flag_history_exit_set(shell, true); | 
 | 		clear_eos(shell); | 
 | 		break; | 
 |  | 
 | 	case SHELL_VT100_ASCII_CTRL_W: /* CTRL + W */ | 
 | 		shell_op_word_remove(shell); | 
 | 		flag_history_exit_set(shell, true); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		break; | 
 | 	} | 
 | } | 
 |  | 
 | /* Functions returns true if new line character shall be processed */ | 
 | static bool process_nl(const struct shell *shell, u8_t data) | 
 | { | 
 | 	if ((data != '\r') && (data != '\n')) { | 
 | 		flag_last_nl_set(shell, 0); | 
 | 		return false; | 
 | 	} | 
 |  | 
 | 	if ((flag_last_nl_get(shell) == 0U) || | 
 | 	    (data == flag_last_nl_get(shell))) { | 
 | 		flag_last_nl_set(shell, data); | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	return false; | 
 | } | 
 |  | 
 | #define SHELL_ASCII_MAX_CHAR (127u) | 
 | static inline int ascii_filter(const char data) | 
 | { | 
 | 	return (u8_t) data > SHELL_ASCII_MAX_CHAR ? -EINVAL : 0; | 
 | } | 
 |  | 
 | static void state_collect(const struct shell *shell) | 
 | { | 
 | 	size_t count = 0; | 
 | 	char data; | 
 |  | 
 | 	while (true) { | 
 | 		(void)shell->iface->api->read(shell->iface, &data, | 
 | 					      sizeof(data), &count); | 
 | 		if (count == 0) { | 
 | 			return; | 
 | 		} | 
 |  | 
 | 		if (ascii_filter(data) != 0) { | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		switch (shell->ctx->receive_state) { | 
 | 		case SHELL_RECEIVE_DEFAULT: | 
 | 			if (process_nl(shell, data)) { | 
 | 				if (!shell->ctx->cmd_buff_len) { | 
 | 					history_mode_exit(shell); | 
 | 					cursor_next_line_move(shell); | 
 | 				} else { | 
 | 					/* Command execution */ | 
 | 					(void)execute(shell); | 
 | 				} | 
 | 				/* Function responsible for printing prompt | 
 | 				 * on received NL. | 
 | 				 */ | 
 | 				state_set(shell, SHELL_STATE_ACTIVE); | 
 | 				continue; | 
 | 			} | 
 |  | 
 | 			switch (data) { | 
 | 			case SHELL_VT100_ASCII_ESC: /* ESCAPE */ | 
 | 				receive_state_change(shell, SHELL_RECEIVE_ESC); | 
 | 				break; | 
 |  | 
 | 			case '\0': | 
 | 				break; | 
 |  | 
 | 			case '\t': /* TAB */ | 
 | 				if (flag_echo_get(shell)) { | 
 | 					/* If the Tab key is pressed, "history | 
 | 					 * mode" must be terminated because | 
 | 					 * tab and history handlers are sharing | 
 | 					 * the same array: temp_buff. | 
 | 					 */ | 
 | 					flag_history_exit_set(shell, true); | 
 | 					tab_handle(shell); | 
 | 				} | 
 | 				break; | 
 |  | 
 | 			case SHELL_VT100_ASCII_BSPACE: /* BACKSPACE */ | 
 | 				if (flag_echo_get(shell)) { | 
 | 					flag_history_exit_set(shell, true); | 
 | 					shell_op_char_backspace(shell); | 
 | 				} | 
 | 				break; | 
 |  | 
 | 			case SHELL_VT100_ASCII_DEL: /* DELETE */ | 
 | 				if (flag_echo_get(shell)) { | 
 | 					flag_history_exit_set(shell, true); | 
 | 					if (flag_mode_delete_get(shell)) { | 
 | 						shell_op_char_backspace(shell); | 
 |  | 
 | 					} else { | 
 | 						shell_op_char_delete(shell); | 
 | 					} | 
 | 				} | 
 | 				break; | 
 |  | 
 | 			default: | 
 | 				if (isprint((int) data)) { | 
 | 					flag_history_exit_set(shell, true); | 
 | 					shell_op_char_insert(shell, data); | 
 | 				} else if (flag_echo_get(shell)) { | 
 | 					ctrl_metakeys_handle(shell, data); | 
 | 				} | 
 | 				break; | 
 | 			} | 
 | 			break; | 
 |  | 
 | 		case SHELL_RECEIVE_ESC: | 
 | 			if (data == '[') { | 
 | 				receive_state_change(shell, | 
 | 						SHELL_RECEIVE_ESC_SEQ); | 
 | 				break; | 
 | 			} else if (flag_echo_get(shell)) { | 
 | 				alt_metakeys_handle(shell, data); | 
 | 			} | 
 | 			receive_state_change(shell, SHELL_RECEIVE_DEFAULT); | 
 | 			break; | 
 |  | 
 | 		case SHELL_RECEIVE_ESC_SEQ: | 
 | 			receive_state_change(shell, SHELL_RECEIVE_DEFAULT); | 
 |  | 
 | 			if (!flag_echo_get(shell)) { | 
 | 				continue; | 
 | 			} | 
 |  | 
 | 			switch (data) { | 
 | 			case 'A': /* UP arrow */ | 
 | 				history_handle(shell, true); | 
 | 				break; | 
 |  | 
 | 			case 'B': /* DOWN arrow */ | 
 | 				history_handle(shell, false); | 
 | 				break; | 
 |  | 
 | 			case 'C': /* RIGHT arrow */ | 
 | 				shell_op_right_arrow(shell); | 
 | 				break; | 
 |  | 
 | 			case 'D': /* LEFT arrow */ | 
 | 				shell_op_left_arrow(shell); | 
 | 				break; | 
 |  | 
 | 			case '4': /* END Button in ESC[n~ mode */ | 
 | 				receive_state_change(shell, | 
 | 						SHELL_RECEIVE_TILDE_EXP); | 
 | 				/* fall through */ | 
 | 				/* no break */ | 
 | 			case 'F': /* END Button in VT100 mode */ | 
 | 				shell_op_cursor_end_move(shell); | 
 | 				break; | 
 |  | 
 | 			case '1': /* HOME Button in ESC[n~ mode */ | 
 | 				receive_state_change(shell, | 
 | 						SHELL_RECEIVE_TILDE_EXP); | 
 | 				/* fall through */ | 
 | 				/* no break */ | 
 | 			case 'H': /* HOME Button in VT100 mode */ | 
 | 				shell_op_cursor_home_move(shell); | 
 | 				break; | 
 |  | 
 | 			case '2': /* INSERT Button in ESC[n~ mode */ | 
 | 				receive_state_change(shell, | 
 | 						SHELL_RECEIVE_TILDE_EXP); | 
 | 				/* fall through */ | 
 | 				/* no break */ | 
 | 			case 'L': {/* INSERT Button in VT100 mode */ | 
 | 				bool status = flag_insert_mode_get(shell); | 
 | 				flag_insert_mode_set(shell, !status); | 
 | 				break; | 
 | 			} | 
 |  | 
 | 			case '3':/* DELETE Button in ESC[n~ mode */ | 
 | 				receive_state_change(shell, | 
 | 						SHELL_RECEIVE_TILDE_EXP); | 
 | 				if (flag_echo_get(shell)) { | 
 | 					shell_op_char_delete(shell); | 
 | 				} | 
 | 				break; | 
 |  | 
 | 			default: | 
 | 				break; | 
 | 			} | 
 | 			break; | 
 |  | 
 | 		case SHELL_RECEIVE_TILDE_EXP: | 
 | 			receive_state_change(shell, SHELL_RECEIVE_DEFAULT); | 
 | 			break; | 
 |  | 
 | 		default: | 
 | 			receive_state_change(shell, SHELL_RECEIVE_DEFAULT); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	transport_buffer_flush(shell); | 
 | } | 
 |  | 
 | static void transport_evt_handler(enum shell_transport_evt evt_type, void *ctx) | 
 | { | 
 | 	struct shell *shell = (struct shell *)ctx; | 
 | 	struct k_poll_signal *signal; | 
 |  | 
 | 	signal = (evt_type == SHELL_TRANSPORT_EVT_RX_RDY) ? | 
 | 			&shell->ctx->signals[SHELL_SIGNAL_RXRDY] : | 
 | 			&shell->ctx->signals[SHELL_SIGNAL_TXDONE]; | 
 | 	k_poll_signal_raise(signal, 0); | 
 | } | 
 |  | 
 | static void shell_log_process(const struct shell *shell) | 
 | { | 
 | 	bool processed = false; | 
 | 	int signaled = 0; | 
 | 	int result; | 
 |  | 
 | 	do { | 
 | 		if (!IS_ENABLED(CONFIG_LOG_IMMEDIATE)) { | 
 | 			shell_cmd_line_erase(shell); | 
 |  | 
 | 			processed = shell_log_backend_process(shell->log_backend); | 
 | 		} | 
 |  | 
 | 		struct k_poll_signal *signal = | 
 | 			&shell->ctx->signals[SHELL_SIGNAL_RXRDY]; | 
 |  | 
 | 		shell_print_prompt_and_cmd(shell); | 
 |  | 
 | 		/* Arbitrary delay added to ensure that prompt is | 
 | 		 * readable and can be used to enter further commands. | 
 | 		 */ | 
 | 		if (shell->ctx->cmd_buff_len) { | 
 | 			k_sleep(K_MSEC(15)); | 
 | 		} | 
 |  | 
 | 		k_poll_signal_check(signal, &signaled, &result); | 
 |  | 
 | 	} while (processed && !signaled); | 
 | } | 
 |  | 
 | static int instance_init(const struct shell *shell, const void *p_config, | 
 | 			 bool use_colors) | 
 | { | 
 | 	__ASSERT_NO_MSG((shell->shell_flag == SHELL_FLAG_CRLF_DEFAULT) || | 
 | 			(shell->shell_flag == SHELL_FLAG_OLF_CRLF)); | 
 |  | 
 | 	int err = shell->iface->api->init(shell->iface, p_config, | 
 | 					  transport_evt_handler, | 
 | 					  (void *) shell); | 
 | 	if (err != 0) { | 
 | 		return err; | 
 | 	} | 
 |  | 
 | 	memset(shell->ctx, 0, sizeof(*shell->ctx)); | 
 | 	shell->ctx->prompt = shell->default_prompt; | 
 |  | 
 | 	history_init(shell); | 
 |  | 
 | 	k_mutex_init(&shell->ctx->wr_mtx); | 
 |  | 
 | 	if (IS_ENABLED(CONFIG_SHELL_STATS)) { | 
 | 		shell->stats->log_lost_cnt = 0; | 
 | 	} | 
 |  | 
 | 	flag_tx_rdy_set(shell, true); | 
 | 	flag_echo_set(shell, IS_ENABLED(CONFIG_SHELL_ECHO_STATUS)); | 
 | 	flag_mode_delete_set(shell, | 
 | 			     IS_ENABLED(CONFIG_SHELL_BACKSPACE_MODE_DELETE)); | 
 | 	shell->ctx->state = SHELL_STATE_INITIALIZED; | 
 | 	shell->ctx->vt100_ctx.cons.terminal_wid = SHELL_DEFAULT_TERMINAL_WIDTH; | 
 | 	shell->ctx->vt100_ctx.cons.terminal_hei = SHELL_DEFAULT_TERMINAL_HEIGHT; | 
 | 	shell->ctx->vt100_ctx.cons.name_len = shell_strlen(shell->ctx->prompt); | 
 | 	flag_use_colors_set(shell, IS_ENABLED(CONFIG_SHELL_VT100_COLORS)); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int instance_uninit(const struct shell *shell) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 | 	__ASSERT_NO_MSG(shell->ctx && shell->iface); | 
 |  | 
 | 	int err; | 
 |  | 
 | 	if (flag_processing_get(shell)) { | 
 | 		return -EBUSY; | 
 | 	} | 
 |  | 
 | 	if (IS_ENABLED(CONFIG_LOG)) { | 
 | 		/* todo purge log queue */ | 
 | 		shell_log_backend_disable(shell->log_backend); | 
 | 	} | 
 |  | 
 | 	err = shell->iface->api->uninit(shell->iface); | 
 | 	if (err != 0) { | 
 | 		return err; | 
 | 	} | 
 |  | 
 | 	history_purge(shell); | 
 |  | 
 | 	shell->ctx->state = SHELL_STATE_UNINITIALIZED; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | typedef void (*shell_signal_handler_t)(const struct shell *shell); | 
 |  | 
 | static void shell_signal_handle(const struct shell *shell, | 
 | 				enum shell_signal sig_idx, | 
 | 				shell_signal_handler_t handler) | 
 | { | 
 | 	struct k_poll_signal *signal = &shell->ctx->signals[sig_idx]; | 
 | 	int set; | 
 | 	int res; | 
 |  | 
 | 	k_poll_signal_check(signal, &set, &res); | 
 |  | 
 | 	if (set) { | 
 | 		k_poll_signal_reset(signal); | 
 | 		handler(shell); | 
 | 	} | 
 | } | 
 |  | 
 | static void kill_handler(const struct shell *shell) | 
 | { | 
 | 	(void)instance_uninit(shell); | 
 | 	k_thread_abort(k_current_get()); | 
 | } | 
 |  | 
 | void shell_thread(void *shell_handle, void *arg_log_backend, | 
 | 		  void *arg_log_level) | 
 | { | 
 | 	struct shell *shell = (struct shell *)shell_handle; | 
 | 	bool log_backend = (bool)arg_log_backend; | 
 | 	u32_t log_level = (u32_t)arg_log_level; | 
 | 	int err; | 
 |  | 
 | 	for (int i = 0; i < SHELL_SIGNALS; i++) { | 
 | 		k_poll_signal_init(&shell->ctx->signals[i]); | 
 | 		k_poll_event_init(&shell->ctx->events[i], | 
 | 				  K_POLL_TYPE_SIGNAL, | 
 | 				  K_POLL_MODE_NOTIFY_ONLY, | 
 | 				  &shell->ctx->signals[i]); | 
 | 	} | 
 |  | 
 | 	err = shell->iface->api->enable(shell->iface, false); | 
 | 	if (err != 0) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	if (log_backend && IS_ENABLED(CONFIG_LOG)) { | 
 | 		shell_log_backend_enable(shell->log_backend, (void *)shell, | 
 | 					 log_level); | 
 | 	} | 
 |  | 
 | 	/* Enable shell and print prompt. */ | 
 | 	err = shell_start(shell); | 
 | 	if (err != 0) { | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	while (true) { | 
 | 		/* waiting for all signals except SHELL_SIGNAL_TXDONE */ | 
 | 		err = k_poll(shell->ctx->events, SHELL_SIGNAL_TXDONE, | 
 | 			     K_FOREVER); | 
 |  | 
 | 		k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER); | 
 |  | 
 | 		if (err != 0) { | 
 | 			shell_internal_fprintf(shell, SHELL_ERROR, | 
 | 					       "Shell thread error: %d", err); | 
 | 			return; | 
 | 		} | 
 |  | 
 | 		if (shell->iface->api->update) { | 
 | 			shell->iface->api->update(shell->iface); | 
 | 		} | 
 |  | 
 | 		shell_signal_handle(shell, SHELL_SIGNAL_KILL, kill_handler); | 
 | 		shell_signal_handle(shell, SHELL_SIGNAL_RXRDY, shell_process); | 
 | 		if (IS_ENABLED(CONFIG_LOG)) { | 
 | 			shell_signal_handle(shell, SHELL_SIGNAL_LOG_MSG, | 
 | 					    shell_log_process); | 
 | 		} | 
 |  | 
 | 		k_mutex_unlock(&shell->ctx->wr_mtx); | 
 | 	} | 
 | } | 
 |  | 
 | int shell_init(const struct shell *shell, const void *transport_config, | 
 | 	       bool use_colors, bool log_backend, u32_t init_log_level) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 | 	__ASSERT_NO_MSG(shell->ctx && shell->iface && shell->default_prompt); | 
 |  | 
 | 	int err = instance_init(shell, transport_config, use_colors); | 
 |  | 
 | 	if (err != 0) { | 
 | 		return err; | 
 | 	} | 
 |  | 
 | 	k_tid_t tid = k_thread_create(shell->thread, | 
 | 			      shell->stack, CONFIG_SHELL_STACK_SIZE, | 
 | 			      shell_thread, (void *)shell, (void *)log_backend, | 
 | 			      (void *)init_log_level, | 
 | 			      K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT); | 
 |  | 
 | 	shell->ctx->tid = tid; | 
 | 	k_thread_name_set(tid, shell->thread_name); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int shell_uninit(const struct shell *shell) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 |  | 
 | 	if (IS_ENABLED(CONFIG_MULTITHREADING)) { | 
 | 		struct k_poll_signal *signal = | 
 | 				&shell->ctx->signals[SHELL_SIGNAL_KILL]; | 
 |  | 
 | 		/* signal kill message */ | 
 | 		(void)k_poll_signal_raise(signal, 0); | 
 |  | 
 | 		return 0; | 
 | 	} else { | 
 | 		return instance_uninit(shell); | 
 | 	} | 
 | } | 
 |  | 
 | int shell_start(const struct shell *shell) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 | 	__ASSERT_NO_MSG(shell->ctx && shell->iface && shell->default_prompt); | 
 |  | 
 | 	if (shell->ctx->state != SHELL_STATE_INITIALIZED) { | 
 | 		return -ENOTSUP; | 
 | 	} | 
 |  | 
 | 	if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) { | 
 | 		shell_vt100_color_set(shell, SHELL_NORMAL); | 
 | 	} | 
 |  | 
 | 	shell_raw_fprintf(shell->fprintf_ctx, "\n\n"); | 
 |  | 
 | 	state_set(shell, SHELL_STATE_ACTIVE); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int shell_stop(const struct shell *shell) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 | 	__ASSERT_NO_MSG(shell->ctx); | 
 |  | 
 | 	if ((shell->ctx->state == SHELL_STATE_INITIALIZED) || | 
 | 	    (shell->ctx->state == SHELL_STATE_UNINITIALIZED)) { | 
 | 		return -ENOTSUP; | 
 | 	} | 
 |  | 
 | 	state_set(shell, SHELL_STATE_INITIALIZED); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | void shell_process(const struct shell *shell) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 | 	__ASSERT_NO_MSG(shell->ctx); | 
 |  | 
 | 	union shell_internal internal; | 
 |  | 
 | 	internal.value = 0U; | 
 | 	internal.flags.processing = 1U; | 
 |  | 
 | 	(void)atomic_or((atomic_t *)&shell->ctx->internal.value, | 
 | 			internal.value); | 
 |  | 
 | 	switch (shell->ctx->state) { | 
 | 	case SHELL_STATE_UNINITIALIZED: | 
 | 	case SHELL_STATE_INITIALIZED: | 
 | 		/* Console initialized but not started. */ | 
 | 		break; | 
 |  | 
 | 	case SHELL_STATE_ACTIVE: | 
 | 		state_collect(shell); | 
 | 		break; | 
 | 	default: | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	internal.value = 0xFFFFFFFF; | 
 | 	internal.flags.processing = 0U; | 
 | 	(void)atomic_and((atomic_t *)&shell->ctx->internal.value, | 
 | 			 internal.value); | 
 | } | 
 |  | 
 | /* This function mustn't be used from shell context to avoid deadlock. | 
 |  * However it can be used in shell command handlers. | 
 |  */ | 
 | void shell_fprintf(const struct shell *shell, enum shell_vt100_color color, | 
 | 		   const char *fmt, ...) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 | 	__ASSERT(!k_is_in_isr(), "Thread context required."); | 
 | 	__ASSERT_NO_MSG((shell->ctx->internal.flags.cmd_ctx == 1) || | 
 | 			(k_current_get() != shell->ctx->tid)); | 
 | 	__ASSERT_NO_MSG(shell->ctx); | 
 | 	__ASSERT_NO_MSG(shell->fprintf_ctx); | 
 | 	__ASSERT_NO_MSG(fmt); | 
 |  | 
 | 	va_list args = { 0 }; | 
 |  | 
 | 	k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER); | 
 | 	if (!flag_cmd_ctx_get(shell)) { | 
 | 		shell_cmd_line_erase(shell); | 
 | 	} | 
 |  | 
 | 	va_start(args, fmt); | 
 | 	shell_internal_vfprintf(shell, color, fmt, args); | 
 | 	va_end(args); | 
 |  | 
 | 	if (!flag_cmd_ctx_get(shell)) { | 
 | 		shell_print_prompt_and_cmd(shell); | 
 | 	} | 
 | 	transport_buffer_flush(shell); | 
 | 	k_mutex_unlock(&shell->ctx->wr_mtx); | 
 | } | 
 |  | 
 | void shell_hexdump(const struct shell *shell, const u8_t *data, size_t len) | 
 | { | 
 | 	int n = 0; | 
 |  | 
 | 	while (len--) { | 
 | 		if (n % 16 == 0) { | 
 | 			shell_fprintf(shell, SHELL_NORMAL, "%08X: ", n); | 
 | 		} | 
 |  | 
 | 		shell_fprintf(shell, SHELL_NORMAL, "%02X ", *data++); | 
 |  | 
 | 		n++; | 
 | 		if (n % 16 == 0) { | 
 | 			shell_print(shell, ""); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if (n % 16) { | 
 | 		shell_print(shell, ""); | 
 | 	} | 
 | } | 
 |  | 
 | int shell_prompt_change(const struct shell *shell, const char *prompt) | 
 | { | 
 | 	__ASSERT_NO_MSG(shell); | 
 |  | 
 | 	if (prompt == NULL) { | 
 | 		return -EINVAL; | 
 | 	} | 
 | 	shell->ctx->prompt = prompt; | 
 | 	shell->ctx->vt100_ctx.cons.name_len = shell_strlen(prompt); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | void shell_help(const struct shell *shell) | 
 | { | 
 | 	k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER); | 
 | 	shell_internal_help_print(shell); | 
 | 	k_mutex_unlock(&shell->ctx->wr_mtx); | 
 | } | 
 |  | 
 | int shell_execute_cmd(const struct shell *shell, const char *cmd) | 
 | { | 
 | 	u16_t cmd_len = shell_strlen(cmd); | 
 | 	int ret_val; | 
 |  | 
 | 	if (cmd == NULL) { | 
 | 		return -ENOEXEC; | 
 | 	} | 
 |  | 
 | 	if (cmd_len > (CONFIG_SHELL_CMD_BUFF_SIZE - 1)) { | 
 | 		return -ENOMEM; | 
 | 	} | 
 |  | 
 | 	if (shell == NULL) { | 
 | #if CONFIG_SHELL_BACKEND_DUMMY | 
 | 		shell = shell_backend_dummy_get_ptr(); | 
 | #else | 
 | 		return -EINVAL; | 
 | #endif | 
 | 	} | 
 |  | 
 | 	__ASSERT(shell->ctx->internal.flags.cmd_ctx == 0, | 
 | 						"Function cannot be called" | 
 | 						" from command context"); | 
 |  | 
 | 	strcpy(shell->ctx->cmd_buff, cmd); | 
 | 	shell->ctx->cmd_buff_len = cmd_len; | 
 | 	shell->ctx->cmd_buff_pos = cmd_len; | 
 |  | 
 | 	k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER); | 
 | 	ret_val = execute(shell); | 
 | 	k_mutex_unlock(&shell->ctx->wr_mtx); | 
 |  | 
 | 	return ret_val; | 
 | } |