summaryrefslogtreecommitdiffstats
path: root/unit/atf-src/tools/config_file.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unit/atf-src/tools/config_file.cpp')
-rw-r--r--unit/atf-src/tools/config_file.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/unit/atf-src/tools/config_file.cpp b/unit/atf-src/tools/config_file.cpp
new file mode 100644
index 0000000..3802c06
--- /dev/null
+++ b/unit/atf-src/tools/config_file.cpp
@@ -0,0 +1,223 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2007 The NetBSD Foundation, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include <cstdlib>
+#include <fstream>
+#include <vector>
+
+#include "config.hpp"
+#include "config_file.hpp"
+#include "defs.hpp"
+#include "env.hpp"
+#include "fs.hpp"
+#include "parser.hpp"
+
+namespace impl = tools::config_file;
+namespace detail = tools::config_file::detail;
+
+namespace {
+
+typedef std::map< std::string, std::string > vars_map;
+
+namespace atf_config {
+
+static const tools::parser::token_type eof_type = 0;
+static const tools::parser::token_type nl_type = 1;
+static const tools::parser::token_type text_type = 2;
+static const tools::parser::token_type dblquote_type = 3;
+static const tools::parser::token_type equal_type = 4;
+static const tools::parser::token_type hash_type = 5;
+
+class tokenizer : public tools::parser::tokenizer< std::istream > {
+public:
+ tokenizer(std::istream& is, size_t curline) :
+ tools::parser::tokenizer< std::istream >
+ (is, true, eof_type, nl_type, text_type, curline)
+ {
+ add_delim('=', equal_type);
+ add_delim('#', hash_type);
+ add_quote('"', dblquote_type);
+ }
+};
+
+} // namespace atf_config
+
+class config_reader : public detail::atf_config_reader {
+ vars_map m_vars;
+
+ void
+ got_var(const std::string& var, const std::string& name)
+ {
+ m_vars[var] = name;
+ }
+
+public:
+ config_reader(std::istream& is) :
+ atf_config_reader(is)
+ {
+ }
+
+ const vars_map&
+ get_vars(void)
+ const
+ {
+ return m_vars;
+ }
+};
+
+template< class K, class V >
+static
+void
+merge_maps(std::map< K, V >& dest, const std::map< K, V >& src)
+{
+ for (typename std::map< K, V >::const_iterator iter = src.begin();
+ iter != src.end(); iter++)
+ dest[(*iter).first] = (*iter).second;
+}
+
+static
+void
+merge_config_file(const tools::fs::path& config_path,
+ vars_map& config)
+{
+ std::ifstream is(config_path.c_str());
+ if (is) {
+ config_reader reader(is);
+ reader.read();
+ merge_maps(config, reader.get_vars());
+ }
+}
+
+static
+std::vector< tools::fs::path >
+get_config_dirs(void)
+{
+ std::vector< tools::fs::path > dirs;
+ dirs.push_back(tools::fs::path(tools::config::get("atf_confdir")));
+ if (tools::env::has("HOME"))
+ dirs.push_back(tools::fs::path(tools::env::get("HOME")) / ".atf");
+ return dirs;
+}
+
+} // anonymous namespace
+
+detail::atf_config_reader::atf_config_reader(std::istream& is) :
+ m_is(is)
+{
+}
+
+detail::atf_config_reader::~atf_config_reader(void)
+{
+}
+
+void
+detail::atf_config_reader::got_var(
+ const std::string& var ATF_DEFS_ATTRIBUTE_UNUSED,
+ const std::string& val ATF_DEFS_ATTRIBUTE_UNUSED)
+{
+}
+
+void
+detail::atf_config_reader::got_eof(void)
+{
+}
+
+void
+detail::atf_config_reader::read(void)
+{
+ using tools::parser::parse_error;
+ using namespace atf_config;
+
+ std::pair< size_t, tools::parser::headers_map > hml =
+ tools::parser::read_headers(m_is, 1);
+ tools::parser::validate_content_type(hml.second,
+ "application/X-atf-config", 1);
+
+ tokenizer tkz(m_is, hml.first);
+ tools::parser::parser< tokenizer > p(tkz);
+
+ for (;;) {
+ try {
+ tools::parser::token t = p.expect(eof_type, hash_type, text_type,
+ nl_type,
+ "eof, #, new line or text");
+ if (t.type() == eof_type)
+ break;
+
+ if (t.type() == hash_type) {
+ (void)p.rest_of_line();
+ t = p.expect(nl_type, "new line");
+ } else if (t.type() == text_type) {
+ std::string name = t.text();
+
+ t = p.expect(equal_type, "equal sign");
+
+ t = p.expect(text_type, "word or quoted string");
+ ATF_PARSER_CALLBACK(p, got_var(name, t.text()));
+
+ t = p.expect(nl_type, hash_type, "new line or comment");
+ if (t.type() == hash_type) {
+ (void)p.rest_of_line();
+ t = p.expect(nl_type, "new line");
+ }
+ } else if (t.type() == nl_type) {
+ } else
+ std::abort();
+ } catch (const parse_error& pe) {
+ p.add_error(pe);
+ p.reset(nl_type);
+ }
+ }
+
+ ATF_PARSER_CALLBACK(p, got_eof());
+}
+
+vars_map
+impl::merge_configs(const vars_map& lower,
+ const vars_map& upper)
+{
+ vars_map merged = lower;
+ merge_maps(merged, upper);
+ return merged;
+}
+
+vars_map
+impl::read_config_files(const std::string& test_suite_name)
+{
+ vars_map config;
+
+ const std::vector< tools::fs::path > dirs = get_config_dirs();
+ for (std::vector< tools::fs::path >::const_iterator iter = dirs.begin();
+ iter != dirs.end(); iter++) {
+ merge_config_file((*iter) / "common.conf", config);
+ merge_config_file((*iter) / (test_suite_name + ".conf"), config);
+ }
+
+ return config;
+}