aboutsummaryrefslogtreecommitdiff
path: root/src/which.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-14 05:22:47 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-14 05:22:47 -0700
commit4b618f9ad1a45f6819dcb65e9b6b5b859e0df9fd (patch)
tree9bc3aac20a9ab2863be3409c6cffb9983d165b84 /src/which.zig
parent0f7bc76f39b6792052be799779e8d10ee03c564c (diff)
downloadbun-4b618f9ad1a45f6819dcb65e9b6b5b859e0df9fd.tar.gz
bun-4b618f9ad1a45f6819dcb65e9b6b5b859e0df9fd.tar.zst
bun-4b618f9ad1a45f6819dcb65e9b6b5b859e0df9fd.zip
`bun create react app` is almost done
Diffstat (limited to 'src/which.zig')
-rw-r--r--src/which.zig40
1 files changed, 40 insertions, 0 deletions
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"));
+}