authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-04 15:27:44-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-04 15:27:44-05:00
log2828a9695f088f5454f445fdd0544d805a33837b
tree2c3da09e586d0fd21f81bbe66148db490e23762f
parentdfbc063f79dc1358208216b466c1bf8c44baa430
parent67bd45f0cf1b452cf8de5a016bc6ff2f85393d70
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'kristate-zig-backport-std.mem.separate'


8 files changed, 167 insertions(+), 45 deletions(-)

build.zig+8-8
...@@ -189,14 +189,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -189,14 +189,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
189 const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" });189 const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" });
190190
191 var result = LibraryDep{191 var result = LibraryDep{
192 .prefix = mem.split(prefix_output, " \r\n").next().?,192 .prefix = mem.tokenize(prefix_output, " \r\n").next().?,
193 .libs = ArrayList([]const u8).init(b.allocator),193 .libs = ArrayList([]const u8).init(b.allocator),
194 .system_libs = ArrayList([]const u8).init(b.allocator),194 .system_libs = ArrayList([]const u8).init(b.allocator),
195 .includes = ArrayList([]const u8).init(b.allocator),195 .includes = ArrayList([]const u8).init(b.allocator),
196 .libdirs = ArrayList([]const u8).init(b.allocator),196 .libdirs = ArrayList([]const u8).init(b.allocator),
197 };197 };
198 {198 {
199 var it = mem.split(libs_output, " \r\n");199 var it = mem.tokenize(libs_output, " \r\n");
200 while (it.next()) |lib_arg| {200 while (it.next()) |lib_arg| {
201 if (mem.startsWith(u8, lib_arg, "-l")) {201 if (mem.startsWith(u8, lib_arg, "-l")) {
202 try result.system_libs.append(lib_arg[2..]);202 try result.system_libs.append(lib_arg[2..]);
...@@ -210,7 +210,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -210,7 +210,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
210 }210 }
211 }211 }
212 {212 {
213 var it = mem.split(includes_output, " \r\n");213 var it = mem.tokenize(includes_output, " \r\n");
214 while (it.next()) |include_arg| {214 while (it.next()) |include_arg| {
215 if (mem.startsWith(u8, include_arg, "-I")) {215 if (mem.startsWith(u8, include_arg, "-I")) {
216 try result.includes.append(include_arg[2..]);216 try result.includes.append(include_arg[2..]);
...@@ -220,7 +220,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -220,7 +220,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
220 }220 }
221 }221 }
222 {222 {
223 var it = mem.split(libdir_output, " \r\n");223 var it = mem.tokenize(libdir_output, " \r\n");
224 while (it.next()) |libdir| {224 while (it.next()) |libdir| {
225 if (mem.startsWith(u8, libdir, "-L")) {225 if (mem.startsWith(u8, libdir, "-L")) {
226 try result.libdirs.append(libdir[2..]);226 try result.libdirs.append(libdir[2..]);
...@@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
233}233}
234234
235pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {235pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
236 var it = mem.split(stdlib_files, ";");236 var it = mem.tokenize(stdlib_files, ";");
237 while (it.next()) |stdlib_file| {237 while (it.next()) |stdlib_file| {
238 const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;238 const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable;
239 const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable;239 const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable;
...@@ -242,7 +242,7 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {...@@ -242,7 +242,7 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
242}242}
243243
244pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {244pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
245 var it = mem.split(c_header_files, ";");245 var it = mem.tokenize(c_header_files, ";");
246 while (it.next()) |c_header_file| {246 while (it.next()) |c_header_file| {
247 const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;247 const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable;
248 const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable;248 const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable;
...@@ -277,7 +277,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {...@@ -277,7 +277,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
277 addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");277 addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
278 if (ctx.lld_include_dir.len != 0) {278 if (ctx.lld_include_dir.len != 0) {
279 exe.addIncludeDir(ctx.lld_include_dir);279 exe.addIncludeDir(ctx.lld_include_dir);
280 var it = mem.split(ctx.lld_libraries, ";");280 var it = mem.tokenize(ctx.lld_libraries, ";");
281 while (it.next()) |lib| {281 while (it.next()) |lib| {
282 exe.addObjectFile(lib);282 exe.addObjectFile(lib);
283 }283 }
...@@ -334,7 +334,7 @@ fn addCxxKnownPath(...@@ -334,7 +334,7 @@ fn addCxxKnownPath(
334 ctx.cxx_compiler,334 ctx.cxx_compiler,
335 b.fmt("-print-file-name={}", objname),335 b.fmt("-print-file-name={}", objname),
336 });336 });
337 const path_unpadded = mem.split(path_padded, "\r\n").next().?;337 const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?;
338 if (mem.eql(u8, path_unpadded, objname)) {338 if (mem.eql(u8, path_unpadded, objname)) {
339 if (errtxt) |msg| {339 if (errtxt) |msg| {
340 warn("{}", msg);340 warn("{}", msg);
src-self-hosted/libc_installation.zig+4-4
...@@ -57,10 +57,10 @@ pub const LibCInstallation = struct {...@@ -57,10 +57,10 @@ pub const LibCInstallation = struct {
57 const contents = try std.io.readFileAlloc(allocator, libc_file);57 const contents = try std.io.readFileAlloc(allocator, libc_file);
58 defer allocator.free(contents);58 defer allocator.free(contents);
5959
60 var it = std.mem.split(contents, "\n");60 var it = std.mem.tokenize(contents, "\n");
61 while (it.next()) |line| {61 while (it.next()) |line| {
62 if (line.len == 0 or line[0] == '#') continue;62 if (line.len == 0 or line[0] == '#') continue;
63 var line_it = std.mem.split(line, "=");63 var line_it = std.mem.separate(line, "=");
64 const name = line_it.next() orelse {64 const name = line_it.next() orelse {
65 try stderr.print("missing equal sign after field name\n");65 try stderr.print("missing equal sign after field name\n");
66 return error.ParseError;66 return error.ParseError;
...@@ -213,7 +213,7 @@ pub const LibCInstallation = struct {...@@ -213,7 +213,7 @@ pub const LibCInstallation = struct {
213 },213 },
214 }214 }
215215
216 var it = std.mem.split(exec_result.stderr, "\n\r");216 var it = std.mem.tokenize(exec_result.stderr, "\n\r");
217 var search_paths = std.ArrayList([]const u8).init(loop.allocator);217 var search_paths = std.ArrayList([]const u8).init(loop.allocator);
218 defer search_paths.deinit();218 defer search_paths.deinit();
219 while (it.next()) |line| {219 while (it.next()) |line| {
...@@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo...@@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo
410 return error.CCompilerCrashed;410 return error.CCompilerCrashed;
411 },411 },
412 }412 }
413 var it = std.mem.split(exec_result.stdout, "\n\r");413 var it = std.mem.tokenize(exec_result.stdout, "\n\r");
414 const line = it.next() orelse return error.LibCRuntimeNotFound;414 const line = it.next() orelse return error.LibCRuntimeNotFound;
415 const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;415 const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;
416416
src-self-hosted/main.zig+1-1
...@@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
351 const root_name = if (provided_name) |n| n else blk: {351 const root_name = if (provided_name) |n| n else blk: {
352 if (root_source_file) |file| {352 if (root_source_file) |file| {
353 const basename = os.path.basename(file);353 const basename = os.path.basename(file);
354 var it = mem.split(basename, ".");354 var it = mem.separate(basename, ".");
355 break :blk it.next() orelse basename;355 break :blk it.next() orelse basename;
356 } else {356 } else {
357 try stderr.write("--name [name] not provided and unable to infer\n");357 try stderr.write("--name [name] not provided and unable to infer\n");
std/build.zig+3-3
...@@ -324,7 +324,7 @@ pub const Builder = struct {...@@ -324,7 +324,7 @@ pub const Builder = struct {
324324
325 fn processNixOSEnvVars(self: *Builder) void {325 fn processNixOSEnvVars(self: *Builder) void {
326 if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {326 if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
327 var it = mem.split(nix_cflags_compile, " ");327 var it = mem.tokenize(nix_cflags_compile, " ");
328 while (true) {328 while (true) {
329 const word = it.next() orelse break;329 const word = it.next() orelse break;
330 if (mem.eql(u8, word, "-isystem")) {330 if (mem.eql(u8, word, "-isystem")) {
...@@ -342,7 +342,7 @@ pub const Builder = struct {...@@ -342,7 +342,7 @@ pub const Builder = struct {
342 assert(err == error.EnvironmentVariableNotFound);342 assert(err == error.EnvironmentVariableNotFound);
343 }343 }
344 if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {344 if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
345 var it = mem.split(nix_ldflags, " ");345 var it = mem.tokenize(nix_ldflags, " ");
346 while (true) {346 while (true) {
347 const word = it.next() orelse break;347 const word = it.next() orelse break;
348 if (mem.eql(u8, word, "-rpath")) {348 if (mem.eql(u8, word, "-rpath")) {
...@@ -689,7 +689,7 @@ pub const Builder = struct {...@@ -689,7 +689,7 @@ pub const Builder = struct {
689 if (os.path.isAbsolute(name)) {689 if (os.path.isAbsolute(name)) {
690 return name;690 return name;
691 }691 }
692 var it = mem.split(PATH, []u8{os.path.delimiter});692 var it = mem.tokenize(PATH, []u8{os.path.delimiter});
693 while (it.next()) |path| {693 while (it.next()) |path| {
694 const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));694 const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension));
695 if (os.path.real(self.allocator, full_path)) |real_path| {695 if (os.path.real(self.allocator, full_path)) |real_path| {
std/mem.zig+131-13
...@@ -689,23 +689,114 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {...@@ -689,23 +689,114 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
689}689}
690690
691/// Returns an iterator that iterates over the slices of `buffer` that are not691/// Returns an iterator that iterates over the slices of `buffer` that are not
692/// any of the bytes in `split_bytes`.692/// any of the bytes in `delimiter_bytes`.
693/// split(" abc def ghi ", " ")693/// tokenize(" abc def ghi ", " ")
694/// Will return slices for "abc", "def", "ghi", null, in that order.694/// Will return slices for "abc", "def", "ghi", null, in that order.
695pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator {695/// If `buffer` is empty, the iterator will return null.
696/// If `delimiter_bytes` does not exist in buffer,
697/// the iterator will return `buffer`, null, in that order.
698/// See also the related function `separate`.
699pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator {
700 return TokenIterator{
701 .index = 0,
702 .buffer = buffer,
703 .delimiter_bytes = delimiter_bytes,
704 };
705}
706
707test "mem.tokenize" {
708 var it = tokenize(" abc def ghi ", " ");
709 assert(eql(u8, it.next().?, "abc"));
710 assert(eql(u8, it.next().?, "def"));
711 assert(eql(u8, it.next().?, "ghi"));
712 assert(it.next() == null);
713
714 it = tokenize("..\\bob", "\\");
715 assert(eql(u8, it.next().?, ".."));
716 assert(eql(u8, "..", "..\\bob"[0..it.index]));
717 assert(eql(u8, it.next().?, "bob"));
718 assert(it.next() == null);
719
720 it = tokenize("//a/b", "/");
721 assert(eql(u8, it.next().?, "a"));
722 assert(eql(u8, it.next().?, "b"));
723 assert(eql(u8, "//a/b", "//a/b"[0..it.index]));
724 assert(it.next() == null);
725
726 it = tokenize("|", "|");
727 assert(it.next() == null);
728
729 it = tokenize("", "|");
730 assert(it.next() == null);
731
732 it = tokenize("hello", "");
733 assert(eql(u8, it.next().?, "hello"));
734 assert(it.next() == null);
735
736 it = tokenize("hello", " ");
737 assert(eql(u8, it.next().?, "hello"));
738 assert(it.next() == null);
739}
740
741test "mem.tokenize (multibyte)" {
742 var it = tokenize("a|b,c/d e", " /,|");
743 assert(eql(u8, it.next().?, "a"));
744 assert(eql(u8, it.next().?, "b"));
745 assert(eql(u8, it.next().?, "c"));
746 assert(eql(u8, it.next().?, "d"));
747 assert(eql(u8, it.next().?, "e"));
748 assert(it.next() == null);
749}
750
751/// Returns an iterator that iterates over the slices of `buffer` that
752/// are separated by bytes in `delimiter`.
753/// separate("abc|def||ghi", "|")
754/// will return slices for "abc", "def", "", "ghi", null, in that order.
755/// If `delimiter` does not exist in buffer,
756/// the iterator will return `buffer`, null, in that order.
757/// The delimiter length must not be zero.
758/// See also the related function `tokenize`.
759/// It is planned to rename this function to `split` before 1.0.0, like this:
760/// pub fn split(buffer: []const u8, delimiter: []const u8) SplitIterator {
761pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator {
762 assert(delimiter.len != 0);
696 return SplitIterator{763 return SplitIterator{
697 .index = 0,764 .index = 0,
698 .buffer = buffer,765 .buffer = buffer,
699 .split_bytes = split_bytes,766 .delimiter = delimiter,
700 };767 };
701}768}
702769
703test "mem.split" {770test "mem.separate" {
704 var it = split(" abc def ghi ", " ");771 var it = separate("abc|def||ghi", "|");
705 assert(eql(u8, it.next().?, "abc"));772 assert(eql(u8, it.next().?, "abc"));
706 assert(eql(u8, it.next().?, "def"));773 assert(eql(u8, it.next().?, "def"));
774 assert(eql(u8, it.next().?, ""));
707 assert(eql(u8, it.next().?, "ghi"));775 assert(eql(u8, it.next().?, "ghi"));
708 assert(it.next() == null);776 assert(it.next() == null);
777
778 it = separate("", "|");
779 assert(eql(u8, it.next().?, ""));
780 assert(it.next() == null);
781
782 it = separate("|", "|");
783 assert(eql(u8, it.next().?, ""));
784 assert(eql(u8, it.next().?, ""));
785 assert(it.next() == null);
786
787 it = separate("hello", " ");
788 assert(eql(u8, it.next().?, "hello"));
789 assert(it.next() == null);
790}
791
792test "mem.separate (multibyte)" {
793 var it = separate("a, b ,, c, d, e", ", ");
794 assert(eql(u8, it.next().?, "a"));
795 assert(eql(u8, it.next().?, "b ,"));
796 assert(eql(u8, it.next().?, "c"));
797 assert(eql(u8, it.next().?, "d"));
798 assert(eql(u8, it.next().?, "e"));
799 assert(it.next() == null);
709}800}
710801
711pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {802pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
...@@ -726,12 +817,13 @@ test "mem.endsWith" {...@@ -726,12 +817,13 @@ test "mem.endsWith" {
726 assert(!endsWith(u8, "Bob", "Bo"));817 assert(!endsWith(u8, "Bob", "Bo"));
727}818}
728819
729pub const SplitIterator = struct {820pub const TokenIterator = struct {
730 buffer: []const u8,821 buffer: []const u8,
731 split_bytes: []const u8,822 delimiter_bytes: []const u8,
732 index: usize,823 index: usize,
733824
734 pub fn next(self: *SplitIterator) ?[]const u8 {825 /// Returns a slice of the next token, or null if tokenization is complete.
826 pub fn next(self: *TokenIterator) ?[]const u8 {
735 // move to beginning of token827 // move to beginning of token
736 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}828 while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {}
737 const start = self.index;829 const start = self.index;
...@@ -747,16 +839,16 @@ pub const SplitIterator = struct {...@@ -747,16 +839,16 @@ pub const SplitIterator = struct {
747 }839 }
748840
749 /// Returns a slice of the remaining bytes. Does not affect iterator state.841 /// Returns a slice of the remaining bytes. Does not affect iterator state.
750 pub fn rest(self: *const SplitIterator) []const u8 {842 pub fn rest(self: TokenIterator) []const u8 {
751 // move to beginning of token843 // move to beginning of token
752 var index: usize = self.index;844 var index: usize = self.index;
753 while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {}845 while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {}
754 return self.buffer[index..];846 return self.buffer[index..];
755 }847 }
756848
757 fn isSplitByte(self: *const SplitIterator, byte: u8) bool {849 fn isSplitByte(self: TokenIterator, byte: u8) bool {
758 for (self.split_bytes) |split_byte| {850 for (self.delimiter_bytes) |delimiter_byte| {
759 if (byte == split_byte) {851 if (byte == delimiter_byte) {
760 return true;852 return true;
761 }853 }
762 }854 }
...@@ -764,6 +856,32 @@ pub const SplitIterator = struct {...@@ -764,6 +856,32 @@ pub const SplitIterator = struct {
764 }856 }
765};857};
766858
859pub const SplitIterator = struct {
860 buffer: []const u8,
861 index: ?usize,
862 delimiter: []const u8,
863
864 /// Returns a slice of the next field, or null if splitting is complete.
865 pub fn next(self: *SplitIterator) ?[]const u8 {
866 const start = self.index orelse return null;
867 const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: {
868 self.index = delim_start + self.delimiter.len;
869 break :blk delim_start;
870 } else blk: {
871 self.index = null;
872 break :blk self.buffer.len;
873 };
874 return self.buffer[start..end];
875 }
876
877 /// Returns a slice of the remaining bytes. Does not affect iterator state.
878 pub fn rest(self: SplitIterator) []const u8 {
879 const end = self.buffer.len;
880 const start = self.index orelse end;
881 return self.buffer[start..end];
882 }
883};
884
767/// Naively combines a series of strings with a separator.885/// Naively combines a series of strings with a separator.
768/// Allocates memory for the result, which must be freed by the caller.886/// Allocates memory for the result, which must be freed by the caller.
769pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {887pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 {
std/os/child_process.zig+1-1
...@@ -595,7 +595,7 @@ pub const ChildProcess = struct {...@@ -595,7 +595,7 @@ pub const ChildProcess = struct {
595 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");595 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
596 defer self.allocator.free(PATH);596 defer self.allocator.free(PATH);
597597
598 var it = mem.split(PATH, ";");598 var it = mem.tokenize(PATH, ";");
599 while (it.next()) |search_path| {599 while (it.next()) |search_path| {
600 const joined_path = try os.path.join(self.allocator, search_path, app_name);600 const joined_path = try os.path.join(self.allocator, search_path, app_name);
601 defer self.allocator.free(joined_path);601 defer self.allocator.free(joined_path);
std/os/index.zig+1-1
...@@ -608,7 +608,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:...@@ -608,7 +608,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:
608 // +1 for the null terminating byte608 // +1 for the null terminating byte
609 const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);609 const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
610 defer allocator.free(path_buf);610 defer allocator.free(path_buf);
611 var it = mem.split(PATH, ":");611 var it = mem.tokenize(PATH, ":");
612 var seen_eacces = false;612 var seen_eacces = false;
613 var err: usize = undefined;613 var err: usize = undefined;
614 while (it.next()) |search_path| {614 while (it.next()) |search_path| {
std/os/path.zig+18-14
...@@ -184,7 +184,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {...@@ -184,7 +184,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
184 return relative_path;184 return relative_path;
185 }185 }
186186
187 var it = mem.split(path, []u8{this_sep});187 var it = mem.tokenize(path, []u8{this_sep});
188 _ = (it.next() orelse return relative_path);188 _ = (it.next() orelse return relative_path);
189 _ = (it.next() orelse return relative_path);189 _ = (it.next() orelse return relative_path);
190 return WindowsPath{190 return WindowsPath{
...@@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {...@@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
202 return relative_path;202 return relative_path;
203 }203 }
204204
205 var it = mem.split(path, []u8{this_sep});205 var it = mem.tokenize(path, []u8{this_sep});
206 _ = (it.next() orelse return relative_path);206 _ = (it.next() orelse return relative_path);
207 _ = (it.next() orelse return relative_path);207 _ = (it.next() orelse return relative_path);
208 return WindowsPath{208 return WindowsPath{
...@@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {...@@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
264 const sep1 = ns1[0];264 const sep1 = ns1[0];
265 const sep2 = ns2[0];265 const sep2 = ns2[0];
266266
267 var it1 = mem.split(ns1, []u8{sep1});267 var it1 = mem.tokenize(ns1, []u8{sep1});
268 var it2 = mem.split(ns2, []u8{sep2});268 var it2 = mem.tokenize(ns2, []u8{sep2});
269269
270 // TODO ASCII is wrong, we actually need full unicode support to compare paths.270 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
271 return asciiEqlIgnoreCase(it1.next().?, it2.next().?);271 return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
...@@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8...@@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8
285 const sep1 = p1[0];285 const sep1 = p1[0];
286 const sep2 = p2[0];286 const sep2 = p2[0];
287287
288 var it1 = mem.split(p1, []u8{sep1});288 var it1 = mem.tokenize(p1, []u8{sep1});
289 var it2 = mem.split(p2, []u8{sep2});289 var it2 = mem.tokenize(p2, []u8{sep2});
290290
291 // TODO ASCII is wrong, we actually need full unicode support to compare paths.291 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
292 return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);292 return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);
...@@ -337,6 +337,8 @@ pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -337,6 +337,8 @@ pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 {
337/// If all paths are relative it uses the current working directory as a starting point.337/// If all paths are relative it uses the current working directory as a starting point.
338/// Each drive has its own current working directory.338/// Each drive has its own current working directory.
339/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.339/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
340/// Note: all usage of this function should be audited due to the existence of symlinks.
341/// Without performing actual syscalls, resolving `..` could be incorrect.
340pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {342pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
341 if (paths.len == 0) {343 if (paths.len == 0) {
342 assert(is_windows); // resolveWindows called on non windows can't use getCwd344 assert(is_windows); // resolveWindows called on non windows can't use getCwd
...@@ -416,7 +418,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -416,7 +418,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
416 },418 },
417 WindowsPath.Kind.NetworkShare => {419 WindowsPath.Kind.NetworkShare => {
418 result = try allocator.alloc(u8, max_size);420 result = try allocator.alloc(u8, max_size);
419 var it = mem.split(paths[first_index], "/\\");421 var it = mem.tokenize(paths[first_index], "/\\");
420 const server_name = it.next().?;422 const server_name = it.next().?;
421 const other_name = it.next().?;423 const other_name = it.next().?;
422424
...@@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
483 if (!correct_disk_designator) {485 if (!correct_disk_designator) {
484 continue;486 continue;
485 }487 }
486 var it = mem.split(p[parsed.disk_designator.len..], "/\\");488 var it = mem.tokenize(p[parsed.disk_designator.len..], "/\\");
487 while (it.next()) |component| {489 while (it.next()) |component| {
488 if (mem.eql(u8, component, ".")) {490 if (mem.eql(u8, component, ".")) {
489 continue;491 continue;
...@@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
516/// It resolves "." and "..".518/// It resolves "." and "..".
517/// The result does not have a trailing path separator.519/// The result does not have a trailing path separator.
518/// If all paths are relative it uses the current working directory as a starting point.520/// If all paths are relative it uses the current working directory as a starting point.
521/// Note: all usage of this function should be audited due to the existence of symlinks.
522/// Without performing actual syscalls, resolving `..` could be incorrect.
519pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {523pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
520 if (paths.len == 0) {524 if (paths.len == 0) {
521 assert(!is_windows); // resolvePosix called on windows can't use getCwd525 assert(!is_windows); // resolvePosix called on windows can't use getCwd
...@@ -550,7 +554,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -550,7 +554,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
550 errdefer allocator.free(result);554 errdefer allocator.free(result);
551555
552 for (paths[first_index..]) |p, i| {556 for (paths[first_index..]) |p, i| {
553 var it = mem.split(p, "/");557 var it = mem.tokenize(p, "/");
554 while (it.next()) |component| {558 while (it.next()) |component| {
555 if (mem.eql(u8, component, ".")) {559 if (mem.eql(u8, component, ".")) {
556 continue;560 continue;
...@@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)...@@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
937 return resolved_to;941 return resolved_to;
938 }942 }
939943
940 var from_it = mem.split(resolved_from, "/\\");944 var from_it = mem.tokenize(resolved_from, "/\\");
941 var to_it = mem.split(resolved_to, "/\\");945 var to_it = mem.tokenize(resolved_to, "/\\");
942 while (true) {946 while (true) {
943 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());947 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
944 const to_rest = to_it.rest();948 const to_rest = to_it.rest();
...@@ -967,7 +971,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)...@@ -967,7 +971,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8)
967 // shave off the trailing slash971 // shave off the trailing slash
968 result_index -= 1;972 result_index -= 1;
969973
970 var rest_it = mem.split(to_rest, "/\\");974 var rest_it = mem.tokenize(to_rest, "/\\");
971 while (rest_it.next()) |to_component| {975 while (rest_it.next()) |to_component| {
972 result[result_index] = '\\';976 result[result_index] = '\\';
973 result_index += 1;977 result_index += 1;
...@@ -988,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![...@@ -988,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![
988 const resolved_to = try resolvePosix(allocator, [][]const u8{to});992 const resolved_to = try resolvePosix(allocator, [][]const u8{to});
989 defer allocator.free(resolved_to);993 defer allocator.free(resolved_to);
990994
991 var from_it = mem.split(resolved_from, "/");995 var from_it = mem.tokenize(resolved_from, "/");
992 var to_it = mem.split(resolved_to, "/");996 var to_it = mem.tokenize(resolved_to, "/");
993 while (true) {997 while (true) {
994 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());998 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
995 const to_rest = to_it.rest();999 const to_rest = to_it.rest();