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> |
46 | at_option_parser(std::string const& s) |
47 | { |
48 | if ('@' == s[0]) |
49 | return std::make_pair(x: std::string("config-file" ), y: s.substr(pos: 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: |
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 |
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>(operand: &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(v: 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(x: t); |
84 | } |
85 | else { |
86 | // store this path as an user path |
87 | p->paths.push_back(x: 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 |
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(is&: istrm, str&: line)) { |
110 | // skip empty lines |
111 | std::string::size_type pos = line.find_first_not_of(s: " \t" ); |
112 | if (pos == std::string::npos) |
113 | continue; |
114 | |
115 | // skip comment lines |
116 | if ('#' != line[pos]) |
117 | options.push_back(x: 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(options: po::command_line_parser(options) |
129 | .options(desc).style(xstyle: (int)unix_style).run(), m&: vm); |
130 | po::notify(m&: 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 |
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(is&: ifs, str&: line)) { |
166 | // skip empty lines |
167 | std::string::size_type pos = line.find_first_not_of(s: " \t" ); |
168 | if (pos == std::string::npos) |
169 | continue; |
170 | |
171 | // skip comment lines |
172 | if ('#' != line[pos]) |
173 | options.push_back(x: 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(name: "input" , max_count: -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(options: po::command_line_parser(options) |
191 | .options(desc).positional(desc: p).style(xstyle: (int)unix_style).run(), m&: vm); |
192 | po::notify(m&: 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 | { |
207 | 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 |
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, tokens: s); |
231 | } |
232 | |
233 | }} // namespace boost::program_options |
234 | |
235 | #endif // !defined(BOOST_WAVE_LIBS_WAVE_TEST_CMD_LINE_UTILS_HPP) |
236 | |