]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/quickbook/src/path.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / quickbook / src / path.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, 2017 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 "path.hpp"
13 #include "glob.hpp"
14 #include "include_paths.hpp"
15 #include "state.hpp"
16 #include "utils.hpp"
17 #include <boost/foreach.hpp>
18 #include <boost/range/algorithm/replace.hpp>
19 #include <boost/filesystem/operations.hpp>
20 #include <cassert>
21
22 #if QUICKBOOK_CYGWIN_PATHS
23 #include <boost/scoped_array.hpp>
24 #include <sys/cygwin.h>
25 #endif
26
27 namespace quickbook
28 {
29 // Not a general purpose normalization function, just
30 // from paths from the root directory. It strips the excess
31 // ".." parts from a path like: "x/../../y", leaving "y".
32 std::vector<fs::path> remove_dots_from_path(fs::path const& path)
33 {
34 assert(!path.has_root_directory() && !path.has_root_name());
35
36 std::vector<fs::path> parts;
37
38 BOOST_FOREACH(fs::path const& part, path)
39 {
40 if (part.empty() || part == ".") {
41 }
42 else if (part == "..") {
43 if (!parts.empty()) parts.pop_back();
44 }
45 else {
46 parts.push_back(part);
47 }
48 }
49
50 return parts;
51 }
52
53 // The relative path from base to path
54 fs::path path_difference(fs::path const& base, fs::path const& path, bool is_file)
55 {
56 fs::path
57 absolute_base = fs::absolute(base),
58 absolute_path = fs::absolute(path);
59
60 // Remove '.', '..' and empty parts from the remaining path
61 std::vector<fs::path>
62 base_parts = remove_dots_from_path(absolute_base.relative_path()),
63 path_parts = remove_dots_from_path(absolute_path.relative_path());
64
65 std::vector<fs::path>::iterator
66 base_it = base_parts.begin(),
67 base_end = base_parts.end(),
68 path_it = path_parts.begin(),
69 path_end = path_parts.end();
70
71 // Build up the two paths in these variables, checking for the first
72 // difference.
73 fs::path
74 base_tmp = absolute_base.root_path(),
75 path_tmp = absolute_path.root_path();
76
77 fs::path result;
78
79 // If they have different roots then there's no relative path so
80 // just build an absolute path.
81 if (!fs::equivalent(base_tmp, path_tmp))
82 {
83 result = path_tmp;
84 }
85 else
86 {
87 // Find the point at which the paths differ
88 for(; base_it != base_end && path_it != path_end; ++base_it, ++path_it)
89 {
90 base_tmp /= *base_it;
91 path_tmp /= *path_it;
92 if (*base_it != *path_it) {
93 if (!fs::exists(base_tmp) || !fs::exists(path_tmp) ||
94 !fs::equivalent(base_tmp, path_tmp)) {
95 break;
96 }
97 }
98 }
99
100 if (is_file && path_it == path_end && path_it != path_parts.begin()) {
101 --path_it;
102 result = "..";
103 } else if (base_it == base_end && path_it == path_end) {
104 result = ".";
105 }
106
107 // Build a relative path to that point
108 for(; base_it != base_end; ++base_it) result /= "..";
109 }
110
111 // Build the rest of our path
112 for(; path_it != path_end; ++path_it) result /= *path_it;
113
114 return result;
115 }
116
117 // Convert a Boost.Filesystem path to a URL.
118 //
119 // I'm really not sure about this, as the meaning of root_name and
120 // root_directory are only clear for windows.
121 //
122 // Some info on file URLs at:
123 // https://en.wikipedia.org/wiki/File_URI_scheme
124 std::string file_path_to_url_impl(fs::path const& x, bool is_dir)
125 {
126 fs::path::const_iterator it = x.begin(), end = x.end();
127 if (it == end) { return is_dir ? "./" : ""; }
128
129 std::string result;
130 bool sep = false;
131 std::string part;
132 if (x.has_root_name()) {
133 // Handle network address (e.g. \\example.com)
134 part = detail::path_to_generic(*it);
135 if (part.size() >= 2 && part[0] == '/' && part[1] == '/') {
136 result = "file:" + detail::escape_uri(part);
137 sep = true;
138 ++it;
139 if (it != end && *it == "/") {
140 result += "/";
141 sep = false;
142 ++it;
143 }
144 } else {
145 result = "file:///";
146 }
147
148 // Handle windows root (e.g. c:)
149 if (it != end) {
150 part = detail::path_to_generic(*it);
151 if (part.size() >= 2 && part[part.size() - 1] == ':') {
152 result += detail::escape_uri(part.substr(0, part.size()- 1));
153 result += ':';
154 sep = false;
155 ++it;
156 }
157 }
158 } else if (x.has_root_directory()) {
159 result = "file://";
160 sep = true;
161 } else if (*it == ".") {
162 result = ".";
163 sep = true;
164 ++it;
165 }
166
167 for (;it != end; ++it)
168 {
169 part = detail::path_to_generic(*it);
170 if (part == "/") {
171 result += "/";
172 sep = false;
173 } else if (part == ".") {
174 // If the path has a trailing slash, write it out,
175 // even if is_dir is false.
176 if (sep) {
177 result += "/";
178 sep = false;
179 }
180 } else {
181 if (sep) {
182 result += "/";
183 }
184 result += detail::escape_uri(detail::path_to_generic(*it));
185 sep = true;
186 }
187 }
188
189 if (is_dir && sep) {
190 result += "/";
191 }
192
193 return result;
194 }
195
196 std::string file_path_to_url(fs::path const& x) {
197 return file_path_to_url_impl(x, false);
198 }
199
200 std::string dir_path_to_url(fs::path const& x)
201 {
202 return file_path_to_url_impl(x, true);
203 }
204
205 namespace detail {
206 #if QUICKBOOK_WIDE_PATHS
207 std::string command_line_to_utf8(command_line_string const& x)
208 {
209 return to_utf8(x);
210 }
211 #else
212 std::string command_line_to_utf8(command_line_string const& x)
213 {
214 return x;
215 }
216 #endif
217
218 #if QUICKBOOK_WIDE_PATHS
219 fs::path generic_to_path(quickbook::string_view x)
220 {
221 return fs::path(from_utf8(x));
222 }
223
224 std::string path_to_generic(fs::path const& x)
225 {
226 return to_utf8(x.generic_wstring());
227 }
228 #else
229 fs::path generic_to_path(quickbook::string_view x)
230 {
231 return fs::path(x.begin(), x.end());
232 }
233
234 std::string path_to_generic(fs::path const& x)
235 {
236 return x.generic_string();
237 }
238 #endif
239
240 #if QUICKBOOK_CYGWIN_PATHS
241 fs::path command_line_to_path(command_line_string const& path)
242 {
243 cygwin_conv_path_t flags = CCP_POSIX_TO_WIN_W | CCP_RELATIVE;
244
245 ssize_t size = cygwin_conv_path(flags, path.c_str(), NULL, 0);
246
247 if (size < 0)
248 throw conversion_error("Error converting cygwin path to windows.");
249
250 boost::scoped_array<char> result(new char[size]);
251 void* ptr = result.get();
252
253 if(cygwin_conv_path(flags, path.c_str(), ptr, size))
254 throw conversion_error("Error converting cygwin path to windows.");
255
256 return fs::path(static_cast<wchar_t*>(ptr));
257 }
258
259 stream_string path_to_stream(fs::path const& path)
260 {
261 cygwin_conv_path_t flags = CCP_WIN_W_TO_POSIX | CCP_RELATIVE;
262
263 ssize_t size = cygwin_conv_path(flags, path.native().c_str(), NULL, 0);
264
265 if (size < 0)
266 throw conversion_error("Error converting windows path to cygwin.");
267
268 boost::scoped_array<char> result(new char[size]);
269
270 if(cygwin_conv_path(flags, path.native().c_str(), result.get(), size))
271 throw conversion_error("Error converting windows path to cygwin.");
272
273 return std::string(result.get());
274 }
275 #else
276 fs::path command_line_to_path(command_line_string const& path)
277 {
278 return fs::path(path);
279 }
280
281 #if QUICKBOOK_WIDE_PATHS && !QUICKBOOK_WIDE_STREAMS
282 stream_string path_to_stream(fs::path const& path)
283 {
284 return path.string();
285 }
286 #else
287 stream_string path_to_stream(fs::path const& path)
288 {
289 return path.native();
290 }
291 #endif
292
293 #endif // QUICKBOOK_CYGWIN_PATHS
294 }
295 }