• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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