]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/wave/tool/cpp.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / wave / tool / cpp.cpp
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3
4 http://www.boost.org/
5
6 Copyright (c) 2001-2012 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 #define BOOST_WAVE_SERIALIZATION 0 // enable serialization
12 #define BOOST_WAVE_BINARY_SERIALIZATION 0 // use binary archives
13 #define BOOST_WAVE_XML_SERIALIZATION 1 // use XML archives
14
15 #include "cpp.hpp" // global configuration
16
17 ///////////////////////////////////////////////////////////////////////////////
18 // Include additional Boost libraries
19 #include <boost/filesystem/path.hpp>
20 #include <boost/filesystem/convenience.hpp>
21 #include <boost/timer.hpp>
22 #include <boost/any.hpp>
23 #include <boost/algorithm/cxx11/any_of.hpp>
24 #include <boost/algorithm/string/join.hpp>
25 #include <boost/range/algorithm/find.hpp>
26 #include <boost/range/end.hpp>
27 #include <boost/foreach.hpp>
28
29 ///////////////////////////////////////////////////////////////////////////////
30 // Include Wave itself
31 #include <boost/wave.hpp>
32
33 ///////////////////////////////////////////////////////////////////////////////
34 // Include the lexer related stuff
35 #include <boost/wave/cpplexer/cpp_lex_token.hpp> // token type
36 #include <boost/wave/cpplexer/cpp_lex_iterator.hpp> // lexer type
37
38 ///////////////////////////////////////////////////////////////////////////////
39 // Include serialization support, if requested
40 #if BOOST_WAVE_SERIALIZATION != 0
41 #include <boost/serialization/serialization.hpp>
42 #if BOOST_WAVE_BINARY_SERIALIZATION != 0
43 #include <boost/archive/binary_iarchive.hpp>
44 #include <boost/archive/binary_oarchive.hpp>
45 typedef boost::archive::binary_iarchive iarchive;
46 typedef boost::archive::binary_oarchive oarchive;
47 #elif BOOST_WAVE_XML_SERIALIZATION != 0
48 #include <boost/archive/xml_iarchive.hpp>
49 #include <boost/archive/xml_oarchive.hpp>
50 typedef boost::archive::xml_iarchive iarchive;
51 typedef boost::archive::xml_oarchive oarchive;
52 #else
53 #include <boost/archive/text_iarchive.hpp>
54 #include <boost/archive/text_oarchive.hpp>
55 typedef boost::archive::text_iarchive iarchive;
56 typedef boost::archive::text_oarchive oarchive;
57 #endif
58 #endif
59
60 ///////////////////////////////////////////////////////////////////////////////
61 // Include the context policies to use
62 #include "trace_macro_expansion.hpp"
63
64 ///////////////////////////////////////////////////////////////////////////////
65 // Include lexer specifics, import lexer names
66 #if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0
67 #include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp>
68 #endif
69
70 ///////////////////////////////////////////////////////////////////////////////
71 // Include the grammar definitions, if these shouldn't be compiled separately
72 // (ATTENTION: _very_ large compilation times!)
73 #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0
74 #include <boost/wave/grammars/cpp_intlit_grammar.hpp>
75 #include <boost/wave/grammars/cpp_chlit_grammar.hpp>
76 #include <boost/wave/grammars/cpp_grammar.hpp>
77 #include <boost/wave/grammars/cpp_expression_grammar.hpp>
78 #include <boost/wave/grammars/cpp_predef_macros_grammar.hpp>
79 #include <boost/wave/grammars/cpp_defined_grammar.hpp>
80 #endif
81
82 ///////////////////////////////////////////////////////////////////////////////
83 // Import required names
84 using namespace boost::spirit::classic;
85
86 using std::pair;
87 using std::vector;
88 using std::getline;
89 using std::ofstream;
90 using std::cout;
91 using std::cerr;
92 using std::endl;
93 using std::ostream;
94 using std::istreambuf_iterator;
95
96 ///////////////////////////////////////////////////////////////////////////////
97 //
98 // This application uses the lex_iterator and lex_token types predefined
99 // with the Wave library, but it is possible to use your own types.
100 //
101 // You may want to have a look at the other samples to see how this is
102 // possible to achieve.
103 typedef boost::wave::cpplexer::lex_token<> token_type;
104 typedef boost::wave::cpplexer::lex_iterator<token_type>
105 lex_iterator_type;
106
107 // The C++ preprocessor iterators shouldn't be constructed directly. They
108 // are to be generated through a boost::wave::context<> object. This
109 // boost::wave::context object is additionally to be used to initialize and
110 // define different parameters of the actual preprocessing.
111 typedef boost::wave::context<
112 std::string::iterator, lex_iterator_type,
113 boost::wave::iteration_context_policies::load_file_to_string,
114 trace_macro_expansion<token_type> >
115 context_type;
116
117 ///////////////////////////////////////////////////////////////////////////////
118 // print the current version
119 std::string get_version()
120 {
121 std::string version (context_type::get_version_string());
122 version = version.substr(1, version.size()-2); // strip quotes
123 version += std::string(" (" CPP_VERSION_DATE_STR ")"); // add date
124 return version;
125 }
126
127 ///////////////////////////////////////////////////////////////////////////////
128 // print the current version for interactive sessions
129 int print_interactive_version()
130 {
131 cout << "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library" << endl;
132 cout << "Version: " << get_version() << endl;
133 return 0;
134 }
135
136 ///////////////////////////////////////////////////////////////////////////////
137 // print the copyright statement
138 int print_copyright()
139 {
140 char const *copyright[] = {
141 "",
142 "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library",
143 "http://www.boost.org/",
144 "",
145 "Copyright (c) 2001-2012 Hartmut Kaiser, Distributed under the Boost",
146 "Software License, Version 1.0. (See accompanying file",
147 "LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)",
148 0
149 };
150
151 for (int i = 0; 0 != copyright[i]; ++i)
152 cout << copyright[i] << endl;
153
154 return 0; // exit app
155 }
156
157 ///////////////////////////////////////////////////////////////////////////////
158 // forward declarations only
159 namespace cmd_line_utils
160 {
161 class include_paths;
162 }
163
164 namespace boost { namespace program_options {
165
166 void validate(boost::any &v, std::vector<std::string> const &s,
167 cmd_line_utils::include_paths *, long);
168
169 }} // boost::program_options
170
171 ///////////////////////////////////////////////////////////////////////////////
172 #include <boost/program_options.hpp>
173
174 namespace po = boost::program_options;
175 namespace fs = boost::filesystem;
176
177 ///////////////////////////////////////////////////////////////////////////////
178 namespace cmd_line_utils {
179 // Additional command line parser which interprets '@something' as an
180 // option "config-file" with the value "something".
181 inline pair<std::string, std::string>
182 at_option_parser(std::string const&s)
183 {
184 if ('@' == s[0])
185 return std::make_pair(std::string("config-file"), s.substr(1));
186 else
187 return pair<std::string, std::string>();
188 }
189
190 // class, which keeps include file information read from the command line
191 class include_paths {
192 public:
193 include_paths() : seen_separator(false) {}
194
195 vector<std::string> paths; // stores user paths
196 vector<std::string> syspaths; // stores system paths
197 bool seen_separator; // command line contains a '-I-' option
198
199 // Function which validates additional tokens from command line.
200 static void
201 validate(boost::any &v, vector<std::string> const &tokens)
202 {
203 if (v.empty())
204 v = boost::any(include_paths());
205
206 include_paths *p = boost::any_cast<include_paths>(&v);
207
208 BOOST_ASSERT(p);
209 // Assume only one path per '-I' occurrence.
210 std::string const& t = po::validators::get_single_string(tokens);
211 if (t == "-") {
212 // found -I- option, so switch behaviour
213 p->seen_separator = true;
214 }
215 else if (p->seen_separator) {
216 // store this path as a system path
217 p->syspaths.push_back(t);
218 }
219 else {
220 // store this path as an user path
221 p->paths.push_back(t);
222 }
223 }
224 };
225
226 // Read all options from a given config file, parse and add them to the
227 // given variables_map
228 bool read_config_file_options(std::string const &filename,
229 po::options_description const &desc, po::variables_map &vm,
230 bool may_fail = false)
231 {
232 std::ifstream ifs(filename.c_str());
233
234 if (!ifs.is_open()) {
235 if (!may_fail) {
236 cerr << filename
237 << ": command line warning: config file not found"
238 << endl;
239 }
240 return false;
241 }
242
243 vector<std::string> options;
244 std::string line;
245
246 while (std::getline(ifs, line)) {
247 // skip empty lines
248 std::string::size_type pos = line.find_first_not_of(" \t");
249 if (pos == std::string::npos)
250 continue;
251
252 // skip comment lines
253 if ('#' != line[pos]) {
254 // strip leading and trailing whitespace
255 std::string::size_type endpos = line.find_last_not_of(" \t");
256 BOOST_ASSERT(endpos != std::string::npos);
257 options.push_back(line.substr(pos, endpos-pos+1));
258 }
259 }
260
261 if (options.size() > 0) {
262 using namespace boost::program_options::command_line_style;
263 po::store(po::command_line_parser(options)
264 .options(desc).style(unix_style).run(), vm);
265 po::notify(vm);
266 }
267 return true;
268 }
269
270 // predicate to extract all positional arguments from the command line
271 struct is_argument {
272 bool operator()(po::option const &opt)
273 {
274 return (opt.position_key == -1) ? true : false;
275 }
276 };
277
278 // trim quotes from path names, if any
279 std::string trim_quotes(std::string const& file)
280 {
281 if (('"' == file[0] || '\'' == file[0]) && file[0] == file[file.size()-1])
282 {
283 return file.substr(1, file.size()-2);
284 }
285 return file;
286 }
287
288 ///////////////////////////////////////////////////////////////////////////////
289 }
290
291 ///////////////////////////////////////////////////////////////////////////////
292 //
293 // Special validator overload, which allows to handle the -I- syntax for
294 // switching the semantics of an -I option.
295 //
296 ///////////////////////////////////////////////////////////////////////////////
297 namespace boost { namespace program_options {
298
299 void validate(boost::any &v, std::vector<std::string> const &s,
300 cmd_line_utils::include_paths *, long)
301 {
302 cmd_line_utils::include_paths::validate(v, s);
303 }
304
305 }} // namespace boost::program_options
306
307 ///////////////////////////////////////////////////////////////////////////////
308 namespace {
309
310 class auto_stop_watch : public stop_watch
311 {
312 public:
313 auto_stop_watch(std::ostream &outstrm_)
314 : print_time(false), outstrm(outstrm_)
315 {
316 }
317
318 ~auto_stop_watch()
319 {
320 if (print_time) {
321 outstrm << "Elapsed time: "
322 << this->format_elapsed_time()
323 << std::endl;
324 }
325 }
326
327 void set_print_time(bool print_time_)
328 {
329 print_time = print_time_;
330 }
331
332 private:
333 bool print_time;
334 std::ostream &outstrm;
335 };
336
337 ///////////////////////////////////////////////////////////////////////////
338 inline std::string
339 report_iostate_error(std::ios::iostate state)
340 {
341 BOOST_ASSERT(state & (std::ios::badbit | std::ios::failbit | std::ios::eofbit));
342 std::string result;
343 if (state & std::ios::badbit) {
344 result += " the reported problem was: "
345 "loss of integrity of the stream buffer\n";
346 }
347 if (state & std::ios::failbit) {
348 result += " the reported problem was: "
349 "an operation was not processed correctly\n";
350 }
351 if (state & std::ios::eofbit) {
352 result += " the reported problem was: "
353 "end-of-file while writing to the stream\n";
354 }
355 return result;
356 }
357
358 ///////////////////////////////////////////////////////////////////////////
359 // Retrieve the position of a macro definition
360 template <typename Context>
361 inline bool
362 get_macro_position(Context &ctx,
363 typename Context::token_type::string_type const& name,
364 typename Context::position_type &pos)
365 {
366 bool has_parameters = false;
367 bool is_predefined = false;
368 std::vector<typename Context::token_type> parameters;
369 typename Context::token_sequence_type definition;
370
371 return ctx.get_macro_definition(name, has_parameters, is_predefined,
372 pos, parameters, definition);
373 }
374
375 ///////////////////////////////////////////////////////////////////////////
376 // Generate some meaningful error messages
377 template <typename Exception>
378 inline int
379 report_error_message(Exception const &e, bool treat_warnings_as_error)
380 {
381 // default error reporting
382 cerr
383 << e.file_name() << ":" << e.line_no() << ":" << e.column_no()
384 << ": " << e.description() << endl;
385
386 // errors count as one
387 return (treat_warnings_as_error ||
388 e.get_severity() == boost::wave::util::severity_error ||
389 e.get_severity() == boost::wave::util::severity_fatal) ? 1 : 0;
390 }
391
392 template <typename Context>
393 inline int
394 report_error_message(Context &ctx, boost::wave::cpp_exception const &e,
395 bool treat_warnings_as_error)
396 {
397 // default error reporting
398 int result = report_error_message(e, treat_warnings_as_error);
399
400 using boost::wave::preprocess_exception;
401 switch(e.get_errorcode()) {
402 case preprocess_exception::macro_redefinition:
403 {
404 // report the point of the initial macro definition
405 typename Context::position_type pos;
406 if (get_macro_position(ctx, e.get_related_name(), pos)) {
407 cerr
408 << pos << ": "
409 << preprocess_exception::severity_text(e.get_severity())
410 << ": this is the location of the previous definition."
411 << endl;
412 }
413 else {
414 cerr
415 << e.file_name() << ":" << e.line_no() << ":"
416 << e.column_no() << ": "
417 << preprocess_exception::severity_text(e.get_severity())
418 << ": not able to retrieve the location of the previous "
419 << "definition." << endl;
420 }
421 }
422 break;
423
424 default:
425 break;
426 }
427
428 return result;
429 }
430
431 ///////////////////////////////////////////////////////////////////////////
432 // Read one logical line of text
433 inline bool
434 read_a_line (std::istream &instream, std::string &instring)
435 {
436 bool eol = true;
437 do {
438 std::string line;
439 std::getline(instream, line);
440 if (instream.rdstate() & std::ios::failbit)
441 return false; // nothing to do
442
443 eol = true;
444 if (line.find_last_of('\\') == line.size()-1)
445 eol = false;
446
447 instring += line + '\n';
448 } while (!eol);
449 return true;
450 }
451
452 ///////////////////////////////////////////////////////////////////////////
453 // Load and save the internal tables of the wave::context object
454 template <typename Context>
455 inline void
456 load_state(po::variables_map const &vm, Context &ctx)
457 {
458 #if BOOST_WAVE_SERIALIZATION != 0
459 try {
460 if (vm.count("state") > 0) {
461 fs::path state_file (
462 boost::wave::util::create_path(vm["state"].as<std::string>()));
463 if (state_file == "-")
464 state_file = boost::wave::util::create_path("wave.state");
465
466 std::ios::openmode mode = std::ios::in;
467
468 #if BOOST_WAVE_BINARY_SERIALIZATION != 0
469 mode = (std::ios::openmode)(mode | std::ios::binary);
470 #endif
471 std::ifstream ifs (state_file.string().c_str(), mode);
472 if (ifs.is_open()) {
473 using namespace boost::serialization;
474 iarchive ia(ifs);
475 std::string version;
476
477 ia >> make_nvp("version", version); // load version
478 if (version == CPP_VERSION_FULL_STR)
479 ia >> make_nvp("state", ctx); // load the internal tables from disc
480 else {
481 cerr << "wave: detected version mismatch while loading state, state was not loaded." << endl;
482 cerr << " loaded version: " << version << endl;
483 cerr << " expected version: " << CPP_VERSION_FULL_STR << endl;
484 }
485 }
486 }
487 }
488 catch (boost::archive::archive_exception const& e) {
489 cerr << "wave: error while loading state: "
490 << e.what() << endl;
491 }
492 catch (boost::wave::preprocess_exception const& e) {
493 cerr << "wave: error while loading state: "
494 << e.description() << endl;
495 }
496 #endif
497 }
498
499 template <typename Context>
500 inline void
501 save_state(po::variables_map const &vm, Context const &ctx)
502 {
503 #if BOOST_WAVE_SERIALIZATION != 0
504 try {
505 if (vm.count("state") > 0) {
506 fs::path state_file (boost::wave::util::create_path(
507 vm["state"].as<std::string>()));
508 if (state_file == "-")
509 state_file = boost::wave::util::create_path("wave.state");
510
511 std::ios::openmode mode = std::ios::out;
512
513 #if BOOST_WAVE_BINARY_SERIALIZATION != 0
514 mode = (std::ios::openmode)(mode | std::ios::binary);
515 #endif
516 ofstream ofs(state_file.string().c_str(), mode);
517 if (!ofs.is_open()) {
518 cerr << "wave: could not open state file for writing: "
519 << state_file.string() << endl;
520 // this is non-fatal
521 }
522 else {
523 using namespace boost::serialization;
524 oarchive oa(ofs);
525 std::string version(CPP_VERSION_FULL_STR);
526 oa << make_nvp("version", version); // write version
527 oa << make_nvp("state", ctx); // write the internal tables to disc
528 }
529 }
530 }
531 catch (boost::archive::archive_exception const& e) {
532 cerr << "wave: error while writing state: "
533 << e.what() << endl;
534 }
535 #endif
536 }
537
538 ///////////////////////////////////////////////////////////////////////////
539 // list all defined macros
540 bool list_macro_names(context_type const& ctx, std::string filename)
541 {
542 // open file for macro names listing
543 std::ofstream macronames_out;
544 fs::path macronames_file (boost::wave::util::create_path(filename));
545
546 if (macronames_file != "-") {
547 macronames_file = boost::wave::util::complete_path(macronames_file);
548 boost::wave::util::create_directories(
549 boost::wave::util::branch_path(macronames_file));
550 macronames_out.open(macronames_file.string().c_str());
551 if (!macronames_out.is_open()) {
552 cerr << "wave: could not open file for macro name listing: "
553 << macronames_file.string() << endl;
554 return false;
555 }
556 }
557 else {
558 macronames_out.copyfmt(cout);
559 macronames_out.clear(cout.rdstate());
560 static_cast<std::basic_ios<char> &>(macronames_out).rdbuf(cout.rdbuf());
561 }
562
563 // simply list all defined macros and its definitions
564 typedef context_type::const_name_iterator name_iterator;
565 name_iterator end = ctx.macro_names_end();
566 for (name_iterator it = ctx.macro_names_begin(); it != end; ++it)
567 {
568 typedef std::vector<context_type::token_type> parameters_type;
569
570 bool has_pars = false;
571 bool predef = false;
572 context_type::position_type pos;
573 parameters_type pars;
574 context_type::token_sequence_type def;
575
576 if (ctx.get_macro_definition(*it, has_pars, predef, pos, pars, def))
577 {
578 macronames_out << (predef ? "-P" : "-D") << *it;
579 if (has_pars) {
580 // list the parameter names for function style macros
581 macronames_out << "(";
582 parameters_type::const_iterator pend = pars.end();
583 for (parameters_type::const_iterator pit = pars.begin();
584 pit != pend; /**/)
585 {
586 macronames_out << (*pit).get_value();
587 if (++pit != pend)
588 macronames_out << ", ";
589 }
590 macronames_out << ")";
591 }
592 macronames_out << "=";
593
594 // print the macro definition
595 context_type::token_sequence_type::const_iterator dend = def.end();
596 for (context_type::token_sequence_type::const_iterator dit = def.begin();
597 dit != dend; ++dit)
598 {
599 macronames_out << (*dit).get_value();
600 }
601
602 macronames_out << std::endl;
603 }
604 }
605 return true;
606 }
607
608 ///////////////////////////////////////////////////////////////////////////
609 // list macro invocation counts
610 bool list_macro_counts(context_type const& ctx, std::string filename)
611 {
612 // open file for macro invocation count listing
613 std::ofstream macrocounts_out;
614 fs::path macrocounts_file (boost::wave::util::create_path(filename));
615
616 if (macrocounts_file != "-") {
617 macrocounts_file = boost::wave::util::complete_path(macrocounts_file);
618 boost::wave::util::create_directories(
619 boost::wave::util::branch_path(macrocounts_file));
620 macrocounts_out.open(macrocounts_file.string().c_str());
621 if (!macrocounts_out.is_open()) {
622 cerr << "wave: could not open file for macro invocation count listing: "
623 << macrocounts_file.string() << endl;
624 return false;
625 }
626 }
627 else {
628 macrocounts_out.copyfmt(cout);
629 macrocounts_out.clear(cout.rdstate());
630 static_cast<std::basic_ios<char> &>(macrocounts_out).rdbuf(cout.rdbuf());
631 }
632
633 // list all expanded macro names and their counts in alphabetical order
634 std::map<std::string, std::size_t> const& counts =
635 ctx.get_hooks().get_macro_counts();
636
637 typedef std::map<std::string, std::size_t>::const_iterator iterator;
638 iterator end = counts.end();
639 for (iterator it = counts.begin(); it != end; ++it)
640 macrocounts_out << (*it).first << "," << (*it).second << std::endl;
641
642 return true;
643 }
644
645 ///////////////////////////////////////////////////////////////////////////
646 // read all of a file into a string
647 std::string read_entire_file(std::istream& instream)
648 {
649 std::string content;
650
651 instream.unsetf(std::ios::skipws);
652
653 #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
654 // this is known to be very slow for large files on some systems
655 copy (std::istream_iterator<char>(instream),
656 std::istream_iterator<char>(),
657 std::inserter(content, content.end()));
658 #else
659 content = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
660 std::istreambuf_iterator<char>());
661 #endif
662 return content;
663 }
664 } // anonymous namespace
665
666 ///////////////////////////////////////////////////////////////////////////////
667 // do the actual preprocessing
668 int
669 do_actual_work (std::string file_name, std::istream &instream,
670 po::variables_map const &vm, bool input_is_stdin)
671 {
672 // current file position is saved for exception handling
673 boost::wave::util::file_position_type current_position;
674 auto_stop_watch elapsed_time(cerr);
675 int error_count = 0;
676 const bool treat_warnings_as_error = vm.count("warning") &&
677 boost::algorithm::any_of_equal(
678 vm["warning"].as<std::vector<std::string> >(), "error");
679
680 try {
681 // process the given file
682 std::string instring;
683
684 instream.unsetf(std::ios::skipws);
685 if (!input_is_stdin)
686 instring = read_entire_file(instream);
687
688 // The preprocessing of the input stream is done on the fly behind the
689 // scenes during iteration over the context_type::iterator_type stream.
690 std::ofstream output;
691 std::ofstream traceout;
692 std::ofstream includelistout;
693 std::ofstream listguardsout;
694
695 trace_flags enable_trace = trace_nothing;
696
697 if (vm.count("traceto")) {
698 // try to open the file, where to put the trace output
699 fs::path trace_file (boost::wave::util::create_path(
700 vm["traceto"].as<std::string>()));
701
702 if (trace_file != "-") {
703 boost::wave::util::create_directories(
704 boost::wave::util::branch_path(trace_file));
705 traceout.open(trace_file.string().c_str());
706 if (!traceout.is_open()) {
707 cerr << "wave: could not open trace file: " << trace_file
708 << endl;
709 return -1;
710 }
711 }
712 enable_trace = trace_macros;
713 }
714 if ((enable_trace & trace_macros) && !traceout.is_open()) {
715 // by default trace to std::cerr
716 traceout.copyfmt(cerr);
717 traceout.clear(cerr.rdstate());
718 static_cast<std::basic_ios<char> &>(traceout).rdbuf(cerr.rdbuf());
719 }
720
721 // Open the stream where to output the list of included file names
722 if (vm.count("listincludes")) {
723 // try to open the file, where to put the include list
724 fs::path includes_file(boost::wave::util::create_path(
725 vm["listincludes"].as<std::string>()));
726
727 if (includes_file != "-") {
728 boost::wave::util::create_directories(
729 boost::wave::util::branch_path(includes_file));
730 includelistout.open(includes_file.string().c_str());
731 if (!includelistout.is_open()) {
732 cerr << "wave: could not open include list file: "
733 << includes_file.string() << endl;
734 return -1;
735 }
736 }
737 enable_trace = trace_flags(enable_trace | trace_includes);
738 }
739 if ((enable_trace & trace_includes) && !includelistout.is_open()) {
740 // by default list included names to std::cout
741 includelistout.copyfmt(cout);
742 includelistout.clear(cout.rdstate());
743 static_cast<std::basic_ios<char> &>(includelistout).
744 rdbuf(cout.rdbuf());
745 }
746
747 // Open the stream where to output the list of included file names
748 if (vm.count("listguards")) {
749 // try to open the file, where to put the include list
750 fs::path listguards_file(boost::wave::util::create_path(
751 vm["listguards"].as<std::string>()));
752
753 if (listguards_file != "-") {
754 boost::wave::util::create_directories(
755 boost::wave::util::branch_path(listguards_file));
756 listguardsout.open(listguards_file.string().c_str());
757 if (!listguardsout.is_open()) {
758 cerr << "wave: could not open include guard list file: "
759 << listguards_file.string() << endl;
760 return -1;
761 }
762 }
763 enable_trace = trace_flags(enable_trace | trace_guards);
764 }
765 if ((enable_trace & trace_guards) && !listguardsout.is_open()) {
766 // by default list included names to std::cout
767 listguardsout.copyfmt(cout);
768 listguardsout.clear(cout.rdstate());
769 static_cast<std::basic_ios<char> &>(listguardsout).
770 rdbuf(cout.rdbuf());
771 }
772
773 // enable preserving comments mode
774 bool preserve_comments = false;
775 bool preserve_whitespace = false;
776 bool preserve_bol_whitespace = false;
777
778 if (vm.count("preserve")) {
779 int preserve = vm["preserve"].as<int>();
780
781 switch(preserve) {
782 case 0: break; // preserve no whitespace
783 case 3: // preserve all whitespace
784 preserve_whitespace = true;
785 preserve_comments = true;
786 preserve_bol_whitespace = true;
787 break;
788
789 case 2: // preserve comments and BOL whitespace only
790 preserve_comments = true;
791 preserve_bol_whitespace = true;
792 break;
793
794 case 1: // preserve BOL whitespace only
795 preserve_bol_whitespace = true;
796 break;
797
798 default:
799 cerr << "wave: bogus preserve whitespace option value: "
800 << preserve << ", should be 0, 1, 2, or 3" << endl;
801 return -1;
802 }
803 }
804
805 // Since the #pragma wave system() directive may cause a potential security
806 // threat, it has to be enabled explicitly by --extended or -x
807 bool enable_system_command = false;
808
809 if (vm.count("extended"))
810 enable_system_command = true;
811
812 // This this the central piece of the Wave library, it provides you with
813 // the iterators to get the preprocessed tokens and allows to configure
814 // the preprocessing stage in advance.
815 bool allow_output = true; // will be manipulated from inside the hooks object
816 std::string default_outfile; // will be used from inside the hooks object
817 trace_macro_expansion<token_type> hooks(preserve_whitespace,
818 preserve_bol_whitespace, output, traceout, includelistout,
819 listguardsout, enable_trace, enable_system_command, allow_output,
820 default_outfile);
821
822 // enable macro invocation count, if appropriate
823 if (vm.count("macrocounts"))
824 hooks.enable_macro_counting();
825
826 // check, if we have a license file to prepend
827 std::string license;
828
829 if (vm.count ("license")) {
830 // try to open the file, where to put the preprocessed output
831 std::string license_file(vm["license"].as<std::string>());
832 std::ifstream license_stream(license_file.c_str());
833
834 if (!license_stream.is_open()) {
835 cerr << "wave: could not open specified license file: "
836 << license_file << endl;
837 return -1;
838 }
839 license = read_entire_file(license_stream);
840 hooks.set_license_info(license);
841 }
842
843 context_type ctx (instring.begin(), instring.end(), file_name.c_str(), hooks);
844
845 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
846 // enable C99 mode, if appropriate (implies variadics)
847 if (vm.count("c99")) {
848 #if BOOST_WAVE_SUPPORT_CPP0X != 0
849 if (vm.count("c++11")) {
850 cerr << "wave: multiple language options specified: --c99 "
851 "and --c++11" << endl;
852 return -1;
853 }
854 #endif
855 ctx.set_language(
856 boost::wave::language_support(
857 boost::wave::support_c99
858 | boost::wave::support_option_convert_trigraphs
859 | boost::wave::support_option_emit_line_directives
860 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
861 | boost::wave::support_option_include_guard_detection
862 #endif
863 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
864 | boost::wave::support_option_emit_pragma_directives
865 #endif
866 | boost::wave::support_option_insert_whitespace
867 ));
868 }
869 else if (vm.count("variadics")) {
870 // enable variadics and placemarkers, if appropriate
871 ctx.set_language(boost::wave::enable_variadics(ctx.get_language()));
872 }
873 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
874 #if BOOST_WAVE_SUPPORT_CPP0X != 0
875 if (vm.count("c++11")) {
876 if (vm.count("c99")) {
877 cerr << "wave: multiple language options specified: --c99 "
878 "and --c++11" << endl;
879 return -1;
880 }
881 ctx.set_language(
882 boost::wave::language_support(
883 boost::wave::support_cpp0x
884 | boost::wave::support_option_convert_trigraphs
885 | boost::wave::support_option_long_long
886 | boost::wave::support_option_emit_line_directives
887 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
888 | boost::wave::support_option_include_guard_detection
889 #endif
890 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
891 | boost::wave::support_option_emit_pragma_directives
892 #endif
893 | boost::wave::support_option_insert_whitespace
894 ));
895 }
896 #endif // BOOST_WAVE_SUPPORT_CPP0X != 0
897
898 // enable long long support, if appropriate
899 if (vm.count("long_long")) {
900 ctx.set_language(
901 boost::wave::enable_long_long(ctx.get_language()));
902 }
903
904 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
905 // disable include guard detection
906 if (vm.count("noguard")) {
907 ctx.set_language(
908 boost::wave::enable_include_guard_detection(
909 ctx.get_language(), false));
910 }
911 #endif
912
913 // enable preserving comments mode
914 if (preserve_comments) {
915 ctx.set_language(
916 boost::wave::enable_preserve_comments(ctx.get_language()));
917 }
918
919 // control the generation of #line directives
920 if (vm.count("line")) {
921 int lineopt = vm["line"].as<int>();
922 if (0 != lineopt && 1 != lineopt && 2 != lineopt) {
923 cerr << "wave: bogus value for --line command line option: "
924 << lineopt << endl;
925 return -1;
926 }
927 ctx.set_language(
928 boost::wave::enable_emit_line_directives(ctx.get_language(),
929 lineopt != 0));
930
931 if (2 == lineopt)
932 ctx.get_hooks().enable_relative_names_in_line_directives(true);
933 }
934
935 // control whether whitespace should be inserted to disambiguate output
936 if (vm.count("disambiguate")) {
937 int disambiguateopt = vm["disambiguate"].as<int>();
938 if (0 != disambiguateopt && 1 != disambiguateopt) {
939 cerr << "wave: bogus value for --disambiguate command line option: "
940 << disambiguateopt << endl;
941 return -1;
942 }
943 ctx.set_language(
944 boost::wave::enable_insert_whitespace(ctx.get_language(),
945 disambiguateopt != 0));
946 }
947
948 // add include directories to the system include search paths
949 if (vm.count("sysinclude")) {
950 vector<std::string> syspaths = vm["sysinclude"].as<vector<std::string> >();
951
952 vector<std::string>::const_iterator end = syspaths.end();
953 for (vector<std::string>::const_iterator cit = syspaths.begin();
954 cit != end; ++cit)
955 {
956 ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*cit).c_str());
957 }
958 }
959
960 // add include directories to the include search paths
961 if (vm.count("include")) {
962 cmd_line_utils::include_paths const &ip =
963 vm["include"].as<cmd_line_utils::include_paths>();
964 vector<std::string>::const_iterator end = ip.paths.end();
965
966 for (vector<std::string>::const_iterator cit = ip.paths.begin();
967 cit != end; ++cit)
968 {
969 ctx.add_include_path(cmd_line_utils::trim_quotes(*cit).c_str());
970 }
971
972 // if -I- was given on the command line, this has to be propagated
973 if (ip.seen_separator)
974 ctx.set_sysinclude_delimiter();
975
976 // add system include directories to the include path
977 vector<std::string>::const_iterator sysend = ip.syspaths.end();
978 for (vector<std::string>::const_iterator syscit = ip.syspaths.begin();
979 syscit != sysend; ++syscit)
980 {
981 ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*syscit).c_str());
982 }
983 }
984
985 // add additional defined macros
986 if (vm.count("define")) {
987 vector<std::string> const &macros = vm["define"].as<vector<std::string> >();
988 vector<std::string>::const_iterator end = macros.end();
989 for (vector<std::string>::const_iterator cit = macros.begin();
990 cit != end; ++cit)
991 {
992 ctx.add_macro_definition(*cit);
993 }
994 }
995
996 // add additional predefined macros
997 if (vm.count("predefine")) {
998 vector<std::string> const &predefmacros =
999 vm["predefine"].as<vector<std::string> >();
1000 vector<std::string>::const_iterator end = predefmacros.end();
1001 for (vector<std::string>::const_iterator cit = predefmacros.begin();
1002 cit != end; ++cit)
1003 {
1004 ctx.add_macro_definition(*cit, true);
1005 }
1006 }
1007
1008 // undefine specified macros
1009 if (vm.count("undefine")) {
1010 vector<std::string> const &undefmacros =
1011 vm["undefine"].as<vector<std::string> >();
1012 vector<std::string>::const_iterator end = undefmacros.end();
1013 for (vector<std::string>::const_iterator cit = undefmacros.begin();
1014 cit != end; ++cit)
1015 {
1016 ctx.remove_macro_definition(*cit, true);
1017 }
1018 }
1019
1020 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
1021 // suppress expansion of specified macros
1022 if (vm.count("noexpand")) {
1023 vector<std::string> const &noexpandmacros =
1024 vm["noexpand"].as<vector<std::string> >();
1025 vector<std::string>::const_iterator end = noexpandmacros.end();
1026 for (vector<std::string>::const_iterator cit = noexpandmacros.begin();
1027 cit != end; ++cit)
1028 {
1029 ctx.get_hooks().add_noexpandmacro(*cit);
1030 }
1031 }
1032 #endif
1033
1034 // maximal include nesting depth
1035 if (vm.count("nesting")) {
1036 int max_depth = vm["nesting"].as<int>();
1037 if (max_depth < 1 || max_depth > 100000) {
1038 cerr << "wave: bogus maximal include nesting depth: "
1039 << max_depth << endl;
1040 return -1;
1041 }
1042 ctx.set_max_include_nesting_depth(max_depth);
1043 }
1044
1045 // open the output file
1046 if (vm.count("output")) {
1047 // try to open the file, where to put the preprocessed output
1048 fs::path out_file (boost::wave::util::create_path(
1049 vm["output"].as<std::string>()));
1050
1051 if (out_file == "-") {
1052 allow_output = false; // inhibit output initially
1053 default_outfile = "-";
1054 }
1055 else {
1056 out_file = boost::wave::util::complete_path(out_file);
1057 boost::wave::util::create_directories(
1058 boost::wave::util::branch_path(out_file));
1059 output.open(out_file.string().c_str());
1060 if (!output.is_open()) {
1061 cerr << "wave: could not open output file: "
1062 << out_file.string() << endl;
1063 return -1;
1064 }
1065 if (!license.empty())
1066 output << license;
1067 default_outfile = out_file.string();
1068 }
1069 }
1070 else if (!input_is_stdin && vm.count("autooutput")) {
1071 // generate output in the file <input_base_name>.i
1072 fs::path out_file (boost::wave::util::create_path(file_name));
1073 std::string basename (boost::wave::util::leaf(out_file));
1074 std::string::size_type pos = basename.find_last_of(".");
1075
1076 if (std::string::npos != pos)
1077 basename = basename.substr(0, pos);
1078 out_file = boost::wave::util::branch_path(out_file) / (basename + ".i");
1079
1080 boost::wave::util::create_directories(
1081 boost::wave::util::branch_path(out_file));
1082 output.open(out_file.string().c_str());
1083 if (!output.is_open()) {
1084 cerr << "wave: could not open output file: "
1085 << out_file.string() << endl;
1086 return -1;
1087 }
1088 if (!license.empty())
1089 output << license;
1090 default_outfile = out_file.string();
1091 }
1092
1093 // we assume the session to be interactive if input is stdin and output is
1094 // stdout and the output is not inhibited
1095 bool is_interactive = input_is_stdin && !output.is_open() && allow_output;
1096
1097 if (is_interactive) {
1098 // if interactive we don't warn for missing endif's etc.
1099 ctx.set_language(
1100 boost::wave::enable_single_line(ctx.get_language()), false);
1101 }
1102
1103 // analyze the input file
1104 context_type::iterator_type first = ctx.begin();
1105 context_type::iterator_type last = ctx.end();
1106
1107 // preprocess the required include files
1108 if (vm.count("forceinclude")) {
1109 // add the filenames to force as include files in _reverse_ order
1110 // the second parameter 'is_last' of the force_include function should
1111 // be set to true for the last (first given) file.
1112 std::vector<std::string> const &force =
1113 vm["forceinclude"].as<std::vector<std::string> >();
1114 std::vector<std::string>::const_reverse_iterator rend = force.rend();
1115 for (std::vector<std::string>::const_reverse_iterator cit = force.rbegin();
1116 cit != rend; /**/)
1117 {
1118 std::string filename(*cit);
1119 first.force_include(filename.c_str(), ++cit == rend);
1120 }
1121 }
1122
1123 elapsed_time.set_print_time(!input_is_stdin && vm.count("timer") > 0);
1124 if (is_interactive) {
1125 print_interactive_version(); // print welcome message
1126 load_state(vm, ctx); // load the internal tables from disc
1127 }
1128 else if (vm.count("state")) {
1129 // the option "state" is usable in interactive mode only
1130 cerr << "wave: ignoring the command line option 'state', "
1131 << "use it in interactive mode only." << endl;
1132 }
1133
1134 // >>>>>>>>>>>>> The actual preprocessing happens here. <<<<<<<<<<<<<<<<<<<
1135 // loop over the input lines if reading from stdin, otherwise this loop
1136 // will be executed once
1137 do {
1138 // loop over all generated tokens outputting the generated text
1139 bool finished = false;
1140
1141 if (input_is_stdin) {
1142 if (is_interactive)
1143 cout << ">>> "; // prompt if is interactive
1144
1145 // read next line and continue
1146 instring.clear();
1147 if (!read_a_line(instream, instring))
1148 break; // end of input reached
1149 first = ctx.begin(instring.begin(), instring.end());
1150 }
1151
1152 bool need_to_advanve = false;
1153
1154 do {
1155 try {
1156 if (need_to_advanve) {
1157 ++first;
1158 need_to_advanve = false;
1159 }
1160
1161 while (first != last) {
1162 // store the last known good token position
1163 current_position = (*first).get_position();
1164
1165 // print out the current token value
1166 if (allow_output) {
1167 if (!output.good()) {
1168 cerr << "wave: problem writing to the current "
1169 << "output file" << endl;
1170 cerr << report_iostate_error(output.rdstate());
1171 break;
1172 }
1173 if (output.is_open())
1174 output << (*first).get_value();
1175 else
1176 cout << (*first).get_value();
1177 }
1178
1179 // advance to the next token
1180 ++first;
1181 }
1182 finished = true;
1183 }
1184 catch (boost::wave::cpp_exception const &e) {
1185 // some preprocessing error
1186 if (is_interactive || boost::wave::is_recoverable(e)) {
1187 error_count += report_error_message(ctx, e,
1188 treat_warnings_as_error);
1189 need_to_advanve = true; // advance to the next token
1190 }
1191 else {
1192 throw; // re-throw for non-recoverable errors
1193 }
1194 }
1195 catch (boost::wave::cpplexer::lexing_exception const &e) {
1196 // some preprocessing error
1197 if (is_interactive ||
1198 boost::wave::cpplexer::is_recoverable(e))
1199 {
1200 error_count +=
1201 report_error_message(e, treat_warnings_as_error);
1202 need_to_advanve = true; // advance to the next token
1203 }
1204 else {
1205 throw; // re-throw for non-recoverable errors
1206 }
1207 }
1208 } while (!finished);
1209 } while (input_is_stdin);
1210
1211 if (is_interactive)
1212 save_state(vm, ctx); // write the internal tables to disc
1213
1214 // list all defined macros at the end of the preprocessing
1215 if (vm.count("macronames")) {
1216 if (!list_macro_names(ctx, vm["macronames"].as<std::string>()))
1217 return -1;
1218 }
1219 if (vm.count("macrocounts")) {
1220 if (!list_macro_counts(ctx, vm["macrocounts"].as<std::string>()))
1221 return -1;
1222 }
1223 }
1224 catch (boost::wave::cpp_exception const &e) {
1225 // some preprocessing error
1226 report_error_message(e, treat_warnings_as_error);
1227 return 1;
1228 }
1229 catch (boost::wave::cpplexer::lexing_exception const &e) {
1230 // some lexing error
1231 report_error_message(e, treat_warnings_as_error);
1232 return 2;
1233 }
1234 catch (std::exception const &e) {
1235 // use last recognized token to retrieve the error position
1236 cerr
1237 << current_position << ": "
1238 << "exception caught: " << e.what()
1239 << endl;
1240 return 3;
1241 }
1242 catch (...) {
1243 // use last recognized token to retrieve the error position
1244 cerr
1245 << current_position << ": "
1246 << "unexpected exception caught." << endl;
1247 return 4;
1248 }
1249 return -error_count; // returns the number of errors as a negative integer
1250 }
1251
1252 ///////////////////////////////////////////////////////////////////////////////
1253 // main entry point
1254 int
1255 main (int argc, char *argv[])
1256 {
1257 const std::string accepted_w_args[] = {"error"};
1258
1259 // test Wave compilation configuration
1260 if (!BOOST_WAVE_TEST_CONFIGURATION()) {
1261 cout << "wave: warning: the library this application was linked against was compiled "
1262 << endl
1263 << " using a different configuration (see wave_config.hpp)."
1264 << endl;
1265 }
1266
1267 // analyze the command line options and arguments
1268 try {
1269 // declare the options allowed on the command line only
1270 po::options_description desc_cmdline ("Options allowed on the command line only");
1271
1272 desc_cmdline.add_options()
1273 ("help,h", "print out program usage (this message)")
1274 ("version,v", "print the version number")
1275 ("copyright", "print out the copyright statement")
1276 ("config-file", po::value<vector<std::string> >()->composing(),
1277 "specify a config file (alternatively: @filepath)")
1278 ;
1279
1280 const std::string w_arg_desc = "Warning settings. Currently supported: -W" +
1281 boost::algorithm::join(accepted_w_args, ", -W");
1282
1283 // declare the options allowed on command line and in config files
1284 po::options_description desc_generic ("Options allowed additionally in a config file");
1285
1286 desc_generic.add_options()
1287 ("output,o", po::value<std::string>(),
1288 "specify a file [arg] to use for output instead of stdout or "
1289 "disable output [-]")
1290 ("autooutput,E",
1291 "output goes into a file named <input_basename>.i")
1292 ("license", po::value<std::string>(),
1293 "prepend the content of the specified file to each created file")
1294 ("include,I", po::value<cmd_line_utils::include_paths>()->composing(),
1295 "specify an additional include directory")
1296 ("sysinclude,S", po::value<vector<std::string> >()->composing(),
1297 "specify an additional system include directory")
1298 ("forceinclude,F", po::value<std::vector<std::string> >()->composing(),
1299 "force inclusion of the given file")
1300 ("define,D", po::value<std::vector<std::string> >()->composing(),
1301 "specify a macro to define (as macro[=[value]])")
1302 ("predefine,P", po::value<std::vector<std::string> >()->composing(),
1303 "specify a macro to predefine (as macro[=[value]])")
1304 ("undefine,U", po::value<std::vector<std::string> >()->composing(),
1305 "specify a macro to undefine")
1306 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
1307 ("noexpand,N", po::value<std::vector<std::string> >()->composing(),
1308 "specify a macro name, which should not be expanded")
1309 #endif
1310 ("nesting,n", po::value<int>(),
1311 "specify a new maximal include nesting depth")
1312 ("warning,W", po::value<std::vector<std::string> >()->composing(),
1313 w_arg_desc.c_str())
1314 ;
1315
1316 po::options_description desc_ext ("Extended options (allowed everywhere)");
1317
1318 desc_ext.add_options()
1319 ("traceto,t", po::value<std::string>(),
1320 "output macro expansion tracing information to a file [arg] "
1321 "or to stderr [-]")
1322 ("timer", "output overall elapsed computing time to stderr")
1323 ("long_long", "enable long long support in C++ mode")
1324 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
1325 ("variadics", "enable certain C99 extensions in C++ mode")
1326 ("c99", "enable C99 mode (implies --variadics)")
1327 #endif
1328 #if BOOST_WAVE_SUPPORT_CPP0X != 0
1329 ("c++11", "enable C++11 mode (implies --variadics and --long_long)")
1330 #endif
1331 ("listincludes,l", po::value<std::string>(),
1332 "list names of included files to a file [arg] or to stdout [-]")
1333 ("macronames,m", po::value<std::string>(),
1334 "list all defined macros to a file [arg] or to stdout [-]")
1335 ("macrocounts,c", po::value<std::string>(),
1336 "list macro invocation counts to a file [arg] or to stdout [-]")
1337 ("preserve,p", po::value<int>()->default_value(0),
1338 "preserve whitespace\n"
1339 "0: no whitespace is preserved (default),\n"
1340 "1: begin of line whitespace is preserved,\n"
1341 "2: comments and begin of line whitespace is preserved,\n"
1342 "3: all whitespace is preserved")
1343 ("line,L", po::value<int>()->default_value(1),
1344 "control the generation of #line directives\n"
1345 "0: no #line directives are generated,\n"
1346 "1: #line directives will be emitted (default),\n"
1347 "2: #line directives will be emitted using relative\n"
1348 " filenames")
1349 ("disambiguate", po::value<int>()->default_value(1),
1350 "control whitespace insertion to disambiguate\n"
1351 "consecutive tokens\n"
1352 "0: no additional whitespace is generated,\n"
1353 "1: whitespace is used to disambiguate output (default)")
1354 ("extended,x", "enable the #pragma wave system() directive")
1355 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
1356 ("noguard,G", "disable include guard detection")
1357 ("listguards,g", po::value<std::string>(),
1358 "list names of files flagged as 'include once' to a file [arg] "
1359 "or to stdout [-]")
1360 #endif
1361 #if BOOST_WAVE_SERIALIZATION != 0
1362 ("state,s", po::value<std::string>(),
1363 "load and save state information from/to the given file [arg] "
1364 "or 'wave.state' [-] (interactive mode only)")
1365 #endif
1366 ;
1367
1368 // combine the options for the different usage schemes
1369 po::options_description desc_overall_cmdline;
1370 po::options_description desc_overall_cfgfile;
1371
1372 desc_overall_cmdline.add(desc_cmdline).add(desc_generic).add(desc_ext);
1373 desc_overall_cfgfile.add(desc_generic).add(desc_ext);
1374
1375 // parse command line and store results
1376 using namespace boost::program_options::command_line_style;
1377
1378 po::parsed_options opts(po::parse_command_line(argc, argv,
1379 desc_overall_cmdline, unix_style, cmd_line_utils::at_option_parser));
1380 po::variables_map vm;
1381
1382 po::store(opts, vm);
1383 po::notify(vm);
1384
1385 // // Try to find a wave.cfg in the same directory as the executable was
1386 // // started from. If this exists, treat it as a wave config file
1387 // fs::path filename(argv[0]);
1388 //
1389 // filename = filename.branch_path() / "wave.cfg";
1390 // cmd_line_utils::read_config_file_options(filename.string(),
1391 // desc_overall_cfgfile, vm, true);
1392
1393 // extract the arguments from the parsed command line
1394 vector<po::option> arguments;
1395
1396 std::remove_copy_if(opts.options.begin(), opts.options.end(),
1397 back_inserter(arguments), cmd_line_utils::is_argument());
1398
1399 // try to find a config file somewhere up the filesystem hierarchy
1400 // starting with the input file path. This allows to use a general wave.cfg
1401 // file for all files in a certain project.
1402 if (arguments.size() > 0 && arguments[0].value[0] != "-") {
1403 // construct full path of input file
1404 fs::path input_dir (boost::wave::util::complete_path(
1405 boost::wave::util::create_path(arguments[0].value[0])));
1406
1407 // chop of file name
1408 input_dir = boost::wave::util::branch_path(
1409 boost::wave::util::normalize(input_dir));
1410
1411 // walk up the hierarchy, trying to find a file wave.cfg
1412 while (!input_dir.empty()) {
1413 fs::path filename = input_dir / "wave.cfg";
1414 if (cmd_line_utils::read_config_file_options(filename.string(),
1415 desc_overall_cfgfile, vm, true))
1416 {
1417 break; // break on the first cfg file found
1418 }
1419 input_dir = boost::wave::util::branch_path(input_dir);
1420 }
1421 }
1422
1423 // if there is specified at least one config file, parse it and add the
1424 // options to the main variables_map
1425 if (vm.count("config-file")) {
1426 vector<std::string> const &cfg_files =
1427 vm["config-file"].as<vector<std::string> >();
1428 vector<std::string>::const_iterator end = cfg_files.end();
1429 for (vector<std::string>::const_iterator cit = cfg_files.begin();
1430 cit != end; ++cit)
1431 {
1432 // parse a single config file and store the results
1433 cmd_line_utils::read_config_file_options(*cit,
1434 desc_overall_cfgfile, vm);
1435 }
1436 }
1437
1438 // validate warning settings
1439 if (vm.count("warning"))
1440 {
1441 BOOST_FOREACH(const std::string& arg,
1442 vm["warning"].as<std::vector<std::string> >())
1443 {
1444 if (boost::range::find(accepted_w_args, arg) ==
1445 boost::end(accepted_w_args))
1446 {
1447 cerr << "wave: Invalid warning setting: " << arg << endl;
1448 return -1;
1449 }
1450 }
1451 }
1452
1453 // ... act as required
1454 if (vm.count("help")) {
1455 po::options_description desc_help (
1456 "Usage: wave [options] [@config-file(s)] [file]");
1457
1458 desc_help.add(desc_cmdline).add(desc_generic).add(desc_ext);
1459 cout << desc_help << endl;
1460 return 1;
1461 }
1462
1463 if (vm.count("version")) {
1464 cout << get_version() << endl;
1465 return 0;
1466 }
1467
1468 if (vm.count("copyright")) {
1469 return print_copyright();
1470 }
1471
1472 // if there is no input file given, then take input from stdin
1473 if (0 == arguments.size() || 0 == arguments[0].value.size() ||
1474 arguments[0].value[0] == "-")
1475 {
1476 // preprocess the given input from stdin
1477 return do_actual_work("<stdin>", std::cin, vm, true);
1478 }
1479 else {
1480 if (arguments.size() > 1) {
1481 // this driver understands to parse one input file only
1482 cerr << "wave: more than one input file specified, "
1483 << "ignoring all but the first!" << endl;
1484 }
1485
1486 std::string file_name(arguments[0].value[0]);
1487 std::ifstream instream(file_name.c_str());
1488
1489 // preprocess the given input file
1490 if (!instream.is_open()) {
1491 cerr << "wave: could not open input file: " << file_name << endl;
1492 return -1;
1493 }
1494 return do_actual_work(file_name, instream, vm, false);
1495 }
1496 }
1497 catch (std::exception const &e) {
1498 cout << "wave: exception caught: " << e.what() << endl;
1499 return 6;
1500 }
1501 catch (...) {
1502 cerr << "wave: unexpected exception caught." << endl;
1503 return 7;
1504 }
1505 }
1506