@@ -7,6 +7,10 @@ include_directories( | |||||
"${CMAKE_HOME_DIRECTORY}/subprojects/minIni/dev" | "${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; | 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 <stdbool.h> | ||||
#include <minIni.h> | #include <minIni.h> | ||||
/** | |||||
* Struct for transformer functions used for properly loading and saving the config item's value. | |||||
*/ | |||||
typedef struct { | typedef struct { | ||||
/** | |||||
* Function that formats the value from memory to a value that is write-friendly to the config file. | |||||
*/ | |||||
void* serialize; | void* serialize; | ||||
/** | |||||
* Function that formats the value from file to a value that is read-friendly to memory. | |||||
*/ | |||||
void* deserialize; | void* deserialize; | ||||
} INI_ConfigTransformer; | |||||
} INI_ConfigTransformer; // TODO: should we unify this with INI_ConfigType? | |||||
struct INI_ConfigItem; | struct INI_ConfigItem; | ||||
/** | |||||
* Function for loading a config item value from file to memory. | |||||
*/ | |||||
typedef void INI_ConfigTypeLoad(struct INI_ConfigItem*, const char*); | typedef void INI_ConfigTypeLoad(struct INI_ConfigItem*, const char*); | ||||
/** | |||||
* Result enum for saving config items. | |||||
*/ | |||||
typedef enum { | typedef enum { | ||||
/** | |||||
* Result returned when saving a config item was not successful. | |||||
*/ | |||||
INI_CONFIG_SAVE_ITEM_ERROR = -1, | INI_CONFIG_SAVE_ITEM_ERROR = -1, | ||||
/** | |||||
* Result returned when saving a config item was successful. | |||||
*/ | |||||
INI_CONFIG_SAVE_ITEM_OK, | INI_CONFIG_SAVE_ITEM_OK, | ||||
} INI_ConfigSaveItemResult; | } INI_ConfigSaveItemResult; | ||||
/** | |||||
* Function for saving a config item value from memory to file. | |||||
*/ | |||||
typedef INI_ConfigSaveItemResult INI_ConfigTypeSave(struct INI_ConfigItem*, const char*); | 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*[]); | typedef void INI_ConfigTypeOverride(struct INI_ConfigItem*, uint8_t, const char*[]); | ||||
/** | |||||
* Struct for the config item type. | |||||
*/ | |||||
typedef struct { | typedef struct { | ||||
/** | |||||
* Size of the corresponding in-memory value of the config item. | |||||
*/ | |||||
size_t size; | size_t size; | ||||
/** | |||||
* Load function. | |||||
* @see INI_ConfigTypeLoad | |||||
*/ | |||||
INI_ConfigTypeLoad* load; | INI_ConfigTypeLoad* load; | ||||
/** | |||||
* Save function. | |||||
* @see INI_ConfigTypeSave | |||||
*/ | |||||
INI_ConfigTypeSave* save; | INI_ConfigTypeSave* save; | ||||
/** | |||||
* Override function. | |||||
* @see INI_ConfigTypeOverride | |||||
*/ | |||||
INI_ConfigTypeOverride* override; | INI_ConfigTypeOverride* override; | ||||
} INI_ConfigType; | } 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 { | typedef struct INI_ConfigItem { | ||||
/** | |||||
* Type of the config item. | |||||
*/ | |||||
INI_ConfigType type; | INI_ConfigType type; | ||||
/** | |||||
* Section where this config item can be found. | |||||
*/ | |||||
const char* section; | const char* section; | ||||
/** | |||||
* Key where this config item value is serialized and stored. | |||||
*/ | |||||
const char* key; | 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; | const void* default_value; | ||||
/** | |||||
* Validator function for the config item's value. | |||||
*/ | |||||
void* validator; | void* validator; | ||||
/** | |||||
* Transformer functions. | |||||
* @see INI_ConfigTransformer | |||||
*/ | |||||
INI_ConfigTransformer transformer; | 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; | void* dest; | ||||
} INI_ConfigItem; | } 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*); | const char* INI_ConfigGetCommandlineOption(uint8_t, const char*[], const char*); | ||||
/** | |||||
* Result enum for initializing config items. | |||||
*/ | |||||
typedef enum { | typedef enum { | ||||
/** | |||||
* Result returned when initializing all config items was not successful. | |||||
*/ | |||||
INI_CONFIG_INITIALIZE_RESULT_ERROR = -1, | INI_CONFIG_INITIALIZE_RESULT_ERROR = -1, | ||||
/** | |||||
* Result returned when initializing all config items was successful. | |||||
*/ | |||||
INI_CONFIG_INITIALIZE_RESULT_OK, | INI_CONFIG_INITIALIZE_RESULT_OK, | ||||
/** | |||||
* Result returned when initializing some config items was successful. | |||||
*/ | |||||
INI_CONFIG_INITIALIZE_RESULT_WARNING | INI_CONFIG_INITIALIZE_RESULT_WARNING | ||||
} INI_ConfigInitializeResult; | } INI_ConfigInitializeResult; | ||||
@@ -58,78 +148,10 @@ typedef int32_t INI_ConfigSaveResult; | |||||
INI_ConfigSaveResult INI_ConfigSave(INI_ConfigItem[], const char*); | 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) { \ | #define INI_CONFIG_TRANSFORMER_NONE (INI_ConfigTransformer) { \ | ||||
.serialize = NULL, \ | .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 |