authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-11-18 16:06:52+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-18 17:47:43-07:00
log50269f23155f65d702e3932f5a8bb08142e023ac
tree2305b55f3123ca3abebb4762f9b64b6dce2bd38e
parent8af0a1987b940732b13b6d4c4e33c00637f69dd5

Merge pull request #6649 from Rocknest/verparse

make Version.parse less strict

2 files changed, 72 insertions(+), 14 deletions(-)

lib/std/builtin.zig+69-4
......@@ -490,11 +490,26 @@ pub const Version = struct {
490490 }
491491
492492 pub fn parse(text: []const u8) !Version {
493 var it = std.mem.split(text, ".");
493 var end: usize = 0;
494 while (end < text.len) : (end += 1) {
495 const c = text[end];
496 if (!std.ascii.isDigit(c) and c != '.') break;
497 }
498 // found no digits or '.' before unexpected character
499 if (end == 0) return error.InvalidVersion;
500
501 var it = std.mem.split(text[0..end], ".");
502 // substring is not empty, first call will succeed
503 const major = it.next().?;
504 if (major.len == 0) return error.InvalidVersion;
505 const minor = it.next() orelse "0";
506 // ignore 'patch' if 'minor' is invalid
507 const patch = if (minor.len == 0) "0" else (it.next() orelse "0");
508
494509 return Version{
495 .major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
496 .minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
497 .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
510 .major = try std.fmt.parseUnsigned(u32, major, 10),
511 .minor = try std.fmt.parseUnsigned(u32, if (minor.len == 0) "0" else minor, 10),
512 .patch = try std.fmt.parseUnsigned(u32, if (patch.len == 0) "0" else patch, 10),
498513 };
499514 }
500515
......@@ -520,6 +535,56 @@ pub const Version = struct {
520535 }
521536};
522537
538test "Version.parse" {
539 @setEvalBranchQuota(3000);
540 try testVersionParse();
541 comptime (try testVersionParse());
542}
543
544pub fn testVersionParse() !void {
545 const f = struct {
546 fn eql(text: []const u8, v1: u32, v2: u32, v3: u32) !void {
547 const v = try Version.parse(text);
548 std.testing.expect(v.major == v1 and v.minor == v2 and v.patch == v3);
549 }
550
551 fn err(text: []const u8, expected_err: anyerror) !void {
552 _ = Version.parse(text) catch |actual_err| {
553 if (actual_err == expected_err) return;
554 return actual_err;
555 };
556 return error.Unreachable;
557 }
558 };
559
560 try f.eql("2.6.32.11-svn21605", 2, 6, 32); // Debian PPC
561 try f.eql("2.11.2(0.329/5/3)", 2, 11, 2); // MinGW
562 try f.eql("5.4.0-1018-raspi", 5, 4, 0); // Ubuntu
563 try f.eql("5.7.12_3", 5, 7, 12); // Void
564 try f.eql("2.13-DEVELOPMENT", 2, 13, 0); // DragonFly
565 try f.eql("2.3-35", 2, 3, 0);
566 try f.eql("1a.4", 1, 0, 0);
567 try f.eql("3.b1.0", 3, 0, 0);
568 try f.eql("1.4beta", 1, 4, 0);
569 try f.eql("2.7.pre", 2, 7, 0);
570 try f.eql("0..3", 0, 0, 0);
571 try f.eql("8.008.", 8, 8, 0);
572 try f.eql("01...", 1, 0, 0);
573 try f.eql("55", 55, 0, 0);
574 try f.eql("4294967295.0.1", 4294967295, 0, 1);
575 try f.eql("429496729_6", 429496729, 0, 0);
576
577 try f.err("foobar", error.InvalidVersion);
578 try f.err("", error.InvalidVersion);
579 try f.err("-1", error.InvalidVersion);
580 try f.err("+4", error.InvalidVersion);
581 try f.err(".", error.InvalidVersion);
582 try f.err("....3", error.InvalidVersion);
583 try f.err("4294967296", error.Overflow);
584 try f.err("5000877755", error.Overflow);
585 // error.InvalidCharacter is not possible anymore
586}
587
523588/// This data structure is used by the Zig language code generation and
524589/// therefore must be kept in sync with the compiler implementation.
525590pub const CallOptions = struct {
lib/std/zig/system.zig+3-10
......@@ -211,16 +211,9 @@ pub const NativeTargetInfo = struct {
211211 .linux => {
212212 const uts = std.os.uname();
213213 const release = mem.spanZ(&uts.release);
214 // The release field may have several other fields after the
215 // kernel version
216 const kernel_version = if (mem.indexOfScalar(u8, release, '-')) |pos|
217 release[0..pos]
218 else if (mem.indexOfScalar(u8, release, '_')) |pos|
219 release[0..pos]
220 else
221 release;
222
223 if (std.builtin.Version.parse(kernel_version)) |ver| {
214 // The release field sometimes has a weird format,
215 // `Version.parse` will attempt to find some meaningful interpretation.
216 if (std.builtin.Version.parse(release)) |ver| {
224217 os.version_range.linux.range.min = ver;
225218 os.version_range.linux.range.max = ver;
226219 } else |err| switch (err) {