BLI Path: add function BLI_path_contains()

Add function `BLI_path_contains(container, containee)` that returns true
if and only `container` contains `containee`.

Paths are normalised and converted to native path separators before
comparing. Relative paths are *not* made absolute, to simplify the
function call; if this is necessary the caller has to do this conversion
first.
This commit is contained in:
2021-09-27 15:22:53 +02:00
parent 6578db57cd
commit aafbe111fc
3 changed files with 55 additions and 0 deletions

View File

@@ -55,6 +55,10 @@ bool BLI_path_name_at_index(const char *__restrict path,
int *__restrict r_offset,
int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/** Return true only if #containee_path is contained in #container_path. */
bool BLI_path_contains(const char *container_path,
const char *containee_path) ATTR_WARN_UNUSED_RESULT;
const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
void BLI_path_slash_rstrip(char *string) ATTR_NONNULL();

View File

@@ -1935,6 +1935,34 @@ bool BLI_path_name_at_index(const char *__restrict path,
return false;
}
bool BLI_path_contains(const char *container_path, const char *containee_path)
{
char container_native[PATH_MAX];
char containee_native[PATH_MAX];
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
* longer than PATH_MAX and the result is ill-defined. */
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
BLI_strncpy(containee_native, containee_path, PATH_MAX);
BLI_path_slash_native(container_native);
BLI_path_slash_native(containee_native);
BLI_path_normalize(NULL, container_native);
BLI_path_normalize(NULL, containee_native);
if (STREQ(container_native, containee_native)) {
/* The paths are equal, they contain each other. */
return true;
}
/* Add a trailing slash to prevent same-prefix directories from matching.
* e.g. "/some/path" doesn't contain "/some/pathlib". */
BLI_path_slash_ensure(container_native);
return BLI_str_startswith(containee_native, container_native);
}
/**
* Returns pointer to the leftmost path separator in string. Not actually used anywhere.
*/

View File

@@ -655,3 +655,26 @@ TEST(path_util, PathRelPath)
# undef PATH_REL
#endif
/* BLI_path_contains */
TEST(path_util, PathContains)
{
EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path")) << "A path contains itself";
EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/inside"))
<< "A path contains its subdirectory";
EXPECT_TRUE(BLI_path_contains("/some/path", "/some/path/../path/inside"))
<< "Paths should be normalised";
EXPECT_TRUE(BLI_path_contains("C:\\some\\path", "C:\\some\\path\\inside"))
<< "Windows paths should be supported as well";
EXPECT_FALSE(BLI_path_contains("C:\\some\\path", "C:\\some\\other\\path"))
<< "Windows paths should be supported as well";
EXPECT_FALSE(BLI_path_contains("/some/path", "/"))
<< "Root directory not be contained in a subdirectory";
EXPECT_FALSE(BLI_path_contains("/some/path", "/some/path/../outside"))
<< "Paths should be normalised";
EXPECT_FALSE(BLI_path_contains("/some/path", "/some/path_library"))
<< "Just sharing a suffix is not enough, path semantics should be followed";
EXPECT_FALSE(BLI_path_contains("/some/path", "./contents"))
<< "Relative paths are not supported";
}