1 // 2 // Automated Testing Framework (atf) 3 // 4 // Copyright (c) 2007 The NetBSD Foundation, Inc. 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions 9 // are met: 10 // 1. Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // 29 30 #include <cstdlib> 31 #include <fstream> 32 #include <vector> 33 34 #include "config.hpp" 35 #include "config_file.hpp" 36 #include "env.hpp" 37 #include "fs.hpp" 38 #include "parser.hpp" 39 40 namespace impl = tools::config_file; 41 namespace detail = tools::config_file::detail; 42 43 namespace { 44 45 typedef std::map< std::string, std::string > vars_map; 46 47 namespace atf_config { 48 49 static const tools::parser::token_type eof_type = 0; 50 static const tools::parser::token_type nl_type = 1; 51 static const tools::parser::token_type text_type = 2; 52 static const tools::parser::token_type dblquote_type = 3; 53 static const tools::parser::token_type equal_type = 4; 54 static const tools::parser::token_type hash_type = 5; 55 56 class tokenizer : public tools::parser::tokenizer< std::istream > { 57 public: 58 tokenizer(std::istream& is, size_t curline) : 59 tools::parser::tokenizer< std::istream > 60 (is, true, eof_type, nl_type, text_type, curline) 61 { 62 add_delim('=', equal_type); 63 add_delim('#', hash_type); 64 add_quote('"', dblquote_type); 65 } 66 }; 67 68 } // namespace atf_config 69 70 class config_reader : public detail::atf_config_reader { 71 vars_map m_vars; 72 73 void 74 got_var(const std::string& var, const std::string& name) 75 { 76 m_vars[var] = name; 77 } 78 79 public: 80 config_reader(std::istream& is) : 81 atf_config_reader(is) 82 { 83 } 84 85 const vars_map& 86 get_vars(void) 87 const 88 { 89 return m_vars; 90 } 91 }; 92 93 template< class K, class V > 94 static 95 void 96 merge_maps(std::map< K, V >& dest, const std::map< K, V >& src) 97 { 98 for (typename std::map< K, V >::const_iterator iter = src.begin(); 99 iter != src.end(); iter++) 100 dest[(*iter).first] = (*iter).second; 101 } 102 103 static 104 void 105 merge_config_file(const tools::fs::path& config_path, 106 vars_map& config) 107 { 108 std::ifstream is(config_path.c_str()); 109 if (is) { 110 config_reader reader(is); 111 reader.read(); 112 merge_maps(config, reader.get_vars()); 113 } 114 } 115 116 static 117 std::vector< tools::fs::path > 118 get_config_dirs(void) 119 { 120 std::vector< tools::fs::path > dirs; 121 dirs.push_back(tools::fs::path(tools::config::get("atf_confdir"))); 122 if (tools::env::has("HOME")) 123 dirs.push_back(tools::fs::path(tools::env::get("HOME")) / ".atf"); 124 return dirs; 125 } 126 127 } // anonymous namespace 128 129 detail::atf_config_reader::atf_config_reader(std::istream& is) : 130 m_is(is) 131 { 132 } 133 134 detail::atf_config_reader::~atf_config_reader(void) 135 { 136 } 137 138 void 139 detail::atf_config_reader::got_var( 140 const std::string& var __attribute__((__unused__)), 141 const std::string& val __attribute__((__unused__))) 142 { 143 } 144 145 void 146 detail::atf_config_reader::got_eof(void) 147 { 148 } 149 150 void 151 detail::atf_config_reader::read(void) 152 { 153 using tools::parser::parse_error; 154 using namespace atf_config; 155 156 std::pair< size_t, tools::parser::headers_map > hml = 157 tools::parser::read_headers(m_is, 1); 158 tools::parser::validate_content_type(hml.second, 159 "application/X-atf-config", 1); 160 161 tokenizer tkz(m_is, hml.first); 162 tools::parser::parser< tokenizer > p(tkz); 163 164 for (;;) { 165 try { 166 tools::parser::token t = p.expect(eof_type, hash_type, text_type, 167 nl_type, 168 "eof, #, new line or text"); 169 if (t.type() == eof_type) 170 break; 171 172 if (t.type() == hash_type) { 173 (void)p.rest_of_line(); 174 t = p.expect(nl_type, "new line"); 175 } else if (t.type() == text_type) { 176 std::string name = t.text(); 177 178 t = p.expect(equal_type, "equal sign"); 179 180 t = p.expect(text_type, "word or quoted string"); 181 ATF_PARSER_CALLBACK(p, got_var(name, t.text())); 182 183 t = p.expect(nl_type, hash_type, "new line or comment"); 184 if (t.type() == hash_type) { 185 (void)p.rest_of_line(); 186 t = p.expect(nl_type, "new line"); 187 } 188 } else if (t.type() == nl_type) { 189 } else 190 std::abort(); 191 } catch (const parse_error& pe) { 192 p.add_error(pe); 193 p.reset(nl_type); 194 } 195 } 196 197 ATF_PARSER_CALLBACK(p, got_eof()); 198 } 199 200 vars_map 201 impl::merge_configs(const vars_map& lower, 202 const vars_map& upper) 203 { 204 vars_map merged = lower; 205 merge_maps(merged, upper); 206 return merged; 207 } 208 209 vars_map 210 impl::read_config_files(const std::string& test_suite_name) 211 { 212 vars_map config; 213 214 const std::vector< tools::fs::path > dirs = get_config_dirs(); 215 for (std::vector< tools::fs::path >::const_iterator iter = dirs.begin(); 216 iter != dirs.end(); iter++) { 217 merge_config_file((*iter) / "common.conf", config); 218 merge_config_file((*iter) / (test_suite_name + ".conf"), config); 219 } 220 221 return config; 222 } 223