]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Boost.Wave: A Standard compliant C++ preprocessor library | |
3 | ||
4 | http://www.boost.org/ | |
5 | ||
6 | Copyright (c) 2001-2012 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 | #if !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) | |
12 | #define CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED | |
13 | ||
14 | #include <string> | |
15 | #include <list> | |
16 | #include <utility> | |
17 | ||
18 | #include <boost/wave/wave_config.hpp> | |
19 | #include <boost/wave/util/filesystem_compatibility.hpp> | |
20 | ||
21 | #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
22 | #include <boost/multi_index_container.hpp> | |
23 | #include <boost/multi_index/member.hpp> | |
24 | #include <boost/multi_index/ordered_index.hpp> | |
25 | #endif | |
26 | ||
27 | #if BOOST_WAVE_SERIALIZATION != 0 | |
28 | #include <boost/serialization/serialization.hpp> | |
29 | #include <boost/serialization/utility.hpp> | |
30 | #include <boost/serialization/collections_save_imp.hpp> | |
31 | #include <boost/serialization/collections_load_imp.hpp> | |
32 | #include <boost/serialization/split_free.hpp> | |
33 | #endif | |
34 | ||
35 | #include <boost/filesystem/path.hpp> | |
36 | #include <boost/filesystem/operations.hpp> | |
37 | ||
38 | // this must occur after all of the includes and before any code appears | |
39 | #ifdef BOOST_HAS_ABI_HEADERS | |
40 | #include BOOST_ABI_PREFIX | |
41 | #endif | |
42 | ||
43 | /////////////////////////////////////////////////////////////////////////////// | |
44 | namespace boost { namespace wave { namespace util { | |
45 | ||
46 | #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
47 | /////////////////////////////////////////////////////////////////////////////// | |
48 | // Tags for accessing both sides of a bidirectional map | |
49 | struct from {}; | |
50 | struct to {}; | |
51 | ||
52 | /////////////////////////////////////////////////////////////////////////////// | |
53 | // The class template bidirectional_map wraps the specification | |
54 | // of a bidirectional map based on multi_index_container. | |
55 | template<typename FromType, typename ToType> | |
56 | struct bidirectional_map | |
57 | { | |
58 | typedef std::pair<FromType, ToType> value_type; | |
59 | ||
60 | #if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) || \ | |
61 | (defined(BOOST_MSVC) && \ | |
62 | ( (BOOST_MSVC < 1300) || (BOOST_MSVC == 1600) )) || \ | |
63 | (defined(BOOST_INTEL_CXX_VERSION) && \ | |
64 | (defined(_MSC_VER) && (BOOST_INTEL_CXX_VERSION <= 700))) | |
65 | ||
66 | BOOST_STATIC_CONSTANT(unsigned, from_offset = offsetof(value_type, first)); | |
67 | BOOST_STATIC_CONSTANT(unsigned, to_offset = offsetof(value_type, second)); | |
68 | ||
69 | typedef boost::multi_index::multi_index_container< | |
70 | value_type, | |
71 | boost::multi_index::indexed_by< | |
72 | boost::multi_index::ordered_unique< | |
73 | boost::multi_index::tag<from>, | |
74 | boost::multi_index::member_offset<value_type, FromType, from_offset> | |
75 | >, | |
76 | boost::multi_index::ordered_non_unique< | |
77 | boost::multi_index::tag<to>, | |
78 | boost::multi_index::member_offset<value_type, ToType, to_offset> | |
79 | > | |
80 | > | |
81 | > type; | |
82 | ||
83 | #else | |
84 | ||
85 | typedef boost::multi_index::multi_index_container< | |
86 | value_type, | |
87 | boost::multi_index::indexed_by< | |
88 | boost::multi_index::ordered_unique< | |
89 | boost::multi_index::tag<from>, | |
90 | boost::multi_index::member<value_type, FromType, &value_type::first> | |
91 | >, | |
92 | boost::multi_index::ordered_non_unique< | |
93 | boost::multi_index::tag<to>, | |
94 | boost::multi_index::member<value_type, ToType, &value_type::second> | |
95 | > | |
96 | > | |
97 | > type; | |
98 | ||
99 | #endif | |
100 | }; | |
101 | #endif // BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
102 | ||
103 | #if BOOST_WAVE_SERIALIZATION != 0 | |
104 | struct load_filepos | |
105 | { | |
106 | static unsigned int get_line() { return 0; } | |
107 | static unsigned int get_column() { return 0; } | |
108 | static std::string get_file() { return "<loading-state>"; } | |
109 | }; | |
110 | #endif | |
111 | ||
112 | /////////////////////////////////////////////////////////////////////////////// | |
113 | // | |
114 | // include_paths - controlling the include path search order | |
115 | // | |
116 | // General notes: | |
117 | // | |
118 | // Any directories specified with the 'add_include_path()' function before | |
119 | // the function 'set_sys_include_delimiter()' is called are searched only | |
120 | // for the case of '#include "file"' directives, they are not searched for | |
121 | // '#include <file>' directives. If additional directories are specified | |
122 | // with the 'add_include_path()' function after a call to the function | |
123 | // 'set_sys_include_delimiter()', these directories are searched for all | |
124 | // '#include' directives. | |
125 | // | |
126 | // In addition, a call to the function 'set_sys_include_delimiter()' | |
127 | // inhibits the use of the current directory as the first search directory | |
128 | // for '#include "file"' directives. Therefore, the current directory is | |
129 | // searched only if it is requested explicitly with a call to the function | |
130 | // 'add_include_path(".")'. | |
131 | // | |
132 | // Calling both functions, the 'set_sys_include_delimiter()' and | |
133 | // 'add_include_path(".")' allows you to control precisely which | |
134 | // directories are searched before the current one and which are searched | |
135 | // after. | |
136 | // | |
137 | /////////////////////////////////////////////////////////////////////////////// | |
138 | class include_paths | |
139 | { | |
140 | private: | |
141 | typedef std::list<std::pair<boost::filesystem::path, std::string> > | |
142 | include_list_type; | |
143 | typedef include_list_type::value_type include_value_type; | |
144 | ||
145 | #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
146 | typedef bidirectional_map<std::string, std::string>::type | |
147 | pragma_once_set_type; | |
148 | #endif | |
149 | ||
150 | public: | |
151 | include_paths() | |
152 | : was_sys_include_path(false), | |
153 | current_dir(initial_path()), | |
154 | current_rel_dir(initial_path()) | |
155 | {} | |
156 | ||
157 | bool add_include_path(char const *path_, bool is_system = false) | |
158 | { | |
159 | return add_include_path(path_, (is_system || was_sys_include_path) ? | |
160 | system_include_paths : user_include_paths); | |
161 | } | |
162 | void set_sys_include_delimiter() { was_sys_include_path = true; } | |
163 | bool find_include_file (std::string &s, std::string &dir, bool is_system, | |
164 | char const *current_file) const; | |
165 | void set_current_directory(char const *path_); | |
166 | boost::filesystem::path get_current_directory() const | |
167 | { return current_dir; } | |
168 | ||
169 | protected: | |
170 | bool find_include_file (std::string &s, std::string &dir, | |
171 | include_list_type const &pathes, char const *) const; | |
172 | bool add_include_path(char const *path_, include_list_type &pathes_); | |
173 | ||
174 | private: | |
175 | include_list_type user_include_paths; | |
176 | include_list_type system_include_paths; | |
177 | bool was_sys_include_path; // saw a set_sys_include_delimiter() | |
178 | boost::filesystem::path current_dir; | |
179 | boost::filesystem::path current_rel_dir; | |
180 | ||
181 | #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
182 | public: | |
183 | bool has_pragma_once(std::string const &filename) | |
184 | { | |
185 | using boost::multi_index::get; | |
186 | return get<from>(pragma_once_files).find(filename) != pragma_once_files.end(); | |
187 | } | |
188 | bool add_pragma_once_header(std::string const &filename, | |
189 | std::string const& guard_name) | |
190 | { | |
191 | typedef pragma_once_set_type::value_type value_type; | |
192 | return pragma_once_files.insert(value_type(filename, guard_name)).second; | |
193 | } | |
194 | bool remove_pragma_once_header(std::string const& guard_name) | |
195 | { | |
196 | typedef pragma_once_set_type::index_iterator<to>::type to_iterator; | |
197 | typedef std::pair<to_iterator, to_iterator> range_type; | |
198 | ||
199 | range_type r = pragma_once_files.get<to>().equal_range(guard_name); | |
200 | if (r.first != r.second) { | |
201 | using boost::multi_index::get; | |
202 | get<to>(pragma_once_files).erase(r.first, r.second); | |
203 | return true; | |
204 | } | |
205 | return false; | |
206 | } | |
207 | ||
208 | private: | |
209 | pragma_once_set_type pragma_once_files; | |
210 | #endif | |
211 | ||
212 | #if BOOST_WAVE_SERIALIZATION != 0 | |
213 | public: | |
214 | BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); | |
215 | BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); | |
216 | ||
217 | private: | |
218 | friend class boost::serialization::access; | |
219 | template<typename Archive> | |
220 | void save(Archive & ar, const unsigned int version) const | |
221 | { | |
222 | using namespace boost::serialization; | |
223 | #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
224 | ar & make_nvp("pragma_once_files", pragma_once_files); | |
225 | #endif | |
226 | ar & make_nvp("user_include_paths", user_include_paths); | |
227 | ar & make_nvp("system_include_paths", system_include_paths); | |
228 | ar & make_nvp("was_sys_include_path", was_sys_include_path); | |
229 | } | |
230 | template<typename Archive> | |
231 | void load(Archive & ar, const unsigned int loaded_version) | |
232 | { | |
233 | using namespace boost::serialization; | |
234 | if (version != (loaded_version & ~version_mask)) { | |
235 | BOOST_WAVE_THROW(preprocess_exception, incompatible_config, | |
236 | "cpp_include_path state version", load_filepos()); | |
237 | return; | |
238 | } | |
239 | ||
240 | #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
241 | ar & make_nvp("pragma_once_files", pragma_once_files); | |
242 | #endif | |
243 | // verify that the old include paths match the current ones | |
244 | include_list_type user_paths, system_paths; | |
245 | ar & make_nvp("user_include_paths", user_paths); | |
246 | ar & make_nvp("system_include_paths", system_paths); | |
247 | ||
248 | if (user_paths != user_include_paths) | |
249 | { | |
250 | BOOST_WAVE_THROW(preprocess_exception, incompatible_config, | |
251 | "user include paths", load_filepos()); | |
252 | return; | |
253 | } | |
254 | if (system_paths != system_include_paths) | |
255 | { | |
256 | BOOST_WAVE_THROW(preprocess_exception, incompatible_config, | |
257 | "system include paths", load_filepos()); | |
258 | return; | |
259 | } | |
260 | ||
261 | ar & make_nvp("was_sys_include_path", was_sys_include_path); | |
262 | } | |
263 | BOOST_SERIALIZATION_SPLIT_MEMBER() | |
264 | #endif | |
265 | }; | |
266 | ||
267 | /////////////////////////////////////////////////////////////////////////////// | |
268 | // Add an include path to one of the search lists (user include path or system | |
269 | // include path). | |
270 | inline | |
271 | bool include_paths::add_include_path ( | |
272 | char const *path_, include_list_type &pathes_) | |
273 | { | |
274 | namespace fs = boost::filesystem; | |
275 | if (path_) { | |
276 | fs::path newpath = util::complete_path(create_path(path_), current_dir); | |
277 | ||
278 | if (!fs::exists(newpath) || !fs::is_directory(newpath)) { | |
279 | // the given path does not form a name of a valid file system directory | |
280 | // item | |
281 | return false; | |
282 | } | |
283 | ||
284 | pathes_.push_back (include_value_type(newpath, path_)); | |
285 | return true; | |
286 | } | |
287 | return false; | |
288 | } | |
289 | ||
290 | /////////////////////////////////////////////////////////////////////////////// | |
291 | // Find an include file by traversing the list of include directories | |
292 | inline | |
293 | bool include_paths::find_include_file (std::string &s, std::string &dir, | |
294 | include_list_type const &pathes, char const *current_file) const | |
295 | { | |
296 | namespace fs = boost::filesystem; | |
297 | typedef include_list_type::const_iterator const_include_list_iter_t; | |
298 | ||
299 | const_include_list_iter_t it = pathes.begin(); | |
300 | const_include_list_iter_t include_paths_end = pathes.end(); | |
301 | ||
302 | #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 | |
303 | if (0 != current_file) { | |
304 | // re-locate the directory of the current file (#include_next handling) | |
305 | ||
306 | // #include_next does not distinguish between <file> and "file" | |
307 | // inclusion, nor does it check that the file you specify has the same | |
308 | // name as the current file. It simply looks for the file named, starting | |
309 | // with the directory in the search path after the one where the current | |
310 | // file was found. | |
311 | ||
312 | fs::path file_path (create_path(current_file)); | |
313 | for (/**/; it != include_paths_end; ++it) { | |
314 | fs::path currpath (create_path((*it).first.string())); | |
315 | if (std::equal(currpath.begin(), currpath.end(), file_path.begin())) | |
316 | { | |
317 | ++it; // start searching with the next directory | |
318 | break; | |
319 | } | |
320 | } | |
321 | } | |
322 | #endif | |
323 | ||
324 | for (/**/; it != include_paths_end; ++it) { | |
325 | fs::path currpath (create_path(s)); | |
326 | if (!currpath.has_root_directory()) { | |
327 | currpath = create_path((*it).first.string()); | |
328 | currpath /= create_path(s); // append filename | |
329 | } | |
330 | ||
331 | if (fs::exists(currpath)) { | |
332 | fs::path dirpath (create_path(s)); | |
333 | if (!dirpath.has_root_directory()) { | |
334 | dirpath = create_path((*it).second); | |
335 | dirpath /= create_path(s); | |
336 | } | |
337 | ||
338 | dir = dirpath.string(); | |
339 | s = normalize(currpath).string(); // found the required file | |
340 | return true; | |
341 | } | |
342 | } | |
343 | return false; | |
344 | } | |
345 | ||
346 | /////////////////////////////////////////////////////////////////////////////// | |
347 | // Find an include file by searching the user and system includes in the | |
348 | // correct sequence (as it was configured by the user of the driver program) | |
349 | inline bool | |
350 | include_paths::find_include_file (std::string &s, std::string &dir, | |
351 | bool is_system, char const *current_file) const | |
352 | { | |
353 | namespace fs = boost::filesystem; | |
354 | ||
355 | // if not system include (<...>), then search current directory first | |
356 | if (!is_system) { | |
357 | if (!was_sys_include_path) { // set_sys_include_delimiter() not called | |
358 | // first have a look at the current directory | |
359 | fs::path currpath (create_path(s)); | |
360 | if (!currpath.has_root_directory()) { | |
361 | currpath = create_path(current_dir.string()); | |
362 | currpath /= create_path(s); | |
363 | } | |
364 | ||
365 | if (fs::exists(currpath) && 0 == current_file) { | |
366 | // if 0 != current_path (#include_next handling) it can't be | |
367 | // the file in the current directory | |
368 | fs::path dirpath (create_path(s)); | |
369 | if (!dirpath.has_root_directory()) { | |
370 | dirpath = create_path(current_rel_dir.string()); | |
371 | dirpath /= create_path(s); | |
372 | } | |
373 | ||
374 | dir = dirpath.string(); | |
375 | s = normalize(currpath).string(); // found in local directory | |
376 | return true; | |
377 | } | |
378 | ||
379 | // iterate all user include file directories to find the file | |
380 | if (find_include_file(s, dir, user_include_paths, current_file)) | |
381 | return true; | |
382 | ||
383 | // ... fall through | |
384 | } | |
385 | else { | |
386 | // if set_sys_include_delimiter() was called, then user include files | |
387 | // are searched in the user search path only | |
388 | return find_include_file(s, dir, user_include_paths, current_file); | |
389 | } | |
390 | ||
391 | // if nothing found, fall through | |
392 | // ... | |
393 | } | |
394 | ||
395 | // iterate all system include file directories to find the file | |
396 | return find_include_file (s, dir, system_include_paths, current_file); | |
397 | } | |
398 | ||
399 | /////////////////////////////////////////////////////////////////////////////// | |
400 | // Set current directory from a given file name | |
401 | ||
402 | inline bool | |
403 | as_relative_to(boost::filesystem::path const& path, | |
404 | boost::filesystem::path const& base, boost::filesystem::path& result) | |
405 | { | |
406 | if (path.has_root_path()) { | |
407 | if (path.root_path() == base.root_path()) | |
408 | return as_relative_to(path.relative_path(), base.relative_path(), result); | |
409 | ||
410 | result = path; // that's our result | |
411 | } | |
412 | else { | |
413 | if (base.has_root_path()) { | |
414 | // cannot find relative path from a relative path and a rooted base | |
415 | return false; | |
416 | } | |
417 | else { | |
418 | typedef boost::filesystem::path::const_iterator path_iterator; | |
419 | path_iterator path_it = path.begin(); | |
420 | path_iterator base_it = base.begin(); | |
421 | while (path_it != path.end() && base_it != base.end() ) { | |
422 | if (*path_it != *base_it) | |
423 | break; | |
424 | ++path_it; ++base_it; | |
425 | } | |
426 | ||
427 | for (/**/; base_it != base.end(); ++base_it) | |
428 | result /= ".."; | |
429 | ||
430 | for (/**/; path_it != path.end(); ++path_it) | |
431 | result /= *path_it; | |
432 | } | |
433 | } | |
434 | return true; | |
435 | } | |
436 | ||
437 | /////////////////////////////////////////////////////////////////////////////// | |
438 | inline | |
439 | void include_paths::set_current_directory(char const *path_) | |
440 | { | |
441 | namespace fs = boost::filesystem; | |
442 | ||
443 | fs::path filepath (create_path(path_)); | |
444 | fs::path filename = util::complete_path(filepath, current_dir); | |
445 | if (fs::exists(filename) && fs::is_directory(filename)) { | |
446 | current_rel_dir.clear(); | |
447 | if (!as_relative_to(filepath, current_dir, current_rel_dir)) | |
448 | current_rel_dir = filepath; | |
449 | current_dir = filename; | |
450 | } | |
451 | else { | |
452 | current_rel_dir.clear(); | |
453 | if (!as_relative_to(branch_path(filepath), current_dir, current_rel_dir)) | |
454 | current_rel_dir = branch_path(filepath); | |
455 | current_dir = branch_path(filename); | |
456 | } | |
457 | } | |
458 | ||
459 | /////////////////////////////////////////////////////////////////////////////// | |
460 | }}} // namespace boost::wave::util | |
461 | ||
462 | #if BOOST_WAVE_SERIALIZATION != 0 | |
463 | /////////////////////////////////////////////////////////////////////////////// | |
464 | namespace boost { namespace serialization { | |
465 | ||
466 | /////////////////////////////////////////////////////////////////////////////// | |
467 | // Serialization support for boost::filesystem::path | |
468 | template<class Archive> | |
469 | inline void save (Archive & ar, boost::filesystem::path const& p, | |
470 | const unsigned int /* file_version */) | |
471 | { | |
472 | using namespace boost::serialization; | |
473 | std::string path_str(p.native_file_string()); | |
474 | ar & make_nvp("filepath", path_str); | |
475 | } | |
476 | ||
477 | template<class Archive> | |
478 | inline void load (Archive & ar, boost::filesystem::path &p, | |
479 | const unsigned int /* file_version */) | |
480 | { | |
481 | using namespace boost::serialization; | |
482 | std::string path_str; | |
483 | ar & make_nvp("filepath", path_str); | |
484 | p = wave::util::create_path(path_str); | |
485 | } | |
486 | ||
487 | // split non-intrusive serialization function member into separate | |
488 | // non intrusive save/load member functions | |
489 | template<class Archive> | |
490 | inline void serialize (Archive & ar, boost::filesystem::path &p, | |
491 | const unsigned int file_version) | |
492 | { | |
493 | boost::serialization::split_free(ar, p, file_version); | |
494 | } | |
495 | ||
496 | /////////////////////////////////////////////////////////////////////////////// | |
497 | // Serialization support for the used multi_index | |
498 | template<class Archive> | |
499 | inline void save (Archive & ar, | |
500 | const typename boost::wave::util::bidirectional_map< | |
501 | std::string, std::string | |
502 | >::type &t, | |
503 | const unsigned int /* file_version */) | |
504 | { | |
505 | boost::serialization::stl::save_collection< | |
506 | Archive, | |
507 | typename boost::wave::util::bidirectional_map< | |
508 | std::string, std::string | |
509 | >::type | |
510 | >(ar, t); | |
511 | } | |
512 | ||
513 | template<class Archive> | |
514 | inline void load (Archive & ar, | |
515 | typename boost::wave::util::bidirectional_map<std::string, std::string>::type &t, | |
516 | const unsigned int /* file_version */) | |
517 | { | |
518 | typedef typename boost::wave::util::bidirectional_map< | |
519 | std::string, std::string | |
520 | >::type map_type; | |
521 | boost::serialization::stl::load_collection< | |
522 | Archive, map_type, | |
523 | boost::serialization::stl::archive_input_unique<Archive, map_type>, | |
524 | boost::serialization::stl::no_reserve_imp<map_type> | |
525 | >(ar, t); | |
526 | } | |
527 | ||
528 | // split non-intrusive serialization function member into separate | |
529 | // non intrusive save/load member functions | |
530 | template<class Archive> | |
531 | inline void serialize (Archive & ar, | |
532 | typename boost::wave::util::bidirectional_map< | |
533 | std::string, std::string | |
534 | >::type &t, | |
535 | const unsigned int file_version) | |
536 | { | |
537 | boost::serialization::split_free(ar, t, file_version); | |
538 | } | |
539 | ||
540 | /////////////////////////////////////////////////////////////////////////////// | |
541 | }} // namespace boost::serialization | |
542 | ||
543 | BOOST_CLASS_VERSION(boost::wave::util::include_paths, | |
544 | boost::wave::util::include_paths::version); | |
545 | ||
546 | #endif // BOOST_WAVE_SERIALIZATION != 0 | |
547 | ||
548 | // the suffix header occurs after all of the code | |
549 | #ifdef BOOST_HAS_ABI_HEADERS | |
550 | #include BOOST_ABI_SUFFIX | |
551 | #endif | |
552 | ||
553 | #endif // !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) |