| ... | ... | @@ -867,6 +867,13 @@ pub const resolveWindows = resolveAllocWindows; |
| 867 | 867 | /// Deprecated in favor of `resolveAllocPosix`. |
| 868 | 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 | 877 | /// On Windows, calls `resolveAllocWindows`; otherwise calls `resolveAllocPosix`. |
| 871 | 878 | pub fn resolveAlloc(gpa: Allocator, paths: []const []const u8) Allocator.Error![]u8 { |
| 872 | 879 | switch (native_os) { |
| ... | ... | @@ -1536,7 +1543,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) !void { |
| 1536 | 1543 | /// |
| 1537 | 1544 | /// See `relativePosix` and `relativeWindows` for operating system specific |
| 1538 | 1545 | /// details and for how `environ_map` is used. |
| 1539 | | pub fn relative( |
| 1546 | pub fn relativeAlloc( |
| 1540 | 1547 | gpa: Allocator, |
| 1541 | 1548 | cwd: []const u8, |
| 1542 | 1549 | environ_map: ?*const std.process.Environ.Map, |
| ... | ... | @@ -1544,9 +1551,36 @@ pub fn relative( |
| 1544 | 1551 | to: []const u8, |
| 1545 | 1552 | ) Allocator.Error![]u8 { |
| 1546 | 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 | 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 | 1601 | /// shell concept, so there's no guarantee that it'll be set or that it'll even |
| 1568 | 1602 | /// be accurate. This is the only reason for the `environ_map` parameter. `null` is |
| 1569 | 1603 | /// treated equivalent to the environment variable missing. |
| 1570 | | pub fn relativeWindows( |
| 1604 | pub fn relativeAllocWindows( |
| 1571 | 1605 | gpa: Allocator, |
| 1572 | 1606 | cwd: []const u8, |
| 1573 | 1607 | environ_map: ?*const std.process.Environ.Map, |
| ... | ... | @@ -1663,6 +1697,23 @@ pub fn relativeWindows( |
| 1663 | 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 | 1717 | fn windowsResolveAgainstCwd( |
| 1667 | 1718 | gpa: Allocator, |
| 1668 | 1719 | cwd: []const u8, |
| ... | ... | @@ -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 | 1784 | /// Other than memory allocation, this is a pure function; the result solely |
| 1734 | 1785 | /// depends on the input parameters. |
| 1735 | 1786 | /// |
| 1736 | 1787 | /// If `from` and `to` each resolve to the same path (after calling `resolve` |
| 1737 | 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 { |
| 1740 | | const resolved_from = try resolveAllocPosix(allocator, &[_][]const u8{ cwd, from }); |
| 1741 | | defer allocator.free(resolved_from); |
| 1742 | | const resolved_to = try resolveAllocPosix(allocator, &[_][]const u8{ cwd, to }); |
| 1743 | | defer allocator.free(resolved_to); |
| 1744 | | |
| 1745 | | var from_it = mem.tokenizeScalar(u8, resolved_from, '/'); |
| 1746 | | var to_it = mem.tokenizeScalar(u8, resolved_to, '/'); |
| 1804 | /// If `from` and `to` each resolve to the same path (after calling |
| 1805 | /// `resolveAppend` on each), nothing is appended to the array list. |
| 1806 | pub fn relativeAppendPosix( |
| 1807 | gpa: Allocator, |
| 1808 | al: *std.ArrayList(u8), |
| 1809 | cwd: []const u8, |
| 1810 | from: []const u8, |
| 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 | 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 | 1833 | const to_rest = to_it.rest(); |
| 1750 | 1834 | if (to_it.next()) |to_component| { |
| 1751 | 1835 | if (mem.eql(u8, from_component, to_component)) |
| 1752 | 1836 | continue; |
| 1753 | 1837 | } |
| 1754 | 1838 | var up_count: usize = 1; |
| 1755 | | while (from_it.next()) |_| { |
| 1756 | | up_count += 1; |
| 1757 | | } |
| 1839 | while (from_it.next()) |_| up_count += 1; |
| 1758 | 1840 | const up_index_end = up_count * "../".len; |
| 1759 | | const result = try allocator.alloc(u8, up_index_end + to_rest.len); |
| 1760 | | errdefer allocator.free(result); |
| 1841 | const result = al.items[orig_len..]; |
| 1761 | 1842 | |
| 1762 | 1843 | var result_index: usize = 0; |
| 1763 | 1844 | while (result_index < up_index_end) { |
| ... | ... | @@ -1765,15 +1846,16 @@ pub fn relativePosix(allocator: Allocator, cwd: []const u8, from: []const u8, to |
| 1765 | 1846 | result_index += 3; |
| 1766 | 1847 | } |
| 1767 | 1848 | if (to_rest.len == 0) { |
| 1768 | | // shave off the trailing slash |
| 1769 | | return allocator.realloc(result, result_index - 1); |
| 1849 | // Shave off the trailing slash. |
| 1850 | al.shrinkRetainingCapacity(orig_len + result_index - 1); |
| 1851 | return; |
| 1770 | 1852 | } |
| 1771 | | |
| 1772 | | @memcpy(result[result_index..][0..to_rest.len], to_rest); |
| 1773 | | return result; |
| 1853 | @memmove(result[result_index..][0..to_rest.len], to_rest); |
| 1854 | al.shrinkRetainingCapacity(orig_len + result_index + to_rest.len); |
| 1855 | return; |
| 1774 | 1856 | } |
| 1775 | 1857 | |
| 1776 | | return [_]u8{}; |
| 1858 | al.shrinkRetainingCapacity(orig_len); |
| 1777 | 1859 | } |
| 1778 | 1860 | |
| 1779 | 1861 | test relative { |