1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <zephyr/sys/atomic.h>
10 #include <zephyr/shell/shell.h>
11 #if defined(CONFIG_SHELL_BACKEND_DUMMY)
12 #include <zephyr/shell/shell_dummy.h>
13 #endif
14 #include "shell_ops.h"
15 #include "shell_help.h"
16 #include "shell_utils.h"
17 #include "shell_vt100.h"
18 #include "shell_wildcard.h"
19 
20 /* 2 == 1 char for cmd + 1 char for '\0' */
21 #if (CONFIG_SHELL_CMD_BUFF_SIZE < 2)
22 	#error too small CONFIG_SHELL_CMD_BUFF_SIZE
23 #endif
24 
25 #if (CONFIG_SHELL_PRINTF_BUFF_SIZE < 1)
26 	#error too small SHELL_PRINTF_BUFF_SIZE
27 #endif
28 
29 #define SHELL_MSG_CMD_NOT_FOUND		": command not found"
30 #define SHELL_MSG_BACKEND_NOT_ACTIVE	\
31 	"WARNING: A print request was detected on not active shell backend.\n"
32 #define SHELL_MSG_TOO_MANY_ARGS		"Too many arguments in the command.\n"
33 #define SHELL_INIT_OPTION_PRINTER	(NULL)
34 
35 #define SHELL_THREAD_PRIORITY \
36 	COND_CODE_1(CONFIG_SHELL_THREAD_PRIORITY_OVERRIDE, \
37 			(CONFIG_SHELL_THREAD_PRIORITY), (K_LOWEST_APPLICATION_THREAD_PRIO))
38 
39 BUILD_ASSERT(SHELL_THREAD_PRIORITY >=
40 		  K_HIGHEST_APPLICATION_THREAD_PRIO
41 		&& SHELL_THREAD_PRIORITY <= K_LOWEST_APPLICATION_THREAD_PRIO,
42 		  "Invalid range for thread priority");
43 
receive_state_change(const struct shell * sh,enum shell_receive_state state)44 static inline void receive_state_change(const struct shell *sh,
45 					enum shell_receive_state state)
46 {
47 	sh->ctx->receive_state = state;
48 }
49 
cmd_buffer_clear(const struct shell * sh)50 static void cmd_buffer_clear(const struct shell *sh)
51 {
52 	sh->ctx->cmd_buff[0] = '\0'; /* clear command buffer */
53 	sh->ctx->cmd_buff_pos = 0;
54 	sh->ctx->cmd_buff_len = 0;
55 }
56 
shell_internal_help_print(const struct shell * sh)57 static void shell_internal_help_print(const struct shell *sh)
58 {
59 	if (!IS_ENABLED(CONFIG_SHELL_HELP)) {
60 		return;
61 	}
62 
63 	z_shell_help_cmd_print(sh, &sh->ctx->active_cmd);
64 	z_shell_help_subcmd_print(sh, &sh->ctx->active_cmd,
65 				  "Subcommands:\n");
66 }
67 
68 /**
69  * @brief Prints error message on wrong argument count.
70  *	  Optionally, printing help on wrong argument count.
71  *
72  * @param[in] shell	  Pointer to the shell instance.
73  * @param[in] arg_cnt_ok  Flag indicating valid number of arguments.
74  *
75  * @return 0		  if check passed
76  * @return -EINVAL	  if wrong argument count
77  */
cmd_precheck(const struct shell * sh,bool arg_cnt_ok)78 static int cmd_precheck(const struct shell *sh,
79 			bool arg_cnt_ok)
80 {
81 	if (!arg_cnt_ok) {
82 		z_shell_fprintf(sh, SHELL_ERROR,
83 				"%s: wrong parameter count\n",
84 				sh->ctx->active_cmd.syntax);
85 
86 		if (IS_ENABLED(CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT)) {
87 			shell_internal_help_print(sh);
88 		}
89 
90 		return -EINVAL;
91 	}
92 
93 	return 0;
94 }
95 
state_set(const struct shell * sh,enum shell_state state)96 static inline void state_set(const struct shell *sh, enum shell_state state)
97 {
98 	sh->ctx->state = state;
99 
100 	if (state == SHELL_STATE_ACTIVE && !sh->ctx->bypass) {
101 		cmd_buffer_clear(sh);
102 		if (z_flag_print_noinit_get(sh)) {
103 			z_shell_fprintf(sh, SHELL_WARNING, "%s",
104 					SHELL_MSG_BACKEND_NOT_ACTIVE);
105 			z_flag_print_noinit_set(sh, false);
106 		}
107 		z_shell_print_prompt_and_cmd(sh);
108 	}
109 }
110 
state_get(const struct shell * sh)111 static inline enum shell_state state_get(const struct shell *sh)
112 {
113 	return sh->ctx->state;
114 }
115 
116 static inline const struct shell_static_entry *
selected_cmd_get(const struct shell * sh)117 selected_cmd_get(const struct shell *sh)
118 {
119 	if (IS_ENABLED(CONFIG_SHELL_CMDS_SELECT)
120 	    || (CONFIG_SHELL_CMD_ROOT[0] != 0)) {
121 		return sh->ctx->selected_cmd;
122 	}
123 
124 	return NULL;
125 }
126 
tab_item_print(const struct shell * sh,const char * option,uint16_t longest_option)127 static void tab_item_print(const struct shell *sh, const char *option,
128 			   uint16_t longest_option)
129 {
130 	static const char *tab = "  ";
131 	uint16_t columns;
132 	uint16_t diff;
133 
134 	/* Function initialization has been requested. */
135 	if (option == NULL) {
136 		sh->ctx->vt100_ctx.printed_cmd = 0;
137 		return;
138 	}
139 
140 	longest_option += z_shell_strlen(tab);
141 
142 	columns = (sh->ctx->vt100_ctx.cons.terminal_wid
143 			- z_shell_strlen(tab)) / longest_option;
144 	diff = longest_option - z_shell_strlen(option);
145 
146 	if (sh->ctx->vt100_ctx.printed_cmd++ % columns == 0U) {
147 		z_shell_fprintf(sh, SHELL_OPTION, "\n%s%s", tab, option);
148 	} else {
149 		z_shell_fprintf(sh, SHELL_OPTION, "%s", option);
150 	}
151 
152 	z_shell_op_cursor_horiz_move(sh, diff);
153 }
154 
history_init(const struct shell * sh)155 static void history_init(const struct shell *sh)
156 {
157 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
158 		return;
159 	}
160 
161 	z_shell_history_init(sh->history);
162 }
163 
history_purge(const struct shell * sh)164 static void history_purge(const struct shell *sh)
165 {
166 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
167 		return;
168 	}
169 
170 	z_shell_history_purge(sh->history);
171 }
172 
history_mode_exit(const struct shell * sh)173 static void history_mode_exit(const struct shell *sh)
174 {
175 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
176 		return;
177 	}
178 
179 	z_flag_history_exit_set(sh, false);
180 	z_shell_history_mode_exit(sh->history);
181 }
182 
history_put(const struct shell * sh,uint8_t * line,size_t length)183 static void history_put(const struct shell *sh, uint8_t *line, size_t length)
184 {
185 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
186 		return;
187 	}
188 
189 	z_shell_history_put(sh->history, line, length);
190 }
191 
history_handle(const struct shell * sh,bool up)192 static void history_handle(const struct shell *sh, bool up)
193 {
194 	bool history_mode;
195 	uint16_t len;
196 
197 	/*optional feature */
198 	if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
199 		return;
200 	}
201 
202 	/* Checking if history process has been stopped */
203 	if (z_flag_history_exit_get(sh)) {
204 		z_flag_history_exit_set(sh, false);
205 		z_shell_history_mode_exit(sh->history);
206 	}
207 
208 	/* Backup command if history is entered */
209 	if (!z_shell_history_active(sh->history)) {
210 		if (up) {
211 			uint16_t cmd_len = z_shell_strlen(sh->ctx->cmd_buff);
212 
213 			if (cmd_len) {
214 				strcpy(sh->ctx->temp_buff,
215 				       sh->ctx->cmd_buff);
216 			} else {
217 				sh->ctx->temp_buff[0] = '\0';
218 			}
219 		} else {
220 			/* Pressing 'down' not in history mode has no effect. */
221 			return;
222 		}
223 	}
224 
225 	/* Start by checking if history is not empty. */
226 	history_mode = z_shell_history_get(sh->history, up,
227 					   sh->ctx->cmd_buff, &len);
228 
229 	/* On exiting history mode print backed up command. */
230 	if (!history_mode) {
231 		strcpy(sh->ctx->cmd_buff, sh->ctx->temp_buff);
232 		len = z_shell_strlen(sh->ctx->cmd_buff);
233 	}
234 
235 	z_shell_op_cursor_home_move(sh);
236 	z_clear_eos(sh);
237 	z_shell_print_cmd(sh);
238 	sh->ctx->cmd_buff_pos = len;
239 	sh->ctx->cmd_buff_len = len;
240 	z_shell_op_cond_next_line(sh);
241 }
242 
completion_space_get(const struct shell * sh)243 static inline uint16_t completion_space_get(const struct shell *sh)
244 {
245 	uint16_t space = (CONFIG_SHELL_CMD_BUFF_SIZE - 1) -
246 			sh->ctx->cmd_buff_len;
247 	return space;
248 }
249 
250 /* Prepare arguments and return number of space available for completion. */
tab_prepare(const struct shell * sh,const struct shell_static_entry ** cmd,const char *** argv,size_t * argc,size_t * complete_arg_idx,struct shell_static_entry * d_entry)251 static bool tab_prepare(const struct shell *sh,
252 			const struct shell_static_entry **cmd,
253 			const char ***argv, size_t *argc,
254 			size_t *complete_arg_idx,
255 			struct shell_static_entry *d_entry)
256 {
257 	uint16_t compl_space = completion_space_get(sh);
258 	size_t search_argc;
259 
260 	if (compl_space == 0U) {
261 		return false;
262 	}
263 
264 	/* Copy command from its beginning to cursor position. */
265 	memcpy(sh->ctx->temp_buff, sh->ctx->cmd_buff,
266 			sh->ctx->cmd_buff_pos);
267 	sh->ctx->temp_buff[sh->ctx->cmd_buff_pos] = '\0';
268 
269 	/* Create argument list. */
270 	(void)z_shell_make_argv(argc, *argv, sh->ctx->temp_buff,
271 				CONFIG_SHELL_ARGC_MAX);
272 
273 	if (*argc > CONFIG_SHELL_ARGC_MAX) {
274 		return false;
275 	}
276 
277 	/* terminate arguments with NULL */
278 	(*argv)[*argc] = NULL;
279 
280 	if ((IS_ENABLED(CONFIG_SHELL_CMDS_SELECT) || (CONFIG_SHELL_CMD_ROOT[0] != 0))
281 	    && (*argc > 0) &&
282 	    (strcmp("select", (*argv)[0]) == 0) &&
283 	    !z_shell_in_select_mode(sh)) {
284 		*argv = *argv + 1;
285 		*argc = *argc - 1;
286 	}
287 
288 	/* If last command is not completed (followed by space) it is treated
289 	 * as uncompleted one.
290 	 */
291 	int space = isspace((int)sh->ctx->cmd_buff[
292 						sh->ctx->cmd_buff_pos - 1]);
293 
294 	/* root command completion */
295 	if ((*argc == 0) || ((space == 0) && (*argc == 1))) {
296 		*complete_arg_idx = Z_SHELL_CMD_ROOT_LVL;
297 		*cmd = selected_cmd_get(sh);
298 		return true;
299 	}
300 
301 	search_argc = space ? *argc : *argc - 1;
302 
303 	*cmd = z_shell_get_last_command(selected_cmd_get(sh), search_argc,
304 					*argv, complete_arg_idx,	d_entry,
305 					false);
306 
307 	/* if search_argc == 0 (empty command line) shell_get_last_command will
308 	 * return NULL tab is allowed, otherwise not.
309 	 */
310 	if ((*cmd == NULL) && (search_argc != 0)) {
311 		return false;
312 	}
313 
314 	return true;
315 }
316 
is_completion_candidate(const char * candidate,const char * str,size_t len)317 static inline bool is_completion_candidate(const char *candidate,
318 					   const char *str, size_t len)
319 {
320 	return (strncmp(candidate, str, len) == 0) ? true : false;
321 }
322 
find_completion_candidates(const struct shell * sh,const struct shell_static_entry * cmd,const char * incompl_cmd,size_t * first_idx,size_t * cnt,uint16_t * longest)323 static void find_completion_candidates(const struct shell *sh,
324 				       const struct shell_static_entry *cmd,
325 				       const char *incompl_cmd,
326 				       size_t *first_idx, size_t *cnt,
327 				       uint16_t *longest)
328 {
329 	const struct shell_static_entry *candidate;
330 	struct shell_static_entry dloc;
331 	size_t incompl_cmd_len;
332 	size_t idx = 0;
333 
334 	incompl_cmd_len = z_shell_strlen(incompl_cmd);
335 	*longest = 0U;
336 	*cnt = 0;
337 
338 	while ((candidate = z_shell_cmd_get(cmd, idx, &dloc)) != NULL) {
339 		bool is_candidate;
340 		is_candidate = is_completion_candidate(candidate->syntax,
341 						incompl_cmd, incompl_cmd_len);
342 		if (is_candidate) {
343 			*longest = Z_MAX(strlen(candidate->syntax), *longest);
344 			if (*cnt == 0) {
345 				*first_idx = idx;
346 			}
347 			(*cnt)++;
348 		}
349 
350 		idx++;
351 	}
352 }
353 
autocomplete(const struct shell * sh,const struct shell_static_entry * cmd,const char * arg,size_t subcmd_idx)354 static void autocomplete(const struct shell *sh,
355 			 const struct shell_static_entry *cmd,
356 			 const char *arg,
357 			 size_t subcmd_idx)
358 {
359 	const struct shell_static_entry *match;
360 	uint16_t cmd_len;
361 	uint16_t arg_len = z_shell_strlen(arg);
362 
363 	/* sh->ctx->active_cmd can be safely used outside of command context
364 	 * to save stack
365 	 */
366 	match = z_shell_cmd_get(cmd, subcmd_idx, &sh->ctx->active_cmd);
367 	__ASSERT_NO_MSG(match != NULL);
368 	cmd_len = z_shell_strlen(match->syntax);
369 
370 	if (!IS_ENABLED(CONFIG_SHELL_TAB_AUTOCOMPLETION)) {
371 		/* Add a space if the Tab button is pressed when command is
372 		 * complete.
373 		 */
374 		if (cmd_len == arg_len) {
375 			z_shell_op_char_insert(sh, ' ');
376 		}
377 		return;
378 	}
379 
380 	/* no exact match found */
381 	if (cmd_len != arg_len) {
382 		z_shell_op_completion_insert(sh,
383 					     match->syntax + arg_len,
384 					     cmd_len - arg_len);
385 	}
386 
387 	/* Next character in the buffer is not 'space'. */
388 	if (isspace((int) sh->ctx->cmd_buff[
389 					sh->ctx->cmd_buff_pos]) == 0) {
390 		if (z_flag_insert_mode_get(sh)) {
391 			z_flag_insert_mode_set(sh, false);
392 			z_shell_op_char_insert(sh, ' ');
393 			z_flag_insert_mode_set(sh, true);
394 		} else {
395 			z_shell_op_char_insert(sh, ' ');
396 		}
397 	} else {
398 		/*  case:
399 		 * | | -> cursor
400 		 * cons_name $: valid_cmd valid_sub_cmd| |argument  <tab>
401 		 */
402 		z_shell_op_cursor_move(sh, 1);
403 		/* result:
404 		 * cons_name $: valid_cmd valid_sub_cmd |a|rgument
405 		 */
406 	}
407 }
408 
str_common(const char * s1,const char * s2,size_t n)409 static size_t str_common(const char *s1, const char *s2, size_t n)
410 {
411 	size_t common = 0;
412 
413 	while ((n > 0) && (*s1 == *s2) && (*s1 != '\0')) {
414 		s1++;
415 		s2++;
416 		n--;
417 		common++;
418 	}
419 
420 	return common;
421 }
422 
tab_options_print(const struct shell * sh,const struct shell_static_entry * cmd,const char * str,size_t first,size_t cnt,uint16_t longest)423 static void tab_options_print(const struct shell *sh,
424 			      const struct shell_static_entry *cmd,
425 			      const char *str, size_t first, size_t cnt,
426 			      uint16_t longest)
427 {
428 	const struct shell_static_entry *match;
429 	size_t str_len = z_shell_strlen(str);
430 	size_t idx = first;
431 
432 	/* Printing all matching commands (options). */
433 	tab_item_print(sh, SHELL_INIT_OPTION_PRINTER, longest);
434 
435 	while (cnt) {
436 		/* sh->ctx->active_cmd can be safely used outside of command
437 		 * context to save stack
438 		 */
439 		match = z_shell_cmd_get(cmd, idx, &sh->ctx->active_cmd);
440 		__ASSERT_NO_MSG(match != NULL);
441 		idx++;
442 		if (str && match->syntax &&
443 		    !is_completion_candidate(match->syntax, str, str_len)) {
444 			continue;
445 		}
446 
447 		tab_item_print(sh, match->syntax, longest);
448 		cnt--;
449 	}
450 
451 	z_cursor_next_line_move(sh);
452 	z_shell_print_prompt_and_cmd(sh);
453 }
454 
common_beginning_find(const struct shell * sh,const struct shell_static_entry * cmd,const char ** str,size_t first,size_t cnt,uint16_t arg_len)455 static uint16_t common_beginning_find(const struct shell *sh,
456 				   const struct shell_static_entry *cmd,
457 				   const char **str,
458 				   size_t first, size_t cnt, uint16_t arg_len)
459 {
460 	struct shell_static_entry dynamic_entry;
461 	const struct shell_static_entry *match;
462 	uint16_t common = UINT16_MAX;
463 	size_t idx = first + 1;
464 
465 	__ASSERT_NO_MSG(cnt > 1);
466 
467 	match = z_shell_cmd_get(cmd, first, &dynamic_entry);
468 	__ASSERT_NO_MSG(match);
469 	strncpy(sh->ctx->temp_buff, match->syntax,
470 			sizeof(sh->ctx->temp_buff) - 1);
471 
472 	*str = match->syntax;
473 
474 	while (cnt > 1) {
475 		struct shell_static_entry dynamic_entry2;
476 		const struct shell_static_entry *match2;
477 		int curr_common;
478 
479 		match2 = z_shell_cmd_get(cmd, idx++, &dynamic_entry2);
480 		if (match2 == NULL) {
481 			break;
482 		}
483 
484 		curr_common = str_common(sh->ctx->temp_buff, match2->syntax,
485 					 UINT16_MAX);
486 		if ((arg_len == 0U) || (curr_common >= arg_len)) {
487 			--cnt;
488 			common = (curr_common < common) ? curr_common : common;
489 		}
490 	}
491 
492 	return common;
493 }
494 
partial_autocomplete(const struct shell * sh,const struct shell_static_entry * cmd,const char * arg,size_t first,size_t cnt)495 static void partial_autocomplete(const struct shell *sh,
496 				 const struct shell_static_entry *cmd,
497 				 const char *arg,
498 				 size_t first, size_t cnt)
499 {
500 	const char *completion;
501 	uint16_t arg_len = z_shell_strlen(arg);
502 	uint16_t common = common_beginning_find(sh, cmd, &completion, first,
503 					     cnt, arg_len);
504 
505 	if (!IS_ENABLED(CONFIG_SHELL_TAB_AUTOCOMPLETION)) {
506 		return;
507 	}
508 
509 	if (common) {
510 		z_shell_op_completion_insert(sh, &completion[arg_len],
511 					     common - arg_len);
512 	}
513 }
514 
exec_cmd(const struct shell * sh,size_t argc,const char ** argv,const struct shell_static_entry * help_entry)515 static int exec_cmd(const struct shell *sh, size_t argc, const char **argv,
516 		    const struct shell_static_entry *help_entry)
517 {
518 	int ret_val = 0;
519 
520 	if (sh->ctx->active_cmd.handler == NULL) {
521 		if ((help_entry != NULL) && IS_ENABLED(CONFIG_SHELL_HELP)) {
522 			if (help_entry->help == NULL) {
523 				return -ENOEXEC;
524 			}
525 			if (help_entry->help != sh->ctx->active_cmd.help) {
526 				sh->ctx->active_cmd = *help_entry;
527 			}
528 			shell_internal_help_print(sh);
529 			return SHELL_CMD_HELP_PRINTED;
530 		} else {
531 			z_shell_fprintf(sh, SHELL_ERROR,
532 					SHELL_MSG_SPECIFY_SUBCOMMAND);
533 			return -ENOEXEC;
534 		}
535 	}
536 
537 	if (sh->ctx->active_cmd.args.mandatory) {
538 		uint32_t mand = sh->ctx->active_cmd.args.mandatory;
539 		uint8_t opt8 = sh->ctx->active_cmd.args.optional;
540 		uint32_t opt = (opt8 == SHELL_OPT_ARG_CHECK_SKIP) ?
541 				UINT16_MAX : opt8;
542 		const bool in_range = IN_RANGE(argc, mand, mand + opt);
543 
544 		/* Check if argc is within allowed range */
545 		ret_val = cmd_precheck(sh, in_range);
546 	}
547 
548 	if (!ret_val) {
549 #if CONFIG_SHELL_GETOPT
550 		getopt_init();
551 #endif
552 
553 		z_flag_cmd_ctx_set(sh, true);
554 		/* Unlock thread mutex in case command would like to borrow
555 		 * shell context to other thread to avoid mutex deadlock.
556 		 */
557 		k_mutex_unlock(&sh->ctx->wr_mtx);
558 		ret_val = sh->ctx->active_cmd.handler(sh, argc,
559 							 (char **)argv);
560 		/* Bring back mutex to shell thread. */
561 		k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
562 		z_flag_cmd_ctx_set(sh, false);
563 	}
564 
565 	return ret_val;
566 }
567 
active_cmd_prepare(const struct shell_static_entry * entry,struct shell_static_entry * active_cmd,struct shell_static_entry * help_entry,size_t * lvl,size_t * handler_lvl,size_t * args_left)568 static void active_cmd_prepare(const struct shell_static_entry *entry,
569 				struct shell_static_entry *active_cmd,
570 				struct shell_static_entry *help_entry,
571 				size_t *lvl, size_t *handler_lvl,
572 				size_t *args_left)
573 {
574 	if (entry->handler) {
575 		*handler_lvl = *lvl;
576 		*active_cmd = *entry;
577 		/* If command is final handler and it has a raw optional argument,
578 		 * then set remaining arguments to mandatory - 1 so after processing mandatory
579 		 * args, handler is passed remaining raw string
580 		 */
581 		if ((entry->subcmd == NULL)
582 		    && entry->args.optional == SHELL_OPT_ARG_RAW) {
583 			*args_left = entry->args.mandatory - 1;
584 		}
585 	}
586 	if (entry->help) {
587 		*help_entry = *entry;
588 	}
589 }
590 
wildcard_check_report(const struct shell * sh,bool found,const struct shell_static_entry * entry)591 static bool wildcard_check_report(const struct shell *sh, bool found,
592 				  const struct shell_static_entry *entry)
593 {
594 	/* An error occurred, fnmatch  argument cannot be followed by argument
595 	 * with a handler to avoid multiple function calls.
596 	 */
597 	if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && found && entry->handler) {
598 		z_shell_op_cursor_end_move(sh);
599 		z_shell_op_cond_next_line(sh);
600 
601 		z_shell_fprintf(sh, SHELL_ERROR,
602 			"Error: requested multiple function executions\n");
603 		return false;
604 	}
605 
606 	return true;
607 }
608 
609 /* Function is analyzing the command buffer to find matching commands. Next, it
610  * invokes the  last recognized command which has a handler and passes the rest
611  * of command buffer as arguments.
612  *
613  * By default command buffer is parsed and spaces are treated by arguments
614  * separators. Complex arguments are provided in quotation marks with quotation
615  * marks escaped within the argument. Argument parser is removing quotation
616  * marks at argument boundary as well as escape characters within the argument.
617  * However, it is possible to indicate that command shall treat remaining part
618  * of command buffer as the last argument without parsing. This can be used for
619  * commands which expects whole command buffer to be passed directly to
620  * the command handler without any preprocessing.
621  * Because of that feature, command buffer is processed argument by argument and
622  * decision on further processing is based on currently processed command.
623  */
execute(const struct shell * sh)624 static int execute(const struct shell *sh)
625 {
626 	struct shell_static_entry dloc; /* Memory for dynamic commands. */
627 	const char *argv[CONFIG_SHELL_ARGC_MAX + 1] = {0}; /* +1 reserved for NULL */
628 	const struct shell_static_entry *parent = selected_cmd_get(sh);
629 	const struct shell_static_entry *entry = NULL;
630 	struct shell_static_entry help_entry;
631 	size_t cmd_lvl = 0;
632 	size_t cmd_with_handler_lvl = 0;
633 	bool wildcard_found = false;
634 	size_t argc = 0, args_left = SIZE_MAX;
635 	char quote;
636 	const char **argvp;
637 	char *cmd_buf = sh->ctx->cmd_buff;
638 	bool has_last_handler = false;
639 
640 	z_shell_op_cursor_end_move(sh);
641 	if (!z_shell_cursor_in_empty_line(sh)) {
642 		z_cursor_next_line_move(sh);
643 	}
644 
645 	memset(&sh->ctx->active_cmd, 0, sizeof(sh->ctx->active_cmd));
646 
647 	if (IS_ENABLED(CONFIG_SHELL_HISTORY)) {
648 		z_shell_cmd_trim(sh);
649 		history_put(sh, sh->ctx->cmd_buff,
650 			    sh->ctx->cmd_buff_len);
651 	}
652 
653 	if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) {
654 		z_shell_wildcard_prepare(sh);
655 	}
656 
657 	/* Parent present means we are in select mode. */
658 	if (parent != NULL) {
659 		argv[0] = parent->syntax;
660 		argv[1] = cmd_buf;
661 		argvp = &argv[1];
662 		active_cmd_prepare(parent, &sh->ctx->active_cmd, &help_entry,
663 				   &cmd_lvl, &cmd_with_handler_lvl, &args_left);
664 		cmd_lvl++;
665 	} else {
666 		help_entry.help = NULL;
667 		argvp = &argv[0];
668 	}
669 
670 	/* Below loop is analyzing subcommands of found root command. */
671 	while ((argc != 1) && (cmd_lvl < CONFIG_SHELL_ARGC_MAX)
672 		&& args_left > 0) {
673 		quote = z_shell_make_argv(&argc, argvp, cmd_buf, 2);
674 		cmd_buf = (char *)argvp[1];
675 
676 		if (argc == 0) {
677 			return -ENOEXEC;
678 		} else if ((argc == 1) && (quote != 0)) {
679 			z_shell_fprintf(sh, SHELL_ERROR,
680 					"not terminated: %c\n", quote);
681 			return -ENOEXEC;
682 		}
683 
684 		if (IS_ENABLED(CONFIG_SHELL_HELP) && (cmd_lvl > 0) &&
685 		    z_shell_help_request(argvp[0])) {
686 			/* Command called with help option so it makes no sense
687 			 * to search deeper commands.
688 			 */
689 			if (help_entry.help) {
690 				sh->ctx->active_cmd = help_entry;
691 				shell_internal_help_print(sh);
692 				return SHELL_CMD_HELP_PRINTED;
693 			}
694 
695 			z_shell_fprintf(sh, SHELL_ERROR,
696 					SHELL_MSG_SPECIFY_SUBCOMMAND);
697 			return -ENOEXEC;
698 		}
699 
700 		if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && (cmd_lvl > 0)) {
701 			enum shell_wildcard_status status;
702 
703 			status = z_shell_wildcard_process(sh, entry,
704 							  argvp[0]);
705 			/* Wildcard character found but there is no matching
706 			 * command.
707 			 */
708 			if (status == SHELL_WILDCARD_CMD_NO_MATCH_FOUND) {
709 				break;
710 			}
711 
712 			/* Wildcard character was not found function can process
713 			 * argument.
714 			 */
715 			if (status != SHELL_WILDCARD_NOT_FOUND) {
716 				++cmd_lvl;
717 				wildcard_found = true;
718 				continue;
719 			}
720 		}
721 
722 		if (has_last_handler == false) {
723 			entry = z_shell_find_cmd(parent, argvp[0], &dloc);
724 		}
725 
726 		argvp++;
727 		args_left--;
728 		if (entry) {
729 			if (wildcard_check_report(sh, wildcard_found, entry)
730 				== false) {
731 				return -ENOEXEC;
732 			}
733 
734 			active_cmd_prepare(entry, &sh->ctx->active_cmd,
735 					  &help_entry, &cmd_lvl,
736 					  &cmd_with_handler_lvl, &args_left);
737 			parent = entry;
738 		} else {
739 			if (cmd_lvl == 0 &&
740 				(!z_shell_in_select_mode(sh) ||
741 				 sh->ctx->selected_cmd->handler == NULL)) {
742 				z_shell_fprintf(sh, SHELL_ERROR,
743 						"%s%s\n", argv[0],
744 						SHELL_MSG_CMD_NOT_FOUND);
745 			}
746 
747 			/* last handler found - no need to search commands in
748 			 * the next iteration.
749 			 */
750 			has_last_handler = true;
751 		}
752 
753 		if (args_left || (argc == 2)) {
754 			cmd_lvl++;
755 		}
756 
757 	}
758 
759 	if ((cmd_lvl >= CONFIG_SHELL_ARGC_MAX) && (argc == 2)) {
760 		/* argc == 2 indicates that when command string was parsed
761 		 * there was more characters remaining. It means that number of
762 		 * arguments exceeds the limit.
763 		 */
764 		z_shell_fprintf(sh, SHELL_ERROR, "%s\n",
765 				SHELL_MSG_TOO_MANY_ARGS);
766 		return -ENOEXEC;
767 	}
768 
769 	if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && wildcard_found) {
770 		z_shell_wildcard_finalize(sh);
771 		/* cmd_buffer has been overwritten by function finalize function
772 		 * with all expanded commands. Hence shell_make_argv needs to
773 		 * be called again.
774 		 */
775 		(void)z_shell_make_argv(&cmd_lvl,
776 					&argv[selected_cmd_get(sh) ? 1 : 0],
777 					sh->ctx->cmd_buff,
778 					CONFIG_SHELL_ARGC_MAX);
779 
780 		if (selected_cmd_get(sh)) {
781 			/* Apart from what is in the command buffer, there is
782 			 * a selected command.
783 			 */
784 			cmd_lvl++;
785 		}
786 	}
787 
788 	/* If a command was found */
789 	if (parent != NULL) {
790 		/* If the found command uses a raw optional argument and
791 		 * we have a remaining unprocessed non-null string,
792 		 * then increment command level so handler receives raw string
793 		 */
794 		if (parent->args.optional == SHELL_OPT_ARG_RAW && argv[cmd_lvl] != NULL) {
795 			cmd_lvl++;
796 		}
797 	}
798 
799 	/* Executing the deepest found handler. */
800 	return exec_cmd(sh, cmd_lvl - cmd_with_handler_lvl,
801 			&argv[cmd_with_handler_lvl], &help_entry);
802 }
803 
tab_handle(const struct shell * sh)804 static void tab_handle(const struct shell *sh)
805 {
806 	const char *__argv[CONFIG_SHELL_ARGC_MAX + 1];
807 	/* d_entry - placeholder for dynamic command */
808 	struct shell_static_entry d_entry;
809 	const struct shell_static_entry *cmd;
810 	const char **argv = __argv;
811 	size_t first = 0;
812 	size_t arg_idx;
813 	uint16_t longest;
814 	size_t argc;
815 	size_t cnt;
816 
817 	bool tab_possible = tab_prepare(sh, &cmd, &argv, &argc, &arg_idx,
818 					&d_entry);
819 
820 	if (tab_possible == false) {
821 		return;
822 	}
823 
824 	find_completion_candidates(sh, cmd, argv[arg_idx], &first, &cnt,
825 				   &longest);
826 
827 	if (cnt == 1) {
828 		/* Autocompletion.*/
829 		autocomplete(sh, cmd, argv[arg_idx], first);
830 	} else if (cnt > 1) {
831 		tab_options_print(sh, cmd, argv[arg_idx], first, cnt,
832 				  longest);
833 		partial_autocomplete(sh, cmd, argv[arg_idx], first, cnt);
834 	}
835 }
836 
alt_metakeys_handle(const struct shell * sh,char data)837 static void alt_metakeys_handle(const struct shell *sh, char data)
838 {
839 	/* Optional feature */
840 	if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) {
841 		return;
842 	}
843 	if (data == SHELL_VT100_ASCII_ALT_B) {
844 		z_shell_op_cursor_word_move(sh, -1);
845 	} else if (data == SHELL_VT100_ASCII_ALT_F) {
846 		z_shell_op_cursor_word_move(sh, 1);
847 	} else if (data == SHELL_VT100_ASCII_ALT_R &&
848 		   IS_ENABLED(CONFIG_SHELL_CMDS_SELECT)) {
849 		if (selected_cmd_get(sh) != NULL) {
850 			z_shell_cmd_line_erase(sh);
851 			z_shell_fprintf(sh, SHELL_WARNING,
852 					"Restored default root commands\n");
853 			if (CONFIG_SHELL_CMD_ROOT[0]) {
854 				sh->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
855 			} else {
856 				sh->ctx->selected_cmd = NULL;
857 			}
858 			z_shell_print_prompt_and_cmd(sh);
859 		}
860 	}
861 }
862 
ctrl_metakeys_handle(const struct shell * sh,char data)863 static void ctrl_metakeys_handle(const struct shell *sh, char data)
864 {
865 	/* Optional feature */
866 	if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) {
867 		return;
868 	}
869 
870 	switch (data) {
871 	case SHELL_VT100_ASCII_CTRL_A: /* CTRL + A */
872 		z_shell_op_cursor_home_move(sh);
873 		break;
874 
875 	case SHELL_VT100_ASCII_CTRL_B: /* CTRL + B */
876 		z_shell_op_left_arrow(sh);
877 		break;
878 
879 	case SHELL_VT100_ASCII_CTRL_C: /* CTRL + C */
880 		z_shell_op_cursor_end_move(sh);
881 		if (!z_shell_cursor_in_empty_line(sh)) {
882 			z_cursor_next_line_move(sh);
883 		}
884 		z_flag_history_exit_set(sh, true);
885 		state_set(sh, SHELL_STATE_ACTIVE);
886 		break;
887 
888 	case SHELL_VT100_ASCII_CTRL_D: /* CTRL + D */
889 		z_shell_op_char_delete(sh);
890 		break;
891 
892 	case SHELL_VT100_ASCII_CTRL_E: /* CTRL + E */
893 		z_shell_op_cursor_end_move(sh);
894 		break;
895 
896 	case SHELL_VT100_ASCII_CTRL_F: /* CTRL + F */
897 		z_shell_op_right_arrow(sh);
898 		break;
899 
900 	case SHELL_VT100_ASCII_CTRL_K: /* CTRL + K */
901 		z_shell_op_delete_from_cursor(sh);
902 		break;
903 
904 	case SHELL_VT100_ASCII_CTRL_L: /* CTRL + L */
905 		Z_SHELL_VT100_CMD(sh, SHELL_VT100_CURSORHOME);
906 		Z_SHELL_VT100_CMD(sh, SHELL_VT100_CLEARSCREEN);
907 		z_shell_print_prompt_and_cmd(sh);
908 		break;
909 
910 	case SHELL_VT100_ASCII_CTRL_N: /* CTRL + N */
911 		history_handle(sh, false);
912 		break;
913 
914 	case SHELL_VT100_ASCII_CTRL_P: /* CTRL + P */
915 		history_handle(sh, true);
916 		break;
917 
918 	case SHELL_VT100_ASCII_CTRL_U: /* CTRL + U */
919 		z_shell_op_cursor_home_move(sh);
920 		cmd_buffer_clear(sh);
921 		z_flag_history_exit_set(sh, true);
922 		z_clear_eos(sh);
923 		break;
924 
925 	case SHELL_VT100_ASCII_CTRL_W: /* CTRL + W */
926 		z_shell_op_word_remove(sh);
927 		z_flag_history_exit_set(sh, true);
928 		break;
929 
930 	default:
931 		break;
932 	}
933 }
934 
935 /* Functions returns true if new line character shall be processed */
process_nl(const struct shell * sh,uint8_t data)936 static bool process_nl(const struct shell *sh, uint8_t data)
937 {
938 	if ((data != '\r') && (data != '\n')) {
939 		z_flag_last_nl_set(sh, 0);
940 		return false;
941 	}
942 
943 	if ((z_flag_last_nl_get(sh) == 0U) ||
944 	    (data == z_flag_last_nl_get(sh))) {
945 		z_flag_last_nl_set(sh, data);
946 		return true;
947 	}
948 
949 	return false;
950 }
951 
952 #define SHELL_ASCII_MAX_CHAR (127u)
ascii_filter(const char data)953 static inline int ascii_filter(const char data)
954 {
955 	if (IS_ENABLED(CONFIG_SHELL_ASCII_FILTER)) {
956 		return (uint8_t) data > SHELL_ASCII_MAX_CHAR ? -EINVAL : 0;
957 	} else {
958 		return 0;
959 	}
960 }
961 
state_collect(const struct shell * sh)962 static void state_collect(const struct shell *sh)
963 {
964 	size_t count = 0;
965 	char data;
966 
967 	while (true) {
968 		shell_bypass_cb_t bypass = sh->ctx->bypass;
969 
970 		if (bypass) {
971 			uint8_t buf[16];
972 
973 			(void)sh->iface->api->read(sh->iface, buf,
974 							sizeof(buf), &count);
975 			if (count) {
976 				z_flag_cmd_ctx_set(sh, true);
977 				bypass(sh, buf, count);
978 				z_flag_cmd_ctx_set(sh, false);
979 				/* Check if bypass mode ended. */
980 				if (!(volatile shell_bypass_cb_t *)sh->ctx->bypass) {
981 					state_set(sh, SHELL_STATE_ACTIVE);
982 				} else {
983 					continue;
984 				}
985 			}
986 
987 			return;
988 		}
989 
990 		(void)sh->iface->api->read(sh->iface, &data,
991 					      sizeof(data), &count);
992 		if (count == 0) {
993 			return;
994 		}
995 
996 		if (ascii_filter(data) != 0) {
997 			continue;
998 		}
999 
1000 		switch (sh->ctx->receive_state) {
1001 		case SHELL_RECEIVE_DEFAULT:
1002 			if (process_nl(sh, data)) {
1003 				if (!sh->ctx->cmd_buff_len) {
1004 					history_mode_exit(sh);
1005 					z_cursor_next_line_move(sh);
1006 				} else {
1007 					/* Command execution */
1008 					sh->ctx->ret_val = execute(sh);
1009 				}
1010 				/* Function responsible for printing prompt
1011 				 * on received NL.
1012 				 */
1013 				state_set(sh, SHELL_STATE_ACTIVE);
1014 				continue;
1015 			}
1016 
1017 			switch (data) {
1018 			case SHELL_VT100_ASCII_ESC: /* ESCAPE */
1019 				receive_state_change(sh, SHELL_RECEIVE_ESC);
1020 				break;
1021 
1022 			case '\0':
1023 				break;
1024 
1025 			case '\t': /* TAB */
1026 				if (z_flag_echo_get(sh) &&
1027 				    IS_ENABLED(CONFIG_SHELL_TAB)) {
1028 					/* If the Tab key is pressed, "history
1029 					 * mode" must be terminated because
1030 					 * tab and history handlers are sharing
1031 					 * the same array: temp_buff.
1032 					 */
1033 					z_flag_history_exit_set(sh, true);
1034 					tab_handle(sh);
1035 				}
1036 				break;
1037 
1038 			case SHELL_VT100_ASCII_BSPACE: /* BACKSPACE */
1039 				if (z_flag_echo_get(sh)) {
1040 					z_flag_history_exit_set(sh, true);
1041 					z_shell_op_char_backspace(sh);
1042 				}
1043 				break;
1044 
1045 			case SHELL_VT100_ASCII_DEL: /* DELETE */
1046 				if (z_flag_echo_get(sh)) {
1047 					z_flag_history_exit_set(sh, true);
1048 					if (z_flag_mode_delete_get(sh)) {
1049 						z_shell_op_char_backspace(sh);
1050 
1051 					} else {
1052 						z_shell_op_char_delete(sh);
1053 					}
1054 				}
1055 				break;
1056 
1057 			default:
1058 				if (isprint((int) data) != 0) {
1059 					z_flag_history_exit_set(sh, true);
1060 					z_shell_op_char_insert(sh, data);
1061 				} else if (z_flag_echo_get(sh)) {
1062 					ctrl_metakeys_handle(sh, data);
1063 				}
1064 				break;
1065 			}
1066 			break;
1067 
1068 		case SHELL_RECEIVE_ESC:
1069 			if (data == '[') {
1070 				receive_state_change(sh,
1071 						SHELL_RECEIVE_ESC_SEQ);
1072 				break;
1073 			} else if (z_flag_echo_get(sh)) {
1074 				alt_metakeys_handle(sh, data);
1075 			}
1076 			receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1077 			break;
1078 
1079 		case SHELL_RECEIVE_ESC_SEQ:
1080 			receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1081 
1082 			if (!z_flag_echo_get(sh)) {
1083 				continue;
1084 			}
1085 
1086 			switch (data) {
1087 			case 'A': /* UP arrow */
1088 				history_handle(sh, true);
1089 				break;
1090 
1091 			case 'B': /* DOWN arrow */
1092 				history_handle(sh, false);
1093 				break;
1094 
1095 			case 'C': /* RIGHT arrow */
1096 				z_shell_op_right_arrow(sh);
1097 				break;
1098 
1099 			case 'D': /* LEFT arrow */
1100 				z_shell_op_left_arrow(sh);
1101 				break;
1102 
1103 			case '4': /* END Button in ESC[n~ mode */
1104 				receive_state_change(sh,
1105 						SHELL_RECEIVE_TILDE_EXP);
1106 				__fallthrough;
1107 			case 'F': /* END Button in VT100 mode */
1108 				z_shell_op_cursor_end_move(sh);
1109 				break;
1110 
1111 			case '1': /* HOME Button in ESC[n~ mode */
1112 				receive_state_change(sh,
1113 						SHELL_RECEIVE_TILDE_EXP);
1114 				__fallthrough;
1115 			case 'H': /* HOME Button in VT100 mode */
1116 				z_shell_op_cursor_home_move(sh);
1117 				break;
1118 
1119 			case '2': /* INSERT Button in ESC[n~ mode */
1120 				receive_state_change(sh,
1121 						SHELL_RECEIVE_TILDE_EXP);
1122 				__fallthrough;
1123 			case 'L': {/* INSERT Button in VT100 mode */
1124 				bool status = z_flag_insert_mode_get(sh);
1125 
1126 				z_flag_insert_mode_set(sh, !status);
1127 				break;
1128 			}
1129 
1130 			case '3':/* DELETE Button in ESC[n~ mode */
1131 				receive_state_change(sh,
1132 						SHELL_RECEIVE_TILDE_EXP);
1133 				if (z_flag_echo_get(sh)) {
1134 					z_shell_op_char_delete(sh);
1135 				}
1136 				break;
1137 
1138 			default:
1139 				break;
1140 			}
1141 			break;
1142 
1143 		case SHELL_RECEIVE_TILDE_EXP:
1144 			receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1145 			break;
1146 
1147 		default:
1148 			receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1149 			break;
1150 		}
1151 	}
1152 
1153 	z_transport_buffer_flush(sh);
1154 }
1155 
transport_evt_handler(enum shell_transport_evt evt_type,void * ctx)1156 static void transport_evt_handler(enum shell_transport_evt evt_type, void *ctx)
1157 {
1158 	struct shell *sh = (struct shell *)ctx;
1159 	struct k_poll_signal *signal;
1160 
1161 	signal = (evt_type == SHELL_TRANSPORT_EVT_RX_RDY) ?
1162 			&sh->ctx->signals[SHELL_SIGNAL_RXRDY] :
1163 			&sh->ctx->signals[SHELL_SIGNAL_TXDONE];
1164 	k_poll_signal_raise(signal, 0);
1165 }
1166 
shell_log_process(const struct shell * sh)1167 static void shell_log_process(const struct shell *sh)
1168 {
1169 	bool processed = false;
1170 	int signaled = 0;
1171 	int result;
1172 
1173 	do {
1174 		if (!IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
1175 			z_shell_cmd_line_erase(sh);
1176 
1177 			processed = z_shell_log_backend_process(
1178 					sh->log_backend);
1179 		}
1180 
1181 		struct k_poll_signal *signal =
1182 			&sh->ctx->signals[SHELL_SIGNAL_RXRDY];
1183 
1184 		z_shell_print_prompt_and_cmd(sh);
1185 
1186 		/* Arbitrary delay added to ensure that prompt is
1187 		 * readable and can be used to enter further commands.
1188 		 */
1189 		if (sh->ctx->cmd_buff_len) {
1190 			k_sleep(K_MSEC(15));
1191 		}
1192 
1193 		k_poll_signal_check(signal, &signaled, &result);
1194 
1195 	} while (processed && !signaled);
1196 }
1197 
instance_init(const struct shell * sh,const void * transport_config,struct shell_backend_config_flags cfg_flags)1198 static int instance_init(const struct shell *sh,
1199 			 const void *transport_config,
1200 			 struct shell_backend_config_flags cfg_flags)
1201 {
1202 	__ASSERT_NO_MSG((sh->shell_flag == SHELL_FLAG_CRLF_DEFAULT) ||
1203 			(sh->shell_flag == SHELL_FLAG_OLF_CRLF));
1204 
1205 	memset(sh->ctx, 0, sizeof(*sh->ctx));
1206 	sh->ctx->prompt = sh->default_prompt;
1207 	if (CONFIG_SHELL_CMD_ROOT[0]) {
1208 		sh->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
1209 	}
1210 
1211 	history_init(sh);
1212 
1213 	k_mutex_init(&sh->ctx->wr_mtx);
1214 
1215 	for (int i = 0; i < SHELL_SIGNALS; i++) {
1216 		k_poll_signal_init(&sh->ctx->signals[i]);
1217 		k_poll_event_init(&sh->ctx->events[i],
1218 				  K_POLL_TYPE_SIGNAL,
1219 				  K_POLL_MODE_NOTIFY_ONLY,
1220 				  &sh->ctx->signals[i]);
1221 	}
1222 
1223 	if (IS_ENABLED(CONFIG_SHELL_STATS)) {
1224 		sh->stats->log_lost_cnt = 0;
1225 	}
1226 
1227 	z_flag_tx_rdy_set(sh, true);
1228 
1229 	sh->ctx->vt100_ctx.cons.terminal_wid =
1230 					CONFIG_SHELL_DEFAULT_TERMINAL_WIDTH;
1231 	sh->ctx->vt100_ctx.cons.terminal_hei =
1232 					CONFIG_SHELL_DEFAULT_TERMINAL_HEIGHT;
1233 	sh->ctx->vt100_ctx.cons.name_len = z_shell_strlen(sh->ctx->prompt);
1234 
1235 	/* Configure backend according to enabled shell features and backend
1236 	 * specific settings.
1237 	 */
1238 	cfg_flags.obscure     &= IS_ENABLED(CONFIG_SHELL_START_OBSCURED);
1239 	cfg_flags.use_colors  &= IS_ENABLED(CONFIG_SHELL_VT100_COLORS);
1240 	cfg_flags.use_vt100   &= IS_ENABLED(CONFIG_SHELL_VT100_COMMANDS);
1241 	cfg_flags.echo        &= IS_ENABLED(CONFIG_SHELL_ECHO_STATUS);
1242 	cfg_flags.mode_delete &= IS_ENABLED(CONFIG_SHELL_BACKSPACE_MODE_DELETE);
1243 	sh->ctx->cfg.flags = cfg_flags;
1244 
1245 	int ret = sh->iface->api->init(sh->iface, transport_config,
1246 				       transport_evt_handler,
1247 				       (void *)sh);
1248 	if (ret == 0) {
1249 		state_set(sh, SHELL_STATE_INITIALIZED);
1250 	}
1251 
1252 	return ret;
1253 }
1254 
instance_uninit(const struct shell * sh)1255 static int instance_uninit(const struct shell *sh)
1256 {
1257 	__ASSERT_NO_MSG(sh);
1258 	__ASSERT_NO_MSG(sh->ctx && sh->iface);
1259 
1260 	int err;
1261 
1262 	if (z_flag_processing_get(sh)) {
1263 		return -EBUSY;
1264 	}
1265 
1266 	if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
1267 		/* todo purge log queue */
1268 		z_shell_log_backend_disable(sh->log_backend);
1269 	}
1270 
1271 	err = sh->iface->api->uninit(sh->iface);
1272 	if (err != 0) {
1273 		return err;
1274 	}
1275 
1276 	history_purge(sh);
1277 	state_set(sh, SHELL_STATE_UNINITIALIZED);
1278 
1279 	return 0;
1280 }
1281 
1282 typedef void (*shell_signal_handler_t)(const struct shell *sh);
1283 
shell_signal_handle(const struct shell * sh,enum shell_signal sig_idx,shell_signal_handler_t handler)1284 static void shell_signal_handle(const struct shell *sh,
1285 				enum shell_signal sig_idx,
1286 				shell_signal_handler_t handler)
1287 {
1288 	struct k_poll_signal *sig = &sh->ctx->signals[sig_idx];
1289 	int set;
1290 	int res;
1291 
1292 	k_poll_signal_check(sig, &set, &res);
1293 
1294 	if (set) {
1295 		k_poll_signal_reset(sig);
1296 		handler(sh);
1297 	}
1298 }
1299 
kill_handler(const struct shell * sh)1300 static void kill_handler(const struct shell *sh)
1301 {
1302 	int err = instance_uninit(sh);
1303 
1304 	if (sh->ctx->uninit_cb) {
1305 		sh->ctx->uninit_cb(sh, err);
1306 	}
1307 
1308 	sh->ctx->tid = NULL;
1309 	k_thread_abort(k_current_get());
1310 }
1311 
shell_thread(void * shell_handle,void * arg_log_backend,void * arg_log_level)1312 void shell_thread(void *shell_handle, void *arg_log_backend,
1313 		  void *arg_log_level)
1314 {
1315 	struct shell *sh = shell_handle;
1316 	bool log_backend = (bool)arg_log_backend;
1317 	uint32_t log_level = POINTER_TO_UINT(arg_log_level);
1318 	int err;
1319 
1320 	err = sh->iface->api->enable(sh->iface, false);
1321 	if (err != 0) {
1322 		return;
1323 	}
1324 
1325 	if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND) && log_backend
1326 	    && !IS_ENABLED(CONFIG_SHELL_START_OBSCURED)) {
1327 		z_shell_log_backend_enable(sh->log_backend, (void *)sh,
1328 					   log_level);
1329 	}
1330 
1331 	if (IS_ENABLED(CONFIG_SHELL_AUTOSTART)) {
1332 		/* Enable shell and print prompt. */
1333 		err = shell_start(sh);
1334 		if (err != 0) {
1335 			return;
1336 		}
1337 	}
1338 
1339 	while (true) {
1340 		/* waiting for all signals except SHELL_SIGNAL_TXDONE */
1341 		err = k_poll(sh->ctx->events, SHELL_SIGNAL_TXDONE,
1342 			     K_FOREVER);
1343 
1344 		if (err != 0) {
1345 			k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1346 			z_shell_fprintf(sh, SHELL_ERROR,
1347 					"Shell thread error: %d", err);
1348 			k_mutex_unlock(&sh->ctx->wr_mtx);
1349 			return;
1350 		}
1351 
1352 		k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1353 
1354 		shell_signal_handle(sh, SHELL_SIGNAL_KILL, kill_handler);
1355 		shell_signal_handle(sh, SHELL_SIGNAL_RXRDY, shell_process);
1356 		if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
1357 			shell_signal_handle(sh, SHELL_SIGNAL_LOG_MSG,
1358 					    shell_log_process);
1359 		}
1360 
1361 		if (sh->iface->api->update) {
1362 			sh->iface->api->update(sh->iface);
1363 		}
1364 
1365 		k_mutex_unlock(&sh->ctx->wr_mtx);
1366 	}
1367 }
1368 
shell_init(const struct shell * sh,const void * transport_config,struct shell_backend_config_flags cfg_flags,bool log_backend,uint32_t init_log_level)1369 int shell_init(const struct shell *sh, const void *transport_config,
1370 	       struct shell_backend_config_flags cfg_flags,
1371 	       bool log_backend, uint32_t init_log_level)
1372 {
1373 	__ASSERT_NO_MSG(sh);
1374 	__ASSERT_NO_MSG(sh->ctx && sh->iface && sh->default_prompt);
1375 
1376 	if (sh->ctx->tid) {
1377 		return -EALREADY;
1378 	}
1379 
1380 	int err = instance_init(sh, transport_config, cfg_flags);
1381 
1382 	if (err != 0) {
1383 		return err;
1384 	}
1385 
1386 	k_tid_t tid = k_thread_create(sh->thread,
1387 				  sh->stack, CONFIG_SHELL_STACK_SIZE,
1388 				  shell_thread, (void *)sh, (void *)log_backend,
1389 				  UINT_TO_POINTER(init_log_level),
1390 				  SHELL_THREAD_PRIORITY, 0, K_NO_WAIT);
1391 
1392 	sh->ctx->tid = tid;
1393 	k_thread_name_set(tid, sh->thread_name);
1394 
1395 	return 0;
1396 }
1397 
shell_uninit(const struct shell * sh,shell_uninit_cb_t cb)1398 void shell_uninit(const struct shell *sh, shell_uninit_cb_t cb)
1399 {
1400 	__ASSERT_NO_MSG(sh);
1401 
1402 	if (IS_ENABLED(CONFIG_MULTITHREADING)) {
1403 		struct k_poll_signal *signal =
1404 				&sh->ctx->signals[SHELL_SIGNAL_KILL];
1405 
1406 		sh->ctx->uninit_cb = cb;
1407 		/* signal kill message */
1408 		(void)k_poll_signal_raise(signal, 0);
1409 
1410 		return;
1411 	}
1412 
1413 	int err = instance_uninit(sh);
1414 
1415 	if (cb) {
1416 		cb(sh, err);
1417 	} else {
1418 		__ASSERT_NO_MSG(0);
1419 	}
1420 }
1421 
shell_start(const struct shell * sh)1422 int shell_start(const struct shell *sh)
1423 {
1424 	__ASSERT_NO_MSG(sh);
1425 	__ASSERT_NO_MSG(sh->ctx && sh->iface && sh->default_prompt);
1426 
1427 	if (state_get(sh) != SHELL_STATE_INITIALIZED) {
1428 		return -ENOTSUP;
1429 	}
1430 
1431 	k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1432 
1433 	if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) {
1434 		z_shell_vt100_color_set(sh, SHELL_NORMAL);
1435 	}
1436 
1437 	if (z_shell_strlen(sh->default_prompt) > 0) {
1438 		z_shell_raw_fprintf(sh->fprintf_ctx, "\n\n");
1439 	}
1440 	state_set(sh, SHELL_STATE_ACTIVE);
1441 
1442 	k_mutex_unlock(&sh->ctx->wr_mtx);
1443 
1444 	return 0;
1445 }
1446 
shell_stop(const struct shell * sh)1447 int shell_stop(const struct shell *sh)
1448 {
1449 	__ASSERT_NO_MSG(sh);
1450 	__ASSERT_NO_MSG(sh->ctx);
1451 
1452 	enum shell_state state = state_get(sh);
1453 
1454 	if ((state == SHELL_STATE_INITIALIZED) ||
1455 	    (state == SHELL_STATE_UNINITIALIZED)) {
1456 		return -ENOTSUP;
1457 	}
1458 
1459 	state_set(sh, SHELL_STATE_INITIALIZED);
1460 
1461 	return 0;
1462 }
1463 
shell_process(const struct shell * sh)1464 void shell_process(const struct shell *sh)
1465 {
1466 	__ASSERT_NO_MSG(sh);
1467 	__ASSERT_NO_MSG(sh->ctx);
1468 
1469 	/* atomically set the processing flag */
1470 	z_flag_processing_set(sh, true);
1471 
1472 	switch (sh->ctx->state) {
1473 	case SHELL_STATE_UNINITIALIZED:
1474 	case SHELL_STATE_INITIALIZED:
1475 		/* Console initialized but not started. */
1476 		break;
1477 
1478 	case SHELL_STATE_ACTIVE:
1479 		state_collect(sh);
1480 		break;
1481 	default:
1482 		break;
1483 	}
1484 
1485 	/* atomically clear the processing flag */
1486 	z_flag_processing_set(sh, false);
1487 }
1488 
1489 /* This function mustn't be used from shell context to avoid deadlock.
1490  * However it can be used in shell command handlers.
1491  */
shell_vfprintf(const struct shell * sh,enum shell_vt100_color color,const char * fmt,va_list args)1492 void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color,
1493 		   const char *fmt, va_list args)
1494 {
1495 	__ASSERT_NO_MSG(sh);
1496 	__ASSERT(!k_is_in_isr(), "Thread context required.");
1497 	__ASSERT_NO_MSG(sh->ctx);
1498 	__ASSERT_NO_MSG(z_flag_cmd_ctx_get(sh) ||
1499 			(k_current_get() != sh->ctx->tid));
1500 	__ASSERT_NO_MSG(sh->fprintf_ctx);
1501 	__ASSERT_NO_MSG(fmt);
1502 
1503 	/* Sending a message to a non-active shell leads to a dead lock. */
1504 	if (state_get(sh) != SHELL_STATE_ACTIVE) {
1505 		z_flag_print_noinit_set(sh, true);
1506 		return;
1507 	}
1508 
1509 	k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1510 	if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) {
1511 		z_shell_cmd_line_erase(sh);
1512 	}
1513 	z_shell_vfprintf(sh, color, fmt, args);
1514 	if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) {
1515 		z_shell_print_prompt_and_cmd(sh);
1516 	}
1517 	z_transport_buffer_flush(sh);
1518 	k_mutex_unlock(&sh->ctx->wr_mtx);
1519 }
1520 
1521 /* This function mustn't be used from shell context to avoid deadlock.
1522  * However it can be used in shell command handlers.
1523  */
shell_fprintf(const struct shell * sh,enum shell_vt100_color color,const char * fmt,...)1524 void shell_fprintf(const struct shell *sh, enum shell_vt100_color color,
1525 		   const char *fmt, ...)
1526 {
1527 	va_list args;
1528 
1529 	va_start(args, fmt);
1530 	shell_vfprintf(sh, color, fmt, args);
1531 	va_end(args);
1532 }
1533 
shell_hexdump_line(const struct shell * sh,unsigned int offset,const uint8_t * data,size_t len)1534 void shell_hexdump_line(const struct shell *sh, unsigned int offset,
1535 			const uint8_t *data, size_t len)
1536 {
1537 	__ASSERT_NO_MSG(sh);
1538 
1539 	int i;
1540 
1541 	shell_fprintf(sh, SHELL_NORMAL, "%08X: ", offset);
1542 
1543 	for (i = 0; i < SHELL_HEXDUMP_BYTES_IN_LINE; i++) {
1544 		if (i > 0 && !(i % 8)) {
1545 			shell_fprintf(sh, SHELL_NORMAL, " ");
1546 		}
1547 
1548 		if (i < len) {
1549 			shell_fprintf(sh, SHELL_NORMAL, "%02x ",
1550 				      data[i] & 0xFF);
1551 		} else {
1552 			shell_fprintf(sh, SHELL_NORMAL, "   ");
1553 		}
1554 	}
1555 
1556 	shell_fprintf(sh, SHELL_NORMAL, "|");
1557 
1558 	for (i = 0; i < SHELL_HEXDUMP_BYTES_IN_LINE; i++) {
1559 		if (i > 0 && !(i % 8)) {
1560 			shell_fprintf(sh, SHELL_NORMAL, " ");
1561 		}
1562 
1563 		if (i < len) {
1564 			char c = data[i];
1565 
1566 			shell_fprintf(sh, SHELL_NORMAL, "%c",
1567 				      isprint((int)c) != 0 ? c : '.');
1568 		} else {
1569 			shell_fprintf(sh, SHELL_NORMAL, " ");
1570 		}
1571 	}
1572 
1573 	shell_print(sh, "|");
1574 }
1575 
shell_hexdump(const struct shell * sh,const uint8_t * data,size_t len)1576 void shell_hexdump(const struct shell *sh, const uint8_t *data, size_t len)
1577 {
1578 	__ASSERT_NO_MSG(sh);
1579 
1580 	const uint8_t *p = data;
1581 	size_t line_len;
1582 
1583 	while (len) {
1584 		line_len = MIN(len, SHELL_HEXDUMP_BYTES_IN_LINE);
1585 
1586 		shell_hexdump_line(sh, p - data, p, line_len);
1587 
1588 		len -= line_len;
1589 		p += line_len;
1590 	}
1591 }
1592 
shell_prompt_change(const struct shell * sh,const char * prompt)1593 int shell_prompt_change(const struct shell *sh, const char *prompt)
1594 {
1595 	__ASSERT_NO_MSG(sh);
1596 
1597 	if (prompt == NULL) {
1598 		return -EINVAL;
1599 	}
1600 	sh->ctx->prompt = prompt;
1601 	sh->ctx->vt100_ctx.cons.name_len = z_shell_strlen(prompt);
1602 
1603 	return 0;
1604 }
1605 
shell_help(const struct shell * sh)1606 void shell_help(const struct shell *sh)
1607 {
1608 	k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1609 	shell_internal_help_print(sh);
1610 	k_mutex_unlock(&sh->ctx->wr_mtx);
1611 }
1612 
shell_execute_cmd(const struct shell * sh,const char * cmd)1613 int shell_execute_cmd(const struct shell *sh, const char *cmd)
1614 {
1615 	uint16_t cmd_len = z_shell_strlen(cmd);
1616 	int ret_val;
1617 
1618 	if (cmd == NULL) {
1619 		return -ENOEXEC;
1620 	}
1621 
1622 	if (cmd_len > (CONFIG_SHELL_CMD_BUFF_SIZE - 1)) {
1623 		return -ENOMEM;
1624 	}
1625 
1626 	if (sh == NULL) {
1627 #if defined(CONFIG_SHELL_BACKEND_DUMMY)
1628 		sh = shell_backend_dummy_get_ptr();
1629 #else
1630 		return -EINVAL;
1631 #endif
1632 	}
1633 
1634 	__ASSERT(!z_flag_cmd_ctx_get(sh), "Function cannot be called"
1635 					  " from command context");
1636 
1637 	strcpy(sh->ctx->cmd_buff, cmd);
1638 	sh->ctx->cmd_buff_len = cmd_len;
1639 	sh->ctx->cmd_buff_pos = cmd_len;
1640 
1641 	k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1642 	ret_val = execute(sh);
1643 	k_mutex_unlock(&sh->ctx->wr_mtx);
1644 
1645 	cmd_buffer_clear(sh);
1646 
1647 	return ret_val;
1648 }
1649 
shell_insert_mode_set(const struct shell * sh,bool val)1650 int shell_insert_mode_set(const struct shell *sh, bool val)
1651 {
1652 	if (sh == NULL) {
1653 		return -EINVAL;
1654 	}
1655 
1656 	return (int)z_flag_insert_mode_set(sh, val);
1657 }
1658 
shell_use_colors_set(const struct shell * sh,bool val)1659 int shell_use_colors_set(const struct shell *sh, bool val)
1660 {
1661 	if (sh == NULL) {
1662 		return -EINVAL;
1663 	}
1664 
1665 	return (int)z_flag_use_colors_set(sh, val);
1666 }
1667 
shell_use_vt100_set(const struct shell * sh,bool val)1668 int shell_use_vt100_set(const struct shell *sh, bool val)
1669 {
1670 	if (sh == NULL) {
1671 		return -EINVAL;
1672 	}
1673 
1674 	return (int)z_flag_use_vt100_set(sh, val);
1675 }
1676 
shell_get_return_value(const struct shell * sh)1677 int shell_get_return_value(const struct shell *sh)
1678 {
1679 	if (sh == NULL) {
1680 		return -EINVAL;
1681 	}
1682 
1683 	return z_shell_get_return_value(sh);
1684 }
1685 
shell_echo_set(const struct shell * sh,bool val)1686 int shell_echo_set(const struct shell *sh, bool val)
1687 {
1688 	if (sh == NULL) {
1689 		return -EINVAL;
1690 	}
1691 
1692 	return (int)z_flag_echo_set(sh, val);
1693 }
1694 
shell_obscure_set(const struct shell * sh,bool val)1695 int shell_obscure_set(const struct shell *sh, bool val)
1696 {
1697 	if (sh == NULL) {
1698 		return -EINVAL;
1699 	}
1700 
1701 	return (int)z_flag_obscure_set(sh, val);
1702 }
1703 
shell_mode_delete_set(const struct shell * sh,bool val)1704 int shell_mode_delete_set(const struct shell *sh, bool val)
1705 {
1706 	if (sh == NULL) {
1707 		return -EINVAL;
1708 	}
1709 
1710 	return (int)z_flag_mode_delete_set(sh, val);
1711 }
1712 
shell_set_bypass(const struct shell * sh,shell_bypass_cb_t bypass)1713 void shell_set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
1714 {
1715 	__ASSERT_NO_MSG(sh);
1716 
1717 	sh->ctx->bypass = bypass;
1718 
1719 	if (bypass == NULL) {
1720 		cmd_buffer_clear(sh);
1721 	}
1722 }
1723 
shell_ready(const struct shell * sh)1724 bool shell_ready(const struct shell *sh)
1725 {
1726 	__ASSERT_NO_MSG(sh);
1727 
1728 	return state_get(sh) ==	SHELL_STATE_ACTIVE;
1729 }
1730 
cmd_help(const struct shell * sh,size_t argc,char ** argv)1731 static int cmd_help(const struct shell *sh, size_t argc, char **argv)
1732 {
1733 	ARG_UNUSED(argc);
1734 	ARG_UNUSED(argv);
1735 
1736 #if defined(CONFIG_SHELL_TAB)
1737 	shell_print(sh, "Please press the <Tab> button to see all available "
1738 			   "commands.");
1739 #endif
1740 
1741 #if defined(CONFIG_SHELL_TAB_AUTOCOMPLETION)
1742 	shell_print(sh,
1743 		"You can also use the <Tab> button to prompt or auto-complete"
1744 		" all commands or its subcommands.");
1745 #endif
1746 
1747 #if defined(CONFIG_SHELL_HELP)
1748 	shell_print(sh,
1749 		"You can try to call commands with <-h> or <--help> parameter"
1750 		" for more information.");
1751 #endif
1752 
1753 #if defined(CONFIG_SHELL_METAKEYS)
1754 	shell_print(sh,
1755 		"\nShell supports following meta-keys:\n"
1756 		"  Ctrl + (a key from: abcdefklnpuw)\n"
1757 		"  Alt  + (a key from: bf)\n"
1758 		"Please refer to shell documentation for more details.");
1759 #endif
1760 
1761 	if (IS_ENABLED(CONFIG_SHELL_HELP)) {
1762 		/* For NULL argument function will print all root commands */
1763 		z_shell_help_subcmd_print(sh, NULL,
1764 					 "\nAvailable commands:\n");
1765 	} else {
1766 		const struct shell_static_entry *entry;
1767 		size_t idx = 0;
1768 
1769 		shell_print(sh, "\nAvailable commands:");
1770 		while ((entry = z_shell_cmd_get(NULL, idx++, NULL)) != NULL) {
1771 			shell_print(sh, "  %s", entry->syntax);
1772 		}
1773 	}
1774 
1775 	return 0;
1776 }
1777 
1778 SHELL_CMD_ARG_REGISTER(help, NULL, "Prints the help message.", cmd_help, 1, 0);
1779