diff options
| author | Veikka Tuominen <git@vexu.eu> | 2020-11-18 16:06:52 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-18 16:06:52 +0200 |
| commit | ee1d21bbef04d7f77f7b1260540ab6a3342ff750 (patch) | |
| tree | ccb7e6594e3d67dc81b2a3f0f1016f5cef6a41b8 /lib/std | |
| parent | c492ef97fdc7c7c71c4656b0553214c61604be49 (diff) | |
| parent | 39841d5e2c97a6b04834ae82a30db27cff01f17f (diff) | |
| download | zig-ee1d21bbef04d7f77f7b1260540ab6a3342ff750.tar.gz zig-ee1d21bbef04d7f77f7b1260540ab6a3342ff750.zip | |
Merge pull request #6649 from Rocknest/verparse
make Version.parse less strict
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/builtin.zig | 73 | ||||
| -rw-r--r-- | lib/std/zig/system.zig | 13 |
2 files changed, 72 insertions, 14 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 97555dc9a5..19d3337138 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -490,11 +490,26 @@ pub const Version = struct { } pub fn parse(text: []const u8) !Version { - var it = std.mem.split(text, "."); + var end: usize = 0; + while (end < text.len) : (end += 1) { + const c = text[end]; + if (!std.ascii.isDigit(c) and c != '.') break; + } + // found no digits or '.' before unexpected character + if (end == 0) return error.InvalidVersion; + + var it = std.mem.split(text[0..end], "."); + // substring is not empty, first call will succeed + const major = it.next().?; + if (major.len == 0) return error.InvalidVersion; + const minor = it.next() orelse "0"; + // ignore 'patch' if 'minor' is invalid + const patch = if (minor.len == 0) "0" else (it.next() orelse "0"); + return Version{ - .major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10), - .minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10), - .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10), + .major = try std.fmt.parseUnsigned(u32, major, 10), + .minor = try std.fmt.parseUnsigned(u32, if (minor.len == 0) "0" else minor, 10), + .patch = try std.fmt.parseUnsigned(u32, if (patch.len == 0) "0" else patch, 10), }; } @@ -520,6 +535,56 @@ pub const Version = struct { } }; +test "Version.parse" { + @setEvalBranchQuota(3000); + try testVersionParse(); + comptime (try testVersionParse()); +} + +pub fn testVersionParse() !void { + const f = struct { + fn eql(text: []const u8, v1: u32, v2: u32, v3: u32) !void { + const v = try Version.parse(text); + std.testing.expect(v.major == v1 and v.minor == v2 and v.patch == v3); + } + + fn err(text: []const u8, expected_err: anyerror) !void { + _ = Version.parse(text) catch |actual_err| { + if (actual_err == expected_err) return; + return actual_err; + }; + return error.Unreachable; + } + }; + + try f.eql("2.6.32.11-svn21605", 2, 6, 32); // Debian PPC + try f.eql("2.11.2(0.329/5/3)", 2, 11, 2); // MinGW + try f.eql("5.4.0-1018-raspi", 5, 4, 0); // Ubuntu + try f.eql("5.7.12_3", 5, 7, 12); // Void + try f.eql("2.13-DEVELOPMENT", 2, 13, 0); // DragonFly + try f.eql("2.3-35", 2, 3, 0); + try f.eql("1a.4", 1, 0, 0); + try f.eql("3.b1.0", 3, 0, 0); + try f.eql("1.4beta", 1, 4, 0); + try f.eql("2.7.pre", 2, 7, 0); + try f.eql("0..3", 0, 0, 0); + try f.eql("8.008.", 8, 8, 0); + try f.eql("01...", 1, 0, 0); + try f.eql("55", 55, 0, 0); + try f.eql("4294967295.0.1", 4294967295, 0, 1); + try f.eql("429496729_6", 429496729, 0, 0); + + try f.err("foobar", error.InvalidVersion); + try f.err("", error.InvalidVersion); + try f.err("-1", error.InvalidVersion); + try f.err("+4", error.InvalidVersion); + try f.err(".", error.InvalidVersion); + try f.err("....3", error.InvalidVersion); + try f.err("4294967296", error.Overflow); + try f.err("5000877755", error.Overflow); + // error.InvalidCharacter is not possible anymore +} + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const CallOptions = struct { diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 071d234be3..cfaeb180c3 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -211,16 +211,9 @@ pub const NativeTargetInfo = struct { .linux => { const uts = std.os.uname(); const release = mem.spanZ(&uts.release); - // The release field may have several other fields after the - // kernel version - const kernel_version = if (mem.indexOfScalar(u8, release, '-')) |pos| - release[0..pos] - else if (mem.indexOfScalar(u8, release, '_')) |pos| - release[0..pos] - else - release; - - if (std.builtin.Version.parse(kernel_version)) |ver| { + // The release field sometimes has a weird format, + // `Version.parse` will attempt to find some meaningful interpretation. + if (std.builtin.Version.parse(release)) |ver| { os.version_range.linux.range.min = ver; os.version_range.linux.range.max = ver; } else |err| switch (err) { |
