| ... | ... | @@ -610,9 +610,14 @@ fn testDirnameWindows(input: []const u8, expected_output: []const u8) { |
| 610 | 610 | } |
| 611 | 611 | |
| 612 | 612 | pub fn basename(path: []const u8) -> []const u8 { |
| 613 | | if (builtin.os == builtin.Os.windows) { |
| 614 | | @compileError("TODO implement os.path.basename for windows"); |
| 613 | if (is_windows) { |
| 614 | return basenameWindows(path); |
| 615 | } else { |
| 616 | return basenamePosix(path); |
| 615 | 617 | } |
| 618 | } |
| 619 | |
| 620 | pub fn basenamePosix(path: []const u8) -> []const u8 { |
| 616 | 621 | if (path.len == 0) |
| 617 | 622 | return []u8{}; |
| 618 | 623 | |
| ... | ... | @@ -633,6 +638,38 @@ pub fn basename(path: []const u8) -> []const u8 { |
| 633 | 638 | return path[start_index + 1..end_index]; |
| 634 | 639 | } |
| 635 | 640 | |
| 641 | pub fn basenameWindows(path: []const u8) -> []const u8 { |
| 642 | if (path.len == 0) |
| 643 | return []u8{}; |
| 644 | |
| 645 | var end_index: usize = path.len - 1; |
| 646 | while (true) { |
| 647 | const byte = path[end_index]; |
| 648 | if (byte == '/' or byte == '\\') { |
| 649 | if (end_index == 0) |
| 650 | return []u8{}; |
| 651 | end_index -= 1; |
| 652 | continue; |
| 653 | } |
| 654 | if (byte == ':' and end_index == 1) { |
| 655 | return []u8{}; |
| 656 | } |
| 657 | break; |
| 658 | } |
| 659 | |
| 660 | var start_index: usize = end_index; |
| 661 | end_index += 1; |
| 662 | while (path[start_index] != '/' and path[start_index] != '\\' and |
| 663 | !(path[start_index] == ':' and start_index == 1)) |
| 664 | { |
| 665 | if (start_index == 0) |
| 666 | return path[0..end_index]; |
| 667 | start_index -= 1; |
| 668 | } |
| 669 | |
| 670 | return path[start_index + 1..end_index]; |
| 671 | } |
| 672 | |
| 636 | 673 | test "os.path.basename" { |
| 637 | 674 | testBasename("", ""); |
| 638 | 675 | testBasename("/", ""); |
| ... | ... | @@ -646,11 +683,44 @@ test "os.path.basename" { |
| 646 | 683 | testBasename("/aaa/b", "b"); |
| 647 | 684 | testBasename("/a/b", "b"); |
| 648 | 685 | testBasename("//a", "a"); |
| 686 | |
| 687 | testBasenamePosix("\\dir\\basename.ext", "\\dir\\basename.ext"); |
| 688 | testBasenamePosix("\\basename.ext", "\\basename.ext"); |
| 689 | testBasenamePosix("basename.ext", "basename.ext"); |
| 690 | testBasenamePosix("basename.ext\\", "basename.ext\\"); |
| 691 | testBasenamePosix("basename.ext\\\\", "basename.ext\\\\"); |
| 692 | testBasenamePosix("foo", "foo"); |
| 693 | |
| 694 | testBasenameWindows("\\dir\\basename.ext", "basename.ext"); |
| 695 | testBasenameWindows("\\basename.ext", "basename.ext"); |
| 696 | testBasenameWindows("basename.ext", "basename.ext"); |
| 697 | testBasenameWindows("basename.ext\\", "basename.ext"); |
| 698 | testBasenameWindows("basename.ext\\\\", "basename.ext"); |
| 699 | testBasenameWindows("foo", "foo"); |
| 700 | testBasenameWindows("C:", ""); |
| 701 | testBasenameWindows("C:.", "."); |
| 702 | testBasenameWindows("C:\\", ""); |
| 703 | testBasenameWindows("C:\\dir\\base.ext", "base.ext"); |
| 704 | testBasenameWindows("C:\\basename.ext", "basename.ext"); |
| 705 | testBasenameWindows("C:basename.ext", "basename.ext"); |
| 706 | testBasenameWindows("C:basename.ext\\", "basename.ext"); |
| 707 | testBasenameWindows("C:basename.ext\\\\", "basename.ext"); |
| 708 | testBasenameWindows("C:foo", "foo"); |
| 709 | testBasenameWindows("file:stream", "file:stream"); |
| 649 | 710 | } |
| 711 | |
| 650 | 712 | fn testBasename(input: []const u8, expected_output: []const u8) { |
| 651 | 713 | assert(mem.eql(u8, basename(input), expected_output)); |
| 652 | 714 | } |
| 653 | 715 | |
| 716 | fn testBasenamePosix(input: []const u8, expected_output: []const u8) { |
| 717 | assert(mem.eql(u8, basenamePosix(input), expected_output)); |
| 718 | } |
| 719 | |
| 720 | fn testBasenameWindows(input: []const u8, expected_output: []const u8) { |
| 721 | assert(mem.eql(u8, basenameWindows(input), expected_output)); |
| 722 | } |
| 723 | |
| 654 | 724 | /// Returns the relative path from ::from to ::to. If ::from and ::to each |
| 655 | 725 | /// resolve to the same path (after calling ::resolve on each), a zero-length |
| 656 | 726 | /// string is returned. |