| author | |
| committer | |
| log | 67bd45f0cf1b452cf8de5a016bc6ff2f85393d70 |
| tree | 2c3da09e586d0fd21f81bbe66148db490e23762f |
| parent | f44ce7836a2f1d29e4f4718d45d6dca3c44ed919 |
| signature |
* rename std.mem.split to std.mem.tokenize
* add future deprecation notice to docs
* (unrelated) add note to std.os.path.resolve docs
* std.mem.separate - assert delimiter.len not zero
* fix implementation of std.mem.separate to respect the delimiter
* separate the two iterators to different structs8 files changed, 112 insertions(+), 97 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" }); |
| 190 | 190 | ||
| 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 | } |
| 234 | 234 | ||
| 235 | pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { | 235 | pub 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 | } |
| 243 | 243 | ||
| 244 | pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { | 244 | pub 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); |
| 59 | 59 | ||
| 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 | } |
| 215 | 215 | ||
| 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; |
| 416 | 416 |
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 { |
| 324 | 324 | ||
| 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+71-58| ... | @@ -689,58 +689,57 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { | ... | @@ -689,58 +689,57 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | /// Returns an iterator that iterates over the slices of `buffer` that are not | 691 | /// 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. |
| 695 | /// If `split_bytes` does not exist in buffer, | 695 | /// If `buffer` is empty, the iterator will return null. |
| 696 | /// If `delimiter_bytes` does not exist in buffer, | ||
| 696 | /// the iterator will return `buffer`, null, in that order. | 697 | /// the iterator will return `buffer`, null, in that order. |
| 697 | pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { | 698 | /// See also the related function `separate`. |
| 698 | return SplitIterator{ | 699 | pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator { |
| 700 | return TokenIterator{ | ||
| 699 | .index = 0, | 701 | .index = 0, |
| 700 | .buffer = buffer, | 702 | .buffer = buffer, |
| 701 | .split_bytes = split_bytes, | 703 | .delimiter_bytes = delimiter_bytes, |
| 702 | .glob = true, | ||
| 703 | .spun = false, | ||
| 704 | }; | 704 | }; |
| 705 | } | 705 | } |
| 706 | 706 | ||
| 707 | test "mem.split" { | 707 | test "mem.tokenize" { |
| 708 | var it = split(" abc def ghi ", " "); | 708 | var it = tokenize(" abc def ghi ", " "); |
| 709 | assert(eql(u8, it.next().?, "abc")); | 709 | assert(eql(u8, it.next().?, "abc")); |
| 710 | assert(eql(u8, it.next().?, "def")); | 710 | assert(eql(u8, it.next().?, "def")); |
| 711 | assert(eql(u8, it.next().?, "ghi")); | 711 | assert(eql(u8, it.next().?, "ghi")); |
| 712 | assert(it.next() == null); | 712 | assert(it.next() == null); |
| 713 | 713 | ||
| 714 | it = split("..\\bob", "\\"); | 714 | it = tokenize("..\\bob", "\\"); |
| 715 | assert(eql(u8, it.next().?, "..")); | 715 | assert(eql(u8, it.next().?, "..")); |
| 716 | assert(eql(u8, "..", "..\\bob"[0..it.index])); | 716 | assert(eql(u8, "..", "..\\bob"[0..it.index])); |
| 717 | assert(eql(u8, it.next().?, "bob")); | 717 | assert(eql(u8, it.next().?, "bob")); |
| 718 | assert(it.next() == null); | 718 | assert(it.next() == null); |
| 719 | 719 | ||
| 720 | it = split("//a/b", "/"); | 720 | it = tokenize("//a/b", "/"); |
| 721 | assert(eql(u8, it.next().?, "a")); | 721 | assert(eql(u8, it.next().?, "a")); |
| 722 | assert(eql(u8, it.next().?, "b")); | 722 | assert(eql(u8, it.next().?, "b")); |
| 723 | assert(eql(u8, "//a/b", "//a/b"[0..it.index])); | 723 | assert(eql(u8, "//a/b", "//a/b"[0..it.index])); |
| 724 | assert(it.next() == null); | 724 | assert(it.next() == null); |
| 725 | 725 | ||
| 726 | it = split("|", "|"); | 726 | it = tokenize("|", "|"); |
| 727 | assert(it.next() == null); | 727 | assert(it.next() == null); |
| 728 | 728 | ||
| 729 | it = split("", "|"); | 729 | it = tokenize("", "|"); |
| 730 | assert(eql(u8, it.next().?, "")); | ||
| 731 | assert(it.next() == null); | 730 | assert(it.next() == null); |
| 732 | 731 | ||
| 733 | it = split("hello", ""); | 732 | it = tokenize("hello", ""); |
| 734 | assert(eql(u8, it.next().?, "hello")); | 733 | assert(eql(u8, it.next().?, "hello")); |
| 735 | assert(it.next() == null); | 734 | assert(it.next() == null); |
| 736 | 735 | ||
| 737 | it = split("hello", " "); | 736 | it = tokenize("hello", " "); |
| 738 | assert(eql(u8, it.next().?, "hello")); | 737 | assert(eql(u8, it.next().?, "hello")); |
| 739 | assert(it.next() == null); | 738 | assert(it.next() == null); |
| 740 | } | 739 | } |
| 741 | 740 | ||
| 742 | test "mem.split (multibyte)" { | 741 | test "mem.tokenize (multibyte)" { |
| 743 | var it = split("a|b,c/d e", " /,|"); | 742 | var it = tokenize("a|b,c/d e", " /,|"); |
| 744 | assert(eql(u8, it.next().?, "a")); | 743 | assert(eql(u8, it.next().?, "a")); |
| 745 | assert(eql(u8, it.next().?, "b")); | 744 | assert(eql(u8, it.next().?, "b")); |
| 746 | assert(eql(u8, it.next().?, "c")); | 745 | assert(eql(u8, it.next().?, "c")); |
| ... | @@ -750,18 +749,21 @@ test "mem.split (multibyte)" { | ... | @@ -750,18 +749,21 @@ test "mem.split (multibyte)" { |
| 750 | } | 749 | } |
| 751 | 750 | ||
| 752 | /// Returns an iterator that iterates over the slices of `buffer` that | 751 | /// Returns an iterator that iterates over the slices of `buffer` that |
| 753 | /// seperates by bytes in `delimiter`. | 752 | /// are separated by bytes in `delimiter`. |
| 754 | /// separate("abc|def||ghi", "|") | 753 | /// separate("abc|def||ghi", "|") |
| 755 | /// Will return slices for "abc", "def", "", "ghi", null, in that order. | 754 | /// will return slices for "abc", "def", "", "ghi", null, in that order. |
| 756 | /// If `delimiter` does not exist in buffer, | 755 | /// If `delimiter` does not exist in buffer, |
| 757 | /// the iterator will return `buffer`, null, in that order. | 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 { | ||
| 758 | pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { | 761 | pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { |
| 762 | assert(delimiter.len != 0); | ||
| 759 | return SplitIterator{ | 763 | return SplitIterator{ |
| 760 | .index = 0, | 764 | .index = 0, |
| 761 | .buffer = buffer, | 765 | .buffer = buffer, |
| 762 | .split_bytes = delimiter, | 766 | .delimiter = delimiter, |
| 763 | .glob = false, | ||
| 764 | .spun = false, | ||
| 765 | }; | 767 | }; |
| 766 | } | 768 | } |
| 767 | 769 | ||
| ... | @@ -782,19 +784,15 @@ test "mem.separate" { | ... | @@ -782,19 +784,15 @@ test "mem.separate" { |
| 782 | assert(eql(u8, it.next().?, "")); | 784 | assert(eql(u8, it.next().?, "")); |
| 783 | assert(it.next() == null); | 785 | assert(it.next() == null); |
| 784 | 786 | ||
| 785 | it = separate("hello", ""); | ||
| 786 | assert(eql(u8, it.next().?, "hello")); | ||
| 787 | assert(it.next() == null); | ||
| 788 | |||
| 789 | it = separate("hello", " "); | 787 | it = separate("hello", " "); |
| 790 | assert(eql(u8, it.next().?, "hello")); | 788 | assert(eql(u8, it.next().?, "hello")); |
| 791 | assert(it.next() == null); | 789 | assert(it.next() == null); |
| 792 | } | 790 | } |
| 793 | 791 | ||
| 794 | test "mem.separate (multibyte)" { | 792 | test "mem.separate (multibyte)" { |
| 795 | var it = separate("a|b,c/d e", " /,|"); | 793 | var it = separate("a, b ,, c, d, e", ", "); |
| 796 | assert(eql(u8, it.next().?, "a")); | 794 | assert(eql(u8, it.next().?, "a")); |
| 797 | assert(eql(u8, it.next().?, "b")); | 795 | assert(eql(u8, it.next().?, "b ,")); |
| 798 | assert(eql(u8, it.next().?, "c")); | 796 | assert(eql(u8, it.next().?, "c")); |
| 799 | assert(eql(u8, it.next().?, "d")); | 797 | assert(eql(u8, it.next().?, "d")); |
| 800 | assert(eql(u8, it.next().?, "e")); | 798 | assert(eql(u8, it.next().?, "e")); |
| ... | @@ -819,49 +817,38 @@ test "mem.endsWith" { | ... | @@ -819,49 +817,38 @@ test "mem.endsWith" { |
| 819 | assert(!endsWith(u8, "Bob", "Bo")); | 817 | assert(!endsWith(u8, "Bob", "Bo")); |
| 820 | } | 818 | } |
| 821 | 819 | ||
| 822 | pub const SplitIterator = struct { | 820 | pub const TokenIterator = struct { |
| 823 | buffer: []const u8, | 821 | buffer: []const u8, |
| 824 | split_bytes: []const u8, | 822 | delimiter_bytes: []const u8, |
| 825 | index: usize, | 823 | index: usize, |
| 826 | glob: bool, | ||
| 827 | spun: bool, | ||
| 828 | 824 | ||
| 829 | /// Iterates and returns null or optionally a slice the next split segment | 825 | /// Returns a slice of the next token, or null if tokenization is complete. |
| 830 | pub fn next(self: *SplitIterator) ?[]const u8 { | 826 | pub fn next(self: *TokenIterator) ?[]const u8 { |
| 831 | if (self.spun) { | 827 | // move to beginning of token |
| 832 | if (self.index + 1 > self.buffer.len) return null; | 828 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} |
| 833 | self.index += 1; | 829 | const start = self.index; |
| 834 | } | 830 | if (start == self.buffer.len) { |
| 835 | 831 | return null; | |
| 836 | self.spun = true; | ||
| 837 | |||
| 838 | if (self.glob) { | ||
| 839 | while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} | ||
| 840 | } | 832 | } |
| 841 | 833 | ||
| 842 | var cursor = self.index; | 834 | // move to end of token |
| 843 | while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {} | 835 | while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} |
| 844 | 836 | const end = self.index; | |
| 845 | defer self.index = cursor; | ||
| 846 | 837 | ||
| 847 | if (cursor == self.buffer.len) { | 838 | return self.buffer[start..end]; |
| 848 | return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..]; | ||
| 849 | } | ||
| 850 | |||
| 851 | return self.buffer[self.index..cursor]; | ||
| 852 | } | 839 | } |
| 853 | 840 | ||
| 854 | /// 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. |
| 855 | pub fn rest(self: *const SplitIterator) []const u8 { | 842 | pub fn rest(self: TokenIterator) []const u8 { |
| 856 | // move to beginning of token | 843 | // move to beginning of token |
| 857 | var index: usize = self.index; | 844 | var index: usize = self.index; |
| 858 | 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) {} |
| 859 | return self.buffer[index..]; | 846 | return self.buffer[index..]; |
| 860 | } | 847 | } |
| 861 | 848 | ||
| 862 | fn isSplitByte(self: *const SplitIterator, byte: u8) bool { | 849 | fn isSplitByte(self: TokenIterator, byte: u8) bool { |
| 863 | for (self.split_bytes) |split_byte| { | 850 | for (self.delimiter_bytes) |delimiter_byte| { |
| 864 | if (byte == split_byte) { | 851 | if (byte == delimiter_byte) { |
| 865 | return true; | 852 | return true; |
| 866 | } | 853 | } |
| 867 | } | 854 | } |
| ... | @@ -869,6 +856,32 @@ pub const SplitIterator = struct { | ... | @@ -869,6 +856,32 @@ pub const SplitIterator = struct { |
| 869 | } | 856 | } |
| 870 | }; | 857 | }; |
| 871 | 858 | ||
| 859 | pub 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 | |||
| 872 | /// Naively combines a series of strings with a separator. | 885 | /// Naively combines a series of strings with a separator. |
| 873 | /// 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. |
| 874 | pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { | 887 | pub 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); |
| 597 | 597 | ||
| 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 byte | 608 | // +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+23-21| ... | @@ -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 | } |
| 186 | 186 | ||
| 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 | } |
| 204 | 204 | ||
| 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]; |
| 266 | 266 | ||
| 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}); |
| 269 | 269 | ||
| 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]; |
| 287 | 287 | ||
| 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}); |
| 290 | 290 | ||
| 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. | ||
| 340 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 342 | pub 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 getCwd | 344 | 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().?; |
| 422 | 424 | ||
| ... | @@ -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. | ||
| 519 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 523 | pub 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 getCwd | 525 | 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); |
| 551 | 555 | ||
| 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 | } |
| 939 | 943 | ||
| 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,14 +971,12 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) | ... | @@ -967,14 +971,12 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) |
| 967 | // shave off the trailing slash | 971 | // shave off the trailing slash |
| 968 | result_index -= 1; | 972 | result_index -= 1; |
| 969 | 973 | ||
| 970 | if (to_rest.len > 0) { | 974 | var rest_it = mem.tokenize(to_rest, "/\\"); |
| 971 | var rest_it = mem.split(to_rest, "/\\"); | 975 | while (rest_it.next()) |to_component| { |
| 972 | while (rest_it.next()) |to_component| { | 976 | result[result_index] = '\\'; |
| 973 | result[result_index] = '\\'; | 977 | result_index += 1; |
| 974 | result_index += 1; | 978 | mem.copy(u8, result[result_index..], to_component); |
| 975 | mem.copy(u8, result[result_index..], to_component); | 979 | result_index += to_component.len; |
| 976 | result_index += to_component.len; | ||
| 977 | } | ||
| 978 | } | 980 | } |
| 979 | 981 | ||
| 980 | return result[0..result_index]; | 982 | return result[0..result_index]; |
| ... | @@ -990,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ | ... | @@ -990,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ |
| 990 | const resolved_to = try resolvePosix(allocator, [][]const u8{to}); | 992 | const resolved_to = try resolvePosix(allocator, [][]const u8{to}); |
| 991 | defer allocator.free(resolved_to); | 993 | defer allocator.free(resolved_to); |
| 992 | 994 | ||
| 993 | var from_it = mem.split(resolved_from, "/"); | 995 | var from_it = mem.tokenize(resolved_from, "/"); |
| 994 | var to_it = mem.split(resolved_to, "/"); | 996 | var to_it = mem.tokenize(resolved_to, "/"); |
| 995 | while (true) { | 997 | while (true) { |
| 996 | 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()); |
| 997 | const to_rest = to_it.rest(); | 999 | const to_rest = to_it.rest(); |