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
18namespace base {
19
20Version::Version()
21{
22}
23
24Version::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
66Version::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
77bool 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
112bool Version::operator==(const Version& other) const
113{
114 return (m_numbers == other.m_numbers &&
115 m_prereleaseLabel == other.m_prereleaseLabel);
116}
117
118std::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