1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/kernel.h>
7 #include <zephyr/shell/shell.h>
8 #if CONFIG_SHELL_GETOPT
9 #include <zephyr/sys/iterable_sections.h>
10 #endif
11 
12 #include <zephyr/sys/sys_getopt.h>
13 
14 /* Referring  below variables is not thread safe. They reflects getopt state
15  * only when 1 thread is using getopt.
16  * When more threads are using getopt please call getopt_state_get to know
17  * getopt state for the current thread.
18  */
19 int sys_getopt_opterr = 1; /* if error message should be printed */
20 int sys_getopt_optind = 1; /* index into parent argv vector */
21 int sys_getopt_optopt;     /* character checked for validity */
22 int sys_getopt_optreset;   /* reset getopt */
23 char *sys_getopt_optarg;   /* argument associated with option */
24 
25 /* Common state for all threads that did not have own getopt state. */
26 static struct sys_getopt_state m_getopt_common_state = {
27 	.opterr = 1,
28 	.optind = 1,
29 	.optopt = 0,
30 	.optreset = 0,
31 	.optarg = NULL,
32 
33 	.place = "", /* EMSG */
34 
35 #if CONFIG_GETOPT_LONG
36 	.nonopt_start = -1, /* first non option argument (for permute) */
37 	.nonopt_end = -1,   /* first option after non options (for permute) */
38 #endif
39 };
40 
41 /* Shim function to update global variables in getopt_shim.c if user wants to
42  * still use the original non-posix compliant getopt. The shim will be deprecated
43  * and eventually removed in the future.
44  */
45 extern void z_getopt_global_state_update_shim(struct sys_getopt_state *state);
46 
47 /* This function is not thread safe. All threads using getopt are calling
48  * this function.
49  */
z_getopt_global_state_update(struct sys_getopt_state * state)50 void z_getopt_global_state_update(struct sys_getopt_state *state)
51 {
52 	sys_getopt_opterr = state->opterr;
53 	sys_getopt_optind = state->optind;
54 	sys_getopt_optopt = state->optopt;
55 	sys_getopt_optreset = state->optreset;
56 	sys_getopt_optarg = state->optarg;
57 
58 	if (!IS_ENABLED(CONFIG_NATIVE_LIBC) && IS_ENABLED(CONFIG_POSIX_C_LIB_EXT)) {
59 		z_getopt_global_state_update_shim(state);
60 	}
61 }
62 
63 /* It is internal getopt API function, it shall not be called by the user. */
sys_getopt_state_get(void)64 struct sys_getopt_state *sys_getopt_state_get(void)
65 {
66 #if CONFIG_SHELL_GETOPT
67 	k_tid_t tid;
68 
69 	tid = k_current_get();
70 	STRUCT_SECTION_FOREACH(shell, sh) {
71 		if (tid == sh->ctx->tid) {
72 			return &sh->ctx->getopt;
73 		}
74 	}
75 #endif
76 	/* If not a shell thread return a common pointer */
77 	return &m_getopt_common_state;
78 }
79