Iterates via iterator and collects all folders with names starting with strip_prefix
and a version. Returns slice of version strings sorted in descending order.
Caller owns result.
fn iterateAndFilterByVersion(
iterator: *Dir.Iterator,
gpa: Allocator,
io: Io,
prefix: []const u8,
) error
fn iterateAndFilterByVersion(
iterator: *Dir.Iterator,
gpa: Allocator,
io: Io,
prefix: []const u8,
) error{OutOfMemory}![][]const u8 {
const Version = struct {
nums: [4]u32,
build: []const u8,
fn parseNum(num: []const u8) ?u32 {
if (num[0] == '0' and num.len > 1) return null;
return std.fmt.parseInt(u32, num, 10) catch null;
}
fn order(lhs: @This(), rhs: @This()) std.math.Order {
return std.mem.order(u32, &lhs.nums, &rhs.nums).differ() orelse
std.mem.order(u8, lhs.build, rhs.build);
}
};
var versions = std.array_list.Managed(Version).init(gpa);
var dirs = std.array_list.Managed([]const u8).init(gpa);
defer {
versions.deinit();
for (dirs.items) |filtered_dir| gpa.free(filtered_dir);
dirs.deinit();
}
iterate: while (iterator.next(io) catch null) |entry| {
if (entry.kind != .directory) continue;
if (!std.mem.startsWith(u8, entry.name, prefix)) continue;
var version: Version = .{
.nums = @splat(0),
.build = "",
};
const suffix = entry.name[prefix.len..];
const underscore = std.mem.findScalar(u8, entry.name, '_');
var num_it = std.mem.splitScalar(u8, suffix[0 .. underscore orelse suffix.len], '.');
version.nums[0] = Version.parseNum(num_it.first()) orelse continue;
for (version.nums[1..]) |*num|
num.* = Version.parseNum(num_it.next() orelse break) orelse continue :iterate
else if (num_it.next()) |_| continue;
const name = try gpa.dupe(u8, suffix);
errdefer gpa.free(name);
if (underscore) |pos| version.build = name[pos + 1 ..];
try versions.append(version);
try dirs.append(name);
}
std.mem.sortUnstableContext(0, dirs.items.len, struct {
versions: []Version,
dirs: [][]const u8,
pub fn lessThan(context: @This(), lhs: usize, rhs: usize) bool {
return context.versions[lhs].order(context.versions[rhs]).compare(.gt);
}
pub fn swap(context: @This(), lhs: usize, rhs: usize) void {
std.mem.swap(Version, &context.versions[lhs], &context.versions[rhs]);
std.mem.swap([]const u8, &context.dirs[lhs], &context.dirs[rhs]);
}
}{ .versions = versions.items, .dirs = dirs.items });
return dirs.toOwnedSlice();
}