Skip to content

Commit e918218

Browse files
committed
stdlib: make CommandLine inspection work
This implements commandline access on Windows by using the Windows Shell API to access the commandline information and making it available in Swift. This is needed for the correct invocation of the child process in the unit tests.
1 parent 69f6ae5 commit e918218

File tree

1 file changed

+53
-2
lines changed

1 file changed

+53
-2
lines changed

stdlib/public/stubs/CommandLine.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
#include "../SwiftShims/RuntimeStubs.h"
3030
#include "../SwiftShims/GlobalObjects.h"
3131

32+
#if defined(_WIN32)
33+
#define WIN32_LEAN_AND_MEAN
34+
#include <Windows.h>
35+
#include <shellapi.h>
36+
#endif
37+
3238
// Backing storage for overrides of `Swift.CommandLine.arguments`.
3339
static char **_swift_stdlib_ProcessOverrideUnsafeArgv = nullptr;
3440
static int _swift_stdlib_ProcessOverrideUnsafeArgc = 0;
@@ -101,8 +107,53 @@ char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) {
101107
return _swift_stdlib_ProcessOverrideUnsafeArgv;
102108
}
103109

104-
*outArgLen = __argc;
105-
return __argv;
110+
*outArgLen = 0;
111+
112+
113+
LPWSTR *szArgList;
114+
int nArgs;
115+
szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);
116+
if (szArgList == nullptr)
117+
return nullptr;
118+
119+
std::vector<char *> argv;
120+
for (int i = 0; i < nArgs; ++i) {
121+
int szBufferSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
122+
szArgList[i], -1, nullptr, 0,
123+
nullptr, nullptr);
124+
if (szBufferSize == 0) {
125+
for (char *arg : argv)
126+
free(arg);
127+
return nullptr;
128+
}
129+
130+
char *buffer = static_cast<char *>(calloc(static_cast<size_t>(szBufferSize),
131+
sizeof(char)));
132+
if (buffer == nullptr) {
133+
for (char *arg : argv)
134+
free(arg);
135+
return nullptr;
136+
}
137+
138+
if (!WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, szArgList[i], -1,
139+
buffer, szBufferSize, nullptr, nullptr)) {
140+
for (char *arg : argv)
141+
free(arg);
142+
return nullptr;
143+
}
144+
145+
argv.push_back(buffer);
146+
}
147+
148+
LocalFree(szArgList);
149+
150+
char **args = static_cast<char **>(calloc(argv.size() + 1, sizeof(char *)));
151+
std::copy(argv.begin(), argv.end(), args);
152+
args[argv.size()] = nullptr;
153+
154+
assert(argv.size() < INT_MAX && "overflow");
155+
*outArgLen = static_cast<int>(argv.size());
156+
return args;
106157
}
107158
#elif defined(__FreeBSD__)
108159
#include <errno.h>

0 commit comments

Comments
 (0)