mirror of https://github.com/mamba-org/mamba.git
1630 lines
44 KiB
C++
1630 lines
44 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
// Neither the name of the organization Sony Pictures Imageworks nor the
|
|
// names of its contributors
|
|
// may be used to endorse or promote products derived from this software
|
|
// without specific prior written permission.
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS
|
|
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER
|
|
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL,
|
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef PYSTRING_HPP
|
|
#define PYSTRING_HPP
|
|
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include "pystring_utils.hpp"
|
|
|
|
#include "pystring_header.hpp"
|
|
|
|
namespace pystring
|
|
{
|
|
|
|
using namespace std::string_literals;
|
|
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
|
|
#ifndef WINDOWS
|
|
#define WINDOWS
|
|
#endif
|
|
#endif
|
|
|
|
// This definition codes from configure.in in the python src.
|
|
// Strictly speaking this limits us to str sizes of 2**31.
|
|
// Should we wish to handle this limit, we could use an architecture
|
|
// specific #defines and read from ssize_t (unistd.h) if the header exists.
|
|
// But in the meantime, the use of std::ptrdiff_t assures maximum arch compatibility.
|
|
// This must also equal the size used in the end = MAX_32BIT_INT default arg.
|
|
|
|
/* helper macro to fixup start/end slice values */
|
|
#define ADJUST_INDICES(start, end, len) \
|
|
if (end > len) \
|
|
end = len; \
|
|
else if (end < 0) { \
|
|
end += len; \
|
|
if (end < 0) \
|
|
end = 0; \
|
|
} \
|
|
if (start < 0) { \
|
|
start += len; \
|
|
if (start < 0) \
|
|
start = 0; \
|
|
}
|
|
|
|
enum strip_dir
|
|
{
|
|
left,
|
|
right,
|
|
both
|
|
};
|
|
|
|
namespace {
|
|
|
|
void split_whitespace(const string_view& str, std::vector<string_view>& result, std::ptrdiff_t maxsplit)
|
|
{
|
|
std::size_t i, j, len = str.size();
|
|
|
|
for (i = j = 0; i < len;) {
|
|
while (i < len && ::isspace(str[i]))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
j = i;
|
|
|
|
while (i < len && !::isspace(str[i]))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
if (j < i) {
|
|
if (maxsplit-- <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
result.push_back(str.substr(j, i - j));
|
|
|
|
while (i < len && ::isspace(str[i])) {
|
|
i++;
|
|
}
|
|
j = i;
|
|
}
|
|
}
|
|
if (j < len) {
|
|
result.push_back(str.substr(j, len - j));
|
|
}
|
|
}
|
|
|
|
void rsplit_whitespace(const string_view& str, std::vector<string_view>& result, std::ptrdiff_t maxsplit)
|
|
{
|
|
std::size_t len = str.size();
|
|
std::size_t i, j;
|
|
for (i = j = len; i > 0;)
|
|
{
|
|
while (i > 0 && ::isspace(str[i - 1]))
|
|
{
|
|
i--;
|
|
}
|
|
j = i;
|
|
|
|
while (i > 0 && !::isspace(str[i - 1]))
|
|
{
|
|
i--;
|
|
}
|
|
|
|
if (j > i)
|
|
{
|
|
if (maxsplit-- <= 0)
|
|
break;
|
|
|
|
result.push_back(str.substr(i, j - i));
|
|
|
|
while (i > 0 && ::isspace(str[i - 1]))
|
|
i--;
|
|
j = i;
|
|
}
|
|
}
|
|
if (j > 0)
|
|
{
|
|
result.push_back(str.substr(0, j));
|
|
}
|
|
|
|
std::reverse(result.begin(), result.end());
|
|
}
|
|
} // namespace
|
|
|
|
std::vector<string_view> split(const string_view& str, const string_view& sep, std::ptrdiff_t maxsplit)
|
|
{
|
|
std::vector<string_view> result;
|
|
|
|
if (maxsplit < 0)
|
|
{
|
|
maxsplit = std::numeric_limits<std::ptrdiff_t>::max(); // result.max_size();
|
|
}
|
|
|
|
if (detail::size(sep) == 0)
|
|
{
|
|
split_whitespace(str, result, maxsplit);
|
|
return result;
|
|
}
|
|
|
|
std::size_t i, j, len = str.size(), n = sep.size();
|
|
|
|
i = j = 0;
|
|
|
|
while (i + n <= len)
|
|
{
|
|
if (str[i] == sep[0] && str.substr(i, n) == sep)
|
|
{
|
|
if (maxsplit-- <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
result.push_back(str.substr(j, i - j));
|
|
i = j = i + n;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
result.push_back(str.substr(j, len - j));
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<string_view> rsplit(const string_view& str, const string_view& sep, std::ptrdiff_t maxsplit)
|
|
{
|
|
if (maxsplit < 0)
|
|
{
|
|
return split(str, sep, maxsplit);
|
|
}
|
|
|
|
std::vector<string_view> result;
|
|
|
|
if (sep.size() == 0)
|
|
{
|
|
rsplit_whitespace(str, result, maxsplit);
|
|
return result;
|
|
}
|
|
|
|
std::ptrdiff_t i, j, len = static_cast<std::ptrdiff_t>(str.size()),
|
|
n = static_cast<std::ptrdiff_t>(sep.size());
|
|
|
|
i = j = len;
|
|
|
|
while (i >= n)
|
|
{
|
|
if (str[i - 1] == sep[n - 1] && str.substr(i - n, n) == sep)
|
|
{
|
|
if (maxsplit-- <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
result.push_back(str.substr(i, j - i));
|
|
i = j = i - n;
|
|
}
|
|
else
|
|
{
|
|
i--;
|
|
}
|
|
}
|
|
|
|
result.push_back(str.substr(0, j));
|
|
std::reverse(result.begin(), result.end());
|
|
|
|
return result;
|
|
}
|
|
|
|
template <class S = std::string>
|
|
string_view do_strip(const string_view& str, strip_dir striptype, const string_view& chars)
|
|
{
|
|
std::ptrdiff_t i, j;
|
|
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(str.size());
|
|
std::ptrdiff_t charslen = static_cast<std::ptrdiff_t>(chars.size());
|
|
|
|
if (charslen == 0)
|
|
{
|
|
i = 0;
|
|
if (striptype != strip_dir::right)
|
|
{
|
|
while (i < len && ::isspace(str[i]))
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
j = len;
|
|
if (striptype != strip_dir::left)
|
|
{
|
|
do
|
|
{
|
|
j--;
|
|
}
|
|
while (j >= i && ::isspace(str[j]));
|
|
|
|
j++;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// TODO check that this still works without \0 termination
|
|
const char* sep = &chars[0];
|
|
|
|
i = 0;
|
|
if (striptype != strip_dir::right)
|
|
{
|
|
while (i < len && memchr(sep, str[i], charslen))
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
j = len;
|
|
if (striptype != strip_dir::left)
|
|
{
|
|
do
|
|
{
|
|
j--;
|
|
}
|
|
while (j >= i && memchr(sep, str[j], charslen));
|
|
j++;
|
|
}
|
|
}
|
|
|
|
if (i == 0 && j == len)
|
|
{
|
|
return str;
|
|
}
|
|
else
|
|
{
|
|
return str.substr(i, j - i);
|
|
}
|
|
}
|
|
|
|
template <class S>
|
|
std::array<string_view, 3> partition(const string_view& str, const string_view& sep)
|
|
{
|
|
std::array<string_view, 3> result;
|
|
std::ptrdiff_t index = find(str, sep);
|
|
|
|
if (index < 0)
|
|
{
|
|
result[0] = str;
|
|
result[1] = "";
|
|
result[2] = "";
|
|
}
|
|
else
|
|
{
|
|
result[0] = str.substr(0, index);
|
|
result[1] = sep;
|
|
result[2] = str.substr(index + sep.size(), str.size());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <class S>
|
|
std::array<string_view, 3> rpartition(const string_view& str, const string_view& sep)
|
|
{
|
|
std::array<string_view, 3> result;
|
|
std::ptrdiff_t index = rfind(str, sep);
|
|
|
|
if (index < 0)
|
|
{
|
|
result[0] = "";
|
|
result[1] = "";
|
|
result[2] = str;
|
|
}
|
|
else
|
|
{
|
|
result[0] = str.substr(0, index);
|
|
result[1] = sep;
|
|
result[2] = str.substr(index + sep.size(), str.size());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
string_view strip(const string_view& str, const string_view& chars)
|
|
{
|
|
return do_strip(str, strip_dir::both, chars);
|
|
}
|
|
|
|
string_view lstrip(const string_view& str, const string_view& chars)
|
|
{
|
|
return do_strip(str, strip_dir::left, chars);
|
|
}
|
|
|
|
string_view rstrip(const string_view& str, const string_view& chars)
|
|
{
|
|
return do_strip(str, strip_dir::right, chars);
|
|
}
|
|
|
|
template <class S, class C>
|
|
string join(const S& str, const C& seq)
|
|
{
|
|
std::size_t seqlen = detail::size(seq), i;
|
|
|
|
if (seqlen == 0)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
std::ostringstream buf;
|
|
buf << seq[0];
|
|
for (i = 1; i < seqlen; ++i)
|
|
{
|
|
buf << str << seq[i];
|
|
}
|
|
|
|
return buf.str();
|
|
}
|
|
|
|
namespace {
|
|
|
|
/********************************************************************
|
|
* Matches the end (direction >= 0) or start (direction < 0) of self
|
|
* against substr, using the start and end arguments. Returns
|
|
* -1 on error, 0 if not found and 1 if found.
|
|
********************************************************************/
|
|
template <class S, class C>
|
|
std::ptrdiff_t _string_tailmatch(const S& self, const C& substr,
|
|
std::ptrdiff_t start, std::ptrdiff_t end, std::ptrdiff_t direction)
|
|
{
|
|
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(detail::size(self));
|
|
std::ptrdiff_t slen = static_cast<std::ptrdiff_t>(detail::size(substr));
|
|
|
|
const char* sub = detail::c_str(substr);
|
|
const char* str = detail::c_str(self);
|
|
|
|
ADJUST_INDICES(start, end, len);
|
|
|
|
if (direction < 0)
|
|
{
|
|
// startswith
|
|
if (start + slen > len)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// endswith
|
|
if (end - start < slen || start > len)
|
|
{
|
|
return 0;
|
|
}
|
|
if (end - slen > start)
|
|
{
|
|
start = end - slen;
|
|
}
|
|
}
|
|
if (end - start >= slen)
|
|
{
|
|
return (!std::memcmp(str + start, sub, slen));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
} // namespace
|
|
|
|
template <class S = std::string, class C = S>
|
|
bool endswith(const S& str, const C& suffix, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
std::ptrdiff_t result = _string_tailmatch(str, suffix, (std::ptrdiff_t)start, (std::ptrdiff_t)end, +1);
|
|
// if (result == -1) // TODO: Error condition
|
|
|
|
return static_cast<bool>(result);
|
|
}
|
|
|
|
template <class S = std::string, class C>
|
|
bool startswith(const S& str, const C& prefix, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
std::ptrdiff_t result = _string_tailmatch(str, prefix, (std::ptrdiff_t)start, (std::ptrdiff_t)end, -1);
|
|
// if (result == -1) // TODO: Error condition
|
|
|
|
return static_cast<bool>(result);
|
|
}
|
|
|
|
template <class S = std::string>
|
|
bool isalnum(const S& str)
|
|
{
|
|
auto it = std::begin(str),
|
|
end = detail::fast_end(str);
|
|
if (it == end)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (; it != end; ++it)
|
|
{
|
|
if (::isalnum(*it) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <class S = std::string>
|
|
bool isalpha(const S& str)
|
|
{
|
|
auto it = std::begin(str),
|
|
end = detail::fast_end(str);
|
|
if (it == end)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (; it != end; ++it)
|
|
{
|
|
if (!::isalpha(*it))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool isdigit(const string_view& str)
|
|
{
|
|
std::size_t len = str.size(), i;
|
|
if (len == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (!::isdigit(str[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool islower(const string_view& str)
|
|
{
|
|
std::size_t len = str.size(), i;
|
|
if (len == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (!::islower(str[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool isspace(const string_view& str)
|
|
{
|
|
std::size_t len = str.size(), i;
|
|
if (len == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (!::isspace(str[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool istitle(const string_view& str)
|
|
{
|
|
std::size_t len = str.size(), i;
|
|
|
|
if (len == 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (len == 1)
|
|
{
|
|
return ::isupper(str[0]);
|
|
}
|
|
|
|
bool cased = false, previous_is_cased = false;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (::isupper(str[i]))
|
|
{
|
|
if (previous_is_cased)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
previous_is_cased = true;
|
|
cased = true;
|
|
}
|
|
else if (::islower(str[i]))
|
|
{
|
|
if (!previous_is_cased)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
previous_is_cased = true;
|
|
cased = true;
|
|
|
|
} else
|
|
{
|
|
previous_is_cased = false;
|
|
}
|
|
}
|
|
|
|
return cased;
|
|
}
|
|
|
|
bool isupper(const string_view& str)
|
|
{
|
|
std::size_t len = str.size(), i;
|
|
if (len == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (!::isupper(str[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <class S>
|
|
S capitalize(const S& str)
|
|
{
|
|
S s(str);
|
|
std::size_t len = detail::size(s), i;
|
|
|
|
if (len > 0 && ::islower(s[0]))
|
|
{
|
|
s[0] = (char)::toupper(s[0]);
|
|
}
|
|
|
|
for (i = 1; i < len; ++i)
|
|
{
|
|
if (::isupper(s[i]))
|
|
{
|
|
s[i] = (char)::tolower(s[i]);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
template <class S>
|
|
S lower(const S& str)
|
|
{
|
|
S s(str);
|
|
std::size_t len = detail::size(s), i;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (::isupper(s[i]))
|
|
{
|
|
s[i] = (char)::tolower(s[i]);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
template <class S>
|
|
S upper(const S& str)
|
|
{
|
|
S s(str);
|
|
std::size_t len = detail::size(s), i;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (::islower(s[i]))
|
|
{
|
|
s[i] = (char)::toupper(s[i]);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
template <class S>
|
|
S swapcase(const S& str)
|
|
{
|
|
S s(str);
|
|
std::size_t len = detail::size(s), i;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (::islower(s[i]))
|
|
{
|
|
s[i] = (char)::toupper(s[i]);
|
|
}
|
|
else if (::isupper(s[i]))
|
|
{
|
|
s[i] = (char)::tolower(s[i]);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
template <class S>
|
|
S title(const S& str)
|
|
{
|
|
S s(str);
|
|
std::size_t len = detail::size(s), i;
|
|
bool previous_is_cased = false;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
std::ptrdiff_t c = s[i];
|
|
if (::islower(c))
|
|
{
|
|
if (!previous_is_cased)
|
|
{
|
|
s[i] = (char)::toupper(c);
|
|
}
|
|
previous_is_cased = true;
|
|
}
|
|
else if (::isupper(c))
|
|
{
|
|
if (previous_is_cased)
|
|
{
|
|
s[i] = (char)::tolower(c);
|
|
}
|
|
previous_is_cased = true;
|
|
}
|
|
else
|
|
{
|
|
previous_is_cased = false;
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
template <class S>
|
|
string translate(const S& str, const string_view& table, const string_view& deletechars)
|
|
{
|
|
string s;
|
|
std::size_t len = detail::size(str), del_len = deletechars.size();
|
|
|
|
if (table.size() != 256)
|
|
{
|
|
// TODO : raise exception instead
|
|
return str;
|
|
}
|
|
|
|
// if nothing is deleted, use faster code
|
|
if (del_len == 0)
|
|
{
|
|
s = str;
|
|
for (std::size_t i = 0; i < len; ++i)
|
|
{
|
|
s[i] = table[s[i]];
|
|
}
|
|
return s;
|
|
}
|
|
|
|
std::ptrdiff_t trans_table[256];
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
trans_table[i] = table[i];
|
|
}
|
|
|
|
for (std::size_t i = 0; i < del_len; i++)
|
|
{
|
|
trans_table[(std::size_t) deletechars[i]] = -1;
|
|
}
|
|
|
|
for (std::size_t i = 0; i < len; ++i)
|
|
{
|
|
if (trans_table[(std::size_t) str[i]] != -1)
|
|
{
|
|
s += table[str[i]];
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
struct fillstream
|
|
{
|
|
char c;
|
|
std::ptrdiff_t n;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& str, const fillstream& fs)
|
|
{
|
|
for (std::ptrdiff_t i = 0; i < fs.n; ++i)
|
|
{
|
|
str << fs.c;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
string zfill(const string_view& str, std::ptrdiff_t width)
|
|
{
|
|
std::ptrdiff_t len = (std::ptrdiff_t)str.size();
|
|
|
|
if (len >= width)
|
|
{
|
|
return std::string(str.begin(), str.end());
|
|
}
|
|
|
|
std::ostringstream os;
|
|
|
|
std::ptrdiff_t fill = width - len;
|
|
|
|
os << fillstream{'0', fill} << str;
|
|
std::string s = os.str();
|
|
|
|
if (s[fill] == '+' || s[fill] == '-')
|
|
{
|
|
s[0] = s[fill];
|
|
s[fill] = '0';
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
string ljust(const string_view& str, std::ptrdiff_t width)
|
|
{
|
|
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(str.size());
|
|
std::ostringstream os;
|
|
os << str << fillstream{' ', width - len};
|
|
return os.str();
|
|
}
|
|
|
|
string rjust(const string_view& str, std::ptrdiff_t width)
|
|
{
|
|
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(str.size());
|
|
std::ostringstream os;
|
|
os << fillstream{' ', width - len} << str;
|
|
return os.str();
|
|
}
|
|
|
|
string center(const string_view& str, std::ptrdiff_t width)
|
|
{
|
|
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(str.size());
|
|
std::ptrdiff_t marg, left;
|
|
std::ostringstream os;
|
|
marg = width - len;
|
|
left = marg / 2 + (marg & width & 1);
|
|
os << fillstream{' ', left} << str << fillstream{' ', marg - left};
|
|
return os.str();
|
|
}
|
|
|
|
string_view slice(const string_view& str, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
ADJUST_INDICES(start, end, (std::ptrdiff_t) str.size());
|
|
if (start >= end)
|
|
return string_view(nullptr, 0);
|
|
return str.substr(start, end - start);
|
|
}
|
|
|
|
template <class S>
|
|
std::ptrdiff_t find(const string_view& str, const S& sub, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
ADJUST_INDICES(start, end, (std::ptrdiff_t) detail::size(str));
|
|
|
|
if (str.size() == 0 && detail::size(sub) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
string_view::size_type result = str.find(sub, start);
|
|
|
|
// If we cannot find the string, or if the end-point of our found substring is past
|
|
// the allowed end limit, return that it can't be found.
|
|
if(result == string_view::npos || (result + detail::size(sub) > (std::string::size_type) end))
|
|
{
|
|
return -1;
|
|
}
|
|
return (ptrdiff_t) result;
|
|
}
|
|
|
|
template <class S>
|
|
std::ptrdiff_t index(const string_view& str, const S& sub, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
return find(str, sub, start, end);
|
|
}
|
|
|
|
template <class S>
|
|
std::ptrdiff_t rfind(const string_view& str, const S& sub, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
ADJUST_INDICES(start, end, (std::ptrdiff_t) str.size());
|
|
|
|
string::size_type result = str.rfind(sub, end);
|
|
|
|
if (result == std::string::npos || result < (string::size_type) start || (result + detail::size(sub) > (string::size_type) end))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return (std::ptrdiff_t) result;
|
|
}
|
|
|
|
template <class S>
|
|
std::ptrdiff_t rindex(const string_view& str, const S& sub, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
return rfind(str, sub, start, end);
|
|
}
|
|
|
|
string expandtabs(const string_view& str, std::ptrdiff_t tabsize)
|
|
{
|
|
std::ostringstream os;
|
|
std::size_t len = str.size(), i = 0;
|
|
std::ptrdiff_t j = 0;
|
|
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (str[i] == '\t')
|
|
{
|
|
if (tabsize > 0)
|
|
{
|
|
std::ptrdiff_t fillsize = tabsize - (j % tabsize);
|
|
j += fillsize;
|
|
os << fillstream{' ', fillsize};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
j++;
|
|
if (str[i] == '\n' || str[i] == '\r')
|
|
{
|
|
j = 0;
|
|
}
|
|
os << str[i];
|
|
}
|
|
}
|
|
|
|
return os.str();
|
|
}
|
|
|
|
std::ptrdiff_t count(const string_view& str, const string_view& substr, std::ptrdiff_t start, std::ptrdiff_t end)
|
|
{
|
|
std::ptrdiff_t nummatches = 0;
|
|
std::ptrdiff_t cursor = start;
|
|
|
|
while (1) {
|
|
cursor = find(str, substr, cursor, end);
|
|
|
|
if (cursor < 0)
|
|
break;
|
|
|
|
cursor += (std::ptrdiff_t) detail::size(substr);
|
|
nummatches += 1;
|
|
}
|
|
|
|
return nummatches;
|
|
}
|
|
|
|
template <class S, class T, class U>
|
|
string replace(const S& str, const T& oldstr, const U& newstr, std::ptrdiff_t count)
|
|
{
|
|
std::ptrdiff_t sofar = 0;
|
|
std::ptrdiff_t cursor = 0;
|
|
string s(str);
|
|
|
|
std::size_t oldlen = detail::size(oldstr), newlen = detail::size(newstr);
|
|
|
|
cursor = find(s, oldstr, cursor);
|
|
|
|
while (cursor != -1 && cursor <= (std::ptrdiff_t) s.size()) {
|
|
if (count > -1 && sofar >= count) {
|
|
break;
|
|
}
|
|
|
|
s.replace(cursor, oldlen, newstr);
|
|
cursor += (std::ptrdiff_t)newlen;
|
|
|
|
if (oldlen != 0) {
|
|
cursor = find(s, oldstr, cursor);
|
|
} else {
|
|
++cursor;
|
|
}
|
|
|
|
++sofar;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
std::vector<string_view> splitlines(const string_view& str, bool keepends)
|
|
{
|
|
std::vector<string_view> result;
|
|
std::size_t len = str.size(), i, j, eol;
|
|
|
|
string_view stv(str);
|
|
for (i = j = 0; i < len;)
|
|
{
|
|
while (i < len && stv[i] != '\n' && stv[i] != '\r')
|
|
i++;
|
|
|
|
eol = i;
|
|
if (i < len) {
|
|
if (stv[i] == '\r' && i + 1 < len && stv[i + 1] == '\n') {
|
|
i += 2;
|
|
} else {
|
|
i++;
|
|
}
|
|
if (keepends)
|
|
eol = i;
|
|
}
|
|
|
|
result.push_back(stv.substr(j, eol - j));
|
|
j = i;
|
|
}
|
|
|
|
if (j < len)
|
|
{
|
|
result.push_back(stv.substr(j, len - j));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <class S>
|
|
string mul(const string_view& str, std::ptrdiff_t n)
|
|
{
|
|
// Early exits
|
|
if (n <= 0)
|
|
return "";
|
|
|
|
if (n == 1)
|
|
{
|
|
return std::string(str.begin(), str.end());
|
|
}
|
|
|
|
std::ostringstream os;
|
|
for (int i = 0; i < n; ++i) {
|
|
os << str;
|
|
}
|
|
return os.str();
|
|
}
|
|
|
|
// namespace os
|
|
// {
|
|
// namespace path
|
|
// {
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
// /// These functions are C++ ports of the python2.6 versions of os.path,
|
|
// /// and come from genericpath.py, ntpath.py, posixpath.py
|
|
|
|
// /// Split a pathname into drive and path specifiers.
|
|
// /// Returns drivespec, pathspec. Either part may be empty.
|
|
// void splitdrive_nt(std::string & drivespec, std::string & pathspec,
|
|
// const std::string & p)
|
|
// {
|
|
// if(pystring::slice(p, 1, 2) == ":")
|
|
// {
|
|
// std::string path = p; // In case drivespec == p
|
|
// drivespec = pystring::slice(path, 0, 2);
|
|
// pathspec = pystring::slice(path, 2);
|
|
// }
|
|
// else
|
|
// {
|
|
// drivespec = "";
|
|
// pathspec = p;
|
|
// }
|
|
// }
|
|
|
|
// // On Posix, drive is always empty
|
|
// void splitdrive_posix(std::string & drivespec, std::string & pathspec,
|
|
// const std::string & path)
|
|
// {
|
|
// drivespec = "";
|
|
// pathspec = path;
|
|
// }
|
|
|
|
// void splitdrive(std::string & drivespec, std::string & pathspec,
|
|
// const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return splitdrive_nt(drivespec, pathspec, path);
|
|
// #else
|
|
// return splitdrive_posix(drivespec, pathspec, path);
|
|
// #endif
|
|
// }
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
// // Test whether a path is absolute
|
|
// // In windows, if the character to the right of the colon
|
|
// // is a forward or backslash it's absolute.
|
|
// bool isabs_nt(const std::string & path)
|
|
// {
|
|
// std::string drivespec, pathspec;
|
|
// splitdrive_nt(drivespec, pathspec, path);
|
|
// if(pathspec.empty()) return false;
|
|
// return ((pathspec[0] == '/') || (pathspec[0] == '\\'));
|
|
// }
|
|
|
|
// bool isabs_posix(const std::string & s)
|
|
// {
|
|
// return pystring::startswith(s, "/"s);
|
|
// }
|
|
|
|
// bool isabs(const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return isabs_nt(path);
|
|
// #else
|
|
// return isabs_posix(path);
|
|
// #endif
|
|
// }
|
|
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
// std::string abspath_nt(const std::string & path, const std::string & cwd)
|
|
// {
|
|
// std::string p = path;
|
|
// if(!isabs_nt(p)) p = join_nt(cwd, p);
|
|
// return normpath_nt(p);
|
|
// }
|
|
|
|
// std::string abspath_posix(const std::string & path, const std::string & cwd)
|
|
// {
|
|
// std::string p = path;
|
|
// if(!isabs_posix(p)) p = join_posix(cwd, p);
|
|
// return normpath_posix(p);
|
|
// }
|
|
|
|
// std::string abspath(const std::string & path, const std::string & cwd)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return abspath_nt(path, cwd);
|
|
// #else
|
|
// return abspath_posix(path, cwd);
|
|
// #endif
|
|
// }
|
|
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
// std::string join_nt(const std::vector< std::string > & paths)
|
|
// {
|
|
// if(paths.empty()) return "";
|
|
// if(paths.size() == 1) return paths[0];
|
|
|
|
// std::string path = paths[0];
|
|
|
|
// for(std::size_t i = 1; i < paths.size(); ++i)
|
|
// {
|
|
// std::string b = paths[i];
|
|
|
|
// bool b_nts = false;
|
|
// if(path.empty())
|
|
// {
|
|
// b_nts = true;
|
|
// }
|
|
// else if(isabs_nt(b))
|
|
// {
|
|
// // This probably wipes out path so far. However, it's more
|
|
// // complicated if path begins with a drive letter:
|
|
// // 1. join('c:', '/a') == 'c:/a'
|
|
// // 2. join('c:/', '/a') == 'c:/a'
|
|
// // But
|
|
// // 3. join('c:/a', '/b') == '/b'
|
|
// // 4. join('c:', 'd:/') = 'd:/'
|
|
// // 5. join('c:/', 'd:/') = 'd:/'
|
|
|
|
// if( (pystring::slice(path, 1, 2) != ":") ||
|
|
// (pystring::slice(b, 1, 2) == ":") )
|
|
// {
|
|
// // Path doesnt start with a drive letter
|
|
// b_nts = true;
|
|
// }
|
|
// // Else path has a drive letter, and b doesn't but is absolute.
|
|
// else if((path.size()>3) ||
|
|
// ((path.size()==3) && !pystring::endswith(path, "/"s) && !pystring::endswith(path, "\\"s)))
|
|
// {
|
|
// b_nts = true;
|
|
// }
|
|
// }
|
|
|
|
// if(b_nts)
|
|
// {
|
|
// path = b;
|
|
// }
|
|
// else
|
|
// {
|
|
// // Join, and ensure there's a separator.
|
|
// // assert len(path) > 0
|
|
// if( pystring::endswith(path, "/"s) || pystring::endswith(path, "\\"s))
|
|
// {
|
|
// if(pystring::startswith(b,"/"s) || pystring::startswith(b,"\\"s))
|
|
// {
|
|
// path += pystring::slice(b, 1);
|
|
// }
|
|
// else
|
|
// {
|
|
// path += b;
|
|
// }
|
|
// }
|
|
// else if(pystring::endswith(path, ":"))
|
|
// {
|
|
// path += b;
|
|
// }
|
|
// else if(!b.empty())
|
|
// {
|
|
// if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
|
|
// {
|
|
// path += b;
|
|
// }
|
|
// else
|
|
// {
|
|
// path += "\\" + b;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// // path is not empty and does not end with a backslash,
|
|
// // but b is empty; since, e.g., split('a/') produces
|
|
// // ('a', ''), it's best if join() adds a backslash in
|
|
// // this case.
|
|
// path += "\\";
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// return path;
|
|
// }
|
|
|
|
// // Join two or more pathname components, inserting "\\" as needed.
|
|
// std::string join_nt(const std::string & a, const std::string & b)
|
|
// {
|
|
// std::vector< std::string > paths(2);
|
|
// paths[0] = a;
|
|
// paths[1] = b;
|
|
// return join_nt(paths);
|
|
// }
|
|
|
|
// // Join pathnames.
|
|
// // If any component is an absolute path, all previous path components
|
|
// // will be discarded.
|
|
// // Ignore the previous parts if a part is absolute.
|
|
// // Insert a '/' unless the first part is empty or already ends in '/'.
|
|
|
|
// std::string join_posix(const std::vector< std::string > & paths)
|
|
// {
|
|
// if(paths.empty()) return "";
|
|
// if(paths.size() == 1) return paths[0];
|
|
|
|
// std::string path = paths[0];
|
|
|
|
// for(std::size_t i = 1; i < paths.size(); ++i)
|
|
// {
|
|
// std::string b = paths[i];
|
|
// if(pystring::startswith(b, "/"s))
|
|
// {
|
|
// path = b;
|
|
// }
|
|
// else if(path.empty() || pystring::endswith(path, "/"s))
|
|
// {
|
|
// path += b;
|
|
// }
|
|
// else
|
|
// {
|
|
// path += "/" + b;
|
|
// }
|
|
// }
|
|
|
|
// return path;
|
|
// }
|
|
|
|
// std::string join_posix(const std::string & a, const std::string & b)
|
|
// {
|
|
// std::vector< std::string > paths(2);
|
|
// paths[0] = a;
|
|
// paths[1] = b;
|
|
// return join_posix(paths);
|
|
// }
|
|
|
|
// std::string join(const std::string & path1, const std::string & path2)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return join_nt(path1, path2);
|
|
// #else
|
|
// return join_posix(path1, path2);
|
|
// #endif
|
|
// }
|
|
|
|
|
|
// std::string join(const std::vector< std::string > & paths)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return join_nt(paths);
|
|
// #else
|
|
// return join_posix(paths);
|
|
// #endif
|
|
// }
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
|
|
// // Split a pathname.
|
|
// // Return (head, tail) where tail is everything after the final slash.
|
|
// // Either part may be empty
|
|
|
|
// void split_nt(std::string & head, std::string & tail, const std::string & path)
|
|
// {
|
|
// std::string d, p;
|
|
// splitdrive_nt(d, p, path);
|
|
|
|
// // set i to index beyond p's last slash
|
|
// std::ptrdiff_t i = (std::ptrdiff_t)p.size();
|
|
|
|
// while(i>0 && (p[i-1] != '\\') && (p[i-1] != '/'))
|
|
// {
|
|
// i = i - 1;
|
|
// }
|
|
|
|
// head = pystring::slice(p,0,i);
|
|
// tail = pystring::slice(p,i); // now tail has no slashes
|
|
|
|
// // remove trailing slashes from head, unless it's all slashes
|
|
// std::string head2 = head;
|
|
// while(!head2.empty() && ((pystring::slice(head2,-1) == "/") ||
|
|
// (pystring::slice(head2,-1) == "\\")))
|
|
// {
|
|
// head2 = pystring::slice(head,0,-1);
|
|
// }
|
|
|
|
// if(!head2.empty()) head = head2;
|
|
// head = d + head;
|
|
// }
|
|
|
|
|
|
// // Split a path in head (everything up to the last '/') and tail (the
|
|
// // rest). If the path ends in '/', tail will be empty. If there is no
|
|
// // '/' in the path, head will be empty.
|
|
// // Trailing '/'es are stripped from head unless it is the root.
|
|
|
|
// void split_posix(std::string & head, std::string & tail, const std::string & p)
|
|
// {
|
|
// std::ptrdiff_t i = pystring::rfind(p, "/"s) + 1;
|
|
|
|
// head = pystring::slice(p,0,i);
|
|
// tail = pystring::slice(p,i);
|
|
|
|
// if(!head.empty() && (head != pystring::mul("/"s, (std::ptrdiff_t) head.size())))
|
|
// {
|
|
// head = pystring::rstrip(head, "/"s);
|
|
// }
|
|
// }
|
|
|
|
// void split(std::string & head, std::string & tail, const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return split_nt(head, tail, path);
|
|
// #else
|
|
// return split_posix(head, tail, path);
|
|
// #endif
|
|
// }
|
|
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
// std::string basename_nt(const std::string & path)
|
|
// {
|
|
// std::string head, tail;
|
|
// split_nt(head, tail, path);
|
|
// return tail;
|
|
// }
|
|
|
|
// std::string basename_posix(const std::string & path)
|
|
// {
|
|
// std::string head, tail;
|
|
// split_posix(head, tail, path);
|
|
// return tail;
|
|
// }
|
|
|
|
// std::string basename(const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return basename_nt(path);
|
|
// #else
|
|
// return basename_posix(path);
|
|
// #endif
|
|
// }
|
|
|
|
// std::string dirname_nt(const std::string & path)
|
|
// {
|
|
// std::string head, tail;
|
|
// split_nt(head, tail, path);
|
|
// return head;
|
|
// }
|
|
|
|
// std::string dirname_posix(const std::string & path)
|
|
// {
|
|
// std::string head, tail;
|
|
// split_posix(head, tail, path);
|
|
// return head;
|
|
// }
|
|
|
|
// std::string dirname(const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return dirname_nt(path);
|
|
// #else
|
|
// return dirname_posix(path);
|
|
// #endif
|
|
// }
|
|
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
// // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
|
|
// std::string normpath_nt(const std::string & p)
|
|
// {
|
|
// std::string path = p;
|
|
// path = pystring::replace(path, "/"s, "\\"s);
|
|
|
|
// std::string prefix;
|
|
// splitdrive_nt(prefix, path, path);
|
|
|
|
// // We need to be careful here. If the prefix is empty, and the path starts
|
|
// // with a backslash, it could either be an absolute path on the current
|
|
// // drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
|
|
// // is therefore imperative NOT to collapse multiple backslashes blindly in
|
|
// // that case.
|
|
// // The code below preserves multiple backslashes when there is no drive
|
|
// // letter. This means that the invalid filename \\\a\b is preserved
|
|
// // unchanged, where a\\\b is normalised to a\b. It's not clear that there
|
|
// // is any better behaviour for such edge cases.
|
|
|
|
// if(prefix.empty())
|
|
// {
|
|
// // No drive letter - preserve initial backslashes
|
|
// while(pystring::slice(path,0,1) == "\\")
|
|
// {
|
|
// prefix = prefix + "\\";
|
|
// path = pystring::slice(path, 1);
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// // We have a drive letter - collapse initial backslashes
|
|
// if(pystring::startswith(path, "\\"s))
|
|
// {
|
|
// prefix = prefix + "\\";
|
|
// path = pystring::lstrip(path, "\\"s);
|
|
// }
|
|
// }
|
|
|
|
// std::vector<std::string> comps = pystring::split(path, "\\"s);
|
|
|
|
// std::ptrdiff_t i = 0;
|
|
|
|
// while(i < (std::ptrdiff_t) comps.size())
|
|
// {
|
|
// if(comps[i].empty() || comps[i] == ".")
|
|
// {
|
|
// comps.erase(comps.begin()+i);
|
|
// }
|
|
// else if(comps[i] == "..")
|
|
// {
|
|
// if(i>0 && comps[i-1] != "..")
|
|
// {
|
|
// comps.erase(comps.begin()+i-1, comps.begin()+i+1);
|
|
// i -= 1;
|
|
// }
|
|
// else if(i == 0 && pystring::endswith(prefix, "\\"s))
|
|
// {
|
|
// comps.erase(comps.begin()+i);
|
|
// }
|
|
// else
|
|
// {
|
|
// i += 1;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// i += 1;
|
|
// }
|
|
// }
|
|
|
|
// // If the path is now empty, substitute '.'
|
|
// if(prefix.empty() && comps.empty())
|
|
// {
|
|
// comps.push_back(".");
|
|
// }
|
|
|
|
// return prefix + pystring::join("\\"s, comps);
|
|
// }
|
|
|
|
// // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
|
|
// // It should be understood that this may change the meaning of the path
|
|
// // if it contains symbolic links!
|
|
// // Normalize path, eliminating double slashes, etc.
|
|
|
|
// std::string normpath_posix(const std::string & p)
|
|
// {
|
|
// if(p.empty()) return ".";
|
|
|
|
// std::string path = p;
|
|
|
|
// std::ptrdiff_t initial_slashes = pystring::startswith(path,"/") ? 1 : 0;
|
|
|
|
// // POSIX allows one or two initial slashes, but treats three or more
|
|
// // as single slash.
|
|
|
|
// if (initial_slashes && pystring::startswith(path,"//")
|
|
// && !pystring::startswith(path,"///"))
|
|
// initial_slashes = 2;
|
|
|
|
// std::vector<std::string> new_comps;
|
|
// std::vector<std::string> comps = pystring::split(path, "/"s);
|
|
|
|
// for(std::size_t i=0; i<comps.size(); ++i)
|
|
// {
|
|
// std::string comp = comps[i];
|
|
// if(comp.empty() || comp == ".")
|
|
// continue;
|
|
|
|
// if( (comp != "..") || ((initial_slashes == 0) && new_comps.empty()) ||
|
|
// (!new_comps.empty() && new_comps[new_comps.size()-1] == ".."))
|
|
// {
|
|
// new_comps.push_back(comp);
|
|
// }
|
|
// else if (!new_comps.empty())
|
|
// {
|
|
// new_comps.pop_back();
|
|
// }
|
|
// }
|
|
|
|
// path = pystring::join("/"s, new_comps);
|
|
|
|
// if (initial_slashes > 0)
|
|
// path = pystring::mul("/"s,initial_slashes) + path;
|
|
|
|
// if(path.empty()) return ".";
|
|
// return path;
|
|
// }
|
|
|
|
// std::string normpath(const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return normpath_nt(path);
|
|
// #else
|
|
// return normpath_posix(path);
|
|
// #endif
|
|
// }
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////////
|
|
// ///
|
|
// ///
|
|
|
|
// // Split the extension from a pathname.
|
|
// // Extension is everything from the last dot to the end, ignoring
|
|
// // leading dots. Returns "(root, ext)"; ext may be empty.
|
|
// // It is always true that root + ext == p
|
|
|
|
// void splitext_generic(std::string & root, std::string & ext,
|
|
// const std::string & p,
|
|
// const std::string & sep,
|
|
// const std::string & altsep,
|
|
// const std::string & extsep)
|
|
// {
|
|
// std::ptrdiff_t sepIndex = pystring::rfind(p, sep);
|
|
// if(!altsep.empty())
|
|
// {
|
|
// std::ptrdiff_t altsepIndex = pystring::rfind(p, altsep);
|
|
// sepIndex = std::max(sepIndex, altsepIndex);
|
|
// }
|
|
|
|
// std::ptrdiff_t dotIndex = pystring::rfind(p, extsep);
|
|
// if(dotIndex > sepIndex)
|
|
// {
|
|
// // Skip all leading dots
|
|
// std::ptrdiff_t filenameIndex = sepIndex + 1;
|
|
|
|
// while(filenameIndex < dotIndex)
|
|
// {
|
|
// if(pystring::slice(p,filenameIndex) != extsep)
|
|
// {
|
|
// root = pystring::slice(p, 0, dotIndex);
|
|
// ext = pystring::slice(p, dotIndex);
|
|
// return;
|
|
// }
|
|
|
|
// filenameIndex += 1;
|
|
// }
|
|
// }
|
|
|
|
// root = p;
|
|
// ext = "";
|
|
// }
|
|
|
|
// void splitext_nt(std::string & root, std::string & ext, const std::string & path)
|
|
// {
|
|
// return splitext_generic(root, ext, path,
|
|
// "\\", "/", ".");
|
|
// }
|
|
|
|
// void splitext_posix(std::string & root, std::string & ext, const std::string & path)
|
|
// {
|
|
// return splitext_generic(root, ext, path,
|
|
// "/", "", ".");
|
|
// }
|
|
|
|
// void splitext(std::string & root, std::string & ext, const std::string & path)
|
|
// {
|
|
// #ifdef WINDOWS
|
|
// return splitext_nt(root, ext, path);
|
|
// #else
|
|
// return splitext_posix(root, ext, path);
|
|
// #endif
|
|
// }
|
|
|
|
// } // namespace path
|
|
// } // namespace os
|
|
|
|
|
|
}//namespace pystring
|
|
|
|
|
|
#endif |