diff --git a/src/LogInit.cxx b/src/LogInit.cxx index 7154c40d6..66add54e6 100644 --- a/src/LogInit.cxx +++ b/src/LogInit.cxx @@ -93,7 +93,7 @@ log_init_file(int line) } static inline LogLevel -parse_log_level(const char *value, int line) +parse_log_level(const char *value) { if (0 == strcmp(value, "default")) return LogLevel::DEFAULT; @@ -102,8 +102,7 @@ parse_log_level(const char *value, int line) else if (0 == strcmp(value, "verbose")) return LogLevel::DEBUG; else - throw FormatRuntimeError("unknown log level \"%s\" at line %d", - value, line); + throw FormatRuntimeError("unknown log level \"%s\"", value); } #endif @@ -132,9 +131,12 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout) #else if (verbose) SetLogThreshold(LogLevel::DEBUG); - else if (const auto ¶m = config.GetParam(ConfigOption::LOG_LEVEL)) - SetLogThreshold(parse_log_level(param->value.c_str(), - param->line)); + else + SetLogThreshold(config.With(ConfigOption::LOG_LEVEL, [](const char *s){ + return s != nullptr + ? parse_log_level(s) + : LogLevel::DEFAULT; + })); if (use_stdout) { out_fd = STDOUT_FILENO; diff --git a/src/Main.cxx b/src/Main.cxx index 7e3b1fcf4..d60018e8f 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -282,20 +282,23 @@ initialize_decoder_and_player(Instance &instance, size_t buffer_size; param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE); if (param != nullptr) { - char *test; - long tmp = strtol(param->value.c_str(), &test, 10); - if (*test != '\0' || tmp <= 0 || tmp == LONG_MAX) - throw FormatRuntimeError("buffer size \"%s\" is not a " - "positive integer, line %i", - param->value.c_str(), param->line); - buffer_size = tmp * KILOBYTE; + buffer_size = param->With([](const char *s){ + char *test; + long tmp = strtol(s, &test, 10); + if (*test != '\0' || tmp <= 0 || tmp == LONG_MAX) + throw FormatRuntimeError("buffer size \"%s\" is not a " + "positive integer", s); + size_t result = tmp * KILOBYTE; - if (buffer_size < MIN_BUFFER_SIZE) { - FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead", - (unsigned long)buffer_size, - (unsigned long)MIN_BUFFER_SIZE); - buffer_size = MIN_BUFFER_SIZE; - } + if (result < MIN_BUFFER_SIZE) { + FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead", + (unsigned long)result, + (unsigned long)MIN_BUFFER_SIZE); + result = MIN_BUFFER_SIZE; + } + + return result; + }); } else buffer_size = DEFAULT_BUFFER_SIZE; @@ -309,17 +312,12 @@ initialize_decoder_and_player(Instance &instance, config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH, DEFAULT_PLAYLIST_MAX_LENGTH); - AudioFormat configured_audio_format = AudioFormat::Undefined(); - param = config.GetParam(ConfigOption::AUDIO_OUTPUT_FORMAT); - if (param != nullptr) { - try { - configured_audio_format = ParseAudioFormat(param->value.c_str(), - true); - } catch (...) { - std::throw_with_nested(FormatRuntimeError("error parsing line %i", - param->line)); - } - } + AudioFormat configured_audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){ + if (s == nullptr) + return AudioFormat::Undefined(); + + return ParseAudioFormat(s, true); + }); instance.partitions.emplace_back(instance, "default", @@ -329,15 +327,11 @@ initialize_decoder_and_player(Instance &instance, replay_gain_config); auto &partition = instance.partitions.back(); - try { - param = config.GetParam(ConfigOption::REPLAYGAIN); - if (param != nullptr) - partition.replay_gain_mode = - FromString(param->value.c_str()); - } catch (...) { - std::throw_with_nested(FormatRuntimeError("Failed to parse line %i", - param->line)); - } + partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){ + return s != nullptr + ? FromString(s) + : ReplayGainMode::OFF; + }); } inline void diff --git a/src/Permission.cxx b/src/Permission.cxx index 6e613dcc1..15dc5b263 100644 --- a/src/Permission.cxx +++ b/src/Permission.cxx @@ -82,44 +82,39 @@ static unsigned parsePermissions(const char *string) void initPermissions(const ConfigData &config) { - unsigned permission; - permission_default = PERMISSION_READ | PERMISSION_ADD | PERMISSION_CONTROL | PERMISSION_ADMIN; for (const auto ¶m : config.GetParamList(ConfigOption::PASSWORD)) { permission_default = 0; - const char *separator = strchr(param.value.c_str(), - PERMISSION_PASSWORD_CHAR); + param.With([](const char *value){ + const char *separator = strchr(value, + PERMISSION_PASSWORD_CHAR); - if (separator == NULL) - throw FormatRuntimeError("\"%c\" not found in password string " - "\"%s\", line %i", - PERMISSION_PASSWORD_CHAR, - param.value.c_str(), - param.line); + if (separator == NULL) + throw FormatRuntimeError("\"%c\" not found in password string", + PERMISSION_PASSWORD_CHAR); - std::string password(param.value.c_str(), separator); + std::string password(value, separator); - permission = parsePermissions(separator + 1); - - permission_passwords.insert(std::make_pair(std::move(password), - permission)); + unsigned permission = parsePermissions(separator + 1); + permission_passwords.insert(std::make_pair(std::move(password), + permission)); + }); } - const ConfigParam *param; - param = config.GetParam(ConfigOption::DEFAULT_PERMS); - - if (param) - permission_default = parsePermissions(param->value.c_str()); + config.With(ConfigOption::DEFAULT_PERMS, [](const char *value){ + if (value != nullptr) + permission_default = parsePermissions(value); + }); #ifdef HAVE_UN - param = config.GetParam(ConfigOption::LOCAL_PERMISSIONS); - if (param != nullptr) - local_permissions = parsePermissions(param->value.c_str()); - else - local_permissions = permission_default; + local_permissions = config.With(ConfigOption::LOCAL_PERMISSIONS, [](const char *value){ + return value != nullptr + ? parsePermissions(value) + : permission_default; + }); #endif } diff --git a/src/ReplayGainGlobal.cxx b/src/ReplayGainGlobal.cxx index 56aaa7890..a45b84d99 100644 --- a/src/ReplayGainGlobal.cxx +++ b/src/ReplayGainGlobal.cxx @@ -43,29 +43,22 @@ ParsePreamp(const char *s) return pow(10, f / 20.0); } -static float -ParsePreamp(const ConfigParam &p) -{ - try { - return ParsePreamp(p.value.c_str()); - } catch (...) { - std::throw_with_nested(FormatRuntimeError("Failed to parse line %i", - p.line)); - } -} - ReplayGainConfig LoadReplayGainConfig(const ConfigData &config) { ReplayGainConfig replay_gain_config; - const auto *param = config.GetParam(ConfigOption::REPLAYGAIN_PREAMP); - if (param) - replay_gain_config.preamp = ParsePreamp(*param); + replay_gain_config.preamp = config.With(ConfigOption::REPLAYGAIN_PREAMP, [](const char *s){ + return s != nullptr + ? ParsePreamp(s) + : 1.0; + }); - param = config.GetParam(ConfigOption::REPLAYGAIN_MISSING_PREAMP); - if (param) - replay_gain_config.missing_preamp = ParsePreamp(*param); + replay_gain_config.missing_preamp = config.With(ConfigOption::REPLAYGAIN_MISSING_PREAMP, [](const char *s){ + return s != nullptr + ? ParsePreamp(s) + : 1.0; + }); replay_gain_config.limit = config.GetBool(ConfigOption::REPLAYGAIN_LIMIT, ReplayGainConfig::DEFAULT_LIMIT); diff --git a/src/config/Data.hxx b/src/config/Data.hxx index 3e0495ad3..0eb6594be 100644 --- a/src/config/Data.hxx +++ b/src/config/Data.hxx @@ -54,6 +54,14 @@ struct ConfigData { return list.empty() ? nullptr : &list.front(); } + template + auto With(ConfigOption option, F &&f) const { + const auto *param = GetParam(option); + return param != nullptr + ? param->With(std::forward(f)) + : f(nullptr); + } + gcc_pure const char *GetString(ConfigOption option, const char *default_value=nullptr) const noexcept; diff --git a/src/config/Param.hxx b/src/config/Param.hxx index 05ca8cd04..b7a573f68 100644 --- a/src/config/Param.hxx +++ b/src/config/Param.hxx @@ -66,6 +66,19 @@ struct ConfigParam { */ [[noreturn]] void ThrowWithNested() const; + + /** + * Invoke a function with the configured value; if the + * function throws, call ThrowWithNested(). + */ + template + auto With(F &&f) const { + try { + return f(value.c_str()); + } catch (...) { + ThrowWithNested(); + } + } }; #endif