@@ -7,6 +7,10 @@ include_directories( | |||
"${CMAKE_HOME_DIRECTORY}/subprojects/minIni/dev" | |||
) | |||
add_executable(ini_config | |||
ini-config.c | |||
ini-config.h) | |||
add_executable( | |||
ini_config | |||
ini-config.c | |||
ini-config.h | |||
int.c | |||
int.h | |||
) |
@@ -21,195 +21,3 @@ const char* INI_ConfigGetCommandlineOption(uint8_t argc, const char* argv[], con | |||
return NULL; | |||
} | |||
#define INI_CONFIG_REGISTER_INT_TYPE(ID, T) \ | |||
typedef bool INI_ConfigValidate##ID(T); \ | |||
\ | |||
typedef T INI_ConfigDeserialize##ID(const char*); \ | |||
\ | |||
typedef void INI_ConfigSerialize##ID(T, const char[128]); \ | |||
\ | |||
void INI_ConfigEnsureValid##ID(INI_ConfigItem* item, T raw_value, T default_value) { \ | |||
T* dest = item->dest; \ | |||
if (item->validator) { \ | |||
INI_ConfigValidate##ID* validate = item->validator; \ | |||
if (validate(raw_value)) { \ | |||
*dest = raw_value; \ | |||
return; \ | |||
} \ | |||
*dest = default_value; \ | |||
return; \ | |||
} \ | |||
*dest = raw_value; \ | |||
} \ | |||
\ | |||
void INI_ConfigLoad##ID(INI_ConfigItem* item, const char* config_path) { \ | |||
static T raw_value; \ | |||
static T default_value; \ | |||
default_value = *((T*) item->default_value); \ | |||
if (item->transformer.deserialize && item->transformer.serialize) { \ | |||
INI_ConfigDeserialize##ID* deserialize = item->transformer.deserialize; \ | |||
INI_ConfigSerialize##ID* serialize = item->transformer.serialize; \ | |||
const char serialized_default_value[128]; \ | |||
if (default_value) { \ | |||
serialize(default_value, serialized_default_value); \ | |||
} \ | |||
char buffer[128]; \ | |||
ini_gets(item->section, item->key, serialized_default_value, buffer, 128, config_path); \ | |||
raw_value = deserialize(buffer); \ | |||
} else { \ | |||
raw_value = ini_getl(item->section, item->key, default_value, config_path); \ | |||
} \ | |||
INI_ConfigEnsureValid##ID(item, raw_value, default_value); \ | |||
} \ | |||
\ | |||
INI_ConfigSaveItemResult INI_ConfigSave##ID(INI_ConfigItem* item, const char* config_path) { \ | |||
T dest = *((T*) item->dest); \ | |||
if (item->validator) { \ | |||
INI_ConfigValidate##ID* validate = item->validator; \ | |||
if (!validate(dest)) { \ | |||
dest = *((const T*) item->default_value); \ | |||
} \ | |||
} \ | |||
\ | |||
if (item->transformer.deserialize && item->transformer.serialize) { \ | |||
INI_ConfigSerialize##ID* serialize = item->transformer.serialize; \ | |||
const char serialized_value[128]; \ | |||
serialize(dest, serialized_value); \ | |||
if (!ini_puts(item->section, item->key, serialized_value, config_path)) { \ | |||
return -1; \ | |||
} \ | |||
return 0; \ | |||
} \ | |||
\ | |||
if (!ini_putl(item->section, item->key, dest, config_path)) { \ | |||
return -1; \ | |||
} \ | |||
\ | |||
return 0; \ | |||
} \ | |||
\ | |||
void INI_ConfigOverride##ID(INI_ConfigItem* item, uint8_t argc, const char* argv[]) { \ | |||
if (!item->cmdline_option) { \ | |||
return; \ | |||
} \ | |||
const char* cmdline_buffer; \ | |||
char* rest_of_string; \ | |||
static T dest; \ | |||
static T config_value; \ | |||
config_value = *((T*) item->dest); \ | |||
if ((cmdline_buffer = INI_ConfigGetCommandlineOption(argc, argv, item->cmdline_option))) { \ | |||
dest = strtol(cmdline_buffer, &rest_of_string, 10); \ | |||
if (strcmp(cmdline_buffer, rest_of_string) != 0) { \ | |||
INI_ConfigEnsureValid##ID(item, dest, config_value); \ | |||
return; \ | |||
} \ | |||
} \ | |||
} | |||
INI_CONFIG_REGISTER_INT_TYPE(U8, uint8_t); | |||
INI_CONFIG_REGISTER_INT_TYPE(U16, uint16_t); | |||
INI_CONFIG_REGISTER_INT_TYPE(U32, uint32_t); | |||
INI_CONFIG_REGISTER_INT_TYPE(I8, int8_t); | |||
INI_CONFIG_REGISTER_INT_TYPE(I16, int16_t); | |||
INI_CONFIG_REGISTER_INT_TYPE(I32, int32_t); | |||
typedef bool INI_ConfigLoadParamsStringValidator(const char*); | |||
void INI_ConfigEnsureValidString(INI_ConfigItem* item, const char* buffer) { | |||
if (item->validator) { | |||
INI_ConfigLoadParamsStringValidator* validator = item->validator; | |||
if (validator(buffer)) { | |||
memcpy(item->dest, buffer, item->type.size); | |||
return; | |||
} | |||
memcpy(item->dest, item->default_value, item->type.size); | |||
return; | |||
} | |||
memcpy(item->dest, buffer, item->type.size); | |||
} | |||
void INI_ConfigLoadString(INI_ConfigItem* item, const char* config_path) { | |||
char buffer[item->type.size]; | |||
ini_gets(item->section, item->key, item->default_value, buffer, (int32_t) item->type.size, config_path); | |||
INI_ConfigEnsureValidString(item, buffer); | |||
} | |||
INI_ConfigSaveItemResult INI_ConfigSaveString(INI_ConfigItem* item, const char* config_path) { | |||
const char* dest = (const char*) item->dest; | |||
if (item->validator) { | |||
INI_ConfigLoadParamsStringValidator* validator = item->validator; | |||
if (!validator(dest)) { | |||
dest = (const char*) item->default_value; | |||
} | |||
} | |||
if (!ini_puts(item->section, item->key, dest, config_path)) { | |||
return INI_CONFIG_SAVE_ITEM_ERROR; | |||
} | |||
return INI_CONFIG_SAVE_ITEM_OK; | |||
} | |||
void INI_ConfigOverrideString(INI_ConfigItem* item, uint8_t argc, const char* argv[]) { | |||
if (!item->cmdline_option) { | |||
return; | |||
} | |||
const char* cmdline_buffer; | |||
if ((cmdline_buffer = INI_ConfigGetCommandlineOption(argc, argv, item->cmdline_option))) { | |||
INI_ConfigEnsureValidString(item, cmdline_buffer); | |||
} | |||
} | |||
void INI_ConfigLoad(INI_ConfigItem item[], const char* config_path) { | |||
uint8_t i; | |||
for (i = 0; item[i].type.size > 0; i += 1) { | |||
if (!item[i].type.load) { | |||
continue; | |||
} | |||
item[i].type.load(&item[i], config_path); | |||
} | |||
} | |||
INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem item[], const char* config_path) { | |||
uint8_t i; | |||
int32_t problems = 0; | |||
for (i = 0; item[i].type.size > 0; i += 1) { | |||
int32_t result = item[i].type.save ? item[i].type.save(&item[i], config_path) : 0; | |||
if (result < 0) { | |||
problems |= (1 << (int32_t) i); | |||
} | |||
} | |||
return -problems; | |||
} | |||
void INI_ConfigOverride(INI_ConfigItem item[], uint8_t argc, const char* argv[]) { | |||
uint8_t i; | |||
for (i = 0; item[i].type.size > 0; i += 1) { | |||
if (!item[i].type.override) { | |||
continue; | |||
} | |||
item[i].type.override(&item[i], argc, argv); | |||
// TODO specify command-line arg external from config item? | |||
} | |||
} | |||
INI_ConfigInitializeResult INI_ConfigInitialize(INI_ConfigItem item[], const char* config_path, uint8_t argc, const char* argv[]) { | |||
INI_ConfigLoad(item, config_path); | |||
INI_ConfigSaveResult save_result = INI_ConfigSave(item, config_path); | |||
if (save_result < 0) { | |||
//INI_LogError("config", "Sync failed! Result: %u", save_result); | |||
return INI_CONFIG_INITIALIZE_RESULT_ERROR; | |||
} | |||
INI_ConfigOverride(item, argc, argv); | |||
if (save_result > 0) { | |||
//INI_LogWarn(false, "config", "Sync encountered issues. Result: %u", save_result); | |||
return INI_CONFIG_INITIALIZE_RESULT_WARNING; | |||
} | |||
//INI_LogInfo(INI_LOG_CATEGORY_GLOBAL, "config", "Sync successful."); | |||
return INI_CONFIG_INITIALIZE_RESULT_OK; | |||
} |
@@ -7,48 +7,138 @@ | |||
#include <stdbool.h> | |||
#include <minIni.h> | |||
/** | |||
* Struct for transformer functions used for properly loading and saving the config item's value. | |||
*/ | |||
typedef struct { | |||
/** | |||
* Function that formats the value from memory to a value that is write-friendly to the config file. | |||
*/ | |||
void* serialize; | |||
/** | |||
* Function that formats the value from file to a value that is read-friendly to memory. | |||
*/ | |||
void* deserialize; | |||
} INI_ConfigTransformer; | |||
} INI_ConfigTransformer; // TODO: should we unify this with INI_ConfigType? | |||
struct INI_ConfigItem; | |||
/** | |||
* Function for loading a config item value from file to memory. | |||
*/ | |||
typedef void INI_ConfigTypeLoad(struct INI_ConfigItem*, const char*); | |||
/** | |||
* Result enum for saving config items. | |||
*/ | |||
typedef enum { | |||
/** | |||
* Result returned when saving a config item was not successful. | |||
*/ | |||
INI_CONFIG_SAVE_ITEM_ERROR = -1, | |||
/** | |||
* Result returned when saving a config item was successful. | |||
*/ | |||
INI_CONFIG_SAVE_ITEM_OK, | |||
} INI_ConfigSaveItemResult; | |||
/** | |||
* Function for saving a config item value from memory to file. | |||
*/ | |||
typedef INI_ConfigSaveItemResult INI_ConfigTypeSave(struct INI_ConfigItem*, const char*); | |||
/** | |||
* Function for retrieving a config item value from the command-line to memory. | |||
*/ | |||
typedef void INI_ConfigTypeOverride(struct INI_ConfigItem*, uint8_t, const char*[]); | |||
/** | |||
* Struct for the config item type. | |||
*/ | |||
typedef struct { | |||
/** | |||
* Size of the corresponding in-memory value of the config item. | |||
*/ | |||
size_t size; | |||
/** | |||
* Load function. | |||
* @see INI_ConfigTypeLoad | |||
*/ | |||
INI_ConfigTypeLoad* load; | |||
/** | |||
* Save function. | |||
* @see INI_ConfigTypeSave | |||
*/ | |||
INI_ConfigTypeSave* save; | |||
/** | |||
* Override function. | |||
* @see INI_ConfigTypeOverride | |||
*/ | |||
INI_ConfigTypeOverride* override; | |||
} INI_ConfigType; | |||
/** | |||
* Struct for the config item, which occuptes a single key in a specific section of the config INI file. | |||
*/ | |||
typedef struct INI_ConfigItem { | |||
/** | |||
* Type of the config item. | |||
*/ | |||
INI_ConfigType type; | |||
/** | |||
* Section where this config item can be found. | |||
*/ | |||
const char* section; | |||
/** | |||
* Key where this config item value is serialized and stored. | |||
*/ | |||
const char* key; | |||
const char* cmdline_option; | |||
/** | |||
* Command-line option for overriding this config item's value. | |||
*/ | |||
const char* cmdline_option; // TODO: should we extract commandline parsing logic? | |||
/** | |||
* Default value of the config item, when the value could not be read from the config file. | |||
*/ | |||
const void* default_value; | |||
/** | |||
* Validator function for the config item's value. | |||
*/ | |||
void* validator; | |||
/** | |||
* Transformer functions. | |||
* @see INI_ConfigTransformer | |||
*/ | |||
INI_ConfigTransformer transformer; | |||
/** | |||
* The memory address where the config item value will reside. This property should allow storing the amount of butes | |||
* specified under `type.size`. | |||
*/ | |||
void* dest; | |||
} INI_ConfigItem; | |||
void INI_ConfigGetDefaultPath(char*, size_t); | |||
/** | |||
* Retrieves the value from a command-line option. | |||
* @return The string value from the command-line option. | |||
*/ | |||
const char* INI_ConfigGetCommandlineOption(uint8_t, const char*[], const char*); | |||
/** | |||
* Result enum for initializing config items. | |||
*/ | |||
typedef enum { | |||
/** | |||
* Result returned when initializing all config items was not successful. | |||
*/ | |||
INI_CONFIG_INITIALIZE_RESULT_ERROR = -1, | |||
/** | |||
* Result returned when initializing all config items was successful. | |||
*/ | |||
INI_CONFIG_INITIALIZE_RESULT_OK, | |||
/** | |||
* Result returned when initializing some config items was successful. | |||
*/ | |||
INI_CONFIG_INITIALIZE_RESULT_WARNING | |||
} INI_ConfigInitializeResult; | |||
@@ -58,78 +148,10 @@ typedef int32_t INI_ConfigSaveResult; | |||
INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem[], const char*); | |||
void INI_ConfigLoadU8(INI_ConfigItem*, const char*); | |||
void INI_ConfigLoadU16(INI_ConfigItem*, const char*); | |||
void INI_ConfigLoadU32(INI_ConfigItem*, const char*); | |||
void INI_ConfigLoadI8(INI_ConfigItem*, const char*); | |||
void INI_ConfigLoadI16(INI_ConfigItem*, const char*); | |||
void INI_ConfigLoadI32(INI_ConfigItem*, const char*); | |||
void INI_ConfigLoadString(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveU8(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveU16(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveU32(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveI8(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveI16(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveI32(INI_ConfigItem*, const char*); | |||
INI_ConfigSaveItemResult INI_ConfigSaveString(INI_ConfigItem*, const char*); | |||
void INI_ConfigOverrideU8(INI_ConfigItem*, uint8_t, const char*[]); | |||
void INI_ConfigOverrideU16(INI_ConfigItem*, uint8_t, const char*[]); | |||
void INI_ConfigOverrideU32(INI_ConfigItem*, uint8_t, const char*[]); | |||
void INI_ConfigOverrideI8(INI_ConfigItem*, uint8_t, const char*[]); | |||
void INI_ConfigOverrideI16(INI_ConfigItem*, uint8_t, const char*[]); | |||
void INI_ConfigOverrideI32(INI_ConfigItem*, uint8_t, const char*[]); | |||
void INI_ConfigOverrideString(INI_ConfigItem*, uint8_t, const char*[]); | |||
#define INI_CONFIG_TYPE_U8 (INI_ConfigType) { \ | |||
.size = sizeof(uint8_t), \ | |||
.load = INI_ConfigLoadU8, \ | |||
.save = INI_ConfigSaveU8, \ | |||
.override = INI_ConfigOverrideU8, \ | |||
} | |||
#define INI_CONFIG_TYPE_U16 (INI_ConfigType) { \ | |||
.size = sizeof(uint16_t), \ | |||
.load = INI_ConfigLoadU16, \ | |||
.save = INI_ConfigSaveU16, \ | |||
.override = INI_ConfigOverrideU16, \ | |||
} | |||
#define INI_CONFIG_TYPE_U32 (INI_ConfigType) { \ | |||
.size = sizeof(uint32_t), \ | |||
.load = INI_ConfigLoadU32, \ | |||
.save = INI_ConfigSaveU32, \ | |||
.override = INI_ConfigOverrideU32, \ | |||
} | |||
#define INI_CONFIG_TYPE_I8 (INI_ConfigType) { \ | |||
.size = sizeof(int8_t), \ | |||
.load = INI_ConfigLoadI8, \ | |||
.save = INI_ConfigSaveI8, \ | |||
.override = INI_ConfigOverrideI8, \ | |||
} | |||
#define INI_CONFIG_TYPE_I16 (INI_ConfigType) { \ | |||
.size = sizeof(int16_t), \ | |||
.load = INI_ConfigLoadI16, \ | |||
.save = INI_ConfigSaveI16, \ | |||
.override = INI_ConfigOverrideI16, \ | |||
} | |||
#define INI_CONFIG_TYPE_I32 (INI_ConfigType) { \ | |||
.size = sizeof(int32_t), \ | |||
.load = INI_ConfigLoadI32, \ | |||
.save = INI_ConfigSaveI32, \ | |||
.override = INI_ConfigOverrideI32, \ | |||
} | |||
#define INI_CONFIG_TYPE_FNS_STRING(X) (INI_ConfigType) { \ | |||
.size = (sizeof(char) * X), \ | |||
.load = INI_ConfigLoadString, \ | |||
.save = INI_ConfigSaveString, \ | |||
.override = INI_ConfigOverrideString, \ | |||
} | |||
#define INI_CONFIG_DECLARE_TYPE(ID) \ | |||
INI_ConfigTypeLoad INI_ConfigLoad##ID; \ | |||
INI_ConfigTypeSave INI_ConfigSave##ID; \ | |||
INI_ConfigTypeOverride INI_ConfigOverride##ID | |||
#define INI_CONFIG_TRANSFORMER_NONE (INI_ConfigTransformer) { \ | |||
.serialize = NULL, \ | |||
@@ -0,0 +1,93 @@ | |||
#include "int.h" | |||
#define INI_CONFIG_IMPLEMENT_INT_TYPE(ID, T) \ | |||
typedef bool INI_ConfigValidate##ID(T); \ | |||
\ | |||
typedef T INI_ConfigDeserialize##ID(const char*); \ | |||
\ | |||
typedef void INI_ConfigSerialize##ID(T, const char[128]); \ | |||
\ | |||
void INI_ConfigEnsureValid##ID(INI_ConfigItem* item, T raw_value, T default_value) { \ | |||
T* dest = item->dest; \ | |||
if (item->validator) { \ | |||
INI_ConfigValidate##ID* validate = item->validator; \ | |||
if (validate(raw_value)) { \ | |||
*dest = raw_value; \ | |||
return; \ | |||
} \ | |||
*dest = default_value; \ | |||
return; \ | |||
} \ | |||
*dest = raw_value; \ | |||
} \ | |||
\ | |||
void INI_ConfigLoad##ID(INI_ConfigItem* item, const char* config_path) { \ | |||
static T raw_value; \ | |||
static T default_value; \ | |||
default_value = *((T*) item->default_value); \ | |||
if (item->transformer.deserialize && item->transformer.serialize) { \ | |||
INI_ConfigDeserialize##ID* deserialize = item->transformer.deserialize; \ | |||
INI_ConfigSerialize##ID* serialize = item->transformer.serialize; \ | |||
const char serialized_default_value[128]; \ | |||
if (default_value) { \ | |||
serialize(default_value, serialized_default_value); \ | |||
} \ | |||
char buffer[128]; \ | |||
ini_gets(item->section, item->key, serialized_default_value, buffer, 128, config_path); \ | |||
raw_value = deserialize(buffer); \ | |||
} else { \ | |||
raw_value = ini_getl(item->section, item->key, default_value, config_path); \ | |||
} \ | |||
INI_ConfigEnsureValid##ID(item, raw_value, default_value); \ | |||
} \ | |||
\ | |||
INI_ConfigSaveItemResult INI_ConfigSave##ID(INI_ConfigItem* item, const char* config_path) { \ | |||
T dest = *((T*) item->dest); \ | |||
if (item->validator) { \ | |||
INI_ConfigValidate##ID* validate = item->validator; \ | |||
if (!validate(dest)) { \ | |||
dest = *((const T*) item->default_value); \ | |||
} \ | |||
} \ | |||
\ | |||
if (item->transformer.deserialize && item->transformer.serialize) { \ | |||
INI_ConfigSerialize##ID* serialize = item->transformer.serialize; \ | |||
const char serialized_value[128]; \ | |||
serialize(dest, serialized_value); \ | |||
if (!ini_puts(item->section, item->key, serialized_value, config_path)) { \ | |||
return -1; \ | |||
} \ | |||
return 0; \ | |||
} \ | |||
\ | |||
if (!ini_putl(item->section, item->key, dest, config_path)) { \ | |||
return -1; \ | |||
} \ | |||
\ | |||
return 0; \ | |||
} \ | |||
\ | |||
void INI_ConfigOverride##ID(INI_ConfigItem* item, uint8_t argc, const char* argv[]) { \ | |||
if (!item->cmdline_option) { \ | |||
return; \ | |||
} \ | |||
const char* cmdline_buffer; \ | |||
char* rest_of_string; \ | |||
static T dest; \ | |||
static T config_value; \ | |||
config_value = *((T*) item->dest); \ | |||
if ((cmdline_buffer = INI_ConfigGetCommandlineOption(argc, argv, item->cmdline_option))) { \ | |||
dest = strtol(cmdline_buffer, &rest_of_string, 10); \ | |||
if (strcmp(cmdline_buffer, rest_of_string) != 0) { \ | |||
INI_ConfigEnsureValid##ID(item, dest, config_value); \ | |||
return; \ | |||
} \ | |||
} \ | |||
} | |||
INI_CONFIG_IMPLEMENT_INT_TYPE(U8, uint8_t); | |||
INI_CONFIG_IMPLEMENT_INT_TYPE(U16, uint16_t); | |||
INI_CONFIG_IMPLEMENT_INT_TYPE(U32, uint32_t); | |||
INI_CONFIG_IMPLEMENT_INT_TYPE(I8, int8_t); | |||
INI_CONFIG_IMPLEMENT_INT_TYPE(I16, int16_t); | |||
INI_CONFIG_IMPLEMENT_INT_TYPE(I32, int32_t); |
@@ -0,0 +1,54 @@ | |||
#ifndef INI_CONFIG_TYPES_INT_H | |||
#define INI_CONFIG_TYPES_INT_H | |||
#include "ini-config.h" | |||
INI_CONFIG_DECLARE_TYPE(U8); | |||
#define INI_CONFIG_TYPE_U8 (INI_ConfigType) { \ | |||
.size = sizeof(uint8_t), \ | |||
.load = INI_ConfigLoadU8, \ | |||
.save = INI_ConfigSaveU8, \ | |||
.override = INI_ConfigOverrideU8, \ | |||
} | |||
INI_CONFIG_DECLARE_TYPE(U16); | |||
#define INI_CONFIG_TYPE_U16 (INI_ConfigType) { \ | |||
.size = sizeof(uint16_t), \ | |||
.load = INI_ConfigLoadU16, \ | |||
.save = INI_ConfigSaveU16, \ | |||
.override = INI_ConfigOverrideU16, \ | |||
} | |||
INI_CONFIG_DECLARE_TYPE(U32); | |||
#define INI_CONFIG_TYPE_U32 (INI_ConfigType) { \ | |||
.size = sizeof(uint32_t), \ | |||
.load = INI_ConfigLoadU32, \ | |||
.save = INI_ConfigSaveU32, \ | |||
.override = INI_ConfigOverrideU32, \ | |||
} | |||
INI_CONFIG_DECLARE_TYPE(I8); | |||
#define INI_CONFIG_TYPE_I8 (INI_ConfigType) { \ | |||
.size = sizeof(int8_t), \ | |||
.load = INI_ConfigLoadI8, \ | |||
.save = INI_ConfigSaveI8, \ | |||
.override = INI_ConfigOverrideI8, \ | |||
} | |||
INI_CONFIG_DECLARE_TYPE(I16); | |||
#define INI_CONFIG_TYPE_I16 (INI_ConfigType) { \ | |||
.size = sizeof(int16_t), \ | |||
.load = INI_ConfigLoadI16, \ | |||
.save = INI_ConfigSaveI16, \ | |||
.override = INI_ConfigOverrideI16, \ | |||
} | |||
INI_CONFIG_DECLARE_TYPE(I32); | |||
#define INI_CONFIG_TYPE_I32 (INI_ConfigType) { \ | |||
.size = sizeof(int32_t), \ | |||
.load = INI_ConfigLoadI32, \ | |||
.save = INI_ConfigSaveI32, \ | |||
.override = INI_ConfigOverrideI32, \ | |||
} | |||
#endif |
@@ -0,0 +1,99 @@ | |||
#include "string.h" | |||
typedef bool INI_ConfigLoadParamsStringValidator(const char*); | |||
void INI_ConfigEnsureValidString(INI_ConfigItem* item, const char* buffer) { | |||
if (item->validator) { | |||
INI_ConfigLoadParamsStringValidator* validator = item->validator; | |||
if (validator(buffer)) { | |||
memcpy(item->dest, buffer, item->type.size); | |||
return; | |||
} | |||
memcpy(item->dest, item->default_value, item->type.size); | |||
return; | |||
} | |||
memcpy(item->dest, buffer, item->type.size); | |||
} | |||
void INI_ConfigLoadString(INI_ConfigItem* item, const char* config_path) { | |||
char buffer[item->type.size]; | |||
ini_gets(item->section, item->key, item->default_value, buffer, (int32_t) item->type.size, config_path); | |||
INI_ConfigEnsureValidString(item, buffer); | |||
} | |||
INI_ConfigSaveItemResult INI_ConfigSaveString(INI_ConfigItem* item, const char* config_path) { | |||
const char* dest = (const char*) item->dest; | |||
if (item->validator) { | |||
INI_ConfigLoadParamsStringValidator* validator = item->validator; | |||
if (!validator(dest)) { | |||
dest = (const char*) item->default_value; | |||
} | |||
} | |||
if (!ini_puts(item->section, item->key, dest, config_path)) { | |||
return INI_CONFIG_SAVE_ITEM_ERROR; | |||
} | |||
return INI_CONFIG_SAVE_ITEM_OK; | |||
} | |||
void INI_ConfigOverrideString(INI_ConfigItem* item, uint8_t argc, const char* argv[]) { | |||
if (!item->cmdline_option) { | |||
return; | |||
} | |||
const char* cmdline_buffer; | |||
if ((cmdline_buffer = INI_ConfigGetCommandlineOption(argc, argv, item->cmdline_option))) { | |||
INI_ConfigEnsureValidString(item, cmdline_buffer); | |||
} | |||
} | |||
void INI_ConfigLoad(INI_ConfigItem item[], const char* config_path) { | |||
uint8_t i; | |||
for (i = 0; item[i].type.size > 0; i += 1) { | |||
if (!item[i].type.load) { | |||
continue; | |||
} | |||
item[i].type.load(&item[i], config_path); | |||
} | |||
} | |||
INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem item[], const char* config_path) { | |||
uint8_t i; | |||
int32_t problems = 0; | |||
for (i = 0; item[i].type.size > 0; i += 1) { | |||
int32_t result = item[i].type.save ? item[i].type.save(&item[i], config_path) : 0; | |||
if (result < 0) { | |||
problems |= (1 << (int32_t) i); | |||
} | |||
} | |||
return -problems; | |||
} | |||
void INI_ConfigOverride(INI_ConfigItem item[], uint8_t argc, const char* argv[]) { | |||
uint8_t i; | |||
for (i = 0; item[i].type.size > 0; i += 1) { | |||
if (!item[i].type.override) { | |||
continue; | |||
} | |||
item[i].type.override(&item[i], argc, argv); | |||
// TODO specify command-line arg external from config item? | |||
} | |||
} | |||
INI_ConfigInitializeResult INI_ConfigInitialize(INI_ConfigItem item[], const char* config_path, uint8_t argc, const char* argv[]) { | |||
INI_ConfigLoad(item, config_path); | |||
INI_ConfigSaveResult save_result = INI_ConfigSave(item, config_path); | |||
if (save_result < 0) { | |||
return INI_CONFIG_INITIALIZE_RESULT_ERROR; | |||
} | |||
INI_ConfigOverride(item, argc, argv); | |||
if (save_result > 0) { | |||
return INI_CONFIG_INITIALIZE_RESULT_WARNING; | |||
} | |||
return INI_CONFIG_INITIALIZE_RESULT_OK; | |||
} |
@@ -0,0 +1,14 @@ | |||
#ifndef INI_CONFIG_TYPES_STRING_H | |||
#define INI_CONFIG_TYPES_STRING_H | |||
#include "ini-config.h" | |||
INI_CONFIG_DECLARE_TYPE(String); | |||
#define INI_CONFIG_TYPE_STRING(X) (INI_ConfigType) { \ | |||
.size = (sizeof(char) * X), \ | |||
.load = INI_ConfigLoadString, \ | |||
.save = INI_ConfigSaveString, \ | |||
.override = INI_ConfigOverrideString, \ | |||
} | |||
#endif |