| ... | @@ -867,6 +867,13 @@ pub const resolveWindows = resolveAllocWindows; | ... | @@ -867,6 +867,13 @@ pub const resolveWindows = resolveAllocWindows; |
| 867 | /// Deprecated in favor of `resolveAllocPosix`. | 867 | /// Deprecated in favor of `resolveAllocPosix`. |
| 868 | pub const resolvePosix = resolveAllocPosix; | 868 | pub const resolvePosix = resolveAllocPosix; |
| 869 | | 869 | |
| | 870 | /// Deprecated in favor of `relativeAlloc`. |
| | 871 | pub const relative = relativeAlloc; |
| | 872 | /// Deprecated in favor of `relativeAllocPosix`. |
| | 873 | pub const relativePosix = relativeAllocPosix; |
| | 874 | /// Deprecated in favor of `relativeAllocWindows`. |
| | 875 | pub const relativeWindows = relativeAllocWindows; |
| | 876 | |
| 870 | /// On Windows, calls `resolveAllocWindows`; otherwise calls `resolveAllocPosix`. | 877 | /// On Windows, calls `resolveAllocWindows`; otherwise calls `resolveAllocPosix`. |
| 871 | pub fn resolveAlloc(gpa: Allocator, paths: []const []const u8) Allocator.Error![]u8 { | 878 | pub fn resolveAlloc(gpa: Allocator, paths: []const []const u8) Allocator.Error![]u8 { |
| 872 | switch (native_os) { | 879 | switch (native_os) { |
| ... | @@ -1536,7 +1543,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) !void { | ... | @@ -1536,7 +1543,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) !void { |
| 1536 | /// | 1543 | /// |
| 1537 | /// See `relativePosix` and `relativeWindows` for operating system specific | 1544 | /// See `relativePosix` and `relativeWindows` for operating system specific |
| 1538 | /// details and for how `environ_map` is used. | 1545 | /// details and for how `environ_map` is used. |
| 1539 | pub fn relative( | 1546 | pub fn relativeAlloc( |
| 1540 | gpa: Allocator, | 1547 | gpa: Allocator, |
| 1541 | cwd: []const u8, | 1548 | cwd: []const u8, |
| 1542 | environ_map: ?*const std.process.Environ.Map, | 1549 | environ_map: ?*const std.process.Environ.Map, |
| ... | @@ -1544,9 +1551,36 @@ pub fn relative( | ... | @@ -1544,9 +1551,36 @@ pub fn relative( |
| 1544 | to: []const u8, | 1551 | to: []const u8, |
| 1545 | ) Allocator.Error![]u8 { | 1552 | ) Allocator.Error![]u8 { |
| 1546 | if (native_os == .windows) { | 1553 | if (native_os == .windows) { |
| 1547 | return relativeWindows(gpa, cwd, environ_map, from, to); | 1554 | return relativeAllocWindows(gpa, cwd, environ_map, from, to); |
| | 1555 | } else { |
| | 1556 | return relativeAllocPosix(gpa, cwd, from, to); |
| | 1557 | } |
| | 1558 | } |
| | 1559 | |
| | 1560 | /// Appends the non-absolute path from `from` to `to` to the provided array |
| | 1561 | /// list. |
| | 1562 | /// |
| | 1563 | /// Other than modifying the provided array list, this is a pure function; the |
| | 1564 | /// result solely depends on the input parameters and no file system operations |
| | 1565 | /// are performed. |
| | 1566 | /// |
| | 1567 | /// If `from` and `to` each resolve to the same path (after calling |
| | 1568 | /// `resolveAppend` on each), a zero-length string is returned. |
| | 1569 | /// |
| | 1570 | /// See `relativeAppendPosix` and `relativeAppendWindows` for operating system |
| | 1571 | /// specific details and for how `environ_map` is used. |
| | 1572 | pub fn relativeAppend( |
| | 1573 | gpa: Allocator, |
| | 1574 | al: *std.ArrayList(u8), |
| | 1575 | cwd: []const u8, |
| | 1576 | environ_map: ?*const std.process.Environ.Map, |
| | 1577 | from: []const u8, |
| | 1578 | to: []const u8, |
| | 1579 | ) Allocator.Error!void { |
| | 1580 | if (native_os == .windows) { |
| | 1581 | return relativeAppendWindows(gpa, al, cwd, environ_map, from, to); |
| 1548 | } else { | 1582 | } else { |
| 1549 | return relativePosix(gpa, cwd, from, to); | 1583 | return relativeAppendPosix(gpa, al, cwd, from, to); |
| 1550 | } | 1584 | } |
| 1551 | } | 1585 | } |
| 1552 | | 1586 | |
| ... | @@ -1567,7 +1601,7 @@ pub fn relative( | ... | @@ -1567,7 +1601,7 @@ pub fn relative( |
| 1567 | /// shell concept, so there's no guarantee that it'll be set or that it'll even | 1601 | /// shell concept, so there's no guarantee that it'll be set or that it'll even |
| 1568 | /// be accurate. This is the only reason for the `environ_map` parameter. `null` is | 1602 | /// be accurate. This is the only reason for the `environ_map` parameter. `null` is |
| 1569 | /// treated equivalent to the environment variable missing. | 1603 | /// treated equivalent to the environment variable missing. |
| 1570 | pub fn relativeWindows( | 1604 | pub fn relativeAllocWindows( |
| 1571 | gpa: Allocator, | 1605 | gpa: Allocator, |
| 1572 | cwd: []const u8, | 1606 | cwd: []const u8, |
| 1573 | environ_map: ?*const std.process.Environ.Map, | 1607 | environ_map: ?*const std.process.Environ.Map, |
| ... | @@ -1663,6 +1697,23 @@ pub fn relativeWindows( | ... | @@ -1663,6 +1697,23 @@ pub fn relativeWindows( |
| 1663 | return [_]u8{}; | 1697 | return [_]u8{}; |
| 1664 | } | 1698 | } |
| 1665 | | 1699 | |
| | 1700 | pub fn relativeAppendWindows( |
| | 1701 | gpa: Allocator, |
| | 1702 | al: *std.ArrayList(u8), |
| | 1703 | cwd: []const u8, |
| | 1704 | environ_map: ?*const std.process.Environ.Map, |
| | 1705 | from: []const u8, |
| | 1706 | to: []const u8, |
| | 1707 | ) Allocator.Error!void { |
| | 1708 | _ = gpa; |
| | 1709 | _ = al; |
| | 1710 | _ = cwd; |
| | 1711 | _ = environ_map; |
| | 1712 | _ = from; |
| | 1713 | _ = to; |
| | 1714 | @panic("TODO"); |
| | 1715 | } |
| | 1716 | |
| 1666 | fn windowsResolveAgainstCwd( | 1717 | fn windowsResolveAgainstCwd( |
| 1667 | gpa: Allocator, | 1718 | gpa: Allocator, |
| 1668 | cwd: []const u8, | 1719 | cwd: []const u8, |
| ... | @@ -1728,36 +1779,66 @@ fn windowsResolveAgainstCwd( | ... | @@ -1728,36 +1779,66 @@ fn windowsResolveAgainstCwd( |
| 1728 | }; | 1779 | }; |
| 1729 | } | 1780 | } |
| 1730 | | 1781 | |
| 1731 | /// Returns the non-absolute path from `from` to `to` according to Windows rules. | 1782 | /// Returns the non-absolute path from `from` to `to` according to POSIX rules. |
| 1732 | /// | 1783 | /// |
| 1733 | /// Other than memory allocation, this is a pure function; the result solely | 1784 | /// Other than memory allocation, this is a pure function; the result solely |
| 1734 | /// depends on the input parameters. | 1785 | /// depends on the input parameters. |
| 1735 | /// | 1786 | /// |
| 1736 | /// If `from` and `to` each resolve to the same path (after calling `resolve` | 1787 | /// If `from` and `to` each resolve to the same path (after calling `resolve` |
| 1737 | /// on each), a zero-length string is returned. | 1788 | /// on each), a zero-length string is returned. |
| | 1789 | pub fn relativeAllocPosix(gpa: Allocator, cwd: []const u8, from: []const u8, to: []const u8) Allocator.Error![]u8 { |
| | 1790 | var buffer: std.ArrayList(u8) = .empty; |
| | 1791 | defer buffer.deinit(gpa); |
| | 1792 | try relativeAppendPosix(gpa, &buffer, cwd, from, to); |
| | 1793 | try buffer.shrinkToLen(gpa); |
| | 1794 | return buffer.toOwnedSliceAssert(); |
| | 1795 | } |
| | 1796 | |
| | 1797 | /// Appends the non-absolute path from `from` to `to` according to POSIX rules |
| | 1798 | /// to the provided array list. |
| | 1799 | /// |
| | 1800 | /// Other than modifying the provided array list, this is a pure function; the |
| | 1801 | /// result solely depends on the input parameters and it does no file system |
| | 1802 | /// operations. |
| 1738 | /// | 1803 | /// |
| 1739 | pub fn relativePosix(allocator: Allocator, cwd: []const u8, from: []const u8, to: []const u8) Allocator.Error![]u8 { | 1804 | /// If `from` and `to` each resolve to the same path (after calling |
| 1740 | const resolved_from = try resolveAllocPosix(allocator, &[_][]const u8{ cwd, from }); | 1805 | /// `resolveAppend` on each), nothing is appended to the array list. |
| 1741 | defer allocator.free(resolved_from); | 1806 | pub fn relativeAppendPosix( |
| 1742 | const resolved_to = try resolveAllocPosix(allocator, &[_][]const u8{ cwd, to }); | 1807 | gpa: Allocator, |
| 1743 | defer allocator.free(resolved_to); | 1808 | al: *std.ArrayList(u8), |
| 1744 | | 1809 | cwd: []const u8, |
| 1745 | var from_it = mem.tokenizeScalar(u8, resolved_from, '/'); | 1810 | from: []const u8, |
| 1746 | var to_it = mem.tokenizeScalar(u8, resolved_to, '/'); | 1811 | to: []const u8, |
| | 1812 | ) Allocator.Error!void { |
| | 1813 | const orig_len = al.items.len; |
| | 1814 | errdefer al.items.len = orig_len; |
| | 1815 | |
| | 1816 | const resolved_from_start = al.items.len; |
| | 1817 | try resolveAppendPosix(gpa, al, &.{ cwd, from }); |
| | 1818 | const resolved_from_end = al.items.len; |
| | 1819 | |
| | 1820 | const resolved_to_start = al.items.len; |
| | 1821 | try resolveAppendPosix(gpa, al, &.{ cwd, to }); |
| | 1822 | const resolved_to_end = al.items.len; |
| | 1823 | |
| | 1824 | var from_it = mem.tokenizeScalar(u8, al.items[resolved_from_start..resolved_from_end], '/'); |
| | 1825 | var to_it = mem.tokenizeScalar(u8, al.items[resolved_to_start..resolved_to_end], '/'); |
| 1747 | while (true) { | 1826 | while (true) { |
| 1748 | const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest()); | 1827 | const from_component = from_it.next() orelse { |
| | 1828 | const result = to_it.rest(); |
| | 1829 | @memmove(al.items[orig_len..][0..result.len], result); |
| | 1830 | al.shrinkRetainingCapacity(orig_len + result.len); |
| | 1831 | return; |
| | 1832 | }; |
| 1749 | const to_rest = to_it.rest(); | 1833 | const to_rest = to_it.rest(); |
| 1750 | if (to_it.next()) |to_component| { | 1834 | if (to_it.next()) |to_component| { |
| 1751 | if (mem.eql(u8, from_component, to_component)) | 1835 | if (mem.eql(u8, from_component, to_component)) |
| 1752 | continue; | 1836 | continue; |
| 1753 | } | 1837 | } |
| 1754 | var up_count: usize = 1; | 1838 | var up_count: usize = 1; |
| 1755 | while (from_it.next()) |_| { | 1839 | while (from_it.next()) |_| up_count += 1; |
| 1756 | up_count += 1; | | |
| 1757 | } | | |
| 1758 | const up_index_end = up_count * "../".len; | 1840 | const up_index_end = up_count * "../".len; |
| 1759 | const result = try allocator.alloc(u8, up_index_end + to_rest.len); | 1841 | const result = al.items[orig_len..]; |
| 1760 | errdefer allocator.free(result); | | |
| 1761 | | 1842 | |
| 1762 | var result_index: usize = 0; | 1843 | var result_index: usize = 0; |
| 1763 | while (result_index < up_index_end) { | 1844 | while (result_index < up_index_end) { |
| ... | @@ -1765,15 +1846,16 @@ pub fn relativePosix(allocator: Allocator, cwd: []const u8, from: []const u8, to | ... | @@ -1765,15 +1846,16 @@ pub fn relativePosix(allocator: Allocator, cwd: []const u8, from: []const u8, to |
| 1765 | result_index += 3; | 1846 | result_index += 3; |
| 1766 | } | 1847 | } |
| 1767 | if (to_rest.len == 0) { | 1848 | if (to_rest.len == 0) { |
| 1768 | // shave off the trailing slash | 1849 | // Shave off the trailing slash. |
| 1769 | return allocator.realloc(result, result_index - 1); | 1850 | al.shrinkRetainingCapacity(orig_len + result_index - 1); |
| | 1851 | return; |
| 1770 | } | 1852 | } |
| 1771 | | 1853 | @memmove(result[result_index..][0..to_rest.len], to_rest); |
| 1772 | @memcpy(result[result_index..][0..to_rest.len], to_rest); | 1854 | al.shrinkRetainingCapacity(orig_len + result_index + to_rest.len); |
| 1773 | return result; | 1855 | return; |
| 1774 | } | 1856 | } |
| 1775 | | 1857 | |
| 1776 | return [_]u8{}; | 1858 | al.shrinkRetainingCapacity(orig_len); |
| 1777 | } | 1859 | } |
| 1778 | | 1860 | |
| 1779 | test relative { | 1861 | test relative { |