/*============================================================================= Boost.Wave: A Standard compliant C++ preprocessor library 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) =============================================================================*/ #include "token_statistics.hpp" // config data /////////////////////////////////////////////////////////////////////////////// // include required boost libraries #include #include /////////////////////////////////////////////////////////////////////////////// // Include Wave itself #include /////////////////////////////////////////////////////////////////////////////// // Include the lexer stuff #include // token class #include "xlex_iterator.hpp" // lexer class #include "collect_token_statistics.hpp" /////////////////////////////////////////////////////////////////////////////// // import required names using namespace boost::spirit::classic; using std::string; using std::vector; using std::cout; using std::cerr; using std::endl; using std::ifstream; using std::ostream; using std::istreambuf_iterator; namespace po = boost::program_options; /////////////////////////////////////////////////////////////////////////////// namespace cmd_line_util { // 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; } }; /////////////////////////////////////////////////////////////////////////////// } /////////////////////////////////////////////////////////////////////////////// // print the current version int print_version() { // get time of last compilation of this file boost::wave::util::time_conversion_helper compilation_time(__DATE__ " " __TIME__); // calculate the number of days since May 9 2005 // (the day the token_statistics project was started) std::tm first_day; std::memset (&first_day, 0, sizeof(std::tm)); first_day.tm_mon = 4; // May first_day.tm_mday = 9; // 09 first_day.tm_year = 105; // 2005 long seconds = long(std::difftime(compilation_time.get_time(), std::mktime(&first_day))); cout << TOKEN_STATISTICS_VERSION_MAJOR << '.' << TOKEN_STATISTICS_VERSION_MINOR << '.' << TOKEN_STATISTICS_VERSION_SUBMINOR << '.' << seconds/(3600*24); // get number of days from seconds return 1; // exit app } /////////////////////////////////////////////////////////////////////////////// // int do_actual_work(vector const &arguments, po::variables_map const &vm) { // current file position is saved for exception handling boost::wave::util::file_position_type current_position; try { // this object keeps track of all the statistics collect_token_statistics stats; // collect the token statistics for all arguments given vector::const_iterator lastfile = arguments.end(); for (vector::const_iterator file_it = arguments.begin(); file_it != lastfile; ++file_it) { ifstream instream((*file_it).c_str()); string instring; if (!instream.is_open()) { cerr << "token_statistics: could not open input file: " << *file_it << endl; continue; } instream.unsetf(std::ios::skipws); instring = string(istreambuf_iterator(instream.rdbuf()), istreambuf_iterator()); // The template boost::wave::cpplexer::lex_token<> is the token type to be // used by the Wave library. typedef boost::wave::cpplexer::xlex::xlex_iterator< boost::wave::cpplexer::lex_token<> > lexer_type; typedef boost::wave::context< std::string::iterator, lexer_type > context_type; // The preprocessor iterator shouldn't be constructed directly. It is // to be generated through a wave::context<> object. This wave:context<> // object is additionally to be used to initialize and define different // parameters of the actual preprocessing. // The preprocessing of the input stream is done on the fly behind the // scenes during iteration over the context_type::iterator_type stream. context_type ctx (instring.begin(), instring.end(), (*file_it).c_str()); // add include directories to the include path if (vm.count("include")) { vector const &paths = vm["include"].as >(); vector::const_iterator end = paths.end(); for (vector::const_iterator cit = paths.begin(); cit != end; ++cit) { ctx.add_include_path((*cit).c_str()); } } // add system include directories to the include path if (vm.count("sysinclude")) { vector const &syspaths = vm["sysinclude"].as >(); vector::const_iterator end = syspaths.end(); for (vector::const_iterator cit = syspaths.begin(); cit != end; ++cit) { ctx.add_sysinclude_path((*cit).c_str()); } } // analyze the actual file context_type::iterator_type first = ctx.begin(); context_type::iterator_type last = ctx.end(); while (first != last) { current_position = (*first).get_position(); stats(*first); ++first; } } // print out the collected statistics stats.print(); } catch (boost::wave::cpp_exception const& e) { // some preprocessing error cerr << e.file_name() << "(" << e.line_no() << "): " << e.description() << endl; return 2; } catch (std::exception const& e) { // use last recognized token to retrieve the error position cerr << current_position.get_file() << "(" << current_position.get_line() << "): " << "exception caught: " << e.what() << endl; return 3; } catch (...) { // use last recognized token to retrieve the error position cerr << current_position.get_file() << "(" << current_position.get_line() << "): " << "unexpected exception caught." << endl; return 4; } return 0; } /////////////////////////////////////////////////////////////////////////////// // here we go! int main (int argc, char *argv[]) { try { // analyze the command line options and arguments vector syspathes; po::options_description desc("Usage: token_statistics [options] file ..."); desc.add_options() ("help,h", "print out program usage (this message)") ("version,v", "print the version number") ("include,I", po::value >(), "specify additional include directory") ("sysinclude,S", po::value >(), "specify additional system include directory") ; using namespace boost::program_options::command_line_style; po::parsed_options opts = po::parse_command_line(argc, argv, desc, unix_style); po::variables_map vm; po::store(opts, vm); po::notify(vm); if (vm.count("help")) { cout << desc << endl; return 1; } if (vm.count("version")) { return print_version(); } // extract the arguments from the parsed command line vector arguments; std::remove_copy_if(opts.options.begin(), opts.options.end(), inserter(arguments, arguments.end()), cmd_line_util::is_argument()); // if there is no input file given, then exit if (0 == arguments.size() || 0 == arguments[0].value.size()) { cerr << "token_statistics: No input file given. " << "Use --help to get a hint." << endl; return 5; } // iterate over all given input files return do_actual_work(arguments[0].value , vm); } catch (std::exception const& e) { cout << "token_statistics: exception caught: " << e.what() << endl; return 6; } catch (...) { cerr << "token_statistics: unexpected exception caught." << endl; return 7; } }