// file : libbuild2/config/utility.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #include <libbuild2/config/utility.hxx> using namespace std; namespace build2 { void (*config_save_variable) (scope&, const variable&, optional<uint64_t>); void (*config_save_environment) (scope&, const char*); void (*config_save_module) (scope&, const char*, int); const string& (*config_preprocess_create) (context&, values&, vector_view<opspec>&, bool, const location&); bool (*config_configure_post) (scope&, bool (*)(action, const scope&)); bool (*config_disfigure_pre) (scope&, bool (*)(action, const scope&)); namespace config { pair<lookup, bool> lookup_config_impl (scope& rs, const variable& var, uint64_t sflags) { // This is a stripped-down version of the default value case. pair<lookup, size_t> org (rs.lookup_original (var)); bool n (false); // New flag. lookup l (org.first); // Treat an inherited value that was set to default as new. // if (l.defined () && l->extra) n = true; if (var.overrides != nullptr) { // This is tricky: if we didn't find the original, pretend we have set // the default value for the purpose of override lookup in order to // have consistent semantics with the default value case (see notes in // that implementation for background). // // In particular, this makes sure we can first do the lookup without // the default value and then, if there is no value, call the version // with the default value and end up with the same result if we called // the default value version straight away. // // Note that we need to detect both when the default value is not // overridden as well as when the override is based on it (e.g., via // append; think config.cxx+=-m32). // // @@ Maybe a callback that computes the default value on demand is a // better way? // variable_map::value_data v; // NULL value, but must be with version. if (!l.defined ()) org = make_pair (lookup (v, var, rs), 1); // As default value case. scope::override_info li (rs.lookup_override_info (var, move (org))); pair<lookup, size_t>& ovr (li.lookup); if (l.defined () ? l != ovr.first : !li.original) // Overriden? { // Override is always treated as new. // n = true; l = move (ovr.first); } } if (l.defined ()) save_variable (rs, var, sflags); return pair<lookup, bool> (l, n); } bool specified_config (scope& rs, const string& n, initializer_list<const char*> ig) { auto& vp (rs.var_pool ()); // Search all outer scopes for any value in this namespace. // // What about "pure" overrides, i.e., those without any original values? // Well, they will also be found since their names have the original // variable as a prefix. But do they apply? Yes, since we haven't found // any original values, they will be "visible"; see find_override() for // details. // const variable& ns (vp.insert ("config." + n)); for (scope* s (&rs); s != nullptr; s = s->parent_scope ()) { for (auto p (s->vars.lookup_namespace (ns)); p.first != p.second; ++p.first) { const variable* v (&p.first->first.get ()); // This can be one of the overrides (__override, __prefix, etc). // if (size_t n = v->override ()) v = vp.find (string (v->name, 0, n)); auto match_tail = [&ns, v] (const char* t) { return v->name.compare (ns.name.size () + 1, string::npos, t) == 0; }; // Ignore config.*.configured and user-supplied names. // if (v->name.size () <= ns.name.size () || (!match_tail ("configured") && find_if (ig.begin (), ig.end (), match_tail) == ig.end ())) return true; } } return false; } bool unconfigured (scope& rs, const string& n) { // Pattern-typed as bool. // const variable& var ( rs.var_pool ().insert ("config." + n + ".configured")); save_variable (rs, var); auto l (rs[var]); // Include inherited values. return l && !cast<bool> (l); } bool unconfigured (scope& rs, const string& n, bool v) { // Pattern-typed as bool. // const variable& var ( rs.var_pool ().insert ("config." + n + ".configured")); save_variable (rs, var); value& x (rs.assign (var)); if (x.null || cast<bool> (x) != !v) { x = !v; return true; } else return false; } } }