31#include <simgear/misc/strutils.hxx>
32#include <simgear/nasal/cppbind/Ghost.hxx>
33#include <simgear/nasal/cppbind/NasalCallContext.hxx>
34#include <simgear/nasal/cppbind/NasalHash.hxx>
35#include <simgear/sg_inlines.h>
36#include <simgear/structure/exception.hxx>
43using simgear::enumValue;
45namespace strutils = simgear::strutils;
59 bool developmental,
int devNum)
60 : _preReleaseType(preReleaseType),
61 _preReleaseNum(preReleaseNum),
62 _developmental(developmental),
70 const std::tuple<AddonVersionSuffixPrereleaseType, int, bool, int>& t)
87 switch (releaseType) {
97 throw sg_error(
"unexpected value for member of "
98 "flightgear::addons::AddonVersionSuffixPrereleaseType: " +
99 std::to_string(enumValue(releaseType)));
106 string res = releaseTypeStr(_preReleaseType);
109 res += std::to_string(_preReleaseNum);
112 if (_developmental) {
113 res +=
".dev" + std::to_string(_devNum);
120std::tuple<AddonVersionSuffixPrereleaseType, int, bool, int>
121AddonVersionSuffix::suffixStringToTuple(
const std::string& suffix)
123#ifdef HAVE_WORKING_STD_REGEX
128 std::regex versionSuffixRegexp(R
"((?:(a|b|rc)(\d+))?(?:\.dev(\d+))?)");
131 if (std::regex_match(suffix, results, versionSuffixRegexp)) {
132 const string preReleaseType_s = results.str(1);
133 const string preReleaseNum_s = results.str(2);
134 const string devNum_s = results.str(3);
137 int preReleaseNum = 0;
140 if (preReleaseType_s.empty()) {
143 if (preReleaseType_s ==
"a") {
145 }
else if (preReleaseType_s ==
"b") {
147 }
else if (preReleaseType_s ==
"rc") {
153 assert(!preReleaseNum_s.empty());
154 preReleaseNum = strutils::readNonNegativeInt<int>(preReleaseNum_s);
156 if (preReleaseNum < 1) {
157 string msg =
"invalid add-on version suffix: '" + suffix +
"' "
158 "(prerelease number must be greater than or equal to 1, but got " +
159 preReleaseNum_s +
")";
160 throw sg_format_exception(msg, suffix);
164 if (!devNum_s.empty()) {
165 devNum = strutils::readNonNegativeInt<int>(devNum_s);
168 string msg =
"invalid add-on version suffix: '" + suffix +
"' "
169 "(development release number must be greater than or equal to 1, "
170 "but got " + devNum_s +
")";
171 throw sg_format_exception(msg, suffix);
175 return std::make_tuple(preReleaseType, preReleaseNum, !devNum_s.empty(),
184 std::tie(isMatch, preReleaseType, preReleaseNum, developmental, devNum) =
185 parseVersionSuffixString_noRegexp(suffix);
188 return std::make_tuple(preReleaseType, preReleaseNum, developmental,
192 string msg =
"invalid add-on version suffix: '" + suffix +
"' "
193 "(expected form is [{a|b|rc}N1][.devN2] where N1 and N2 are positive "
195 throw sg_format_exception(msg, suffix);
202std::tuple<bool, AddonVersionSuffixPrereleaseType, int, bool, int>
203AddonVersionSuffix::parseVersionSuffixString_noRegexp(
const string& suffix)
207 int preReleaseNum = 0;
209 bool developmental =
false;
212 std::tie(preReleaseType, rest) = popPrereleaseTypeFromBeginning(suffix);
215 std::size_t startPrerelNum = rest.find_first_of(
"0123456789");
216 if (startPrerelNum != 0) {
217 return std::make_tuple(
false, preReleaseType, preReleaseNum,
false,
221 std::size_t endPrerelNum = rest.find_first_not_of(
"0123456789", 1);
223 string preReleaseNum_s = rest.substr(0, endPrerelNum);
224 preReleaseNum = strutils::readNonNegativeInt<int>(preReleaseNum_s);
226 if (preReleaseNum < 1) {
227 string msg =
"invalid add-on version suffix: '" + suffix +
"' "
228 "(prerelease number must be greater than or equal to 1, but got " +
229 preReleaseNum_s +
")";
230 throw sg_format_exception(msg, suffix);
233 rest = (endPrerelNum == string::npos) ?
"" : rest.substr(endPrerelNum);
236 if (strutils::starts_with(rest,
".dev")) {
237 rest = rest.substr(4);
238 std::size_t startDevNum = rest.find_first_of(
"0123456789");
239 if (startDevNum != 0) {
240 return std::make_tuple(
false, preReleaseType, preReleaseNum,
false,
244 std::size_t endDevNum = rest.find_first_not_of(
"0123456789", 1);
245 if (endDevNum != string::npos) {
248 return std::make_tuple(
false, preReleaseType, preReleaseNum,
false,
252 devNum = strutils::readNonNegativeInt<int>(rest);
254 string msg =
"invalid add-on version suffix: '" + suffix +
"' "
255 "(development release number must be greater than or equal to 1, "
256 "but got " + rest +
")";
257 throw sg_format_exception(msg, suffix);
260 developmental =
true;
263 return std::make_tuple(
true, preReleaseType, preReleaseNum, developmental,
268std::tuple<AddonVersionSuffixPrereleaseType, string>
269AddonVersionSuffix::popPrereleaseTypeFromBeginning(
const string& s)
273 }
else if (s[0] ==
'a') {
276 }
else if (s[0] ==
'b') {
278 }
else if (strutils::starts_with(s,
"rc")) {
287std::tuple<AddonVersionSuffixPrereleaseType, int, bool, int>
290 return std::make_tuple(_preReleaseType, _preReleaseNum, _developmental,
295 std::underlying_type<AddonVersionSuffixPrereleaseType>::type,
297AddonVersionSuffix::genSortKey()
const
304 return std::make_tuple(
305 ((_developmental && _preReleaseType == AddonRelType::none) ? 0 : 1),
306 enumValue(_preReleaseType),
308 (_developmental ? 0 : 1),
313{
return lhs.genSortKey() == rhs.genSortKey(); }
319{
return lhs.genSortKey() < rhs.genSortKey(); }
332{
return os << addonVersionSuffix.
str(); }
343 _suffix(std::move(
suffix))
349 const std::tuple<int, int, int, AddonVersionSuffix>& t)
350 :
AddonVersion(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t))
362std::tuple<int, int, int, AddonVersionSuffix>
363AddonVersion::versionStringToTuple(
const std::string& versionStr)
365#ifdef HAVE_WORKING_STD_REGEX
370 std::regex versionRegexp(R
"((\d+)\.(\d+).(\d+)(.*))");
373 if (std::regex_match(versionStr, results, versionRegexp)) {
374 const string majorNumber_s = results.str(1);
375 const string minorNumber_s = results.str(2);
376 const string patchLevel_s = results.str(3);
377 const string suffix_s = results.str(4);
379 int major = strutils::readNonNegativeInt<int>(majorNumber_s);
380 int minor = strutils::readNonNegativeInt<int>(minorNumber_s);
381 int patchLevel = strutils::readNonNegativeInt<int>(patchLevel_s);
383 return std::make_tuple(major, minor,
patchLevel,
391 parseVersionString_noRegexp(versionStr);
397 string msg =
"invalid add-on version number: '" + versionStr +
"' "
398 "(expected form is MAJOR.MINOR.PATCHLEVEL[{a|b|rc}N1][.devN2] where "
399 "N1 and N2 are positive integers)";
400 throw sg_format_exception(msg, versionStr);
407std::tuple<bool, int, int, int, AddonVersionSuffix>
408AddonVersion::parseVersionString_noRegexp(
const string& versionStr)
411 AddonVersionSuffix
suffix{};
414 std::size_t endMajor = versionStr.find_first_not_of(
"0123456789");
415 if (endMajor == 0 || endMajor == string::npos) {
418 major = strutils::readNonNegativeInt<int>(versionStr.substr(0, endMajor));
421 if (versionStr.size() < endMajor + 1 || versionStr[endMajor] !=
'.') {
424 string rest = versionStr.substr(endMajor + 1);
427 std::size_t endMinor = rest.find_first_not_of(
"0123456789");
428 if (endMinor == 0 || endMinor == string::npos) {
431 minor = strutils::readNonNegativeInt<int>(rest.substr(0, endMinor));
434 if (rest.size() < endMinor + 1 || rest[endMinor] !=
'.') {
437 rest = rest.substr(endMinor + 1);
440 std::size_t endPatchLevel = rest.find_first_not_of(
"0123456789");
441 if (endPatchLevel == 0) {
444 patchLevel = strutils::readNonNegativeInt<int>(rest.substr(0, endPatchLevel));
446 if (endPatchLevel != string::npos) {
447 suffix = AddonVersionSuffix(rest.substr(endPatchLevel));
460{
return _patchLevel; }
468std::tuple<int, int, int, AddonVersionSuffix> AddonVersion::makeTuple()
const
477 string relSeg = std::accumulate(std::next(v.begin()), v.end(),
478 std::to_string(v[0]),
479 [](
string s,
int num) {
480 return s +
'.' + std::to_string(num);
489{
return lhs.makeTuple() == rhs.makeTuple(); }
495{
return lhs.makeTuple() < rhs.makeTuple(); }
507{
return os << addonVersion.
str(); }
517 return *
this == *other;
523 return *
this != *other;
529 return *
this < *other;
535 return *
this <= *other;
541 return *
this > *other;
547 return *
this >= *other;
553 nasal::Ghost<AddonVersionRef>::init(
"addons.AddonVersion")
friend bool operator<(const AddonVersionSuffix &lhs, const AddonVersionSuffix &rhs)
AddonVersionSuffix(AddonVersionSuffixPrereleaseType _preReleaseType=AddonVersionSuffixPrereleaseType::none, int preReleaseNum=0, bool developmental=false, int devNum=0)
std::tuple< AddonVersionSuffixPrereleaseType, int, bool, int > makeTuple() const
friend bool operator==(const AddonVersionSuffix &lhs, const AddonVersionSuffix &rhs)
std::string suffixStr() const
bool lowerThan(const nasal::CallContext &ctx) const
bool nonEqual(const nasal::CallContext &ctx) const
friend bool operator==(const AddonVersion &lhs, const AddonVersion &rhs)
bool equal(const nasal::CallContext &ctx) const
bool lowerThanOrEqual(const nasal::CallContext &ctx) const
AddonVersionSuffix suffix() const
static void setupGhost(nasal::Hash &addonsModule)
bool greaterThan(const nasal::CallContext &ctx) const
bool greaterThanOrEqual(const nasal::CallContext &ctx) const
friend bool operator<(const AddonVersion &lhs, const AddonVersion &rhs)
AddonVersion(int major=0, int minor=0, int patchLevel=0, AddonVersionSuffix suffix=AddonVersionSuffix())
bool operator>(const AddonVersionSuffix &lhs, const AddonVersionSuffix &rhs)
bool operator<=(const AddonVersionSuffix &lhs, const AddonVersionSuffix &rhs)
bool operator>=(const AddonVersionSuffix &lhs, const AddonVersionSuffix &rhs)
std::ostream & operator<<(std::ostream &os, const Addon &addon)
AddonVersionSuffixPrereleaseType
bool operator!=(const AddonVersionSuffix &lhs, const AddonVersionSuffix &rhs)
SGSharedPtr< AddonVersion > AddonVersionRef
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...