]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/wave/test/testwave/testwave_app.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / wave / test / testwave / testwave_app.cpp
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3 http://www.boost.org/
4
5 Copyright (c) 2001-2013 Hartmut Kaiser. Distributed under the Boost
6 Software License, Version 1.0. (See accompanying file
7 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9
10 // disable stupid compiler warnings
11 #include <boost/config/warning_disable.hpp>
12
13 // system headers
14 #include <string>
15 #include <iostream>
16 #include <vector>
17 #include <ctime>
18
19 // include boost
20 #include <boost/config.hpp>
21 #include <boost/assert.hpp>
22 #include <boost/throw_exception.hpp>
23 #include <boost/filesystem/path.hpp>
24 #include <boost/filesystem/operations.hpp>
25 #include <boost/detail/workaround.hpp>
26
27 // include Wave
28
29 // always use new hooks
30 #define BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS 0
31
32 #include <boost/wave.hpp>
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 lexer specifics, import lexer names
40 #if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0
41 #include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp>
42 #endif
43
44 ///////////////////////////////////////////////////////////////////////////////
45 // Include the grammar definitions, if these shouldn't be compiled separately
46 // (ATTENTION: _very_ large compilation times!)
47 #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0
48 #include <boost/wave/grammars/cpp_intlit_grammar.hpp>
49 #include <boost/wave/grammars/cpp_chlit_grammar.hpp>
50 #include <boost/wave/grammars/cpp_grammar.hpp>
51 #include <boost/wave/grammars/cpp_expression_grammar.hpp>
52 #include <boost/wave/grammars/cpp_predef_macros_grammar.hpp>
53 #include <boost/wave/grammars/cpp_defined_grammar.hpp>
54 #endif
55
56 // test application related headers
57 #include "cmd_line_utils.hpp"
58 #include "testwave_app.hpp"
59 #include "collect_hooks_information.hpp"
60
61 # ifdef BOOST_NO_STDC_NAMESPACE
62 namespace std
63 {
64 using ::asctime; using ::gmtime; using ::localtime;
65 using ::difftime; using ::time; using ::tm; using ::mktime; using ::system;
66 }
67 # endif
68
69 namespace po = boost::program_options;
70 namespace fs = boost::filesystem;
71
72 ///////////////////////////////////////////////////////////////////////////////
73 // testwave version definitions
74 #define TESTWAVE_VERSION_MAJOR 0
75 #define TESTWAVE_VERSION_MINOR 6
76 #define TESTWAVE_VERSION_SUBMINOR 0
77
78 namespace {
79
80 ///////////////////////////////////////////////////////////////////////////
81 template <typename Iterator>
82 inline bool
83 handle_next_token(Iterator &it, Iterator const& end,
84 std::string &result)
85 {
86 typedef typename Iterator::value_type token_type;
87
88 token_type tok = *it++;
89 result = result + tok.get_value().c_str();
90 return (it == end) ? false : true;
91 }
92
93 ///////////////////////////////////////////////////////////////////////////
94 template <typename String>
95 String const& handle_quoted_filepath(String &name)
96 {
97 using boost::wave::util::impl::unescape_lit;
98
99 String unesc_name = unescape_lit(name.substr(1, name.size()-2));
100 fs::path p (boost::wave::util::create_path(unesc_name.c_str()));
101
102 name = String("\"") + boost::wave::util::leaf(p).c_str() + String("\"");
103 return name;
104 }
105
106 ///////////////////////////////////////////////////////////////////////////
107 template <typename Iterator>
108 bool handle_line_directive(Iterator &it, Iterator const& end,
109 std::string &result)
110 {
111 typedef typename Iterator::value_type token_type;
112 typedef typename token_type::string_type string_type;
113
114 if (!handle_next_token(it, end, result) || // #line
115 !handle_next_token(it, end, result) || // whitespace
116 !handle_next_token(it, end, result) || // number
117 !handle_next_token(it, end, result)) // whitespace
118 {
119 return false;
120 }
121
122 using boost::wave::util::impl::unescape_lit;
123
124 token_type filename = *it;
125 string_type name = filename.get_value();
126
127 handle_quoted_filepath(name);
128 result = result + name.c_str();
129 return true;
130 }
131
132 template <typename T>
133 inline T const&
134 variables_map_as(po::variable_value const& v, T*)
135 {
136 #if (__GNUC__ == 3 && (__GNUC_MINOR__ == 2 || __GNUC_MINOR__ == 3)) || \
137 BOOST_WORKAROUND(__MWERKS__, < 0x3200)
138 // gcc 3.2.x and 3.3.x choke on vm[...].as<...>()
139 // CW 8.3 has problems with the v.as<T>() below
140 T const* r = boost::any_cast<T>(&v.value());
141 if (!r)
142 boost::throw_exception(boost::bad_any_cast());
143 return *r;
144 #else
145 return v.as<T>();
146 #endif
147 }
148
149 }
150
151 ///////////////////////////////////////////////////////////////////////////
152 //
153 // This function compares the real result and the expected one but first
154 // replaces all occurrences in the expected result of
155 // $E: to the result of preprocessing the given expression
156 // $F: to the passed full filepath
157 // $P: to the full path
158 // $B: to the full path (same as $P, but using forward slash '/' on Windows)
159 // $V: to the current Boost version number
160 //
161 ///////////////////////////////////////////////////////////////////////////
162 bool
163 testwave_app::got_expected_result(std::string const& filename,
164 std::string const& result, std::string& expected)
165 {
166 using boost::wave::util::impl::escape_lit;
167
168 std::string full_result;
169 std::string::size_type pos = 0;
170 std::string::size_type pos1 = expected.find_first_of("$");
171
172 if (pos1 != std::string::npos) {
173 do {
174 switch(expected[pos1+1]) {
175 case 'E': // preprocess the given token sequence
176 {
177 if ('(' == expected[pos1+2]) {
178 std::size_t p = expected.find_first_of(")", pos1+1);
179 if (std::string::npos == p) {
180 std::cerr
181 << "testwave: unmatched parenthesis in $E"
182 " directive" << std::endl;
183 return false;
184 }
185 std::string source = expected.substr(pos1+3, p-pos1-3);
186 std::string result, error, hooks;
187 bool pp_result = preprocess_file(filename, source,
188 result, error, hooks, "", true);
189 if (!pp_result) {
190 std::cerr
191 << "testwave: preprocessing error in $E directive: "
192 << error << std::endl;
193 return false;
194 }
195 full_result = full_result +
196 expected.substr(pos, pos1-pos) + result;
197 pos1 = expected.find_first_of ("$",
198 pos = pos1 + 4 + source.size());
199 }
200 }
201 break;
202
203 case 'F': // insert base file name
204 full_result = full_result +
205 expected.substr(pos, pos1-pos) + escape_lit(filename);
206 pos1 = expected.find_first_of ("$", pos = pos1 + 2);
207 break;
208
209 case 'P': // insert full path
210 case 'B': // same as 'P', but forward slashes on Windows
211 {
212 fs::path fullpath (
213 boost::wave::util::complete_path(
214 boost::wave::util::create_path(filename),
215 boost::wave::util::current_path())
216 );
217
218 if ('(' == expected[pos1+2]) {
219 // the $P(basename) syntax is used
220 std::size_t p = expected.find_first_of(")", pos1+1);
221 if (std::string::npos == p) {
222 std::cerr
223 << "testwave: unmatched parenthesis in $P"
224 " directive" << std::endl;
225 return false;
226 }
227 std::string base = expected.substr(pos1+3, p-pos1-3);
228 fullpath = boost::wave::util::branch_path(fullpath) /
229 boost::wave::util::create_path(base);
230 full_result += expected.substr(pos, pos1-pos);
231 if ('P' == expected[pos1+1]) {
232 #if defined(BOOST_WINDOWS)
233 std::string p = replace_slashes(
234 boost::wave::util::native_file_string(
235 boost::wave::util::normalize(fullpath)),
236 "/", '\\');
237 #else
238 std::string p (
239 boost::wave::util::native_file_string(
240 boost::wave::util::normalize(fullpath)));
241 #endif
242 full_result += escape_lit(p);
243 }
244 else {
245 #if defined(BOOST_WINDOWS)
246 std::string p = replace_slashes(
247 boost::wave::util::normalize(fullpath).string());
248 #else
249 std::string p (
250 boost::wave::util::normalize(fullpath).string());
251 #endif
252 full_result += escape_lit(p);
253 }
254 pos1 = expected.find_first_of ("$",
255 pos = pos1 + 4 + base.size());
256 }
257 else {
258 // the $P is used on its own
259 full_result += expected.substr(pos, pos1-pos);
260 if ('P' == expected[pos1+1]) {
261 full_result += escape_lit(
262 boost::wave::util::native_file_string(fullpath));
263 }
264 else {
265 #if defined(BOOST_WINDOWS)
266 std::string p = replace_slashes(fullpath.string());
267 #else
268 std::string p (fullpath.string());
269 #endif
270 full_result += escape_lit(fullpath.string());
271 }
272 pos1 = expected.find_first_of ("$", pos = pos1 + 2);
273 }
274 }
275 break;
276
277 case 'R': // insert relative file name
278 case 'S': // same as 'R', but forward slashes on Windows
279 {
280 fs::path relpath;
281 boost::wave::util::as_relative_to(
282 boost::wave::util::create_path(filename),
283 boost::wave::util::current_path(),
284 relpath);
285
286 if ('(' == expected[pos1+2]) {
287 // the $R(basename) syntax is used
288 std::size_t p = expected.find_first_of(")", pos1+1);
289 if (std::string::npos == p) {
290 std::cerr
291 << "testwave: unmatched parenthesis in $R"
292 " directive" << std::endl;
293 return false;
294 }
295 std::string base = expected.substr(pos1+3, p-pos1-3);
296 relpath = boost::wave::util::branch_path(relpath) /
297 boost::wave::util::create_path(base);
298 full_result += expected.substr(pos, pos1-pos);
299 if ('R' == expected[pos1+1]) {
300 full_result += escape_lit(
301 boost::wave::util::native_file_string(
302 boost::wave::util::normalize(relpath)));
303 }
304 else {
305 #if defined(BOOST_WINDOWS)
306 std::string p = replace_slashes(
307 boost::wave::util::normalize(relpath).string());
308 #else
309 std::string p (
310 boost::wave::util::normalize(relpath).string());
311 #endif
312 full_result += escape_lit(p);
313 }
314 pos1 = expected.find_first_of ("$",
315 pos = pos1 + 4 + base.size());
316 }
317 else {
318 // the $R is used on its own
319 full_result += expected.substr(pos, pos1-pos);
320 if ('R' == expected[pos1+1]) {
321 full_result += escape_lit(
322 boost::wave::util::native_file_string(relpath));
323 }
324 else {
325 #if defined(BOOST_WINDOWS)
326 std::string p = replace_slashes(relpath.string());
327 #else
328 std::string p (relpath.string());
329 #endif
330 full_result += escape_lit(p);
331 }
332 pos1 = expected.find_first_of ("$", pos = pos1 + 2);
333 }
334 }
335 break;
336
337 case 'V': // insert Boost version
338 full_result = full_result +
339 expected.substr(pos, pos1-pos) + BOOST_LIB_VERSION;
340 pos1 = expected.find_first_of ("$", pos = pos1 + 2);
341 break;
342
343 default:
344 full_result = full_result +
345 expected.substr(pos, pos1-pos);
346 pos1 = expected.find_first_of ("$", (pos = pos1) + 1);
347 break;
348 }
349
350 } while(pos1 != std::string::npos);
351 full_result += expected.substr(pos);
352 }
353 else {
354 full_result = expected;
355 }
356
357 expected = full_result;
358 return full_result == result;
359 }
360
361 ///////////////////////////////////////////////////////////////////////////////
362 testwave_app::testwave_app(po::variables_map const& vm)
363 : debuglevel(1), desc_options("Preprocessor configuration options"),
364 global_vm(vm)
365 {
366 desc_options.add_options()
367 ("include,I", po::value<cmd_line_utils::include_paths>()->composing(),
368 "specify an additional include directory")
369 ("sysinclude,S", po::value<std::vector<std::string> >()->composing(),
370 "specify an additional system include directory")
371 ("forceinclude,F", po::value<std::vector<std::string> >()->composing(),
372 "force inclusion of the given file")
373 ("define,D", po::value<std::vector<std::string> >()->composing(),
374 "specify a macro to define (as macro[=[value]])")
375 ("predefine,P", po::value<std::vector<std::string> >()->composing(),
376 "specify a macro to predefine (as macro[=[value]])")
377 ("undefine,U", po::value<std::vector<std::string> >()->composing(),
378 "specify a macro to undefine")
379 ("nesting,n", po::value<int>(),
380 "specify a new maximal include nesting depth")
381 ("long_long", "enable long long support in C++ mode")
382 ("preserve", "preserve comments")
383 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
384 ("variadics", "enable certain C99 extensions in C++ mode")
385 ("c99", "enable C99 mode (implies --variadics)")
386 #endif
387 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
388 ("noguard,G", "disable include guard detection")
389 #endif
390 ("skipped_token_hooks", "record skipped_token hook calls")
391 #if BOOST_WAVE_SUPPORT_CPP0X != 0
392 ("c++11", "enable C++11 mode (implies --variadics and --long_long)")
393 #endif
394 ("warning,W", po::value<std::vector<std::string> >()->composing(),
395 "Warning settings.")
396 ;
397 }
398
399 ///////////////////////////////////////////////////////////////////////////////
400 //
401 // Test the given file (i.e. preprocess the file and compare the result
402 // against the embedded 'R' comments, if an error occurs compare the error
403 // message against the given 'E' comments, if no error occurred, compare the
404 // generated hooks result against the given 'H' comments).
405 //
406 ///////////////////////////////////////////////////////////////////////////////
407 bool
408 testwave_app::test_a_file(std::string filename)
409 {
410 // read the input file into a string
411 std::string instr;
412 if (!read_file(filename, instr))
413 return false; // error was reported already
414
415 bool test_hooks = true;
416 if (global_vm.count("hooks"))
417 test_hooks = variables_map_as(global_vm["hooks"], (bool *)NULL);
418
419 std::string expected_cfg_macro;
420 extract_special_information(filename, instr, 'D', expected_cfg_macro);
421
422 // extract expected output, preprocess the data and compare results
423 std::string expected, expected_hooks;
424 if (extract_expected_output(filename, instr, expected, expected_hooks)) {
425 bool retval = true; // assume success
426 bool printed_result = false;
427 std::string result, error, hooks;
428 bool pp_result = preprocess_file(filename, instr, result, error, hooks,
429 expected_cfg_macro);
430 if (pp_result || !result.empty()) {
431 // did we expect an error?
432 std::string expected_error;
433 if (!extract_special_information(filename, instr, 'E', expected_error))
434 return false;
435
436 if (!expected_error.empty() &&
437 !got_expected_result(filename, error, expected_error))
438 {
439 // we expected an error but got none (or a different one)
440 if (debuglevel > 2) {
441 std::cerr
442 << filename << ": failed" << std::endl
443 << "result: " << std::endl << result << std::endl;
444
445 if (!error.empty()) {
446 std::cerr << "expected result: " << std::endl
447 << expected << std::endl;
448 }
449 if (!expected_error.empty()) {
450 std::cerr << "expected error: " << std::endl
451 << expected_error << std::endl;
452 }
453 }
454 else if (debuglevel > 1) {
455 std::cerr << filename << ": failed" << std::endl;
456 }
457 retval = false;
458 }
459 else if (!got_expected_result(filename, result, expected)) {
460 // no preprocessing error encountered
461 if (debuglevel > 2) {
462 std::cerr
463 << filename << ": failed" << std::endl
464 << "result: " << std::endl << result << std::endl
465 << "expected: " << std::endl << expected << std::endl;
466 }
467 else if (debuglevel > 1) {
468 std::cerr << filename << ": failed" << std::endl;
469 }
470 retval = false;
471 }
472 else {
473 // preprocessing succeeded, check hook information, if appropriate
474 if (test_hooks && !expected_hooks.empty() &&
475 !got_expected_result(filename, hooks, expected_hooks))
476 {
477 if (debuglevel > 2) {
478 std::cerr << filename << ": failed" << std::endl
479 << "hooks result: " << std::endl << hooks
480 << std::endl;
481 std::cerr << "expected hooks result: " << std::endl
482 << expected_hooks << std::endl;
483 }
484 else if (debuglevel > 1) {
485 std::cerr << filename << ": failed" << std::endl;
486 }
487 retval = false;
488 }
489 }
490
491 // print success message, if appropriate
492 if (retval) {
493 if (debuglevel > 5) {
494 std::cerr
495 << filename << ": succeeded" << std::endl
496 << "result: " << std::endl << result << std::endl
497 << "hooks result: " << std::endl << hooks << std::endl;
498 }
499 else if (debuglevel > 4) {
500 std::cerr
501 << filename << ": succeeded" << std::endl
502 << "result: " << std::endl << result << std::endl;
503 }
504 else if (debuglevel > 3) {
505 std::cerr << filename << ": succeeded" << std::endl;
506 }
507 printed_result = true;
508 }
509 }
510
511 if (!pp_result) {
512 // there was a preprocessing error, was it expected?
513 std::string expected_error;
514 if (!extract_special_information(filename, instr, 'E', expected_error))
515 return false;
516
517 if (!got_expected_result(filename, error, expected_error)) {
518 // the error was unexpected
519 if (debuglevel > 2) {
520 std::cerr
521 << filename << ": failed" << std::endl;
522
523 if (!expected_error.empty()) {
524 std::cerr
525 << "error result: " << std::endl << error << std::endl
526 << "expected error: " << std::endl
527 << expected_error << std::endl;
528 }
529 else {
530 std::cerr << "unexpected error: " << error << std::endl;
531 }
532 }
533 else if (debuglevel > 1) {
534 std::cerr << filename << ": failed" << std::endl;
535 }
536 retval = false;
537 }
538
539 if (retval) {
540 if (debuglevel > 5) {
541 std::cerr
542 << filename << ": succeeded (caught expected error)"
543 << std::endl << "error result: " << std::endl << error
544 << std::endl;
545
546 if (!printed_result) {
547 std::cerr
548 << "hooks result: " << std::endl << hooks
549 << std::endl;
550 }
551 }
552 else if (debuglevel > 4) {
553 std::cerr
554 << filename << ": succeeded (caught expected error)"
555 << std::endl << "error result: " << std::endl << error
556 << std::endl;
557 }
558 else if (debuglevel > 3) {
559 // caught the expected error message
560 std::cerr << filename << ": succeeded" << std::endl;
561 }
562 }
563 }
564 return retval;
565 }
566 else {
567 std::cerr
568 << filename << ": no information about expected results found"
569 << std::endl;
570 }
571 return false;
572 }
573
574 ///////////////////////////////////////////////////////////////////////////////
575 //
576 // print the current version of this program
577 //
578 ///////////////////////////////////////////////////////////////////////////////
579 int
580 testwave_app::print_version()
581 {
582 // get time of last compilation of this file
583 boost::wave::util::time_conversion_helper compilation_time(__DATE__ " " __TIME__);
584
585 // calculate the number of days since Feb 12 2005
586 // (the day the testwave project was started)
587 std::tm first_day;
588
589 using namespace std; // some platforms have memset in namespace std
590 memset (&first_day, 0, sizeof(std::tm));
591 first_day.tm_mon = 1; // Feb
592 first_day.tm_mday = 12; // 12
593 first_day.tm_year = 105; // 2005
594
595 long seconds = long(std::difftime(compilation_time.get_time(),
596 std::mktime(&first_day)));
597
598 std::cout
599 << TESTWAVE_VERSION_MAJOR << '.'
600 << TESTWAVE_VERSION_MINOR << '.'
601 << TESTWAVE_VERSION_SUBMINOR << '.'
602 << seconds/(3600*24) // get number of days from seconds
603 << std::endl;
604 return 0; // exit app
605 }
606
607 ///////////////////////////////////////////////////////////////////////////////
608 //
609 // print the copyright statement
610 //
611 ///////////////////////////////////////////////////////////////////////////////
612 int
613 testwave_app::print_copyright()
614 {
615 char const *copyright[] = {
616 "",
617 "Testwave: A test driver for the Boost.Wave C++ preprocessor library",
618 "http://www.boost.org/",
619 "",
620 "Copyright (c) 2001-2012 Hartmut Kaiser, Distributed under the Boost",
621 "Software License, Version 1.0. (See accompanying file",
622 "LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)",
623 0
624 };
625
626 for (int i = 0; 0 != copyright[i]; ++i)
627 std::cout << copyright[i] << std::endl;
628
629 return 0; // exit app
630 }
631
632 ///////////////////////////////////////////////////////////////////////////////
633 //
634 // Read the given file into a string
635 //
636 ///////////////////////////////////////////////////////////////////////////////
637 bool
638 testwave_app::read_file(std::string const& filename, std::string& instr)
639 {
640 // open the given file and report error, if appropriate
641 std::ifstream instream(filename.c_str());
642 if (!instream.is_open()) {
643 std::cerr << "testwave: could not open input file: "
644 << filename << std::endl;
645 return false;
646 }
647 else if (9 == debuglevel) {
648 std::cerr << "read_file: succeeded to open input file: "
649 << filename << std::endl;
650 }
651 instream.unsetf(std::ios::skipws);
652
653 // read the input file into a string
654
655 #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
656 // this is known to be very slow for large files on some systems
657 std::copy (std::istream_iterator<char>(instream),
658 std::istream_iterator<char>(),
659 std::inserter(instr, instr.end()));
660 #else
661 instr = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
662 std::istreambuf_iterator<char>());
663 #endif
664
665 if (9 == debuglevel) {
666 std::cerr << "read_file: succeeded to read input file: "
667 << filename << std::endl;
668 }
669 return true;
670 }
671
672 ///////////////////////////////////////////////////////////////////////////////
673 namespace {
674
675 std::string const& trim_whitespace(std::string& value)
676 {
677 std::string::size_type first = value.find_first_not_of(" \t");
678 if (std::string::npos == first)
679 value.clear();
680 else {
681 std::string::size_type last = value.find_last_not_of(" \t");
682 BOOST_ASSERT(std::string::npos != last);
683 value = value.substr(first, last-first+1);
684 }
685 return value;
686 }
687 }
688
689 ///////////////////////////////////////////////////////////////////////////////
690 //
691 // Extract special information from comments marked with the given letter
692 //
693 ///////////////////////////////////////////////////////////////////////////////
694 bool
695 testwave_app::extract_special_information(std::string const& filename,
696 std::string const& instr, char flag, std::string& content)
697 {
698 if (9 == debuglevel) {
699 std::cerr << "extract_special_information: extracting special information ('"
700 << flag << "') from input file: " << filename << std::endl;
701 }
702
703 // tokenize the input data into C++ tokens using the C++ lexer
704 typedef boost::wave::cpplexer::lex_token<> token_type;
705 typedef boost::wave::cpplexer::lex_iterator<token_type> lexer_type;
706 typedef token_type::position_type position_type;
707
708 boost::wave::language_support const lang_opts =
709 (boost::wave::language_support)(
710 boost::wave::support_option_variadics |
711 boost::wave::support_option_long_long |
712 boost::wave::support_option_no_character_validation |
713 boost::wave::support_option_convert_trigraphs |
714 boost::wave::support_option_insert_whitespace);
715
716 position_type pos(filename.c_str());
717 lexer_type it = lexer_type(instr.begin(), instr.end(), pos, lang_opts);
718 lexer_type end = lexer_type();
719
720 try {
721 // look for C or C++ comments starting with the special character
722 for (/**/; it != end; ++it) {
723 using namespace boost::wave;
724 token_id id = token_id(*it);
725 if (T_CCOMMENT == id) {
726 std::string value = (*it).get_value().c_str();
727 if (flag == value[2]) {
728 if (value.size() > 3 && '(' == value[3]) {
729 std::size_t p = value.find_first_of(")");
730 if (std::string::npos == p) {
731 std::cerr
732 << "testwave: missing closing parenthesis in '"
733 << flag << "()' directive" << std::endl;
734 return false;
735 }
736 std::string source = value.substr(4, p-4);
737 std::string result, error, hooks;
738 bool pp_result = preprocess_file(filename, source,
739 result, error, hooks, "", true);
740 if (!pp_result) {
741 std::cerr
742 << "testwave: preprocessing error in '" << flag
743 << "()' directive: " << error << std::endl;
744 return false;
745 }
746
747 // include this text into the extracted information
748 // only if the result is not zero
749 using namespace std; // some system have atoi in namespace std
750 if (0 != atoi(result.c_str())) {
751 std::string thiscontent(value.substr(p+1));
752 if (9 == debuglevel) {
753 std::cerr << "extract_special_information: extracted: "
754 << thiscontent << std::endl;
755 }
756 trim_whitespace(thiscontent);
757 content += thiscontent;
758 }
759 }
760 else {
761 std::string thiscontent(value.substr(3, value.size()-5));
762 if (9 == debuglevel) {
763 std::cerr << "extract_special_information: extracted: "
764 << thiscontent << std::endl;
765 }
766 trim_whitespace(thiscontent);
767 content += thiscontent;
768 }
769 }
770 }
771 else if (T_CPPCOMMENT == id) {
772 std::string value = (*it).get_value().c_str();
773 if (flag == value[2]) {
774 if (value.size() > 3 && '(' == value[3]) {
775 std::size_t p = value.find_first_of(")");
776 if (std::string::npos == p) {
777 std::cerr
778 << "testwave: missing closing parenthesis in '"
779 << flag << "()' directive" << std::endl;
780 return false;
781 }
782 std::string source = value.substr(4, p-4);
783 std::string result, error, hooks;
784 bool pp_result = preprocess_file(filename, source,
785 result, error, hooks, "", true);
786 if (!pp_result) {
787 std::cerr
788 << "testwave: preprocessing error in '" << flag
789 << "()' directive: " << error << std::endl;
790 return false;
791 }
792
793 // include this text into the extracted information
794 // only if the result is not zero
795 using namespace std; // some system have atoi in namespace std
796 if (0 != atoi(result.c_str())) {
797 std::string thiscontent(value.substr((' ' == value[p+1]) ? p+2 : p+1));
798 if (9 == debuglevel) {
799 std::cerr << "extract_special_information: extracted: "
800 << thiscontent << std::endl;
801 }
802 trim_whitespace(thiscontent);
803 content += thiscontent;
804 }
805 }
806 else {
807 std::string thiscontent(value.substr((' ' == value[3]) ? 4 : 3));
808 if (9 == debuglevel) {
809 std::cerr << "extract_special_information: extracted: "
810 << thiscontent;
811 }
812 trim_whitespace(content);
813 content += thiscontent;
814 }
815 }
816 }
817 }
818 }
819 catch (boost::wave::cpplexer::lexing_exception const &e) {
820 // some lexing error
821 std::cerr
822 << e.file_name() << "(" << e.line_no() << "): "
823 << e.description() << std::endl;
824 return false;
825 }
826
827 if (9 == debuglevel) {
828 std::cerr << "extract_special_information: succeeded extracting special information ('"
829 << flag << "')" << std::endl;
830 }
831 return true;
832 }
833
834 ///////////////////////////////////////////////////////////////////////////////
835 //
836 // Extract the expected output from the given input data
837 //
838 // The expected output has to be provided inside of special comments which
839 // start with a capital 'R'. All such comments are concatenated and returned
840 // through the parameter 'expected'.
841 //
842 ///////////////////////////////////////////////////////////////////////////////
843 inline bool
844 testwave_app::extract_expected_output(std::string const& filename,
845 std::string const& instr, std::string& expected, std::string& expectedhooks)
846 {
847 return extract_special_information(filename, instr, 'R', expected) &&
848 extract_special_information(filename, instr, 'H', expectedhooks);
849 }
850
851 ///////////////////////////////////////////////////////////////////////////////
852 //
853 // Extracts the required preprocessing options from the given input data and
854 // initialises the given Wave context object accordingly.
855 // We allow the same (applicable) options to be used as are valid for the wave
856 // driver executable.
857 //
858 ///////////////////////////////////////////////////////////////////////////////
859 template <typename Context>
860 bool
861 testwave_app::extract_options(std::string const& filename,
862 std::string const& instr, Context& ctx, bool single_line,
863 po::variables_map& vm)
864 {
865 if (9 == debuglevel) {
866 std::cerr << "extract_options: extracting options" << std::endl;
867 }
868
869 // extract the required information from the comments flagged by a
870 // capital 'O'
871 std::string options;
872 if (!extract_special_information(filename, instr, 'O', options))
873 return false;
874
875 try {
876 // parse the configuration information into a program_options_description
877 // object
878 cmd_line_utils::read_config_options(debuglevel, options, desc_options, vm);
879 initialise_options(ctx, vm, single_line);
880 }
881 catch (std::exception const &e) {
882 std::cerr << filename << ": exception caught: " << e.what()
883 << std::endl;
884 return false;
885 }
886
887 if (9 == debuglevel) {
888 std::cerr << "extract_options: succeeded extracting options"
889 << std::endl;
890 }
891
892 return true;
893 }
894
895 template <typename Context>
896 bool
897 testwave_app::initialise_options(Context& ctx, po::variables_map const& vm,
898 bool single_line)
899 {
900 if (9 == debuglevel) {
901 std::cerr << "initialise_options: initializing options" << std::endl;
902 }
903
904 if (vm.count("skipped_token_hooks")) {
905 if (9 == debuglevel) {
906 std::cerr << "initialise_options: option: skipped_token_hooks" << std::endl;
907 }
908 ctx.get_hooks().set_skipped_token_hooks(true);
909 }
910
911 // initialize the given context from the parsed options
912 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
913 // enable C99 mode, if appropriate (implies variadics)
914 if (vm.count("c99")) {
915 if (9 == debuglevel) {
916 std::cerr << "initialise_options: option: c99" << std::endl;
917 }
918 ctx.set_language(
919 boost::wave::language_support(
920 boost::wave::support_c99
921 | boost::wave::support_option_emit_line_directives
922 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
923 | boost::wave::support_option_include_guard_detection
924 #endif
925 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
926 | boost::wave::support_option_emit_pragma_directives
927 #endif
928 | boost::wave::support_option_insert_whitespace
929 ));
930 }
931 else if (vm.count("variadics")) {
932 // enable variadics and placemarkers, if appropriate
933 if (9 == debuglevel) {
934 std::cerr << "initialise_options: option: variadics" << std::endl;
935 }
936 ctx.set_language(boost::wave::enable_variadics(ctx.get_language()));
937 }
938 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
939
940 #if BOOST_WAVE_SUPPORT_CPP0X
941 if (vm.count("c++11")) {
942 if (9 == debuglevel) {
943 std::cerr << "initialise_options: option: c++11" << std::endl;
944 }
945 ctx.set_language(
946 boost::wave::language_support(
947 boost::wave::support_cpp0x
948 | boost::wave::support_option_convert_trigraphs
949 | boost::wave::support_option_long_long
950 | boost::wave::support_option_emit_line_directives
951 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
952 | boost::wave::support_option_include_guard_detection
953 #endif
954 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
955 | boost::wave::support_option_emit_pragma_directives
956 #endif
957 | boost::wave::support_option_insert_whitespace
958 ));
959 }
960 #endif
961
962 // enable long_long mode, if appropriate
963 if (vm.count("long_long")) {
964 if (9 == debuglevel) {
965 std::cerr << "initialise_options: option: long_long" << std::endl;
966 }
967 ctx.set_language(boost::wave::enable_long_long(ctx.get_language()));
968 }
969
970 // enable preserving comments mode, if appropriate
971 if (vm.count("preserve")) {
972 if (9 == debuglevel) {
973 std::cerr << "initialise_options: option: preserve" << std::endl;
974 }
975 ctx.set_language(
976 boost::wave::enable_preserve_comments(ctx.get_language()));
977 }
978
979 // disable automatic include guard detection
980 if (vm.count("noguard")) {
981 if (9 == debuglevel) {
982 std::cerr << "initialise_options: option: guard" << std::endl;
983 }
984 ctx.set_language(
985 boost::wave::enable_include_guard_detection(ctx.get_language(), false));
986 }
987
988 // enable trigraph conversion
989 if (9 == debuglevel) {
990 std::cerr << "initialise_options: option: convert_trigraphs" << std::endl;
991 }
992 ctx.set_language(boost::wave::enable_convert_trigraphs(ctx.get_language()));
993
994 // enable single_line mode
995 if (single_line) {
996 if (9 == debuglevel) {
997 std::cerr << "initialise_options: option: single_line" << std::endl;
998 }
999 ctx.set_language(boost::wave::enable_single_line(ctx.get_language()));
1000 ctx.set_language(boost::wave::enable_emit_line_directives(ctx.get_language(), false));
1001 }
1002
1003 // add include directories to the system include search paths
1004 if (vm.count("sysinclude")) {
1005 std::vector<std::string> const& syspaths =
1006 variables_map_as(vm["sysinclude"], (std::vector<std::string> *)NULL);
1007
1008 std::vector<std::string>::const_iterator end = syspaths.end();
1009 for (std::vector<std::string>::const_iterator cit = syspaths.begin();
1010 cit != end; ++cit)
1011 {
1012 if (9 == debuglevel) {
1013 std::cerr << "initialise_options: option: -S" << *cit
1014 << std::endl;
1015 }
1016 ctx.add_sysinclude_path((*cit).c_str());
1017 }
1018 }
1019
1020 // add include directories to the user include search paths
1021 if (vm.count("include")) {
1022 cmd_line_utils::include_paths const &ip =
1023 variables_map_as(vm["include"], (cmd_line_utils::include_paths*)NULL);
1024 std::vector<std::string>::const_iterator end = ip.paths.end();
1025
1026 for (std::vector<std::string>::const_iterator cit = ip.paths.begin();
1027 cit != end; ++cit)
1028 {
1029 if (9 == debuglevel) {
1030 std::cerr << "initialise_options: option: -I" << *cit
1031 << std::endl;
1032 }
1033 ctx.add_include_path((*cit).c_str());
1034 }
1035
1036 // if on the command line was given -I- , this has to be propagated
1037 if (ip.seen_separator) {
1038 if (9 == debuglevel) {
1039 std::cerr << "initialise_options: option: -I-" << std::endl;
1040 }
1041 ctx.set_sysinclude_delimiter();
1042 }
1043
1044 // add system include directories to the include path
1045 std::vector<std::string>::const_iterator sysend = ip.syspaths.end();
1046 for (std::vector<std::string>::const_iterator syscit = ip.syspaths.begin();
1047 syscit != sysend; ++syscit)
1048 {
1049 if (9 == debuglevel) {
1050 std::cerr << "initialise_options: option: -S" << *syscit
1051 << std::endl;
1052 }
1053 ctx.add_sysinclude_path((*syscit).c_str());
1054 }
1055 }
1056
1057 // add additional defined macros
1058 if (vm.count("define")) {
1059 std::vector<std::string> const &macros =
1060 variables_map_as(vm["define"], (std::vector<std::string>*)NULL);
1061 std::vector<std::string>::const_iterator end = macros.end();
1062 for (std::vector<std::string>::const_iterator cit = macros.begin();
1063 cit != end; ++cit)
1064 {
1065 if (9 == debuglevel) {
1066 std::cerr << "initialise_options: option: -D" << *cit
1067 << std::endl;
1068 }
1069 ctx.add_macro_definition(*cit, true);
1070 }
1071 }
1072
1073 // add additional predefined macros
1074 if (vm.count("predefine")) {
1075 std::vector<std::string> const &predefmacros =
1076 variables_map_as(vm["predefine"], (std::vector<std::string>*)NULL);
1077 std::vector<std::string>::const_iterator end = predefmacros.end();
1078 for (std::vector<std::string>::const_iterator cit = predefmacros.begin();
1079 cit != end; ++cit)
1080 {
1081 if (9 == debuglevel) {
1082 std::cerr << "initialise_options: option: -P" << *cit
1083 << std::endl;
1084 }
1085 ctx.add_macro_definition(*cit, true);
1086 }
1087 }
1088
1089 // undefine specified macros
1090 if (vm.count("undefine")) {
1091 std::vector<std::string> const &undefmacros =
1092 variables_map_as(vm["undefine"], (std::vector<std::string>*)NULL);
1093 std::vector<std::string>::const_iterator end = undefmacros.end();
1094 for (std::vector<std::string>::const_iterator cit = undefmacros.begin();
1095 cit != end; ++cit)
1096 {
1097 if (9 == debuglevel) {
1098 std::cerr << "initialise_options: option: -U" << *cit
1099 << std::endl;
1100 }
1101 ctx.remove_macro_definition(*cit);
1102 }
1103 }
1104
1105 // maximal include nesting depth
1106 if (vm.count("nesting")) {
1107 int max_depth = variables_map_as(vm["nesting"], (int*)NULL);
1108 if (max_depth < 1 || max_depth > 100000) {
1109 std::cerr << "testwave: bogus maximal include nesting depth: "
1110 << max_depth << std::endl;
1111 return false;
1112 }
1113 else if (9 == debuglevel) {
1114 std::cerr << "initialise_options: option: -n" << max_depth
1115 << std::endl;
1116 }
1117 ctx.set_max_include_nesting_depth(max_depth);
1118 }
1119
1120 if (9 == debuglevel) {
1121 std::cerr << "initialise_options: succeeded to initialize options"
1122 << std::endl;
1123 }
1124 return true;
1125 }
1126
1127 ///////////////////////////////////////////////////////////////////////////////
1128 // construct a SIZEOF macro definition string and predefine this macro
1129 template <typename Context>
1130 inline bool
1131 testwave_app::add_sizeof_definition(Context& ctx, char const *name, int value)
1132 {
1133 BOOST_WAVETEST_OSSTREAM strm;
1134 strm << "__TESTWAVE_SIZEOF_" << name << "__=" << value;
1135
1136 std::string macro(BOOST_WAVETEST_GETSTRING(strm));
1137 if (!ctx.add_macro_definition(macro, true)) {
1138 std::cerr << "testwave: failed to predefine macro: " << macro
1139 << std::endl;
1140 return false;
1141 }
1142 else if (9 == debuglevel) {
1143 std::cerr << "add_sizeof_definition: predefined macro: " << macro
1144 << std::endl;
1145 }
1146 return true;
1147 }
1148
1149 // construct a MIN macro definition string and predefine this macro
1150 template <typename T, typename Context>
1151 inline bool
1152 testwave_app::add_min_definition(Context& ctx, char const *name)
1153 {
1154 BOOST_WAVETEST_OSSTREAM strm;
1155 if (!std::numeric_limits<T>::is_signed) {
1156 strm << "__TESTWAVE_" << name << "_MIN__="
1157 << "0x" << std::hex
1158 << (std::numeric_limits<T>::min)() << "U";
1159 }
1160 else {
1161 strm << "__TESTWAVE_" << name << "_MIN__=( "
1162 << (std::numeric_limits<T>::min)()+1 << "-1)";
1163 }
1164
1165 std::string macro(BOOST_WAVETEST_GETSTRING(strm));
1166 if (!ctx.add_macro_definition(macro, true)) {
1167 std::cerr << "testwave: failed to predefine macro: " << macro
1168 << std::endl;
1169 return false;
1170 }
1171 else if (9 == debuglevel) {
1172 std::cerr << "add_min_definition: predefined macro: " << macro
1173 << std::endl;
1174 }
1175 return true;
1176 }
1177
1178 // construct a MAX macro definition string and predefine this macro
1179 template <typename T, typename Context>
1180 inline bool
1181 testwave_app::add_max_definition(Context& ctx, char const *name)
1182 {
1183 BOOST_WAVETEST_OSSTREAM strm;
1184 if (!std::numeric_limits<T>::is_signed) {
1185 strm << "__TESTWAVE_" << name << "_MAX__="
1186 << "0x" << std::hex
1187 << (std::numeric_limits<T>::max)() << "U";
1188 }
1189 else {
1190 strm << "__TESTWAVE_" << name << "_MAX__="
1191 << (std::numeric_limits<T>::max)();
1192 }
1193
1194 std::string macro(BOOST_WAVETEST_GETSTRING(strm));
1195 if (!ctx.add_macro_definition(macro, true)) {
1196 std::cerr << "testwave: failed to predefine macro: " << macro
1197 << std::endl;
1198 return false;
1199 }
1200 else if (9 == debuglevel) {
1201 std::cerr << "add_max_definition: predefined macro: " << macro
1202 << std::endl;
1203 }
1204 return true;
1205 }
1206
1207 // Predefine __TESTWAVE_HAS_STRICT_LEXER__
1208 template <typename Context>
1209 inline bool
1210 testwave_app::add_strict_lexer_definition(Context& ctx)
1211 {
1212 std::string macro("__TESTWAVE_HAS_STRICT_LEXER__=1");
1213 if (!ctx.add_macro_definition(macro, true)) {
1214 std::cerr << "testwave: failed to predefine macro: " << macro
1215 << std::endl;
1216 return false;
1217 }
1218 else if (9 == debuglevel) {
1219 std::cerr << "add_strict_lexer_definition: predefined macro: " << macro
1220 << std::endl;
1221 }
1222 return true;
1223 }
1224
1225 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS
1226 // Predefine __TESTWAVE_SUPPORT_MS_EXTENSIONS__
1227 template <typename Context>
1228 inline bool
1229 testwave_app::add_support_ms_extensions_definition(Context& ctx)
1230 {
1231 std::string macro("__TESTWAVE_SUPPORT_MS_EXTENSIONS__=1");
1232 if (!ctx.add_macro_definition(macro, true)) {
1233 std::cerr << "testwave: failed to predefine macro: " << macro
1234 << std::endl;
1235 return false;
1236 }
1237 else if (9 == debuglevel) {
1238 std::cerr << "add_support_ms_extensions_definition: predefined macro: "
1239 << macro
1240 << std::endl;
1241 }
1242 return true;
1243 }
1244 #endif
1245
1246 ///////////////////////////////////////////////////////////////////////////////
1247 //
1248 // Add special predefined macros to the context object.
1249 //
1250 // This adds a lot of macros to the test environment, which allows to adjust
1251 // the test cases for different platforms.
1252 //
1253 ///////////////////////////////////////////////////////////////////////////////
1254 template <typename Context>
1255 bool
1256 testwave_app::add_predefined_macros(Context& ctx)
1257 {
1258 // add the __TESTWAVE_SIZEOF_<type>__ macros
1259 if (!add_sizeof_definition(ctx, "CHAR", sizeof(char)) ||
1260 !add_sizeof_definition(ctx, "SHORT", sizeof(short)) ||
1261 !add_sizeof_definition(ctx, "INT", sizeof(int)) ||
1262 #if defined(BOOST_HAS_LONG_LONG)
1263 !add_sizeof_definition(ctx, "LONGLONG", sizeof(boost::long_long_type)) ||
1264 #endif
1265 !add_sizeof_definition(ctx, "LONG", sizeof(long)))
1266 {
1267 std::cerr << "testwave: failed to add a predefined macro (SIZEOF)."
1268 << std::endl;
1269 return false;
1270 }
1271
1272 // add the __TESTWAVE_<type>_MIN__ macros
1273 if (/*!add_min_definition<char>(ctx, "CHAR") ||*/
1274 /*!add_min_definition<unsigned char>(ctx, "UCHAR") ||*/
1275 !add_min_definition<short>(ctx, "SHORT") ||
1276 !add_min_definition<unsigned short>(ctx, "USHORT") ||
1277 !add_min_definition<int>(ctx, "INT") ||
1278 !add_min_definition<unsigned int>(ctx, "UINT") ||
1279 #if defined(BOOST_HAS_LONG_LONG)
1280 !add_min_definition<boost::long_long_type>(ctx, "LONGLONG") ||
1281 !add_min_definition<boost::ulong_long_type>(ctx, "ULONGLONG") ||
1282 #endif
1283 !add_min_definition<long>(ctx, "LONG") ||
1284 !add_min_definition<unsigned long>(ctx, "ULONG"))
1285 {
1286 std::cerr << "testwave: failed to add a predefined macro (MIN)."
1287 << std::endl;
1288 }
1289
1290 // add the __TESTWAVE_<type>_MAX__ macros
1291 if (/*!add_max_definition<char>(ctx, "CHAR") ||*/
1292 /*!add_max_definition<unsigned char>(ctx, "UCHAR") ||*/
1293 !add_max_definition<short>(ctx, "SHORT") ||
1294 !add_max_definition<unsigned short>(ctx, "USHORT") ||
1295 !add_max_definition<int>(ctx, "INT") ||
1296 !add_max_definition<unsigned int>(ctx, "UINT") ||
1297 #if defined(BOOST_HAS_LONG_LONG)
1298 !add_max_definition<boost::long_long_type>(ctx, "LONGLONG") ||
1299 !add_max_definition<boost::ulong_long_type>(ctx, "ULONGLONG") ||
1300 #endif
1301 !add_max_definition<long>(ctx, "LONG") ||
1302 !add_max_definition<unsigned long>(ctx, "ULONG"))
1303 {
1304 std::cerr << "testwave: failed to add a predefined macro (MAX)."
1305 << std::endl;
1306 }
1307
1308 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS
1309 // Predefine __TESTWAVE_SUPPORT_MS_EXTENSIONS__
1310 if (!add_support_ms_extensions_definition(ctx))
1311 {
1312 std::cerr << "testwave: failed to add a predefined macro "
1313 "(__TESTWAVE_SUPPORT_MS_EXTENSIONS__)."
1314 << std::endl;
1315 }
1316 #endif
1317
1318 #if BOOST_WAVE_USE_STRICT_LEXER != 0
1319 return add_strict_lexer_definition(ctx);
1320 #else
1321 return true;
1322 #endif
1323 }
1324
1325 ///////////////////////////////////////////////////////////////////////////////
1326 //
1327 // Preprocess the given input data and return the generated output through
1328 // the parameter 'result'.
1329 //
1330 ///////////////////////////////////////////////////////////////////////////////
1331 bool
1332 testwave_app::preprocess_file(std::string filename, std::string const& instr,
1333 std::string& result, std::string& error, std::string& hooks,
1334 std::string const& expected_cfg_macro, bool single_line)
1335 {
1336 // create the wave::context object and initialize it from the file to
1337 // preprocess (may contain options inside of special comments)
1338 typedef boost::wave::cpplexer::lex_token<> token_type;
1339 typedef boost::wave::cpplexer::lex_iterator<token_type> lexer_type;
1340 typedef boost::wave::context<
1341 std::string::const_iterator, lexer_type,
1342 boost::wave::iteration_context_policies::load_file_to_string,
1343 collect_hooks_information<token_type> >
1344 context_type;
1345
1346 if (9 == debuglevel) {
1347 std::cerr << "preprocess_file: preprocessing input file: " << filename
1348 << std::endl;
1349 }
1350
1351 try {
1352 // create preprocessing context
1353 context_type ctx(instr.begin(), instr.end(), filename.c_str(),
1354 collect_hooks_information<token_type>(hooks));
1355
1356 // initialize the context from the options given on the command line
1357 if (!initialise_options(ctx, global_vm, single_line))
1358 return false;
1359
1360 // extract the options from the input data and initialize the context
1361 boost::program_options::variables_map local_vm;
1362 if (!extract_options(filename, instr, ctx, single_line, local_vm))
1363 return false;
1364
1365 // add special predefined macros
1366 if (!add_predefined_macros(ctx))
1367 return false;
1368
1369 if (!expected_cfg_macro.empty() &&
1370 !ctx.is_defined_macro(expected_cfg_macro))
1371 {
1372 // skip this test as it is for a disabled configuration
1373 return false;
1374 }
1375
1376 // preprocess the input, loop over all generated tokens collecting the
1377 // generated text
1378 context_type::iterator_type it = ctx.begin();
1379 context_type::iterator_type end = ctx.end();
1380
1381 if (local_vm.count("forceinclude")) {
1382 // add the filenames to force as include files in _reverse_ order
1383 // the second parameter 'is_last' of the force_include function should
1384 // be set to true for the last (first given) file.
1385 std::vector<std::string> const &force =
1386 local_vm["forceinclude"].as<std::vector<std::string> >();
1387 std::vector<std::string>::const_reverse_iterator rend = force.rend();
1388 for (std::vector<std::string>::const_reverse_iterator cit = force.rbegin();
1389 cit != rend; /**/)
1390 {
1391 std::string forceinclude(*cit);
1392 if (9 == debuglevel) {
1393 std::cerr << "preprocess_file: option: forceinclude ("
1394 << forceinclude << ")" << std::endl;
1395 }
1396 it.force_include(forceinclude.c_str(), ++cit == rend);
1397 }
1398 }
1399
1400 // perform actual preprocessing
1401 for (/**/; it != end; ++it)
1402 {
1403 using namespace boost::wave;
1404
1405 if (T_PP_LINE == token_id(*it)) {
1406 // special handling of the whole #line directive is required to
1407 // allow correct file name matching
1408 if (!handle_line_directive(it, end, result))
1409 return false; // unexpected eof
1410 }
1411 else {
1412 // add the value of the current token
1413 result = result + (*it).get_value().c_str();
1414 }
1415 }
1416 error.clear();
1417 }
1418 catch (boost::wave::cpplexer::lexing_exception const& e) {
1419 // some lexer error
1420 BOOST_WAVETEST_OSSTREAM strm;
1421 std::string filename = e.file_name();
1422 strm
1423 << handle_filepath(filename) << "(" << e.line_no() << "): "
1424 << e.description() << std::endl;
1425
1426 error = BOOST_WAVETEST_GETSTRING(strm);
1427 return false;
1428 }
1429 catch (boost::wave::cpp_exception const& e) {
1430 // some preprocessing error
1431 BOOST_WAVETEST_OSSTREAM strm;
1432 std::string filename = e.file_name();
1433 strm
1434 << handle_filepath(filename) << "(" << e.line_no() << "): "
1435 << e.description() << std::endl;
1436
1437 error = BOOST_WAVETEST_GETSTRING(strm);
1438 return false;
1439 }
1440
1441 if (9 == debuglevel) {
1442 std::cerr << "preprocess_file: succeeded to preprocess input file: "
1443 << filename << std::endl;
1444 }
1445
1446 return true;
1447 }
1448