| ... | @@ -610,9 +610,14 @@ fn testDirnameWindows(input: []const u8, expected_output: []const u8) { | ... | @@ -610,9 +610,14 @@ fn testDirnameWindows(input: []const u8, expected_output: []const u8) { |
| 610 | } | 610 | } |
| 611 | | 611 | |
| 612 | pub fn basename(path: []const u8) -> []const u8 { | 612 | pub fn basename(path: []const u8) -> []const u8 { |
| 613 | if (builtin.os == builtin.Os.windows) { | 613 | if (is_windows) { |
| 614 | @compileError("TODO implement os.path.basename for 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 | if (path.len == 0) | 621 | if (path.len == 0) |
| 617 | return []u8{}; | 622 | return []u8{}; |
| 618 | | 623 | |
| ... | @@ -633,6 +638,38 @@ pub fn basename(path: []const u8) -> []const u8 { | ... | @@ -633,6 +638,38 @@ pub fn basename(path: []const u8) -> []const u8 { |
| 633 | return path[start_index + 1..end_index]; | 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 | test "os.path.basename" { | 673 | test "os.path.basename" { |
| 637 | testBasename("", ""); | 674 | testBasename("", ""); |
| 638 | testBasename("/", ""); | 675 | testBasename("/", ""); |
| ... | @@ -646,11 +683,44 @@ test "os.path.basename" { | ... | @@ -646,11 +683,44 @@ test "os.path.basename" { |
| 646 | testBasename("/aaa/b", "b"); | 683 | testBasename("/aaa/b", "b"); |
| 647 | testBasename("/a/b", "b"); | 684 | testBasename("/a/b", "b"); |
| 648 | testBasename("//a", "a"); | 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 | fn testBasename(input: []const u8, expected_output: []const u8) { | 712 | fn testBasename(input: []const u8, expected_output: []const u8) { |
| 651 | assert(mem.eql(u8, basename(input), expected_output)); | 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 | /// Returns the relative path from ::from to ::to. If ::from and ::to each | 724 | /// Returns the relative path from ::from to ::to. If ::from and ::to each |
| 655 | /// resolve to the same path (after calling ::resolve on each), a zero-length | 725 | /// resolve to the same path (after calling ::resolve on each), a zero-length |
| 656 | /// string is returned. | 726 | /// string is returned. |