diff options
| author | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
| commit | 6232d13f5321b87ddf12a1aa36b4545da45f173d (patch) | |
| tree | 23f3316470a14136debd9d02f9e920ca2b06f4cc /src/config.cc | |
Travel3: Simple image and video display site
Reads the images and videos from filesystem and builds a site in
memroy.
Diffstat (limited to 'src/config.cc')
| -rw-r--r-- | src/config.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/config.cc b/src/config.cc new file mode 100644 index 0000000..4d7cf52 --- /dev/null +++ b/src/config.cc @@ -0,0 +1,182 @@ +#include "common.hh" + +#include "config.hh" +#include "io.hh" +#include "logger.hh" +#include "strutil.hh" + +#include <errno.h> +#include <fstream> +#include <string.h> +#include <unordered_map> +#include <unordered_set> + +namespace { + +class ConfigImpl : public Config { +public: + ConfigImpl() + : data_(), root_() {} + + ConfigImpl(std::unordered_map<std::string, std::string> data, + std::filesystem::path root) + : data_(std::move(data)), root_(std::move(root)) {} + + std::string_view get(std::string const& key, + std::string_view default_) const override { + auto it = data_.find(key); + if (it == data_.end()) + return default_; + return it->second; + } + + char const* get(std::string const& key, + char const* default_) const override { + auto it = data_.find(key); + if (it == data_.end()) + return default_; + return it->second.c_str(); + } + + std::optional<uint64_t> get(std::string const& key, uint64_t default_) + const override { + auto* data = get(key, nullptr); + if (!data) + return default_; + return str::parse_uint64(data); + } + + std::optional<uint64_t> get_size(std::string const& key, uint64_t default_) + const override { + auto* data = get(key, nullptr); + if (!data) + return default_; + char* end = nullptr; + double value = strtod(data, &end); + if (end == data) + return std::nullopt; + std::string_view suffix(end); + if (suffix == "t" || suffix == "T" || suffix == "TB" || suffix == "Tb") + return value * 1024 * 1024 * 1024 * 1024; + if (suffix == "g" || suffix == "G" || suffix == "GB" || suffix == "Gb") + return value * 1024 * 1024 * 1024; + if (suffix == "m" || suffix == "M" || suffix == "MB" || suffix == "Mb") + return value * 1024 * 1024; + if (suffix == "k" || suffix == "K" || suffix == "KB" || suffix == "Kb") + return value * 1024; + if (suffix == "b" || suffix == "B" || suffix == "") + return value; + return std::nullopt; + } + + std::optional<double> get_duration(std::string const& key, double default_) + const override { + auto* data = get(key, nullptr); + if (!data) + return default_; + char* end = nullptr; + double value = strtod(data, &end); + if (end == data) + return std::nullopt; + std::string_view suffix(end); + if (suffix == "h" || suffix == "H") + return value * 60.0 * 60.0; + if (suffix == "m" || suffix == "M") + return value * 60.0; + if (suffix == "ms" || suffix == "MS") + return value / 1000.0; + if (suffix == "ns" || suffix == "NS") + return value / 1000000.0; + if (suffix == "s" || suffix == "S" || suffix == "") + return value; + return std::nullopt; + } + + std::filesystem::path get_path(std::string const& key, + std::string_view default_) const override { + auto it = data_.find(key); + if (it == data_.end()) { + if (default_.empty()) + return std::filesystem::path(); + return root_ / default_; + } + return root_ / it->second; + } + +private: + std::unordered_map<std::string, std::string> const data_; + std::filesystem::path const root_; +}; + + +inline bool is_space(char c) { + return c == ' ' || c == '\t'; +} + +void trim(std::string_view str, size_t* start, size_t* end) { + while (*start < *end && is_space(str[*start])) + ++*start; + while (*end > *start && is_space(str[*end - 1])) + --*end; +} + +std::unique_ptr<Config> load(Logger* logger, + std::filesystem::path const& path) { + std::ifstream in(path); + if (!in.good()) { + logger->warn("Unable to open %s for reading: %s", + path.c_str(), strerror(errno)); + return nullptr; + } + auto root = path.parent_path(); + std::unordered_map<std::string, std::string> data; + std::string line; + unsigned long num = 0; + while (std::getline(in, line)) { + ++num; + if (line.empty() || line.front() == '#') + continue; + auto eq = line.find('='); + if (eq == std::string::npos) { + logger->warn("%s:%lu: Invalid line, no equal sign (=).", + path.c_str(), num); + return nullptr; + } + size_t key_start = 0; + size_t key_end = eq; + trim(line, &key_start, &key_end); + if (key_start == key_end) { + logger->warn("%s:%lu: Invalid line, no key before equal sign (=).", + path.c_str(), num); + return nullptr; + } + size_t value_start = eq + 1; + size_t value_end = line.size(); + trim(line, &value_start, &value_end); + auto key = line.substr(key_start, key_end - key_start); + data[key] = line.substr(value_start, value_end - value_start); + } + if (!in.eof()) { + logger->warn("Error reading %s: %s", + path.c_str(), strerror(errno)); + return nullptr; + } + return Config::create(std::move(data), std::move(root)); +} + +} // namespace + +std::unique_ptr<Config> Config::create(Logger* logger, + std::filesystem::path const& filepath) { + return load(logger, filepath); +} + +std::unique_ptr<Config> Config::create( + std::unordered_map<std::string, std::string> data, + std::filesystem::path root) { + return std::make_unique<ConfigImpl>(std::move(data), std::move(root)); +} + +std::unique_ptr<Config> Config::create_empty() { + return std::make_unique<ConfigImpl>(); +} |
