117 lines
3.4 KiB
C
117 lines
3.4 KiB
C
#include <zinnia/cmdline.h>
|
|
#include <zinnia/init.h>
|
|
#include <zinnia/stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
// Defined in linker script.
|
|
extern const struct cmdline_option* __ld_cmdline_start[];
|
|
extern const struct cmdline_option* __ld_cmdline_end[];
|
|
|
|
static char cmdline_buf[0x1000];
|
|
|
|
void cmdline_parse_buf(
|
|
char* cmdline_buf,
|
|
size_t len,
|
|
const struct cmdline_option* const* start,
|
|
const struct cmdline_option* const* end
|
|
) {
|
|
size_t idx = 0;
|
|
|
|
while (1) {
|
|
const struct cmdline_option* const* opt = start;
|
|
char* name = nullptr;
|
|
char* value = nullptr;
|
|
|
|
// Skip all leading spaces.
|
|
while (idx < len && cmdline_buf[idx] == ' ')
|
|
idx++;
|
|
if (idx >= len)
|
|
break;
|
|
size_t name_idx = idx;
|
|
name = cmdline_buf + name_idx;
|
|
|
|
// Find the next equal sign or space.
|
|
while (idx < len && cmdline_buf[idx] != '=' && cmdline_buf[idx] != ' ')
|
|
idx++;
|
|
if (idx > len)
|
|
break;
|
|
|
|
// Check if the option has a value (=foo).
|
|
char seperator = cmdline_buf[idx];
|
|
cmdline_buf[idx++] = 0;
|
|
if (seperator == '=') {
|
|
// Check if we need to escape the value.
|
|
char check;
|
|
if (cmdline_buf[idx] == '"') {
|
|
check = '"';
|
|
cmdline_buf[idx++] = 0;
|
|
} else {
|
|
check = ' ';
|
|
}
|
|
|
|
value = cmdline_buf + idx;
|
|
|
|
// Skip the value.
|
|
while (idx < len && cmdline_buf[idx] != check)
|
|
idx++;
|
|
if (idx > len)
|
|
break;
|
|
cmdline_buf[idx++] = 0;
|
|
}
|
|
|
|
// Find the corresponding option.
|
|
while (opt < end) {
|
|
const struct cmdline_option* current = *opt;
|
|
if (!strcmp(current->name, name)) {
|
|
if (value == nullptr)
|
|
break;
|
|
switch (current->option_type) {
|
|
case CMDLINE_STRING:
|
|
current->func_str(value);
|
|
break;
|
|
case CMDLINE_BOOL:
|
|
if (!strcmp(value, "on") || !strcmp(value, "yes") || !strcmp(value, "true") || !strcmp(value, "1"))
|
|
current->func_bool(true);
|
|
else
|
|
current->func_bool(false);
|
|
break;
|
|
case CMDLINE_INTPTR: {
|
|
int base = 10;
|
|
if (!strncmp(value, "0x", 2)) {
|
|
base = 0x10;
|
|
value += 2;
|
|
}
|
|
current->func_intptr(atol(value, base));
|
|
break;
|
|
}
|
|
case CMDLINE_UINTPTR: {
|
|
int base = 10;
|
|
if (!strncmp(value, "0x", 2)) {
|
|
base = 0x10;
|
|
value += 2;
|
|
}
|
|
current->func_uintptr(atolu(value, base));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
opt++;
|
|
}
|
|
|
|
if (idx >= len)
|
|
break;
|
|
}
|
|
}
|
|
|
|
[[__init]]
|
|
void cmdline_parse(const char* cmdline) {
|
|
if (cmdline == nullptr)
|
|
cmdline = "";
|
|
|
|
const size_t len = strnlen(cmdline, sizeof(cmdline_buf) - 1);
|
|
memcpy(cmdline_buf, cmdline, len);
|
|
cmdline_parse_buf(cmdline_buf, len, __ld_cmdline_start, __ld_cmdline_end);
|
|
}
|