Function resolveWindows [src]

This function is like a series of cd statements executed one after another. It resolves "." and "..", but will not convert relative path to absolute path, use std.fs.Dir.realpath instead. The result does not have a trailing path separator. Each drive has its own current working directory. Path separators are canonicalized to '\' and drives are canonicalized to capital letters. Note: all usage of this function should be audited due to the existence of symlinks. Without performing actual syscalls, resolving .. could be incorrect. This API may break in the future: https://github.com/ziglang/zig/issues/13613

Prototype

pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8

Parameters

allocator: Allocatorpaths: []const []const u8

Example

test resolveWindows { try testResolveWindows( &[_][]const u8{ "Z:\\", "/usr/local", "lib\\zig\\std\\array_list.zig" }, "Z:\\usr\\local\\lib\\zig\\std\\array_list.zig", ); try testResolveWindows( &[_][]const u8{ "z:\\", "usr/local", "lib\\zig" }, "Z:\\usr\\local\\lib\\zig", ); try testResolveWindows(&[_][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }, "C:\\hi\\ok"); try testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }, "C:\\blah\\a"); try testResolveWindows(&[_][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }, "C:\\blah\\a"); try testResolveWindows(&[_][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }, "D:\\e.exe"); try testResolveWindows(&[_][]const u8{ "c:/ignore", "c:/some/file" }, "C:\\some\\file"); try testResolveWindows(&[_][]const u8{ "d:/ignore", "d:some/dir//" }, "D:\\ignore\\some\\dir"); try testResolveWindows(&[_][]const u8{ "//server/share", "..", "relative\\" }, "\\\\server\\share\\relative"); try testResolveWindows(&[_][]const u8{ "c:/", "//" }, "C:\\"); try testResolveWindows(&[_][]const u8{ "c:/", "//dir" }, "C:\\dir"); try testResolveWindows(&[_][]const u8{ "c:/", "//server/share" }, "\\\\server\\share\\"); try testResolveWindows(&[_][]const u8{ "c:/", "//server//share" }, "\\\\server\\share\\"); try testResolveWindows(&[_][]const u8{ "c:/", "///some//dir" }, "C:\\some\\dir"); try testResolveWindows(&[_][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }, "C:\\foo\\tmp.3\\cycles\\root.js"); // Keep relative paths relative. try testResolveWindows(&[_][]const u8{"a/b"}, "a\\b"); }

Source

pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { assert(paths.len > 0); // determine which disk designator we will result with, if any var result_drive_buf = "_:".*; var disk_designator: []const u8 = ""; var drive_kind = WindowsPath.Kind.None; var have_abs_path = false; var first_index: usize = 0; for (paths, 0..) |p, i| { const parsed = windowsParsePath(p); if (parsed.is_abs) { have_abs_path = true; first_index = i; } switch (parsed.kind) { .Drive => { result_drive_buf[0] = ascii.toUpper(parsed.disk_designator[0]); disk_designator = result_drive_buf[0..]; drive_kind = WindowsPath.Kind.Drive; }, .NetworkShare => { disk_designator = parsed.disk_designator; drive_kind = WindowsPath.Kind.NetworkShare; }, .None => {}, } } // if we will result with a disk designator, loop again to determine // which is the last time the disk designator is absolutely specified, if any // and count up the max bytes for paths related to this disk designator if (drive_kind != WindowsPath.Kind.None) { have_abs_path = false; first_index = 0; var correct_disk_designator = false; for (paths, 0..) |p, i| { const parsed = windowsParsePath(p); if (parsed.kind != WindowsPath.Kind.None) { if (parsed.kind == drive_kind) { correct_disk_designator = compareDiskDesignators(drive_kind, disk_designator, parsed.disk_designator); } else { continue; } } if (!correct_disk_designator) { continue; } if (parsed.is_abs) { first_index = i; have_abs_path = true; } } } // Allocate result and fill in the disk designator. var result = std.ArrayList(u8).init(allocator); defer result.deinit(); const disk_designator_len: usize = l: { if (!have_abs_path) break :l 0; switch (drive_kind) { .Drive => { try result.appendSlice(disk_designator); break :l disk_designator.len; }, .NetworkShare => { var it = mem.tokenizeAny(u8, paths[first_index], "/\\"); const server_name = it.next().?; const other_name = it.next().?; try result.ensureUnusedCapacity(2 + 1 + server_name.len + other_name.len); result.appendSliceAssumeCapacity("\\\\"); result.appendSliceAssumeCapacity(server_name); result.appendAssumeCapacity('\\'); result.appendSliceAssumeCapacity(other_name); break :l result.items.len; }, .None => { break :l 1; }, } }; var correct_disk_designator = true; var negative_count: usize = 0; for (paths[first_index..]) |p| { const parsed = windowsParsePath(p); if (parsed.kind != .None) { if (parsed.kind == drive_kind) { const dd = result.items[0..disk_designator_len]; correct_disk_designator = compareDiskDesignators(drive_kind, dd, parsed.disk_designator); } else { continue; } } if (!correct_disk_designator) { continue; } var it = mem.tokenizeAny(u8, p[parsed.disk_designator.len..], "/\\"); while (it.next()) |component| { if (mem.eql(u8, component, ".")) { continue; } else if (mem.eql(u8, component, "..")) { if (result.items.len == 0) { negative_count += 1; continue; } while (true) { if (result.items.len == disk_designator_len) { break; } const end_with_sep = switch (result.items[result.items.len - 1]) { '\\', '/' => true, else => false, }; result.items.len -= 1; if (end_with_sep or result.items.len == 0) break; } } else if (!have_abs_path and result.items.len == 0) { try result.appendSlice(component); } else { try result.ensureUnusedCapacity(1 + component.len); result.appendAssumeCapacity('\\'); result.appendSliceAssumeCapacity(component); } } } if (disk_designator_len != 0 and result.items.len == disk_designator_len) { try result.append('\\'); return result.toOwnedSlice(); } if (result.items.len == 0) { if (negative_count == 0) { return allocator.dupe(u8, "."); } else { const real_result = try allocator.alloc(u8, 3 * negative_count - 1); var count = negative_count - 1; var i: usize = 0; while (count > 0) : (count -= 1) { real_result[i..][0..3].* = "..\\".*; i += 3; } real_result[i..][0..2].* = "..".*; return real_result; } } if (negative_count == 0) { return result.toOwnedSlice(); } else { const real_result = try allocator.alloc(u8, 3 * negative_count + result.items.len); var count = negative_count; var i: usize = 0; while (count > 0) : (count -= 1) { real_result[i..][0..3].* = "..\\".*; i += 3; } @memcpy(real_result[i..][0..result.items.len], result.items); return real_result; } }