mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-12 19:35:34 +00:00
This commit refactors kernel and arch headers to establish a boundary between private and public interface headers. The refactoring strategy used in this commit is detailed in the issue This commit introduces the following major changes: 1. Establish a clear boundary between private and public headers by removing "kernel/include" and "arch/*/include" from the global include paths. Ideally, only kernel/ and arch/*/ source files should reference the headers in these directories. If these headers must be used by a component, these include paths shall be manually added to the CMakeLists.txt file of the component. This is intended to discourage applications from including private kernel and arch headers either knowingly and unknowingly. - kernel/include/ (PRIVATE) This directory contains the private headers that provide private kernel definitions which should not be visible outside the kernel and arch source code. All public kernel definitions must be added to an appropriate header located under include/. - arch/*/include/ (PRIVATE) This directory contains the private headers that provide private architecture-specific definitions which should not be visible outside the arch and kernel source code. All public architecture- specific definitions must be added to an appropriate header located under include/arch/*/. - include/ AND include/sys/ (PUBLIC) This directory contains the public headers that provide public kernel definitions which can be referenced by both kernel and application code. - include/arch/*/ (PUBLIC) This directory contains the public headers that provide public architecture-specific definitions which can be referenced by both kernel and application code. 2. Split arch_interface.h into "kernel-to-arch interface" and "public arch interface" divisions. - kernel/include/kernel_arch_interface.h * provides private "kernel-to-arch interface" definition. * includes arch/*/include/kernel_arch_func.h to ensure that the interface function implementations are always available. * includes sys/arch_interface.h so that public arch interface definitions are automatically included when including this file. - arch/*/include/kernel_arch_func.h * provides architecture-specific "kernel-to-arch interface" implementation. * only the functions that will be used in kernel and arch source files are defined here. - include/sys/arch_interface.h * provides "public arch interface" definition. * includes include/arch/arch_inlines.h to ensure that the architecture-specific public inline interface function implementations are always available. - include/arch/arch_inlines.h * includes architecture-specific arch_inlines.h in include/arch/*/arch_inline.h. - include/arch/*/arch_inline.h * provides architecture-specific "public arch interface" inline function implementation. * supersedes include/sys/arch_inline.h. 3. Refactor kernel and the existing architecture implementations. - Remove circular dependency of kernel and arch headers. The following general rules should be observed: * Never include any private headers from public headers * Never include kernel_internal.h in kernel_arch_data.h * Always include kernel_arch_data.h from kernel_arch_func.h * Never include kernel.h from kernel_struct.h either directly or indirectly. Only add the kernel structures that must be referenced from public arch headers in this file. - Relocate syscall_handler.h to include/ so it can be used in the public code. This is necessary because many user-mode public codes reference the functions defined in this header. - Relocate kernel_arch_thread.h to include/arch/*/thread.h. This is necessary to provide architecture-specific thread definition for 'struct k_thread' in kernel.h. - Remove any private header dependencies from public headers using the following methods: * If dependency is not required, simply omit * If dependency is required, - Relocate a portion of the required dependencies from the private header to an appropriate public header OR - Relocate the required private header to make it public. This commit supersedes #20047, addresses #19666, and fixes #3056. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
419 lines
9.2 KiB
C
419 lines
9.2 KiB
C
/*
|
|
* Copyright (c) 2018 Oticon A/S
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <arch/posix/posix_trace.h>
|
|
#include "posix_board_if.h"
|
|
#include "zephyr/types.h"
|
|
#include "cmdline_common.h"
|
|
|
|
/**
|
|
* Check if <arg> is the option <option>
|
|
* The accepted syntax is:
|
|
* * For options without a value following:
|
|
* [-[-]]<option>
|
|
* * For options with value:
|
|
* [-[-]]<option>{:|=}<value>
|
|
*
|
|
* Returns 0 if it is not, or a number > 0 if it is.
|
|
* The returned number is the number of characters it went through
|
|
* to find the end of the option including the ':' or '=' character in case of
|
|
* options with value
|
|
*/
|
|
int cmd_is_option(const char *arg, const char *option, int with_value)
|
|
{
|
|
int of = 0;
|
|
size_t to_match_len = strlen(option);
|
|
|
|
if (arg[of] == '-') {
|
|
of++;
|
|
}
|
|
if (arg[of] == '-') {
|
|
of++;
|
|
}
|
|
|
|
if (!with_value) {
|
|
if (strcmp(&arg[of], option) != 0) {
|
|
return 0;
|
|
} else {
|
|
return of + to_match_len;
|
|
}
|
|
}
|
|
|
|
while (!(arg[of] == 0 && *option == 0)) {
|
|
if (*option == 0) {
|
|
if ((arg[of] == ':') || (arg[of] == '=')) {
|
|
of++;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
if (arg[of] != *option) {
|
|
return 0;
|
|
}
|
|
of++;
|
|
option++;
|
|
}
|
|
|
|
if (arg[of] == 0) { /* we need a value to follow */
|
|
posix_print_error_and_exit("Incorrect option syntax '%s'. The "
|
|
"value should follow the options. "
|
|
"For example --ratio=3\n",
|
|
arg);
|
|
}
|
|
return of;
|
|
}
|
|
|
|
/**
|
|
* Return 1 if <arg> matches an accepted help option.
|
|
* 0 otherwise
|
|
*
|
|
* Valid help options are [-[-]]{?|h|help}
|
|
* with the h or help in any case combination
|
|
*/
|
|
int cmd_is_help_option(const char *arg)
|
|
{
|
|
if (arg[0] == '-') {
|
|
arg++;
|
|
}
|
|
if (arg[0] == '-') {
|
|
arg++;
|
|
}
|
|
if ((strcasecmp(arg, "?") == 0) ||
|
|
(strcasecmp(arg, "h") == 0) ||
|
|
(strcasecmp(arg, "help") == 0)) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#define CMD_TYPE_ERROR "Coding error: type %c not understood"
|
|
#define CMD_ERR_BOOL_SWI "Programming error: I only know how to "\
|
|
"automatically read boolean switches\n"
|
|
|
|
/**
|
|
* Read out a the value following an option from str, and store it into
|
|
* <dest>
|
|
* <type> indicates the type of parameter (and type of dest pointer)
|
|
* 'b' : boolean
|
|
* 's' : string (char *)
|
|
* 'u' : 32 bit unsigned integer
|
|
* 'U' : 64 bit unsigned integer
|
|
* 'i' : 32 bit signed integer
|
|
* 'I' : 64 bit signed integer
|
|
* 'd' : *double* float
|
|
*
|
|
* Note: list type ('l') cannot be handled by this function and must always be
|
|
* manual
|
|
*
|
|
* <long_d> is the long name of the option
|
|
*/
|
|
void cmd_read_option_value(const char *str, void *dest, const char type,
|
|
const char *option)
|
|
{
|
|
int error = 0;
|
|
char *endptr = NULL;
|
|
|
|
switch (type) {
|
|
case 'b':
|
|
if (strcasecmp(str, "false") == 0) {
|
|
*(bool *)dest = false;
|
|
endptr = (char *)str + 5;
|
|
} else if (strcmp(str, "0") == 0) {
|
|
*(bool *)dest = false;
|
|
endptr = (char *)str + 1;
|
|
} else if (strcasecmp(str, "true") == 0) {
|
|
*(bool *)dest = true;
|
|
endptr = (char *)str + 4;
|
|
} else if (strcmp(str, "1") == 0) {
|
|
*(bool *)dest = true;
|
|
endptr = (char *)str + 1;
|
|
} else {
|
|
error = 1;
|
|
}
|
|
break;
|
|
case 's':
|
|
*(char **)dest = (char *)str;
|
|
endptr = (char *)str + strlen(str);
|
|
break;
|
|
case 'u':
|
|
*(u32_t *)dest = strtoul(str, &endptr, 0);
|
|
break;
|
|
case 'U':
|
|
*(u64_t *)dest = strtoull(str, &endptr, 0);
|
|
break;
|
|
case 'i':
|
|
*(s32_t *)dest = strtol(str, &endptr, 0);
|
|
break;
|
|
case 'I':
|
|
*(s64_t *)dest = strtoll(str, &endptr, 0);
|
|
break;
|
|
case 'd':
|
|
*(double *)dest = strtod(str, &endptr);
|
|
break;
|
|
default:
|
|
posix_print_error_and_exit(CMD_TYPE_ERROR, type);
|
|
/* Unreachable */
|
|
break;
|
|
}
|
|
|
|
if (!error && endptr && *endptr != 0) {
|
|
error = 1;
|
|
}
|
|
|
|
if (error) {
|
|
posix_print_error_and_exit("Error reading value of %s '%s'. Use"
|
|
" --help for usage information\n",
|
|
option, str);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize existing dest* to defaults based on type
|
|
*/
|
|
void cmd_args_set_defaults(struct args_struct_t args_struct[])
|
|
{
|
|
int count = 0;
|
|
|
|
while (args_struct[count].option != NULL) {
|
|
|
|
if (args_struct[count].dest == NULL) {
|
|
count++;
|
|
continue;
|
|
}
|
|
|
|
switch (args_struct[count].type) {
|
|
case 0: /* does not have storage */
|
|
break;
|
|
case 'b':
|
|
*(bool *)args_struct[count].dest = false;
|
|
break;
|
|
case 's':
|
|
*(char **)args_struct[count].dest = NULL;
|
|
break;
|
|
case 'u':
|
|
*(u32_t *)args_struct[count].dest = UINT32_MAX;
|
|
break;
|
|
case 'U':
|
|
*(u64_t *)args_struct[count].dest = UINT64_MAX;
|
|
break;
|
|
case 'i':
|
|
*(s32_t *)args_struct[count].dest = INT32_MAX;
|
|
break;
|
|
case 'I':
|
|
*(s64_t *)args_struct[count].dest = INT64_MAX;
|
|
break;
|
|
case 'd':
|
|
*(double *)args_struct[count].dest = NAN;
|
|
break;
|
|
default:
|
|
posix_print_error_and_exit(CMD_TYPE_ERROR,
|
|
args_struct[count].type);
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* For the help messages:
|
|
* Generate a string containing how the option described by <args_s_el>
|
|
* should be used
|
|
*
|
|
* The string is saved in <buf> which has been allocated <size> bytes by the
|
|
* caller
|
|
*/
|
|
static void cmd_gen_switch_syntax(char *buf, int size,
|
|
struct args_struct_t *args_s_el)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (size <= 0) {
|
|
return;
|
|
}
|
|
|
|
if (args_s_el->is_mandatory == false) {
|
|
*buf++ = '[';
|
|
size--;
|
|
}
|
|
|
|
if (args_s_el->is_switch == true) {
|
|
ret = snprintf(buf, size, "-%s", args_s_el->option);
|
|
} else {
|
|
if (args_s_el->type != 'l') {
|
|
ret = snprintf(buf, size, "-%s=<%s>",
|
|
args_s_el->option, args_s_el->name);
|
|
} else {
|
|
ret = snprintf(buf, size, "-%s <%s>...",
|
|
args_s_el->option, args_s_el->name);
|
|
}
|
|
}
|
|
|
|
if (ret < 0) {
|
|
posix_print_error_and_exit("Unexpected error in %s %i\n",
|
|
__FILE__, __LINE__);
|
|
}
|
|
if (size - ret < 0) {
|
|
/*
|
|
* If we run out of space we can just stop,
|
|
* this is not critical
|
|
*/
|
|
return;
|
|
}
|
|
buf += ret;
|
|
size -= ret;
|
|
|
|
if (args_s_el->is_mandatory == false) {
|
|
snprintf(buf, size, "] ");
|
|
} else {
|
|
snprintf(buf, size, " ");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print short list of available switches
|
|
*/
|
|
void cmd_print_switches_help(struct args_struct_t args_struct[])
|
|
{
|
|
int count = 0;
|
|
int printed_in_line = strlen(_HELP_SWITCH) + 1;
|
|
|
|
fprintf(stdout, "%s ", _HELP_SWITCH);
|
|
|
|
while (args_struct[count].option != NULL) {
|
|
char stringy[_MAX_STRINGY_LEN];
|
|
|
|
cmd_gen_switch_syntax(stringy, _MAX_STRINGY_LEN,
|
|
&args_struct[count]);
|
|
|
|
if (printed_in_line + strlen(stringy) > _MAX_LINE_WIDTH) {
|
|
fprintf(stdout, "\n");
|
|
printed_in_line = 0;
|
|
}
|
|
|
|
fprintf(stdout, "%s", stringy);
|
|
printed_in_line += strlen(stringy);
|
|
count++;
|
|
}
|
|
|
|
fprintf(stdout, "\n");
|
|
}
|
|
|
|
/**
|
|
* Print the long help message of the program
|
|
*/
|
|
void cmd_print_long_help(struct args_struct_t args_struct[])
|
|
{
|
|
int ret;
|
|
int count = 0;
|
|
int printed_in_line = 0;
|
|
char stringy[_MAX_STRINGY_LEN];
|
|
|
|
cmd_print_switches_help(args_struct);
|
|
|
|
fprintf(stdout, "\n %-*s:%s\n", _LONG_HELP_ALIGN-1,
|
|
_HELP_SWITCH, _HELP_DESCR);
|
|
|
|
while (args_struct[count].option != NULL) {
|
|
int printed_right;
|
|
char *toprint;
|
|
int total_to_print;
|
|
|
|
cmd_gen_switch_syntax(stringy, _MAX_STRINGY_LEN,
|
|
&args_struct[count]);
|
|
|
|
ret = fprintf(stdout, " %-*s:", _LONG_HELP_ALIGN-1, stringy);
|
|
printed_in_line = ret;
|
|
printed_right = 0;
|
|
toprint = args_struct[count].descript;
|
|
total_to_print = strlen(toprint);
|
|
ret = fprintf(stdout, "%.*s\n",
|
|
_MAX_LINE_WIDTH - printed_in_line,
|
|
&toprint[printed_right]);
|
|
printed_right += ret - 1;
|
|
|
|
while (printed_right < total_to_print) {
|
|
fprintf(stdout, "%*s", _LONG_HELP_ALIGN, "");
|
|
ret = fprintf(stdout, "%.*s\n",
|
|
_MAX_LINE_WIDTH - _LONG_HELP_ALIGN,
|
|
&toprint[printed_right]);
|
|
printed_right += ret - 1;
|
|
}
|
|
count++;
|
|
}
|
|
fprintf(stdout, "\n");
|
|
fprintf(stdout, "Note that which options are available depends on the "
|
|
"enabled features/drivers\n\n");
|
|
}
|
|
|
|
/*
|
|
* <argv> matched the argument described in <arg_element>
|
|
*
|
|
* If arg_element->dest points to a place to store a possible value, read it
|
|
* If there is a callback registered, call it after
|
|
*/
|
|
static void cmd_handle_this_matched_arg(char *argv, int offset,
|
|
struct args_struct_t *arg_element)
|
|
{
|
|
if (arg_element->dest != NULL) {
|
|
if (arg_element->is_switch) {
|
|
if (arg_element->type == 'b') {
|
|
*(bool *)arg_element->dest = true;
|
|
} else {
|
|
posix_print_error_and_exit(CMD_ERR_BOOL_SWI);
|
|
}
|
|
} else { /* if not a switch we need to read its value */
|
|
cmd_read_option_value(&argv[offset],
|
|
arg_element->dest,
|
|
arg_element->type,
|
|
arg_element->option);
|
|
}
|
|
}
|
|
|
|
if (arg_element->call_when_found) {
|
|
arg_element->call_when_found(argv, offset);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Try to find if this argument is in the list (and it is not manual)
|
|
* if it does, try to parse it, set its dest accordingly, and return true
|
|
* if it is not found, return false
|
|
*/
|
|
bool cmd_parse_one_arg(char *argv, struct args_struct_t args_struct[])
|
|
{
|
|
int count = 0;
|
|
int ret;
|
|
|
|
if (cmd_is_help_option(argv)) {
|
|
cmd_print_long_help(args_struct);
|
|
posix_exit(0);
|
|
}
|
|
|
|
while (args_struct[count].option != NULL) {
|
|
if (args_struct[count].manual) {
|
|
count++;
|
|
continue;
|
|
}
|
|
ret = cmd_is_option(argv, args_struct[count].option,
|
|
!args_struct[count].is_switch);
|
|
if (ret) {
|
|
cmd_handle_this_matched_arg(argv,
|
|
ret,
|
|
&args_struct[count]);
|
|
return true;
|
|
}
|
|
count++;
|
|
}
|
|
return false;
|
|
}
|