Files
swift-mirror/stdlib/public/stubs/CommandLine.cpp
Saleem Abdulrasool e918218b4c 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.
2018-12-16 14:04:38 -08:00

222 lines
6.4 KiB
C++

//===--- CommandLine.cpp - OS-specific command line arguments -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// OS-specific command line argument handling is defined here.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include <string>
#include <cassert>
#include <climits>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "swift/Runtime/Debug.h"
#include "../SwiftShims/RuntimeStubs.h"
#include "../SwiftShims/GlobalObjects.h"
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>
#endif
// Backing storage for overrides of `Swift.CommandLine.arguments`.
static char **_swift_stdlib_ProcessOverrideUnsafeArgv = nullptr;
static int _swift_stdlib_ProcessOverrideUnsafeArgc = 0;
SWIFT_RUNTIME_STDLIB_API
void _swift_stdlib_overrideUnsafeArgvArgc(char **argv, int argc) {
_swift_stdlib_ProcessOverrideUnsafeArgv = argv;
_swift_stdlib_ProcessOverrideUnsafeArgc = argc;
}
#if defined(__APPLE__)
// NOTE: forward declare this rather than including crt_externs.h as not all
// SDKs provide it
extern "C" char ***_NSGetArgv(void);
extern "C" int *_NSGetArgc(void);
SWIFT_RUNTIME_STDLIB_API
char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) {
assert(outArgLen != nullptr);
if (_swift_stdlib_ProcessOverrideUnsafeArgv) {
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc;
return _swift_stdlib_ProcessOverrideUnsafeArgv;
}
*outArgLen = *_NSGetArgc();
return *_NSGetArgv();
}
#elif defined(__linux__) || defined(__CYGWIN__)
SWIFT_RUNTIME_STDLIB_API
char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) {
assert(outArgLen != nullptr);
if (_swift_stdlib_ProcessOverrideUnsafeArgv) {
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc;
return _swift_stdlib_ProcessOverrideUnsafeArgv;
}
FILE *cmdline = fopen("/proc/self/cmdline", "rb");
if (!cmdline) {
swift::fatalError(0,
"Fatal error: Unable to open interface to '/proc/self/cmdline'.\n");
}
char *arg = nullptr;
size_t size = 0;
std::vector<char *> argvec;
while (getdelim(&arg, &size, 0, cmdline) != -1) {
argvec.push_back(strdup(arg));
}
if (arg) {
free(arg);
}
fclose(cmdline);
*outArgLen = argvec.size();
char **outBuf = (char **)calloc(argvec.size() + 1, sizeof(char *));
std::copy(argvec.begin(), argvec.end(), outBuf);
outBuf[argvec.size()] = nullptr;
return outBuf;
}
#elif defined (_WIN32)
#include <stdlib.h>
SWIFT_RUNTIME_STDLIB_API
char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) {
assert(outArgLen != nullptr);
if (_swift_stdlib_ProcessOverrideUnsafeArgv) {
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc;
return _swift_stdlib_ProcessOverrideUnsafeArgv;
}
*outArgLen = 0;
LPWSTR *szArgList;
int nArgs;
szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if (szArgList == nullptr)
return nullptr;
std::vector<char *> argv;
for (int i = 0; i < nArgs; ++i) {
int szBufferSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
szArgList[i], -1, nullptr, 0,
nullptr, nullptr);
if (szBufferSize == 0) {
for (char *arg : argv)
free(arg);
return nullptr;
}
char *buffer = static_cast<char *>(calloc(static_cast<size_t>(szBufferSize),
sizeof(char)));
if (buffer == nullptr) {
for (char *arg : argv)
free(arg);
return nullptr;
}
if (!WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, szArgList[i], -1,
buffer, szBufferSize, nullptr, nullptr)) {
for (char *arg : argv)
free(arg);
return nullptr;
}
argv.push_back(buffer);
}
LocalFree(szArgList);
char **args = static_cast<char **>(calloc(argv.size() + 1, sizeof(char *)));
std::copy(argv.begin(), argv.end(), args);
args[argv.size()] = nullptr;
assert(argv.size() < INT_MAX && "overflow");
*outArgLen = static_cast<int>(argv.size());
return args;
}
#elif defined(__FreeBSD__)
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
SWIFT_RUNTIME_STDLIB_API
char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) {
assert(outArgLen != nullptr);
if (_swift_stdlib_ProcessOverrideUnsafeArgv) {
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc;
return _swift_stdlib_ProcessOverrideUnsafeArgv;
}
char *argPtr = nullptr; // or use ARG_MAX? 8192 is used in LLDB though..
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid() };
size_t argPtrSize = 0;
for (int i = 0; i < 3 && !argPtr; i++) { // give up after 3 tries
if (sysctl(mib, 4, nullptr, &argPtrSize, nullptr, 0) != -1) {
argPtr = (char *)malloc(argPtrSize);
if (sysctl(mib, 4, argPtr, &argPtrSize, nullptr, 0) == -1) {
free(argPtr);
argPtr = nullptr;
if (errno != ENOMEM)
break;
}
} else {
break;
}
}
if (!argPtr)
swift::fatalError(0, "Fatal error: Could not retrieve commandline "
"arguments: sysctl: %s.\n", strerror(errno));
char *curPtr = argPtr;
char *endPtr = argPtr + argPtrSize;
std::vector<char *> argvec;
for (; curPtr < endPtr; curPtr += strlen(curPtr) + 1)
argvec.push_back(strdup(curPtr));
*outArgLen = argvec.size();
char **outBuf = (char **)calloc(argvec.size() + 1, sizeof(char *));
std::copy(argvec.begin(), argvec.end(), outBuf);
outBuf[argvec.size()] = nullptr;
free(argPtr);
return outBuf;
}
#else // __ANDROID__; Add your favorite arch's command line arg grabber here.
SWIFT_RUNTIME_STDLIB_API
char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) {
if (_swift_stdlib_ProcessOverrideUnsafeArgv) {
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc;
return _swift_stdlib_ProcessOverrideUnsafeArgv;
}
swift::fatalError(0,
"Fatal error: Command line arguments not supported on this platform.\n");
}
#endif