DoxigAlpha

relativeWindows

Function parameters

Parameters

#
from:[]const u8
to:[]const u8

Type definitions in this namespace

Types

#

Returns if the given byte is a valid path separator

Functions

#
isSep
Returns if the given byte is a valid path separator
join
Naively combines a series of paths with the native path separator.
joinZ
Naively combines a series of paths with the native path separator and null terminator.
resolve
On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
resolveWindows
This function is like a series of `cd` statements executed one after another.
resolvePosix
This function is like a series of `cd` statements executed one after another.
dirname
Strip the last component from a file path.
relative
Returns the relative path from `from` to `to`.
extension
Searches for a file extension separated by a `.` and returns the string after that `.`.
stem
Returns the last component of this path without its extension (if any):
ComponentIterator
A path component iterator that can move forwards and backwards.
fmtAsUtf8Lossy
Format a path encoded as bytes for display as UTF-8.
fmtWtf16LeAsUtf8Lossy
Format a path encoded as WTF-16 LE for display as UTF-8.

= '\\'

Values

#
sep
= switch (native_os) { .windows, .uefi => sep_windows, else => sep_posix, }
sep_str
= switch (native_os) { .windows, .uefi => sep_str_windows, else => sep_str_posix, }
delimiter
= if (native_os == .windows) delimiter_windows else delimiter_posix

Source

Implementation

#
pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) ![]u8 {
    const cwd = try process.getCwdAlloc(allocator);
    defer allocator.free(cwd);
    const resolved_from = try resolveWindows(allocator, &[_][]const u8{ cwd, from });
    defer allocator.free(resolved_from);

    var clean_up_resolved_to = true;
    const resolved_to = try resolveWindows(allocator, &[_][]const u8{ cwd, to });
    defer if (clean_up_resolved_to) allocator.free(resolved_to);

    const parsed_from = windowsParsePath(resolved_from);
    const parsed_to = windowsParsePath(resolved_to);
    const result_is_to = x: {
        if (parsed_from.kind != parsed_to.kind) {
            break :x true;
        } else switch (parsed_from.kind) {
            .NetworkShare => {
                break :x !networkShareServersEql(parsed_to.disk_designator, parsed_from.disk_designator);
            },
            .Drive => {
                break :x ascii.toUpper(parsed_from.disk_designator[0]) != ascii.toUpper(parsed_to.disk_designator[0]);
            },
            .None => {
                break :x false;
            },
        }
    };

    if (result_is_to) {
        clean_up_resolved_to = false;
        return resolved_to;
    }

    var from_it = mem.tokenizeAny(u8, resolved_from, "/\\");
    var to_it = mem.tokenizeAny(u8, resolved_to, "/\\");
    while (true) {
        const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest());
        const to_rest = to_it.rest();
        if (to_it.next()) |to_component| {
            if (windows.eqlIgnoreCaseWtf8(from_component, to_component))
                continue;
        }
        var up_index_end = "..".len;
        while (from_it.next()) |_| {
            up_index_end += "\\..".len;
        }
        const result = try allocator.alloc(u8, up_index_end + @intFromBool(to_rest.len > 0) + to_rest.len);
        errdefer allocator.free(result);

        result[0..2].* = "..".*;
        var result_index: usize = 2;
        while (result_index < up_index_end) {
            result[result_index..][0..3].* = "\\..".*;
            result_index += 3;
        }

        var rest_it = mem.tokenizeAny(u8, to_rest, "/\\");
        while (rest_it.next()) |to_component| {
            result[result_index] = '\\';
            result_index += 1;
            @memcpy(result[result_index..][0..to_component.len], to_component);
            result_index += to_component.len;
        }

        return allocator.realloc(result, result_index);
    }

    return [_]u8{};
}