Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

relativeWindows

Returns the non-absolute path from from to to according to Windows rules.

Other than memory allocation, this is a pure function; the result solely depends on the input parameters.

If from and to each resolve to the same path (after calling resolve on each), a zero-length string is returned.

The result is not guaranteed to be relative, as the paths may be on different volumes. In that case, the result will be the canonicalized absolute path of to.

Per-drive CWDs are stored in special semi-hidden environment variables of the format =<drive-letter>:, e.g. =C:. This type of CWD is purely a shell concept, so there's no guarantee that it'll be set or that it'll even be accurate. This is the only reason for the environ_map parameter. null is treated equivalent to the environment variable missing.

path.relativeWindows
pub fn relativeWindows(
    gpa: Allocator,
    cwd: []const u8,
    environ_map: ?*const std.process.Environ.Map,
    from: []const u8,
    to: []const u8,
) Allocator.Error![]u8

File

lib/std/fs/path.zig:1542

Code

pub fn relativeWindows(
    gpa: Allocator,
    cwd: []const u8,
    environ_map: ?*const std.process.Environ.Map,
    from: []const u8,
    to: []const u8,
) Allocator.Error![]u8 {
    const parsed_from = parsePathWindows(u8, from);
    const parsed_to = parsePathWindows(u8, to);

    const result_is_always_to = x: {
        if (parsed_from.kind != parsed_to.kind) {
            break :x false;
        }
        switch (parsed_from.kind) {
            .drive_relative, .drive_absolute => {
                break :x !compareDiskDesignators(u8, .drive, parsed_from.root, parsed_to.root);
            },
            .unc_absolute => {
                break :x !compareDiskDesignators(u8, .unc, parsed_from.root, parsed_to.root);
            },
            .relative, .rooted, .local_device => break :x false,
            .root_local_device => break :x true,
        }
    };

    if (result_is_always_to) {
        return windowsResolveAgainstCwd(gpa, cwd, environ_map, to, parsed_to);
    }

    const resolved_from = try windowsResolveAgainstCwd(gpa, cwd, environ_map, from, parsed_from);
    defer gpa.free(resolved_from);
    var clean_up_resolved_to = true;
    const resolved_to = try windowsResolveAgainstCwd(gpa, cwd, environ_map, to, parsed_to);
    defer if (clean_up_resolved_to) gpa.free(resolved_to);

    const parsed_resolved_from = parsePathWindows(u8, resolved_from);
    const parsed_resolved_to = parsePathWindows(u8, resolved_to);

    const result_is_to = x: {
        if (parsed_resolved_from.kind != parsed_resolved_to.kind) {
            break :x true;
        }
        switch (parsed_resolved_from.kind) {
            .drive_absolute, .drive_relative => {
                break :x !compareDiskDesignators(u8, .drive, parsed_resolved_from.root, parsed_resolved_to.root);
            },
            .unc_absolute => {
                break :x !compareDiskDesignators(u8, .unc, parsed_resolved_from.root, parsed_resolved_to.root);
            },
            .relative, .rooted, .local_device => break :x false,
            .root_local_device => break :x true,
        }
    };

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

    var from_it = mem.tokenizeAny(u8, resolved_from[parsed_resolved_from.root.len..], "/\\");
    var to_it = mem.tokenizeAny(u8, resolved_to[parsed_resolved_to.root.len..], "/\\");
    while (true) {
        const from_component = from_it.next() orelse return gpa.dupe(u8, to_it.rest());
        const to_rest = to_it.rest();
        if (to_it.next()) |to_component| {
            if (eqlIgnoreCaseWtf8(from_component, to_component))
                continue;
        }
        var up_index_end = "..".len;
        while (from_it.next()) |_| {
            up_index_end += "\\..".len;
        }
        const result = try gpa.alloc(u8, up_index_end + @intFromBool(to_rest.len > 0) + to_rest.len);
        errdefer gpa.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 gpa.realloc(result, result_index);
    }
    return [_]u8{};
}