123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /*=============================================================================
- 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 <boost/assert.hpp>
- #include <boost/program_options.hpp>
- ///////////////////////////////////////////////////////////////////////////////
- // Include Wave itself
- #include <boost/wave.hpp>
- ///////////////////////////////////////////////////////////////////////////////
- // Include the lexer stuff
- #include <boost/wave/cpplexer/cpp_lex_token.hpp> // 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<string> 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<string>::const_iterator lastfile = arguments.end();
- for (vector<string>::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<char>(instream.rdbuf()),
- istreambuf_iterator<char>());
-
- // 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<string> const &paths =
- vm["include"].as<vector<string> >();
- vector<string>::const_iterator end = paths.end();
- for (vector<string>::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<string> const &syspaths =
- vm["sysinclude"].as<vector<string> >();
- vector<string>::const_iterator end = syspaths.end();
- for (vector<string>::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<string> 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<vector<string> >(),
- "specify additional include directory")
- ("sysinclude,S", po::value<vector<string> >(),
- "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<po::option> 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;
- }
- }
|