| 732 | } |
| 733 | |
| 734 | std::string lexically_relative_normal(string_view base |
| 735 | , string_view target, error_code& ec) |
| 736 | { |
| 737 | // strip shared leading components from base and target |
| 738 | auto b = lsplit_path(base); |
| 739 | auto t = lsplit_path(target); |
| 740 | while (!b.first.empty() && b.first == t.first) |
| 741 | { |
| 742 | b = lsplit_path(b.second); |
| 743 | t = lsplit_path(t.second); |
| 744 | } |
| 745 | |
| 746 | // any leftover in base means target lies outside base (sibling, |
| 747 | // ancestor, or different root) |
| 748 | if (!b.first.empty()) |
| 749 | { |
| 750 | ec = make_error_code(boost::system::errc::invalid_argument); |
| 751 | return {}; |
| 752 | } |
| 753 | |
| 754 | // resolve the remainder of target into a component stack |
| 755 | std::vector<string_view> components; |
| 756 | for (; !t.first.empty(); t = lsplit_path(t.second)) |
| 757 | { |
| 758 | if (t.first == ".") continue; |
| 759 | if (t.first == "..") |
| 760 | { |
| 761 | if (components.empty()) |
| 762 | { |
| 763 | ec = make_error_code(boost::system::errc::invalid_argument); |
| 764 | return {}; |
| 765 | } |
| 766 | components.pop_back(); |
| 767 | continue; |
| 768 | } |
| 769 | components.push_back(t.first); |
| 770 | } |
| 771 | |
| 772 | std::string ret; |
| 773 | for (auto const& c : components) |
| 774 | { |
| 775 | if (!ret.empty()) ret += TORRENT_SEPARATOR_CHAR; |
| 776 | ret.append(c.data(), c.size()); |
| 777 | } |
| 778 | return ret; |
| 779 | } |
| 780 | |
| 781 | std::string current_working_directory() |
| 782 | { |