mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 20:33:08 +00:00
Add a fancy new paths_are_equivalent function to test for equivalent
paths instead of merely equal ones
This commit is contained in:
parent
85ce80d72e
commit
24f1da7f30
3 changed files with 61 additions and 16 deletions
|
@ -766,9 +766,8 @@ static void test_path()
|
||||||
say(L"Testing path functions");
|
say(L"Testing path functions");
|
||||||
|
|
||||||
wcstring path = L"//foo//////bar/";
|
wcstring path = L"//foo//////bar/";
|
||||||
wcstring canon = path;
|
path_make_canonical(path);
|
||||||
path_make_canonical(canon);
|
if (path != L"/foo/bar")
|
||||||
if (canon != L"/foo/bar")
|
|
||||||
{
|
{
|
||||||
err(L"Bug in canonical PATH code");
|
err(L"Bug in canonical PATH code");
|
||||||
}
|
}
|
||||||
|
@ -779,6 +778,11 @@ static void test_path()
|
||||||
{
|
{
|
||||||
err(L"Bug in canonical PATH code");
|
err(L"Bug in canonical PATH code");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (paths_are_equivalent(L"/foo/bar/baz", L"foo/bar/baz")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||||
|
if (! paths_are_equivalent(L"///foo///bar/baz", L"/foo/bar////baz//")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||||
|
if (! paths_are_equivalent(L"/foo/bar/baz", L"/foo/bar/baz")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||||
|
if (! paths_are_equivalent(L"/", L"/")) err(L"Bug in canonical PATH code on line %ld", (long)__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum word_motion_t
|
enum word_motion_t
|
||||||
|
|
62
path.cpp
62
path.cpp
|
@ -380,24 +380,62 @@ static void replace_all(wcstring &str, const wchar_t *needle, const wchar_t *rep
|
||||||
|
|
||||||
void path_make_canonical(wcstring &path)
|
void path_make_canonical(wcstring &path)
|
||||||
{
|
{
|
||||||
|
// Ignore trailing slashes, unless it's the first character
|
||||||
|
size_t len = path.size();
|
||||||
|
while (len > 1 && path.at(len - 1) == L'/')
|
||||||
|
len--;
|
||||||
|
|
||||||
/* Remove double slashes */
|
// Turn runs of slashes into a single slash
|
||||||
size_t size;
|
size_t trailing = 0;
|
||||||
do
|
bool prev_was_slash = false;
|
||||||
|
for (size_t leading = 0; leading < len; leading++)
|
||||||
{
|
{
|
||||||
size = path.size();
|
wchar_t c = path.at(leading);
|
||||||
replace_all(path, L"//", L"/");
|
bool is_slash = (c == '/');
|
||||||
|
if (! prev_was_slash || ! is_slash)
|
||||||
|
{
|
||||||
|
// This is either the first slash in a run, or not a slash at all
|
||||||
|
path.at(trailing++) = c;
|
||||||
|
}
|
||||||
|
prev_was_slash = is_slash;
|
||||||
|
}
|
||||||
|
assert(trailing <= len);
|
||||||
|
if (trailing < len)
|
||||||
|
path.resize(trailing);
|
||||||
}
|
}
|
||||||
while (path.size() != size);
|
|
||||||
|
|
||||||
/* Remove trailing slashes, except don't remove the first one */
|
bool paths_are_equivalent(const wcstring &p1, const wcstring &p2)
|
||||||
while (size-- > 1)
|
|
||||||
{
|
{
|
||||||
if (path.at(size) != L'/')
|
if (p1 == p2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
size_t len1 = p1.size(), len2 = p2.size();
|
||||||
|
|
||||||
|
// Ignore trailing slashes after the first character
|
||||||
|
while (len1 > 1 && p1.at(len1 - 1) == L'/') len1--;
|
||||||
|
while (len2 > 1 && p2.at(len2 - 1) == L'/') len2--;
|
||||||
|
|
||||||
|
// Start walking
|
||||||
|
size_t idx1 = 0, idx2 = 0;
|
||||||
|
while (idx1 < len1 && idx2 < len2)
|
||||||
|
{
|
||||||
|
wchar_t c1 = p1.at(idx1), c2 = p2.at(idx2);
|
||||||
|
|
||||||
|
// If the characters are different, the strings are not equivalent
|
||||||
|
if (c1 != c2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
idx1++;
|
||||||
|
idx2++;
|
||||||
|
|
||||||
|
// If the character was a slash, walk forwards until we hit the end of the string, or a non-slash
|
||||||
|
// Note the first condition is invariant within the loop
|
||||||
|
while (c1 == L'/' && idx1 < len1 && p1.at(idx1) == L'/') idx1++;
|
||||||
|
while (c2 == L'/' && idx2 < len2 && p2.at(idx2) == L'/') idx2++;
|
||||||
}
|
}
|
||||||
/* Now size is either -1 (if the entire string was slashes) or is the index of the last non-slash character. Either way this will set it to the correct size. */
|
|
||||||
path.resize(size+1);
|
// We matched if we consumed all of the characters in both strings
|
||||||
|
return idx1 == len1 && idx2 == len2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path_is_valid(const wcstring &path, const wcstring &working_directory)
|
bool path_is_valid(const wcstring &path, const wcstring &working_directory)
|
||||||
|
@ -433,7 +471,7 @@ bool path_is_valid(const wcstring &path, const wcstring &working_directory)
|
||||||
|
|
||||||
bool paths_are_same_file(const wcstring &path1, const wcstring &path2)
|
bool paths_are_same_file(const wcstring &path1, const wcstring &path2)
|
||||||
{
|
{
|
||||||
if (path1 == path2)
|
if (paths_are_equivalent(path1, path2))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
struct stat s1, s2;
|
struct stat s1, s2;
|
||||||
|
|
3
path.h
3
path.h
|
@ -73,6 +73,9 @@ bool path_can_be_implicit_cd(const wcstring &path,
|
||||||
*/
|
*/
|
||||||
void path_make_canonical(wcstring &path);
|
void path_make_canonical(wcstring &path);
|
||||||
|
|
||||||
|
/** Check if two paths are equivalent, which means to ignore runs of multiple slashes (or trailing slashes) */
|
||||||
|
bool paths_are_equivalent(const wcstring &p1, const wcstring &p2);
|
||||||
|
|
||||||
bool path_is_valid(const wcstring &path, const wcstring &working_directory);
|
bool path_is_valid(const wcstring &path, const wcstring &working_directory);
|
||||||
|
|
||||||
/** Returns whether the two paths refer to the same file */
|
/** Returns whether the two paths refer to the same file */
|
||||||
|
|
Loading…
Reference in a new issue