From 644abf105de9bce850e7c13ed067f7e958cd9bf2 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 18 Apr 2026 17:35:11 +0200 Subject: [PATCH] replace semver with home grown simplier alternative --- lib/semver/LICENSE | 22 ---- lib/semver/README.md | 7 -- lib/semver/Semver200_comparator.cpp | 121 ------------------ lib/semver/Semver200_parser.cpp | 187 ---------------------------- lib/semver/semver200.h | 53 -------- lib/semver/version.h | 149 ---------------------- lib/semver/version.inl | 132 -------------------- src/core/EMSESP_Version.h | 124 ++++++++++++++++++ 8 files changed, 124 insertions(+), 671 deletions(-) delete mode 100644 lib/semver/LICENSE delete mode 100644 lib/semver/README.md delete mode 100644 lib/semver/Semver200_comparator.cpp delete mode 100644 lib/semver/Semver200_parser.cpp delete mode 100644 lib/semver/semver200.h delete mode 100644 lib/semver/version.h delete mode 100644 lib/semver/version.inl create mode 100644 src/core/EMSESP_Version.h diff --git a/lib/semver/LICENSE b/lib/semver/LICENSE deleted file mode 100644 index 53234651b..000000000 --- a/lib/semver/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Marko Živanović - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/lib/semver/README.md b/lib/semver/README.md deleted file mode 100644 index 82c86d7d3..000000000 --- a/lib/semver/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# About - -This project is MIT-licensed, C++14 implementation of [semantic versioning](http://semver.org) parser and comparator with support for modifying parsed version strings. Semantic versioning 2.0.0 specification is supported out-of-the-box and the code should be flexible-enough to support future revisions or other similar versioning schemes. - -Copyright (c) 2015 Marko Zivanovic - -Based on https://github.com/zmarko/semver diff --git a/lib/semver/Semver200_comparator.cpp b/lib/semver/Semver200_comparator.cpp deleted file mode 100644 index 1430bd14b..000000000 --- a/lib/semver/Semver200_comparator.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Marko Zivanovic - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include -#include -#include -#include "semver200.h" - -using namespace std; - -namespace version { - -namespace { - -// Compare normal version identifiers. -int compare_normal(const Version_data & l, const Version_data & r) { - if (l.major > r.major) - return 1; - if (l.major < r.major) - return -1; - if (l.minor > r.minor) - return 1; - if (l.minor < r.minor) - return -1; - if (l.patch > r.patch) - return 1; - if (l.patch < r.patch) - return -1; - return 0; -} - -// Compare alphanumeric prerelease identifiers. -inline int cmp_alnum_prerel_ids(const string & l, const string & r) { - auto cmp = l.compare(r); - if (cmp == 0) { - return cmp; - } else { - return cmp > 0 ? 1 : -1; - } -} - -// Compare numeric prerelease identifiers. -inline int cmp_num_prerel_ids(const string & l, const string & r) { - long long li = stoll(l); - long long ri = stoll(r); - if (li == ri) - return 0; - return li > ri ? 1 : -1; -} - -using Prerel_type_pair = pair; -using Prerel_id_comparator = function; -const map comparators = {{{Id_type::alnum, Id_type::alnum}, cmp_alnum_prerel_ids}, - {{Id_type::alnum, Id_type::num}, [](const string &, const string &) { return 1; }}, - {{Id_type::num, Id_type::alnum}, [](const string &, const string &) { return -1; }}, - {{Id_type::num, Id_type::num}, cmp_num_prerel_ids}}; - -// Compare prerelease identifiers based on their types. -inline int compare_prerel_identifiers(const Prerelease_identifier & l, const Prerelease_identifier & r) { - auto cmp = comparators.at({l.second, r.second}); - return cmp(l.first, r.first); -} - -inline int cmp_rel_prerel(const Prerelease_identifiers & l, const Prerelease_identifiers & r) { - if (l.empty() && !r.empty()) - return 1; - if (r.empty() && !l.empty()) - return -1; - return 0; -} -} // namespace - -int Semver200_comparator::compare(const Version_data & l, const Version_data & r) const { - // Compare normal version components. - int cmp = compare_normal(l, r); - if (cmp != 0) - return cmp; - - // Compare if one version is release and the other prerelease - release is always higher. - cmp = cmp_rel_prerel(l.prerelease_ids, r.prerelease_ids); - if (cmp != 0) - return cmp; - - // Compare prerelease by looking at each identifier: numeric ones are compared as numbers, - // alphanum as ASCII strings. - auto shorter = min(l.prerelease_ids.size(), r.prerelease_ids.size()); - for (size_t i = 0; i < shorter; i++) { - cmp = compare_prerel_identifiers(l.prerelease_ids[i], r.prerelease_ids[i]); - if (cmp != 0) - return cmp; - } - - // Prerelease identifiers are the same, to the length of the shorter version string; - // if they are the same length, then versions are equal, otherwise, longer one wins. - if (l.prerelease_ids.size() == r.prerelease_ids.size()) - return 0; - return l.prerelease_ids.size() > r.prerelease_ids.size() ? 1 : -1; -} - -} // namespace version diff --git a/lib/semver/Semver200_parser.cpp b/lib/semver/Semver200_parser.cpp deleted file mode 100644 index e5956be0e..000000000 --- a/lib/semver/Semver200_parser.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Marko Zivanovic - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include -#include -#include "semver200.h" - -using namespace std; - -namespace version { - -namespace { -enum class Parser_state { major, minor, patch, prerelease, build }; - -using Validator = function; -using State_transition_hook = function; -/// State transition is described by a character that triggers it, a state to transition to and -/// optional hook to be invoked on transition. -using Transition = tuple; -using Transitions = vector; -using State = tuple; -using State_machine = std::map; - -// Ranges of characters allowed in prerelease and build identifiers. -const vector> allowed_prerel_id_chars = {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {'-', '-'}}; - -inline Transition mkx(const char c, Parser_state p, State_transition_hook pth) { - return make_tuple(c, p, pth); -} - -inline void Parse_error(const std::string & s) { - // EMSESP::logger().err("parse error: %s", s.c_str()); -} - -/// Advance parser state machine by a single step. -/** - Perform single step of parser state machine: if character matches one from transition tables - - trigger transition to next state; otherwise, validate if current token is in legal state - (throw Parse_error if not) and then add character to current token; State transition includes - preparing various vars for next state and invoking state transition hook (if specified) which is - where whole tokens are validated. - */ -inline void process_char(const char c, Parser_state & cstate, Parser_state & pstate, const Transitions & transitions, string & target, Validator validate) { - for (const auto & transition : transitions) { - if (c == get<0>(transition)) { - if (get<2>(transition)) - get<2>(transition)(target); - pstate = cstate; - cstate = get<1>(transition); - return; - } - } - validate(target, c); - target.push_back(c); -} - -/// Validate normal (major, minor, patch) version components. -inline void normal_version_validator(const string & tgt, const char c) { - if (c < '0' || c > '9') - Parse_error("invalid character encountered: " + string(1, c)); - if (tgt.compare(0, 1, "0") == 0) - Parse_error("leading 0 not allowed"); -} - -/// Validate that prerelease and build version identifiers are comprised of allowed chars only. -inline void prerelease_version_validator(const string &, const char c) { - bool res = false; - for (const auto & r : allowed_prerel_id_chars) { - res |= (c >= r.first && c <= r.second); - } - if (!res) - Parse_error("invalid character encountered: " + string(1, c)); -} - -inline bool is_identifier_numeric(const string & id) { - return id.find_first_not_of("0123456789") == string::npos; -} - -inline bool check_for_leading_0(const string & str) { - return str.length() > 1 && str[0] == '0'; -} - -/// Validate every individual prerelease identifier, determine it's type and add it to collection. -void prerelease_hook_impl(string & id, Prerelease_identifiers & prerelease) { - if (id.empty()) - Parse_error("version identifier cannot be empty"); - Id_type t = Id_type::alnum; - if (is_identifier_numeric(id)) { - t = Id_type::num; - if (check_for_leading_0(id)) { - Parse_error("numeric identifiers cannot have leading 0"); - } - } - prerelease.push_back(Prerelease_identifier(id, t)); - id.clear(); -} - -/// Validate every individual build identifier and add it to collection. -void build_hook_impl(string & id, Parser_state & pstate, Build_identifiers & build, std::string & prerelease_id, Prerelease_identifiers & prerelease) { - // process last token left from parsing prerelease data - if (pstate == Parser_state::prerelease) - prerelease_hook_impl(prerelease_id, prerelease); - if (id.empty()) - Parse_error("version identifier cannot be empty"); - build.push_back(id); - id.clear(); -} - -} // namespace - -/// Parse semver 2.0.0-compatible string to Version_data structure. -/** - Version text parser is implemented as a state machine. In each step one successive character from version - string is consumed and is either added to current token or triggers state transition. Hooks can be - injected into state transitions for validation/customization purposes. - */ -Version_data Semver200_parser::parse(const string & s) const { - string major; - string minor; - string patch; - string prerelease_id; - string build_id; - Prerelease_identifiers prerelease; - Build_identifiers build; - Parser_state cstate{Parser_state::major}; - Parser_state pstate; - - auto prerelease_hook = [&](string & id) { prerelease_hook_impl(id, prerelease); }; - - auto build_hook = [&](string & id) { build_hook_impl(id, pstate, build, prerelease_id, prerelease); }; - - // State transition tables - auto major_trans = {mkx('.', Parser_state::minor, {})}; - auto minor_trans = {mkx('.', Parser_state::patch, {})}; - auto patch_trans = {mkx('-', Parser_state::prerelease, {}), mkx('+', Parser_state::build, {})}; - auto prerelease_trans = {// When identifier separator (.) is found, stay in the same state but invoke hook - // in order to process each individual identifier separately. - mkx('.', Parser_state::prerelease, prerelease_hook), - mkx('+', Parser_state::build, {})}; - auto build_trans = {// Same stay-in-the-same-state-but-invoke-hook trick from above. - mkx('.', Parser_state::build, build_hook)}; - - State_machine state_machine = {{Parser_state::major, State{major_trans, major, normal_version_validator}}, - {Parser_state::minor, State{minor_trans, minor, normal_version_validator}}, - {Parser_state::patch, State{patch_trans, patch, normal_version_validator}}, - {Parser_state::prerelease, State{prerelease_trans, prerelease_id, prerelease_version_validator}}, - {Parser_state::build, State{build_trans, build_id, prerelease_version_validator}}}; - - // Main loop. - for (const auto & c : s) { - auto state = state_machine.at(cstate); - process_char(c, cstate, pstate, get<0>(state), get<1>(state), get<2>(state)); - } - - // Trigger appropriate hooks in order to process last token, because no state transition was - // triggered for it. - if (cstate == Parser_state::prerelease) { - prerelease_hook(prerelease_id); - } else if (cstate == Parser_state::build) { - build_hook(build_id); - } - - return Version_data{stoi(major), stoi(minor), stoi(patch), prerelease, build}; -} - -} // namespace version diff --git a/lib/semver/semver200.h b/lib/semver/semver200.h deleted file mode 100644 index 5c19f07ff..000000000 --- a/lib/semver/semver200.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Marko Zivanovic - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once - -#include "version.h" - -namespace version { - -/// Parse string into Version_data structure according to semantic versioning 2.0.0 rules. -struct Semver200_parser { - Version_data parse(const std::string &) const; -}; - -/// Compare Version_data to another using semantic versioning 2.0.0 rules. -struct Semver200_comparator { - int compare(const Version_data &, const Version_data &) const; -}; - -/// Concrete version class that binds all semver 2.0.0 functionality together. -class Semver200_version : public Basic_version { - public: - Semver200_version() - : Basic_version{Semver200_parser(), Semver200_comparator()} { - } - - Semver200_version(const std::string & v) - : Basic_version{v, Semver200_parser(), Semver200_comparator()} { - } -}; - -} // namespace version \ No newline at end of file diff --git a/lib/semver/version.h b/lib/semver/version.h deleted file mode 100644 index 517d6f435..000000000 --- a/lib/semver/version.h +++ /dev/null @@ -1,149 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Marko Zivanovic - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once - -#include -#include - -namespace version { - -/// Type of prerelease identifier: alphanumeric or numeric. -/** - Type of identifier affects comparison: alphanumeric identifiers are compared as ASCII strings, while - numeric identifiers are compared as numbers. - */ -enum class Id_type { - alnum, ///< Identifier is alphanumerical - num ///< Identifier is numeric -}; - -/// Container for prerelease identifier value and it's type. -/** - Prerelease version string consist of an optional series of dot-separated identifiers. - These identifiers can be either numerical or alphanumerical. - This structure describes one such identifier. - */ -using Prerelease_identifier = std::pair; - -/// Container for all prerelease identifiers for a given version string. -using Prerelease_identifiers = std::vector; - -/// Build identifier is arbitrary string with no special meaning with regards to version precedence. -using Build_identifier = std::string; - -/// Container for all build identifiers of a given version string. -using Build_identifiers = std::vector; - -/// Description of version broken into parts, as per semantic versioning specification. -struct Version_data { - Version_data(const int M, const int m, const int p, const Prerelease_identifiers & pr, const Build_identifiers & b) - : major{M} - , minor{m} - , patch{p} - , prerelease_ids{pr} - , build_ids{b} { - } - - int major; ///< Major version, change only on incompatible API modifications. - int minor; ///< Minor version, change on backwards-compatible API modifications. - int patch; ///< Patch version, change only on bugfixes. - - /// Optional series of prerelease identifiers. - Prerelease_identifiers prerelease_ids; - - /// Optional series of build identifiers. - Build_identifiers build_ids; -}; - -// Forward declaration required for operators' template declarations. -template -class Basic_version; - -/// Test if left-hand version operand is of lower precedence than the right-hand version. -template -bool operator<(const Basic_version &, const Basic_version &); - -/// Test if left-hand version operand if of equal precedence as the right-hand version. -template -bool operator==(const Basic_version &, const Basic_version &); - -/// Test if left-hand version and right-hand version are of different precedence. -template -bool operator!=(const Basic_version &, const Basic_version &); - -/// Test if left-hand version operand is of higher precedence than the right-hand version. -template -bool operator>(const Basic_version &, const Basic_version &); - -/// Test if left-hand version operand is of higher or equal precedence as the right-hand version. -template -bool operator>=(const Basic_version &, const Basic_version &); - -/// Test if left-hand version operand is of lower or equal precedence as the right-hand version. -template -bool operator<=(const Basic_version &, const Basic_version &); - -/// Base class for various version parsing, precedence ordering and data manipulation schemes. -/** - Basic_version class describes general version object without prescribing parsing, - validation, comparison and modification rules. These rules are implemented by supplied Parser, Comparator - and Modifier objects. - */ -template -class Basic_version { - public: - /// Construct Basic_version object using Parser object to parse default ("0.0.0") version string, Comparator for comparison and Modifier for modification. - Basic_version(Parser, Comparator); - - /// Construct Basic_version object using Parser to parse supplied version string, Comparator for comparison and Modifier for modification. - Basic_version(const std::string &, Parser, Comparator); - - /// Construct Basic_version object using supplied Version_data, Parser, Comparator and Modifier objects. - Basic_version(const Version_data &, Parser, Comparator); - - /// Construct Basic_version by copying data from another one. - Basic_version(const Basic_version &); - - /// Copy version data from another Basic_version to this one. - Basic_version & operator=(const Basic_version &); - - int major() const; ///< Get major version. - int minor() const; ///< Get minor version. - int patch() const; ///< Get patch version. - const std::string prerelease() const; ///< Get prerelease version string. - const std::string build() const; ///< Get build version string. - - friend bool operator< <>(const Basic_version &, const Basic_version &); - friend bool operator==<>(const Basic_version &, const Basic_version &); - - private: - Parser parser_; - Comparator comparator_; - Version_data ver_; -}; - -} // namespace version - -#include "version.inl" diff --git a/lib/semver/version.inl b/lib/semver/version.inl deleted file mode 100644 index 8de18af61..000000000 --- a/lib/semver/version.inl +++ /dev/null @@ -1,132 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Marko Zivanovic - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once - -#include "version.h" - -namespace version { - -namespace { - -/// Utility function to splice all vector elements to output stream, using designated separator -/// between elements and function object for getting values from vector elements. -template -std::string & splice(std::string & ss, const std::vector & vec, const std::string & sep, F read) { - if (!vec.empty()) { - for (auto it = vec.cbegin(); it < vec.cend() - 1; ++it) { - ss += read(*it) + sep; - } - ss += read(*vec.crbegin()); - } - return ss; -} - -} // namespace - -template -Basic_version::Basic_version(Parser p, Comparator c) - : parser_(p) - , comparator_(c) - , ver_(parser_.parse("0.0.0")) { -} - -template -Basic_version::Basic_version(const std::string & v, Parser p, Comparator c) - : parser_(p) - , comparator_(c) - , ver_(parser_.parse(v)) { -} - -template -Basic_version::Basic_version(const Version_data & v, Parser p, Comparator c) - : parser_(p) - , comparator_(c) - , ver_(v) { -} - -template -Basic_version::Basic_version(const Basic_version &) = default; - -template -Basic_version & Basic_version::operator=(const Basic_version &) = default; - -template -int Basic_version::major() const { - return ver_.major; -} - -template -int Basic_version::minor() const { - return ver_.minor; -} - -template -int Basic_version::patch() const { - return ver_.patch; -} - -template -const std::string Basic_version::prerelease() const { - std::string ss; - return splice(ss, ver_.prerelease_ids, ".", [](const Prerelease_identifier & id) { return id.first; }); -} - -template -const std::string Basic_version::build() const { - std::string ss; - return splice(ss, ver_.build_ids, ".", [](const std::string & id) { return id; }); -} - -template -bool operator<(const Basic_version & l, const Basic_version & r) { - return l.comparator_.compare(l.ver_, r.ver_) == -1; -} - -template -bool operator==(const Basic_version & l, const Basic_version & r) { - return l.comparator_.compare(l.ver_, r.ver_) == 0; -} - -template -inline bool operator!=(const Basic_version & l, const Basic_version & r) { - return !(l == r); -} - -template -inline bool operator>(const Basic_version & l, const Basic_version & r) { - return r < l; -} - -template -inline bool operator>=(const Basic_version & l, const Basic_version & r) { - return !(l < r); -} - -template -inline bool operator<=(const Basic_version & l, const Basic_version & r) { - return !(l > r); -} - -} // namespace version diff --git a/src/core/EMSESP_Version.h b/src/core/EMSESP_Version.h new file mode 100644 index 000000000..c9be68f61 --- /dev/null +++ b/src/core/EMSESP_Version.h @@ -0,0 +1,124 @@ +/* + * EMS-ESP - https://github.com/emsesp/EMS-ESP + * Copyright 2020-2026 emsesp.org + * + * 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, see . + */ + +#ifndef EMSESP_Version_H +#define EMSESP_Version_H + +#include +#include +#include + +// Drop-in lightweight replacement for the subset of the semver library actually used by EMS-ESP. +// The previous semver library (lib/semver) builds a std::map + std::function-based state machine on +// every parse, which fragments the internal heap on the ESP32. This replacement does no heap +// allocation beyond the std::string member for the prerelease tag, and matches the API surface +// we consume: construction from string, major()/minor()/patch()/prerelease(), and operator>/(const EMSESP_Version & a, const EMSESP_Version & b) { + return b < a; + } + + friend bool operator==(const EMSESP_Version & a, const EMSESP_Version & b) { + return a.major_ == b.major_ && a.minor_ == b.minor_ && a.patch_ == b.patch_; + } + + friend bool operator!=(const EMSESP_Version & a, const EMSESP_Version & b) { + return !(a == b); + } + + friend bool operator>=(const EMSESP_Version & a, const EMSESP_Version & b) { + return !(a < b); + } + + friend bool operator<=(const EMSESP_Version & a, const EMSESP_Version & b) { + return !(b < a); + } + + private: + int major_ = 0; + int minor_ = 0; + int patch_ = 0; + std::string prerelease_; + + void parse(const char * s) { + major_ = minor_ = patch_ = 0; + prerelease_.clear(); + if (s == nullptr || *s == '\0') { + return; + } + // parse numeric major.minor.patch; accept partial ("3", "3.9", "3.9.0") + sscanf(s, "%d.%d.%d", &major_, &minor_, &patch_); + // capture prerelease tag after '-' if present (stop at '+' which is build metadata) + const char * dash = strchr(s, '-'); + if (dash != nullptr) { + const char * plus = strchr(dash, '+'); + if (plus != nullptr) { + prerelease_.assign(dash + 1, plus - dash - 1); + } else { + prerelease_.assign(dash + 1); + } + } + } +}; + +} // namespace version + +#endif