• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Boost.Wave: A Standard compliant C++ preprocessor library
3 
4     http://www.boost.org/
5 
6     Copyright (c) 2001-2010 Hartmut Kaiser. Distributed under the Boost
7     Software License, Version 1.0. (See accompanying file
8     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 
11 #include "token_statistics.hpp"                     // config data
12 
13 ///////////////////////////////////////////////////////////////////////////////
14 //  include required boost libraries
15 #include <boost/assert.hpp>
16 #include <boost/program_options.hpp>
17 
18 ///////////////////////////////////////////////////////////////////////////////
19 //  Include Wave itself
20 #include <boost/wave.hpp>
21 
22 ///////////////////////////////////////////////////////////////////////////////
23 // Include the lexer stuff
24 #include <boost/wave/cpplexer/cpp_lex_token.hpp>    // token class
25 #include "xlex_iterator.hpp"                        // lexer class
26 
27 #include "collect_token_statistics.hpp"
28 
29 #include <iostream>
30 
31 ///////////////////////////////////////////////////////////////////////////////
32 //  import required names
33 using namespace boost::spirit::classic;
34 
35 using std::string;
36 using std::vector;
37 using std::cout;
38 using std::cerr;
39 using std::endl;
40 using std::ifstream;
41 using std::ostream;
42 using std::istreambuf_iterator;
43 
44 namespace po = boost::program_options;
45 
46 ///////////////////////////////////////////////////////////////////////////////
47 namespace cmd_line_util {
48 
49     // predicate to extract all positional arguments from the command line
50     struct is_argument {
51 
operator ()cmd_line_util::is_argument52         bool operator()(po::option const &opt)
53         {
54             return (opt.position_key == -1) ? true : false;
55         }
56     };
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 }
60 
61 ///////////////////////////////////////////////////////////////////////////////
62 // print the current version
63 
print_version()64 int print_version()
65 {
66 // get time of last compilation of this file
67 boost::wave::util::time_conversion_helper compilation_time(__DATE__ " " __TIME__);
68 
69 // calculate the number of days since May 9 2005
70 // (the day the token_statistics project was started)
71 std::tm first_day;
72 
73     std::memset (&first_day, 0, sizeof(std::tm));
74     first_day.tm_mon = 4;           // May
75     first_day.tm_mday = 9;          // 09
76     first_day.tm_year = 105;        // 2005
77 
78 long seconds = long(std::difftime(compilation_time.get_time(),
79     std::mktime(&first_day)));
80 
81     cout
82         << TOKEN_STATISTICS_VERSION_MAJOR << '.'
83         << TOKEN_STATISTICS_VERSION_MINOR << '.'
84         << TOKEN_STATISTICS_VERSION_SUBMINOR << '.'
85         << seconds/(3600*24);       // get number of days from seconds
86     return 1;                       // exit app
87 }
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 //
91 int
do_actual_work(vector<string> const & arguments,po::variables_map const & vm)92 do_actual_work(vector<string> const &arguments, po::variables_map const &vm)
93 {
94 // current file position is saved for exception handling
95 boost::wave::util::file_position_type current_position;
96 
97     try {
98     // this object keeps track of all the statistics
99         collect_token_statistics stats;
100 
101     // collect the token statistics for all arguments given
102         vector<string>::const_iterator lastfile = arguments.end();
103         for (vector<string>::const_iterator file_it = arguments.begin();
104              file_it != lastfile; ++file_it)
105         {
106         ifstream instream((*file_it).c_str());
107         string instring;
108 
109             if (!instream.is_open()) {
110                 cerr << "token_statistics: could not open input file: "
111                      << *file_it << endl;
112                 continue;
113             }
114             instream.unsetf(std::ios::skipws);
115             instring = string(istreambuf_iterator<char>(instream.rdbuf()),
116                               istreambuf_iterator<char>());
117 
118         //  The template boost::wave::cpplexer::lex_token<> is the token type to be
119         //  used by the Wave library.
120             typedef boost::wave::cpplexer::xlex::xlex_iterator<
121                     boost::wave::cpplexer::lex_token<> >
122                 lexer_type;
123             typedef boost::wave::context<
124                     std::string::iterator, lexer_type
125                 > context_type;
126 
127         // The preprocessor iterator shouldn't be constructed directly. It is
128         // to be generated through a wave::context<> object. This wave:context<>
129         // object is additionally to be used to initialize and define different
130         // parameters of the actual preprocessing.
131         // The preprocessing of the input stream is done on the fly behind the
132         // scenes during iteration over the context_type::iterator_type stream.
133         context_type ctx (instring.begin(), instring.end(), (*file_it).c_str());
134 
135         // add include directories to the include path
136             if (vm.count("include")) {
137                 vector<string> const &paths =
138                     vm["include"].as<vector<string> >();
139                 vector<string>::const_iterator end = paths.end();
140                 for (vector<string>::const_iterator cit = paths.begin();
141                      cit != end; ++cit)
142                 {
143                     ctx.add_include_path((*cit).c_str());
144                 }
145             }
146 
147         // add system include directories to the include path
148             if (vm.count("sysinclude")) {
149                 vector<string> const &syspaths =
150                     vm["sysinclude"].as<vector<string> >();
151                 vector<string>::const_iterator end = syspaths.end();
152                 for (vector<string>::const_iterator cit = syspaths.begin();
153                      cit != end; ++cit)
154                 {
155                     ctx.add_sysinclude_path((*cit).c_str());
156                 }
157             }
158 
159         // analyze the actual file
160         context_type::iterator_type first = ctx.begin();
161         context_type::iterator_type last = ctx.end();
162 
163             while (first != last) {
164                 current_position = (*first).get_position();
165                 stats(*first);
166                 ++first;
167             }
168         }
169 
170     // print out the collected statistics
171         stats.print();
172     }
173     catch (boost::wave::cpp_exception const& e) {
174     // some preprocessing error
175         cerr
176             << e.file_name() << "(" << e.line_no() << "): "
177             << e.description() << endl;
178         return 2;
179     }
180     catch (std::exception const& e) {
181     // use last recognized token to retrieve the error position
182         cerr
183             << current_position.get_file()
184             << "(" << current_position.get_line() << "): "
185             << "exception caught: " << e.what()
186             << endl;
187         return 3;
188     }
189     catch (...) {
190     // use last recognized token to retrieve the error position
191         cerr
192             << current_position.get_file()
193             << "(" << current_position.get_line() << "): "
194             << "unexpected exception caught." << endl;
195         return 4;
196     }
197     return 0;
198 }
199 
200 ///////////////////////////////////////////////////////////////////////////////
201 //  here we go!
202 int
main(int argc,char * argv[])203 main (int argc, char *argv[])
204 {
205     try {
206     // analyze the command line options and arguments
207     vector<string> syspathes;
208     po::options_description desc("Usage: token_statistics [options] file ...");
209 
210         desc.add_options()
211             ("help,h", "print out program usage (this message)")
212             ("version,v", "print the version number")
213             ("include,I", po::value<vector<string> >(),
214                 "specify additional include directory")
215             ("sysinclude,S", po::value<vector<string> >(),
216                 "specify additional system include directory")
217         ;
218 
219         using namespace boost::program_options::command_line_style;
220 
221     po::parsed_options opts = po::parse_command_line(argc, argv, desc, unix_style);
222     po::variables_map vm;
223 
224         po::store(opts, vm);
225         po::notify(vm);
226 
227         if (vm.count("help")) {
228             cout << desc << endl;
229             return 1;
230         }
231 
232         if (vm.count("version")) {
233             return print_version();
234         }
235 
236     // extract the arguments from the parsed command line
237     vector<po::option> arguments;
238 
239         std::remove_copy_if(opts.options.begin(), opts.options.end(),
240             inserter(arguments, arguments.end()), cmd_line_util::is_argument());
241 
242     // if there is no input file given, then exit
243         if (0 == arguments.size() || 0 == arguments[0].value.size()) {
244             cerr << "token_statistics: No input file given. "
245                  << "Use --help to get a hint." << endl;
246             return 5;
247         }
248 
249     // iterate over all given input files
250         return do_actual_work(arguments[0].value , vm);
251     }
252     catch (std::exception const& e) {
253         cout << "token_statistics: exception caught: " << e.what() << endl;
254         return 6;
255     }
256     catch (...) {
257         cerr << "token_statistics: unexpected exception caught." << endl;
258         return 7;
259     }
260 }
261 
262