15std::map<std::string, std::string, std::less<>>
settings;
17std::string_view
trim(std::string_view text)
19 const auto is_space = [](
char c) {
return std::isspace(
static_cast<unsigned char>(c)) != 0; };
20 while (!text.empty() && is_space(text.front())) {
21 text.remove_prefix(1);
23 while (!text.empty() && is_space(text.back())) {
24 text.remove_suffix(1);
29std::string
lower(std::string_view text)
31 std::string result(text);
32 std::ranges::transform(result, result.begin(),
33 [](
char c) { return static_cast<char>(std::tolower(static_cast<unsigned char>(c))); });
37void parse(std::string_view text,
const std::string& path)
40 while (!text.empty()) {
41 const auto end = text.find(
'\n');
42 const auto raw = text.substr(0, end);
43 text = end == std::string_view::npos ? std::string_view { } : text.substr(end + 1);
46 const auto line =
trim(raw);
47 if (line.empty() || line.front() ==
'#' || line.front() ==
';') {
51 const auto equals = line.find(
'=');
52 const auto key =
trim(line.substr(0, equals));
53 if (equals == std::string_view::npos || key.empty()) {
54 asw::log::warn(
"{}:{}: ignoring line, use key = value", path, line_number);
58 const auto value =
trim(line.substr(equals + 1));
59 settings.insert_or_assign(std::string(key), std::string(value));
70 if (path !=
nullptr && *path !=
'\0') {
83 void* data = SDL_LoadFile(path.c_str(), &size);
84 if (data ==
nullptr) {
85 asw::log::warn(
"Could not read config {}: {}", path, SDL_GetError());
89 parse(std::string_view(
static_cast<const char*
>(data), size), path);
115 const auto v =
lower(*value);
116 if (v ==
"1" || v ==
"true" || v ==
"yes" || v ==
"on") {
119 if (v ==
"0" || v ==
"false" || v ==
"no" || v ==
"off") {
123 asw::log::warn(
"Ignoring config {} = {}, use true or false", key, *value);
136 const long parsed = std::strtol(value->c_str(), &end, 10);
137 if (value->empty() || *end !=
'\0' || errno == ERANGE || parsed < INT_MIN || parsed > INT_MAX) {
138 asw::log::warn(
"Ignoring config {} = {}, use a whole number", key, *value);
142 return static_cast<int>(parsed);
154 const float parsed = std::strtof(value->c_str(), &end);
155 if (value->empty() || *end !=
'\0' || errno == ERANGE) {
156 asw::log::warn(
"Ignoring config {} = {}, use a number", key, *value);
Settings from a config file, set by whoever runs the game.
Structured logging system.
std::map< std::string, std::string, std::less<> > settings
std::string_view trim(std::string_view text)
void parse(std::string_view text, const std::string &path)
std::string lower(std::string_view text)
void _shutdown()
Remove all settings. Called by asw::core::shutdown().
std::optional< std::string > get_string(const std::string &key)
Get a setting as text.
constexpr const char * PATH_VARIABLE
Name of the environment variable that holds the config file path.
std::optional< float > get_float(const std::string &key)
Get a setting as a number.
bool has(const std::string &key)
Check if a setting is set.
std::optional< int > get_int(const std::string &key)
Get a setting as a whole number.
bool load(const std::string &path)
Load settings from a file. Settings already loaded stay, unless the file sets them again.
void _init()
Load the file named by ASW_CONFIG, if it is set. Called by asw::core::init() before the window opens.
std::optional< bool > get_bool(const std::string &key)
Get a setting as true or false. 1, true, yes and on are true. 0, false, no and off are false....
void info(const std::string &message)
Log an info message.
void warn(const std::string &message)
Log a warning message.