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