5#include <initializer_list>
18 static std::string
join(std::initializer_list<std::string> sections)
20 return join(std::vector<std::string>(sections));
23 template<
typename... Args>
24 static std::string
join(
const std::string& first,
const Args&... rest)
26 std::vector<std::string> sections;
27 sections.reserve(1 +
sizeof...(rest));
28 sections.push_back(first);
29 (sections.push_back(rest), ...);
30 return join(sections);
33 static std::string
join(
const std::vector<std::string>& sections)
35 if (sections.empty()) {
39 std::string result = sections.front();
40 for (
size_t i = 0; i < sections.size() - 1; ++i) {
41 const std::string& one = sections[i];
42 const std::string& two = sections[i + 1];
44 if (!two.empty() && two[0] ==
delimiter) {
49 if (!one.empty() && !two.empty() && one[one.length() - 1] !=
delimiter && two[0] !=
delimiter) {
60 static std::string
normalize(
const std::string& pathname)
62 const bool lead = !pathname.empty() && pathname.front() ==
delimiter;
63 const bool trail = !pathname.empty() && pathname.back() ==
delimiter;
65 std::vector<std::string> parts;
67 for (
char ch : pathname) {
70 parts.push_back(token);
78 parts.push_back(token);
81 std::vector<std::string> cleaned;
82 for (
const std::string& part : parts) {
83 if (part.empty() || part ==
".") {
86 if (part ==
".." && !cleaned.empty())
91 cleaned.push_back(part);
99 for (
size_t i = 0; i < cleaned.size(); ++i) {
103 result += cleaned[i];
106 if (trail && (result.empty() || result.back() !=
delimiter)) {
110 if (!lead && !result.empty() && result.front() ==
delimiter) {
111 result.erase(result.begin());
117 static std::pair<std::string, std::string>
split(
const std::string& pathname)
119 const size_t lastDelimiter = pathname.find_last_of(
delimiter);
120 if (lastDelimiter == std::string::npos) {
121 return {
"", pathname};
124 return {pathname.substr(0, lastDelimiter), pathname.substr(lastDelimiter + 1)};
129 return split(pathname).second;
134 return split(pathname).first;
139 const std::string pathNoQuery = pathname.substr(0, pathname.find(
'?'));
140 const size_t dot = pathNoQuery.find_last_of(
'.');
141 if (dot == std::string::npos) {
144 return pathNoQuery.substr(dot);
149 if (pathname.empty()) {
153 return pathname.front() !=
delimiter && !std::regex_search(pathname, std::regex(R
"(:\/\/)"));
158 std::vector<std::string> parts;
160 for (
char ch : pathname) {
162 parts.push_back(token);
168 parts.push_back(token);
170 if (parts.size() <= 1) {
175 if (
isRelativePath(pathname) && parts[0] !=
"." && parts[0] !=
"..") {
179 for (
size_t i = 0; i + 1 < parts.size(); ++i) {
180 if (i > 0 || !result.empty()) {
static std::string normalize(const std::string &pathname)
static constexpr char delimiter
static std::string extractPath(const std::string &pathname)
static bool isRelativePath(const std::string &pathname)
static std::string getExtension(const std::string &pathname)
static std::pair< std::string, std::string > split(const std::string &pathname)
static std::string getDirectory(const std::string &pathname)
static std::string join(const std::string &first, const Args &... rest)
static std::string join(std::initializer_list< std::string > sections)
static std::string getBasename(const std::string &pathname)
static std::string join(const std::vector< std::string > §ions)