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 | ///////////////////////////////////////////////////////////////////////////////
|
---|
25 | namespace boost {
|
---|
26 | namespace wave {
|
---|
27 | namespace 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 | ///////////////////////////////////////////////////////////////////////////////
|
---|
55 | class 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 |
|
---|
65 | public:
|
---|
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 |
|
---|
84 | protected:
|
---|
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 |
|
---|
89 | private:
|
---|
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
|
---|
97 | public:
|
---|
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 |
|
---|
107 | private:
|
---|
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).
|
---|
115 | inline
|
---|
116 | bool 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
|
---|
137 | inline
|
---|
138 | bool 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)
|
---|
188 | inline bool
|
---|
189 | include_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 |
|
---|
235 | inline
|
---|
236 | void 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)
|
---|