#include "local.h"
static alias_str _boolean_read(const void *data_pointer, const void *ud) {
bool data = *(const bool *)data_pointer;
return alias_str_clone(NULL, data ? "true" : "false");
}
static void _boolean_write(void *data_pointer, const void *ud, alias_str string) {
bool * data = (bool *)data_pointer;
if(*string >= '0' && *string <= '9') {
*data = !!atoi(string);
}
*data = strcmp(string, "true") == 0;
}
struct EngineVariableType EngineVariableType_boolean = {
.read = _boolean_read,
.write = _boolean_write
};
static alias_str _integer_read(const void *data_pointer, const void *ud) {
int64_t data = *(const int64_t *)data_pointer;
return alias_str_format(NULL, "%ill", data);
}
static void _integer_write(void *data_pointer, const void *ud, alias_str string) {
int64_t * data = (int64_t *)data_pointer;
*data = atoi(string);
}
struct EngineVariableType EngineVariableType_integer = {
.read = _integer_read,
.write = _integer_write
};
static alias_str _real_read(const void *data_pointer, const void *ud) {
float data = *(const float *)data_pointer;
return alias_str_format(NULL, "%f", data);
}
static void _real_write(void *data_pointer, const void *ud, alias_str string) {
float * data = (float *)data_pointer;
*data = atof(string);
}
struct EngineVariableType EngineVariableType_real = {
.read = _real_read,
.write = _real_write
};
alias_str EngineVariableTypeEnum_read(const void *data_pointer, const void *ud) {
int64_t data = *(const int64_t *)data_pointer;
const struct EngineVariableTypeEnumOption *options = ud;
for(; options->name != NULL; options++) {
if(options->value == data) {
return alias_str_clone(NULL, options->name);
}
}
return NULL;
}
void EngineVariableTypeEnum_write(void *data_pointer, const void *ud, alias_str string) {
int64_t * data = (int64_t *)data_pointer;
if(*string >= '0' && *string <= '9') {
*data = atoi(string);
}
const struct EngineVariableTypeEnumOption *options = ud;
for(; options->name != NULL; options++) {
if(strcmp(options->name, string) == 0) {
*data = options->value;
}
}
}
static alias_Vector(struct EngineVariable *) _variables = ALIAS_VECTOR_INIT;
static alias_Vector(uint32_t) _by_name = ALIAS_VECTOR_INIT;
static int _by_name_compare(const void *ap, const void *bp, void *ud) {
uint32_t a = *(uint32_t *)ap;
uint32_t b = *(uint32_t *)bp;
return strcmp(_variables.data[a]->name, _variables.data[b]->name);
}
static struct EngineVariable ** _find(alias_str name) {
if(_variables.length == 0) {
return NULL;
}
struct EngineVariable _search_variable = {.name = name};
uint32_t key = _variables.length;
_variables.data[key] = &_search_variable;
uint32_t *found = bsearch(&key, _by_name.data, _by_name.length, sizeof(*_by_name.data), _by_name_compare, NULL);
if(found == NULL) {
return NULL;
}
return &_variables.data[*found];
}
static void _insert(struct EngineVariable *var) {
uint32_t index = _variables.length;
alias_Vector_space_for(&_variables, NULL, 2);
alias_Vector_space_for(&_by_name, NULL, 2);
*alias_Vector_push(&_variables) = var;
*alias_Vector_push(&_by_name) = index;
qsort(_by_name.data, _by_name.length, sizeof(*_by_name.data), _by_name_compare, NULL);
}
void Engine_variable_register(struct EngineVariable *var) {
struct EngineVariable **var_ptr = _find(var->name);
if(var_ptr == NULL) {
var->default_value = var->variable_type->read(var->data_pointer, var->variable_type->ud);
var->current_value = var->variable_type->read(var->data_pointer, var->variable_type->ud);
_insert(var);
return;
}
if((*var_ptr)->default_value == NULL && (*var_ptr)->variable_type == NULL) {
alias_str_free(NULL, (*var_ptr)->name);
alias_str_free(NULL, (*var_ptr)->default_value);
alias_free(NULL, (*var_ptr), sizeof(*(*var_ptr)), alignof(*(*var_ptr)));
*var_ptr = var;
var->default_value = var->variable_type->read(var->data_pointer, var->variable_type->ud);
var->current_value = var->variable_type->read(var->data_pointer, var->variable_type->ud);
} else {
ALIAS_ERROR("Attempting to register Engine variable %s more than once", var->name);
return;
}
}
alias_str Engine_variable_get(alias_str name) {
struct EngineVariable **var_ptr = _find(name);
if(var_ptr == NULL) return "";
return (*var_ptr)->current_value;
}
void Engine_variable_set(alias_str name, alias_str value) {
struct EngineVariable **var_ptr = _find(name);
if(var_ptr == NULL) {
struct EngineVariable *var = alias_malloc(NULL, sizeof(*var), alignof(*var));
var->name = alias_str_clone(NULL, name);
var->default_value = NULL;
var->current_value = alias_str_clone(NULL, value);
var->data_pointer = NULL;
var->variable_type = NULL;
_insert(var);
return;
}
struct EngineVariable *var = *var_ptr;
alias_str_free(NULL, var->current_value);
var->current_value = alias_str_clone(NULL, value);
if(var->variable_type != NULL && var->data_pointer != NULL) {
var->variable_type->write(var->data_pointer, var->variable_type->ud, value);
}
}