1 /*============================================================================= 2 Boost.Wave: A Standard compliant C++ preprocessor library 3 http://www.boost.org/ 4 5 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost 6 Software License, Version 1.0. (See accompanying file 7 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 =============================================================================*/ 9 10 #if !defined(BOOST_WAVE_LIBS_WAVE_TEST_CMD_LINE_UTILS_HPP) 11 #define BOOST_WAVE_LIBS_WAVE_TEST_CMD_LINE_UTILS_HPP 12 13 #include <string> 14 #include <fstream> 15 #include <vector> 16 17 #include <boost/config.hpp> 18 #include <boost/assert.hpp> 19 #include <boost/any.hpp> 20 21 /////////////////////////////////////////////////////////////////////////////// 22 // forward declarations only 23 namespace cmd_line_utils 24 { 25 class include_paths; 26 } 27 28 namespace boost { namespace program_options 29 { 30 void validate(boost::any &v, std::vector<std::string> const &s, 31 cmd_line_utils::include_paths *, int); 32 }} // boost::program_options 33 34 /////////////////////////////////////////////////////////////////////////////// 35 #include <boost/program_options.hpp> 36 37 /////////////////////////////////////////////////////////////////////////////// 38 namespace cmd_line_utils { 39 40 namespace po = boost::program_options; 41 42 /////////////////////////////////////////////////////////////////////////// 43 // Additional command line parser which interprets '@something' as an 44 // option "config-file" with the value "something". 45 inline std::pair<std::string, std::string> at_option_parser(std::string const & s)46 at_option_parser(std::string const& s) 47 { 48 if ('@' == s[0]) 49 return std::make_pair(std::string("config-file"), s.substr(1)); 50 else 51 return std::pair<std::string, std::string>(); 52 } 53 54 /////////////////////////////////////////////////////////////////////////// 55 // class, which keeps the include file information read from the options 56 class include_paths 57 { 58 public: include_paths()59 include_paths() : seen_separator(false) {} 60 61 std::vector<std::string> paths; // stores user paths 62 std::vector<std::string> syspaths; // stores system paths 63 bool seen_separator; // options contain a '-I-' option 64 65 // Function which validates additional tokens from the given option. 66 static void validate(boost::any & v,std::vector<std::string> const & tokens)67 validate(boost::any &v, std::vector<std::string> const &tokens) 68 { 69 if (v.empty()) 70 v = boost::any(include_paths()); 71 72 include_paths *p = boost::any_cast<include_paths>(&v); 73 BOOST_ASSERT(NULL != p); 74 75 // Assume only one path per '-I' occurrence. 76 std::string const& t = po::validators::get_single_string(tokens); 77 if (t == "-") { 78 // found -I- option, so switch behaviour 79 p->seen_separator = true; 80 } 81 else if (p->seen_separator) { 82 // store this path as a system path 83 p->syspaths.push_back(t); 84 } 85 else { 86 // store this path as an user path 87 p->paths.push_back(t); 88 } 89 } 90 }; 91 92 /////////////////////////////////////////////////////////////////////////// 93 // Read all options from a given config string, parse and add them to the 94 // given variables_map 95 inline void read_config_options(int debuglevel,std::string const & indata,po::options_description const & desc,po::variables_map & vm)96 read_config_options(int debuglevel, std::string const &indata, 97 po::options_description const &desc, po::variables_map &vm) 98 { 99 if (9 == debuglevel) { 100 std::cerr << "read_config_options: reading config options" 101 << std::endl; 102 } 103 104 std::istringstream istrm(indata); 105 106 std::vector<std::string> options; 107 std::string line; 108 109 while (std::getline(istrm, line)) { 110 // skip empty lines 111 std::string::size_type pos = line.find_first_not_of(" \t"); 112 if (pos == std::string::npos) 113 continue; 114 115 // skip comment lines 116 if ('#' != line[pos]) 117 options.push_back(line); 118 } 119 120 if (options.size() > 0) { 121 if (9 == debuglevel) { 122 std::cerr << "read_config_options: options size is: " 123 << (int)options.size() << std::endl; 124 } 125 126 // (the (int) cast is to make the True64 compiler happy) 127 using namespace boost::program_options::command_line_style; 128 po::store(po::command_line_parser(options) 129 .options(desc).style((int)unix_style).run(), vm); 130 po::notify(vm); 131 } 132 133 if (9 == debuglevel) { 134 std::cerr << "read_config_options: succeeded to read config options" 135 << std::endl; 136 } 137 } 138 139 /////////////////////////////////////////////////////////////////////////// 140 // Read all options from a given config file, parse and add them to the 141 // given variables_map 142 inline bool read_config_file(int debuglevel,std::string const & filename,po::options_description const & desc,po::variables_map & vm)143 read_config_file(int debuglevel, std::string const &filename, 144 po::options_description const &desc, po::variables_map &vm) 145 { 146 if (9 == debuglevel) { 147 std::cerr << "read_config_file: reading config options" 148 << std::endl; 149 } 150 151 std::ifstream ifs(filename.c_str()); 152 153 if (!ifs.is_open()) { 154 std::cerr 155 << "testwave: " << filename 156 << ": command line warning: config file not found" 157 << std::endl; 158 return false; 159 } 160 161 // parse the file and extract all given arguments and options 162 std::vector<std::string> options; 163 std::string line; 164 165 while (std::getline(ifs, line)) { 166 // skip empty lines 167 std::string::size_type pos = line.find_first_not_of(" \t"); 168 if (pos == std::string::npos) 169 continue; 170 171 // skip comment lines 172 if ('#' != line[pos]) 173 options.push_back(line); 174 } 175 176 if (options.size() > 0) { 177 if (9 == debuglevel) { 178 std::cerr << "read_config_file: options size is: " 179 << (int)options.size() << std::endl; 180 } 181 182 // treat positional arguments as --input parameters 183 po::positional_options_description p; 184 p.add("input", -1); 185 186 // parse the vector of lines and store the results into the given 187 // variables map 188 // (the (int) cast is to make the True64 compiler happy) 189 using namespace boost::program_options::command_line_style; 190 po::store(po::command_line_parser(options) 191 .options(desc).positional(p).style((int)unix_style).run(), vm); 192 po::notify(vm); 193 } 194 195 196 if (9 == debuglevel) { 197 std::cerr << "read_config_file: succeeded to read config options" 198 << std::endl; 199 } 200 return true; 201 } 202 203 /////////////////////////////////////////////////////////////////////////// 204 // predicate to extract all positional arguments from the command line 205 struct is_argument 206 { operator ()cmd_line_utils::is_argument207 bool operator()(po::option const &opt) 208 { 209 return (opt.position_key == -1) ? true : false; 210 } 211 }; 212 213 /////////////////////////////////////////////////////////////////////////////// 214 } // namespace cmd_line_utils 215 216 /////////////////////////////////////////////////////////////////////////////// 217 // 218 // Special validator overload, which allows to handle the -I- syntax for 219 // switching the semantics of an -I option. 220 // 221 // This must be injected into the boost::program_options namespace 222 // 223 /////////////////////////////////////////////////////////////////////////////// 224 namespace boost { namespace program_options { 225 226 inline void validate(boost::any & v,std::vector<std::string> const & s,cmd_line_utils::include_paths *,int)227 validate(boost::any &v, std::vector<std::string> const &s, 228 cmd_line_utils::include_paths *, int) 229 { 230 cmd_line_utils::include_paths::validate(v, s); 231 } 232 233 }} // namespace boost::program_options 234 235 #endif // !defined(BOOST_WAVE_LIBS_WAVE_TEST_CMD_LINE_UTILS_HPP) 236