Skip to content

Instantly share code, notes, and snippets.

@bstaletic
Created August 4, 2020 10:20
Show Gist options
  • Save bstaletic/ba0afff792396ea438937948b2d80582 to your computer and use it in GitHub Desktop.
Save bstaletic/ba0afff792396ea438937948b2d80582 to your computer and use it in GitHub Desktop.
#if PY_VERSION_MAJOR >= 3
#define PYBIND11_ARGV_TYPE wchar_t**
#else
#define PYBIND11_ARGV_TYPE char**
#endif
struct wide_char_arg_deleter {
void operator()(void* ptr) const {
#if PY_VERSION_HEX >= 0x030500f0
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
PyMem_RawFree(ptr);
#else
delete ptr;
#endif
}
};
wchar_t* widen_chars(char* safe_arg) {
#if PY_VERSION_HEX >= 0x030500f0
wchar_t* widened_arg = Py_DecodeLocale(safe_arg, nullptr);
#elif HAVE_BROKEN_MBSTOWCS
size_t count = strlen(safe_arg);
widened_arg = nullptr;
if (count != static_cast<size_t>(-1)) {
widened_arg = new wchar_t[count + 1];
mbstowcs(widened_arg, safe_arg, count + 1);
}
#else
size_t count = mbstowcs(nullptr, safe_arg, 0);
widened_arg = nullptr;
if (count != static_cast<size_t>(-1)) {
widened_arg = new wchar_t[count + 1];
mbstowcs(widened_arg, safe_arg, count + 1);
}
#endif
return widened_arg;
}
inline void set_interpreter_argv(int argc, char** argv, bool add_current_dir_to_path) {
// Before it was special-cased in python 3.8, passing an empty or null argv
// caused a segfault, so we have to reimplement the special case ourselves.
char** safe_argv = argv;
std::unique_ptr<char*[]> argv_guard;
std::unique_ptr<char[]> argv_inner_guard;
if (nullptr == argv || argc <= 0) {
argv_guard = std::unique_ptr<char*[]>(safe_argv = new char*[1]);
argv_inner_guard = std::unique_ptr<char[]>(safe_argv[0] = new char[1]);
safe_argv[0][0] = '\0';
argc = 1;
}
#if PY_MAJOR_VERSION >= 3
size_t argv_size = static_cast<size_t>(argc);
// SetArgv* on python 3 takes wchar_t, so we have to convert.
std::vector< std::unique_ptr<wchar_t[], wide_char_arg_deleter> > widened_argv_entries;
for (size_t ii = 0; ii < argv_size; ++ii) {
widened_argv_entries.emplace_back(widen_chars(safe_argv[ii]));
if (widened_argv_entries.back()) {
// A null here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
return;
}
}
PYBIND11_ARGV_TYPE pysys_argv = widened_argv.get();
#else
PYBIND11_ARGV_TYPE pysys_argv = safe_argv;
#endif
PySys_SetArgv(argc, pysys_argv);
if (!add_current_dir_to_path)
PyList_PopItem(py::module::import("sys").attr("path").ptr(), 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment