diff --git a/emper/lib/LinuxVersion.cpp b/emper/lib/LinuxVersion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f37e5f362e0b865f429c6b317bd49e7b1748d0af --- /dev/null +++ b/emper/lib/LinuxVersion.cpp @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Fischer +#include "lib/LinuxVersion.hpp" + +#include <cassert> +#include <cerrno> +#include <cstdlib> + +#include "Common.hpp" +#include "Debug.hpp" + +static auto checked_strtol(const std::string& s) -> long { + static const int DECIMAL = 10; + char* endptr; + const char* startptr = s.c_str(); + errno = 0; + + long res = strtol(startptr, &endptr, DECIMAL); + if (errno != 0) { + DIE_MSG_ERRNO("strtol failed"); + } + + if (endptr == startptr) { + DIE_MSG("strtol found no digits in " << s); + } + + if (endptr != startptr + s.size()) { + LOGW("LinuxVersion compare ignored non digits in " << s) + } + + return res; +} + +namespace emper::lib { + +LinuxVersion LinuxVersion::linuxVersion; + +// Returns 1 if s is smaller, -1 if this is smaller, 0 if equal +auto LinuxVersion::compare(const std::string& s) -> int { + size_t last_dot_pos = 0, last_dot_pos2 = 0; + + for (;;) { + size_t dot_pos = this->version.find('.', last_dot_pos); + // We run out of parts to compare the versions must be equal + if (dot_pos == std::string::npos) return 0; + + size_t dot_pos2 = s.find('.', last_dot_pos2); + assert(dot_pos2 != std::string::npos); + + long n1 = checked_strtol(this->version.substr(last_dot_pos, dot_pos - last_dot_pos)); + long n2 = checked_strtol(s.substr(last_dot_pos2, dot_pos2 - last_dot_pos2)); + + if (n1 > n2) return 1; + + if (n1 < n2) return -1; + + last_dot_pos = dot_pos + 1; + last_dot_pos2 = dot_pos2 + 1; + } +} + +} // namespace emper::lib diff --git a/emper/lib/LinuxVersion.hpp b/emper/lib/LinuxVersion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6256cc40210261e7f413bb0f34cec92e03f02ead --- /dev/null +++ b/emper/lib/LinuxVersion.hpp @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Fischer +#pragma once + +#include <sys/utsname.h> + +#include <string> + +namespace emper::lib { +class LinuxVersion { + std::string version; + + auto compare(const std::string& s) -> int; + + public: + static LinuxVersion linuxVersion; + + LinuxVersion() { + struct utsname buf; + uname(&buf); + this->version = std::string(buf.release); + } + + auto operator>(const std::string& s) -> bool { return compare(s) > 0; } + + auto operator<(const std::string& s) -> bool { return compare(s) < 0; } + + auto operator==(const std::string& s) -> bool { return compare(s) == 0; } + + auto operator>=(const std::string& s) -> bool { return *this > s || *this == s; } + + auto operator<=(const std::string& s) -> bool { return *this < s || *this == s; } +}; +} // namespace emper::lib + +#define EMPER_LINUX_EQ(version) \ + ([]() -> bool { return empere::lib::LinuxVersion::linuxVersion == version; }()) +#define EMPER_LINUX_GT(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion > version; }()) +#define EMPER_LINUX_GE(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion >= version; }()) +#define EMPER_LINUX_LT(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion < version; }()) +#define EMPER_LINUX_LE(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion <= version; }()) diff --git a/emper/lib/meson.build b/emper/lib/meson.build index 126bdd278cc7cb27c107f35b8c4f230a59f51dc8..88b68f898aa5ccb9a4a790bae234b640e48306c8 100644 --- a/emper/lib/meson.build +++ b/emper/lib/meson.build @@ -1,3 +1,4 @@ emper_cpp_sources += files( 'DebugUtil.cpp', + 'LinuxVersion.cpp', )