From 56c765e944c1cb82b10809dd3dffe809b7ae4426 Mon Sep 17 00:00:00 2001 From: doylet Date: Tue, 21 Jul 2026 17:10:33 +1000 Subject: [PATCH] misc fixes --- Single-Header/dn_single_header.cpp | 43 +++++++++++++++++++++--------- Single-Header/dn_single_header.h | 2 +- Source/OS/dn_os_w32.cpp | 41 +++++++++++++++++++--------- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/Single-Header/dn_single_header.cpp b/Single-Header/dn_single_header.cpp index 3575df0..28d7bc5 100644 --- a/Single-Header/dn_single_header.cpp +++ b/Single-Header/dn_single_header.cpp @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-07-19 16:12:36 +// Generated by the DN single header generator 2026-07-19 17:56:21 // DN: Single header generator commented out => #if defined(_CLANGD) // #define DN_WITH_TESTS 1 @@ -15506,8 +15506,10 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs if (it.index) count_req += cmd_separator.count; - if (DN_Str8Find(*it.data, DN_Str8FindFlag_Whitespace).found) - count_req += 2; // If there's whitespace, we'll quote the string for the user + if (!DN_Str8StartsWithSensitive(*it.data, DN_Str8Lit("\""))) { + 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; } @@ -15522,8 +15524,11 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } // NOTE: Quote the string if needed - DN_Str8 str8 = *it.data; - bool needs_quotes = DN_Str8Find(str8, DN_Str8FindFlag_Whitespace).found; + DN_Str8 str8 = *it.data; + bool needs_quotes = false; + if (!DN_Str8StartsWithSensitive(*it.data, DN_Str8Lit("\""))) + needs_quotes = DN_Str8Find(str8, DN_Str8FindFlag_Whitespace).found; + if (needs_quotes) cmd.data[write_index++] = '\"'; @@ -15571,7 +15576,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs if (DN_BitIsSet(args.flags, DN_OSExecFlags_SaveStdout)) { if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) { DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); - result.os_error_code = win_error.code; + result.os_error_code = win_error.code; DN_ErrSinkAppendF( err, result.os_error_code, @@ -15640,14 +15645,23 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } } + // NOTE: Create a null stdin pipe so child gets EOF on read + // TODO: Eventually we should let the caller optionally write to stdin + HANDLE stdin_read = {}; + if (DN_BitIsSet(args.flags, DN_OSExecFlags_SaveStdout) || DN_BitIsSet(args.flags, DN_OSExecFlags_SaveStderr)) { + HANDLE stdin_write = {}; + if (CreatePipe(&stdin_read, &stdin_write, &save_std_security_attribs, 0)) + CloseHandle(stdin_write); + } + // NOTE: Execute command - PROCESS_INFORMATION proc_info = {}; - STARTUPINFOW startup_info = {}; - startup_info.cb = sizeof(STARTUPINFOW); - startup_info.hStdError = stderr_write ? stderr_write : GetStdHandle(STD_ERROR_HANDLE); - startup_info.hStdOutput = stdout_write ? stdout_write : GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup_info.dwFlags |= STARTF_USESTDHANDLES; + PROCESS_INFORMATION proc_info = {}; + STARTUPINFOW startup_info = {}; + startup_info.cb = sizeof(STARTUPINFOW); + startup_info.hStdError = stderr_write ? stderr_write : GetStdHandle(STD_ERROR_HANDLE); + startup_info.hStdOutput = stdout_write ? stdout_write : GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdInput = stdin_read ? stdin_read : GetStdHandle(STD_INPUT_HANDLE); + startup_info.dwFlags |= STARTF_USESTDHANDLES; BOOL create_result = CreateProcessW(nullptr, cmd16.data, nullptr, @@ -15658,6 +15672,9 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs working_dir16.data, &startup_info, &proc_info); + if (stdin_read) + CloseHandle(stdin_read); + if (!create_result) { DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code; diff --git a/Single-Header/dn_single_header.h b/Single-Header/dn_single_header.h index c3b6087..7a4489a 100644 --- a/Single-Header/dn_single_header.h +++ b/Single-Header/dn_single_header.h @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-07-19 16:12:36 +// Generated by the DN single header generator 2026-07-19 17:56:21 #if !defined(DN_H) #define DN_H diff --git a/Source/OS/dn_os_w32.cpp b/Source/OS/dn_os_w32.cpp index 5338207..24a7999 100644 --- a/Source/OS/dn_os_w32.cpp +++ b/Source/OS/dn_os_w32.cpp @@ -867,8 +867,10 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs if (it.index) count_req += cmd_separator.count; - if (DN_Str8Find(*it.data, DN_Str8FindFlag_Whitespace).found) - count_req += 2; // If there's whitespace, we'll quote the string for the user + if (!DN_Str8StartsWithSensitive(*it.data, DN_Str8Lit("\""))) { + 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; } @@ -883,8 +885,11 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } // NOTE: Quote the string if needed - DN_Str8 str8 = *it.data; - bool needs_quotes = DN_Str8Find(str8, DN_Str8FindFlag_Whitespace).found; + DN_Str8 str8 = *it.data; + bool needs_quotes = false; + if (!DN_Str8StartsWithSensitive(*it.data, DN_Str8Lit("\""))) + needs_quotes = DN_Str8Find(str8, DN_Str8FindFlag_Whitespace).found; + if (needs_quotes) cmd.data[write_index++] = '\"'; @@ -932,7 +937,7 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs if (DN_BitIsSet(args.flags, DN_OSExecFlags_SaveStdout)) { if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) { DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); - result.os_error_code = win_error.code; + result.os_error_code = win_error.code; DN_ErrSinkAppendF( err, result.os_error_code, @@ -1001,14 +1006,23 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs } } + // NOTE: Create a null stdin pipe so child gets EOF on read + // TODO: Eventually we should let the caller optionally write to stdin + HANDLE stdin_read = {}; + if (DN_BitIsSet(args.flags, DN_OSExecFlags_SaveStdout) || DN_BitIsSet(args.flags, DN_OSExecFlags_SaveStderr)) { + HANDLE stdin_write = {}; + if (CreatePipe(&stdin_read, &stdin_write, &save_std_security_attribs, 0)) + CloseHandle(stdin_write); + } + // NOTE: Execute command - PROCESS_INFORMATION proc_info = {}; - STARTUPINFOW startup_info = {}; - startup_info.cb = sizeof(STARTUPINFOW); - startup_info.hStdError = stderr_write ? stderr_write : GetStdHandle(STD_ERROR_HANDLE); - startup_info.hStdOutput = stdout_write ? stdout_write : GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup_info.dwFlags |= STARTF_USESTDHANDLES; + PROCESS_INFORMATION proc_info = {}; + STARTUPINFOW startup_info = {}; + startup_info.cb = sizeof(STARTUPINFOW); + startup_info.hStdError = stderr_write ? stderr_write : GetStdHandle(STD_ERROR_HANDLE); + startup_info.hStdOutput = stdout_write ? stdout_write : GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdInput = stdin_read ? stdin_read : GetStdHandle(STD_INPUT_HANDLE); + startup_info.dwFlags |= STARTF_USESTDHANDLES; BOOL create_result = CreateProcessW(nullptr, cmd16.data, nullptr, @@ -1019,6 +1033,9 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs working_dir16.data, &startup_info, &proc_info); + if (stdin_read) + CloseHandle(stdin_read); + if (!create_result) { DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); result.os_error_code = win_error.code;