📄 testwave_app.cpp
字号:
/*============================================================================= Boost.Wave: A Standard compliant C++ preprocessor library http://www.boost.org/ Copyright (c) 2001-2008 Hartmut Kaiser. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)=============================================================================*/// system headers#include <string>#include <iostream>#include <vector>// include boost#include <boost/config.hpp>#include <boost/throw_exception.hpp>#include <boost/filesystem/path.hpp>#include <boost/filesystem/operations.hpp>#include <boost/detail/workaround.hpp>// include Wave // always use new hooks#define BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS 0#include <boost/wave.hpp>// include the lexer related stuff#include <boost/wave/cpplexer/cpp_lex_token.hpp> // token type#include <boost/wave/cpplexer/cpp_lex_iterator.hpp> // lexer type// test application related headers#include "cmd_line_utils.hpp"#include "testwave_app.hpp"#include "collect_hooks_information.hpp"namespace po = boost::program_options;namespace fs = boost::filesystem;///////////////////////////////////////////////////////////////////////////////// testwave version definitions#define TESTWAVE_VERSION_MAJOR 0#define TESTWAVE_VERSION_MINOR 5#define TESTWAVE_VERSION_SUBMINOR 0namespace { /////////////////////////////////////////////////////////////////////////// template <typename Iterator> inline bool handle_next_token(Iterator &it, Iterator const& end, std::string &result) { typedef typename Iterator::value_type token_type; token_type tok = *it++; result = result + tok.get_value().c_str(); return (it == end) ? false : true; } /////////////////////////////////////////////////////////////////////////// template <typename String> String const& handle_quoted_filepath(String &name) { using boost::wave::util::impl::unescape_lit; String unesc_name = unescape_lit(name.substr(1, name.size()-2)); fs::path p (unesc_name.c_str(), fs::native); name = String("\"") + p.leaf().c_str() + String("\""); return name; } /////////////////////////////////////////////////////////////////////////// template <typename Iterator> bool handle_line_directive(Iterator &it, Iterator const& end, std::string &result) { typedef typename Iterator::value_type token_type; typedef typename token_type::string_type string_type; if (!handle_next_token(it, end, result) || // #line !handle_next_token(it, end, result) || // whitespace !handle_next_token(it, end, result) || // number !handle_next_token(it, end, result)) // whitespace { return false; } using boost::wave::util::impl::unescape_lit; token_type filename = *it; string_type name = filename.get_value(); handle_quoted_filepath(name); result = result + name.c_str(); return true; } template <typename T> inline T const& variables_map_as(po::variable_value const& v, T*) {#if (__GNUC__ == 3 && (__GNUC_MINOR__ == 2 || __GNUC_MINOR__ == 3)) || \ BOOST_WORKAROUND(__MWERKS__, < 0x3200)// gcc 3.2.x and 3.3.x choke on vm[...].as<...>()// CW 8.3 has problems with the v.as<T>() below T const* r = boost::any_cast<T>(&v.value()); if (!r) boost::throw_exception(boost::bad_any_cast()); return *r;#else return v.as<T>();#endif }}/////////////////////////////////////////////////////////////////////////////// This function compares the real result and the expected one but first // replaces all occurrences in the expected result of // $E: to the result of preprocessing the given expression// $F: to the passed full filepath // $P: to the full path// $B: to the full path (same as $P, but using forward slash '/' on Windows)// $V: to the current Boost version number/////////////////////////////////////////////////////////////////////////////bool testwave_app::got_expected_result(std::string const& filename, std::string const& result, std::string& expected){ using boost::wave::util::impl::escape_lit; std::string full_result; std::string::size_type pos = 0; std::string::size_type pos1 = expected.find_first_of("$"); if (pos1 != std::string::npos) { do { switch(expected[pos1+1]) { case 'E': // preprocess the given token sequence { if ('(' == expected[pos1+2]) { std::size_t p = expected.find_first_of(")", pos1+1); if (std::string::npos == p) { std::cerr << "testwave: unmatched parenthesis in $E" " directive" << std::endl; return false; } std::string source = expected.substr(pos1+3, p-pos1-3); std::string result, error, hooks; bool pp_result = preprocess_file(filename, source, result, error, hooks, true); if (!pp_result) { std::cerr << "testwave: preprocessing error in $E directive: " << error << std::endl; return false; } full_result = full_result + expected.substr(pos, pos1-pos) + result; pos1 = expected.find_first_of ("$", pos = pos1 + 4 + source.size()); } } break; case 'F': // insert base file name full_result = full_result + expected.substr(pos, pos1-pos) + escape_lit(filename); pos1 = expected.find_first_of ("$", pos = pos1 + 2); break; case 'P': // insert full path case 'B': // same as 'P', but forward slashs on Windows { fs::path fullpath ( fs::complete( fs::path(filename, fs::native), fs::current_path()) ); if ('(' == expected[pos1+2]) { // the $P(basename) syntax is used std::size_t p = expected.find_first_of(")", pos1+1); if (std::string::npos == p) { std::cerr << "testwave: unmatched parenthesis in $P" " directive" << std::endl; return false; } std::string base = expected.substr(pos1+3, p-pos1-3); fullpath = fullpath.branch_path() / fs::path(base, fs::native); full_result += expected.substr(pos, pos1-pos); if ('P' == expected[pos1+1]) { full_result += escape_lit(fullpath.normalize().native_file_string()); } else { full_result += escape_lit(fullpath.normalize().string()); } pos1 = expected.find_first_of ("$", pos = pos1 + 4 + base.size()); } else { // the $P is used on its own full_result += expected.substr(pos, pos1-pos); if ('P' == expected[pos1+1]) { full_result += escape_lit(fullpath.native_file_string()); } else { full_result += escape_lit(fullpath.string()); } pos1 = expected.find_first_of ("$", pos = pos1 + 2); } } break; case 'V': // insert Boost version full_result = full_result + expected.substr(pos, pos1-pos) + BOOST_LIB_VERSION; pos1 = expected.find_first_of ("$", pos = pos1 + 2); break; default: full_result = full_result + expected.substr(pos, pos1-pos); pos1 = expected.find_first_of ("$", (pos = pos1) + 1); break; } } while(pos1 != std::string::npos); full_result += expected.substr(pos); } else { full_result = expected; } expected = full_result; return full_result == result;}///////////////////////////////////////////////////////////////////////////////testwave_app::testwave_app(po::variables_map const& vm): debuglevel(1), desc_options("Preprocessor configuration options"), global_vm(vm){ desc_options.add_options() ("include,I", po::value<cmd_line_utils::include_paths>()->composing(), "specify an additional include directory") ("sysinclude,S", po::value<std::vector<std::string> >()->composing(), "specify an additional system include directory") ("define,D", po::value<std::vector<std::string> >()->composing(), "specify a macro to define (as macro[=[value]])") ("predefine,P", po::value<std::vector<std::string> >()->composing(), "specify a macro to predefine (as macro[=[value]])") ("undefine,U", po::value<std::vector<std::string> >()->composing(), "specify a macro to undefine") ("nesting,n", po::value<int>(), "specify a new maximal include nesting depth") ("long_long", "enable long long support in C++ mode") ("preserve", "preserve comments")#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 ("variadics", "enable certain C99 extensions in C++ mode") ("c99", "enable C99 mode (implies --variadics)")#endif #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 ("noguard,G", "disable include guard detection")#endif ;}/////////////////////////////////////////////////////////////////////////////////// Test the given file (i.e. preprocess the file and compare the result // against the embedded 'R' comments, if an error occurs compare the error// message against the given 'E' comments, if no error occurred, compare the// generated hooks result against the given 'H' comments)./////////////////////////////////////////////////////////////////////////////////bool testwave_app::test_a_file(std::string filename){// read the input file into a string std::string instr; if (!read_file(filename, instr)) return false; // error was reported already bool test_hooks = true; if (global_vm.count("hooks")) test_hooks = variables_map_as(global_vm["hooks"], (bool *)NULL); // extract expected output, preprocess the data and compare results std::string expected, expected_hooks; if (extract_expected_output(filename, instr, expected, expected_hooks)) { bool retval = true; // assume success bool printed_result = false; std::string result, error, hooks; bool pp_result = preprocess_file(filename, instr, result, error, hooks); if (pp_result || !result.empty()) { // did we expect an error? std::string expected_error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -