libcamera: utils: Add a C++ dirname implementation
Provide a std::string based implementation which conforms to the behaviour of the dirname() fucntion defined by POSIX. Tests are added to cover expected corner cases of the implementation. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
a8be6e94e7
commit
a15e8d92ea
3 changed files with 103 additions and 0 deletions
|
@ -33,6 +33,7 @@ namespace utils {
|
|||
const char *basename(const char *path);
|
||||
|
||||
char *secure_getenv(const char *name);
|
||||
std::string dirname(const std::string &path);
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
unsigned int set_overlap(InputIt1 first1, InputIt1 last1,
|
||||
|
|
|
@ -70,6 +70,54 @@ char *secure_getenv(const char *name)
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Identify the dirname portion of a path
|
||||
* \param[in] path The full path to parse
|
||||
*
|
||||
* This function conforms with the behaviour of the %dirname() function as
|
||||
* defined by POSIX.
|
||||
*
|
||||
* \return A string of the directory component of the path
|
||||
*/
|
||||
std::string dirname(const std::string &path)
|
||||
{
|
||||
if (path.empty())
|
||||
return ".";
|
||||
|
||||
/*
|
||||
* Skip all trailing slashes. If the path is only made of slashes,
|
||||
* return "/".
|
||||
*/
|
||||
size_t pos = path.size() - 1;
|
||||
while (path[pos] == '/') {
|
||||
if (!pos)
|
||||
return "/";
|
||||
pos--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the previous slash. If the path contains no non-trailing slash,
|
||||
* return ".".
|
||||
*/
|
||||
while (path[pos] != '/') {
|
||||
if (!pos)
|
||||
return ".";
|
||||
pos--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the directory name up to (but not including) any trailing
|
||||
* slash. If this would result in an empty string, return "/".
|
||||
*/
|
||||
while (path[pos] == '/') {
|
||||
if (!pos)
|
||||
return "/";
|
||||
pos--;
|
||||
}
|
||||
|
||||
return path.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn libcamera::utils::set_overlap(InputIt1 first1, InputIt1 last1,
|
||||
* InputIt2 first2, InputIt2 last2)
|
||||
|
|
|
@ -19,6 +19,56 @@ using namespace libcamera;
|
|||
class UtilsTest : public Test
|
||||
{
|
||||
protected:
|
||||
int testDirname()
|
||||
{
|
||||
static const std::vector<std::string> paths = {
|
||||
"",
|
||||
"///",
|
||||
"/bin",
|
||||
"/usr/bin",
|
||||
"//etc////",
|
||||
"//tmp//d//",
|
||||
"current_file",
|
||||
"./current_file",
|
||||
"./current_dir/",
|
||||
"current_dir/",
|
||||
};
|
||||
|
||||
static const std::vector<std::string> expected = {
|
||||
".",
|
||||
"/",
|
||||
"/",
|
||||
"/usr",
|
||||
"/",
|
||||
"//tmp",
|
||||
".",
|
||||
".",
|
||||
".",
|
||||
".",
|
||||
};
|
||||
|
||||
std::vector<std::string> results;
|
||||
|
||||
for (const auto &path : paths)
|
||||
results.push_back(utils::dirname(path));
|
||||
|
||||
if (results != expected) {
|
||||
cerr << "utils::dirname() tests failed" << endl;
|
||||
|
||||
cerr << "expected: " << endl;
|
||||
for (const auto &path : expected)
|
||||
cerr << "\t" << path << endl;
|
||||
|
||||
cerr << "results: " << endl;
|
||||
for (const auto &path : results)
|
||||
cerr << "\t" << path << endl;
|
||||
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
int run()
|
||||
{
|
||||
/* utils::hex() test. */
|
||||
|
@ -71,6 +121,10 @@ protected:
|
|||
return TestFail;
|
||||
}
|
||||
|
||||
/* utils::dirname() tests. */
|
||||
if (TestPass != testDirname())
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue