diff options
Diffstat (limited to 'butl/standard-version.cxx')
-rw-r--r-- | butl/standard-version.cxx | 161 |
1 files changed, 97 insertions, 64 deletions
diff --git a/butl/standard-version.cxx b/butl/standard-version.cxx index 1952653..74a5848 100644 --- a/butl/standard-version.cxx +++ b/butl/standard-version.cxx @@ -38,32 +38,32 @@ namespace butl } static void - check_version (uint64_t version, bool snapshot, bool allow_earliest) + check_version (uint64_t vr, bool sn, standard_version::flags fl) { // Check that the version isn't too large. // - // AAABBBCCCDDDE - bool r (version < 10000000000000ULL); + // AAABBBCCCDDDE + bool r (vr < 10000000000000ULL); // Check that E version component is consistent with the snapshot flag. - // Note that if the allow_earliest flag is true, then E can be 1 for the + // Note that if the allow_earliest flag is set, then E can be 1 for the // snapshot flag being false, denoting the earliest pre-release of the // version. // if (r) { - uint64_t e (version % 10); - if (!allow_earliest) - r = e == (snapshot ? 1 : 0); + uint64_t e (vr % 10); + if ((fl & standard_version::allow_earliest) == 0) + r = e == (sn ? 1 : 0); else - r = e == 1 || (e == 0 && !snapshot); + r = e == 1 || (e == 0 && !sn); } // Check that pre-release number is consistent with the snapshot flag. // if (r) { - uint64_t ab (version / 10 % 1000); + uint64_t ab (vr / 10 % 1000); // Note that if ab is 0, it can either mean non-pre-release version in // the absence of snapshot number, or 'a.0' pre-release otherwise. If ab @@ -71,14 +71,16 @@ namespace butl // number. // if (ab != 0) - r = ab != 500 || snapshot; + r = ab != 500 || sn; } - // Check that the major, the minor and the bugfix versions are not - // simultaneously zeros. + // Check that the major, the minor and the patch versions are not + // simultaneously zeros, unless stub is allowed, in which case the snapshot + // flag must be false. // if (r) - r = (version / 10000) != 0; + r = (vr / 10000) != 0 || + ((fl & standard_version::allow_stub) != 0 && !sn); if (!r) throw invalid_argument ("invalid project version"); @@ -87,7 +89,7 @@ namespace butl // standard_version // standard_version:: - standard_version (const std::string& s, bool allow_earliest) + standard_version (const std::string& s, flags f) { auto bail = [] (const char* m) {throw invalid_argument (m);}; @@ -101,7 +103,10 @@ namespace butl ep = *e == '~'; } - size_t p (0); + // Note that here and below p is less or equal n, and so s[p] is always + // valid. + // + size_t p (0), n (s.size ()); if (ep) { @@ -110,59 +115,70 @@ namespace butl } uint16_t ma, mi, bf, ab (0); + bool earliest (false); ma = parse_num (s, p, "invalid major version"); - // Note that here and below p is less or equal n, and so s[p] is always - // valid. + // The only valid version that has no epoch, contains only the major + // version being equal to zero, that is optionally followed by the plus + // character, is the stub version, unless forbidden. For such a version + // we go straight to the package revision parsing. // - if (s[p] != '.') - bail ("'.' expected after major version"); + bool stub ((f & allow_stub) != 0 && !ep && ma == 0 && + (p == n || s[p] == '+')); - mi = parse_num (s, ++p, "invalid minor version"); + if (!stub) + { + if (s[p] != '.') + bail ("'.' expected after major version"); - if (s[p] != '.') - bail ("'.' expected after minor version"); + mi = parse_num (s, ++p, "invalid minor version"); - bf = parse_num (s, ++p, "invalid bugfix version"); + if (s[p] != '.') + bail ("'.' expected after minor version"); - // AAABBBCCCDDDE - version = ma * 10000000000ULL + - mi * 10000000ULL + - bf * 10000ULL; + bf = parse_num (s, ++p, "invalid patch version"); - if (version == 0) - bail ("0.0.0 version"); + // AAABBBCCCDDDE + version = ma * 10000000000ULL + + mi * 10000000ULL + + bf * 10000ULL; - // Parse the pre-release component if present. - // - bool earliest (false); - if (s[p] == '-') - { - char k (s[++p]); + if (version == 0) + bail ("0.0.0 version"); - if (k == '\0' && allow_earliest) // Dash is the last string character. - earliest = true; - else + // Parse the pre-release component if present. + // + if (s[p] == '-') { - if (k != 'a' && k != 'b') - bail ("'a' or 'b' expected in pre-release"); - - if (s[++p] != '.') - bail ("'.' expected after pre-release letter"); - - ab = parse_num (s, ++p, "invalid pre-release", 0, 499); - - if (k == 'b') - ab += 500; + char k (s[++p]); - // Parse the snapshot components if present. Note that pre-release number - // can't be zero for the final pre-release. + // If the last character in the string is dash, then this is the + // earliest version pre-release, unless forbidden. // - if (s[p] == '.') - parse_snapshot (s, ++p); - else if (ab == 0 || ab == 500) - bail ("invalid final pre-release"); + if (k == '\0' && (f & allow_earliest) != 0) + earliest = true; + else + { + if (k != 'a' && k != 'b') + bail ("'a' or 'b' expected in pre-release"); + + if (s[++p] != '.') + bail ("'.' expected after pre-release letter"); + + ab = parse_num (s, ++p, "invalid pre-release", 0, 499); + + if (k == 'b') + ab += 500; + + // Parse the snapshot components if present. Note that pre-release + // number can't be zero for the final pre-release. + // + if (s[p] == '.') + parse_snapshot (s, ++p); + else if (ab == 0 || ab == 500) + bail ("invalid final pre-release"); + } } } @@ -173,7 +189,7 @@ namespace butl revision = parse_num (s, ++p, "invalid revision", 1, uint16_t (~0)); } - if (p != s.size ()) + if (p != n) bail ("junk after version"); if (ab != 0 || snapshot_sn != 0 || earliest) @@ -184,18 +200,18 @@ namespace butl } standard_version:: - standard_version (uint64_t v, bool allow_earliest) + standard_version (uint64_t v, flags f) : version (v) { - check_version (v, false, allow_earliest); + check_version (v, false, f); } standard_version:: - standard_version (uint64_t v, const std::string& s, bool allow_earliest) + standard_version (uint64_t v, const std::string& s, flags f) : version (v) { bool snapshot (!s.empty ()); - check_version (version, snapshot, allow_earliest); + check_version (version, snapshot, f); if (snapshot) { @@ -213,14 +229,23 @@ namespace butl uint64_t sn, std::string si, uint16_t rv, - bool allow_earliest) + flags fl) : epoch (ep), version (vr), snapshot_sn (sn), snapshot_id (move (si)), revision (rv) { - check_version (vr, true, allow_earliest); + check_version (vr, true, fl); + + if (stub ()) + { + if (ep != 0) + throw invalid_argument ("epoch for stub"); + + if (sn != 0) + throw invalid_argument ("snapshot for stub"); + } if (!snapshot_id.empty () && (snapshot_id.size () > 16 || snapshot_sn == 0 || @@ -286,6 +311,9 @@ namespace butl string standard_version:: string_version () const { + if (stub ()) + return "0"; + std::string r (to_string (major ()) + '.' + to_string (minor ()) + '.' + to_string (patch ())); @@ -395,7 +423,8 @@ namespace butl try { - min_version = standard_version (s.substr (p, e - p), true); + min_version = standard_version (s.substr (p, e - p), + standard_version::allow_earliest); } catch (const invalid_argument& e) { @@ -412,7 +441,8 @@ namespace butl try { - max_version = standard_version (s.substr (p, e - p), true); + max_version = standard_version (s.substr (p, e - p), + standard_version::allow_earliest); } catch (const invalid_argument& e) { @@ -460,7 +490,10 @@ namespace butl try { - v = standard_version (s.substr (p), operation != comparison::eq); + v = standard_version (s.substr (p), + operation != comparison::eq + ? standard_version::allow_earliest + : standard_version::none); } catch (const invalid_argument& e) { |