[libcamera-devel] [PATCH v4 1/6] libcamera: utils: Add a C++ dirname implementation

Kieran Bingham kieran.bingham at ideasonboard.com
Fri Feb 21 17:31:25 CET 2020


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 at ideasonboard.com>
---
 src/libcamera/include/utils.h |  1 +
 src/libcamera/utils.cpp       | 48 +++++++++++++++++++++++++++++++
 test/utils.cpp                | 54 +++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)

diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h
index 080ea6614de0..940597760ee2 100644
--- a/src/libcamera/include/utils.h
+++ b/src/libcamera/include/utils.h
@@ -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,
diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp
index 453e3b3b5995..f566e88cec5b 100644
--- a/src/libcamera/utils.cpp
+++ b/src/libcamera/utils.cpp
@@ -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)
diff --git a/test/utils.cpp b/test/utils.cpp
index db1fbdde847d..e4184e39ce32 100644
--- a/test/utils.cpp
+++ b/test/utils.cpp
@@ -19,6 +19,56 @@ using namespace libcamera;
 class UtilsTest : public Test
 {
 protected:
+	int testDirname()
+	{
+		std::vector<std::string> paths = {
+			"",
+			"///",
+			"/bin",
+			"/usr/bin",
+			"//etc////",
+			"//tmp//d//",
+			"current_file",
+			"./current_file",
+			"./current_dir/",
+			"current_dir/",
+		};
+
+		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 << " " << path << endl;
+
+			cerr << "results: " << endl;
+			for (const auto &path : results)
+				cerr << " " << path << endl;
+
+			return TestFail;
+		}
+
+		return 0;
+	}
+
 	int run()
 	{
 		/* utils::hex() test. */
@@ -71,6 +121,10 @@ protected:
 			return TestFail;
 		}
 
+		/* utils::dirname() tests. */
+		if (testDirname())
+			return TestFail;
+
 		return TestPass;
 	}
 };
-- 
2.20.1



More information about the libcamera-devel mailing list