1 /*
2  * Copyright (c) 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "cmdline_common.h"
11 #include <zephyr/types.h>
12 #include "hw_models_top.h"
13 #include "timer_model.h"
14 #include "cmdline.h"
15 #include <zephyr/toolchain.h>
16 #include <zephyr/arch/posix/posix_trace.h>
17 #include "native_tracing.h"
18 
19 static int s_argc, test_argc;
20 static char **s_argv, **test_argv;
21 
22 static struct args_struct_t *args_struct;
23 static int used_args;
24 static int args_aval;
25 #define ARGS_ALLOC_CHUNK_SIZE 20
26 
native_cleanup_cmd_line(void)27 void native_cleanup_cmd_line(void)
28 {
29 	if (args_struct != NULL) { /* LCOV_EXCL_BR_LINE */
30 		free(args_struct);
31 		args_struct = NULL;
32 	}
33 }
34 
35 /**
36  * Add a set of command line options to the program.
37  *
38  * Each option to be added is described in one entry of the input <args>
39  * This input must be terminated with an entry containing ARG_TABLE_ENDMARKER.
40  */
native_add_command_line_opts(struct args_struct_t * args)41 void native_add_command_line_opts(struct args_struct_t *args)
42 {
43 	int count = 0;
44 
45 	while (args[count].option != NULL) {
46 		count++;
47 	}
48 	count++; /*for the end marker*/
49 
50 	if (used_args + count >= args_aval) {
51 		int growby = count;
52 		/* reallocs are expensive let's do them only in big chunks */
53 		if (growby < ARGS_ALLOC_CHUNK_SIZE) {
54 			growby = ARGS_ALLOC_CHUNK_SIZE;
55 		}
56 
57 		struct args_struct_t *new_args_struct = realloc(args_struct,
58 				      (args_aval + growby)*
59 				      sizeof(struct args_struct_t));
60 		args_aval += growby;
61 		/* LCOV_EXCL_START */
62 		if (new_args_struct == NULL) {
63 			posix_print_error_and_exit("Could not allocate memory");
64 		} else {
65 			args_struct = new_args_struct;
66 		}
67 		/* LCOV_EXCL_STOP */
68 	}
69 
70 	memcpy(&args_struct[used_args], args,
71 		count*sizeof(struct args_struct_t));
72 
73 	used_args += count - 1;
74 	/*
75 	 * -1 as the end marker should be overwritten next time something
76 	 * is added
77 	 */
78 }
79 
native_add_testargs_option(void)80 void native_add_testargs_option(void)
81 {
82 	static struct args_struct_t testargs_options[] = {
83 		/*
84 		 * Fields:
85 		 * manual, mandatory, switch,
86 		 * option_name, var_name ,type,
87 		 * destination, callback,
88 		 * description
89 		 */
90 		{true, false, false,
91 		"testargs", "arg", 'l',
92 		(void *)NULL, NULL,
93 		"Any argument that follows will be ignored by the top level, "
94 		"and made available for possible tests"},
95 		ARG_TABLE_ENDMARKER};
96 
97 	native_add_command_line_opts(testargs_options);
98 }
99 
print_invalid_opt_error(char * argv)100 static void print_invalid_opt_error(char *argv)
101 {
102 	posix_print_error_and_exit("Incorrect option '%s'. Did you misspell it?"
103 				   " Is that feature supported in this build?"
104 				   "\n",
105 				   argv);
106 
107 }
108 
109 /**
110  * Handle possible command line arguments.
111  *
112  * We also store them for later use by possible test applications
113  */
native_handle_cmd_line(int argc,char * argv[])114 void native_handle_cmd_line(int argc, char *argv[])
115 {
116 	int i;
117 
118 	native_add_tracing_options();
119 	native_add_testargs_option();
120 
121 	s_argv = argv;
122 	s_argc = argc;
123 
124 	cmd_args_set_defaults(args_struct);
125 
126 	for (i = 1; i < argc; i++) {
127 
128 		if ((cmd_is_option(argv[i], "testargs", 0))) {
129 			test_argc = argc - i - 1;
130 			test_argv = &argv[i+1];
131 			break;
132 		}
133 
134 		if (!cmd_parse_one_arg(argv[i], args_struct)) {
135 			cmd_print_switches_help(args_struct);
136 			print_invalid_opt_error(argv[i]);
137 		}
138 	}
139 }
140 
141 /**
142  * The application/test can use this function to inspect all the command line
143  * arguments
144  */
native_get_cmd_line_args(int * argc,char *** argv)145 void native_get_cmd_line_args(int *argc, char ***argv)
146 {
147 	*argc = s_argc;
148 	*argv = s_argv;
149 }
150 
151 /**
152  * The application/test can use this function to inspect the command line
153  * arguments received after --testargs
154  */
native_get_test_cmd_line_args(int * argc,char *** argv)155 void native_get_test_cmd_line_args(int *argc, char ***argv)
156 {
157 	*argc = test_argc;
158 	*argv = test_argv;
159 }
160