1240116Smarcel// 2240116Smarcel// Automated Testing Framework (atf) 3240116Smarcel// 4240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc. 5240116Smarcel// All rights reserved. 6240116Smarcel// 7240116Smarcel// Redistribution and use in source and binary forms, with or without 8240116Smarcel// modification, are permitted provided that the following conditions 9240116Smarcel// are met: 10240116Smarcel// 1. Redistributions of source code must retain the above copyright 11240116Smarcel// notice, this list of conditions and the following disclaimer. 12240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel// notice, this list of conditions and the following disclaimer in the 14240116Smarcel// documentation and/or other materials provided with the distribution. 15240116Smarcel// 16240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel// 29240116Smarcel 30240116Smarcel#include <fstream> 31240116Smarcel#include <vector> 32240116Smarcel 33240116Smarcel#include "atf-c/defs.h" 34240116Smarcel 35240116Smarcel#include "atf-c++/config.hpp" 36240116Smarcel 37240116Smarcel#include "atf-c++/detail/env.hpp" 38240116Smarcel#include "atf-c++/detail/fs.hpp" 39240116Smarcel#include "atf-c++/detail/sanity.hpp" 40240116Smarcel#include "atf-c++/detail/parser.hpp" 41240116Smarcel 42240116Smarcel#include "config.hpp" 43240116Smarcel 44240116Smarcelnamespace impl = atf::atf_run; 45240116Smarcelnamespace detail = atf::atf_run::detail; 46240116Smarcel 47240116Smarcelnamespace { 48240116Smarcel 49240116Smarcelnamespace atf_config { 50240116Smarcel 51240116Smarcelstatic const atf::parser::token_type eof_type = 0; 52240116Smarcelstatic const atf::parser::token_type nl_type = 1; 53240116Smarcelstatic const atf::parser::token_type text_type = 2; 54240116Smarcelstatic const atf::parser::token_type dblquote_type = 3; 55240116Smarcelstatic const atf::parser::token_type equal_type = 4; 56240116Smarcelstatic const atf::parser::token_type hash_type = 5; 57240116Smarcel 58240116Smarcelclass tokenizer : public atf::parser::tokenizer< std::istream > { 59240116Smarcelpublic: 60240116Smarcel tokenizer(std::istream& is, size_t curline) : 61240116Smarcel atf::parser::tokenizer< std::istream > 62240116Smarcel (is, true, eof_type, nl_type, text_type, curline) 63240116Smarcel { 64240116Smarcel add_delim('=', equal_type); 65240116Smarcel add_delim('#', hash_type); 66240116Smarcel add_quote('"', dblquote_type); 67240116Smarcel } 68240116Smarcel}; 69240116Smarcel 70240116Smarcel} // namespace atf_config 71240116Smarcel 72240116Smarcelclass config_reader : public detail::atf_config_reader { 73240116Smarcel atf::tests::vars_map m_vars; 74240116Smarcel 75240116Smarcel void 76240116Smarcel got_var(const std::string& var, const std::string& name) 77240116Smarcel { 78240116Smarcel m_vars[var] = name; 79240116Smarcel } 80240116Smarcel 81240116Smarcelpublic: 82240116Smarcel config_reader(std::istream& is) : 83240116Smarcel atf_config_reader(is) 84240116Smarcel { 85240116Smarcel } 86240116Smarcel 87240116Smarcel const atf::tests::vars_map& 88240116Smarcel get_vars(void) 89240116Smarcel const 90240116Smarcel { 91240116Smarcel return m_vars; 92240116Smarcel } 93240116Smarcel}; 94240116Smarcel 95240116Smarceltemplate< class K, class V > 96240116Smarcelstatic 97240116Smarcelvoid 98240116Smarcelmerge_maps(std::map< K, V >& dest, const std::map< K, V >& src) 99240116Smarcel{ 100240116Smarcel for (typename std::map< K, V >::const_iterator iter = src.begin(); 101240116Smarcel iter != src.end(); iter++) 102240116Smarcel dest[(*iter).first] = (*iter).second; 103240116Smarcel} 104240116Smarcel 105240116Smarcelstatic 106240116Smarcelvoid 107240116Smarcelmerge_config_file(const atf::fs::path& config_path, 108240116Smarcel atf::tests::vars_map& config) 109240116Smarcel{ 110240116Smarcel std::ifstream is(config_path.c_str()); 111240116Smarcel if (is) { 112240116Smarcel config_reader reader(is); 113240116Smarcel reader.read(); 114240116Smarcel merge_maps(config, reader.get_vars()); 115240116Smarcel } 116240116Smarcel} 117240116Smarcel 118240116Smarcelstatic 119240116Smarcelstd::vector< atf::fs::path > 120240116Smarcelget_config_dirs(void) 121240116Smarcel{ 122240116Smarcel std::vector< atf::fs::path > dirs; 123240116Smarcel dirs.push_back(atf::fs::path(atf::config::get("atf_confdir"))); 124240116Smarcel if (atf::env::has("HOME")) 125240116Smarcel dirs.push_back(atf::fs::path(atf::env::get("HOME")) / ".atf"); 126240116Smarcel return dirs; 127240116Smarcel} 128240116Smarcel 129240116Smarcel} // anonymous namespace 130240116Smarcel 131240116Smarceldetail::atf_config_reader::atf_config_reader(std::istream& is) : 132240116Smarcel m_is(is) 133240116Smarcel{ 134240116Smarcel} 135240116Smarcel 136240116Smarceldetail::atf_config_reader::~atf_config_reader(void) 137240116Smarcel{ 138240116Smarcel} 139240116Smarcel 140240116Smarcelvoid 141240116Smarceldetail::atf_config_reader::got_var( 142240116Smarcel const std::string& var ATF_DEFS_ATTRIBUTE_UNUSED, 143240116Smarcel const std::string& val ATF_DEFS_ATTRIBUTE_UNUSED) 144240116Smarcel{ 145240116Smarcel} 146240116Smarcel 147240116Smarcelvoid 148240116Smarceldetail::atf_config_reader::got_eof(void) 149240116Smarcel{ 150240116Smarcel} 151240116Smarcel 152240116Smarcelvoid 153240116Smarceldetail::atf_config_reader::read(void) 154240116Smarcel{ 155240116Smarcel using atf::parser::parse_error; 156240116Smarcel using namespace atf_config; 157240116Smarcel 158240116Smarcel std::pair< size_t, atf::parser::headers_map > hml = 159240116Smarcel atf::parser::read_headers(m_is, 1); 160240116Smarcel atf::parser::validate_content_type(hml.second, 161240116Smarcel "application/X-atf-config", 1); 162240116Smarcel 163240116Smarcel tokenizer tkz(m_is, hml.first); 164240116Smarcel atf::parser::parser< tokenizer > p(tkz); 165240116Smarcel 166240116Smarcel for (;;) { 167240116Smarcel try { 168240116Smarcel atf::parser::token t = p.expect(eof_type, hash_type, text_type, 169240116Smarcel nl_type, 170240116Smarcel "eof, #, new line or text"); 171240116Smarcel if (t.type() == eof_type) 172240116Smarcel break; 173240116Smarcel 174240116Smarcel if (t.type() == hash_type) { 175240116Smarcel (void)p.rest_of_line(); 176240116Smarcel t = p.expect(nl_type, "new line"); 177240116Smarcel } else if (t.type() == text_type) { 178240116Smarcel std::string name = t.text(); 179240116Smarcel 180240116Smarcel t = p.expect(equal_type, "equal sign"); 181240116Smarcel 182240116Smarcel t = p.expect(text_type, "word or quoted string"); 183240116Smarcel ATF_PARSER_CALLBACK(p, got_var(name, t.text())); 184240116Smarcel 185240116Smarcel t = p.expect(nl_type, hash_type, "new line or comment"); 186240116Smarcel if (t.type() == hash_type) { 187240116Smarcel (void)p.rest_of_line(); 188240116Smarcel t = p.expect(nl_type, "new line"); 189240116Smarcel } 190240116Smarcel } else if (t.type() == nl_type) { 191240116Smarcel } else 192240116Smarcel UNREACHABLE; 193240116Smarcel } catch (const parse_error& pe) { 194240116Smarcel p.add_error(pe); 195240116Smarcel p.reset(nl_type); 196240116Smarcel } 197240116Smarcel } 198240116Smarcel 199240116Smarcel ATF_PARSER_CALLBACK(p, got_eof()); 200240116Smarcel} 201240116Smarcel 202240116Smarcelatf::tests::vars_map 203240116Smarcelimpl::merge_configs(const atf::tests::vars_map& lower, 204240116Smarcel const atf::tests::vars_map& upper) 205240116Smarcel{ 206240116Smarcel atf::tests::vars_map merged = lower; 207240116Smarcel merge_maps(merged, upper); 208240116Smarcel return merged; 209240116Smarcel} 210240116Smarcel 211240116Smarcelatf::tests::vars_map 212240116Smarcelimpl::read_config_files(const std::string& test_suite_name) 213240116Smarcel{ 214240116Smarcel atf::tests::vars_map config; 215240116Smarcel 216240116Smarcel const std::vector< atf::fs::path > dirs = get_config_dirs(); 217240116Smarcel for (std::vector< atf::fs::path >::const_iterator iter = dirs.begin(); 218240116Smarcel iter != dirs.end(); iter++) { 219240116Smarcel merge_config_file((*iter) / "common.conf", config); 220240116Smarcel merge_config_file((*iter) / (test_suite_name + ".conf"), config); 221240116Smarcel } 222240116Smarcel 223240116Smarcel return config; 224240116Smarcel} 225