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:
Kieran Bingham 2019-10-22 16:01:02 +01:00
parent a8be6e94e7
commit a15e8d92ea
3 changed files with 103 additions and 0 deletions

View file

@ -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,

View file

@ -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)

View file

@ -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;
}
};