authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-14 16:15:32-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-14 16:15:32-04:00
log6943cefebf94631ff02d6e28436c07f4030924c6
tree0f74832cd4549b4852299639cb2fb90fdb66a4cc
parent2219cc061229bdc69314616869ad731b592d9e96

std.os.path.dirname: return null instead of empty slice

for when there is no directory component. Makes it harder to write bugs. closes #1017

5 files changed, 51 insertions(+), 35 deletions(-)

src-self-hosted/introspect.zig+1-1
...@@ -27,7 +27,7 @@ pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {...@@ -27,7 +27,7 @@ pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
2727
28 var cur_path: []const u8 = self_exe_path;28 var cur_path: []const u8 = self_exe_path;
29 while (true) {29 while (true) {
30 const test_dir = os.path.dirname(cur_path);30 const test_dir = os.path.dirname(cur_path) orelse ".";
3131
32 if (mem.eql(u8, test_dir, cur_path)) {32 if (mem.eql(u8, test_dir, cur_path)) {
33 break;33 break;
src-self-hosted/main.zig+1-1
...@@ -249,7 +249,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {...@@ -249,7 +249,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
249 defer build_args.deinit();249 defer build_args.deinit();
250250
251 const build_file_basename = os.path.basename(build_file_abs);251 const build_file_basename = os.path.basename(build_file_abs);
252 const build_file_dirname = os.path.dirname(build_file_abs);252 const build_file_dirname = os.path.dirname(build_file_abs) orelse ".";
253253
254 var full_cache_dir: []u8 = undefined;254 var full_cache_dir: []u8 = undefined;
255 if (flags.single("cache-dir")) |cache_dir| {255 if (flags.single("cache-dir")) |cache_dir| {
std/build.zig+9-7
...@@ -617,7 +617,7 @@ pub const Builder = struct {...@@ -617,7 +617,7 @@ pub const Builder = struct {
617 warn("cp {} {}\n", source_path, dest_path);617 warn("cp {} {}\n", source_path, dest_path);
618 }618 }
619619
620 const dirname = os.path.dirname(dest_path);620 const dirname = os.path.dirname(dest_path) orelse ".";
621 const abs_source_path = self.pathFromRoot(source_path);621 const abs_source_path = self.pathFromRoot(source_path);
622 os.makePath(self.allocator, dirname) catch |err| {622 os.makePath(self.allocator, dirname) catch |err| {
623 warn("Unable to create path {}: {}\n", dirname, @errorName(err));623 warn("Unable to create path {}: {}\n", dirname, @errorName(err));
...@@ -1395,8 +1395,9 @@ pub const LibExeObjStep = struct {...@@ -1395,8 +1395,9 @@ pub const LibExeObjStep = struct {
1395 cc_args.append(abs_source_file) catch unreachable;1395 cc_args.append(abs_source_file) catch unreachable;
13961396
1397 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;1397 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
1398 const cache_o_dir = os.path.dirname(cache_o_src);1398 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1399 try builder.makePath(cache_o_dir);1399 try builder.makePath(cache_o_dir);
1400 }
1400 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());1401 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
1401 cc_args.append("-o") catch unreachable;1402 cc_args.append("-o") catch unreachable;
1402 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;1403 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
...@@ -1509,8 +1510,9 @@ pub const LibExeObjStep = struct {...@@ -1509,8 +1510,9 @@ pub const LibExeObjStep = struct {
1509 cc_args.append(abs_source_file) catch unreachable;1510 cc_args.append(abs_source_file) catch unreachable;
15101511
1511 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;1512 const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable;
1512 const cache_o_dir = os.path.dirname(cache_o_src);1513 if (os.path.dirname(cache_o_src)) |cache_o_dir| {
1513 try builder.makePath(cache_o_dir);1514 try builder.makePath(cache_o_dir);
1515 }
1514 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());1516 const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
1515 cc_args.append("-o") catch unreachable;1517 cc_args.append("-o") catch unreachable;
1516 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;1518 cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
...@@ -1855,7 +1857,7 @@ pub const WriteFileStep = struct {...@@ -1855,7 +1857,7 @@ pub const WriteFileStep = struct {
1855 fn make(step: *Step) !void {1857 fn make(step: *Step) !void {
1856 const self = @fieldParentPtr(WriteFileStep, "step", step);1858 const self = @fieldParentPtr(WriteFileStep, "step", step);
1857 const full_path = self.builder.pathFromRoot(self.file_path);1859 const full_path = self.builder.pathFromRoot(self.file_path);
1858 const full_path_dir = os.path.dirname(full_path);1860 const full_path_dir = os.path.dirname(full_path) orelse ".";
1859 os.makePath(self.builder.allocator, full_path_dir) catch |err| {1861 os.makePath(self.builder.allocator, full_path_dir) catch |err| {
1860 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));1862 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
1861 return err;1863 return err;
...@@ -1945,7 +1947,7 @@ pub const Step = struct {...@@ -1945,7 +1947,7 @@ pub const Step = struct {
1945};1947};
19461948
1947fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {1949fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1948 const out_dir = os.path.dirname(output_path);1950 const out_dir = os.path.dirname(output_path) orelse ".";
1949 const out_basename = os.path.basename(output_path);1951 const out_basename = os.path.basename(output_path);
1950 // sym link for libfoo.so.1 to libfoo.so.1.2.31952 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1951 const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;1953 const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable;
std/os/index.zig+6-6
...@@ -714,7 +714,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:...@@ -714,7 +714,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
714 else => return err, // TODO zig should know this set does not include PathAlreadyExists714 else => return err, // TODO zig should know this set does not include PathAlreadyExists
715 }715 }
716716
717 const dirname = os.path.dirname(new_path);717 const dirname = os.path.dirname(new_path) orelse ".";
718718
719 var rand_buf: [12]u8 = undefined;719 var rand_buf: [12]u8 = undefined;
720 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));720 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
...@@ -860,14 +860,14 @@ pub const AtomicFile = struct {...@@ -860,14 +860,14 @@ pub const AtomicFile = struct {
860860
861 var rand_buf: [12]u8 = undefined;861 var rand_buf: [12]u8 = undefined;
862862
863 const dirname_component_len = if (dirname.len == 0) 0 else dirname.len + 1;863 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
864 const tmp_path = try allocator.alloc(u8, dirname_component_len +864 const tmp_path = try allocator.alloc(u8, dirname_component_len +
865 base64.Base64Encoder.calcSize(rand_buf.len));865 base64.Base64Encoder.calcSize(rand_buf.len));
866 errdefer allocator.free(tmp_path);866 errdefer allocator.free(tmp_path);
867867
868 if (dirname.len != 0) {868 if (dirname) |dir| {
869 mem.copy(u8, tmp_path[0..], dirname);869 mem.copy(u8, tmp_path[0..], dir);
870 tmp_path[dirname.len] = os.path.sep;870 tmp_path[dir.len] = os.path.sep;
871 }871 }
872872
873 while (true) {873 while (true) {
...@@ -1965,7 +1965,7 @@ pub fn selfExeDirPath(allocator: *mem.Allocator) ![]u8 {...@@ -1965,7 +1965,7 @@ pub fn selfExeDirPath(allocator: *mem.Allocator) ![]u8 {
1965 // the executable was in when it was run.1965 // the executable was in when it was run.
1966 const full_exe_path = try readLink(allocator, "/proc/self/exe");1966 const full_exe_path = try readLink(allocator, "/proc/self/exe");
1967 errdefer allocator.free(full_exe_path);1967 errdefer allocator.free(full_exe_path);
1968 const dir = path.dirname(full_exe_path);1968 const dir = path.dirname(full_exe_path) orelse ".";
1969 return allocator.shrink(u8, full_exe_path, dir.len);1969 return allocator.shrink(u8, full_exe_path, dir.len);
1970 },1970 },
1971 Os.windows, Os.macosx, Os.ios => {1971 Os.windows, Os.macosx, Os.ios => {
std/os/path.zig+34-20
...@@ -648,8 +648,8 @@ fn testResolvePosix(paths: []const []const u8) []u8 {...@@ -648,8 +648,8 @@ fn testResolvePosix(paths: []const []const u8) []u8 {
648}648}
649649
650/// If the path is a file in the current directory (no directory component)650/// If the path is a file in the current directory (no directory component)
651/// then the returned slice has .len = 0.651/// then returns null
652pub fn dirname(path: []const u8) []const u8 {652pub fn dirname(path: []const u8) ?[]const u8 {
653 if (is_windows) {653 if (is_windows) {
654 return dirnameWindows(path);654 return dirnameWindows(path);
655 } else {655 } else {
...@@ -657,9 +657,9 @@ pub fn dirname(path: []const u8) []const u8 {...@@ -657,9 +657,9 @@ pub fn dirname(path: []const u8) []const u8 {
657 }657 }
658}658}
659659
660pub fn dirnameWindows(path: []const u8) []const u8 {660pub fn dirnameWindows(path: []const u8) ?[]const u8 {
661 if (path.len == 0)661 if (path.len == 0)
662 return path[0..0];662 return null;
663663
664 const root_slice = diskDesignatorWindows(path);664 const root_slice = diskDesignatorWindows(path);
665 if (path.len == root_slice.len)665 if (path.len == root_slice.len)
...@@ -671,13 +671,13 @@ pub fn dirnameWindows(path: []const u8) []const u8 {...@@ -671,13 +671,13 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
671671
672 while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {672 while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
673 if (end_index == 0)673 if (end_index == 0)
674 return path[0..0];674 return null;
675 end_index -= 1;675 end_index -= 1;
676 }676 }
677677
678 while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {678 while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
679 if (end_index == 0)679 if (end_index == 0)
680 return path[0..0];680 return null;
681 end_index -= 1;681 end_index -= 1;
682 }682 }
683683
...@@ -685,12 +685,15 @@ pub fn dirnameWindows(path: []const u8) []const u8 {...@@ -685,12 +685,15 @@ pub fn dirnameWindows(path: []const u8) []const u8 {
685 end_index += 1;685 end_index += 1;
686 }686 }
687687
688 if (end_index == 0)
689 return null;
690
688 return path[0..end_index];691 return path[0..end_index];
689}692}
690693
691pub fn dirnamePosix(path: []const u8) []const u8 {694pub fn dirnamePosix(path: []const u8) ?[]const u8 {
692 if (path.len == 0)695 if (path.len == 0)
693 return path[0..0];696 return null;
694697
695 var end_index: usize = path.len - 1;698 var end_index: usize = path.len - 1;
696 while (path[end_index] == '/') {699 while (path[end_index] == '/') {
...@@ -701,13 +704,16 @@ pub fn dirnamePosix(path: []const u8) []const u8 {...@@ -701,13 +704,16 @@ pub fn dirnamePosix(path: []const u8) []const u8 {
701704
702 while (path[end_index] != '/') {705 while (path[end_index] != '/') {
703 if (end_index == 0)706 if (end_index == 0)
704 return path[0..0];707 return null;
705 end_index -= 1;708 end_index -= 1;
706 }709 }
707710
708 if (end_index == 0 and path[end_index] == '/')711 if (end_index == 0 and path[end_index] == '/')
709 return path[0..1];712 return path[0..1];
710713
714 if (end_index == 0)
715 return null;
716
711 return path[0..end_index];717 return path[0..end_index];
712}718}
713719
...@@ -717,10 +723,10 @@ test "os.path.dirnamePosix" {...@@ -717,10 +723,10 @@ test "os.path.dirnamePosix" {
717 testDirnamePosix("/a", "/");723 testDirnamePosix("/a", "/");
718 testDirnamePosix("/", "/");724 testDirnamePosix("/", "/");
719 testDirnamePosix("////", "/");725 testDirnamePosix("////", "/");
720 testDirnamePosix("", "");726 testDirnamePosix("", null);
721 testDirnamePosix("a", "");727 testDirnamePosix("a", null);
722 testDirnamePosix("a/", "");728 testDirnamePosix("a/", null);
723 testDirnamePosix("a//", "");729 testDirnamePosix("a//", null);
724}730}
725731
726test "os.path.dirnameWindows" {732test "os.path.dirnameWindows" {
...@@ -742,7 +748,7 @@ test "os.path.dirnameWindows" {...@@ -742,7 +748,7 @@ test "os.path.dirnameWindows" {
742 testDirnameWindows("c:foo\\bar", "c:foo");748 testDirnameWindows("c:foo\\bar", "c:foo");
743 testDirnameWindows("c:foo\\bar\\", "c:foo");749 testDirnameWindows("c:foo\\bar\\", "c:foo");
744 testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");750 testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
745 testDirnameWindows("file:stream", "");751 testDirnameWindows("file:stream", null);
746 testDirnameWindows("dir\\file:stream", "dir");752 testDirnameWindows("dir\\file:stream", "dir");
747 testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");753 testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
748 testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");754 testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
...@@ -753,18 +759,26 @@ test "os.path.dirnameWindows" {...@@ -753,18 +759,26 @@ test "os.path.dirnameWindows" {
753 testDirnameWindows("/a/b/", "/a");759 testDirnameWindows("/a/b/", "/a");
754 testDirnameWindows("/a/b", "/a");760 testDirnameWindows("/a/b", "/a");
755 testDirnameWindows("/a", "/");761 testDirnameWindows("/a", "/");
756 testDirnameWindows("", "");762 testDirnameWindows("", null);
757 testDirnameWindows("/", "/");763 testDirnameWindows("/", "/");
758 testDirnameWindows("////", "/");764 testDirnameWindows("////", "/");
759 testDirnameWindows("foo", "");765 testDirnameWindows("foo", null);
760}766}
761767
762fn testDirnamePosix(input: []const u8, expected_output: []const u8) void {768fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void {
763 assert(mem.eql(u8, dirnamePosix(input), expected_output));769 if (dirnamePosix(input)) |output| {
770 assert(mem.eql(u8, output, expected_output.?));
771 } else {
772 assert(expected_output == null);
773 }
764}774}
765775
766fn testDirnameWindows(input: []const u8, expected_output: []const u8) void {776fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
767 assert(mem.eql(u8, dirnameWindows(input), expected_output));777 if (dirnameWindows(input)) |output| {
778 assert(mem.eql(u8, output, expected_output.?));
779 } else {
780 assert(expected_output == null);
781 }
768}782}
769783
770pub fn basename(path: []const u8) []const u8 {784pub fn basename(path: []const u8) []const u8 {