]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/wave/samples/list_includes/list_includes.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / wave / samples / list_includes / list_includes.cpp
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3
4 Sample: List include dependencies of a given source file
5
6 The 'list_includes' sample shows a simple way, how to use the Wave C++
7 preprocessor library to extract a list of included files from a given
8 source file.
9 To get a hint which commandline options are supported, call it with the
10 --help option.
11
12 http://www.boost.org/
13
14 Copyright (c) 2001-2010 Hartmut Kaiser. Distributed under the Boost
15 Software License, Version 1.0. (See accompanying file
16 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
17 =============================================================================*/
18
19 #include "list_includes.hpp" // config data
20
21 ///////////////////////////////////////////////////////////////////////////////
22 // include required boost libraries
23 #include <boost/assert.hpp>
24 #include <boost/program_options.hpp>
25
26 ///////////////////////////////////////////////////////////////////////////////
27 // Include Wave itself
28 #include <boost/wave.hpp>
29
30 ///////////////////////////////////////////////////////////////////////////////
31 // Include the lexer stuff
32 #include <boost/wave/cpplexer/cpp_lex_token.hpp> // standard token type
33 #include "lexertl_iterator.hpp" // lexertl based lexer
34
35 ///////////////////////////////////////////////////////////////////////////////
36 // Include the default context trace policies
37 #include <boost/wave/preprocessing_hooks.hpp>
38
39 ///////////////////////////////////////////////////////////////////////////////
40 // include lexer specifics, import lexer names
41 #if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0
42 #include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp>
43 #endif
44
45 ///////////////////////////////////////////////////////////////////////////////
46 // import required names
47 using namespace boost::spirit::classic;
48
49 using std::string;
50 using std::vector;
51 using std::set;
52 using std::cout;
53 using std::cerr;
54 using std::endl;
55 using std::ifstream;
56 using std::ostream;
57 using std::istreambuf_iterator;
58
59 namespace po = boost::program_options;
60
61 ///////////////////////////////////////////////////////////////////////////////
62 namespace cmd_line_util {
63
64 // predicate to extract all positional arguments from the command line
65 struct is_argument {
66 bool operator()(po::option const &opt)
67 {
68 return (opt.position_key == -1) ? true : false;
69 }
70 };
71
72 ///////////////////////////////////////////////////////////////////////////////
73 }
74
75 ///////////////////////////////////////////////////////////////////////////////
76 // print the current version
77
78 int print_version()
79 {
80 // get time of last compilation of this file
81 boost::wave::util::time_conversion_helper compilation_time(__DATE__ " " __TIME__);
82
83 // calculate the number of days since Jan 29 2003
84 // (the day the list_includes project was started)
85 std::tm first_day;
86
87 std::memset (&first_day, 0, sizeof(std::tm));
88 first_day.tm_mon = 0; // Jan
89 first_day.tm_mday = 29; // 29
90 first_day.tm_year = 103; // 2003
91
92 long seconds = long(std::difftime(compilation_time.get_time(),
93 std::mktime(&first_day)));
94
95 cout
96 << LIST_INCLUDES_VERSION_MAJOR << '.'
97 << LIST_INCLUDES_VERSION_MINOR << '.'
98 << LIST_INCLUDES_VERSION_SUBMINOR << '.'
99 << seconds/(3600*24); // get number of days from seconds
100 return 1; // exit app
101 }
102
103 ///////////////////////////////////////////////////////////////////////////////
104 // policy class
105 struct trace_include_files
106 : public boost::wave::context_policies::default_preprocessing_hooks
107 {
108 trace_include_files(set<string> &files_)
109 : files(files_), include_depth(0)
110 {}
111
112 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
113 void
114 opened_include_file(string const &relname, string const &filename,
115 std::size_t /*include_depth*/, bool is_system_include)
116 #else
117 template <typename ContextT>
118 void
119 opened_include_file(ContextT const& ctx, std::string const& relname,
120 std::string const& filename, bool is_system_include)
121 #endif
122 {
123 set<string>::iterator it = files.find(filename);
124 if (it == files.end()) {
125 // print indented filename
126 for (std::size_t i = 0; i < include_depth; ++i)
127 cout << " ";
128 cout << filename << endl;
129
130 files.insert(filename);
131 }
132 ++include_depth;
133 }
134
135 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
136 void returning_from_include_file()
137 #else
138 template <typename ContextT>
139 void returning_from_include_file(ContextT const& ctx)
140 #endif
141 {
142 --include_depth;
143 }
144
145 set<string> &files;
146 std::size_t include_depth;
147 };
148
149 ///////////////////////////////////////////////////////////////////////////////
150 //
151 int
152 do_actual_work(vector<string> const &arguments, po::variables_map const &vm)
153 {
154 // current file position is saved for exception handling
155 boost::wave::util::file_position_type current_position;
156
157 try {
158 // list the included files for all arguments given
159 vector<string>::const_iterator lastfile = arguments.end();
160 for (vector<string>::const_iterator file_it = arguments.begin();
161 file_it != lastfile; ++file_it)
162 {
163 ifstream instream((*file_it).c_str());
164 string instring;
165
166 if (!instream.is_open()) {
167 cerr << "Could not open input file: " << *file_it << endl;
168 continue;
169 }
170 instream.unsetf(std::ios::skipws);
171 instring = string(istreambuf_iterator<char>(instream.rdbuf()),
172 istreambuf_iterator<char>());
173
174 // The template boost::wave::cpplexer::lex_token<> is the token type to be
175 // used by the Wave library.
176 typedef boost::wave::cpplexer::lexertl::lex_iterator<
177 boost::wave::cpplexer::lex_token<> >
178 lex_iterator_type;
179 typedef boost::wave::context<
180 std::string::iterator, lex_iterator_type,
181 boost::wave::iteration_context_policies::load_file_to_string,
182 trace_include_files
183 > context_type;
184
185 set<string> files;
186 trace_include_files trace(files);
187
188 // The preprocessor iterator shouldn't be constructed directly. It is
189 // to be generated through a wave::context<> object. This wave:context<>
190 // object is additionally to be used to initialize and define different
191 // parameters of the actual preprocessing.
192 // The preprocessing of the input stream is done on the fly behind the
193 // scenes during iteration over the context_type::iterator_type stream.
194 context_type ctx (instring.begin(), instring.end(), (*file_it).c_str(), trace);
195
196 // add include directories to the include path
197 if (vm.count("include")) {
198 vector<string> const &paths =
199 vm["include"].as<vector<string> >();
200 vector<string>::const_iterator end = paths.end();
201 for (vector<string>::const_iterator cit = paths.begin();
202 cit != end; ++cit)
203 {
204 ctx.add_include_path((*cit).c_str());
205 }
206 }
207
208 // add system include directories to the include path
209 if (vm.count("sysinclude")) {
210 vector<string> const &syspaths =
211 vm["sysinclude"].as<vector<string> >();
212 vector<string>::const_iterator end = syspaths.end();
213 for (vector<string>::const_iterator cit = syspaths.begin();
214 cit != end; ++cit)
215 {
216 ctx.add_sysinclude_path((*cit).c_str());
217 }
218 }
219
220 // analyze the actual file
221 context_type::iterator_type first = ctx.begin();
222 context_type::iterator_type last = ctx.end();
223
224 cout << "Printing dependency information for: "
225 << *file_it << endl;
226
227 while (first != last) {
228 current_position = (*first).get_position();
229 ++first;
230 }
231
232 // prepend endl before next file
233 cout << endl;
234 }
235 }
236 catch (boost::wave::cpp_exception &e) {
237 // some preprocessing error
238 cerr
239 << e.file_name() << "(" << e.line_no() << "): "
240 << e.description() << endl;
241 return 2;
242 }
243 catch (std::exception &e) {
244 // use last recognized token to retrieve the error position
245 cerr
246 << current_position.get_file()
247 << "(" << current_position.get_line() << "): "
248 << "exception caught: " << e.what()
249 << endl;
250 return 3;
251 }
252 catch (...) {
253 // use last recognized token to retrieve the error position
254 cerr
255 << current_position.get_file()
256 << "(" << current_position.get_line() << "): "
257 << "unexpected exception caught." << endl;
258 return 4;
259 }
260 return 0;
261 }
262
263 ///////////////////////////////////////////////////////////////////////////////
264 // here we go!
265 int
266 main (int argc, char *argv[])
267 {
268 try {
269 // analyze the command line options and arguments
270 vector<string> syspathes;
271 po::options_description desc("Usage: list_includes [options] file ...");
272
273 desc.add_options()
274 ("help,h", "print out program usage (this message)")
275 ("version,v", "print the version number")
276 ("include,I", po::value<vector<string> >(),
277 "specify additional include directory")
278 ("sysinclude,S", po::value<vector<string> >(),
279 "specify additional system include directory")
280 ;
281
282 using namespace boost::program_options::command_line_style;
283
284 po::parsed_options opts = po::parse_command_line(argc, argv, desc, unix_style);
285 po::variables_map vm;
286
287 po::store(opts, vm);
288 po::notify(vm);
289
290 if (vm.count("help")) {
291 cout << desc << endl;
292 return 1;
293 }
294
295 if (vm.count("version")) {
296 return print_version();
297 }
298
299 // extract the arguments from the parsed command line
300 vector<po::option> arguments;
301
302 std::remove_copy_if(opts.options.begin(), opts.options.end(),
303 inserter(arguments, arguments.end()), cmd_line_util::is_argument());
304
305 // if there is no input file given, then exit
306 if (0 == arguments.size() || 0 == arguments[0].value.size()) {
307 cerr << "list_includes: No input file given. "
308 << "Use --help to get a hint." << endl;
309 return 5;
310 }
311
312 // iterate over all given input files
313 return do_actual_work(arguments[0].value , vm);
314 }
315 catch (std::exception &e) {
316 cout << "list_includes: exception caught: " << e.what() << endl;
317 return 6;
318 }
319 catch (...) {
320 cerr << "list_includes: unexpected exception caught." << endl;
321 return 7;
322 }
323 }
324