mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-31 19:28:55 +00:00
Merge pull request #7162 from BunterSchatten/fix-windows-run-spaces
handle spaces in args for 'odin run . -- <args>' on Windows
This commit is contained in:
@@ -640,7 +640,7 @@ gb_internal gb_inline f64 gb_sqrt(f64 x) {
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
|
||||
gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc, isize *_double_dash_pos, wchar_t **_after_double_dash_raw) {
|
||||
u32 i, j;
|
||||
|
||||
u32 len = cast(u32)string16_len(cast(u16 *)cmd_line);
|
||||
@@ -649,6 +649,9 @@ gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t));
|
||||
wchar_t *_argv = cast(wchar_t *)((cast(u8 *)argv)+i);
|
||||
|
||||
wchar_t *after_double_dash_raw = nullptr;
|
||||
isize double_dash_pos = -1;
|
||||
|
||||
u32 argc = 0;
|
||||
argv[argc] = _argv;
|
||||
bool in_quote = false;
|
||||
@@ -657,6 +660,18 @@ gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
auto const check_double_dash = [&]() {
|
||||
if (double_dash_pos == -1 &&
|
||||
argc >= 1 &&
|
||||
argv[argc - 1][0] == '-' &&
|
||||
argv[argc - 1][1] == '-' &&
|
||||
argv[argc - 1][2] == '\0') {
|
||||
|
||||
double_dash_pos = argc - 1;
|
||||
after_double_dash_raw = cmd_line + i;
|
||||
}
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
wchar_t a = cmd_line[i];
|
||||
if (a == 0) {
|
||||
@@ -673,7 +688,10 @@ gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
case '\"':
|
||||
in_quote = true;
|
||||
in_text = true;
|
||||
if (in_space) argv[argc++] = _argv+j;
|
||||
if (in_space) {
|
||||
check_double_dash();
|
||||
argv[argc++] = _argv + j;
|
||||
}
|
||||
in_space = false;
|
||||
break;
|
||||
case ' ':
|
||||
@@ -686,7 +704,10 @@ gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
break;
|
||||
default:
|
||||
in_text = true;
|
||||
if (in_space) argv[argc++] = _argv+j;
|
||||
if (in_space) {
|
||||
check_double_dash();
|
||||
argv[argc++] = _argv + j;
|
||||
}
|
||||
_argv[j++] = a;
|
||||
in_space = false;
|
||||
break;
|
||||
@@ -696,8 +717,11 @@ gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
}
|
||||
_argv[j] = '\0';
|
||||
argv[argc] = nullptr;
|
||||
check_double_dash();
|
||||
|
||||
if (_argc) *_argc = argc;
|
||||
if (_double_dash_pos) *_double_dash_pos = double_dash_pos;
|
||||
if (_after_double_dash_raw) *_after_double_dash_raw = after_double_dash_raw;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
95
src/main.cpp
95
src/main.cpp
@@ -178,17 +178,63 @@ gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt,
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#include <process.h>
|
||||
#else
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
#include <spawn.h>
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
int run_subprocess(const char *name, const char **args) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
return (int)_spawnv(_P_WAIT, name, args);
|
||||
int run_subprocess(String const &exe_name, wchar_t *after_double_dash_raw) {
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
String16 wexe_name = string_to_string16(a, exe_name);
|
||||
defer (gb_free(a, wexe_name.text));
|
||||
|
||||
isize args_len = 0;
|
||||
if (after_double_dash_raw) {
|
||||
args_len = string16_len(cast(u16 *)after_double_dash_raw);
|
||||
}
|
||||
|
||||
isize cmd_len = wexe_name.len + 2;
|
||||
if (args_len > 0) cmd_len += args_len + 1;
|
||||
|
||||
wchar_t *cmd_line = gb_alloc_array(a, wchar_t, cmd_len + 1);
|
||||
defer (gb_free(a, cmd_line));
|
||||
|
||||
isize n = 0;
|
||||
cmd_line[n++] = '"';
|
||||
gb_memmove(cmd_line + n, wexe_name.text, wexe_name.len * gb_size_of(wchar_t));
|
||||
n += wexe_name.len;
|
||||
cmd_line[n++] = '"';
|
||||
if (args_len > 0) {
|
||||
cmd_line[n++] = ' ';
|
||||
gb_memmove(cmd_line + n, after_double_dash_raw, args_len * gb_size_of(wchar_t));
|
||||
n += args_len;
|
||||
}
|
||||
cmd_line[n] = '\0';
|
||||
|
||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
int exit_code = 0;
|
||||
|
||||
if (CreateProcessW(nullptr, cmd_line,
|
||||
nullptr, nullptr, true, 0, nullptr, nullptr,
|
||||
&start_info, &pi)) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
} else {
|
||||
String cmd_line_utf8 = string16_to_string(a, make_string16(cast(u16 *)cmd_line, n));
|
||||
gb_printf_err("Failed to execute command:\n\t%.*s\n", LIT(cmd_line_utf8));
|
||||
gb_free(a, cmd_line_utf8.text);
|
||||
exit_code = -1;
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
#else
|
||||
int run_subprocess(const char *name, const char **args) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
status = posix_spawn(&pid, name, NULL, NULL, (char *const *)args, environ);
|
||||
@@ -215,8 +261,8 @@ int run_subprocess(const char *name, const char **args) {
|
||||
}
|
||||
}
|
||||
GB_PANIC("Subprocess failure");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#define popen _popen
|
||||
@@ -250,12 +296,12 @@ gb_internal bool system_exec_command_line_app_output(char const *command, gbStri
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal Array<String> setup_args(int argc, char const **argv) {
|
||||
gb_internal Array<String> setup_args(int argc, char const **argv, isize *double_dash_pos, wchar_t **after_double_dash_raw) {
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
int wargc = 0;
|
||||
wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc);
|
||||
wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc, double_dash_pos, after_double_dash_raw);
|
||||
auto args = array_make<String>(a, 0, wargc);
|
||||
for (isize i = 0; i < wargc; i++) {
|
||||
u16 *warg = cast(u16 *)wargv[i];
|
||||
@@ -264,6 +310,8 @@ gb_internal Array<String> setup_args(int argc, char const **argv) {
|
||||
String arg = string16_to_string(a, wstr);
|
||||
if (arg.len > 0) {
|
||||
array_add(&args, arg);
|
||||
} else if (double_dash_pos && *double_dash_pos > 0 && args.count < *double_dash_pos) {
|
||||
*double_dash_pos -= 1;
|
||||
}
|
||||
}
|
||||
return args;
|
||||
@@ -3757,17 +3805,23 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
|
||||
init_build_context_error_pos_style();
|
||||
|
||||
Array<String> args = setup_args(arg_count, arg_ptr);
|
||||
isize double_dash_pos = -1;
|
||||
wchar_t *after_double_dash_raw = nullptr;
|
||||
Array<String> args = setup_args(arg_count, arg_ptr, &double_dash_pos, &after_double_dash_raw);
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
|
||||
defer (array_free(&run_args));
|
||||
#endif
|
||||
|
||||
String command = args[1];
|
||||
String init_filename = {};
|
||||
isize last_non_run_arg = args.count;
|
||||
|
||||
isize double_dash_pos = -1;
|
||||
for_array(i, args) {
|
||||
if (args[i] == "--") {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
GB_ASSERT(double_dash_pos == i);
|
||||
#endif
|
||||
double_dash_pos = i;
|
||||
break;
|
||||
}
|
||||
@@ -3811,25 +3865,20 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
build_context.command_kind = Command_test;
|
||||
}
|
||||
|
||||
isize run_args_start_idx = -1;
|
||||
for_array(i, args) {
|
||||
if (args[i] == "--") {
|
||||
run_args_start_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (run_args_start_idx != -1) {
|
||||
last_non_run_arg = run_args_start_idx;
|
||||
if (double_dash_pos != -1) {
|
||||
last_non_run_arg = double_dash_pos;
|
||||
|
||||
if (run_args_start_idx == 2) {
|
||||
if (double_dash_pos == 2) {
|
||||
// missing src path on argv[2], invocation: odin [run|test] --
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(isize i = run_args_start_idx+1; i < args.count; ++i) {
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
for(isize i = double_dash_pos+1; i < args.count; ++i) {
|
||||
array_add(&run_args, args[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
args = array_slice(args, 0, last_non_run_arg);
|
||||
|
||||
@@ -4422,6 +4471,9 @@ end_of_code_gen:;
|
||||
String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]);
|
||||
defer (gb_free(heap_allocator(), exe_name.text));
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
int subprocess_res = run_subprocess(exe_name, after_double_dash_raw);
|
||||
#else
|
||||
const char* exe_name_cstring = alloc_cstring(heap_allocator(), exe_name);
|
||||
Array<const char *> run_args_cstring = array_make<const char *>(heap_allocator(), 0, run_args.count);
|
||||
defer({
|
||||
@@ -4436,6 +4488,7 @@ end_of_code_gen:;
|
||||
array_add(&run_args_cstring, NULL);
|
||||
|
||||
int subprocess_res = run_subprocess(exe_name_cstring, run_args_cstring.data);
|
||||
#endif
|
||||
if (subprocess_res) {
|
||||
gb_exit(subprocess_res);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user