]>
git.proxmox.com Git - ceph.git/blob - 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
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 =============================================================================*/
14 #include <boost/filesystem/operations.hpp>
15 #include <boost/range/algorithm/replace.hpp>
18 #include "include_paths.hpp"
22 #if QUICKBOOK_CYGWIN_PATHS
23 #include <sys/cygwin.h>
24 #include <boost/scoped_array.hpp>
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
)
34 assert(!path
.has_root_directory() && !path
.has_root_name());
36 std::vector
<fs::path
> parts
;
38 QUICKBOOK_FOR (fs::path
const& part
, path
) {
39 if (part
.empty() || part
== ".") {
41 else if (part
== "..") {
42 if (!parts
.empty()) parts
.pop_back();
45 parts
.push_back(part
);
52 // The relative path from base to path
53 fs::path
path_difference(
54 fs::path
const& base
, fs::path
const& path
, bool is_file
)
56 fs::path absolute_base
= fs::absolute(base
),
57 absolute_path
= fs::absolute(path
);
59 // Remove '.', '..' and empty parts from the remaining path
60 std::vector
<fs::path
> base_parts
= remove_dots_from_path(
61 absolute_base
.relative_path()),
62 path_parts
= remove_dots_from_path(
63 absolute_path
.relative_path());
65 std::vector
<fs::path
>::iterator base_it
= base_parts
.begin(),
66 base_end
= base_parts
.end(),
67 path_it
= path_parts
.begin(),
68 path_end
= path_parts
.end();
70 // Build up the two paths in these variables, checking for the first
72 fs::path base_tmp
= absolute_base
.root_path(),
73 path_tmp
= absolute_path
.root_path();
77 // If they have different roots then there's no relative path so
78 // just build an absolute path.
79 if (!fs::equivalent(base_tmp
, path_tmp
)) {
83 // Find the point at which the paths differ
84 for (; base_it
!= base_end
&& path_it
!= path_end
;
85 ++base_it
, ++path_it
) {
88 if (*base_it
!= *path_it
) {
89 if (!fs::exists(base_tmp
) || !fs::exists(path_tmp
) ||
90 !fs::equivalent(base_tmp
, path_tmp
)) {
96 if (is_file
&& path_it
== path_end
&&
97 path_it
!= path_parts
.begin()) {
101 else if (base_it
== base_end
&& path_it
== path_end
) {
105 // Build a relative path to that point
106 for (; base_it
!= base_end
; ++base_it
)
110 // Build the rest of our path
111 for (; path_it
!= path_end
; ++path_it
)
117 // Convert a Boost.Filesystem path to a URL.
119 // I'm really not sure about this, as the meaning of root_name and
120 // root_directory are only clear for windows.
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
)
126 fs::path::const_iterator it
= x
.begin(), end
= x
.end();
128 return is_dir
? "./" : "";
134 if (x
.has_root_name()) {
135 // Handle network address (e.g. \\example.com)
136 part
= detail::path_to_generic(*it
);
137 if (part
.size() >= 2 && part
[0] == '/' && part
[1] == '/') {
138 result
= "file:" + detail::escape_uri(part
);
141 if (it
!= end
&& *it
== "/") {
151 // Handle windows root (e.g. c:)
153 part
= detail::path_to_generic(*it
);
154 if (part
.size() >= 2 && part
[part
.size() - 1] == ':') {
156 detail::escape_uri(part
.substr(0, part
.size() - 1));
163 else if (x
.has_root_directory()) {
167 else if (*it
== ".") {
173 for (; it
!= end
; ++it
) {
174 part
= detail::path_to_generic(*it
);
179 else if (part
== ".") {
180 // If the path has a trailing slash, write it out,
181 // even if is_dir is false.
191 result
+= detail::escape_uri(detail::path_to_generic(*it
));
203 std::string
file_path_to_url(fs::path
const& x
)
205 return file_path_to_url_impl(x
, false);
208 std::string
dir_path_to_url(fs::path
const& x
)
210 return file_path_to_url_impl(x
, true);
215 #if QUICKBOOK_WIDE_PATHS
216 std::string
command_line_to_utf8(command_line_string
const& x
)
221 std::string
command_line_to_utf8(command_line_string
const& x
)
227 #if QUICKBOOK_WIDE_PATHS
228 fs::path
generic_to_path(quickbook::string_view x
)
230 return fs::path(from_utf8(x
));
233 std::string
path_to_generic(fs::path
const& x
)
235 return to_utf8(x
.generic_wstring());
238 fs::path
generic_to_path(quickbook::string_view x
)
240 return fs::path(x
.begin(), x
.end());
243 std::string
path_to_generic(fs::path
const& x
)
245 return x
.generic_string();
249 #if QUICKBOOK_CYGWIN_PATHS
250 fs::path
command_line_to_path(command_line_string
const& path
)
252 cygwin_conv_path_t flags
= CCP_POSIX_TO_WIN_W
| CCP_RELATIVE
;
254 ssize_t size
= cygwin_conv_path(flags
, path
.c_str(), NULL
, 0);
257 throw conversion_error(
258 "Error converting cygwin path to windows.");
260 boost::scoped_array
<char> result(new char[size
]);
261 void* ptr
= result
.get();
263 if (cygwin_conv_path(flags
, path
.c_str(), ptr
, size
))
264 throw conversion_error(
265 "Error converting cygwin path to windows.");
267 return fs::path(static_cast<wchar_t*>(ptr
));
270 stream_string
path_to_stream(fs::path
const& path
)
272 cygwin_conv_path_t flags
= CCP_WIN_W_TO_POSIX
| CCP_RELATIVE
;
275 cygwin_conv_path(flags
, path
.native().c_str(), NULL
, 0);
278 throw conversion_error(
279 "Error converting windows path to cygwin.");
281 boost::scoped_array
<char> result(new char[size
]);
283 if (cygwin_conv_path(
284 flags
, path
.native().c_str(), result
.get(), size
))
285 throw conversion_error(
286 "Error converting windows path to cygwin.");
288 return std::string(result
.get());
291 fs::path
command_line_to_path(command_line_string
const& path
)
293 return fs::path(path
);
296 #if QUICKBOOK_WIDE_PATHS && !QUICKBOOK_WIDE_STREAMS
297 stream_string
path_to_stream(fs::path
const& path
)
299 return path
.string();
302 stream_string
path_to_stream(fs::path
const& path
)
304 return path
.native();
308 #endif // QUICKBOOK_CYGWIN_PATHS
310 enum path_or_url_type
312 path_or_url_empty
= 0,
317 path_or_url::path_or_url() : type_(path_or_url_empty
) {}
319 path_or_url::path_or_url(path_or_url
const& x
)
320 : type_(x
.type_
), path_(x
.path_
), url_(x
.url_
)
324 path_or_url::path_or_url(command_line_string
const& x
)
326 auto rep
= command_line_to_utf8(x
);
327 auto it
= rep
.begin(), end
= rep
.end();
328 std::size_t count
= 0;
330 ((*it
>= 'a' && *it
<= 'z') || (*it
>= 'A' && *it
<= 'Z') ||
331 *it
== '+' || *it
== '-' || *it
== '.')) {
336 if (it
!= end
&& *it
== ':' && count
> 1) {
337 type_
= path_or_url_url
;
340 type_
= path_or_url_path
;
344 case path_or_url_empty
:
346 case path_or_url_path
:
347 path_
= command_line_to_path(x
);
349 case path_or_url_url
:
357 path_or_url
& path_or_url::operator=(path_or_url
const& x
)
365 path_or_url
& path_or_url::operator=(command_line_string
const& x
)
372 void path_or_url::swap(path_or_url
& x
)
374 std::swap(type_
, x
.type_
);
375 std::swap(path_
, x
.path_
);
376 std::swap(url_
, x
.url_
);
379 path_or_url
path_or_url::url(string_view x
)
382 r
.type_
= path_or_url_url
;
383 r
.url_
.assign(x
.begin(), x
.end());
387 path_or_url
path_or_url::path(boost::filesystem::path
const& x
)
390 r
.type_
= path_or_url_path
;
395 path_or_url::operator bool() const
397 return type_
!= path_or_url_empty
;
400 bool path_or_url::is_path() const { return type_
== path_or_url_path
; }
402 bool path_or_url::is_url() const { return type_
== path_or_url_url
; }
404 boost::filesystem::path
const& path_or_url::get_path() const
410 std::string
const& path_or_url::get_url() const
416 path_or_url
path_or_url::operator/(string_view x
) const
422 case path_or_url_empty
:
425 case path_or_url_path
:
426 r
.path_
= path_
/ x
.to_s();
428 case path_or_url_url
: {
430 auto pos
= r
.url_
.rfind('/');
431 if (pos
== std::string::npos
) {
432 pos
= r
.url_
.rfind(':');
434 if (pos
!= std::string::npos
) {
435 r
.url_
.resize(pos
+ 1);
438 // Error? Empty string?