From patchwork Fri Feb 21 16:31:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 2867 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0146D6262D for ; Fri, 21 Feb 2020 17:31:35 +0100 (CET) Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8494EA53; Fri, 21 Feb 2020 17:31:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1582302694; bh=o9PQFCR1f94r3LacThxrHefONDhTKBExmHz6YKNo/r0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=C5nAkQasskB8+PpShxgxpwBVxCfSq3bMQc6wBLv7dAjTssABlq378k9+vAuxyKkPC Sod5f+9FvyG7XQHWu2z3xkecv7hWh/9KSvtThbmQnS0RIzU2Fv6G03jTWUaiZQC45a W/ODDwcwlP1KluRHgYKBmNav58lFtZv/xyMNj5KY= From: Kieran Bingham To: libcamera devel Date: Fri, 21 Feb 2020 16:31:25 +0000 Message-Id: <20200221163130.4791-2-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200221163130.4791-1-kieran.bingham@ideasonboard.com> References: <20200221163130.4791-1-kieran.bingham@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 1/6] libcamera: utils: Add a C++ dirname implementation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Feb 2020 16:31:35 -0000 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 Reviewed-by: Laurent Pinchart --- 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 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 paths = { + "", + "///", + "/bin", + "/usr/bin", + "//etc////", + "//tmp//d//", + "current_file", + "./current_file", + "./current_dir/", + "current_dir/", + }; + + std::vector expected = { + ".", + "/", + "/", + "/usr", + "/", + "//tmp", + ".", + ".", + ".", + ".", + }; + + std::vector 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; } };