Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/wave/util/cpp_include_paths.hpp @ 30

Last change on this file since 30 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

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