summaryrefslogtreecommitdiff
path: root/src/config.cc
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2021-11-17 22:34:57 +0100
committerJoel Klinghed <the_jk@spawned.biz>2021-11-17 22:34:57 +0100
commit6232d13f5321b87ddf12a1aa36b4545da45f173d (patch)
tree23f3316470a14136debd9d02f9e920ca2b06f4cc /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.cc182
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>();
+}