Line data Source code
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/assert.hpp>
19 : #include <boost/wave/wave_config.hpp>
20 : #include <boost/wave/util/filesystem_compatibility.hpp>
21 :
22 : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
23 : #include <boost/multi_index_container.hpp>
24 : #include <boost/multi_index/member.hpp>
25 : #include <boost/multi_index/ordered_index.hpp>
26 : #endif
27 :
28 : #if BOOST_WAVE_SERIALIZATION != 0
29 : #include <boost/serialization/serialization.hpp>
30 : #include <boost/serialization/utility.hpp>
31 : #include <boost/serialization/collections_save_imp.hpp>
32 : #include <boost/serialization/collections_load_imp.hpp>
33 : #include <boost/serialization/split_free.hpp>
34 : #endif
35 :
36 : #include <boost/filesystem/path.hpp>
37 : #include <boost/filesystem/operations.hpp>
38 :
39 : // this must occur after all of the includes and before any code appears
40 : #ifdef BOOST_HAS_ABI_HEADERS
41 : #include BOOST_ABI_PREFIX
42 : #endif
43 :
44 : ///////////////////////////////////////////////////////////////////////////////
45 : namespace boost { namespace wave { namespace util {
46 :
47 : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
48 : ///////////////////////////////////////////////////////////////////////////////
49 : // Tags for accessing both sides of a bidirectional map
50 : struct from {};
51 : struct to {};
52 :
53 : ///////////////////////////////////////////////////////////////////////////////
54 : // The class template bidirectional_map wraps the specification
55 : // of a bidirectional map based on multi_index_container.
56 : template<typename FromType, typename ToType>
57 : struct bidirectional_map
58 : {
59 : typedef std::pair<FromType, ToType> value_type;
60 :
61 : #if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) || \
62 : (defined(BOOST_MSVC) && (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 0 : include_paths()
152 0 : : was_sys_include_path(false),
153 : current_dir(initial_path()),
154 0 : current_rel_dir(initial_path())
155 0 : {}
156 :
157 0 : bool add_include_path(char const *path_, bool is_system = false)
158 : {
159 0 : 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 0 : bool has_pragma_once(std::string const &filename)
184 : {
185 0 : using boost::multi_index::get;
186 0 : return get<from>(pragma_once_files).find(filename) != pragma_once_files.end();
187 : }
188 0 : bool add_pragma_once_header(std::string const &filename,
189 : std::string const& guard_name)
190 : {
191 0 : typedef pragma_once_set_type::value_type value_type;
192 0 : return pragma_once_files.insert(value_type(filename, guard_name)).second;
193 : }
194 0 : bool remove_pragma_once_header(std::string const& guard_name)
195 : {
196 0 : typedef pragma_once_set_type::index_iterator<to>::type to_iterator;
197 0 : typedef std::pair<to_iterator, to_iterator> range_type;
198 :
199 0 : range_type r = pragma_once_files.get<to>().equal_range(guard_name);
200 0 : if (r.first != r.second) {
201 : using boost::multi_index::get;
202 0 : 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 0 : bool include_paths::add_include_path (
272 : char const *path_, include_list_type &pathes_)
273 : {
274 0 : namespace fs = boost::filesystem;
275 0 : if (path_) {
276 0 : fs::path newpath = util::complete_path(create_path(path_), current_dir);
277 :
278 0 : 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 0 : return false;
282 : }
283 :
284 0 : pathes_.push_back (include_value_type(newpath, path_));
285 0 : return true;
286 : }
287 : return false;
288 : }
289 :
290 : ///////////////////////////////////////////////////////////////////////////////
291 : // Find an include file by traversing the list of include directories
292 : inline
293 0 : 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 0 : namespace fs = boost::filesystem;
297 0 : typedef include_list_type::const_iterator const_include_list_iter_t;
298 :
299 0 : const_include_list_iter_t it = pathes.begin();
300 0 : const_include_list_iter_t include_paths_end = pathes.end();
301 :
302 : #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
303 0 : 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 0 : fs::path file_path (create_path(current_file));
313 0 : for (/**/; it != include_paths_end; ++it) {
314 0 : fs::path currpath (create_path((*it).first.string()));
315 0 : if (std::equal(currpath.begin(), currpath.end(), file_path.begin()))
316 : {
317 0 : ++it; // start searching with the next directory
318 0 : break;
319 : }
320 : }
321 : }
322 : #endif
323 :
324 0 : for (/**/; it != include_paths_end; ++it) {
325 0 : fs::path currpath (create_path(s));
326 0 : if (!currpath.has_root_directory()) {
327 0 : currpath = create_path((*it).first.string());
328 0 : currpath /= create_path(s); // append filename
329 : }
330 :
331 0 : if (fs::exists(currpath)) {
332 0 : fs::path dirpath (create_path(s));
333 0 : if (!dirpath.has_root_directory()) {
334 0 : dirpath = create_path((*it).second);
335 0 : dirpath /= create_path(s);
336 : }
337 :
338 0 : dir = dirpath.string();
339 0 : s = normalize(currpath).string(); // found the required file
340 0 : 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 0 : include_paths::find_include_file (std::string &s, std::string &dir,
351 : bool is_system, char const *current_file) const
352 : {
353 0 : namespace fs = boost::filesystem;
354 :
355 : // if not system include (<...>), then search current directory first
356 0 : if (!is_system) {
357 0 : if (!was_sys_include_path) { // set_sys_include_delimiter() not called
358 : // first have a look at the current directory
359 0 : fs::path currpath (create_path(s));
360 0 : if (!currpath.has_root_directory()) {
361 0 : currpath = create_path(current_dir.string());
362 0 : currpath /= create_path(s);
363 : }
364 :
365 0 : 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 0 : fs::path dirpath (create_path(s));
369 0 : if (!dirpath.has_root_directory()) {
370 0 : dirpath = create_path(current_rel_dir.string());
371 0 : dirpath /= create_path(s);
372 : }
373 :
374 0 : dir = dirpath.string();
375 0 : s = normalize(currpath).string(); // found in local directory
376 0 : return true;
377 : }
378 :
379 : // iterate all user include file directories to find the file
380 0 : 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 0 : 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 0 : 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 0 : as_relative_to(boost::filesystem::path const& path,
404 : boost::filesystem::path const& base, boost::filesystem::path& result)
405 : {
406 0 : if (path.has_root_path()) {
407 0 : if (path.root_path() == base.root_path())
408 0 : return as_relative_to(path.relative_path(), base.relative_path(), result);
409 :
410 0 : result = path; // that's our result
411 : }
412 : else {
413 0 : 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 0 : typedef boost::filesystem::path::const_iterator path_iterator;
419 0 : path_iterator path_it = path.begin();
420 0 : path_iterator base_it = base.begin();
421 0 : while (path_it != path.end() && base_it != base.end() ) {
422 0 : if (*path_it != *base_it)
423 : break;
424 0 : ++path_it; ++base_it;
425 : }
426 :
427 0 : for (/**/; base_it != base.end(); ++base_it)
428 0 : result /= "..";
429 :
430 0 : for (/**/; path_it != path.end(); ++path_it)
431 0 : result /= *path_it;
432 : }
433 : }
434 : return true;
435 : }
436 :
437 : ///////////////////////////////////////////////////////////////////////////////
438 : inline
439 0 : void include_paths::set_current_directory(char const *path_)
440 : {
441 0 : namespace fs = boost::filesystem;
442 :
443 0 : fs::path filepath (create_path(path_));
444 0 : fs::path filename = util::complete_path(filepath, current_dir);
445 :
446 0 : BOOST_ASSERT(!(fs::exists(filename) && fs::is_directory(filename)));
447 :
448 0 : current_rel_dir.clear();
449 0 : if (!as_relative_to(branch_path(filepath), current_dir, current_rel_dir))
450 0 : current_rel_dir = branch_path(filepath);
451 0 : current_dir = branch_path(filename);
452 0 : }
453 :
454 : ///////////////////////////////////////////////////////////////////////////////
455 : }}} // namespace boost::wave::util
456 :
457 : #if BOOST_WAVE_SERIALIZATION != 0
458 : ///////////////////////////////////////////////////////////////////////////////
459 : namespace boost { namespace serialization {
460 :
461 : ///////////////////////////////////////////////////////////////////////////////
462 : // Serialization support for boost::filesystem::path
463 : template<class Archive>
464 : inline void save (Archive & ar, boost::filesystem::path const& p,
465 : const unsigned int /* file_version */)
466 : {
467 : using namespace boost::serialization;
468 : std::string path_str(p.native_file_string());
469 : ar & make_nvp("filepath", path_str);
470 : }
471 :
472 : template<class Archive>
473 : inline void load (Archive & ar, boost::filesystem::path &p,
474 : const unsigned int /* file_version */)
475 : {
476 : using namespace boost::serialization;
477 : std::string path_str;
478 : ar & make_nvp("filepath", path_str);
479 : p = wave::util::create_path(path_str);
480 : }
481 :
482 : // split non-intrusive serialization function member into separate
483 : // non intrusive save/load member functions
484 : template<class Archive>
485 : inline void serialize (Archive & ar, boost::filesystem::path &p,
486 : const unsigned int file_version)
487 : {
488 : boost::serialization::split_free(ar, p, file_version);
489 : }
490 :
491 : ///////////////////////////////////////////////////////////////////////////////
492 : // Serialization support for the used multi_index
493 : template<class Archive>
494 : inline void save (Archive & ar,
495 : const typename boost::wave::util::bidirectional_map<
496 : std::string, std::string
497 : >::type &t,
498 : const unsigned int /* file_version */)
499 : {
500 : boost::serialization::stl::save_collection<
501 : Archive,
502 : typename boost::wave::util::bidirectional_map<
503 : std::string, std::string
504 : >::type
505 : >(ar, t);
506 : }
507 :
508 : template<class Archive>
509 : inline void load (Archive & ar,
510 : typename boost::wave::util::bidirectional_map<std::string, std::string>::type &t,
511 : const unsigned int /* file_version */)
512 : {
513 : typedef typename boost::wave::util::bidirectional_map<
514 : std::string, std::string
515 : >::type map_type;
516 : boost::serialization::stl::load_collection<
517 : Archive, map_type,
518 : boost::serialization::stl::archive_input_unique<Archive, map_type>,
519 : boost::serialization::stl::no_reserve_imp<map_type>
520 : >(ar, t);
521 : }
522 :
523 : // split non-intrusive serialization function member into separate
524 : // non intrusive save/load member functions
525 : template<class Archive>
526 : inline void serialize (Archive & ar,
527 : typename boost::wave::util::bidirectional_map<
528 : std::string, std::string
529 : >::type &t,
530 : const unsigned int file_version)
531 : {
532 : boost::serialization::split_free(ar, t, file_version);
533 : }
534 :
535 : ///////////////////////////////////////////////////////////////////////////////
536 : }} // namespace boost::serialization
537 :
538 : BOOST_CLASS_VERSION(boost::wave::util::include_paths,
539 : boost::wave::util::include_paths::version);
540 :
541 : #endif // BOOST_WAVE_SERIALIZATION != 0
542 :
543 : // the suffix header occurs after all of the code
544 : #ifdef BOOST_HAS_ABI_HEADERS
545 : #include BOOST_ABI_SUFFIX
546 : #endif
547 :
548 : #endif // !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED)
|