#include "IZ_config.h" const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const char* val) { size_t n = strlen(val); int c = argc; while (--c > 0) { if (!strncmp(argv[c], val, n)) { if (!*(argv[c] + n) && c < argc - 1) { /* coverity treats unchecked argv as "tainted" */ if (!argv[c + 1] || strlen(argv[c + 1]) > 1024) return NULL; return argv[c + 1]; } if (argv[c][n] == '=') return &argv[c][n + 1]; return argv[c] + n; } } return NULL; } typedef bool IZ_ConfigLoadParamsStringValidator(const char*); typedef bool IZ_ConfigLoadParamsU16Validator(u16); typedef bool IZ_ConfigLoadParamsU8Validator(u8); void IZ_ConfigEnsureValidString(IZ_ConfigItem item, const char* buffer) { char dest[item.dest_size]; if (item.validator) { IZ_ConfigLoadParamsStringValidator* validator = item.validator; if (validator(buffer)) { memcpy_s(dest, item.dest_size, buffer, item.dest_size); item.dest = &dest; return; } memcpy_s(dest, item.dest_size, item.default_value, item.dest_size); item.dest = &dest; return; } memcpy_s(dest, item.dest_size, buffer, item.dest_size); item.dest = &dest; } void IZ_ConfigLoadString(IZ_ConfigItem item, const char* config_path) { char buffer[item.dest_size]; ini_gets(item.section, item.key, item.default_value, buffer, (i32) item.dest_size, config_path); IZ_ConfigEnsureValidString(item, buffer); } void IZ_ConfigEnsureValidU8(IZ_ConfigItem item, u8 raw_value, u8 default_value) { if (item.validator) { IZ_ConfigLoadParamsU8Validator* validator = item.validator; if (validator(raw_value)) { item.dest = &raw_value; return; } item.dest = &default_value; return; } item.dest = &raw_value; } void IZ_ConfigLoadU8(IZ_ConfigItem item, const char* config_path) { static u8 raw_value; static u8 default_value; default_value = *((u8*) item.default_value); raw_value = ini_getl(item.section, item.key, default_value, config_path); IZ_ConfigEnsureValidU8(item, raw_value, default_value); } void IZ_ConfigEnsureValidU16(IZ_ConfigItem item, u16 raw_value, u16 default_value) { if (item.validator) { IZ_ConfigLoadParamsU16Validator* validator = item.validator; if (validator(raw_value)) { item.dest = &raw_value; return; } item.dest = &default_value; return; } item.dest = &raw_value; } void IZ_ConfigLoadU16(IZ_ConfigItem item, const char* config_path) { static u16 raw_value; static u16 default_value; default_value = *((u16*) item.default_value); raw_value = ini_getl(item.section, item.key, default_value, config_path); IZ_ConfigEnsureValidU16(item, raw_value, default_value); } void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) { u8 i; for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) { switch (item[i].type) { case IZ_CONFIG_TYPE_STRING: IZ_ConfigLoadString(item[i], config_path); break; case IZ_CONFIG_TYPE_U8: IZ_ConfigLoadU8(item[i], config_path); break; case IZ_CONFIG_TYPE_U16: IZ_ConfigLoadU16(item[i], config_path); break; default: break; } } } IZ_ProcedureResult IZ_ConfigSaveU8(IZ_ConfigItem item, const char* config_path) { u8 dest = *((u8*) item.dest); if (item.validator) { IZ_ConfigLoadParamsU8Validator* validator = item.validator; if (!validator(dest)) { dest = *((const u8*) item.default_value); } } if (!ini_putl(item.section, item.key, dest, config_path)) { return -1; } return 0; } IZ_ProcedureResult IZ_ConfigSaveU16(IZ_ConfigItem item, const char* config_path) { u16 dest = *((u16*) item.dest); if (item.validator) { IZ_ConfigLoadParamsU8Validator* validator = item.validator; if (!validator(dest)) { dest = *((const u16*) item.default_value); } } if (!ini_putl(item.section, item.key, dest, config_path)) { return -1; } return 0; } IZ_ProcedureResult IZ_ConfigSaveString(IZ_ConfigItem item, const char* config_path) { const char* dest = (const char*) item.dest; if (item.validator) { IZ_ConfigLoadParamsStringValidator* validator = item.validator; if (!validator(dest)) { dest = (const char*) item.default_value; } } if (!ini_puts(item.section, item.key, dest, config_path)) { return -1; } return 0; } IZ_ProcedureResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path) { u8 i; u16 problems = 0; for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) { switch (item[i].type) { case IZ_CONFIG_TYPE_STRING: IZ_ConfigSaveString(item[i], config_path); break; case IZ_CONFIG_TYPE_U8: IZ_ConfigSaveU8(item[i], config_path); break; case IZ_CONFIG_TYPE_U16: IZ_ConfigSaveU16(item[i], config_path); break; default: break; } } return -problems; } void IZ_ConfigOverrideU8(IZ_ConfigItem item, u8 argc, const char* argv[]) { if (!item.cmdline_option) { return; } const char* cmdline_buffer; char* rest_of_string; static u8 dest; static u8 default_value; default_value = *((u16*) item.default_value); if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item.cmdline_option))) { dest = strtol(cmdline_buffer, &rest_of_string, 10); if (strcmp(cmdline_buffer, rest_of_string) != 0) { IZ_ConfigEnsureValidU8(item, dest, default_value); return; } item.dest = &default_value; } } void IZ_ConfigOverrideU16(IZ_ConfigItem item, u8 argc, const char* argv[]) { if (!item.cmdline_option) { return; } const char* cmdline_buffer; char* rest_of_string; static u16 dest; static u16 default_value; default_value = *((u16*) item.default_value); if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item.cmdline_option))) { dest = strtol(cmdline_buffer, &rest_of_string, 10); if (strcmp(cmdline_buffer, rest_of_string) != 0) { IZ_ConfigEnsureValidU16(item, dest, default_value); return; } item.dest = &default_value; } } void IZ_ConfigOverrideString(IZ_ConfigItem item, u8 argc, const char* argv[]) { if (!item.cmdline_option) { return; } const char* cmdline_buffer; if ((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item.cmdline_option))) { IZ_ConfigEnsureValidString(item, cmdline_buffer); } } void IZ_ConfigOverride(IZ_ConfigItem item[], u8 argc, const char* argv[]) { u8 i; for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) { switch (item[i].type) { case IZ_CONFIG_TYPE_U8: IZ_ConfigOverrideU8(item[i], argc, argv); break; case IZ_CONFIG_TYPE_U16: IZ_ConfigOverrideU16(item[i], argc, argv); break; case IZ_CONFIG_TYPE_STRING: IZ_ConfigOverrideString(item[i], argc, argv); break; default: break; } } } void IZ_ConfigInit(IZ_ConfigItem item[], const char* config_path, u8 argc, const char* argv[]) { IZ_ConfigLoad(item, config_path); if (IZ_ConfigSave(item, config_path)) { // TODO log errors in saving } IZ_ConfigOverride(item, argc, argv); }