| 1 | /*============================================================================= | 
|---|
| 2 |     Boost.Wave: A Standard compliant C++ preprocessor library | 
|---|
| 3 |  | 
|---|
| 4 |     http://www.boost.org/ | 
|---|
| 5 |  | 
|---|
| 6 |     Copyright (c) 2001-2005 Hartmut Kaiser. Distributed under the Boost | 
|---|
| 7 |     Software License, Version 1.0. (See accompanying file | 
|---|
| 8 |     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 
|---|
| 9 | =============================================================================*/ | 
|---|
| 10 |  | 
|---|
| 11 | #include "cpp.hpp"                  // global configuration | 
|---|
| 12 |  | 
|---|
| 13 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 14 | // Include additional Boost libraries | 
|---|
| 15 | #include <boost/filesystem/path.hpp> | 
|---|
| 16 | #include <boost/timer.hpp> | 
|---|
| 17 | #include <boost/any.hpp> | 
|---|
| 18 |  | 
|---|
| 19 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 20 | //  Include Wave itself | 
|---|
| 21 | #include <boost/wave.hpp> | 
|---|
| 22 |  | 
|---|
| 23 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 24 | //  Include the lexer related stuff | 
|---|
| 25 | #include <boost/wave/cpplexer/cpp_lex_token.hpp>      // token type | 
|---|
| 26 | #include <boost/wave/cpplexer/cpp_lex_iterator.hpp>   // lexer type | 
|---|
| 27 |  | 
|---|
| 28 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 29 | //  Include the context trace policies to use | 
|---|
| 30 | #include "trace_macro_expansion.hpp" | 
|---|
| 31 |  | 
|---|
| 32 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 33 | //  include lexer specifics, import lexer names | 
|---|
| 34 | // | 
|---|
| 35 | #if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0 | 
|---|
| 36 | #include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp> | 
|---|
| 37 | #endif  | 
|---|
| 38 |  | 
|---|
| 39 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 40 | //  include the grammar definitions, if these shouldn't be compiled separately | 
|---|
| 41 | //  (ATTENTION: _very_ large compilation times!) | 
|---|
| 42 | // | 
|---|
| 43 | #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0 | 
|---|
| 44 | #include <boost/wave/grammars/cpp_intlit_grammar.hpp> | 
|---|
| 45 | #include <boost/wave/grammars/cpp_chlit_grammar.hpp> | 
|---|
| 46 | #include <boost/wave/grammars/cpp_grammar.hpp> | 
|---|
| 47 | #include <boost/wave/grammars/cpp_expression_grammar.hpp> | 
|---|
| 48 | #include <boost/wave/grammars/cpp_predef_macros_grammar.hpp> | 
|---|
| 49 | #include <boost/wave/grammars/cpp_defined_grammar.hpp> | 
|---|
| 50 | #endif  | 
|---|
| 51 |  | 
|---|
| 52 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 53 | //  import required names | 
|---|
| 54 | using namespace boost::spirit; | 
|---|
| 55 |  | 
|---|
| 56 | using std::string; | 
|---|
| 57 | using std::pair; | 
|---|
| 58 | using std::vector; | 
|---|
| 59 | using std::getline; | 
|---|
| 60 | using std::ifstream; | 
|---|
| 61 | using std::cout; | 
|---|
| 62 | using std::cerr; | 
|---|
| 63 | using std::endl; | 
|---|
| 64 | using std::ostream; | 
|---|
| 65 | using std::istreambuf_iterator; | 
|---|
| 66 |  | 
|---|
| 67 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 68 | // print the current version | 
|---|
| 69 | int print_version() | 
|---|
| 70 | { | 
|---|
| 71 |     typedef boost::wave::cpplexer::lex_iterator< | 
|---|
| 72 |             boost::wave::cpplexer::lex_token<> > | 
|---|
| 73 |         lex_iterator_type; | 
|---|
| 74 |     typedef boost::wave::context< | 
|---|
| 75 |             std::string::iterator, lex_iterator_type, | 
|---|
| 76 |             boost::wave::iteration_context_policies::load_file_to_string, | 
|---|
| 77 |             trace_macro_expansion>  | 
|---|
| 78 |         context_type; | 
|---|
| 79 |          | 
|---|
| 80 |     string version (context_type::get_version_string()); | 
|---|
| 81 |     cout  | 
|---|
| 82 |         << version.substr(1, version.size()-2)  // strip quotes | 
|---|
| 83 |         << " (" << CPP_VERSION_DATE << ")"      // add date | 
|---|
| 84 |         << endl; | 
|---|
| 85 |     return 0;                       // exit app | 
|---|
| 86 | } | 
|---|
| 87 |  | 
|---|
| 88 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 89 | // print the copyright statement | 
|---|
| 90 | int print_copyright() | 
|---|
| 91 | { | 
|---|
| 92 |     char const *copyright[] = { | 
|---|
| 93 |         "", | 
|---|
| 94 |         "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library", | 
|---|
| 95 |         "http://www.boost.org/", | 
|---|
| 96 |         "", | 
|---|
| 97 |         "Copyright (c) 2001-2005 Hartmut Kaiser, Distributed under the Boost", | 
|---|
| 98 |         "Software License, Version 1.0. (See accompanying file", | 
|---|
| 99 |         "LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)", | 
|---|
| 100 |         0 | 
|---|
| 101 |     }; | 
|---|
| 102 |      | 
|---|
| 103 |     for (int i = 0; 0 != copyright[i]; ++i) | 
|---|
| 104 |         cout << copyright[i] << endl; | 
|---|
| 105 |          | 
|---|
| 106 |     return 0;                       // exit app | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 110 | // forward declarations only | 
|---|
| 111 | namespace cmd_line_utils  | 
|---|
| 112 | { | 
|---|
| 113 |     class include_paths; | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | namespace boost { namespace program_options  | 
|---|
| 117 | { | 
|---|
| 118 |     void validate(boost::any &v, std::vector<std::string> const &s, | 
|---|
| 119 |         cmd_line_utils::include_paths *, int); | 
|---|
| 120 | }} // boost::program_options | 
|---|
| 121 |  | 
|---|
| 122 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 123 | #include <boost/program_options.hpp> | 
|---|
| 124 |  | 
|---|
| 125 | namespace po = boost::program_options; | 
|---|
| 126 | namespace fs = boost::filesystem; | 
|---|
| 127 |  | 
|---|
| 128 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 129 | namespace cmd_line_util { | 
|---|
| 130 |  | 
|---|
| 131 |     // Additional command line parser which interprets '@something' as an  | 
|---|
| 132 |     // option "config-file" with the value "something". | 
|---|
| 133 |     inline pair<string, string>  | 
|---|
| 134 |     at_option_parser(string const&s) | 
|---|
| 135 |     { | 
|---|
| 136 |         if ('@' == s[0])  | 
|---|
| 137 |             return std::make_pair(string("config-file"), s.substr(1)); | 
|---|
| 138 |         else | 
|---|
| 139 |             return pair<string, string>(); | 
|---|
| 140 |     } | 
|---|
| 141 |  | 
|---|
| 142 |     // class, which keeps include file information read from the command line | 
|---|
| 143 |     class include_paths { | 
|---|
| 144 |     public: | 
|---|
| 145 |         include_paths() : seen_separator(false) {} | 
|---|
| 146 |  | 
|---|
| 147 |         vector<string> paths;       // stores user paths | 
|---|
| 148 |         vector<string> syspaths;    // stores system paths | 
|---|
| 149 |         bool seen_separator;        // command line contains a '-I-' option | 
|---|
| 150 |  | 
|---|
| 151 |         // Function which validates additional tokens from command line. | 
|---|
| 152 |         static void  | 
|---|
| 153 |         validate(boost::any &v, vector<string> const &tokens) | 
|---|
| 154 |         { | 
|---|
| 155 |             if (v.empty()) | 
|---|
| 156 |                 v = boost::any(include_paths()); | 
|---|
| 157 |  | 
|---|
| 158 |             include_paths *p = boost::any_cast<include_paths>(&v); | 
|---|
| 159 |  | 
|---|
| 160 |             BOOST_ASSERT(p); | 
|---|
| 161 |             // Assume only one path per '-I' occurrence. | 
|---|
| 162 |             string const& t = po::validators::get_single_string(tokens); | 
|---|
| 163 |             if (t == "-") { | 
|---|
| 164 |             // found -I- option, so switch behaviour | 
|---|
| 165 |                 p->seen_separator = true; | 
|---|
| 166 |             }  | 
|---|
| 167 |             else if (p->seen_separator) { | 
|---|
| 168 |             // store this path as a system path | 
|---|
| 169 |                 p->syspaths.push_back(t);  | 
|---|
| 170 |             }  | 
|---|
| 171 |             else { | 
|---|
| 172 |             // store this path as an user path | 
|---|
| 173 |                 p->paths.push_back(t); | 
|---|
| 174 |             }             | 
|---|
| 175 |         } | 
|---|
| 176 |     }; | 
|---|
| 177 |  | 
|---|
| 178 |     // Read all options from a given config file, parse and add them to the | 
|---|
| 179 |     // given variables_map | 
|---|
| 180 |     void read_config_file_options(string const &filename,  | 
|---|
| 181 |         po::options_description const &desc, po::variables_map &vm, | 
|---|
| 182 |         bool may_fail = false) | 
|---|
| 183 |     { | 
|---|
| 184 |     ifstream ifs(filename.c_str()); | 
|---|
| 185 |  | 
|---|
| 186 |         if (!ifs.is_open()) { | 
|---|
| 187 |             if (!may_fail) { | 
|---|
| 188 |                 cerr << filename  | 
|---|
| 189 |                     << ": command line warning: config file not found" | 
|---|
| 190 |                     << endl; | 
|---|
| 191 |             } | 
|---|
| 192 |             return; | 
|---|
| 193 |         } | 
|---|
| 194 |          | 
|---|
| 195 |     vector<string> options; | 
|---|
| 196 |     string line; | 
|---|
| 197 |  | 
|---|
| 198 |         while (std::getline(ifs, line)) { | 
|---|
| 199 |         // skip empty lines | 
|---|
| 200 |             string::size_type pos = line.find_first_not_of(" \t"); | 
|---|
| 201 |             if (pos == string::npos)  | 
|---|
| 202 |                 continue; | 
|---|
| 203 |  | 
|---|
| 204 |         // skip comment lines | 
|---|
| 205 |             if ('#' != line[pos]) | 
|---|
| 206 |                 options.push_back(line); | 
|---|
| 207 |         } | 
|---|
| 208 |  | 
|---|
| 209 |         if (options.size() > 0) { | 
|---|
| 210 |             using namespace boost::program_options::command_line_style; | 
|---|
| 211 |             po::store(po::command_line_parser(options) | 
|---|
| 212 |                 .options(desc).style(unix_style).run(), vm); | 
|---|
| 213 |             po::notify(vm); | 
|---|
| 214 |         } | 
|---|
| 215 |     } | 
|---|
| 216 |  | 
|---|
| 217 |     // predicate to extract all positional arguments from the command line | 
|---|
| 218 |     struct is_argument { | 
|---|
| 219 |         bool operator()(po::option const &opt) | 
|---|
| 220 |         { | 
|---|
| 221 |           return (opt.position_key == -1) ? true : false; | 
|---|
| 222 |         } | 
|---|
| 223 |     }; | 
|---|
| 224 |  | 
|---|
| 225 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 226 | } | 
|---|
| 227 |  | 
|---|
| 228 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 229 | // | 
|---|
| 230 | //  Special validator overload, which allows to handle the -I- syntax for | 
|---|
| 231 | //  switching the semantics of an -I option. | 
|---|
| 232 | // | 
|---|
| 233 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 234 | namespace boost { namespace program_options { | 
|---|
| 235 |  | 
|---|
| 236 |     void validate(boost::any &v, std::vector<std::string> const &s, | 
|---|
| 237 |         cmd_line_util::include_paths *, int)  | 
|---|
| 238 |     { | 
|---|
| 239 |         cmd_line_util::include_paths::validate(v, s); | 
|---|
| 240 |     } | 
|---|
| 241 |  | 
|---|
| 242 | }}  // namespace boost::program_options | 
|---|
| 243 |  | 
|---|
| 244 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 245 | namespace { | 
|---|
| 246 |  | 
|---|
| 247 |   class auto_stop_watch : public stop_watch | 
|---|
| 248 |   { | 
|---|
| 249 |   public: | 
|---|
| 250 |       auto_stop_watch(bool print_time_, std::ostream &outstrm_) | 
|---|
| 251 |       :   print_time(print_time_), outstrm(outstrm_) | 
|---|
| 252 |       { | 
|---|
| 253 |       } | 
|---|
| 254 |        | 
|---|
| 255 |       ~auto_stop_watch() | 
|---|
| 256 |       { | 
|---|
| 257 |           if (print_time) { | 
|---|
| 258 |               outstrm << "Elapsed time: "  | 
|---|
| 259 |                     << this->format_elapsed_time()  | 
|---|
| 260 |                     << std::endl; | 
|---|
| 261 |           } | 
|---|
| 262 |       } | 
|---|
| 263 |    | 
|---|
| 264 |   private: | 
|---|
| 265 |       bool print_time; | 
|---|
| 266 |       std::ostream &outstrm; | 
|---|
| 267 |   }; | 
|---|
| 268 |    | 
|---|
| 269 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 270 | }   // anonymous namespace | 
|---|
| 271 |  | 
|---|
| 272 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 273 | //  do the actual preprocessing | 
|---|
| 274 | int  | 
|---|
| 275 | do_actual_work (std::string file_name, std::istream &instream,  | 
|---|
| 276 |     po::variables_map const &vm) | 
|---|
| 277 | { | 
|---|
| 278 | // current file position is saved for exception handling | 
|---|
| 279 | boost::wave::util::file_position_type current_position; | 
|---|
| 280 |  | 
|---|
| 281 |     try { | 
|---|
| 282 |     // process the given file | 
|---|
| 283 |     string instring; | 
|---|
| 284 |  | 
|---|
| 285 |         instream.unsetf(std::ios::skipws); | 
|---|
| 286 |  | 
|---|
| 287 | #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) | 
|---|
| 288 |         // this is known to be very slow for large files on some systems | 
|---|
| 289 |         copy (istream_iterator<char>(instream), | 
|---|
| 290 |               istream_iterator<char>(),  | 
|---|
| 291 |               inserter(instring, instring.end())); | 
|---|
| 292 | #else | 
|---|
| 293 |         instring = string(istreambuf_iterator<char>(instream.rdbuf()), | 
|---|
| 294 |                           istreambuf_iterator<char>()); | 
|---|
| 295 | #endif  | 
|---|
| 296 |  | 
|---|
| 297 |     //  This application uses the lex_iterator and lex_token types predefined  | 
|---|
| 298 |     //  with the Wave library, but it is possible to use your own types. | 
|---|
| 299 |     // | 
|---|
| 300 |     //  You may want to have a look at the other samples to see how this is | 
|---|
| 301 |     //  possible to achieve. | 
|---|
| 302 |         typedef boost::wave::cpplexer::lex_iterator< | 
|---|
| 303 |                 boost::wave::cpplexer::lex_token<> > | 
|---|
| 304 |             lex_iterator_type; | 
|---|
| 305 |  | 
|---|
| 306 |     // The C++ preprocessor iterators shouldn't be constructed directly. They  | 
|---|
| 307 |     // are to be generated through a boost::wave::context<> object. This  | 
|---|
| 308 |     // boost::wave::context object is additionally to be used to initialize and  | 
|---|
| 309 |     // define different parameters of the actual preprocessing. | 
|---|
| 310 |         typedef boost::wave::context< | 
|---|
| 311 |                 std::string::iterator, lex_iterator_type, | 
|---|
| 312 |                 boost::wave::iteration_context_policies::load_file_to_string, | 
|---|
| 313 |                 trace_macro_expansion>  | 
|---|
| 314 |             context_type; | 
|---|
| 315 |  | 
|---|
| 316 |     // The preprocessing of the input stream is done on the fly behind the  | 
|---|
| 317 |     // scenes during iteration over the context_type::iterator_type stream. | 
|---|
| 318 |     std::ofstream traceout; | 
|---|
| 319 |     std::ofstream includelistout; | 
|---|
| 320 |     trace_flags enable_trace = trace_nothing; | 
|---|
| 321 |      | 
|---|
| 322 |         if (vm.count("traceto")) { | 
|---|
| 323 |         // try to open the file, where to put the trace output | 
|---|
| 324 |         string trace_file (vm["traceto"].as<string>()); | 
|---|
| 325 |          | 
|---|
| 326 |             if (trace_file != "-") { | 
|---|
| 327 |                 traceout.open(trace_file.c_str()); | 
|---|
| 328 |                 if (!traceout.is_open()) { | 
|---|
| 329 |                     cerr << "wave: could not open trace file: " << trace_file  | 
|---|
| 330 |                         << endl; | 
|---|
| 331 |                     return -1; | 
|---|
| 332 |                 } | 
|---|
| 333 |             } | 
|---|
| 334 |             enable_trace = trace_macros; | 
|---|
| 335 |         } | 
|---|
| 336 |         if ((enable_trace & trace_macros) && !traceout.is_open()) { | 
|---|
| 337 |         // by default trace to std::cerr | 
|---|
| 338 |             traceout.copyfmt(cerr); | 
|---|
| 339 |             traceout.clear(cerr.rdstate()); | 
|---|
| 340 |             static_cast<std::basic_ios<char> &>(traceout).rdbuf(cerr.rdbuf()); | 
|---|
| 341 |         } | 
|---|
| 342 |  | 
|---|
| 343 |     // Open the stream where to output the list of included file names | 
|---|
| 344 |         if (vm.count("listincludes")) { | 
|---|
| 345 |         // try to open the file, where to put the include list  | 
|---|
| 346 |         string includes_file (vm["listincludes"].as<string>()); | 
|---|
| 347 |          | 
|---|
| 348 |             if (includes_file != "-") { | 
|---|
| 349 |                 includelistout.open(includes_file.c_str()); | 
|---|
| 350 |                 if (!includelistout.is_open()) { | 
|---|
| 351 |                     cerr << "wave: could not open include list file: "  | 
|---|
| 352 |                         << includes_file << endl; | 
|---|
| 353 |                     return -1; | 
|---|
| 354 |                 } | 
|---|
| 355 |             } | 
|---|
| 356 |             enable_trace = trace_includes; | 
|---|
| 357 |         } | 
|---|
| 358 |         if ((enable_trace & trace_includes) && !includelistout.is_open()) { | 
|---|
| 359 |         // by default list included names to std::cout | 
|---|
| 360 |             includelistout.copyfmt(cout); | 
|---|
| 361 |             includelistout.clear(cout.rdstate()); | 
|---|
| 362 |             static_cast<std::basic_ios<char> &>(includelistout). | 
|---|
| 363 |                 rdbuf(cout.rdbuf()); | 
|---|
| 364 |         } | 
|---|
| 365 |          | 
|---|
| 366 |     // This this the central piece of the Wave library, it provides you with  | 
|---|
| 367 |     // the iterators to get the preprocessed tokens and allows to configure | 
|---|
| 368 |     // the preprocessing stage in advance. | 
|---|
| 369 |     context_type ctx (instring.begin(), instring.end(), file_name.c_str(), | 
|---|
| 370 |         trace_macro_expansion(traceout, includelistout, enable_trace)); | 
|---|
| 371 |  | 
|---|
| 372 | #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | 
|---|
| 373 |     // enable C99 mode, if appropriate (implies variadics) | 
|---|
| 374 |         if (vm.count("c99")) { | 
|---|
| 375 |             ctx.set_language(boost::wave::support_c99); | 
|---|
| 376 |         } | 
|---|
| 377 |         else if (vm.count("variadics")) { | 
|---|
| 378 |         // enable variadics and placemarkers, if appropriate | 
|---|
| 379 |             ctx.set_language(boost::wave::enable_variadics(ctx.get_language())); | 
|---|
| 380 |         } | 
|---|
| 381 | #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | 
|---|
| 382 |  | 
|---|
| 383 |     // enable long long support, if appropriate | 
|---|
| 384 |          if (vm.count("long_long")) { | 
|---|
| 385 |              ctx.set_language( | 
|---|
| 386 |                 boost::wave::enable_long_long(ctx.get_language())); | 
|---|
| 387 |          } | 
|---|
| 388 |  | 
|---|
| 389 |     // enable preserving comments mode | 
|---|
| 390 |         if (vm.count("preserve")) { | 
|---|
| 391 |             ctx.set_language( | 
|---|
| 392 |                 boost::wave::enable_preserve_comments(ctx.get_language())); | 
|---|
| 393 |         } | 
|---|
| 394 |          | 
|---|
| 395 |     // add include directories to the system include search paths | 
|---|
| 396 |         if (vm.count("sysinclude")) { | 
|---|
| 397 |         vector<string> syspaths = vm["sysinclude"].as<vector<string> >(); | 
|---|
| 398 |          | 
|---|
| 399 |             vector<string>::const_iterator end = syspaths.end(); | 
|---|
| 400 |             for (vector<string>::const_iterator cit = syspaths.begin();  | 
|---|
| 401 |                  cit != end; ++cit) | 
|---|
| 402 |             { | 
|---|
| 403 |                 ctx.add_sysinclude_path((*cit).c_str()); | 
|---|
| 404 |             } | 
|---|
| 405 |         } | 
|---|
| 406 |          | 
|---|
| 407 |     // add include directories to the include search paths | 
|---|
| 408 |         if (vm.count("include")) { | 
|---|
| 409 |             cmd_line_util::include_paths const &ip =  | 
|---|
| 410 |                 vm["include"].as<cmd_line_util::include_paths>(); | 
|---|
| 411 |             vector<string>::const_iterator end = ip.paths.end(); | 
|---|
| 412 |  | 
|---|
| 413 |             for (vector<string>::const_iterator cit = ip.paths.begin();  | 
|---|
| 414 |                  cit != end; ++cit) | 
|---|
| 415 |             { | 
|---|
| 416 |                 ctx.add_include_path((*cit).c_str()); | 
|---|
| 417 |             } | 
|---|
| 418 |  | 
|---|
| 419 |         // if on the command line was given -I- , this has to be propagated | 
|---|
| 420 |             if (ip.seen_separator)  | 
|---|
| 421 |                 ctx.set_sysinclude_delimiter(); | 
|---|
| 422 |                   | 
|---|
| 423 |         // add system include directories to the include path | 
|---|
| 424 |             vector<string>::const_iterator sysend = ip.syspaths.end(); | 
|---|
| 425 |             for (vector<string>::const_iterator syscit = ip.syspaths.begin();  | 
|---|
| 426 |                  syscit != sysend; ++syscit) | 
|---|
| 427 |             { | 
|---|
| 428 |                 ctx.add_sysinclude_path((*syscit).c_str()); | 
|---|
| 429 |             } | 
|---|
| 430 |         } | 
|---|
| 431 |      | 
|---|
| 432 |     // add additional defined macros  | 
|---|
| 433 |         if (vm.count("define")) { | 
|---|
| 434 |             vector<string> const ¯os = vm["define"].as<vector<string> >(); | 
|---|
| 435 |             vector<string>::const_iterator end = macros.end(); | 
|---|
| 436 |             for (vector<string>::const_iterator cit = macros.begin();  | 
|---|
| 437 |                  cit != end; ++cit) | 
|---|
| 438 |             { | 
|---|
| 439 |                 ctx.add_macro_definition(*cit); | 
|---|
| 440 |             } | 
|---|
| 441 |         } | 
|---|
| 442 |  | 
|---|
| 443 |     // add additional predefined macros  | 
|---|
| 444 |         if (vm.count("predefine")) { | 
|---|
| 445 |             vector<string> const &predefmacros =  | 
|---|
| 446 |                 vm["predefine"].as<vector<string> >(); | 
|---|
| 447 |             vector<string>::const_iterator end = predefmacros.end(); | 
|---|
| 448 |             for (vector<string>::const_iterator cit = predefmacros.begin();  | 
|---|
| 449 |                  cit != end; ++cit) | 
|---|
| 450 |             { | 
|---|
| 451 |                 ctx.add_macro_definition(*cit, true); | 
|---|
| 452 |             } | 
|---|
| 453 |         } | 
|---|
| 454 |  | 
|---|
| 455 |     // undefine specified macros | 
|---|
| 456 |         if (vm.count("undefine")) { | 
|---|
| 457 |             vector<string> const &undefmacros =  | 
|---|
| 458 |                 vm["undefine"].as<vector<string> >(); | 
|---|
| 459 |             vector<string>::const_iterator end = undefmacros.end(); | 
|---|
| 460 |             for (vector<string>::const_iterator cit = undefmacros.begin();  | 
|---|
| 461 |                  cit != end; ++cit) | 
|---|
| 462 |             { | 
|---|
| 463 |                 ctx.remove_macro_definition((*cit).c_str(), true); | 
|---|
| 464 |             } | 
|---|
| 465 |         } | 
|---|
| 466 |  | 
|---|
| 467 |     // maximal include nesting depth | 
|---|
| 468 |         if (vm.count("nesting")) { | 
|---|
| 469 |             int max_depth = vm["nesting"].as<int>(); | 
|---|
| 470 |             if (max_depth < 1 || max_depth > 100000) { | 
|---|
| 471 |                 cerr << "wave: bogus maximal include nesting depth: "  | 
|---|
| 472 |                     << max_depth << endl; | 
|---|
| 473 |                 return -1; | 
|---|
| 474 |             } | 
|---|
| 475 |             ctx.set_max_include_nesting_depth(max_depth); | 
|---|
| 476 |         } | 
|---|
| 477 |          | 
|---|
| 478 |     // open the output file | 
|---|
| 479 |     std::ofstream output; | 
|---|
| 480 |      | 
|---|
| 481 |         if (vm.count("output")) { | 
|---|
| 482 |         // try to open the file, where to put the preprocessed output | 
|---|
| 483 |         string out_file (vm["output"].as<string>()); | 
|---|
| 484 |          | 
|---|
| 485 |             output.open(out_file.c_str()); | 
|---|
| 486 |             if (!output.is_open()) { | 
|---|
| 487 |                 cerr << "wave: could not open output file: " << out_file << endl; | 
|---|
| 488 |                 return -1; | 
|---|
| 489 |             } | 
|---|
| 490 |         } | 
|---|
| 491 |         else { | 
|---|
| 492 |         // output the preprocessed result to std::cout | 
|---|
| 493 |             output.copyfmt(cout); | 
|---|
| 494 |             output.clear(cout.rdstate()); | 
|---|
| 495 |             static_cast<std::basic_ios<char> &>(output).rdbuf(cout.rdbuf()); | 
|---|
| 496 |         } | 
|---|
| 497 |  | 
|---|
| 498 |     // analyze the input file | 
|---|
| 499 |     auto_stop_watch elapsed_time(vm.count("timer") > 0, cout); | 
|---|
| 500 |     context_type::iterator_type first = ctx.begin(); | 
|---|
| 501 |     context_type::iterator_type last = ctx.end(); | 
|---|
| 502 |      | 
|---|
| 503 |     // preprocess the required include files  | 
|---|
| 504 |         if (vm.count("forceinclude")) { | 
|---|
| 505 |         // add the filenames to force as include files in _reverse_ order | 
|---|
| 506 |         // the second parameter 'is_last' of the force_include function should | 
|---|
| 507 |         // be set to true for the last (first given) file. | 
|---|
| 508 |             vector<string> const &force =  | 
|---|
| 509 |                 vm["forceinclude"].as<vector<string> >(); | 
|---|
| 510 |             vector<string>::const_reverse_iterator rend = force.rend(); | 
|---|
| 511 |             for (vector<string>::const_reverse_iterator cit = force.rbegin();  | 
|---|
| 512 |                  cit != rend; /**/) | 
|---|
| 513 |             { | 
|---|
| 514 |                 string filename(*cit); | 
|---|
| 515 |                 first.force_include(filename.c_str(), ++cit == rend); | 
|---|
| 516 |             } | 
|---|
| 517 |         } | 
|---|
| 518 |  | 
|---|
| 519 |     // >>>>>>>>>>>>> Here the actual preprocessing happens. <<<<<<<<<<<<<<<<<<< | 
|---|
| 520 |     // loop over all generated tokens outputting the generated text  | 
|---|
| 521 |         while (first != last) { | 
|---|
| 522 |         // store the last known good token position | 
|---|
| 523 |             current_position = (*first).get_position(); | 
|---|
| 524 |  | 
|---|
| 525 |         // print out the current token value | 
|---|
| 526 |             output << (*first).get_value(); | 
|---|
| 527 |  | 
|---|
| 528 |         // advance to the next token | 
|---|
| 529 |             ++first; | 
|---|
| 530 |         } | 
|---|
| 531 |     } | 
|---|
| 532 |     catch (boost::wave::cpp_exception &e) { | 
|---|
| 533 |     // some preprocessing error | 
|---|
| 534 |         cerr  | 
|---|
| 535 |             << e.file_name() << "(" << e.line_no() << "): " | 
|---|
| 536 |             << e.description() << endl; | 
|---|
| 537 |         return 1; | 
|---|
| 538 |     } | 
|---|
| 539 |     catch (boost::wave::cpplexer::lexing_exception &e) { | 
|---|
| 540 |     // some lexing error | 
|---|
| 541 |         cerr  | 
|---|
| 542 |             << e.file_name() << "(" << e.line_no() << "): " | 
|---|
| 543 |             << e.description() << endl; | 
|---|
| 544 |         return 2; | 
|---|
| 545 |     } | 
|---|
| 546 |     catch (std::exception &e) { | 
|---|
| 547 |     // use last recognized token to retrieve the error position | 
|---|
| 548 |         cerr  | 
|---|
| 549 |             << current_position.get_file()  | 
|---|
| 550 |             << "(" << current_position.get_line() << "): " | 
|---|
| 551 |             << "exception caught: " << e.what() | 
|---|
| 552 |             << endl; | 
|---|
| 553 |         return 3; | 
|---|
| 554 |     } | 
|---|
| 555 |     catch (...) { | 
|---|
| 556 |     // use last recognized token to retrieve the error position | 
|---|
| 557 |         cerr  | 
|---|
| 558 |             << current_position.get_file()  | 
|---|
| 559 |             << "(" << current_position.get_line() << "): " | 
|---|
| 560 |             << "unexpected exception caught." << endl; | 
|---|
| 561 |         return 4; | 
|---|
| 562 |     } | 
|---|
| 563 |     return 0; | 
|---|
| 564 | } | 
|---|
| 565 |  | 
|---|
| 566 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 567 | //  main entry point | 
|---|
| 568 | int | 
|---|
| 569 | main (int argc, char *argv[]) | 
|---|
| 570 | { | 
|---|
| 571 |     try { | 
|---|
| 572 |     // analyze the command line options and arguments | 
|---|
| 573 |      | 
|---|
| 574 |     // declare the options allowed from the command line only | 
|---|
| 575 |     po::options_description desc_cmdline ("Options allowed on the command line only"); | 
|---|
| 576 |          | 
|---|
| 577 |         desc_cmdline.add_options() | 
|---|
| 578 |             ("help,h", "print out program usage (this message)") | 
|---|
| 579 |             ("version,v", "print the version number") | 
|---|
| 580 |             ("copyright,c", "print out the copyright statement") | 
|---|
| 581 |             ("config-file", po::value<vector<string> >()->composing(),  | 
|---|
| 582 |                 "specify a config file (alternatively: @filepath)") | 
|---|
| 583 |         ; | 
|---|
| 584 |  | 
|---|
| 585 |     // declare the options allowed on command line and in config files | 
|---|
| 586 |     po::options_description desc_generic ("Options allowed additionally in a config file"); | 
|---|
| 587 |  | 
|---|
| 588 |         desc_generic.add_options() | 
|---|
| 589 |             ("output,o", po::value<string>(),  | 
|---|
| 590 |                 "specify a file to use for output instead of stdout") | 
|---|
| 591 |             ("include,I", po::value<cmd_line_util::include_paths>()->composing(),  | 
|---|
| 592 |                 "specify an additional include directory") | 
|---|
| 593 |             ("sysinclude,S", po::value<vector<string> >()->composing(),  | 
|---|
| 594 |                 "specify an additional system include directory") | 
|---|
| 595 |             ("forceinclude,F", po::value<vector<string> >()->composing(), | 
|---|
| 596 |                 "force inclusion of the given file") | 
|---|
| 597 |             ("define,D", po::value<vector<string> >()->composing(),  | 
|---|
| 598 |                 "specify a macro to define (as macro[=[value]])") | 
|---|
| 599 |             ("predefine,P", po::value<vector<string> >()->composing(),  | 
|---|
| 600 |                 "specify a macro to predefine (as macro[=[value]])") | 
|---|
| 601 |             ("undefine,U", po::value<vector<string> >()->composing(),  | 
|---|
| 602 |                 "specify a macro to undefine") | 
|---|
| 603 |             ("nesting,n", po::value<int>(),  | 
|---|
| 604 |                 "specify a new maximal include nesting depth") | 
|---|
| 605 |         ; | 
|---|
| 606 |          | 
|---|
| 607 |     po::options_description desc_ext ("Extended options (allowed everywhere)"); | 
|---|
| 608 |  | 
|---|
| 609 |         desc_ext.add_options() | 
|---|
| 610 |             ("traceto,t", po::value<string>(),  | 
|---|
| 611 |                 "output trace info to a file [arg] or to stderr [-]") | 
|---|
| 612 |             ("timer", "output overall elapsed computing time to stderr") | 
|---|
| 613 |             ("long_long", "enable long long support in C++ mode") | 
|---|
| 614 | #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | 
|---|
| 615 |             ("variadics", "enable certain C99 extensions in C++ mode") | 
|---|
| 616 |             ("c99", "enable C99 mode (implies --variadics)") | 
|---|
| 617 | #endif  | 
|---|
| 618 |             ("listincludes,l", po::value<string>(),  | 
|---|
| 619 |                 "list included file to a file [arg] or to stdout [-]") | 
|---|
| 620 |             ("preserve,p", "preserve comments") | 
|---|
| 621 |         ; | 
|---|
| 622 |      | 
|---|
| 623 |     // combine the options for the different usage schemes | 
|---|
| 624 |     po::options_description desc_overall_cmdline; | 
|---|
| 625 |     po::options_description desc_overall_cfgfile; | 
|---|
| 626 |  | 
|---|
| 627 |         desc_overall_cmdline.add(desc_cmdline).add(desc_generic).add(desc_ext); | 
|---|
| 628 |         desc_overall_cfgfile.add(desc_generic).add(desc_ext); | 
|---|
| 629 |          | 
|---|
| 630 |     // parse command line and store results | 
|---|
| 631 |         using namespace boost::program_options::command_line_style; | 
|---|
| 632 |  | 
|---|
| 633 |     po::parsed_options opts(po::parse_command_line(argc, argv,  | 
|---|
| 634 |             desc_overall_cmdline, unix_style, cmd_line_util::at_option_parser)); | 
|---|
| 635 |     po::variables_map vm; | 
|---|
| 636 |      | 
|---|
| 637 |         po::store(opts, vm); | 
|---|
| 638 |         po::notify(vm); | 
|---|
| 639 |  | 
|---|
| 640 |     // Try to find a wave.cfg in the same directory as the executable was  | 
|---|
| 641 |     // started from. If this exists, treat it as a wave config file | 
|---|
| 642 |     fs::path filename(argv[0], fs::native); | 
|---|
| 643 |  | 
|---|
| 644 |         filename = filename.branch_path() / "wave.cfg"; | 
|---|
| 645 |         cmd_line_util::read_config_file_options(filename.string(),  | 
|---|
| 646 |             desc_overall_cfgfile, vm, true); | 
|---|
| 647 |  | 
|---|
| 648 |     // if there is specified at least one config file, parse it and add the  | 
|---|
| 649 |     // options to the main variables_map | 
|---|
| 650 |         if (vm.count("config-file")) { | 
|---|
| 651 |             vector<string> const &cfg_files =  | 
|---|
| 652 |                 vm["config-file"].as<vector<string> >(); | 
|---|
| 653 |             vector<string>::const_iterator end = cfg_files.end(); | 
|---|
| 654 |             for (vector<string>::const_iterator cit = cfg_files.begin();  | 
|---|
| 655 |                  cit != end; ++cit) | 
|---|
| 656 |             { | 
|---|
| 657 |             // parse a single config file and store the results | 
|---|
| 658 |                 cmd_line_util::read_config_file_options(*cit,  | 
|---|
| 659 |                     desc_overall_cfgfile, vm); | 
|---|
| 660 |             } | 
|---|
| 661 |         } | 
|---|
| 662 |  | 
|---|
| 663 |     // ... act as required  | 
|---|
| 664 |         if (vm.count("help")) { | 
|---|
| 665 |         po::options_description desc_help ( | 
|---|
| 666 |             "Usage: wave [options] [@config-file(s)] [file]"); | 
|---|
| 667 |  | 
|---|
| 668 |             desc_help.add(desc_cmdline).add(desc_generic).add(desc_ext); | 
|---|
| 669 |             cout << desc_help << endl; | 
|---|
| 670 |             return 1; | 
|---|
| 671 |         } | 
|---|
| 672 |          | 
|---|
| 673 |         if (vm.count("version")) { | 
|---|
| 674 |             return print_version(); | 
|---|
| 675 |         } | 
|---|
| 676 |  | 
|---|
| 677 |         if (vm.count("copyright")) { | 
|---|
| 678 |             return print_copyright(); | 
|---|
| 679 |         } | 
|---|
| 680 |  | 
|---|
| 681 |     // extract the arguments from the parsed command line | 
|---|
| 682 |     vector<po::option> arguments; | 
|---|
| 683 |      | 
|---|
| 684 |         std::remove_copy_if(opts.options.begin(), opts.options.end(),  | 
|---|
| 685 |             back_inserter(arguments), cmd_line_util::is_argument()); | 
|---|
| 686 |              | 
|---|
| 687 |     // if there is no input file given, then take input from stdin | 
|---|
| 688 |         if (0 == arguments.size() || 0 == arguments[0].value.size() || | 
|---|
| 689 |             arguments[0].value[0] == "-")  | 
|---|
| 690 |         { | 
|---|
| 691 |         // preprocess the given input from stdin | 
|---|
| 692 |             return do_actual_work("stdin", std::cin, vm); | 
|---|
| 693 |         } | 
|---|
| 694 |         else { | 
|---|
| 695 |         std::string file_name(arguments[0].value[0]); | 
|---|
| 696 |         ifstream instream(file_name.c_str()); | 
|---|
| 697 |  | 
|---|
| 698 |         // preprocess the given input file | 
|---|
| 699 |             if (!instream.is_open()) { | 
|---|
| 700 |                 cerr << "wave: could not open input file: " << file_name << endl; | 
|---|
| 701 |                 return -1; | 
|---|
| 702 |             } | 
|---|
| 703 |             return do_actual_work(file_name, instream, vm); | 
|---|
| 704 |         } | 
|---|
| 705 |     } | 
|---|
| 706 |     catch (std::exception &e) { | 
|---|
| 707 |         cout << "wave: exception caught: " << e.what() << endl; | 
|---|
| 708 |         return 6; | 
|---|
| 709 |     } | 
|---|
| 710 |     catch (...) { | 
|---|
| 711 |         cerr << "wave: unexpected exception caught." << endl; | 
|---|
| 712 |         return 7; | 
|---|
| 713 |     } | 
|---|
| 714 | } | 
|---|
| 715 |  | 
|---|