mirror of
https://github.com/ziglang/zig.git
synced 2025-12-21 05:33:15 +00:00
123 lines
3.8 KiB
Zig
Vendored
123 lines
3.8 KiB
Zig
Vendored
const std = @import("std");
|
|
const mem = std.mem;
|
|
const Order = std.math.Order;
|
|
|
|
const GCCVersion = @This();
|
|
|
|
/// Raw version number text
|
|
raw: []const u8 = "",
|
|
|
|
/// -1 indicates not present
|
|
major: i32 = -1,
|
|
/// -1 indicates not present
|
|
minor: i32 = -1,
|
|
/// -1 indicates not present
|
|
patch: i32 = -1,
|
|
|
|
/// Text of parsed major version number
|
|
major_str: []const u8 = "",
|
|
/// Text of parsed major + minor version number
|
|
minor_str: []const u8 = "",
|
|
|
|
/// Patch number suffix
|
|
suffix: []const u8 = "",
|
|
|
|
/// This orders versions according to the preferred usage order, not a notion of release-time ordering
|
|
/// Higher version numbers are preferred, but nonexistent minor/patch/suffix is preferred to one that does exist
|
|
/// e.g. `4.1` is preferred over `4.0` but `4` is preferred over both `4.0` and `4.1`
|
|
pub fn isLessThan(self: GCCVersion, rhs_major: i32, rhs_minor: i32, rhs_patch: i32, rhs_suffix: []const u8) bool {
|
|
if (self.major != rhs_major) {
|
|
return self.major < rhs_major;
|
|
}
|
|
if (self.minor != rhs_minor) {
|
|
if (rhs_minor == -1) return true;
|
|
if (self.minor == -1) return false;
|
|
return self.minor < rhs_minor;
|
|
}
|
|
if (self.patch != rhs_patch) {
|
|
if (rhs_patch == -1) return true;
|
|
if (self.patch == -1) return false;
|
|
return self.patch < rhs_patch;
|
|
}
|
|
if (!mem.eql(u8, self.suffix, rhs_suffix)) {
|
|
if (rhs_suffix.len == 0) return true;
|
|
if (self.suffix.len == 0) return false;
|
|
return switch (std.mem.order(u8, self.suffix, rhs_suffix)) {
|
|
.lt => true,
|
|
.eq => unreachable,
|
|
.gt => false,
|
|
};
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Strings in the returned GCCVersion struct have the same lifetime as `text`
|
|
pub fn parse(text: []const u8) GCCVersion {
|
|
const bad = GCCVersion{ .major = -1 };
|
|
var good = bad;
|
|
|
|
var it = mem.splitScalar(u8, text, '.');
|
|
const first = it.next().?;
|
|
const second = it.next() orelse "";
|
|
const rest = it.next() orelse "";
|
|
|
|
good.major = std.fmt.parseInt(i32, first, 10) catch return bad;
|
|
if (good.major < 0) return bad;
|
|
good.major_str = first;
|
|
|
|
if (second.len == 0) return good;
|
|
var minor_str = second;
|
|
|
|
if (rest.len == 0) {
|
|
const end = mem.indexOfNone(u8, minor_str, "0123456789") orelse minor_str.len;
|
|
if (end > 0) {
|
|
good.suffix = minor_str[end..];
|
|
minor_str = minor_str[0..end];
|
|
}
|
|
}
|
|
good.minor = std.fmt.parseInt(i32, minor_str, 10) catch return bad;
|
|
if (good.minor < 0) return bad;
|
|
good.minor_str = minor_str;
|
|
|
|
if (rest.len > 0) {
|
|
const end = mem.indexOfNone(u8, rest, "0123456789") orelse rest.len;
|
|
if (end > 0) {
|
|
const patch_num_text = rest[0..end];
|
|
good.patch = std.fmt.parseInt(i32, patch_num_text, 10) catch return bad;
|
|
if (good.patch < 0) return bad;
|
|
good.suffix = rest[end..];
|
|
}
|
|
}
|
|
|
|
return good;
|
|
}
|
|
|
|
pub fn order(a: GCCVersion, b: GCCVersion) Order {
|
|
if (a.isLessThan(b.major, b.minor, b.patch, b.suffix)) return .lt;
|
|
if (b.isLessThan(a.major, a.minor, a.patch, a.suffix)) return .gt;
|
|
return .eq;
|
|
}
|
|
|
|
test parse {
|
|
const versions = [10]GCCVersion{
|
|
parse("5"),
|
|
parse("4"),
|
|
parse("4.2"),
|
|
parse("4.0"),
|
|
parse("4.0-patched"),
|
|
parse("4.0.2"),
|
|
parse("4.0.1"),
|
|
parse("4.0.1-patched"),
|
|
parse("4.0.0"),
|
|
parse("4.0.0-patched"),
|
|
};
|
|
|
|
for (versions[0 .. versions.len - 1], versions[1..versions.len]) |first, second| {
|
|
try std.testing.expectEqual(Order.eq, first.order(first));
|
|
try std.testing.expectEqual(Order.gt, first.order(second));
|
|
try std.testing.expectEqual(Order.lt, second.order(first));
|
|
}
|
|
const last = versions[versions.len - 1];
|
|
try std.testing.expectEqual(Order.eq, last.order(last));
|
|
}
|