From: Joel Rosdahl Date: Wed, 7 Aug 2019 19:52:15 +0000 (+0200) Subject: Add some C++-ified utility functions X-Git-Tag: v4.0~840 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e33d114c47f96db40de0df1ee47c3cf0999cac9e;p=thirdparty%2Fccache.git Add some C++-ified utility functions --- diff --git a/Makefile.in b/Makefile.in index 46bea4f0a..f6809abdb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -89,6 +89,7 @@ test_suites += unittest/test_hashutil.cpp test_suites += unittest/test_legacy_util.cpp test_suites += unittest/test_lockfile.cpp test_suites += unittest/test_stats.cpp +test_suites += unittest/test_util.cpp test_sources = unittest/main.cpp unittest/framework.cpp unittest/util.cpp test_sources += $(test_suites) diff --git a/dev.mk.in b/dev.mk.in index b8281d73d..d4faad473 100644 --- a/dev.mk.in +++ b/dev.mk.in @@ -55,6 +55,7 @@ non_third_party_headers = \ src/result.hpp \ src/system.hpp \ src/unify.hpp \ + src/util.hpp \ unittest/framework.hpp \ unittest/util.hpp third_party_headers = \ diff --git a/src/util.cpp b/src/util.cpp index 26c7e499e..b50bf23c4 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -17,8 +17,16 @@ // this program; if not, write to the Free Software Foundation, Inc., 51 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +#include "util.hpp" + +#include "Error.hpp" #include "ccache.hpp" +#include +#include +#include +#include + #ifdef HAVE_PWD_H # include #endif @@ -1793,3 +1801,54 @@ time_seconds(void) return (double)time(NULL); #endif } + +namespace util { + +std::string +read_file(const std::string& path) +{ + std::ifstream file(path); + if (!file) { + throw Error(fmt::format("{}: {}", path, strerror(errno))); + } + return std::string(std::istreambuf_iterator(file), + std::istreambuf_iterator()); +} + +bool +starts_with(const std::string& string, const std::string& prefix) +{ + return prefix.length() <= string.length() + && string.compare(0, prefix.length(), prefix) == 0; +} + +std::string +strip_whitespace(const std::string& string) +{ + auto is_space = [](int ch) { return std::isspace(ch); }; + auto start = std::find_if_not(string.begin(), string.end(), is_space); + auto end = std::find_if_not(string.rbegin(), string.rend(), is_space).base(); + return start < end ? std::string(start, end) : std::string(); +} + +std::string +to_lowercase(const std::string& string) +{ + std::string result = string; + std::transform(result.begin(), result.end(), result.begin(), tolower); + return result; +} + +// Write file data from a string. +void +write_file(const std::string& path, const std::string& data, bool binary) +{ + std::ofstream file(path, + binary ? std::ios::out | std::ios::binary : std::ios::out); + if (!file) { + throw Error(fmt::format("{}: {}", path, strerror(errno))); + } + file << data; +} + +} // namespace util diff --git a/src/util.hpp b/src/util.hpp new file mode 100644 index 000000000..47536bca2 --- /dev/null +++ b/src/util.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2019 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#include + +namespace util { + +// Read file data as a string. +std::string read_file(const std::string& path); + +// Return true if prefix is a prefix of string. +bool starts_with(const std::string& string, const std::string& prefix); + +// Strip whitespace from left and right side of a string. +[[gnu::warn_unused_result]] std::string +strip_whitespace(const std::string& string); + +// Convert a string to lowercase. +[[gnu::warn_unused_result]] std::string to_lowercase(const std::string& string); + +// Write file data from a string. +void write_file(const std::string& path, + const std::string& data, + bool binary = false); + +} // namespace util diff --git a/unittest/test_util.cpp b/unittest/test_util.cpp new file mode 100644 index 000000000..fcd4d1527 --- /dev/null +++ b/unittest/test_util.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2019 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#include "../src/util.hpp" + +#include "third_party/catch.hpp" + +TEST_CASE("util::read_file and util::write_file") +{ + util::write_file("test", "foo\nbar\n"); + std::string data = util::read_file("test"); + CHECK(data == "foo\nbar\n"); +} + +TEST_CASE("util::starts_with") +{ + CHECK(util::starts_with("", "")); + CHECK(util::starts_with("x", "")); + CHECK(util::starts_with("x", "x")); + CHECK(util::starts_with("xy", "")); + CHECK(util::starts_with("xy", "x")); + CHECK(util::starts_with("xy", "xy")); + CHECK(util::starts_with("xyz", "")); + CHECK(util::starts_with("xyz", "x")); + CHECK(util::starts_with("xyz", "xy")); + CHECK(util::starts_with("xyz", "xyz")); + + CHECK_FALSE(util::starts_with("", "x")); + CHECK_FALSE(util::starts_with("x", "y")); + CHECK_FALSE(util::starts_with("x", "xy")); +} + +TEST_CASE("util::strip_whitespace") +{ + CHECK(util::strip_whitespace("") == ""); + CHECK(util::strip_whitespace("x") == "x"); + CHECK(util::strip_whitespace(" x") == "x"); + CHECK(util::strip_whitespace("x ") == "x"); + CHECK(util::strip_whitespace(" x ") == "x"); + CHECK(util::strip_whitespace(" \n\tx \n\t") == "x"); + CHECK(util::strip_whitespace(" x y ") == "x y"); +} + +TEST_CASE("util::to_lowercase") +{ + CHECK(util::to_lowercase("") == ""); + CHECK(util::to_lowercase("x") == "x"); + CHECK(util::to_lowercase("X") == "x"); + CHECK(util::to_lowercase(" x_X@") == " x_x@"); +}