]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/quickbook/src/include_paths.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / quickbook / src / include_paths.cpp
1 /*=============================================================================
2 Copyright (c) 2002 2004 2006 Joel de Guzman
3 Copyright (c) 2004 Eric Niebler
4 Copyright (c) 2005 Thomas Guest
5 Copyright (c) 2013 Daniel James
6
7 Use, modification and distribution is subject to the Boost Software
8 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 http://www.boost.org/LICENSE_1_0.txt)
10 =============================================================================*/
11
12 #include "include_paths.hpp"
13 #include <cassert>
14 #include <boost/filesystem.hpp>
15 #include <boost/range/algorithm/replace.hpp>
16 #include "for.hpp"
17 #include "glob.hpp"
18 #include "path.hpp"
19 #include "quickbook.hpp" // For the include_path global (yuck)
20 #include "state.hpp"
21 #include "stream.hpp"
22 #include "utils.hpp"
23
24 namespace quickbook
25 {
26 //
27 // check_path
28 //
29
30 path_parameter check_path(value const& path, quickbook::state& state)
31 {
32 if (qbk_version_n >= 107u) {
33 std::string path_text = path.get_encoded();
34 if (path_text.empty()) {
35 detail::outerr(path.get_file(), path.get_position())
36 << "Empty path argument"
37 << "std::endl";
38 ++state.error_count;
39 return path_parameter(path_text, path_parameter::invalid);
40 }
41
42 try {
43 if (check_glob(path_text)) {
44 return path_parameter(path_text, path_parameter::glob);
45 }
46 else {
47 return path_parameter(
48 glob_unescape(path_text), path_parameter::path);
49 }
50 } catch (glob_error& e) {
51 detail::outerr(path.get_file(), path.get_position())
52 << "Invalid path (" << e.what() << "): " << path_text
53 << std::endl;
54 ++state.error_count;
55 return path_parameter(path_text, path_parameter::invalid);
56 }
57 }
58 else {
59 // Paths are encoded for quickbook 1.6+ and also xmlbase
60 // values (technically xmlbase is a 1.6 feature, but that
61 // isn't enforced as it's backwards compatible).
62 //
63 // Counter-intuitively: encoded == plain text here.
64
65 std::string path_text = qbk_version_n >= 106u || path.is_encoded()
66 ? path.get_encoded()
67 : path.get_quickbook().to_s();
68
69 if (path_text.empty()) {
70 detail::outerr(path.get_file(), path.get_position())
71 << "Empty path argument" << std::endl;
72 ++state.error_count;
73 return path_parameter(path_text, path_parameter::invalid);
74 }
75
76 // Check for windows paths, an error in quickbook 1.6
77 // In quickbook 1.7 backslash is used as an escape character
78 // for glob characters.
79 if (path_text.find('\\') != std::string::npos) {
80 quickbook::detail::ostream* err;
81
82 if (qbk_version_n >= 106u) {
83 err = &detail::outerr(path.get_file(), path.get_position());
84 ++state.error_count;
85 }
86 else {
87 err =
88 &detail::outwarn(path.get_file(), path.get_position());
89 }
90
91 *err << "Path isn't portable: '" << path_text << "'"
92 << std::endl;
93
94 boost::replace(path_text, '\\', '/');
95 }
96
97 return path_parameter(path_text, path_parameter::path);
98 }
99 }
100
101 path_parameter check_xinclude_path(value const& p, quickbook::state& state)
102 {
103 path_parameter parameter = check_path(p, state);
104
105 if (parameter.type == path_parameter::glob) {
106 detail::outerr(p.get_file(), p.get_position())
107 << "Glob used for xml path." << std::endl;
108 ++state.error_count;
109 parameter.type = path_parameter::invalid;
110 }
111
112 return parameter;
113 }
114
115 //
116 // Search include path
117 //
118
119 void include_search_glob(
120 std::set<quickbook_path>& result,
121 quickbook_path const& location,
122 std::string path,
123 quickbook::state& state)
124 {
125 std::size_t glob_pos = find_glob_char(path);
126
127 if (glob_pos == std::string::npos) {
128 quickbook_path complete_path = location / glob_unescape(path);
129
130 if (fs::exists(complete_path.file_path)) {
131 state.dependencies.add_glob_match(complete_path.file_path);
132 result.insert(complete_path);
133 }
134 return;
135 }
136
137 std::size_t prev = path.rfind('/', glob_pos);
138 std::size_t next = path.find('/', glob_pos);
139
140 std::size_t glob_begin = prev == std::string::npos ? 0 : prev + 1;
141 std::size_t glob_end = next == std::string::npos ? path.size() : next;
142
143 quickbook_path new_location = location;
144
145 if (prev != std::string::npos) {
146 new_location /= glob_unescape(path.substr(0, prev));
147 }
148
149 if (next != std::string::npos) ++next;
150
151 quickbook::string_view glob(
152 path.data() + glob_begin, glob_end - glob_begin);
153
154 fs::path base_dir = new_location.file_path.empty()
155 ? fs::path(".")
156 : new_location.file_path;
157 if (!fs::is_directory(base_dir)) return;
158
159 // Walk through the dir for matches.
160 for (fs::directory_iterator dir_i(base_dir), dir_e; dir_i != dir_e;
161 ++dir_i) {
162 fs::path f = dir_i->path().filename();
163 std::string generic_path = detail::path_to_generic(f);
164
165 // Skip if the dir item doesn't match.
166 if (!quickbook::glob(glob, generic_path)) continue;
167
168 // If it's a file we add it to the results.
169 if (next == std::string::npos) {
170 if (fs::is_regular_file(dir_i->status())) {
171 quickbook_path r = new_location / generic_path;
172 state.dependencies.add_glob_match(r.file_path);
173 result.insert(r);
174 }
175 }
176 // If it's a matching dir, we recurse looking for more files.
177 else {
178 if (!fs::is_regular_file(dir_i->status())) {
179 include_search_glob(
180 result, new_location / generic_path, path.substr(next),
181 state);
182 }
183 }
184 }
185 }
186
187 std::set<quickbook_path> include_search(
188 path_parameter const& parameter,
189 quickbook::state& state,
190 string_iterator pos)
191 {
192 std::set<quickbook_path> result;
193
194 switch (parameter.type) {
195 case path_parameter::glob:
196 // If the path has some glob match characters
197 // we do a discovery of all the matches..
198 {
199 fs::path current = state.current_file->path.parent_path();
200
201 // Search for the current dir accumulating to the result.
202 state.dependencies.add_glob(current / parameter.value);
203 include_search_glob(
204 result, state.current_path.parent_path(), parameter.value,
205 state);
206
207 // Search the include path dirs accumulating to the result.
208 unsigned count = 0;
209 QUICKBOOK_FOR (fs::path dir, include_path) {
210 ++count;
211 state.dependencies.add_glob(dir / parameter.value);
212 include_search_glob(
213 result, quickbook_path(dir, count, fs::path()),
214 parameter.value, state);
215 }
216
217 // Done.
218 return result;
219 }
220
221 case path_parameter::path: {
222 fs::path path = detail::generic_to_path(parameter.value);
223
224 // If the path is relative, try and resolve it.
225 if (!path.has_root_directory() && !path.has_root_name()) {
226 quickbook_path path2 =
227 state.current_path.parent_path() / parameter.value;
228
229 // See if it can be found locally first.
230 if (state.dependencies.add_dependency(path2.file_path)) {
231 result.insert(path2);
232 return result;
233 }
234
235 // Search in each of the include path locations.
236 unsigned count = 0;
237 QUICKBOOK_FOR (fs::path full, include_path) {
238 ++count;
239 full /= path;
240
241 if (state.dependencies.add_dependency(full)) {
242 result.insert(quickbook_path(full, count, path));
243 return result;
244 }
245 }
246 }
247 else {
248 if (state.dependencies.add_dependency(path)) {
249 result.insert(quickbook_path(path, 0, path));
250 return result;
251 }
252 }
253
254 detail::outerr(state.current_file, pos)
255 << "Unable to find file: " << parameter.value << std::endl;
256 ++state.error_count;
257
258 return result;
259 }
260
261 case path_parameter::invalid:
262 return result;
263
264 default:
265 assert(0);
266 return result;
267 }
268 }
269
270 //
271 // quickbook_path
272 //
273
274 void swap(quickbook_path& x, quickbook_path& y)
275 {
276 boost::swap(x.file_path, y.file_path);
277 boost::swap(x.include_path_offset, y.include_path_offset);
278 boost::swap(x.abstract_file_path, y.abstract_file_path);
279 }
280
281 bool quickbook_path::operator<(quickbook_path const& other) const
282 {
283 return abstract_file_path != other.abstract_file_path
284 ? abstract_file_path < other.abstract_file_path
285 : include_path_offset != other.include_path_offset
286 ? include_path_offset < other.include_path_offset
287 : file_path < other.file_path;
288 }
289
290 quickbook_path quickbook_path::operator/(quickbook::string_view x) const
291 {
292 return quickbook_path(*this) /= x;
293 }
294
295 quickbook_path& quickbook_path::operator/=(quickbook::string_view x)
296 {
297 fs::path x2 = detail::generic_to_path(x);
298 file_path /= x2;
299 abstract_file_path /= x2;
300 return *this;
301 }
302
303 quickbook_path quickbook_path::parent_path() const
304 {
305 return quickbook_path(
306 file_path.parent_path(), include_path_offset,
307 abstract_file_path.parent_path());
308 }
309
310 quickbook_path resolve_xinclude_path(
311 std::string const& x, quickbook::state& state, bool is_file)
312 {
313 fs::path path = detail::generic_to_path(x);
314 fs::path full_path = path;
315
316 // If the path is relative
317 if (!path.has_root_directory()) {
318 // Resolve the path from the current file
319 full_path = state.current_file->path.parent_path() / path;
320
321 // Then calculate relative to the current xinclude_base.
322 path = path_difference(state.xinclude_base, full_path, is_file);
323 }
324
325 return quickbook_path(full_path, 0, path);
326 }
327 }