Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/std/SemanticVersion.zig
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ pub fn parse(text: []const u8) !Version {
return ver;
}

fn parseNum(text: []const u8) !usize {
fn parseNum(text: []const u8) error{ InvalidVersion, Overflow }!usize {
// Leading zeroes are not allowed.
if (text.len > 1 and text[0] == '0') return error.InvalidVersion;

return std.fmt.parseUnsigned(usize, text, 10) catch |err| switch (err) {
error.InvalidCharacter => return error.InvalidVersion,
else => |e| return e,
error.Overflow => return error.Overflow,
};
}

Expand Down
36 changes: 21 additions & 15 deletions lib/std/zig/CrossTarget.zig
Original file line number Diff line number Diff line change
Expand Up @@ -354,31 +354,37 @@ pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch {
}
}

/// Parses a version with an omitted patch component, such as "1.0",
/// which SemanticVersion.parse is not capable of.
fn parseVersion(ver: []const u8) !SemanticVersion {
const parseVersionComponent = struct {
fn parseVersionComponent(component: []const u8) !usize {
return std.fmt.parseUnsigned(usize, component, 10) catch |err| {
switch (err) {
error.InvalidCharacter => return error.InvalidVersion,
error.Overflow => return error.Overflow,
}
/// Similar to `SemanticVersion.parse`, but with following changes:
/// * Leading zeroes are allowed.
/// * Supports only 2 or 3 version components (major, minor, [patch]). If 3-rd component is omitted, it will be 0.
pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticVersion {
const parseVersionComponentFn = (struct {
fn parseVersionComponentInner(component: []const u8) error{ InvalidVersion, Overflow }!usize {
return std.fmt.parseUnsigned(usize, component, 10) catch |err| switch (err) {
error.InvalidCharacter => return error.InvalidVersion,
error.Overflow => return error.Overflow,
};
}
}.parseVersionComponent;
var version_components = mem.split(u8, ver, ".");
}).parseVersionComponentInner;
var version_components = mem.splitScalar(u8, ver, '.');
const major = version_components.first();
const minor = version_components.next() orelse return error.InvalidVersion;
const patch = version_components.next() orelse "0";
if (version_components.next() != null) return error.InvalidVersion;
return .{
.major = try parseVersionComponent(major),
.minor = try parseVersionComponent(minor),
.patch = try parseVersionComponent(patch),
.major = try parseVersionComponentFn(major),
.minor = try parseVersionComponentFn(minor),
.patch = try parseVersionComponentFn(patch),
};
}

test parseVersion {
try std.testing.expectError(error.InvalidVersion, parseVersion("1"));
try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 0 }, try parseVersion("1.2"));
try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 3 }, try parseVersion("1.2.3"));
try std.testing.expectError(error.InvalidVersion, parseVersion("1.2.3.4"));
}

/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
pub fn getCpu(self: CrossTarget) Target.Cpu {
switch (self.cpu_model) {
Expand Down
19 changes: 15 additions & 4 deletions lib/std/zig/system/NativeTargetInfo.zig
Original file line number Diff line number Diff line change
Expand Up @@ -557,15 +557,15 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
var buf: [80000]u8 = undefined;
if (buf.len < dynstr.size) return error.InvalidGnuLibCVersion;

const dynstr_size = @as(usize, @intCast(dynstr.size));
const dynstr_size: usize = @intCast(dynstr.size);
const dynstr_bytes = buf[0..dynstr_size];
_ = try preadMin(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len);
var it = mem.splitScalar(u8, dynstr_bytes, 0);
var max_ver: std.SemanticVersion = .{ .major = 2, .minor = 2, .patch = 5 };
while (it.next()) |s| {
if (mem.startsWith(u8, s, "GLIBC_2.")) {
const chopped = s["GLIBC_".len..];
const ver = std.SemanticVersion.parse(chopped) catch |err| switch (err) {
const ver = CrossTarget.parseVersion(chopped) catch |err| switch (err) {
error.Overflow => return error.InvalidGnuLibCVersion,
error.InvalidVersion => return error.InvalidGnuLibCVersion,
};
Expand All @@ -578,7 +578,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
return max_ver;
}

fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.SemanticVersion {
fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) error{ UnrecognizedGnuLibCFileName, InvalidGnuLibCVersion }!std.SemanticVersion {
// example: "libc-2.3.4.so"
// example: "libc-2.27.so"
// example: "ld-2.33.so"
Expand All @@ -588,12 +588,23 @@ fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.Semantic
}
// chop off "libc-" and ".so"
const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len];
return std.SemanticVersion.parse(link_name_chopped) catch |err| switch (err) {
return CrossTarget.parseVersion(link_name_chopped) catch |err| switch (err) {
error.Overflow => return error.InvalidGnuLibCVersion,
error.InvalidVersion => return error.InvalidGnuLibCVersion,
};
}

test glibcVerFromLinkName {
try std.testing.expectError(error.UnrecognizedGnuLibCFileName, glibcVerFromLinkName("ld-2.37.so", "this-prefix-does-not-exist"));
try std.testing.expectError(error.UnrecognizedGnuLibCFileName, glibcVerFromLinkName("libc-2.37.so-is-not-end", "libc-"));

try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.so", "ld-"));
try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 0 }, try glibcVerFromLinkName("ld-2.37.so", "ld-"));
try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 0 }, try glibcVerFromLinkName("ld-2.37.0.so", "ld-"));
try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 1 }, try glibcVerFromLinkName("ld-2.37.1.so", "ld-"));
try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.37.4.5.so", "ld-"));
}

pub const AbiAndDynamicLinkerFromFileError = error{
FileSystem,
SystemResources,
Expand Down
21 changes: 1 addition & 20 deletions lib/std/zig/system/darwin/macos.zig
Original file line number Diff line number Diff line change
Expand Up @@ -87,26 +87,7 @@ fn parseSystemVersion(buf: []const u8) !std.SemanticVersion {
const ver = try svt.expectContent();
try svt.skipUntilTag(.end, "string");

const parseVersionComponent = struct {
fn parseVersionComponent(component: []const u8) !usize {
return std.fmt.parseUnsigned(usize, component, 10) catch |err| {
switch (err) {
error.InvalidCharacter => return error.InvalidVersion,
error.Overflow => return error.Overflow,
}
};
}
}.parseVersionComponent;
var version_components = mem.split(u8, ver, ".");
const major = version_components.first();
const minor = version_components.next() orelse return error.InvalidVersion;
const patch = version_components.next() orelse "0";
if (version_components.next() != null) return error.InvalidVersion;
return .{
.major = try parseVersionComponent(major),
.minor = try parseVersionComponent(minor),
.patch = try parseVersionComponent(patch),
};
return try std.zig.CrossTarget.parseVersion(ver);
}

const SystemVersionTokenizer = struct {
Expand Down