mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 12:23:09 +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");
|
||||
|
||||
wcstring path = L"//foo//////bar/";
|
||||
wcstring canon = path;
|
||||
path_make_canonical(canon);
|
||||
if (canon != L"/foo/bar")
|
||||
path_make_canonical(path);
|
||||
if (path != L"/foo/bar")
|
||||
{
|
||||
err(L"Bug in canonical PATH code");
|
||||
}
|
||||
|
@ -779,6 +778,11 @@ static void test_path()
|
|||
{
|
||||
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
|
||||
|
|
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)
|
||||
{
|
||||
// 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 */
|
||||
size_t size;
|
||||
do
|
||||
// Turn runs of slashes into a single slash
|
||||
size_t trailing = 0;
|
||||
bool prev_was_slash = false;
|
||||
for (size_t leading = 0; leading < len; leading++)
|
||||
{
|
||||
size = path.size();
|
||||
replace_all(path, L"//", L"/");
|
||||
wchar_t c = path.at(leading);
|
||||
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;
|
||||
}
|
||||
while (path.size() != size);
|
||||
prev_was_slash = is_slash;
|
||||
}
|
||||
assert(trailing <= len);
|
||||
if (trailing < len)
|
||||
path.resize(trailing);
|
||||
}
|
||||
|
||||
/* Remove trailing slashes, except don't remove the first one */
|
||||
while (size-- > 1)
|
||||
bool paths_are_equivalent(const wcstring &p1, const wcstring &p2)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (path.at(size) != L'/')
|
||||
wchar_t c1 = p1.at(idx1), c2 = p2.at(idx2);
|
||||
|
||||
// If the characters are different, the strings are not equivalent
|
||||
if (c1 != c2)
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
if (path1 == path2)
|
||||
if (paths_are_equivalent(path1, path2))
|
||||
return true;
|
||||
|
||||
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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Returns whether the two paths refer to the same file */
|
||||
|
|
Loading…
Reference in a new issue