| /* |
| * Copyright (c) 2018 Oticon A/S |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "nsi_cmdline.h" |
| #include "nsi_cmdline_internal.h" |
| #include "nsi_tracing.h" |
| #include "nsi_timer_model.h" |
| #include "nsi_hw_scheduler.h" |
| #include "nsi_tasks.h" |
| |
| static int s_argc, test_argc; |
| static char **s_argv, **test_argv; |
| |
| /* Extra "command line options" provided programmatically: */ |
| static int extra_argc; |
| static char **extra_argv; |
| |
| static struct args_struct_t *args_struct; |
| static int used_args; |
| static int args_aval; |
| #define ARGS_ALLOC_CHUNK_SIZE 20 |
| |
| static void nsi_cleanup_cmd_line(void) |
| { |
| if (args_struct != NULL) { /* LCOV_EXCL_BR_LINE */ |
| free(args_struct); |
| args_struct = NULL; |
| } |
| } |
| |
| NSI_TASK(nsi_cleanup_cmd_line, ON_EXIT_POST, 0); |
| |
| /** |
| * Add a set of command line options to the program. |
| * |
| * Each option to be added is described in one entry of the input <args> |
| * This input must be terminated with an entry containing ARG_TABLE_ENDMARKER. |
| */ |
| void nsi_add_command_line_opts(struct args_struct_t *args) |
| { |
| int count = 0; |
| |
| while (args[count].option != NULL) { |
| count++; |
| } |
| count++; /*for the end marker*/ |
| |
| if (used_args + count >= args_aval) { |
| int growby = count; |
| /* reallocs are expensive let's do them only in big chunks */ |
| if (growby < ARGS_ALLOC_CHUNK_SIZE) { |
| growby = ARGS_ALLOC_CHUNK_SIZE; |
| } |
| |
| struct args_struct_t *new_args_struct = realloc(args_struct, |
| (args_aval + growby)* |
| sizeof(struct args_struct_t)); |
| args_aval += growby; |
| /* LCOV_EXCL_START */ |
| if (new_args_struct == NULL) { |
| nsi_print_error_and_exit("Could not allocate memory"); |
| } else { |
| args_struct = new_args_struct; |
| } |
| /* LCOV_EXCL_STOP */ |
| } |
| |
| memcpy(&args_struct[used_args], args, |
| count*sizeof(struct args_struct_t)); |
| |
| used_args += count - 1; |
| /* |
| * -1 as the end marker should be overwritten next time something |
| * is added |
| */ |
| } |
| |
| void nsi_add_testargs_option(void) |
| { |
| static struct args_struct_t testargs_options[] = { |
| { |
| .manual = true, |
| .option = "testargs", |
| .name = "arg", |
| .type = 'l', |
| .descript = "Any argument that follows will be ignored by the top level, " |
| "and made available for possible tests" |
| }, |
| ARG_TABLE_ENDMARKER |
| }; |
| |
| nsi_add_command_line_opts(testargs_options); |
| } |
| |
| static void print_invalid_opt_error(char *argv) |
| { |
| nsi_print_error_and_exit("Incorrect option '%s'. Did you misspell it?" |
| " Is that feature supported in this build?\n", |
| argv); |
| |
| } |
| |
| /** |
| * Handle possible command line arguments. |
| * |
| * We also store them for later use by possible test applications |
| */ |
| void nsi_handle_cmd_line(int argc, char *argv[]) |
| { |
| int i; |
| |
| nsi_add_testargs_option(); |
| |
| s_argv = argv; |
| s_argc = argc; |
| |
| nsi_cmd_args_set_defaults(args_struct); |
| |
| for (int i = 0; i < extra_argc; i++) { |
| if (!nsi_cmd_parse_one_arg(extra_argv[i], args_struct)) { |
| nsi_cmd_print_switches_help(args_struct); |
| print_invalid_opt_error(extra_argv[i]); |
| } |
| } |
| |
| for (i = 1; i < argc; i++) { |
| |
| if ((nsi_cmd_is_option(argv[i], "testargs", 0))) { |
| test_argc = argc - i - 1; |
| test_argv = &argv[i+1]; |
| break; |
| } |
| |
| if (!nsi_cmd_parse_one_arg(argv[i], args_struct)) { |
| nsi_cmd_print_switches_help(args_struct); |
| print_invalid_opt_error(argv[i]); |
| } |
| } |
| } |
| |
| void nsi_register_extra_args(int argc, char *argv[]) |
| { |
| int new_size = extra_argc + argc; |
| |
| extra_argv = realloc(extra_argv, new_size*sizeof(char *)); |
| for (int i = 0; i < argc; i++) { |
| memcpy(&extra_argv[extra_argc], argv, argc*sizeof(char *)); |
| } |
| extra_argc += argc; |
| } |
| |
| static void clear_extra_args(void) |
| { |
| free(extra_argv); |
| } |
| |
| NSI_TASK(clear_extra_args, ON_EXIT_PRE, 100); |
| |
| /** |
| * The application/test can use this function to inspect all the command line |
| * arguments |
| */ |
| void nsi_get_cmd_line_args(int *argc, char ***argv) |
| { |
| *argc = s_argc; |
| *argv = s_argv; |
| } |
| |
| /** |
| * The application/test can use this function to inspect the command line |
| * arguments received after --testargs |
| */ |
| void nsi_get_test_cmd_line_args(int *argc, char ***argv) |
| { |
| *argc = test_argc; |
| *argv = test_argv; |
| } |