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