1 | // LAF Base Library |
2 | // Copyright (c) 2019-2021 Igara Studio S.A. |
3 | // Copyright (c) 2001-2016 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "base/version.h" |
13 | |
14 | #include "base/convert_to.h" |
15 | |
16 | #include <cctype> |
17 | |
18 | namespace base { |
19 | |
20 | Version::Version() |
21 | { |
22 | } |
23 | |
24 | Version::Version(const std::string& from) |
25 | { |
26 | std::string::size_type i = 0; |
27 | std::string::size_type j = 0; |
28 | std::string::size_type k = from.find('-', 0); |
29 | |
30 | while ((j != std::string::npos) && |
31 | (k == std::string::npos || j < k)) { |
32 | j = from.find('.', i); |
33 | |
34 | std::string number; |
35 | if (j != std::string::npos) { |
36 | number = from.substr(i, j - i); |
37 | i = j+1; |
38 | } |
39 | else { |
40 | if (from.size() == i) // Empty string |
41 | break; |
42 | |
43 | number = from.substr(i); |
44 | } |
45 | |
46 | m_numbers.push_back(convert_to<int>(number)); |
47 | } |
48 | |
49 | if (k != std::string::npos) { |
50 | auto k0 = ++k; |
51 | for (; k < from.size() && !std::isdigit(from[k]); ++k) |
52 | ; |
53 | if (k < from.size()) { |
54 | m_prereleaseNumber = convert_to<int>(from.substr(k)); |
55 | m_prereleaseLabel = from.substr(k0, k - k0); |
56 | } |
57 | else |
58 | m_prereleaseLabel = from.substr(k0); |
59 | } |
60 | |
61 | while (!m_prereleaseLabel.empty() && |
62 | m_prereleaseLabel[m_prereleaseLabel.size()-1] == '.') |
63 | m_prereleaseLabel.erase(m_prereleaseLabel.size()-1); |
64 | } |
65 | |
66 | Version::Version(int major, int minor, int patch, int build) |
67 | { |
68 | m_numbers.push_back(major); |
69 | if (minor || patch || build) |
70 | m_numbers.push_back(minor); |
71 | if (patch || build) |
72 | m_numbers.push_back(patch); |
73 | if (build) |
74 | m_numbers.push_back(build); |
75 | } |
76 | |
77 | bool Version::operator<(const Version& other) const |
78 | { |
79 | Numbers::const_iterator |
80 | it1 = m_numbers.begin(), end1 = m_numbers.end(), |
81 | it2 = other.m_numbers.begin(), end2 = other.m_numbers.end(); |
82 | |
83 | while (it1 != end1 || it2 != end2) { |
84 | int number1 = (it1 != end1 ? *it1++: 0); |
85 | int number2 = (it2 != end2 ? *it2++: 0); |
86 | |
87 | if (number1 < number2) |
88 | return true; |
89 | else if (number1 > number2) |
90 | return false; |
91 | } |
92 | |
93 | if (m_prereleaseLabel.empty()) { |
94 | return false; |
95 | } |
96 | else if (other.m_prereleaseLabel.empty()) { |
97 | return true; |
98 | } |
99 | else { |
100 | int res = m_prereleaseLabel.compare(other.m_prereleaseLabel); |
101 | if (res < 0) |
102 | return true; |
103 | else if (res > 0) |
104 | return false; |
105 | else |
106 | return (m_prereleaseNumber < other.m_prereleaseNumber); |
107 | } |
108 | |
109 | return false; |
110 | } |
111 | |
112 | bool Version::operator==(const Version& other) const |
113 | { |
114 | return (m_numbers == other.m_numbers && |
115 | m_prereleaseLabel == other.m_prereleaseLabel); |
116 | } |
117 | |
118 | std::string Version::str() const |
119 | { |
120 | std::string res; |
121 | for (auto number : m_numbers) { |
122 | if (!res.empty()) |
123 | res.push_back('.'); |
124 | res += base::convert_to<std::string>(number); |
125 | } |
126 | if (!m_prereleaseLabel.empty()) { |
127 | res.push_back('-'); |
128 | res += m_prereleaseLabel; |
129 | if (m_prereleaseNumber) |
130 | res += base::convert_to<std::string>(m_prereleaseNumber); |
131 | } |
132 | return res; |
133 | } |
134 | |
135 | } // namespace base |
136 | |