From 4b618f9ad1a45f6819dcb65e9b6b5b859e0df9fd Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 14 Oct 2021 05:22:47 -0700 Subject: `bun create react app` is almost done --- src/which.zig | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/which.zig (limited to 'src/which.zig') diff --git a/src/which.zig b/src/which.zig new file mode 100644 index 000000000..7cb65cbe2 --- /dev/null +++ b/src/which.zig @@ -0,0 +1,40 @@ +const std = @import("std"); + +fn isValid(buf: *[std.fs.MAX_PATH_BYTES]u8, segment: []const u8, bin: []const u8) ?u16 { + std.mem.copy(u8, buf, segment); + buf[segment.len] = std.fs.path.sep; + std.mem.copy(u8, buf[segment.len + 1 ..], bin); + buf[segment.len + 1 + bin.len ..][0] = 0; + var filepath = buf[0 .. segment.len + 1 + bin.len :0]; + + std.os.accessZ(filepath, std.os.X_OK) catch return null; + return @intCast(u16, filepath.len); +} + +// Like /usr/bin/which but without needing to exec a child process +// Remember to resolve the symlink if necessary +pub fn which(buf: *[std.fs.MAX_PATH_BYTES]u8, path: []const u8, cwd: []const u8, bin: []const u8) ?[:0]const u8 { + if (isValid(buf, std.mem.trimRight(u8, cwd, std.fs.path.sep_str), bin)) |len| { + return buf[0..len :0]; + } + + var path_iter = std.mem.tokenize(u8, path, ":"); + while (path_iter.next()) |segment| { + if (isValid(buf, segment, bin)) |len| { + return buf[0..len :0]; + } + } + + return null; +} + +test "which" { + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var realpath = std.os.getenv("PATH") orelse unreachable; + var whichbin = which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "which"); + try std.testing.expectEqualStrings(whichbin orelse return std.debug.assert(false), "/usr/bin/which"); + try std.testing.expect(null == which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "baconnnnnn")); + try std.testing.expect(null != which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "zig")); + try std.testing.expect(null == which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "bin")); + try std.testing.expect(null == which(&buf, realpath, try std.process.getCwdAlloc(std.heap.c_allocator), "usr")); +} -- cgit v1.2.3