From 2de58233c4865956b2b8e8d81bf18c221461093a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=A1k?= Date: Thu, 30 Jan 2025 17:08:42 +0100 Subject: [PATCH] new ini support proposal --- platform/CMakeLists.txt | 11 ++- platform/config.cpp | 170 ++++++++++++++++++++++++++++++++++++++++ platform/config.h | 97 +++++++++++++++++++++++ skeldal.ini | 42 ++++++++++ 4 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 platform/config.cpp create mode 100644 platform/config.h create mode 100644 skeldal.ini diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index 1d1b2f6..576dd1d 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -1,7 +1,14 @@ -SET(files error.cpp legacy_coroutines.cpp platform.cpp int2ascii.c istr.c file_access.cpp) +SET(files error.cpp + legacy_coroutines.cpp + platform.cpp + int2ascii.c + istr.c + file_access.cpp + config.cpp +) add_library(skeldal_platform_libs ${files}) set_property(TARGET skeldal_platform_libs PROPERTY CXX_STANDARD 20) add_subdirectory(sdl) -add_subdirectory(linux) \ No newline at end of file +add_subdirectory(linux) diff --git a/platform/config.cpp b/platform/config.cpp new file mode 100644 index 0000000..1eaa900 --- /dev/null +++ b/platform/config.cpp @@ -0,0 +1,170 @@ +#include "config.h" +#include "platform.h" +#include +#include +#include +#include +typedef struct ini_config_tag { + + using Section = std::map>; + using Config = std::map>; + Config data; + +} INI_CONFIG; + + + +// Trim whitespace z obou stran pro string_view +static inline std::string_view trim(std::string_view str) { + const size_t first = str.find_first_not_of(" \t"); + if (first == std::string_view::npos) return {}; + const size_t last = str.find_last_not_of(" \t"); + return str.substr(first, last - first + 1); +} + +// Parser INI souboru +template Callback > +void parseIniStream(std::istream& input, Callback &&callback) { + std::string line; + std::string currentSection; + + while (std::getline(input, line)) { + std::string_view line_view = trim(line); + + // Ignoruj prázdné řádky nebo komentáře + if (line_view.empty() || line_view.front() == '#') continue; + + // Detekce sekce [sekce] + if (line_view.front() == '[' && line_view.back() == ']') { + currentSection = std::string(trim(line_view.substr(1, line_view.size() - 2))); + } else { + // Zpracuj klíč = hodnota + size_t eqPos = line_view.find('='); + if (eqPos != std::string_view::npos) { + std::string_view key_view = trim(line_view.substr(0, eqPos)); + std::string_view value_view = trim(line_view.substr(eqPos + 1)); + callback(currentSection, std::string(key_view), std::string(value_view)); + } + } + } +} + + +const INI_CONFIG* ini_open(const char *filename) { + INI_CONFIG *c = new INI_CONFIG; + + std::fstream input(filename); + if (!input) return c; + parseIniStream(input, [&](std::string_view section, std::string_view key, std::string_view value) { + INI_CONFIG::Config::iterator iter = c->data.find(section); + if (iter == c->data.end()) { + iter = c->data.emplace(std::string(section), INI_CONFIG::Section()).first; + } + iter->second.emplace(std::string(key), std::string(value)); + }); + return c; +} + +void ini_close(const INI_CONFIG *config) { + delete config; +} + +const INI_CONFIG_SECTION* ini_section_open(const INI_CONFIG *cfg, const char *section) { + auto iter = cfg->data.find(std::string_view(section)); + if (iter == cfg->data.end()) return NULL; + else return reinterpret_cast(&iter->second); +} + +const char* ini_find_key(const INI_CONFIG_SECTION *section, + const char *key) { + if (section == NULL) return NULL; + const INI_CONFIG::Section *s = reinterpret_cast(section); + auto iter = s->find(std::string_view(key)); + if (iter == s->end()) return NULL; + return iter->second.c_str(); +} + + +long ini_get_value_int(const char *value, int *conv_ok) { + char *out = NULL; + if (value != NULL) { + long ret = strtol(value, &out, 10); + if (*out == 0) { + if (*conv_ok) *conv_ok = 1; + return ret; + } + } + if (*conv_ok) *conv_ok = 0; + return -1; + +} + +double ini_get_value_double(const char *value, int *conv_ok) { + char *out = NULL; + if (value != NULL) { + double ret = strtod(value, &out); + if (*out == 0) { + if (*conv_ok) *conv_ok = 1; + return ret; + } + } + if (*conv_ok) *conv_ok = 0; + return -1; +} + +int ini_get_value_boolean(const char *value) { + int r = -1; + if (value != NULL) { + if (stricmp(value, "true") == 0 + || stricmp(value, "1") == 0 + || stricmp(value, "on") == 0 + || stricmp(value, "yes") == 0) { + r = 1; + } else if (stricmp(value, "false") == 0 + || stricmp(value, "0") == 0 + || stricmp(value, "off") == 0 + || stricmp(value, "no") == 0) { + r = 0; + } else { + r = -1; + } + } + return r; +} + +const char* ini_get_string( + const INI_CONFIG_SECTION *section, const char *key, const char *defval) { + const char *k = ini_find_key(section, key); + return k?k:defval; +} + +long ini_get_int(const INI_CONFIG_SECTION *section, const char *key, long defval) { + const char *k = ini_find_key(section, key); + if (k) { + int ok; + long r = ini_get_value_int(k, &ok); + return ok?r:defval; + } + return defval; +} + +int ini_get_double(const INI_CONFIG_SECTION *section, const char *key, + double defval) { + const char *k = ini_find_key(section, key); + if (k) { + int ok; + double r = ini_get_value_double(k, &ok); + return ok?r:defval; + } + return defval; +} + +int ini_get_boolean(const INI_CONFIG_SECTION *section, const char *key, + int defval) { + const char *k = ini_find_key(section, key); + if (k) { + int r = ini_get_value_boolean(k); + return r>=0?r:defval; + } + return defval; +} diff --git a/platform/config.h b/platform/config.h new file mode 100644 index 0000000..fb9456c --- /dev/null +++ b/platform/config.h @@ -0,0 +1,97 @@ +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct ini_config_tag INI_CONFIG; +typedef struct ini_config_section_tag INI_CONFIG_SECTION; + +///Opens config, returns handle +const INI_CONFIG *ini_open(const char *filename); +///closes the config and frees memory +void ini_close(const INI_CONFIG *config); + +///Opens section +/** + * + * @param cfg ini config + * @param section section name + * @return if section exists, return handle to section otherwise returns NULL. + * The section don't need to be closed, however it is tied to INI_CONFIG handle, so + * one the config is closed, the section becomes invalid + */ +const INI_CONFIG_SECTION *ini_section_open(const INI_CONFIG *cfg, const char *section); +///Finds key in section +/** + * @param section handle to section + * @param key name of key + * @return handle of key if found, or NULL if not. The returned pointer points + * to string representation of the value (so you can use it as string value) + */ +const char *ini_find_key(const INI_CONFIG_SECTION *section, const char *key); +///retrieves value as integer +/** + * @param value found value + * @param conv_error (optional, can be NULL) - retrieves 1 if conversion succes, 0 if failed + * @return if conversion successed, returns value, otherwise returns -1 + */ +long ini_get_value_int(const char *value, int *conv_ok); +///retrieves value as double +/** + * @param value found value + * @param conv_error (optional, can be NULL) - retrieves 1 if conversion succes, 0 if failed + * @return if conversion successed, returns value, otherwise returns -1 + */ +double ini_get_value_double(const char *value, int *conv_ok); +///retrieves value as boolean +/** + * @param value found value + * @param conv_error (optional, can be NULL) - retrieves 1 if conversion succes, 0 if failed + * @retval 1 value is true, nonzero, yes or on + * @retval 0 value is false, zero, no, or off + * @retval -1 cannot convert value + * + */ +int ini_get_value_boolean(const char *value); + + +///retrieve string from ini +/** + * @param section section + * @param key key + * @param defval default value + * @return if key doesn't exits or parse error, returns defval, otherwise returns value + */ +const char *ini_get_string(const INI_CONFIG_SECTION *section, const char *key, const char *defval); +///retrieve int from ini +/** + * @param section section + * @param key key + * @param defval default value + * @return if key doesn't exits or parse error, returns defval, otherwise returns value + */ +long ini_get_int(const INI_CONFIG_SECTION *section, const char *key, long defval); +///retrieve double from ini +/** + * @param section section + * @param key key + * @param defval default value + * @return if key doesn't exits or parse error, returns defval, otherwise returns value + */ +int ini_get_double(const INI_CONFIG_SECTION *section, const char *key, double defval); +///retrieve boolean from ini +/** + * @param section section + * @param key key + * @param defval default value + * @return if key doesn't exits or parse error, returns defval, otherwise returns value + */ +int ini_get_boolean(const INI_CONFIG_SECTION *section, const char *key, int defval); + + + + + +#ifdef __cplusplus +} +#endif diff --git a/skeldal.ini b/skeldal.ini new file mode 100644 index 0000000..a1c71a6 --- /dev/null +++ b/skeldal.ini @@ -0,0 +1,42 @@ +##### path +# +# game_path = path to root of the game +# maps = relative path to maps +# video = relative path to videp +# data = relative path to skeldal.ddl +# savegame = path to savegame, if not defined, retrieved from platform settings + + +[path] +game_path=/home/ondra/skeldal_game/ +# maps=./maps/ +# video=./video/ +# data=./ +# savegame = determine default + + +#### video settings +# +# fullscreen = run game in fullscreen mode +# window_width = set window with (in windowed mode) +# window_height = set window height (in windowed mode) +# crt_filter = enable filter simmulates lowres CRT monitor for higher resolution +# composer = auto - choose best supported driver +# hardware,hw - use hardware for composition +# software,sw - use software for composition +# scale_quality = auto - best for hardware composer, nearest for software comporser +# best - best scale quality (SDL = linear) +# linear - use linear filtering (Direct3D and OpenGL) +# nearest - use nearest filtering +# +[video] +fullscreen=on +#window_width=640 +#window_height=480 +#crt_filter=on +#smooth_scale=auto +#composer=auto +#scale_quality + + +[audio] \ No newline at end of file