| ... | @@ -43,17 +43,32 @@ pub fn isSep(byte: u8) bool { | ... | @@ -43,17 +43,32 @@ pub fn isSep(byte: u8) bool { |
| 43 | fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { | 43 | fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { |
| 44 | if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; | 44 | if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; |
| 45 | | 45 | |
| | 46 | // Find first non-empty path index. |
| | 47 | const first_path_index = blk: { |
| | 48 | for (paths) |path, index| { |
| | 49 | if (path.len == 0) continue else break :blk index; |
| | 50 | } |
| | 51 | |
| | 52 | // All paths provided were empty, so return early. |
| | 53 | return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; |
| | 54 | }; |
| | 55 | |
| | 56 | // Calculate length needed for resulting joined path buffer. |
| 46 | const total_len = blk: { | 57 | const total_len = blk: { |
| 47 | var sum: usize = paths[0].len; | 58 | var sum: usize = paths[first_path_index].len; |
| 48 | var i: usize = 1; | 59 | var prev_path = paths[first_path_index]; |
| | 60 | assert(prev_path.len > 0); |
| | 61 | var i: usize = first_path_index + 1; |
| 49 | while (i < paths.len) : (i += 1) { | 62 | while (i < paths.len) : (i += 1) { |
| 50 | const prev_path = paths[i - 1]; | | |
| 51 | const this_path = paths[i]; | 63 | const this_path = paths[i]; |
| 52 | const prev_sep = (prev_path.len != 0 and sepPredicate(prev_path[prev_path.len - 1])); | 64 | if (this_path.len == 0) continue; |
| 53 | const this_sep = (this_path.len != 0 and sepPredicate(this_path[0])); | 65 | const prev_sep = sepPredicate(prev_path[prev_path.len - 1]); |
| | 66 | const this_sep = sepPredicate(this_path[0]); |
| 54 | sum += @boolToInt(!prev_sep and !this_sep); | 67 | sum += @boolToInt(!prev_sep and !this_sep); |
| 55 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; | 68 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; |
| | 69 | prev_path = this_path; |
| 56 | } | 70 | } |
| | 71 | |
| 57 | if (zero) sum += 1; | 72 | if (zero) sum += 1; |
| 58 | break :blk sum; | 73 | break :blk sum; |
| 59 | }; | 74 | }; |
| ... | @@ -61,14 +76,16 @@ fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) boo | ... | @@ -61,14 +76,16 @@ fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) boo |
| 61 | const buf = try allocator.alloc(u8, total_len); | 76 | const buf = try allocator.alloc(u8, total_len); |
| 62 | errdefer allocator.free(buf); | 77 | errdefer allocator.free(buf); |
| 63 | | 78 | |
| 64 | mem.copy(u8, buf, paths[0]); | 79 | mem.copy(u8, buf, paths[first_path_index]); |
| 65 | var buf_index: usize = paths[0].len; | 80 | var buf_index: usize = paths[first_path_index].len; |
| 66 | var i: usize = 1; | 81 | var prev_path = paths[first_path_index]; |
| | 82 | assert(prev_path.len > 0); |
| | 83 | var i: usize = first_path_index + 1; |
| 67 | while (i < paths.len) : (i += 1) { | 84 | while (i < paths.len) : (i += 1) { |
| 68 | const prev_path = paths[i - 1]; | | |
| 69 | const this_path = paths[i]; | 85 | const this_path = paths[i]; |
| 70 | const prev_sep = (prev_path.len != 0 and sepPredicate(prev_path[prev_path.len - 1])); | 86 | if (this_path.len == 0) continue; |
| 71 | const this_sep = (this_path.len != 0 and sepPredicate(this_path[0])); | 87 | const prev_sep = sepPredicate(prev_path[prev_path.len - 1]); |
| | 88 | const this_sep = sepPredicate(this_path[0]); |
| 72 | if (!prev_sep and !this_sep) { | 89 | if (!prev_sep and !this_sep) { |
| 73 | buf[buf_index] = separator; | 90 | buf[buf_index] = separator; |
| 74 | buf_index += 1; | 91 | buf_index += 1; |
| ... | @@ -76,6 +93,7 @@ fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) boo | ... | @@ -76,6 +93,7 @@ fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) boo |
| 76 | const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path; | 93 | const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path; |
| 77 | mem.copy(u8, buf[buf_index..], adjusted_path); | 94 | mem.copy(u8, buf[buf_index..], adjusted_path); |
| 78 | buf_index += adjusted_path.len; | 95 | buf_index += adjusted_path.len; |
| | 96 | prev_path = this_path; |
| 79 | } | 97 | } |
| 80 | | 98 | |
| 81 | if (zero) buf[buf.len - 1] = 0; | 99 | if (zero) buf[buf.len - 1] = 0; |
| ... | @@ -148,6 +166,10 @@ test "join" { | ... | @@ -148,6 +166,10 @@ test "join" { |
| 148 | try testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero); | 166 | try testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero); |
| 149 | try testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero); | 167 | try testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero); |
| 150 | | 168 | |
| | 169 | try testJoinMaybeZWindows(&[_][]const u8{ "", "c:\\", "", "", "a", "b\\", "c", "" }, "c:\\a\\b\\c", zero); |
| | 170 | try testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "", "b\\", "", "/c" }, "c:\\a/b\\c", zero); |
| | 171 | try testJoinMaybeZWindows(&[_][]const u8{ "", "" }, "", zero); |
| | 172 | |
| 151 | try testJoinMaybeZPosix(&[_][]const u8{}, "", zero); | 173 | try testJoinMaybeZPosix(&[_][]const u8{}, "", zero); |
| 152 | try testJoinMaybeZPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c", zero); | 174 | try testJoinMaybeZPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c", zero); |
| 153 | try testJoinMaybeZPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c", zero); | 175 | try testJoinMaybeZPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c", zero); |
| ... | @@ -163,6 +185,10 @@ test "join" { | ... | @@ -163,6 +185,10 @@ test "join" { |
| 163 | | 185 | |
| 164 | try testJoinMaybeZPosix(&[_][]const u8{ "a", "/c" }, "a/c", zero); | 186 | try testJoinMaybeZPosix(&[_][]const u8{ "a", "/c" }, "a/c", zero); |
| 165 | try testJoinMaybeZPosix(&[_][]const u8{ "a/", "/c" }, "a/c", zero); | 187 | try testJoinMaybeZPosix(&[_][]const u8{ "a/", "/c" }, "a/c", zero); |
| | 188 | |
| | 189 | try testJoinMaybeZPosix(&[_][]const u8{ "", "/", "a", "", "b/", "c", "" }, "/a/b/c", zero); |
| | 190 | try testJoinMaybeZPosix(&[_][]const u8{ "/a/", "", "", "b/", "c" }, "/a/b/c", zero); |
| | 191 | try testJoinMaybeZPosix(&[_][]const u8{ "", "" }, "", zero); |
| 166 | } | 192 | } |
| 167 | } | 193 | } |
| 168 | | 194 | |