This function is like a series of cd statements executed one after another.
It resolves "." and ".." to the best of its ability, but will not convert relative paths to an absolute path, use Io.Dir.realpath instead.
".." components may persist in the resolved path if the resolved path is relative.
The result does not have a trailing path separator.
This function does not perform any syscalls. Executing this series of path lookups on the actual filesystem may produce different results due to symlinks.
pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.Error![]u8
pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.Error![]u8 {
assert(paths.len > 0);
var result = std.array_list.Managed(u8).init(allocator);
defer result.deinit();
var negative_count: usize = 0;
var is_abs = false;
for (paths) |p| {
if (isAbsolutePosix(p)) {
is_abs = true;
negative_count = 0;
result.clearRetainingCapacity();
}
var it = mem.tokenizeScalar(u8, p, '/');
while (it.next()) |component| {
if (mem.eql(u8, component, ".")) {
continue;
} else if (mem.eql(u8, component, "..")) {
if (result.items.len == 0) {
negative_count += @intFromBool(!is_abs);
continue;
}
while (true) {
const ends_with_slash = result.items[result.items.len - 1] == '/';
result.items.len -= 1;
if (ends_with_slash or result.items.len == 0) break;
}
} else if (result.items.len > 0 or is_abs) {
try result.ensureUnusedCapacity(1 + component.len);
result.appendAssumeCapacity('/');
result.appendSliceAssumeCapacity(component);
} else {
try result.appendSlice(component);
}
}
}
if (result.items.len == 0) {
if (is_abs) {
return allocator.dupe(u8, "/");
}
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;
}
}