const WindowsCommandLineCache = struct cmd_line: ?[:0]u16 = nullscript_cmd_line: ?[:0]u16 = nullcmd_exe_path: ?[:0]u16 = nullargv: []const []const u8allocator: Allocatorfn init(allocator: Allocator, argv: []const []const u8) WindowsCommandLineCachefn deinit(self: *WindowsCommandLineCache) voidfn commandLine(self: *WindowsCommandLineCache) ![: 0]u16fn scriptCommandLine(self: *WindowsCommandLineCache, script_path: []const u16) ![: 0]u16Not cached, since the path to the batch script will change during PATH searching. script_path should be as qualified as possible, e.g. if the PATH is being searched, then script_path should include both the search path and the script filename (this allows avoiding cmd.exe having to search the PATH again).
fn cmdExePath(self: *WindowsCommandLineCache) Allocator.Error![: 0]u1616671
16672
16673
16674
16675
16676
16677
16678
16679
16680
16681
16682
16683
16684
16685
16686
16687
16688
16689
16690
16691
16692
16693
16694
16695
16696
16697
16698
16699
16700
16701
16702
16703
16704
16705
16706
16707
16708
16709
16710
16711
16712
16713
16714
16715
16716
16717
16718
16719
16720
16721
16722
16723
16724
16725const WindowsCommandLineCache = struct {
cmd_line: ?[:0]u16 = null,
script_cmd_line: ?[:0]u16 = null,
cmd_exe_path: ?[:0]u16 = null,
argv: []const []const u8,
allocator: Allocator,
fn init(allocator: Allocator, argv: []const []const u8) WindowsCommandLineCache {
return .{
.allocator = allocator,
.argv = argv,
};
}
fn deinit(self: *WindowsCommandLineCache) void {
if (self.cmd_line) |cmd_line| self.allocator.free(cmd_line);
if (self.script_cmd_line) |script_cmd_line| self.allocator.free(script_cmd_line);
if (self.cmd_exe_path) |cmd_exe_path| self.allocator.free(cmd_exe_path);
}
fn commandLine(self: *WindowsCommandLineCache) ![:0]u16 {
if (self.cmd_line == null) {
self.cmd_line = try argvToCommandLineWindows(self.allocator, self.argv);
}
return self.cmd_line.?;
}
/// Not cached, since the path to the batch script will change during PATH searching.
/// `script_path` should be as qualified as possible, e.g. if the PATH is being searched,
/// then script_path should include both the search path and the script filename
/// (this allows avoiding cmd.exe having to search the PATH again).
fn scriptCommandLine(self: *WindowsCommandLineCache, script_path: []const u16) ![:0]u16 {
if (self.script_cmd_line) |v| self.allocator.free(v);
self.script_cmd_line = try argvToScriptCommandLineWindows(
self.allocator,
script_path,
self.argv[1..],
);
return self.script_cmd_line.?;
}
fn cmdExePath(self: *WindowsCommandLineCache) Allocator.Error![:0]u16 {
if (self.cmd_exe_path == null) {
// Remove trailing slash from system directory path; we'll re-add it below
const system_dir = std.mem.trimEnd(u16, windows.getSystemDirectoryWtf16Le(), &.{ '/', '\\' });
const suffix = std.unicode.utf8ToUtf16LeStringLiteral("\\cmd.exe");
const buf = try self.allocator.allocSentinel(u16, system_dir.len + suffix.len, 0);
errdefer comptime unreachable;
@memcpy(buf[0..system_dir.len], system_dir);
@memcpy(buf[system_dir.len..], suffix);
self.cmd_exe_path = buf;
}
return self.cmd_exe_path.?;
}
}
Serializes argv into a WTF-16 encoded command-line string for use with CreateProcessW.
Serialization is done on-demand and the result is cached in order to allow for:
.bat/.cmdcommand line serialization is different from.exe/etc)