os.path.basename implementation for windows

This commit is contained in:
Andrew Kelley 2017-10-08 19:18:47 -04:00
parent dcf5c9074e
commit e15e1e09f0

View File

@ -610,9 +610,14 @@ fn testDirnameWindows(input: []const u8, expected_output: []const u8) {
}
pub fn basename(path: []const u8) -> []const u8 {
if (builtin.os == builtin.Os.windows) {
@compileError("TODO implement os.path.basename for windows");
if (is_windows) {
return basenameWindows(path);
} else {
return basenamePosix(path);
}
}
pub fn basenamePosix(path: []const u8) -> []const u8 {
if (path.len == 0)
return []u8{};
@ -633,6 +638,38 @@ pub fn basename(path: []const u8) -> []const u8 {
return path[start_index + 1..end_index];
}
pub fn basenameWindows(path: []const u8) -> []const u8 {
if (path.len == 0)
return []u8{};
var end_index: usize = path.len - 1;
while (true) {
const byte = path[end_index];
if (byte == '/' or byte == '\\') {
if (end_index == 0)
return []u8{};
end_index -= 1;
continue;
}
if (byte == ':' and end_index == 1) {
return []u8{};
}
break;
}
var start_index: usize = end_index;
end_index += 1;
while (path[start_index] != '/' and path[start_index] != '\\' and
!(path[start_index] == ':' and start_index == 1))
{
if (start_index == 0)
return path[0..end_index];
start_index -= 1;
}
return path[start_index + 1..end_index];
}
test "os.path.basename" {
testBasename("", "");
testBasename("/", "");
@ -646,11 +683,44 @@ test "os.path.basename" {
testBasename("/aaa/b", "b");
testBasename("/a/b", "b");
testBasename("//a", "a");
testBasenamePosix("\\dir\\basename.ext", "\\dir\\basename.ext");
testBasenamePosix("\\basename.ext", "\\basename.ext");
testBasenamePosix("basename.ext", "basename.ext");
testBasenamePosix("basename.ext\\", "basename.ext\\");
testBasenamePosix("basename.ext\\\\", "basename.ext\\\\");
testBasenamePosix("foo", "foo");
testBasenameWindows("\\dir\\basename.ext", "basename.ext");
testBasenameWindows("\\basename.ext", "basename.ext");
testBasenameWindows("basename.ext", "basename.ext");
testBasenameWindows("basename.ext\\", "basename.ext");
testBasenameWindows("basename.ext\\\\", "basename.ext");
testBasenameWindows("foo", "foo");
testBasenameWindows("C:", "");
testBasenameWindows("C:.", ".");
testBasenameWindows("C:\\", "");
testBasenameWindows("C:\\dir\\base.ext", "base.ext");
testBasenameWindows("C:\\basename.ext", "basename.ext");
testBasenameWindows("C:basename.ext", "basename.ext");
testBasenameWindows("C:basename.ext\\", "basename.ext");
testBasenameWindows("C:basename.ext\\\\", "basename.ext");
testBasenameWindows("C:foo", "foo");
testBasenameWindows("file:stream", "file:stream");
}
fn testBasename(input: []const u8, expected_output: []const u8) {
assert(mem.eql(u8, basename(input), expected_output));
}
fn testBasenamePosix(input: []const u8, expected_output: []const u8) {
assert(mem.eql(u8, basenamePosix(input), expected_output));
}
fn testBasenameWindows(input: []const u8, expected_output: []const u8) {
assert(mem.eql(u8, basenameWindows(input), expected_output));
}
/// Returns the relative path from ::from to ::to. If ::from and ::to each
/// resolve to the same path (after calling ::resolve on each), a zero-length
/// string is returned.