1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
/*=============================================================================
Boost.Wave: A Standard compliant C++ preprocessor library
http://www.boost.org/
Copyright (c) 2001-2008 Hartmut Kaiser. Distributed under the Boost
Software License, Version 1.0. (See accompanying file
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#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;
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;
}
}
|