/* * This source code is released into the public domain. */ module; /* * The configuration store. There should only be one of these. */ #include #include #include export module nihil.config:store; import nihil; import :error; import :option; namespace nihil::config { // Exception thrown on an attempt to fetch an undefined option. export struct unknown_option final : error { std::string varname; unknown_option(std::string_view varname_) : error("unknown configuration variable '{}'", varname_) , varname(varname_) {} }; export struct store final { /* * Get the global config store. */ static auto get() -> store& { if (instance == nullptr) instance = new store; return *instance; } /* * Initialise the global config store. */ #if 0 void init(context const &ctx) { std::string config_text; // Load the configuration text. auto config_path = ctx.dbdir / "config.ucl"; try { read_file(config_path, std::back_inserter(config_text)); } catch (io_error const &exc) { // Ignore ENOENT, it simply means we haven't created the // config file yet, so default values will be used. if (exc.error == std::errc::no_such_file_or_directory) return; throw; } // Parse the UCL. std::string err; auto uclconfig = ucl::Ucl::parse(config_text, err); if (!uclconfig) throw error("{0}: {1}", config_path, err); auto const &cfg = get(); for (auto const &uclvalue : uclconfig) { auto &value = cfg.fetch(uclvalue.key()); switch (uclvalue.type()) { case UCL_INT: value.integer(uclvalue.int_value()); break; case UCL_STRING: value.string(uclvalue.string_value()); break; default: throw error( "INTERNAL ERROR: unknown value type {0}", static_cast(uclvalue.type())); } } } #endif /* * Register a new value with the config store. */ auto register_option(this store &self, option *object) -> void { auto [it, okay] = self.options.insert( std::pair{object->name(), object}); if (okay) return; throw error("INTERNAL ERROR: attempt to register " "duplicate config value '{0}'", object->name()); } /* * Fetch an existing value in the config store. */ auto fetch(this store const &self, std::string_view name) -> option & { if (auto it = self.options.find(name); it != self.options.end()) return *it->second; throw unknown_option(name); } /* * Fetch all values in the configuration store. */ auto all(this auto &&self) -> nihil::generator