source: NonGTP/Boost/boost/wave/util/cpp_include_paths.hpp @ 857

Revision 857, 9.6 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3
4    http://www.boost.org/
5
6    Copyright (c) 2001-2005 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 <set>
17#include <utility>
18
19#include <boost/filesystem/path.hpp>
20#include <boost/filesystem/operations.hpp>
21
22#include <boost/wave/wave_config.hpp>
23
24///////////////////////////////////////////////////////////////////////////////
25namespace boost {
26namespace wave {
27namespace util {
28
29///////////////////////////////////////////////////////////////////////////////
30//
31//  include_paths - controlling the include path search order
32//
33//  General notes:
34//
35//      Any directories specified with the 'add_include_path()' function before
36//      the function 'set_sys_include_delimiter()' is called are searched only
37//      for the case of '#include "file"' directives, they are not searched for
38//      '#include <file>' directives. If additional directories are specified
39//      with the 'add_include_path()' function after a call to the function
40//      'set_sys_include_delimiter()', these directories are searched for all
41//      '#include' directives.
42//
43//      In addition, a call to the function 'set_sys_include_delimiter()'
44//      inhibits the use of the current directory as the first search directory
45//      for '#include "file"' directives. Therefore, the current directory is
46//      searched only if it is requested explicitly with a call to the function
47//      'add_include_path(".")'.
48//
49//      Calling both functions, the 'set_sys_include_delimiter()' and
50//      'add_include_path(".")' allows you to control precisely which
51//      directories are searched before the current one and which are searched
52//      after.
53//
54///////////////////////////////////////////////////////////////////////////////
55class include_paths
56{
57    typedef std::list<std::pair<boost::filesystem::path, std::string> >
58        include_list_type;
59    typedef include_list_type::value_type include_value_type;
60   
61#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
62    typedef std::set<std::string> pragma_once_set_t;
63#endif
64
65public:
66    include_paths()
67    :   was_sys_include_path(false),
68        current_dir(boost::filesystem::initial_path()),
69        current_rel_dir(boost::filesystem::initial_path())
70    {}
71   
72    bool add_include_path(char const *path_, bool is_system = false)
73    {
74        return add_include_path(path_, (is_system || was_sys_include_path) ?
75            system_include_paths : user_include_paths);
76    }
77    void set_sys_include_delimiter() { was_sys_include_path = true; }
78    bool find_include_file (std::string &s, std::string &dir, bool is_system,
79        char const *current_file) const;
80    void set_current_directory(char const *path_);
81
82    void init_initial_path() { boost::filesystem::initial_path(); }
83   
84protected:
85    bool find_include_file (std::string &s, std::string &dir,
86        include_list_type const &pathes, char const *) const;
87    bool add_include_path(char const *path_, include_list_type &pathes_);
88
89private:
90    include_list_type user_include_paths;
91    include_list_type system_include_paths;
92    bool was_sys_include_path;          // saw a set_sys_include_delimiter()
93    boost::filesystem::path current_dir;
94    boost::filesystem::path current_rel_dir;
95
96#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
97public:
98    bool has_pragma_once(std::string const &filename)
99    {
100        return pragma_once_files.find(filename) != pragma_once_files.end();
101    }
102    bool add_pragma_once_header(std::string const &filename)
103    {
104        return pragma_once_files.insert(filename).second;
105    }
106
107private:
108    pragma_once_set_t pragma_once_files;
109#endif
110};
111
112///////////////////////////////////////////////////////////////////////////////
113//  Add an include path to one of the search lists (user include path or system
114//  include path).
115inline
116bool include_paths::add_include_path (
117    char const *path_, include_list_type &pathes_)
118{
119    namespace fs = boost::filesystem;
120    if (path_) {
121    fs::path newpath = fs::complete(fs::path(path_, fs::native), current_dir);
122
123        if (!fs::exists(newpath) || !fs::is_directory(newpath)) {
124        // the given path does not form a name of a valid file system directory
125        // item
126            return false;
127        }
128
129        pathes_.push_back (include_value_type(newpath, path_));
130        return true;
131    }
132    return false;
133}
134
135///////////////////////////////////////////////////////////////////////////////
136//  Find an include file by traversing the list of include directories
137inline
138bool include_paths::find_include_file (std::string &s, std::string &dir,
139    include_list_type const &pathes, char const *current_file) const
140{
141    namespace fs = boost::filesystem;
142    typedef include_list_type::const_iterator const_include_list_iter_t;
143
144    const_include_list_iter_t it = pathes.begin();
145    const_include_list_iter_t include_paths_end = pathes.end();
146
147#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0   
148    if (0 != current_file) {
149    // re-locate the directory of the current file (#include_next handling)
150
151    // #include_next does not distinguish between <file> and "file"
152    // inclusion, nor does it check that the file you specify has the same
153    // name as the current file.  It simply looks for the file named, starting
154    // with the directory in the search path after the one where the current
155    // file was found.
156
157        fs::path file_path (current_file, fs::native);
158        for (/**/; it != include_paths_end; ++it) {
159            fs::path currpath ((*it).first.string(), fs::native);
160            if (std::equal(currpath.begin(), currpath.end(), file_path.begin()))
161            {
162                ++it;     // start searching with the next directory
163                break;
164            }
165        }
166    }
167#endif
168
169    for (/**/; it != include_paths_end; ++it) {
170        fs::path currpath ((*it).first.string(), fs::native);
171        currpath /= fs::path(s, fs::native);      // append filename
172
173        if (fs::exists(currpath)) {
174            fs::path dirpath ((*it).second, fs::native);
175            dirpath /= fs::path(s, fs::native);
176           
177            dir = dirpath.string();
178            s = currpath.normalize().string();    // found the required file
179            return true;
180        }
181    }
182    return false;
183}
184
185///////////////////////////////////////////////////////////////////////////////
186//  Find an include file by searching the user and system includes in the
187//  correct sequence (as it was configured by the user of the driver program)
188inline bool
189include_paths::find_include_file (std::string &s, std::string &dir,
190    bool is_system, char const *current_file) const
191{
192    namespace fs = boost::filesystem;
193   
194// if not system include (<...>), then search current directory first
195    if (!is_system) {
196        if (!was_sys_include_path) {  // set_sys_include_delimiter() not called
197        // first have a look at the current directory
198            fs::path currpath (current_dir.string(), fs::native);
199            currpath /= fs::path(s, fs::native);
200           
201            if (fs::exists(currpath) && 0 == current_file) {
202            // if 0 != current_path (#include_next handling) it can't be
203            // the file in the current directory
204                fs::path dirpath (current_rel_dir.string(), fs::native);
205                dirpath /= fs::path(s, fs::native);
206
207                dir = dirpath.string();
208                s = currpath.normalize().string();    // found in local directory
209                return true;
210            }   
211
212        // iterate all user include file directories to find the file
213            if (find_include_file(s, dir, user_include_paths, current_file))
214                return true;
215
216        // ... fall through
217        }
218        else {
219        //  if set_sys_include_delimiter() was called, then user include files
220        //  are searched in the user search path only
221            return find_include_file(s, dir, user_include_paths, current_file);
222        }
223       
224    // if nothing found, fall through
225    // ...
226    }
227
228// iterate all system include file directories to find the file
229    return find_include_file (s, dir, system_include_paths, current_file);
230}
231
232///////////////////////////////////////////////////////////////////////////////
233//  Set current directory from a given file name
234
235inline
236void include_paths::set_current_directory(char const *path_)
237{
238    namespace fs = boost::filesystem;
239   
240    fs::path filepath (path_, fs::native);
241    fs::path filename = fs::complete(filepath, current_dir);
242    if (fs::exists(filename) && fs::is_directory(filename)) {
243        current_dir = filename;
244        current_rel_dir = filepath;
245    }
246    else {
247        current_dir = filename.branch_path();
248        current_rel_dir = filepath.branch_path();
249    }
250}
251
252///////////////////////////////////////////////////////////////////////////////
253}   // namespace util
254}   // namespace wave
255}   // namespace boost
256
257#endif // !defined(CPP_include_paths_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED)
Note: See TracBrowser for help on using the repository browser.