#include #include #include #include // Loosely according to https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ int argvQuote(wchar_t *in, wchar_t *out) { int ipos; int opos; int bs_count; int c; ipos = 0; opos = 0; if (!wcschr(in, L' ') && !wcschr(in, L'"') && !wcschr(in, L'\\t') && !wcschr(in, L'\\n') && !wcschr(in, L'\\v')) { if (out) wcscpy(out, in); return wcslen(in) + 1; } if (out) out[opos] = L'"'; opos++; while (in[ipos] != 0) { bs_count = 0; while (in[ipos] != 0 && in[ipos] == L'\\\\') { ipos++; bs_count++; } if (in[ipos] == 0) { for (c = 0; c < (bs_count * 2); c++) { if (out) out[opos] = L'\\\\'; opos++; } break; } else if (in[ipos] == L'"') { for (c = 0; c < (bs_count * 2 + 1); c++) { if (out) out[opos] = L'\\\\'; opos++; } if (out) out[opos] = in[ipos]; opos++; } else { for (c = 0; c < bs_count; c++) { if (out) out[opos] = L'\\\\'; opos++; } if (out) out[opos] = in[ipos]; opos++; } ipos++; } if (out) out[opos] = L'"'; opos++; if (out) out[opos] = 0; opos++; return opos; } int wmain(int argc, wchar_t *argv[]) { int moar_argc; int exec_argc; int c; wchar_t **exec_argv; size_t arg_size; wchar_t *moar; size_t cmd_line_size; wchar_t *cmd_line; DWORD exit_code; BOOL success; STARTUPINFOW si; PROCESS_INFORMATION pi; moar_argc = 6; // moar args + passed args (without program name) + NULL pointer exec_argc = moar_argc + (argc - 1) + 1; exec_argv = malloc(exec_argc * sizeof(void*)); // Set up moar args. exec_argv[0] = L"@c_escape(@nfp(@MOAR@)@)@"; exec_argv[1] = L"--execname=@c_escape(@nfp(@exec_name@)@)@"; exec_argv[2] = L"--libpath=@c_escape(@nfp(@base_dir@)@)@"; exec_argv[3] = L"--libpath=@c_escape(@nfp(@base_dir@/blib)@)@"; exec_argv[4] = L"--libpath=@c_escape(@nfp(@nqp_lib_dir@)@)@"; exec_argv[5] = L"@c_escape(@nfp(@base_dir@/@mbc@)@)@"; // Copy passed args. for (c = 0; c < argc - 1; c++) { exec_argv[moar_argc + c] = argv[c + 1]; } exec_argv[exec_argc - 1] = NULL; // Encode program name arg_size = argvQuote(exec_argv[0], NULL); moar = malloc(arg_size * sizeof(wchar_t)); argvQuote(exec_argv[0], moar); // Size of the final command line string. // cmd_line_size = size of each argument + one space each - the last space + the trailing \0 cmd_line_size = 0; cmd_line = NULL; for (c = 0; c < exec_argc - 1; c++) { // argvQuote leaves space for a trailing \0 arg_size = argvQuote(exec_argv[c], NULL); cmd_line = realloc(cmd_line, (cmd_line_size + arg_size) * sizeof(wchar_t)); argvQuote(exec_argv[c], cmd_line + cmd_line_size); cmd_line_size += arg_size; cmd_line[cmd_line_size - 1] = L' '; } cmd_line[cmd_line_size - 1] = 0; _wputenv_s(L"NQP_HOME", L"@c_escape(@nfp(@nqp_home@)@)@"); // Hack: Explicitly set a dummy RAKUDO_HOME, so the autogenerated CompUnitRepo // folder structure does not end up in the build directories parent folder. _wputenv_s(L"RAKUDO_HOME", L"@c_escape(@nfp(@base_dir@/gen/build_rakudo_home)@)@"); // Execute the command and wait for it to finish. ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); success = CreateProcessW( moar, // ApplicationName cmd_line, // CommandLine NULL, // ProcessAttributes NULL, // ThreadAttributes FALSE, // InheritHandles 0, // CreationFlags NULL, // Environment NULL, // CurrentDirectory &si, // StartupInfo &pi); // ProcessInformation if (!success) { fprintf(stderr, "ERROR: Failed to execute moar. Error code: %ld\n", GetLastError()); return EXIT_FAILURE; } // I guess processes only signal when they are done. So no need to check the return value. WaitForSingleObject(pi.hProcess, INFINITE); success = GetExitCodeProcess(pi.hProcess, &exit_code); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (!success) { fprintf(stderr, "Couldn't retrieve exit code. Error code: %ld\n", GetLastError()); return EXIT_FAILURE; } return exit_code; }