| ... | @@ -39,7 +39,7 @@ pub fn isSep(byte: u8) bool { | ... | @@ -39,7 +39,7 @@ pub fn isSep(byte: u8) bool { |
| 39 | | 39 | |
| 40 | /// This is different from mem.join in that the separator will not be repeated if | 40 | /// This is different from mem.join in that the separator will not be repeated if |
| 41 | /// it is found at the end or beginning of a pair of consecutive paths. | 41 | /// it is found at the end or beginning of a pair of consecutive paths. |
| 42 | fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u8 { | 42 | fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8) ![]u8 { |
| 43 | if (paths.len == 0) return &[0]u8{}; | 43 | if (paths.len == 0) return &[0]u8{}; |
| 44 | | 44 | |
| 45 | const total_len = blk: { | 45 | const total_len = blk: { |
| ... | @@ -48,8 +48,8 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u | ... | @@ -48,8 +48,8 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u |
| 48 | while (i < paths.len) : (i += 1) { | 48 | while (i < paths.len) : (i += 1) { |
| 49 | const prev_path = paths[i - 1]; | 49 | const prev_path = paths[i - 1]; |
| 50 | const this_path = paths[i]; | 50 | const this_path = paths[i]; |
| 51 | const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator); | 51 | const prev_sep = (prev_path.len != 0 and sepPredicate(prev_path[prev_path.len - 1])); |
| 52 | const this_sep = (this_path.len != 0 and this_path[0] == separator); | 52 | const this_sep = (this_path.len != 0 and sepPredicate(this_path[0])); |
| 53 | sum += @boolToInt(!prev_sep and !this_sep); | 53 | sum += @boolToInt(!prev_sep and !this_sep); |
| 54 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; | 54 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; |
| 55 | } | 55 | } |
| ... | @@ -65,8 +65,8 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u | ... | @@ -65,8 +65,8 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u |
| 65 | while (i < paths.len) : (i += 1) { | 65 | while (i < paths.len) : (i += 1) { |
| 66 | const prev_path = paths[i - 1]; | 66 | const prev_path = paths[i - 1]; |
| 67 | const this_path = paths[i]; | 67 | const this_path = paths[i]; |
| 68 | const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator); | 68 | const prev_sep = (prev_path.len != 0 and sepPredicate(prev_path[prev_path.len - 1])); |
| 69 | const this_sep = (this_path.len != 0 and this_path[0] == separator); | 69 | const this_sep = (this_path.len != 0 and sepPredicate(this_path[0])); |
| 70 | if (!prev_sep and !this_sep) { | 70 | if (!prev_sep and !this_sep) { |
| 71 | buf[buf_index] = separator; | 71 | buf[buf_index] = separator; |
| 72 | buf_index += 1; | 72 | buf_index += 1; |
| ... | @@ -80,28 +80,30 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u | ... | @@ -80,28 +80,30 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u |
| 80 | return buf; | 80 | return buf; |
| 81 | } | 81 | } |
| 82 | | 82 | |
| 83 | pub const join = if (builtin.os.tag == .windows) joinWindows else joinPosix; | | |
| 84 | | | |
| 85 | /// Naively combines a series of paths with the native path seperator. | | |
| 86 | /// Allocates memory for the result, which must be freed by the caller. | | |
| 87 | pub fn joinWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | | |
| 88 | return joinSep(allocator, sep_windows, paths); | | |
| 89 | } | | |
| 90 | | | |
| 91 | /// Naively combines a series of paths with the native path seperator. | 83 | /// Naively combines a series of paths with the native path seperator. |
| 92 | /// Allocates memory for the result, which must be freed by the caller. | 84 | /// Allocates memory for the result, which must be freed by the caller. |
| 93 | pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 85 | pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 94 | return joinSep(allocator, sep_posix, paths); | 86 | return joinSep(allocator, sep, isSep, paths); |
| 95 | } | 87 | } |
| 96 | | 88 | |
| 97 | fn testJoinWindows(paths: []const []const u8, expected: []const u8) void { | 89 | fn testJoinWindows(paths: []const []const u8, expected: []const u8) void { |
| 98 | const actual = joinWindows(testing.allocator, paths) catch @panic("fail"); | 90 | const windowsIsSep = struct { |
| | 91 | fn isSep(byte: u8) bool { |
| | 92 | return byte == '/' or byte == '\\'; |
| | 93 | } |
| | 94 | }.isSep; |
| | 95 | const actual = joinSep(testing.allocator, sep_windows, windowsIsSep, paths) catch @panic("fail"); |
| 99 | defer testing.allocator.free(actual); | 96 | defer testing.allocator.free(actual); |
| 100 | testing.expectEqualSlices(u8, expected, actual); | 97 | testing.expectEqualSlices(u8, expected, actual); |
| 101 | } | 98 | } |
| 102 | | 99 | |
| 103 | fn testJoinPosix(paths: []const []const u8, expected: []const u8) void { | 100 | fn testJoinPosix(paths: []const []const u8, expected: []const u8) void { |
| 104 | const actual = joinPosix(testing.allocator, paths) catch @panic("fail"); | 101 | const posixIsSep = struct { |
| | 102 | fn isSep(byte: u8) bool { |
| | 103 | return byte == '/'; |
| | 104 | } |
| | 105 | }.isSep; |
| | 106 | const actual = joinSep(testing.allocator, sep_posix, posixIsSep, paths) catch @panic("fail"); |
| 105 | defer testing.allocator.free(actual); | 107 | defer testing.allocator.free(actual); |
| 106 | testing.expectEqualSlices(u8, expected, actual); | 108 | testing.expectEqualSlices(u8, expected, actual); |
| 107 | } | 109 | } |
| ... | @@ -119,6 +121,9 @@ test "join" { | ... | @@ -119,6 +121,9 @@ test "join" { |
| 119 | "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", | 121 | "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", |
| 120 | ); | 122 | ); |
| 121 | | 123 | |
| | 124 | testJoinWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c"); |
| | 125 | testJoinWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c"); |
| | 126 | |
| 122 | testJoinPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); | 127 | testJoinPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); |
| 123 | testJoinPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c"); | 128 | testJoinPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c"); |
| 124 | | 129 | |