Fix DN_OSExec not quoting CLI args on Windows
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Generated by the DN single header generator 2026-07-15 22:47:49
|
||||
// Generated by the DN single header generator 2026-07-16 14:16:33
|
||||
|
||||
// DN: Single header generator commented out => #if defined(_CLANGD)
|
||||
// #define DN_WITH_TESTS 1
|
||||
@@ -15440,12 +15440,54 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
if (cmd_line.count == 0)
|
||||
return result;
|
||||
|
||||
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
|
||||
DN_Str8 cmd_rendered = DN_Str8SliceRender(cmd_line, DN_Str8Lit(" "), &scratch.arena);
|
||||
DN_Str16 cmd16 = DN_OS_W32Str8ToStr16(&scratch.arena, cmd_rendered);
|
||||
DN_Str16 working_dir16 = DN_OS_W32Str8ToStr16(&scratch.arena, args->working_dir);
|
||||
// NOTE: Render the command line into single string to pass into the Win32 API. We'll quote the
|
||||
// string on behalf of the user if there's whitespace in the string
|
||||
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
|
||||
DN_Str8 cmd = {};
|
||||
{
|
||||
DN_USize count_req = 0;
|
||||
DN_Str8 cmd_separator = DN_Str8Lit(" ");
|
||||
for (DN_ForIt(it, DN_Str8, &cmd_line)) {
|
||||
if (it.index)
|
||||
count_req += cmd_separator.count;
|
||||
|
||||
DN_Str8Builder env_builder = DN_Str8BuilderFromArena(&scratch.arena);
|
||||
if (DN_Str8Find(*it.data, DN_Str8FindFlag_Whitespace).found)
|
||||
count_req += 2; // If there's whitespace, we'll quote the string for the user
|
||||
count_req += it.data->count;
|
||||
}
|
||||
|
||||
// NOTE: Build the string
|
||||
cmd = DN_Str8AllocArena(count_req, DN_ZMem_No, &scratch.arena);
|
||||
if (cmd.data) {
|
||||
DN_USize write_index = 0;
|
||||
for (DN_ForIt(it, DN_Str8, &cmd_line)) {
|
||||
if (it.index) {
|
||||
DN_Memcpy(cmd.data + write_index, cmd_separator.data, cmd_separator.count);
|
||||
write_index += cmd_separator.count;
|
||||
}
|
||||
|
||||
// NOTE: Quote the string if needed
|
||||
DN_Str8 str8 = *it.data;
|
||||
bool needs_quotes = DN_Str8Find(str8, DN_Str8FindFlag_Whitespace).found;
|
||||
if (needs_quotes)
|
||||
cmd.data[write_index++] = '\"';
|
||||
|
||||
// NOTE: Write contents
|
||||
DN_Memcpy(cmd.data + write_index, str8.data, str8.count);
|
||||
write_index += str8.count;
|
||||
|
||||
// NOTE: Close quote if needed
|
||||
if (needs_quotes)
|
||||
cmd.data[write_index++] = '\"';
|
||||
}
|
||||
DN_Assert(write_index == cmd.count);
|
||||
}
|
||||
}
|
||||
DN_AssertF(cmd.count < DN_Kilobytes(32), "Command exceeds the allowable size in Win32");
|
||||
|
||||
DN_Str16 cmd16 = DN_OS_W32Str8ToStr16(&scratch.arena, cmd);
|
||||
DN_Str16 working_dir16 = DN_OS_W32Str8ToStr16(&scratch.arena, args->working_dir);
|
||||
DN_Str8Builder env_builder = DN_Str8BuilderFromArena(&scratch.arena);
|
||||
DN_Str8BuilderAppendArrayRef(&env_builder, args->environment.data, args->environment.count);
|
||||
if (env_builder.string_size)
|
||||
DN_Str8BuilderAppendRef(&env_builder, DN_Str8Lit("\0"));
|
||||
@@ -15479,7 +15521,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
err,
|
||||
result.os_error_code,
|
||||
"Failed to create stdout pipe to redirect the output of the command '%.*s': %.*s",
|
||||
DN_Str8PrintFmt(cmd_rendered),
|
||||
DN_Str8PrintFmt(cmd),
|
||||
DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
@@ -15492,14 +15534,14 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
result.os_error_code,
|
||||
"Failed to make stdout 'read' pipe non-inheritable when trying to "
|
||||
"execute command '%.*s': %.*s",
|
||||
DN_Str8PrintFmt(cmd_rendered),
|
||||
DN_Str8PrintFmt(cmd),
|
||||
DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Redirect stderr ///////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Redirect stderr
|
||||
HANDLE stderr_read = {};
|
||||
HANDLE stderr_write = {};
|
||||
DN_DEFER
|
||||
@@ -15522,7 +15564,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
err,
|
||||
result.os_error_code,
|
||||
"Failed to create stderr pipe to redirect the output of the command '%.*s': %.*s",
|
||||
DN_Str8PrintFmt(cmd_rendered),
|
||||
DN_Str8PrintFmt(cmd),
|
||||
DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
@@ -15532,11 +15574,11 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
DN_ErrSinkAppendF(err,
|
||||
result.os_error_code,
|
||||
"Failed to make stderr 'read' pipe non-inheritable when trying to "
|
||||
"execute command '%.*s': %.*s",
|
||||
DN_Str8PrintFmt(cmd_rendered),
|
||||
DN_Str8PrintFmt(win_error.msg));
|
||||
result.os_error_code,
|
||||
"Failed to make stderr 'read' pipe non-inheritable when trying to "
|
||||
"execute command '%.*s': %.*s",
|
||||
DN_Str8PrintFmt(cmd),
|
||||
DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -15564,7 +15606,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
if (!create_result) {
|
||||
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
DN_ErrSinkAppendF(err, result.os_error_code, "Failed to execute command '%.*s': %.*s", DN_Str8PrintFmt(cmd_rendered), DN_Str8PrintFmt(win_error.msg));
|
||||
DN_ErrSinkAppendF(err, result.os_error_code, "Failed to execute command '%.*s': %.*s", DN_Str8PrintFmt(cmd), DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user