diff options
Diffstat (limited to 'src/boost/libs/wave/tool')
-rw-r--r-- | src/boost/libs/wave/tool/build/Jamfile.v2 | 73 | ||||
-rw-r--r-- | src/boost/libs/wave/tool/cpp.cpp | 1508 | ||||
-rw-r--r-- | src/boost/libs/wave/tool/cpp.hpp | 42 | ||||
-rw-r--r-- | src/boost/libs/wave/tool/cpp_config.hpp | 63 | ||||
-rw-r--r-- | src/boost/libs/wave/tool/cpp_version.hpp | 25 | ||||
-rw-r--r-- | src/boost/libs/wave/tool/stop_watch.hpp | 84 | ||||
-rw-r--r-- | src/boost/libs/wave/tool/trace_macro_expansion.hpp | 1494 |
7 files changed, 3289 insertions, 0 deletions
diff --git a/src/boost/libs/wave/tool/build/Jamfile.v2 b/src/boost/libs/wave/tool/build/Jamfile.v2 new file mode 100644 index 00000000..e7d91114 --- /dev/null +++ b/src/boost/libs/wave/tool/build/Jamfile.v2 @@ -0,0 +1,73 @@ +# Wave: A Standard compliant C++ preprocessor +# +# Boost Wave Library Build Jamfile +# +# http://www.boost.org/ +# +# Copyright (c) 2001-2010 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) + +# Make sure all of Wave is compiled with threading disabled. We still need +# to link with Boost.Thread, but no multi-threaded features are being used +# in the Wave tool anyway. + +import feature ; +import option ; + +feature.feature wavetool + : on + : optional composite propagated + ; + +feature.compose <wavetool>on + : <define>BOOST_WAVE_SUPPORT_THREADING=0 + ; + +############################################################################### +project + : requirements + <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE + <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE + ; + +exe wave + : + ../cpp.cpp + /boost//wave + /boost//program_options + /boost//filesystem + /boost//serialization + /boost//system + /boost//thread + /boost//date_time + : + <threading>multi +# <debug-symbols>on + <wavetool>on + : + release + ; + +local bindir = [ option.get bindir : ../../../dist/bin ] ; +local libdir = [ option.get libdir : ../../../dist/lib ] ; + +install dist-bin + : + wave + : + <install-type>EXE + <location>$(bindir) + : + release + ; + +install dist-lib + : + wave + : + <install-type>LIB + <location>$(libdir) + : + release + ; diff --git a/src/boost/libs/wave/tool/cpp.cpp b/src/boost/libs/wave/tool/cpp.cpp new file mode 100644 index 00000000..36988a6b --- /dev/null +++ b/src/boost/libs/wave/tool/cpp.cpp @@ -0,0 +1,1508 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2012 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) +=============================================================================*/ + +#define BOOST_WAVE_SERIALIZATION 0 // enable serialization +#define BOOST_WAVE_BINARY_SERIALIZATION 0 // use binary archives +#define BOOST_WAVE_XML_SERIALIZATION 1 // use XML archives + +#include "cpp.hpp" // global configuration + +/////////////////////////////////////////////////////////////////////////////// +// Include additional Boost libraries +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/convenience.hpp> +#include <boost/filesystem/fstream.hpp> +#include <boost/timer.hpp> +#include <boost/any.hpp> +#include <boost/algorithm/cxx11/any_of.hpp> +#include <boost/algorithm/string/join.hpp> +#include <boost/range/algorithm/find.hpp> +#include <boost/range/end.hpp> +#include <boost/foreach.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// Include Wave itself +#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 + +/////////////////////////////////////////////////////////////////////////////// +// Include serialization support, if requested +#if BOOST_WAVE_SERIALIZATION != 0 +#include <boost/serialization/serialization.hpp> +#if BOOST_WAVE_BINARY_SERIALIZATION != 0 +#include <boost/archive/binary_iarchive.hpp> +#include <boost/archive/binary_oarchive.hpp> +typedef boost::archive::binary_iarchive iarchive; +typedef boost::archive::binary_oarchive oarchive; +#elif BOOST_WAVE_XML_SERIALIZATION != 0 +#include <boost/archive/xml_iarchive.hpp> +#include <boost/archive/xml_oarchive.hpp> +typedef boost::archive::xml_iarchive iarchive; +typedef boost::archive::xml_oarchive oarchive; +#else +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +typedef boost::archive::text_iarchive iarchive; +typedef boost::archive::text_oarchive oarchive; +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Include the context policies to use +#include "trace_macro_expansion.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// Include lexer specifics, import lexer names +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0 +#include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp> +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Include the grammar definitions, if these shouldn't be compiled separately +// (ATTENTION: _very_ large compilation times!) +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0 +#include <boost/wave/grammars/cpp_intlit_grammar.hpp> +#include <boost/wave/grammars/cpp_chlit_grammar.hpp> +#include <boost/wave/grammars/cpp_grammar.hpp> +#include <boost/wave/grammars/cpp_expression_grammar.hpp> +#include <boost/wave/grammars/cpp_predef_macros_grammar.hpp> +#include <boost/wave/grammars/cpp_defined_grammar.hpp> +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Import required names +using namespace boost::spirit::classic; + +using std::pair; +using std::vector; +using std::getline; +using boost::filesystem::ofstream; +using boost::filesystem::ifstream; +using std::cout; +using std::cerr; +using std::endl; +using std::ostream; +using std::istreambuf_iterator; + +/////////////////////////////////////////////////////////////////////////////// +// +// This application uses the lex_iterator and lex_token types predefined +// with the Wave library, but it is possible to use your own types. +// +// You may want to have a look at the other samples to see how this is +// possible to achieve. + typedef boost::wave::cpplexer::lex_token<> token_type; + typedef boost::wave::cpplexer::lex_iterator<token_type> + lex_iterator_type; + +// The C++ preprocessor iterators shouldn't be constructed directly. They +// are to be generated through a boost::wave::context<> object. This +// boost::wave::context object is additionally to be used to initialize and +// define different parameters of the actual preprocessing. + typedef boost::wave::context< + std::string::iterator, lex_iterator_type, + boost::wave::iteration_context_policies::load_file_to_string, + trace_macro_expansion<token_type> > + context_type; + +/////////////////////////////////////////////////////////////////////////////// +// print the current version +std::string get_version() +{ + std::string version (context_type::get_version_string()); + version = version.substr(1, version.size()-2); // strip quotes + version += std::string(" (" CPP_VERSION_DATE_STR ")"); // add date + return version; +} + +/////////////////////////////////////////////////////////////////////////////// +// print the current version for interactive sessions +int print_interactive_version() +{ + cout << "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library" << endl; + cout << "Version: " << get_version() << endl; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// print the copyright statement +int print_copyright() +{ + char const *copyright[] = { + "", + "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library", + "http://www.boost.org/", + "", + "Copyright (c) 2001-2012 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)", + 0 + }; + + for (int i = 0; 0 != copyright[i]; ++i) + cout << copyright[i] << endl; + + return 0; // exit app +} + +/////////////////////////////////////////////////////////////////////////////// +// forward declarations only +namespace cmd_line_utils +{ + class include_paths; +} + +namespace boost { namespace program_options { + + void validate(boost::any &v, std::vector<std::string> const &s, + cmd_line_utils::include_paths *, long); + +}} // boost::program_options + +/////////////////////////////////////////////////////////////////////////////// +#include <boost/program_options.hpp> + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + +/////////////////////////////////////////////////////////////////////////////// +namespace cmd_line_utils { + // Additional command line parser which interprets '@something' as an + // option "config-file" with the value "something". + inline pair<std::string, std::string> + at_option_parser(std::string const&s) + { + if ('@' == s[0]) + return std::make_pair(std::string("config-file"), s.substr(1)); + else + return pair<std::string, std::string>(); + } + + // class, which keeps include file information read from the command line + class include_paths { + public: + include_paths() : seen_separator(false) {} + + vector<std::string> paths; // stores user paths + vector<std::string> syspaths; // stores system paths + bool seen_separator; // command line contains a '-I-' option + + // Function which validates additional tokens from command line. + static void + validate(boost::any &v, vector<std::string> const &tokens) + { + if (v.empty()) + v = boost::any(include_paths()); + + include_paths *p = boost::any_cast<include_paths>(&v); + + BOOST_ASSERT(p); + // Assume only one path per '-I' occurrence. + std::string const& t = po::validators::get_single_string(tokens); + if (t == "-") { + // found -I- option, so switch behaviour + p->seen_separator = true; + } + else if (p->seen_separator) { + // store this path as a system path + p->syspaths.push_back(t); + } + else { + // store this path as an user path + p->paths.push_back(t); + } + } + }; + + // Read all options from a given config file, parse and add them to the + // given variables_map + bool read_config_file_options(std::string const &filename, + po::options_description const &desc, po::variables_map &vm, + bool may_fail = false) + { + ifstream ifs(filename.c_str()); + + if (!ifs.is_open()) { + if (!may_fail) { + cerr << filename + << ": command line warning: config file not found" + << endl; + } + return false; + } + + vector<std::string> options; + std::string line; + + while (std::getline(ifs, line)) { + // skip empty lines + std::string::size_type pos = line.find_first_not_of(" \t"); + if (pos == std::string::npos) + continue; + + // skip comment lines + if ('#' != line[pos]) { + // strip leading and trailing whitespace + std::string::size_type endpos = line.find_last_not_of(" \t"); + BOOST_ASSERT(endpos != std::string::npos); + options.push_back(line.substr(pos, endpos-pos+1)); + } + } + + if (options.size() > 0) { + using namespace boost::program_options::command_line_style; + po::store(po::command_line_parser(options) + .options(desc).style(unix_style).run(), vm); + po::notify(vm); + } + return true; + } + + // predicate to extract all positional arguments from the command line + struct is_argument { + bool operator()(po::option const &opt) + { + return (opt.position_key == -1) ? true : false; + } + }; + + // trim quotes from path names, if any + std::string trim_quotes(std::string const& file) + { + if (('"' == file[0] || '\'' == file[0]) && file[0] == file[file.size()-1]) + { + return file.substr(1, file.size()-2); + } + return file; + } + +/////////////////////////////////////////////////////////////////////////////// +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Special validator overload, which allows to handle the -I- syntax for +// switching the semantics of an -I option. +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace program_options { + + void validate(boost::any &v, std::vector<std::string> const &s, + cmd_line_utils::include_paths *, long) + { + cmd_line_utils::include_paths::validate(v, s); + } + +}} // namespace boost::program_options + +/////////////////////////////////////////////////////////////////////////////// +namespace { + + class auto_stop_watch : public stop_watch + { + public: + auto_stop_watch(std::ostream &outstrm_) + : print_time(false), outstrm(outstrm_) + { + } + + ~auto_stop_watch() + { + if (print_time) { + outstrm << "Elapsed time: " + << this->format_elapsed_time() + << std::endl; + } + } + + void set_print_time(bool print_time_) + { + print_time = print_time_; + } + + private: + bool print_time; + std::ostream &outstrm; + }; + + /////////////////////////////////////////////////////////////////////////// + inline std::string + report_iostate_error(std::ios::iostate state) + { + BOOST_ASSERT(state & (std::ios::badbit | std::ios::failbit | std::ios::eofbit)); + std::string result; + if (state & std::ios::badbit) { + result += " the reported problem was: " + "loss of integrity of the stream buffer\n"; + } + if (state & std::ios::failbit) { + result += " the reported problem was: " + "an operation was not processed correctly\n"; + } + if (state & std::ios::eofbit) { + result += " the reported problem was: " + "end-of-file while writing to the stream\n"; + } + return result; + } + + /////////////////////////////////////////////////////////////////////////// + // Retrieve the position of a macro definition + template <typename Context> + inline bool + get_macro_position(Context &ctx, + typename Context::token_type::string_type const& name, + typename Context::position_type &pos) + { + bool has_parameters = false; + bool is_predefined = false; + std::vector<typename Context::token_type> parameters; + typename Context::token_sequence_type definition; + + return ctx.get_macro_definition(name, has_parameters, is_predefined, + pos, parameters, definition); + } + + /////////////////////////////////////////////////////////////////////////// + // Generate some meaningful error messages + template <typename Exception> + inline int + report_error_message(Exception const &e, bool treat_warnings_as_error) + { + // default error reporting + cerr + << e.file_name() << ":" << e.line_no() << ":" << e.column_no() + << ": " << e.description() << endl; + + // errors count as one + return (treat_warnings_as_error || + e.get_severity() == boost::wave::util::severity_error || + e.get_severity() == boost::wave::util::severity_fatal) ? 1 : 0; + } + + template <typename Context> + inline int + report_error_message(Context &ctx, boost::wave::cpp_exception const &e, + bool treat_warnings_as_error) + { + // default error reporting + int result = report_error_message(e, treat_warnings_as_error); + + using boost::wave::preprocess_exception; + switch(e.get_errorcode()) { + case preprocess_exception::macro_redefinition: + { + // report the point of the initial macro definition + typename Context::position_type pos; + if (get_macro_position(ctx, e.get_related_name(), pos)) { + cerr + << pos << ": " + << preprocess_exception::severity_text(e.get_severity()) + << ": this is the location of the previous definition." + << endl; + } + else { + cerr + << e.file_name() << ":" << e.line_no() << ":" + << e.column_no() << ": " + << preprocess_exception::severity_text(e.get_severity()) + << ": not able to retrieve the location of the previous " + << "definition." << endl; + } + } + break; + + default: + break; + } + + return result; + } + + /////////////////////////////////////////////////////////////////////////// + // Read one logical line of text + inline bool + read_a_line (std::istream &instream, std::string &instring) + { + bool eol = true; + do { + std::string line; + std::getline(instream, line); + if (instream.rdstate() & std::ios::failbit) + return false; // nothing to do + + eol = true; + if (line.find_last_of('\\') == line.size()-1) + eol = false; + + instring += line + '\n'; + } while (!eol); + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // Load and save the internal tables of the wave::context object + template <typename Context> + inline void + load_state(po::variables_map const &vm, Context &ctx) + { +#if BOOST_WAVE_SERIALIZATION != 0 + try { + if (vm.count("state") > 0) { + fs::path state_file ( + boost::wave::util::create_path(vm["state"].as<std::string>())); + if (state_file == "-") + state_file = boost::wave::util::create_path("wave.state"); + + std::ios::openmode mode = std::ios::in; + +#if BOOST_WAVE_BINARY_SERIALIZATION != 0 + mode = (std::ios::openmode)(mode | std::ios::binary); +#endif + ifstream ifs (state_file.string().c_str(), mode); + if (ifs.is_open()) { + using namespace boost::serialization; + iarchive ia(ifs); + std::string version; + + ia >> make_nvp("version", version); // load version + if (version == CPP_VERSION_FULL_STR) + ia >> make_nvp("state", ctx); // load the internal tables from disc + else { + cerr << "wave: detected version mismatch while loading state, state was not loaded." << endl; + cerr << " loaded version: " << version << endl; + cerr << " expected version: " << CPP_VERSION_FULL_STR << endl; + } + } + } + } + catch (boost::archive::archive_exception const& e) { + cerr << "wave: error while loading state: " + << e.what() << endl; + } + catch (boost::wave::preprocess_exception const& e) { + cerr << "wave: error while loading state: " + << e.description() << endl; + } +#endif + } + + template <typename Context> + inline void + save_state(po::variables_map const &vm, Context const &ctx) + { +#if BOOST_WAVE_SERIALIZATION != 0 + try { + if (vm.count("state") > 0) { + fs::path state_file (boost::wave::util::create_path( + vm["state"].as<std::string>())); + if (state_file == "-") + state_file = boost::wave::util::create_path("wave.state"); + + std::ios::openmode mode = std::ios::out; + +#if BOOST_WAVE_BINARY_SERIALIZATION != 0 + mode = (std::ios::openmode)(mode | std::ios::binary); +#endif + ofstream ofs(state_file.string().c_str(), mode); + if (!ofs.is_open()) { + cerr << "wave: could not open state file for writing: " + << state_file.string() << endl; + // this is non-fatal + } + else { + using namespace boost::serialization; + oarchive oa(ofs); + std::string version(CPP_VERSION_FULL_STR); + oa << make_nvp("version", version); // write version + oa << make_nvp("state", ctx); // write the internal tables to disc + } + } + } + catch (boost::archive::archive_exception const& e) { + cerr << "wave: error while writing state: " + << e.what() << endl; + } +#endif + } + + /////////////////////////////////////////////////////////////////////////// + // list all defined macros + bool list_macro_names(context_type const& ctx, std::string filename) + { + // open file for macro names listing + ofstream macronames_out; + fs::path macronames_file (boost::wave::util::create_path(filename)); + + if (macronames_file != "-") { + macronames_file = boost::wave::util::complete_path(macronames_file); + boost::wave::util::create_directories( + boost::wave::util::branch_path(macronames_file)); + macronames_out.open(macronames_file.string().c_str()); + if (!macronames_out.is_open()) { + cerr << "wave: could not open file for macro name listing: " + << macronames_file.string() << endl; + return false; + } + } + else { + macronames_out.copyfmt(cout); + macronames_out.clear(cout.rdstate()); + static_cast<std::basic_ios<char> &>(macronames_out).rdbuf(cout.rdbuf()); + } + + // simply list all defined macros and its definitions + typedef context_type::const_name_iterator name_iterator; + name_iterator end = ctx.macro_names_end(); + for (name_iterator it = ctx.macro_names_begin(); it != end; ++it) + { + typedef std::vector<context_type::token_type> parameters_type; + + bool has_pars = false; + bool predef = false; + context_type::position_type pos; + parameters_type pars; + context_type::token_sequence_type def; + + if (ctx.get_macro_definition(*it, has_pars, predef, pos, pars, def)) + { + macronames_out << (predef ? "-P" : "-D") << *it; + if (has_pars) { + // list the parameter names for function style macros + macronames_out << "("; + parameters_type::const_iterator pend = pars.end(); + for (parameters_type::const_iterator pit = pars.begin(); + pit != pend; /**/) + { + macronames_out << (*pit).get_value(); + if (++pit != pend) + macronames_out << ", "; + } + macronames_out << ")"; + } + macronames_out << "="; + + // print the macro definition + context_type::token_sequence_type::const_iterator dend = def.end(); + for (context_type::token_sequence_type::const_iterator dit = def.begin(); + dit != dend; ++dit) + { + macronames_out << (*dit).get_value(); + } + + macronames_out << std::endl; + } + } + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // list macro invocation counts + bool list_macro_counts(context_type const& ctx, std::string filename) + { + // open file for macro invocation count listing + ofstream macrocounts_out; + fs::path macrocounts_file (boost::wave::util::create_path(filename)); + + if (macrocounts_file != "-") { + macrocounts_file = boost::wave::util::complete_path(macrocounts_file); + boost::wave::util::create_directories( + boost::wave::util::branch_path(macrocounts_file)); + macrocounts_out.open(macrocounts_file.string().c_str()); + if (!macrocounts_out.is_open()) { + cerr << "wave: could not open file for macro invocation count listing: " + << macrocounts_file.string() << endl; + return false; + } + } + else { + macrocounts_out.copyfmt(cout); + macrocounts_out.clear(cout.rdstate()); + static_cast<std::basic_ios<char> &>(macrocounts_out).rdbuf(cout.rdbuf()); + } + + // list all expanded macro names and their counts in alphabetical order + std::map<std::string, std::size_t> const& counts = + ctx.get_hooks().get_macro_counts(); + + typedef std::map<std::string, std::size_t>::const_iterator iterator; + iterator end = counts.end(); + for (iterator it = counts.begin(); it != end; ++it) + macrocounts_out << (*it).first << "," << (*it).second << std::endl; + + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // read all of a file into a string + std::string read_entire_file(std::istream& instream) + { + std::string content; + + instream.unsetf(std::ios::skipws); + +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + // this is known to be very slow for large files on some systems + copy (std::istream_iterator<char>(instream), + std::istream_iterator<char>(), + std::inserter(content, content.end())); +#else + content = std::string(std::istreambuf_iterator<char>(instream.rdbuf()), + std::istreambuf_iterator<char>()); +#endif + return content; + } +} // anonymous namespace + +/////////////////////////////////////////////////////////////////////////////// +// do the actual preprocessing +int +do_actual_work (std::string file_name, std::istream &instream, + po::variables_map const &vm, bool input_is_stdin) +{ +// current file position is saved for exception handling +boost::wave::util::file_position_type current_position; +auto_stop_watch elapsed_time(cerr); +int error_count = 0; +const bool treat_warnings_as_error = vm.count("warning") && + boost::algorithm::any_of_equal( + vm["warning"].as<std::vector<std::string> >(), "error"); + + try { + // process the given file + std::string instring; + + instream.unsetf(std::ios::skipws); + if (!input_is_stdin) + instring = read_entire_file(instream); + + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the context_type::iterator_type stream. + ofstream output; + ofstream traceout; + ofstream includelistout; + ofstream listguardsout; + + trace_flags enable_trace = trace_nothing; + + if (vm.count("traceto")) { + // try to open the file, where to put the trace output + fs::path trace_file (boost::wave::util::create_path( + vm["traceto"].as<std::string>())); + + if (trace_file != "-") { + boost::wave::util::create_directories( + boost::wave::util::branch_path(trace_file)); + traceout.open(trace_file.string().c_str()); + if (!traceout.is_open()) { + cerr << "wave: could not open trace file: " << trace_file + << endl; + return -1; + } + } + enable_trace = trace_macros; + } + if ((enable_trace & trace_macros) && !traceout.is_open()) { + // by default trace to std::cerr + traceout.copyfmt(cerr); + traceout.clear(cerr.rdstate()); + static_cast<std::basic_ios<char> &>(traceout).rdbuf(cerr.rdbuf()); + } + + // Open the stream where to output the list of included file names + if (vm.count("listincludes")) { + // try to open the file, where to put the include list + fs::path includes_file(boost::wave::util::create_path( + vm["listincludes"].as<std::string>())); + + if (includes_file != "-") { + boost::wave::util::create_directories( + boost::wave::util::branch_path(includes_file)); + includelistout.open(includes_file.string().c_str()); + if (!includelistout.is_open()) { + cerr << "wave: could not open include list file: " + << includes_file.string() << endl; + return -1; + } + } + enable_trace = trace_flags(enable_trace | trace_includes); + } + if ((enable_trace & trace_includes) && !includelistout.is_open()) { + // by default list included names to std::cout + includelistout.copyfmt(cout); + includelistout.clear(cout.rdstate()); + static_cast<std::basic_ios<char> &>(includelistout). + rdbuf(cout.rdbuf()); + } + + // Open the stream where to output the list of included file names + if (vm.count("listguards")) { + // try to open the file, where to put the include list + fs::path listguards_file(boost::wave::util::create_path( + vm["listguards"].as<std::string>())); + + if (listguards_file != "-") { + boost::wave::util::create_directories( + boost::wave::util::branch_path(listguards_file)); + listguardsout.open(listguards_file.string().c_str()); + if (!listguardsout.is_open()) { + cerr << "wave: could not open include guard list file: " + << listguards_file.string() << endl; + return -1; + } + } + enable_trace = trace_flags(enable_trace | trace_guards); + } + if ((enable_trace & trace_guards) && !listguardsout.is_open()) { + // by default list included names to std::cout + listguardsout.copyfmt(cout); + listguardsout.clear(cout.rdstate()); + static_cast<std::basic_ios<char> &>(listguardsout). + rdbuf(cout.rdbuf()); + } + + // enable preserving comments mode + bool preserve_comments = false; + bool preserve_whitespace = false; + bool preserve_bol_whitespace = false; + + if (vm.count("preserve")) { + int preserve = vm["preserve"].as<int>(); + + switch(preserve) { + case 0: break; // preserve no whitespace + case 3: // preserve all whitespace + preserve_whitespace = true; + preserve_comments = true; + preserve_bol_whitespace = true; + break; + + case 2: // preserve comments and BOL whitespace only + preserve_comments = true; + preserve_bol_whitespace = true; + break; + + case 1: // preserve BOL whitespace only + preserve_bol_whitespace = true; + break; + + default: + cerr << "wave: bogus preserve whitespace option value: " + << preserve << ", should be 0, 1, 2, or 3" << endl; + return -1; + } + } + + // Since the #pragma wave system() directive may cause a potential security + // threat, it has to be enabled explicitly by --extended or -x + bool enable_system_command = false; + + if (vm.count("extended")) + enable_system_command = true; + + // This this the central piece of the Wave library, it provides you with + // the iterators to get the preprocessed tokens and allows to configure + // the preprocessing stage in advance. + bool allow_output = true; // will be manipulated from inside the hooks object + std::string default_outfile; // will be used from inside the hooks object + trace_macro_expansion<token_type> hooks(preserve_whitespace, + preserve_bol_whitespace, output, traceout, includelistout, + listguardsout, enable_trace, enable_system_command, allow_output, + default_outfile); + + // enable macro invocation count, if appropriate + if (vm.count("macrocounts")) + hooks.enable_macro_counting(); + + // check, if we have a license file to prepend + std::string license; + + if (vm.count ("license")) { + // try to open the file, where to put the preprocessed output + std::string license_file(vm["license"].as<std::string>()); + ifstream license_stream(license_file.c_str()); + + if (!license_stream.is_open()) { + cerr << "wave: could not open specified license file: " + << license_file << endl; + return -1; + } + license = read_entire_file(license_stream); + hooks.set_license_info(license); + } + + context_type ctx (instring.begin(), instring.end(), file_name.c_str(), hooks); + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + // enable C99 mode, if appropriate (implies variadics) + if (vm.count("c99")) { +#if BOOST_WAVE_SUPPORT_CPP0X != 0 + if (vm.count("c++11")) { + cerr << "wave: multiple language options specified: --c99 " + "and --c++11" << endl; + return -1; + } +#endif + ctx.set_language( + boost::wave::language_support( + boost::wave::support_c99 + | boost::wave::support_option_convert_trigraphs + | boost::wave::support_option_emit_line_directives +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + | boost::wave::support_option_include_guard_detection +#endif +#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 + | boost::wave::support_option_emit_pragma_directives +#endif + | boost::wave::support_option_insert_whitespace + )); + } + else if (vm.count("variadics")) { + // enable variadics and placemarkers, if appropriate + ctx.set_language(boost::wave::enable_variadics(ctx.get_language())); + } +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +#if BOOST_WAVE_SUPPORT_CPP0X != 0 + if (vm.count("c++11")) { + if (vm.count("c99")) { + cerr << "wave: multiple language options specified: --c99 " + "and --c++11" << endl; + return -1; + } + ctx.set_language( + boost::wave::language_support( + boost::wave::support_cpp0x + | boost::wave::support_option_convert_trigraphs + | boost::wave::support_option_long_long + | boost::wave::support_option_emit_line_directives +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + | boost::wave::support_option_include_guard_detection +#endif +#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 + | boost::wave::support_option_emit_pragma_directives +#endif + | boost::wave::support_option_insert_whitespace + )); + } +#endif // BOOST_WAVE_SUPPORT_CPP0X != 0 + + // enable long long support, if appropriate + if (vm.count("long_long")) { + ctx.set_language( + boost::wave::enable_long_long(ctx.get_language())); + } + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +// disable include guard detection + if (vm.count("noguard")) { + ctx.set_language( + boost::wave::enable_include_guard_detection( + ctx.get_language(), false)); + } +#endif + + // enable preserving comments mode + if (preserve_comments) { + ctx.set_language( + boost::wave::enable_preserve_comments(ctx.get_language())); + } + + // control the generation of #line directives + if (vm.count("line")) { + int lineopt = vm["line"].as<int>(); + if (0 != lineopt && 1 != lineopt && 2 != lineopt) { + cerr << "wave: bogus value for --line command line option: " + << lineopt << endl; + return -1; + } + ctx.set_language( + boost::wave::enable_emit_line_directives(ctx.get_language(), + lineopt != 0)); + + if (2 == lineopt) + ctx.get_hooks().enable_relative_names_in_line_directives(true); + } + + // control whether whitespace should be inserted to disambiguate output + if (vm.count("disambiguate")) { + int disambiguateopt = vm["disambiguate"].as<int>(); + if (0 != disambiguateopt && 1 != disambiguateopt) { + cerr << "wave: bogus value for --disambiguate command line option: " + << disambiguateopt << endl; + return -1; + } + ctx.set_language( + boost::wave::enable_insert_whitespace(ctx.get_language(), + disambiguateopt != 0)); + } + + // add include directories to the system include search paths + if (vm.count("sysinclude")) { + vector<std::string> syspaths = vm["sysinclude"].as<vector<std::string> >(); + + vector<std::string>::const_iterator end = syspaths.end(); + for (vector<std::string>::const_iterator cit = syspaths.begin(); + cit != end; ++cit) + { + ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*cit).c_str()); + } + } + + // add include directories to the include search paths + if (vm.count("include")) { + cmd_line_utils::include_paths const &ip = + vm["include"].as<cmd_line_utils::include_paths>(); + vector<std::string>::const_iterator end = ip.paths.end(); + + for (vector<std::string>::const_iterator cit = ip.paths.begin(); + cit != end; ++cit) + { + ctx.add_include_path(cmd_line_utils::trim_quotes(*cit).c_str()); + } + + // if -I- was given on the command line, this has to be propagated + if (ip.seen_separator) + ctx.set_sysinclude_delimiter(); + + // add system include directories to the include path + vector<std::string>::const_iterator sysend = ip.syspaths.end(); + for (vector<std::string>::const_iterator syscit = ip.syspaths.begin(); + syscit != sysend; ++syscit) + { + ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*syscit).c_str()); + } + } + + // add additional defined macros + if (vm.count("define")) { + vector<std::string> const ¯os = vm["define"].as<vector<std::string> >(); + vector<std::string>::const_iterator end = macros.end(); + for (vector<std::string>::const_iterator cit = macros.begin(); + cit != end; ++cit) + { + ctx.add_macro_definition(*cit); + } + } + + // add additional predefined macros + if (vm.count("predefine")) { + vector<std::string> const &predefmacros = + vm["predefine"].as<vector<std::string> >(); + vector<std::string>::const_iterator end = predefmacros.end(); + for (vector<std::string>::const_iterator cit = predefmacros.begin(); + cit != end; ++cit) + { + ctx.add_macro_definition(*cit, true); + } + } + + // undefine specified macros + if (vm.count("undefine")) { + vector<std::string> const &undefmacros = + vm["undefine"].as<vector<std::string> >(); + vector<std::string>::const_iterator end = undefmacros.end(); + for (vector<std::string>::const_iterator cit = undefmacros.begin(); + cit != end; ++cit) + { + ctx.remove_macro_definition(*cit, true); + } + } + +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0 + // suppress expansion of specified macros + if (vm.count("noexpand")) { + vector<std::string> const &noexpandmacros = + vm["noexpand"].as<vector<std::string> >(); + vector<std::string>::const_iterator end = noexpandmacros.end(); + for (vector<std::string>::const_iterator cit = noexpandmacros.begin(); + cit != end; ++cit) + { + ctx.get_hooks().add_noexpandmacro(*cit); + } + } +#endif + + // maximal include nesting depth + if (vm.count("nesting")) { + int max_depth = vm["nesting"].as<int>(); + if (max_depth < 1 || max_depth > 100000) { + cerr << "wave: bogus maximal include nesting depth: " + << max_depth << endl; + return -1; + } + ctx.set_max_include_nesting_depth(max_depth); + } + + // open the output file + if (vm.count("output")) { + // try to open the file, where to put the preprocessed output + fs::path out_file (boost::wave::util::create_path( + vm["output"].as<std::string>())); + + if (out_file == "-") { + allow_output = false; // inhibit output initially + default_outfile = "-"; + } + else { + out_file = boost::wave::util::complete_path(out_file); + boost::wave::util::create_directories( + boost::wave::util::branch_path(out_file)); + output.open(out_file.string().c_str()); + if (!output.is_open()) { + cerr << "wave: could not open output file: " + << out_file.string() << endl; + return -1; + } + if (!license.empty()) + output << license; + default_outfile = out_file.string(); + } + } + else if (!input_is_stdin && vm.count("autooutput")) { + // generate output in the file <input_base_name>.i + fs::path out_file (boost::wave::util::create_path(file_name)); + std::string basename (boost::wave::util::leaf(out_file)); + std::string::size_type pos = basename.find_last_of("."); + + if (std::string::npos != pos) + basename = basename.substr(0, pos); + out_file = boost::wave::util::branch_path(out_file) / (basename + ".i"); + + boost::wave::util::create_directories( + boost::wave::util::branch_path(out_file)); + output.open(out_file.string().c_str()); + if (!output.is_open()) { + cerr << "wave: could not open output file: " + << out_file.string() << endl; + return -1; + } + if (!license.empty()) + output << license; + default_outfile = out_file.string(); + } + + // we assume the session to be interactive if input is stdin and output is + // stdout and the output is not inhibited + bool is_interactive = input_is_stdin && !output.is_open() && allow_output; + + if (is_interactive) { + // if interactive we don't warn for missing endif's etc. + ctx.set_language( + boost::wave::enable_single_line(ctx.get_language()), false); + } + + // analyze the input file + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + // preprocess the required include files + if (vm.count("forceinclude")) { + // add the filenames to force as include files in _reverse_ order + // the second parameter 'is_last' of the force_include function should + // be set to true for the last (first given) file. + std::vector<std::string> const &force = + vm["forceinclude"].as<std::vector<std::string> >(); + std::vector<std::string>::const_reverse_iterator rend = force.rend(); + for (std::vector<std::string>::const_reverse_iterator cit = force.rbegin(); + cit != rend; /**/) + { + std::string filename(*cit); + first.force_include(filename.c_str(), ++cit == rend); + } + } + + elapsed_time.set_print_time(!input_is_stdin && vm.count("timer") > 0); + if (is_interactive) { + print_interactive_version(); // print welcome message + load_state(vm, ctx); // load the internal tables from disc + } + else if (vm.count("state")) { + // the option "state" is usable in interactive mode only + cerr << "wave: ignoring the command line option 'state', " + << "use it in interactive mode only." << endl; + } + + // >>>>>>>>>>>>> The actual preprocessing happens here. <<<<<<<<<<<<<<<<<<< + // loop over the input lines if reading from stdin, otherwise this loop + // will be executed once + do { + // loop over all generated tokens outputting the generated text + bool finished = false; + + if (input_is_stdin) { + if (is_interactive) + cout << ">>> "; // prompt if is interactive + + // read next line and continue + instring.clear(); + if (!read_a_line(instream, instring)) + break; // end of input reached + first = ctx.begin(instring.begin(), instring.end()); + } + + bool need_to_advanve = false; + + do { + try { + if (need_to_advanve) { + ++first; + need_to_advanve = false; + } + + while (first != last) { + // store the last known good token position + current_position = (*first).get_position(); + + // print out the current token value + if (allow_output) { + if (!output.good()) { + cerr << "wave: problem writing to the current " + << "output file" << endl; + cerr << report_iostate_error(output.rdstate()); + break; + } + if (output.is_open()) + output << (*first).get_value(); + else + cout << (*first).get_value(); + } + + // advance to the next token + ++first; + } + finished = true; + } + catch (boost::wave::cpp_exception const &e) { + // some preprocessing error + if (is_interactive || boost::wave::is_recoverable(e)) { + error_count += report_error_message(ctx, e, + treat_warnings_as_error); + need_to_advanve = true; // advance to the next token + } + else { + throw; // re-throw for non-recoverable errors + } + } + catch (boost::wave::cpplexer::lexing_exception const &e) { + // some preprocessing error + if (is_interactive || + boost::wave::cpplexer::is_recoverable(e)) + { + error_count += + report_error_message(e, treat_warnings_as_error); + need_to_advanve = true; // advance to the next token + } + else { + throw; // re-throw for non-recoverable errors + } + } + } while (!finished); + } while (input_is_stdin); + + if (is_interactive) + save_state(vm, ctx); // write the internal tables to disc + + // list all defined macros at the end of the preprocessing + if (vm.count("macronames")) { + if (!list_macro_names(ctx, vm["macronames"].as<std::string>())) + return -1; + } + if (vm.count("macrocounts")) { + if (!list_macro_counts(ctx, vm["macrocounts"].as<std::string>())) + return -1; + } + } + catch (boost::wave::cpp_exception const &e) { + // some preprocessing error + report_error_message(e, treat_warnings_as_error); + return 1; + } + catch (boost::wave::cpplexer::lexing_exception const &e) { + // some lexing error + report_error_message(e, treat_warnings_as_error); + return 2; + } + catch (std::exception const &e) { + // use last recognized token to retrieve the error position + cerr + << current_position << ": " + << "exception caught: " << e.what() + << endl; + return 3; + } + catch (...) { + // use last recognized token to retrieve the error position + cerr + << current_position << ": " + << "unexpected exception caught." << endl; + return 4; + } + return -error_count; // returns the number of errors as a negative integer +} + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int +main (int argc, char *argv[]) +{ + const std::string accepted_w_args[] = {"error"}; + + // test Wave compilation configuration + if (!BOOST_WAVE_TEST_CONFIGURATION()) { + cout << "wave: warning: the library this application was linked against was compiled " + << endl + << " using a different configuration (see wave_config.hpp)." + << endl; + } + + // analyze the command line options and arguments + try { + // declare the options allowed on the command line only + po::options_description desc_cmdline ("Options allowed on the command line only"); + + desc_cmdline.add_options() + ("help,h", "print out program usage (this message)") + ("version,v", "print the version number") + ("copyright", "print out the copyright statement") + ("config-file", po::value<vector<std::string> >()->composing(), + "specify a config file (alternatively: @filepath)") + ; + + const std::string w_arg_desc = "Warning settings. Currently supported: -W" + + boost::algorithm::join(accepted_w_args, ", -W"); + + // declare the options allowed on command line and in config files + po::options_description desc_generic ("Options allowed additionally in a config file"); + + desc_generic.add_options() + ("output,o", po::value<std::string>(), + "specify a file [arg] to use for output instead of stdout or " + "disable output [-]") + ("autooutput,E", + "output goes into a file named <input_basename>.i") + ("license", po::value<std::string>(), + "prepend the content of the specified file to each created file") + ("include,I", po::value<cmd_line_utils::include_paths>()->composing(), + "specify an additional include directory") + ("sysinclude,S", po::value<vector<std::string> >()->composing(), + "specify an additional system include directory") + ("forceinclude,F", po::value<std::vector<std::string> >()->composing(), + "force inclusion of the given file") + ("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") +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0 + ("noexpand,N", po::value<std::vector<std::string> >()->composing(), + "specify a macro name, which should not be expanded") +#endif + ("nesting,n", po::value<int>(), + "specify a new maximal include nesting depth") + ("warning,W", po::value<std::vector<std::string> >()->composing(), + w_arg_desc.c_str()) + ; + + po::options_description desc_ext ("Extended options (allowed everywhere)"); + + desc_ext.add_options() + ("traceto,t", po::value<std::string>(), + "output macro expansion tracing information to a file [arg] " + "or to stderr [-]") + ("timer", "output overall elapsed computing time to stderr") + ("long_long", "enable long long support in C++ mode") +#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_CPP0X != 0 + ("c++11", "enable C++11 mode (implies --variadics and --long_long)") +#endif + ("listincludes,l", po::value<std::string>(), + "list names of included files to a file [arg] or to stdout [-]") + ("macronames,m", po::value<std::string>(), + "list all defined macros to a file [arg] or to stdout [-]") + ("macrocounts,c", po::value<std::string>(), + "list macro invocation counts to a file [arg] or to stdout [-]") + ("preserve,p", po::value<int>()->default_value(0), + "preserve whitespace\n" + "0: no whitespace is preserved (default),\n" + "1: begin of line whitespace is preserved,\n" + "2: comments and begin of line whitespace is preserved,\n" + "3: all whitespace is preserved") + ("line,L", po::value<int>()->default_value(1), + "control the generation of #line directives\n" + "0: no #line directives are generated,\n" + "1: #line directives will be emitted (default),\n" + "2: #line directives will be emitted using relative\n" + " filenames") + ("disambiguate", po::value<int>()->default_value(1), + "control whitespace insertion to disambiguate\n" + "consecutive tokens\n" + "0: no additional whitespace is generated,\n" + "1: whitespace is used to disambiguate output (default)") + ("extended,x", "enable the #pragma wave system() directive") +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + ("noguard,G", "disable include guard detection") + ("listguards,g", po::value<std::string>(), + "list names of files flagged as 'include once' to a file [arg] " + "or to stdout [-]") +#endif +#if BOOST_WAVE_SERIALIZATION != 0 + ("state,s", po::value<std::string>(), + "load and save state information from/to the given file [arg] " + "or 'wave.state' [-] (interactive mode only)") +#endif + ; + + // combine the options for the different usage schemes + po::options_description desc_overall_cmdline; + po::options_description desc_overall_cfgfile; + + desc_overall_cmdline.add(desc_cmdline).add(desc_generic).add(desc_ext); + desc_overall_cfgfile.add(desc_generic).add(desc_ext); + + // parse command line and store results + using namespace boost::program_options::command_line_style; + + po::parsed_options opts(po::parse_command_line(argc, argv, + desc_overall_cmdline, unix_style, cmd_line_utils::at_option_parser)); + po::variables_map vm; + + po::store(opts, vm); + po::notify(vm); + +// // Try to find a wave.cfg in the same directory as the executable was +// // started from. If this exists, treat it as a wave config file +// fs::path filename(argv[0]); +// +// filename = filename.branch_path() / "wave.cfg"; +// cmd_line_utils::read_config_file_options(filename.string(), +// desc_overall_cfgfile, vm, true); + + // extract the arguments from the parsed command line + vector<po::option> arguments; + + std::remove_copy_if(opts.options.begin(), opts.options.end(), + back_inserter(arguments), cmd_line_utils::is_argument()); + + // try to find a config file somewhere up the filesystem hierarchy + // starting with the input file path. This allows to use a general wave.cfg + // file for all files in a certain project. + if (arguments.size() > 0 && arguments[0].value[0] != "-") { + // construct full path of input file + fs::path input_dir (boost::wave::util::complete_path( + boost::wave::util::create_path(arguments[0].value[0]))); + + // chop of file name + input_dir = boost::wave::util::branch_path( + boost::wave::util::normalize(input_dir)); + + // walk up the hierarchy, trying to find a file wave.cfg + while (!input_dir.empty()) { + fs::path filename = input_dir / "wave.cfg"; + if (cmd_line_utils::read_config_file_options(filename.string(), + desc_overall_cfgfile, vm, true)) + { + break; // break on the first cfg file found + } + input_dir = boost::wave::util::branch_path(input_dir); + } + } + + // if there is specified at least one config file, parse it and add the + // options to the main variables_map + if (vm.count("config-file")) { + vector<std::string> const &cfg_files = + vm["config-file"].as<vector<std::string> >(); + vector<std::string>::const_iterator end = cfg_files.end(); + for (vector<std::string>::const_iterator cit = cfg_files.begin(); + cit != end; ++cit) + { + // parse a single config file and store the results + cmd_line_utils::read_config_file_options(*cit, + desc_overall_cfgfile, vm); + } + } + + // validate warning settings + if (vm.count("warning")) + { + BOOST_FOREACH(const std::string& arg, + vm["warning"].as<std::vector<std::string> >()) + { + if (boost::range::find(accepted_w_args, arg) == + boost::end(accepted_w_args)) + { + cerr << "wave: Invalid warning setting: " << arg << endl; + return -1; + } + } + } + + // ... act as required + if (vm.count("help")) { + po::options_description desc_help ( + "Usage: wave [options] [@config-file(s)] [file]"); + + desc_help.add(desc_cmdline).add(desc_generic).add(desc_ext); + cout << desc_help << endl; + return 1; + } + + if (vm.count("version")) { + cout << get_version() << endl; + return 0; + } + + if (vm.count("copyright")) { + return print_copyright(); + } + + // if there is no input file given, then take input from stdin + if (0 == arguments.size() || 0 == arguments[0].value.size() || + arguments[0].value[0] == "-") + { + // preprocess the given input from stdin + return do_actual_work("<stdin>", std::cin, vm, true); + } + else { + if (arguments.size() > 1) { + // this driver understands to parse one input file only + cerr << "wave: more than one input file specified, " + << "ignoring all but the first!" << endl; + } + + std::string file_name(arguments[0].value[0]); + ifstream instream(file_name.c_str()); + + // preprocess the given input file + if (!instream.is_open()) { + cerr << "wave: could not open input file: " << file_name << endl; + return -1; + } + return do_actual_work(file_name, instream, vm, false); + } + } + catch (std::exception const &e) { + cout << "wave: exception caught: " << e.what() << endl; + return 6; + } + catch (...) { + cerr << "wave: unexpected exception caught." << endl; + return 7; + } +} + diff --git a/src/boost/libs/wave/tool/cpp.hpp b/src/boost/libs/wave/tool/cpp.hpp new file mode 100644 index 00000000..2c795d2b --- /dev/null +++ b/src/boost/libs/wave/tool/cpp.hpp @@ -0,0 +1,42 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2012 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) +=============================================================================*/ + +#if !defined(CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED) +#define CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// This file may be used as a precompiled header (if applicable) + +/////////////////////////////////////////////////////////////////////////////// +// include often used files from the stdlib +#include <iostream> +#include <string> +#include <vector> +#include <algorithm> +#include <iterator> + +/////////////////////////////////////////////////////////////////////////////// +// include boost config +#include <boost/config.hpp> // global configuration information + +/////////////////////////////////////////////////////////////////////////////// +// build version +#include "cpp_version.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// configure this app here (global configuration constants) +#include "cpp_config.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// include required boost libraries +#include <boost/assert.hpp> +#include <boost/pool/pool_alloc.hpp> + +#endif // !defined(CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED) diff --git a/src/boost/libs/wave/tool/cpp_config.hpp b/src/boost/libs/wave/tool/cpp_config.hpp new file mode 100644 index 00000000..e6e4f63e --- /dev/null +++ b/src/boost/libs/wave/tool/cpp_config.hpp @@ -0,0 +1,63 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Global application configuration of the Wave driver command + + http://www.boost.org/ + + Copyright (c) 2001-2012 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) +=============================================================================*/ + +#if !defined(CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) +#define CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS constants below helps to fine control the amount of +// the generated debug output +//#define BOOST_SPIRIT_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// debug rules, subrules and grammars only, for possible flags see +// spirit/include/classic_debug.hpp +#if defined(BOOST_SPIRIT_DEBUG) + +#define BOOST_SPIRIT_DEBUG_FLAGS ( \ + BOOST_SPIRIT_DEBUG_FLAGS_NODES | \ + BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES \ + ) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Debug flags for the Wave library, possible flags (defined in +// wave_config.hpp): +// +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +// #define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +// #define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +// #define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +// #define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +// #define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP ( 0 \ + /* insert the required flags from above */ \ + ) \ + /**/ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Include the configuration stuff for the Wave library itself +#include <boost/wave/wave_config.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// MSVC specific #pragma's +#if defined(BOOST_MSVC) +#pragma warning (disable: 4355) // 'this' used in base member initializer list +#pragma warning (disable: 4800) // forcing value to bool 'true' or 'false' +#pragma inline_depth(255) +#pragma inline_recursion(on) +#endif // defined(BOOST_MSVC) + +#endif // !defined(CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) diff --git a/src/boost/libs/wave/tool/cpp_version.hpp b/src/boost/libs/wave/tool/cpp_version.hpp new file mode 100644 index 00000000..43330c2c --- /dev/null +++ b/src/boost/libs/wave/tool/cpp_version.hpp @@ -0,0 +1,25 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2012 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) +=============================================================================*/ + +#if !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED) +#define CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED + +#include <boost/wave/wave_version.hpp> + +#define CPP_VERSION_MAJOR BOOST_WAVE_VERSION_MAJOR +#define CPP_VERSION_MINOR BOOST_WAVE_VERSION_MINOR +#define CPP_VERSION_SUBMINOR BOOST_WAVE_VERSION_SUBMINOR +#define CPP_VERSION_FULL BOOST_WAVE_VERSION + +#define CPP_VERSION_FULL_STR BOOST_PP_STRINGIZE(CPP_VERSION_FULL) + +#define CPP_VERSION_DATE 20120523L +#define CPP_VERSION_DATE_STR "20120523" + +#endif // !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED) diff --git a/src/boost/libs/wave/tool/stop_watch.hpp b/src/boost/libs/wave/tool/stop_watch.hpp new file mode 100644 index 00000000..e3285466 --- /dev/null +++ b/src/boost/libs/wave/tool/stop_watch.hpp @@ -0,0 +1,84 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2012 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) +=============================================================================*/ + +#if !defined(STOP_WATCH_HPP_HK040911_INCLUDED) +#define STOP_WATCH_HPP_HK040911_INCLUDED + +#include <boost/config.hpp> +#include <boost/timer.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// +class stop_watch : public boost::timer { + + typedef boost::timer base_t; + +public: + stop_watch() : is_suspended_since(0), suspended_overall(0) {} + + void suspend() + { + if (0 == is_suspended_since) { + // if not already suspended + is_suspended_since = this->base_t::elapsed(); + } + } + void resume() + { + if (0 != is_suspended_since) { + // if really suspended + suspended_overall += this->base_t::elapsed() - is_suspended_since; + is_suspended_since = 0; + } + } + double elapsed() const + { + if (0 == is_suspended_since) { + // currently running + return this->base_t::elapsed() - suspended_overall; + } + + // currently suspended + BOOST_ASSERT(is_suspended_since >= suspended_overall); + return is_suspended_since - suspended_overall; + } + + std::string format_elapsed_time() const + { + double current = elapsed(); + char time_buffer[sizeof("1234:56:78.90 abcd.")+1]; + + using namespace std; + if (current >= 3600) { + // show hours + sprintf (time_buffer, "%d:%02d:%02d.%03d hrs.", + (int)(current) / 3600, ((int)(current) % 3600) / 60, + ((int)(current) % 3600) % 60, + (int)(current * 1000) % 1000); + } + else if (current >= 60) { + // show minutes + sprintf (time_buffer, "%d:%02d.%03d min.", + (int)(current) / 60, (int)(current) % 60, + (int)(current * 1000) % 1000); + } + else { + // show seconds + sprintf(time_buffer, "%d.%03d sec.", (int)current, + (int)(current * 1000) % 1000); + } + return time_buffer; + } + +private: + double is_suspended_since; + double suspended_overall; +}; + +#endif // !defined(STOP_WATCH_HPP_HK040911_INCLUDED) diff --git a/src/boost/libs/wave/tool/trace_macro_expansion.hpp b/src/boost/libs/wave/tool/trace_macro_expansion.hpp new file mode 100644 index 00000000..99a3647e --- /dev/null +++ b/src/boost/libs/wave/tool/trace_macro_expansion.hpp @@ -0,0 +1,1494 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2012 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) +=============================================================================*/ + +#if !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED) +#define TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED + +#include <cstdio> +#include <cstdlib> +#include <ctime> + +#include <ostream> +#include <string> +#include <stack> +#include <set> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/convenience.hpp> + +#include <boost/wave/token_ids.hpp> +#include <boost/wave/util/macro_helpers.hpp> +#include <boost/wave/util/filesystem_compatibility.hpp> +#include <boost/wave/preprocessing_hooks.hpp> +#include <boost/wave/whitespace_handling.hpp> +#include <boost/wave/language_support.hpp> +#include <boost/wave/cpp_exceptions.hpp> + +#include "stop_watch.hpp" + +#ifdef BOOST_NO_STRINGSTREAM +#include <strstream> +#define BOOST_WAVE_OSSTREAM std::ostrstream +std::string BOOST_WAVE_GETSTRING(std::ostrstream& ss) +{ + ss << std::ends; + std::string rval = ss.str(); + ss.freeze(false); + return rval; +} +#else +#include <sstream> +#define BOOST_WAVE_GETSTRING(ss) ss.str() +#define BOOST_WAVE_OSSTREAM std::ostringstream +#endif + +// trace_flags: enable single tracing functionality +enum trace_flags { + trace_nothing = 0, // disable tracing + trace_macros = 1, // enable macro tracing + trace_macro_counts = 2, // enable invocation counting + trace_includes = 4, // enable include file tracing + trace_guards = 8 // enable include guard tracing +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Special error thrown whenever the #pragma wave system() directive is +// disabled +// +/////////////////////////////////////////////////////////////////////////////// +class bad_pragma_exception : + public boost::wave::preprocess_exception +{ +public: + enum error_code { + pragma_system_not_enabled = + boost::wave::preprocess_exception::last_error_number + 1, + pragma_mismatched_push_pop, + }; + + bad_pragma_exception(char const *what_, error_code code, std::size_t line_, + std::size_t column_, char const *filename_) throw() + : boost::wave::preprocess_exception(what_, + (boost::wave::preprocess_exception::error_code)code, line_, + column_, filename_) + { + } + ~bad_pragma_exception() throw() {} + + virtual char const *what() const throw() + { + return "boost::wave::bad_pragma_exception"; + } + virtual bool is_recoverable() const throw() + { + return true; + } + virtual int get_severity() const throw() + { + return boost::wave::util::severity_remark; + } + + static char const *error_text(int code) + { + switch(code) { + case pragma_system_not_enabled: + return "the directive '#pragma wave system()' was not enabled, use the " + "-x command line argument to enable the execution of"; + + case pragma_mismatched_push_pop: + return "unbalanced #pragma push/pop in input file(s) for option"; + } + return "Unknown exception"; + } + static boost::wave::util::severity severity_level(int code) + { + switch(code) { + case pragma_system_not_enabled: + return boost::wave::util::severity_remark; + + case pragma_mismatched_push_pop: + return boost::wave::util::severity_error; + } + return boost::wave::util::severity_fatal; + } + static char const *severity_text(int code) + { + return boost::wave::util::get_severity(boost::wave::util::severity_remark); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The trace_macro_expansion policy is used to trace the macro expansion of +// macros whenever it is requested from inside the input stream to preprocess +// through the '#pragma wave_option(trace: enable)' directive. The macro +// tracing is disabled with the help of a '#pragma wave_option(trace: disable)' +// directive. +// +// This policy type is used as a template parameter to the boost::wave::context<> +// object. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename TokenT> +class trace_macro_expansion +: public boost::wave::context_policies::eat_whitespace<TokenT> +{ + typedef boost::wave::context_policies::eat_whitespace<TokenT> base_type; + +public: + trace_macro_expansion( + bool preserve_whitespace_, bool preserve_bol_whitespace_, + std::ofstream &output_, std::ostream &tracestrm_, + std::ostream &includestrm_, std::ostream &guardstrm_, + trace_flags flags_, bool enable_system_command_, + bool& generate_output_, std::string const& default_outfile_) + : outputstrm(output_), tracestrm(tracestrm_), + includestrm(includestrm_), guardstrm(guardstrm_), + level(0), flags(flags_), logging_flags(trace_nothing), + enable_system_command(enable_system_command_), + preserve_whitespace(preserve_whitespace_), + preserve_bol_whitespace(preserve_bol_whitespace_), + generate_output(generate_output_), + default_outfile(default_outfile_), + emit_relative_filenames(false) + { + } + ~trace_macro_expansion() + { + } + + void enable_macro_counting() + { + logging_flags = trace_flags(logging_flags | trace_macro_counts); + } + std::map<std::string, std::size_t> const& get_macro_counts() const + { + return counts; + } + + void enable_relative_names_in_line_directives(bool flag) + { + emit_relative_filenames = flag; + } + bool enable_relative_names_in_line_directives() const + { + return emit_relative_filenames; + } + + // add a macro name, which should not be expanded at all (left untouched) + void add_noexpandmacro(std::string const& name) + { + noexpandmacros.insert(name); + } + + void set_license_info(std::string const& info) + { + license_info = info; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_function_like_macro' is called whenever a + // function-like macro is to be expanded. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'macrodef' marks the position, where the macro to expand + // is defined. + // + // The parameter 'formal_args' holds the formal arguments used during the + // definition of the macro. + // + // The parameter 'definition' holds the macro definition for the macro to + // trace. + // + // The parameter 'macro_call' marks the position, where this macro invoked. + // + // The parameter 'arguments' holds the macro arguments used during the + // invocation of the macro + // + // The parameters 'seqstart' and 'seqend' point into the input token + // stream allowing to access the whole token sequence comprising the macro + // invocation (starting with the opening parenthesis and ending after the + // closing one). + // + // The return value defines whether the corresponding macro will be + // expanded (return false) or will be copied to the output (return true). + // Note: the whole argument list is copied unchanged to the output as well + // without any further processing. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void expanding_function_like_macro( + TokenT const ¯odef, std::vector<TokenT> const &formal_args, + ContainerT const &definition, + TokenT const ¯ocall, std::vector<ContainerT> const &arguments) + { + if (enabled_macro_counting()) + count_invocation(macrodef.get_value().c_str()); + + if (!enabled_macro_tracing()) + return; +#else + // new signature + template <typename ContextT, typename ContainerT, typename IteratorT> + bool + expanding_function_like_macro(ContextT const& ctx, + TokenT const ¯odef, std::vector<TokenT> const &formal_args, + ContainerT const &definition, + TokenT const ¯ocall, std::vector<ContainerT> const &arguments, + IteratorT const& seqstart, IteratorT const& seqend) + { + if (enabled_macro_counting() || !noexpandmacros.empty()) { + std::string name (macrodef.get_value().c_str()); + + if (noexpandmacros.find(name.c_str()) != noexpandmacros.end()) + return true; // do not expand this macro + + if (enabled_macro_counting()) + count_invocation(name.c_str()); + } + + if (!enabled_macro_tracing()) + return false; +#endif + if (0 == get_level()) { + // output header line + BOOST_WAVE_OSSTREAM stream; + + stream + << macrocall.get_position() << ": " + << macrocall.get_value() << "("; + + // argument list + for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) { + stream << boost::wave::util::impl::as_string(arguments[i]); + if (i < arguments.size()-1) + stream << ", "; + } + stream << ")" << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + increment_level(); + } + + // output definition reference + { + BOOST_WAVE_OSSTREAM stream; + + stream + << macrodef.get_position() << ": see macro definition: " + << macrodef.get_value() << "("; + + // formal argument list + for (typename std::vector<TokenT>::size_type i = 0; + i < formal_args.size(); ++i) + { + stream << formal_args[i].get_value(); + if (i < formal_args.size()-1) + stream << ", "; + } + stream << ")" << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + } + + if (formal_args.size() > 0) { + // map formal and real arguments + open_trace_body("invoked with\n"); + for (typename std::vector<TokenT>::size_type j = 0; + j < formal_args.size(); ++j) + { + using namespace boost::wave; + + BOOST_WAVE_OSSTREAM stream; + stream << formal_args[j].get_value() << " = "; +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + if (T_ELLIPSIS == token_id(formal_args[j])) { + // ellipsis + for (typename ContainerT::size_type k = j; + k < arguments.size(); ++k) + { + stream << boost::wave::util::impl::as_string(arguments[k]); + if (k < arguments.size()-1) + stream << ", "; + } + } + else +#endif + { + stream << boost::wave::util::impl::as_string(arguments[j]); + } + stream << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + } + close_trace_body(); + } + open_trace_body(); + +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0 + return false; +#endif + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_object_like_macro' is called whenever a + // object-like macro is to be expanded . + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'macrodef' marks the position, where the macro to expand + // is defined. + // + // The definition 'definition' holds the macro definition for the macro to + // trace. + // + // The parameter 'macrocall' marks the position, where this macro invoked. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void expanding_object_like_macro(TokenT const ¯odef, + ContainerT const &definition, TokenT const ¯ocall) + { + if (enabled_macro_counting()) + count_invocation(macrodef.get_value().c_str()); + + if (!enabled_macro_tracing()) + return; +#else + // new signature + template <typename ContextT, typename ContainerT> + bool + expanding_object_like_macro(ContextT const& ctx, + TokenT const ¯odef, ContainerT const &definition, + TokenT const ¯ocall) + { + if (enabled_macro_counting() || !noexpandmacros.empty()) { + std::string name (macrodef.get_value().c_str()); + + if (noexpandmacros.find(name.c_str()) != noexpandmacros.end()) + return true; // do not expand this macro + + if (enabled_macro_counting()) + count_invocation(name.c_str()); + } + + if (!enabled_macro_tracing()) + return false; +#endif + if (0 == get_level()) { + // output header line + BOOST_WAVE_OSSTREAM stream; + + stream + << macrocall.get_position() << ": " + << macrocall.get_value() << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + increment_level(); + } + + // output definition reference + { + BOOST_WAVE_OSSTREAM stream; + + stream + << macrodef.get_position() << ": see macro definition: " + << macrodef.get_value() << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + } + open_trace_body(); + +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0 + return false; +#endif + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanded_macro' is called whenever the expansion of a + // macro is finished but before the rescanning process starts. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'result' contains the token sequence generated as the + // result of the macro expansion. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void expanded_macro(ContainerT const &result) +#else + // new signature + template <typename ContextT, typename ContainerT> + void expanded_macro(ContextT const& ctx,ContainerT const &result) +#endif + { + if (!enabled_macro_tracing()) return; + + BOOST_WAVE_OSSTREAM stream; + stream << boost::wave::util::impl::as_string(result) << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + + open_trace_body("rescanning\n"); + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'rescanned_macro' is called whenever the rescanning of a + // macro is finished. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'result' contains the token sequence generated as the + // result of the rescanning. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void rescanned_macro(ContainerT const &result) +#else + // new signature + template <typename ContextT, typename ContainerT> + void rescanned_macro(ContextT const& ctx,ContainerT const &result) +#endif + { + if (!enabled_macro_tracing() || get_level() == 0) + return; + + BOOST_WAVE_OSSTREAM stream; + stream << boost::wave::util::impl::as_string(result) << std::endl; + output(BOOST_WAVE_GETSTRING(stream)); + close_trace_body(); + close_trace_body(); + + if (1 == get_level()) + decrement_level(); + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'interpret_pragma' is called whenever a #pragma command + // directive is found which isn't known to the core Wave library, where + // command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant + // which defaults to "wave". + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used as the replacement text for the whole + // #pragma directive. + // + // The parameter 'option' contains the name of the interpreted pragma. + // + // The parameter 'values' holds the values of the parameter provided to + // the pragma operator. + // + // The parameter 'act_token' contains the actual #pragma token, which may + // be used for error output. + // + // If the return value is 'false', the whole #pragma directive is + // interpreted as unknown and a corresponding error message is issued. A + // return value of 'true' signs a successful interpretation of the given + // #pragma. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + interpret_pragma(ContextT &ctx, ContainerT &pending, + typename ContextT::token_type const &option, ContainerT const &valuetokens, + typename ContextT::token_type const &act_token) + { + typedef typename ContextT::token_type token_type; + + ContainerT values(valuetokens); + boost::wave::util::impl::trim_sequence(values); // trim whitespace + + if (option.get_value() == "timer") { + // #pragma wave timer(value) + if (0 == values.size()) { + // no value means '1' + using namespace boost::wave; + timer(token_type(T_INTLIT, "1", act_token.get_position())); + } + else { + timer(values.front()); + } + return true; + } + if (option.get_value() == "trace") { + // enable/disable tracing option + return interpret_pragma_trace(ctx, values, act_token); + } + if (option.get_value() == "system") { + if (!enable_system_command) { + // if the #pragma wave system() directive is not enabled, throw + // a corresponding error (actually its a remark), + typename ContextT::string_type msg( + boost::wave::util::impl::as_string(values)); + BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception, + pragma_system_not_enabled, + msg.c_str(), act_token.get_position()); + return false; + } + + // try to spawn the given argument as a system command and return the + // std::cout of this process as the replacement of this _Pragma + return interpret_pragma_system(ctx, pending, values, act_token); + } + if (option.get_value() == "stop") { + // stop the execution and output the argument + typename ContextT::string_type msg( + boost::wave::util::impl::as_string(values)); + BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception, + error_directive, msg.c_str(), act_token.get_position()); + return false; + } + if (option.get_value() == "option") { + // handle different options + return interpret_pragma_option(ctx, values, act_token); + } + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'emit_line_directive' is called whenever a #line directive + // has to be emitted into the generated output. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used instead of the default output generated + // for the #line directive. + // + // The parameter 'act_token' contains the actual #pragma token, which may + // be used for error output. The line number stored in this token can be + // used as the line number emitted as part of the #line directive. + // + // If the return value is 'false', a default #line directive is emitted + // by the library. A return value of 'true' will inhibit any further + // actions, the tokens contained in 'pending' will be copied verbatim + // to the output. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + emit_line_directive(ContextT const& ctx, ContainerT &pending, + typename ContextT::token_type const& act_token) + { + if (!need_emit_line_directives(ctx.get_language()) || + !enable_relative_names_in_line_directives()) + { + return false; + } + + // emit a #line directive showing the relative filename instead + typename ContextT::position_type pos = act_token.get_position(); + unsigned int column = 6; + + typedef typename ContextT::token_type result_type; + using namespace boost::wave; + + pos.set_column(1); + pending.push_back(result_type(T_PP_LINE, "#line", pos)); + + pos.set_column(column); // account for '#line' + pending.push_back(result_type(T_SPACE, " ", pos)); + + // 21 is the max required size for a 64 bit integer represented as a + // string + char buffer[22]; + + using namespace std; // for some systems sprintf is in namespace std + sprintf (buffer, "%zd", pos.get_line()); + + pos.set_column(++column); // account for ' ' + pending.push_back(result_type(T_INTLIT, buffer, pos)); + pos.set_column(column += (unsigned int)strlen(buffer)); // account for <number> + pending.push_back(result_type(T_SPACE, " ", pos)); + pos.set_column(++column); // account for ' ' + + std::string file("\""); + boost::filesystem::path filename( + boost::wave::util::create_path(ctx.get_current_relative_filename().c_str())); + + using boost::wave::util::impl::escape_lit; + file += escape_lit(boost::wave::util::native_file_string(filename)) + "\""; + + pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos)); + pos.set_column(column += (unsigned int)file.size()); // account for filename + pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos)); + + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'opened_include_file' is called whenever a file referred + // by an #include directive was successfully located and opened. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'filename' contains the file system path of the + // opened file (this is relative to the directory of the currently + // processed file or a absolute path depending on the paths given as the + // include search paths). + // + // The include_depth parameter contains the current include file depth. + // + // The is_system_include parameter denotes, whether the given file was + // found as a result of a #include <...> directive. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + void + opened_include_file(std::string const &relname, std::string const &absname, + std::size_t include_depth, bool is_system_include) + { +#else + // new signature + template <typename ContextT> + void + opened_include_file(ContextT const& ctx, std::string const &relname, + std::string const &absname, bool is_system_include) + { + std::size_t include_depth = ctx.get_iteration_depth(); +#endif + if (enabled_include_tracing()) { + // print indented filename + for (std::size_t i = 0; i < include_depth; ++i) + includestrm << " "; + + if (is_system_include) + includestrm << "<" << relname << "> (" << absname << ")"; + else + includestrm << "\"" << relname << "\" (" << absname << ")"; + + includestrm << std::endl; + } + } + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + /////////////////////////////////////////////////////////////////////////// + // + // The function 'detected_include_guard' is called whenever either a + // include file is about to be added to the list of #pragma once headers. + // That means this header file will not be opened and parsed again even + // if it is specified in a later #include directive. + // This function is called as the result of a detected include guard + // scheme. + // + // The implemented heuristics for include guards detects two forms of + // include guards: + // + // #ifndef INCLUDE_GUARD_MACRO + // #define INCLUDE_GUARD_MACRO + // ... + // #endif + // + // or + // + // if !defined(INCLUDE_GUARD_MACRO) + // #define INCLUDE_GUARD_MACRO + // ... + // #endif + // + // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO + // will work as well). The code allows for any whitespace, newline and single + // '#' tokens before the #if/#ifndef and after the final #endif. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'filename' contains the file system path of the + // opened file (this is relative to the directory of the currently + // processed file or a absolute path depending on the paths given as the + // include search paths). + // + // The parameter contains the name of the detected include guard. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT> + void + detected_include_guard(ContextT const& ctx, std::string const& filename, + std::string const& include_guard) + { + if (enabled_guard_tracing()) { + guardstrm << include_guard << ":" << std::endl + << " " << filename << std::endl; + } + } +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'may_skip_whitespace' will be called by the + // library whenever a token is about to be returned to the calling + // application. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The 'token' parameter holds a reference to the current token. The policy + // is free to change this token if needed. + // + // The 'skipped_newline' parameter holds a reference to a boolean value + // which should be set to true by the policy function whenever a newline + // is going to be skipped. + // + // If the return value is true, the given token is skipped and the + // preprocessing continues to the next token. If the return value is + // false, the given token is returned to the calling application. + // + // ATTENTION! + // Caution has to be used, because by returning true the policy function + // is able to force skipping even significant tokens, not only whitespace. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT> + bool may_skip_whitespace(ContextT const &ctx, TokenT &token, + bool &skipped_newline) + { + return this->base_type::may_skip_whitespace( + ctx, token, need_preserve_comments(ctx.get_language()), + preserve_bol_whitespace, skipped_newline) ? + !preserve_whitespace : false; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'throw_exception' will be called by the library whenever a + // preprocessing exception occurs. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'e' is the exception object containing detailed error + // information. + // + // The default behavior is to call the function boost::throw_exception. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT> + void + throw_exception(ContextT const& ctx, boost::wave::preprocess_exception const& e) + { +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + if (!is_import_directive_error(e)) + boost::throw_exception(e); +#else + boost::throw_exception(e); +#endif + } + using base_type::throw_exception; + +protected: +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + /////////////////////////////////////////////////////////////////////////// + // Avoid throwing an error from a #import directive + bool is_import_directive_error(boost::wave::preprocess_exception const& e) + { + using namespace boost::wave; + if (e.get_errorcode() != preprocess_exception::ill_formed_directive) + return false; + + // the error string is formatted as 'severity: error: directive' + std::string error(e.description()); + std::string::size_type p = error.find_last_of(":"); + return p != std::string::npos && error.substr(p+2) == "import"; + } +#endif + + /////////////////////////////////////////////////////////////////////////// + // Interpret the different Wave specific pragma directives/operators + template <typename ContextT, typename ContainerT> + bool + interpret_pragma_trace(ContextT& ctx, ContainerT const &values, + typename ContextT::token_type const &act_token) + { + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + + bool valid_option = false; + + if (1 == values.size()) { + token_type const &value = values.front(); + + if (value.get_value() == "enable" || + value.get_value() == "on" || + value.get_value() == "1") + { + // #pragma wave trace(enable) + enable_tracing(static_cast<trace_flags>( + tracing_enabled() | trace_macros)); + valid_option = true; + } + else if (value.get_value() == "disable" || + value.get_value() == "off" || + value.get_value() == "0") + { + // #pragma wave trace(disable) + enable_tracing(static_cast<trace_flags>( + tracing_enabled() & ~trace_macros)); + valid_option = true; + } + } + if (!valid_option) { + // unknown option value + string_type option_str ("trace"); + + if (values.size() > 0) { + option_str += "("; + option_str += boost::wave::util::impl::as_string(values); + option_str += ")"; + } + BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception, + ill_formed_pragma_option, option_str.c_str(), + act_token.get_position()); + return false; + } + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // interpret the pragma wave option(preserve: [0|1|2|3|push|pop]) directive + template <typename ContextT> + static bool + interpret_pragma_option_preserve_set(int mode, bool &preserve_whitespace, + bool& preserve_bol_whitespace, ContextT &ctx) + { + switch(mode) { + // preserve no whitespace + case 0: + preserve_whitespace = false; + preserve_bol_whitespace = false; + ctx.set_language( + enable_preserve_comments(ctx.get_language(), false), + false); + break; + + // preserve BOL whitespace only + case 1: + preserve_whitespace = false; + preserve_bol_whitespace = true; + ctx.set_language( + enable_preserve_comments(ctx.get_language(), false), + false); + break; + + // preserve comments and BOL whitespace only + case 2: + preserve_whitespace = false; + preserve_bol_whitespace = true; + ctx.set_language( + enable_preserve_comments(ctx.get_language()), + false); + break; + + // preserve all whitespace + case 3: + preserve_whitespace = true; + preserve_bol_whitespace = true; + ctx.set_language( + enable_preserve_comments(ctx.get_language()), + false); + break; + + default: + return false; + } + return true; + } + + template <typename ContextT, typename IteratorT> + bool + interpret_pragma_option_preserve(ContextT &ctx, IteratorT &it, + IteratorT end, typename ContextT::token_type const &act_token) + { + using namespace boost::wave; + + token_id id = util::impl::skip_whitespace(it, end); + if (T_COLON == id) + id = util::impl::skip_whitespace(it, end); + + // implement push/pop + if (T_IDENTIFIER == id) { + if ((*it).get_value() == "push") { + // push current preserve option onto the internal option stack + if (need_preserve_comments(ctx.get_language())) { + if (preserve_whitespace) + preserve_options.push(3); + else + preserve_options.push(2); + } + else if (preserve_bol_whitespace) { + preserve_options.push(1); + } + else { + preserve_options.push(0); + } + return true; + } + else if ((*it).get_value() == "pop") { + // test for mismatched push/pop #pragmas + if (preserve_options.empty()) { + BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception, + pragma_mismatched_push_pop, "preserve", + act_token.get_position()); + } + + // pop output preserve from the internal option stack + bool result = interpret_pragma_option_preserve_set( + preserve_options.top(), preserve_whitespace, + preserve_bol_whitespace, ctx); + preserve_options.pop(); + return result; + } + return false; + } + + if (T_PP_NUMBER != id) + return false; + + using namespace std; // some platforms have atoi in namespace std + return interpret_pragma_option_preserve_set( + atoi((*it).get_value().c_str()), preserve_whitespace, + preserve_bol_whitespace, ctx); + } + + // interpret the pragma wave option(line: [0|1|2|push|pop]) directive + template <typename ContextT, typename IteratorT> + bool + interpret_pragma_option_line(ContextT &ctx, IteratorT &it, + IteratorT end, typename ContextT::token_type const &act_token) + { + using namespace boost::wave; + + token_id id = util::impl::skip_whitespace(it, end); + if (T_COLON == id) + id = util::impl::skip_whitespace(it, end); + + // implement push/pop + if (T_IDENTIFIER == id) { + if ((*it).get_value() == "push") { + // push current line option onto the internal option stack + int mode = 0; + if (need_emit_line_directives(ctx.get_language())) { + mode = 1; + if (enable_relative_names_in_line_directives()) + mode = 2; + } + line_options.push(mode); + return true; + } + else if ((*it).get_value() == "pop") { + // test for mismatched push/pop #pragmas + if (line_options.empty()) { + BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception, + pragma_mismatched_push_pop, "line", + act_token.get_position()); + } + + // pop output line from the internal option stack + ctx.set_language( + enable_emit_line_directives(ctx.get_language(), 0 != line_options.top()), + false); + enable_relative_names_in_line_directives(2 == line_options.top()); + line_options.pop(); + return true; + } + return false; + } + + if (T_PP_NUMBER != id) + return false; + + using namespace std; // some platforms have atoi in namespace std + int emit_lines = atoi((*it).get_value().c_str()); + if (0 == emit_lines || 1 == emit_lines || 2 == emit_lines) { + // set the new emit #line directive mode + ctx.set_language( + enable_emit_line_directives(ctx.get_language(), emit_lines), + false); + return true; + } + return false; + } + + // interpret the pragma wave option(output: ["filename"|null|default|push|pop]) + // directive + template <typename ContextT> + bool + interpret_pragma_option_output_open(boost::filesystem::path &fpath, + ContextT& ctx, typename ContextT::token_type const &act_token) + { + namespace fs = boost::filesystem; + + // ensure all directories for this file do exist + boost::wave::util::create_directories( + boost::wave::util::branch_path(fpath)); + + // figure out, whether the file has been written to by us, if yes, we + // append any output to this file, otherwise we overwrite it + std::ios::openmode mode = std::ios::out; + if (fs::exists(fpath) && written_by_us.find(fpath) != written_by_us.end()) + mode = (std::ios::openmode)(std::ios::out | std::ios::app); + + written_by_us.insert(fpath); + + // close the current file + if (outputstrm.is_open()) + outputstrm.close(); + + // open the new file + outputstrm.open(fpath.string().c_str(), mode); + if (!outputstrm.is_open()) { + BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception, + could_not_open_output_file, + fpath.string().c_str(), act_token.get_position()); + return false; + } + + // write license text, if file was created and if requested + if (mode == std::ios::out && !license_info.empty()) + outputstrm << license_info; + + generate_output = true; + current_outfile = fpath; + return true; + } + + bool interpret_pragma_option_output_close(bool generate) + { + if (outputstrm.is_open()) + outputstrm.close(); + current_outfile = boost::filesystem::path(); + generate_output = generate; + return true; + } + + template <typename ContextT, typename IteratorT> + bool + interpret_pragma_option_output(ContextT &ctx, IteratorT &it, + IteratorT end, typename ContextT::token_type const &act_token) + { + using namespace boost::wave; + namespace fs = boost::filesystem; + + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + + token_id id = util::impl::skip_whitespace(it, end); + if (T_COLON == id) + id = util::impl::skip_whitespace(it, end); + + bool result = false; + if (T_STRINGLIT == id) { + namespace fs = boost::filesystem; + + string_type fname ((*it).get_value()); + fs::path fpath (boost::wave::util::create_path( + util::impl::unescape_lit(fname.substr(1, fname.size()-2)).c_str())); + fpath = boost::wave::util::complete_path(fpath, ctx.get_current_directory()); + result = interpret_pragma_option_output_open(fpath, ctx, act_token); + } + else if (T_IDENTIFIER == id) { + if ((*it).get_value() == "null") { + // suppress all output from this point on + result = interpret_pragma_option_output_close(false); + } + else if ((*it).get_value() == "push") { + // initialize the current_outfile, if appropriate + if (output_options.empty() && current_outfile.empty() && + !default_outfile.empty() && default_outfile != "-") + { + current_outfile = boost::wave::util::complete_path( + default_outfile, ctx.get_current_directory()); + } + + // push current output option onto the internal option stack + output_options.push( + output_option_type(generate_output, current_outfile)); + result = true; + } + else if ((*it).get_value() == "pop") { + // test for mismatched push/pop #pragmas + if (output_options.empty()) { + BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception, + pragma_mismatched_push_pop, "output", + act_token.get_position()); + return false; + } + + // pop output option from the internal option stack + output_option_type const& opts = output_options.top(); + generate_output = opts.first; + current_outfile = opts.second; + if (!current_outfile.empty()) { + // re-open the last file + result = interpret_pragma_option_output_open(current_outfile, + ctx, act_token); + } + else { + // either no output or generate to std::cout + result = interpret_pragma_option_output_close(generate_output); + } + output_options.pop(); + } + } + else if (T_DEFAULT == id) { + // re-open the default output given on command line + if (!default_outfile.empty()) { + if (default_outfile == "-") { + // the output was suppressed on the command line + result = interpret_pragma_option_output_close(false); + } + else { + // there was a file name on the command line + fs::path fpath(boost::wave::util::create_path(default_outfile)); + result = interpret_pragma_option_output_open(fpath, ctx, + act_token); + } + } + else { + // generate the output to std::cout + result = interpret_pragma_option_output_close(true); + } + } + return result; + } + + /////////////////////////////////////////////////////////////////////////// + // join all adjacent string tokens into the first one + template <typename StringT> + StringT unlit(StringT const& str) + { + return str.substr(1, str.size()-2); + } + + template <typename StringT> + StringT merge_string_lits(StringT const& lhs, StringT const& rhs) + { + StringT result ("\""); + + result += unlit(lhs); + result += unlit(rhs); + result += "\""; + return result; + } + + template <typename ContextT, typename ContainerT> + void join_adjacent_string_tokens(ContextT &ctx, ContainerT const& values, + ContainerT& joined_values) + { + using namespace boost::wave; + + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + typedef typename ContainerT::const_iterator const_iterator; + typedef typename ContainerT::iterator iterator; + + token_type* current = 0; + + const_iterator end = values.end(); + for (const_iterator it = values.begin(); it != end; ++it) { + token_id id(*it); + + if (id == T_STRINGLIT) { + if (!current) { + joined_values.push_back(*it); + current = &joined_values.back(); + } + else { + current->set_value(merge_string_lits( + current->get_value(), (*it).get_value())); + } + } + else if (current) { + typedef util::impl::next_token<const_iterator> next_token_type; + token_id next_id (next_token_type::peek(it, end, true)); + + if (next_id != T_STRINGLIT) { + current = 0; + joined_values.push_back(*it); + } + } + else { + joined_values.push_back(*it); + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // interpret the pragma wave option() directives + template <typename ContextT, typename ContainerT> + bool + interpret_pragma_option(ContextT &ctx, ContainerT const &cvalues, + typename ContextT::token_type const &act_token) + { + using namespace boost::wave; + + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + typedef typename ContainerT::const_iterator const_iterator; + + ContainerT values; + join_adjacent_string_tokens(ctx, cvalues, values); + + const_iterator end = values.end(); + for (const_iterator it = values.begin(); it != end; /**/) { + bool valid_option = false; + + token_type const &value = *it; + if (value.get_value() == "preserve") { + // #pragma wave option(preserve: [0|1|2|3|push|pop]) + valid_option = interpret_pragma_option_preserve(ctx, it, end, + act_token); + } + else if (value.get_value() == "line") { + // #pragma wave option(line: [0|1|2|push|pop]) + valid_option = interpret_pragma_option_line(ctx, it, end, + act_token); + } + else if (value.get_value() == "output") { + // #pragma wave option(output: ["filename"|null|default|push|pop]) + valid_option = interpret_pragma_option_output(ctx, it, end, + act_token); + } + + if (!valid_option) { + // unknown option value + string_type option_str ("option"); + + if (values.size() > 0) { + option_str += "("; + option_str += util::impl::as_string(values); + option_str += ")"; + } + BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception, + ill_formed_pragma_option, + option_str.c_str(), act_token.get_position()); + return false; + } + + token_id id = util::impl::skip_whitespace(it, end); + if (id == T_COMMA) + util::impl::skip_whitespace(it, end); + } + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // interpret the #pragma wave system() directive + template <typename ContextT, typename ContainerT> + bool + interpret_pragma_system(ContextT& ctx, ContainerT &pending, + ContainerT const &values, + typename ContextT::token_type const &act_token) + { + typedef typename ContextT::token_type token_type; + typedef typename token_type::string_type string_type; + + if (0 == values.size()) return false; // ill_formed_pragma_option + + string_type stdout_file(std::tmpnam(0)); + string_type stderr_file(std::tmpnam(0)); + string_type system_str(boost::wave::util::impl::as_string(values)); + string_type native_cmd(system_str); + + system_str += " >" + stdout_file + " 2>" + stderr_file; + if (0 != std::system(system_str.c_str())) { + // unable to spawn the command + string_type error_str("unable to spawn command: "); + + error_str += native_cmd; + BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception, + ill_formed_pragma_option, + error_str.c_str(), act_token.get_position()); + return false; + } + + // rescan the content of the stdout_file and insert it as the + // _Pragma replacement + typedef typename ContextT::lexer_type lexer_type; + typedef typename ContextT::input_policy_type input_policy_type; + typedef boost::wave::iteration_context< + ContextT, lexer_type, input_policy_type> + iteration_context_type; + + iteration_context_type iter_ctx(ctx, stdout_file.c_str(), + act_token.get_position(), ctx.get_language()); + ContainerT pragma; + + for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first) + pragma.push_back(*iter_ctx.first); + + // prepend the newly generated token sequence to the 'pending' container + pending.splice(pending.begin(), pragma); + + // erase the created tempfiles + std::remove(stdout_file.c_str()); + std::remove(stderr_file.c_str()); + return true; + } + + /////////////////////////////////////////////////////////////////////////// + // The function enable_tracing is called, whenever the status of the + // tracing was changed. + // The parameter 'enable' is to be used as the new tracing status. + void enable_tracing(trace_flags flags) + { logging_flags = flags; } + + // The function tracing_enabled should return the current tracing status. + trace_flags tracing_enabled() + { return logging_flags; } + + // Helper functions for generating the trace output + void open_trace_body(char const *label = 0) + { + if (label) + output(label); + output("[\n"); + increment_level(); + } + void close_trace_body() + { + if (get_level() > 0) { + decrement_level(); + output("]\n"); + tracestrm << std::flush; // flush the stream buffer + } + } + + template <typename StringT> + void output(StringT const &outstr) const + { + indent(get_level()); + tracestrm << outstr; // output the given string + } + + void indent(int level) const + { + for (int i = 0; i < level; ++i) + tracestrm << " "; // indent + } + + int increment_level() { return ++level; } + int decrement_level() { BOOST_ASSERT(level > 0); return --level; } + int get_level() const { return level; } + + bool enabled_macro_tracing() const + { + return (flags & trace_macros) && (logging_flags & trace_macros); + } + bool enabled_include_tracing() const + { + return (flags & trace_includes); + } + bool enabled_guard_tracing() const + { + return (flags & trace_guards); + } + bool enabled_macro_counting() const + { + return logging_flags & trace_macro_counts; + } + + void count_invocation(std::string const& name) + { + typedef std::map<std::string, std::size_t>::iterator iterator; + typedef std::map<std::string, std::size_t>::value_type value_type; + + iterator it = counts.find(name); + if (it == counts.end()) + { + std::pair<iterator, bool> p = counts.insert(value_type(name, 0)); + if (p.second) + it = p.first; + } + + if (it != counts.end()) + ++(*it).second; + } + + void timer(TokenT const &value) + { + if (value.get_value() == "0" || value.get_value() == "restart") { + // restart the timer + elapsed_time.restart(); + } + else if (value.get_value() == "1") { + // print out the current elapsed time + std::cerr + << value.get_position() << ": " + << elapsed_time.format_elapsed_time() + << std::endl; + } + else if (value.get_value() == "suspend") { + // suspend the timer + elapsed_time.suspend(); + } + else if (value.get_value() == "resume") { + // resume the timer + elapsed_time.resume(); + } + } + +private: + std::ofstream &outputstrm; // main output stream + std::ostream &tracestrm; // trace output stream + std::ostream &includestrm; // included list output stream + std::ostream &guardstrm; // include guard output stream + int level; // indentation level + trace_flags flags; // enabled globally + trace_flags logging_flags; // enabled by a #pragma + bool enable_system_command; // enable #pragma wave system() command + bool preserve_whitespace; // enable whitespace preservation + bool preserve_bol_whitespace; // enable begin of line whitespace preservation + bool& generate_output; // allow generated tokens to be streamed to output + std::string const& default_outfile; // name of the output file given on command line + boost::filesystem::path current_outfile; // name of the current output file + + stop_watch elapsed_time; // trace timings + std::set<boost::filesystem::path> written_by_us; // all files we have written to + + typedef std::pair<bool, boost::filesystem::path> output_option_type; + std::stack<output_option_type> output_options; // output option stack + std::stack<int> line_options; // line option stack + std::stack<int> preserve_options; // preserve option stack + + std::map<std::string, std::size_t> counts; // macro invocation counts + bool emit_relative_filenames; // emit relative names in #line directives + + std::set<std::string> noexpandmacros; // list of macros not to expand + + std::string license_info; // text to pre-pend to all generated output files +}; + +#undef BOOST_WAVE_GETSTRING +#undef BOOST_WAVE_OSSTREAM + +#endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED) |