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