diff options
Diffstat (limited to 'bbot/build-config.cxx')
-rw-r--r-- | bbot/build-config.cxx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/bbot/build-config.cxx b/bbot/build-config.cxx new file mode 100644 index 0000000..226ead3 --- /dev/null +++ b/bbot/build-config.cxx @@ -0,0 +1,121 @@ +// file : bbot/build-config.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <bbot/build-config> + +#include <string> +#include <cstddef> // size_t +#include <utility> // move() +#include <stdexcept> // invalid_argument + +#include <butl/path> +#include <butl/fdstream> +#include <butl/tab-parser> + +using namespace std; +using namespace butl; + +namespace bbot +{ + LIBBBOT_EXPORT build_configs + parse_buildtab (istream& is, const string& name) + { + build_configs r; + tab_parser parser (is, name); + + tab_fields tl; + while (!(tl = parser.next ()).empty ()) + { + size_t n (tl.size ()); // Fields count. + size_t i (0); // The field currently being processed. + + // Throw tab_parsing for the field currently being processed. If i == n + // then we refer to the end-of-line column (presumably reporting a missed + // field). + // + auto bad_line = [&name, &tl, &i, n] (const string& d, size_t offset = 0) + { + // Offset beyond the end-of-line is meaningless. + // + assert (i < n || (i == n && offset == 0)); + + throw tab_parsing (name, + tl.line, + i == n + ? tl.end_column + : tl[i].column + offset, + d); + }; + + build_config config; + config.machine_pattern = move (tl[i++].value); + + // Configuration name field is a required one. + // + if (i == n) + bad_line ("no configuration name found"); + + config.name = move (tl[i].value); + + // Make sure the name is unique. + // + for (const auto& c: r) + if (c.name == config.name) + bad_line ("duplicate configuration name"); + + // If there is no target nor configuration variables then save the + // configuration and proceed with the next line. + // + if (++i == n) + { + r.emplace_back (move (config)); + continue; + } + + // If the third field doesn't contain '=' character, then we will treat + // it as a target. + // + if (tl[i].value.find ('=') == string::npos) + { + try + { + config.target = target_triplet (tl[i].value); + } + catch (const invalid_argument& e) + { + bad_line (e.what ()); + } + + ++i; + } + + try + { + for (; i < n; ++i) + config.vars.emplace_back (variable (move (tl[i].value))); + } + catch (const invalid_variable& e) + { + bad_line (e.what (), e.pos); // Note that tl[i].value is moved from, + // but happily we don't use it + } + + // Save the configuration. + // + r.emplace_back (move (config)); + } + + return r; + } + + build_configs + parse_buildtab (const path& p) + { + ifdstream ifs (p); + build_configs r (parse_buildtab (ifs, p.string ())); + + ifs.close (); // Throws on failure. + return r; + } +} |