aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Modules/getpath.c
diff options
context:
space:
mode:
authornkozlovskiy <nmk@ydb.tech>2023-09-29 12:24:06 +0300
committernkozlovskiy <nmk@ydb.tech>2023-09-29 12:41:34 +0300
commite0e3e1717e3d33762ce61950504f9637a6e669ed (patch)
treebca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python3/src/Modules/getpath.c
parent38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff)
downloadydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz
add ydb deps
Diffstat (limited to 'contrib/tools/python3/src/Modules/getpath.c')
-rw-r--r--contrib/tools/python3/src/Modules/getpath.c962
1 files changed, 962 insertions, 0 deletions
diff --git a/contrib/tools/python3/src/Modules/getpath.c b/contrib/tools/python3/src/Modules/getpath.c
new file mode 100644
index 0000000000..22b105eadc
--- /dev/null
+++ b/contrib/tools/python3/src/Modules/getpath.c
@@ -0,0 +1,962 @@
+#define PYTHONPATH ":"
+/* Return the initial module search path. */
+
+#include "Python.h"
+#include "marshal.h" // PyMarshal_ReadObjectFromString
+#include "osdefs.h" // DELIM
+#include "pycore_initconfig.h"
+#include "pycore_fileutils.h"
+#include "pycore_pathconfig.h"
+#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
+#include <wchar.h>
+
+#ifdef MS_WINDOWS
+# include <windows.h> // GetFullPathNameW(), MAX_PATH
+# include <pathcch.h>
+#endif
+
+#ifdef __APPLE__
+# include <mach-o/dyld.h>
+#endif
+
+/* Reference the precompiled getpath.py */
+#include "../Python/frozen_modules/getpath.h"
+
+#if (!defined(PREFIX) || !defined(EXEC_PREFIX) \
+ || !defined(VERSION) || !defined(VPATH) \
+ || !defined(PLATLIBDIR))
+#error "PREFIX, EXEC_PREFIX, VERSION, VPATH and PLATLIBDIR macros must be defined"
+#endif
+
+#if !defined(PYTHONPATH)
+#define PYTHONPATH NULL
+#endif
+
+#if !defined(PYDEBUGEXT)
+#define PYDEBUGEXT NULL
+#endif
+
+#if !defined(PYWINVER)
+#ifdef MS_DLL_ID
+#define PYWINVER MS_DLL_ID
+#else
+#define PYWINVER NULL
+#endif
+#endif
+
+#if !defined(EXE_SUFFIX)
+#if defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(__MINGW32__)
+#define EXE_SUFFIX L".exe"
+#else
+#define EXE_SUFFIX NULL
+#endif
+#endif
+
+
+/* HELPER FUNCTIONS for getpath.py */
+
+static PyObject *
+getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ wchar_t *path;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+ Py_ssize_t len;
+ path = PyUnicode_AsWideCharString(pathobj, &len);
+ if (path) {
+ wchar_t *abs;
+ if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) {
+ r = PyUnicode_FromWideChar(abs, -1);
+ PyMem_RawFree((void *)abs);
+ } else {
+ PyErr_SetString(PyExc_OSError, "failed to make path absolute");
+ }
+ PyMem_Free((void *)path);
+ }
+ return r;
+}
+
+
+static PyObject *
+getpath_basename(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *path;
+ if (!PyArg_ParseTuple(args, "U", &path)) {
+ return NULL;
+ }
+ Py_ssize_t end = PyUnicode_GET_LENGTH(path);
+ Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1);
+ if (pos < 0) {
+ return Py_NewRef(path);
+ }
+ return PyUnicode_Substring(path, pos + 1, end);
+}
+
+
+static PyObject *
+getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *path;
+ if (!PyArg_ParseTuple(args, "U", &path)) {
+ return NULL;
+ }
+ Py_ssize_t end = PyUnicode_GET_LENGTH(path);
+ Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1);
+ if (pos < 0) {
+ return PyUnicode_FromStringAndSize(NULL, 0);
+ }
+ return PyUnicode_Substring(path, 0, pos);
+}
+
+
+static PyObject *
+getpath_isabs(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ const wchar_t *path;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+ path = PyUnicode_AsWideCharString(pathobj, NULL);
+ if (path) {
+ r = _Py_isabs(path) ? Py_True : Py_False;
+ PyMem_Free((void *)path);
+ }
+ Py_XINCREF(r);
+ return r;
+}
+
+
+static PyObject *
+getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ PyObject *suffixobj;
+ const wchar_t *path;
+ const wchar_t *suffix;
+ if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) {
+ return NULL;
+ }
+ Py_ssize_t len, suffixLen;
+ path = PyUnicode_AsWideCharString(pathobj, &len);
+ if (path) {
+ suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen);
+ if (suffix) {
+ if (suffixLen > len ||
+#ifdef MS_WINDOWS
+ wcsicmp(&path[len - suffixLen], suffix) != 0
+#else
+ wcscmp(&path[len - suffixLen], suffix) != 0
+#endif
+ ) {
+ r = Py_False;
+ } else {
+ r = Py_True;
+ }
+ Py_INCREF(r);
+ PyMem_Free((void *)suffix);
+ }
+ PyMem_Free((void *)path);
+ }
+ return r;
+}
+
+
+static PyObject *
+getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ const wchar_t *path;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+ path = PyUnicode_AsWideCharString(pathobj, NULL);
+ if (path) {
+#ifdef MS_WINDOWS
+ DWORD attr = GetFileAttributesW(path);
+ r = (attr != INVALID_FILE_ATTRIBUTES) &&
+ (attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
+#else
+ struct stat st;
+ r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False;
+#endif
+ PyMem_Free((void *)path);
+ }
+ Py_XINCREF(r);
+ return r;
+}
+
+
+static PyObject *
+getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ const wchar_t *path;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+ path = PyUnicode_AsWideCharString(pathobj, NULL);
+ if (path) {
+#ifdef MS_WINDOWS
+ DWORD attr = GetFileAttributesW(path);
+ r = (attr != INVALID_FILE_ATTRIBUTES) &&
+ !(attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
+#else
+ struct stat st;
+ r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False;
+#endif
+ PyMem_Free((void *)path);
+ }
+ Py_XINCREF(r);
+ return r;
+}
+
+
+static PyObject *
+getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ const wchar_t *path;
+ Py_ssize_t cchPath;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+ path = PyUnicode_AsWideCharString(pathobj, &cchPath);
+ if (path) {
+#ifdef MS_WINDOWS
+ const wchar_t *ext;
+ DWORD attr = GetFileAttributesW(path);
+ r = (attr != INVALID_FILE_ATTRIBUTES) &&
+ !(attr & FILE_ATTRIBUTE_DIRECTORY) &&
+ SUCCEEDED(PathCchFindExtension(path, cchPath + 1, &ext)) &&
+ (CompareStringOrdinal(ext, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL)
+ ? Py_True : Py_False;
+#else
+ struct stat st;
+ r = (_Py_wstat(path, &st) == 0) &&
+ S_ISREG(st.st_mode) &&
+ (st.st_mode & 0111)
+ ? Py_True : Py_False;
+#endif
+ PyMem_Free((void *)path);
+ }
+ Py_XINCREF(r);
+ return r;
+}
+
+
+static PyObject *
+getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_TypeError, "requires tuple of arguments");
+ return NULL;
+ }
+ Py_ssize_t n = PyTuple_GET_SIZE(args);
+ if (n == 0) {
+ return PyUnicode_FromStringAndSize(NULL, 0);
+ }
+ /* Convert all parts to wchar and accumulate max final length */
+ wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *));
+ memset(parts, 0, n * sizeof(wchar_t *));
+ Py_ssize_t cchFinal = 0;
+ Py_ssize_t first = 0;
+
+ for (Py_ssize_t i = 0; i < n; ++i) {
+ PyObject *s = PyTuple_GET_ITEM(args, i);
+ Py_ssize_t cch;
+ if (s == Py_None) {
+ cch = 0;
+ } else if (PyUnicode_Check(s)) {
+ parts[i] = PyUnicode_AsWideCharString(s, &cch);
+ if (!parts[i]) {
+ cchFinal = -1;
+ break;
+ }
+ if (_Py_isabs(parts[i])) {
+ first = i;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "all arguments to joinpath() must be str or None");
+ cchFinal = -1;
+ break;
+ }
+ cchFinal += cch + 1;
+ }
+
+ wchar_t *final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL;
+ if (!final) {
+ for (Py_ssize_t i = 0; i < n; ++i) {
+ PyMem_Free(parts[i]);
+ }
+ PyMem_Free(parts);
+ if (cchFinal) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ return PyUnicode_FromStringAndSize(NULL, 0);
+ }
+
+ final[0] = '\0';
+ /* Now join all the paths. The final result should be shorter than the buffer */
+ for (Py_ssize_t i = 0; i < n; ++i) {
+ if (!parts[i]) {
+ continue;
+ }
+ if (i >= first && final) {
+ if (!final[0]) {
+ /* final is definitely long enough to fit any individual part */
+ wcscpy(final, parts[i]);
+ } else if (_Py_add_relfile(final, parts[i], cchFinal) < 0) {
+ /* if we fail, keep iterating to free memory, but stop adding parts */
+ PyMem_Free(final);
+ final = NULL;
+ }
+ }
+ PyMem_Free(parts[i]);
+ }
+ PyMem_Free(parts);
+ if (!final) {
+ PyErr_SetString(PyExc_SystemError, "failed to join paths");
+ return NULL;
+ }
+ PyObject *r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1);
+ PyMem_Free(final);
+ return r;
+}
+
+
+static PyObject *
+getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *r = NULL;
+ PyObject *pathobj;
+ const wchar_t *path;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+ path = PyUnicode_AsWideCharString(pathobj, NULL);
+ if (!path) {
+ return NULL;
+ }
+ FILE *fp = _Py_wfopen(path, L"rb");
+ PyMem_Free((void *)path);
+ if (!fp) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ r = PyList_New(0);
+ if (!r) {
+ fclose(fp);
+ return NULL;
+ }
+ const size_t MAX_FILE = 32 * 1024;
+ char *buffer = (char *)PyMem_Malloc(MAX_FILE);
+ if (!buffer) {
+ Py_DECREF(r);
+ fclose(fp);
+ return NULL;
+ }
+
+ size_t cb = fread(buffer, 1, MAX_FILE, fp);
+ fclose(fp);
+ if (!cb) {
+ return r;
+ }
+ if (cb >= MAX_FILE) {
+ Py_DECREF(r);
+ PyErr_SetString(PyExc_MemoryError,
+ "cannot read file larger than 32KB during initialization");
+ return NULL;
+ }
+ buffer[cb] = '\0';
+
+ size_t len;
+ wchar_t *wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len);
+ PyMem_Free((void *)buffer);
+ if (!wbuffer) {
+ Py_DECREF(r);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ wchar_t *p1 = wbuffer;
+ wchar_t *p2 = p1;
+ while ((p2 = wcschr(p1, L'\n')) != NULL) {
+ Py_ssize_t cb = p2 - p1;
+ while (cb >= 0 && (p1[cb] == L'\n' || p1[cb] == L'\r')) {
+ --cb;
+ }
+ PyObject *u = PyUnicode_FromWideChar(p1, cb >= 0 ? cb + 1 : 0);
+ if (!u || PyList_Append(r, u) < 0) {
+ Py_XDECREF(u);
+ Py_CLEAR(r);
+ break;
+ }
+ Py_DECREF(u);
+ p1 = p2 + 1;
+ }
+ if (r && p1 && *p1) {
+ PyObject *u = PyUnicode_FromWideChar(p1, -1);
+ if (!u || PyList_Append(r, u) < 0) {
+ Py_CLEAR(r);
+ }
+ Py_XDECREF(u);
+ }
+ PyMem_RawFree(wbuffer);
+ return r;
+}
+
+
+static PyObject *
+getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args)
+{
+ PyObject *pathobj;
+ if (!PyArg_ParseTuple(args, "U", &pathobj)) {
+ return NULL;
+ }
+#if defined(HAVE_READLINK)
+ /* This readlink calculation only resolves a symlinked file, and
+ does not resolve any path segments. This is consistent with
+ prior releases, however, the realpath implementation below is
+ potentially correct in more cases. */
+ PyObject *r = NULL;
+ int nlink = 0;
+ wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
+ if (!path) {
+ goto done;
+ }
+ wchar_t *path2 = _PyMem_RawWcsdup(path);
+ PyMem_Free((void *)path);
+ path = path2;
+ while (path) {
+ wchar_t resolved[MAXPATHLEN + 1];
+ int linklen = _Py_wreadlink(path, resolved, Py_ARRAY_LENGTH(resolved));
+ if (linklen == -1) {
+ r = PyUnicode_FromWideChar(path, -1);
+ break;
+ }
+ if (_Py_isabs(resolved)) {
+ PyMem_RawFree((void *)path);
+ path = _PyMem_RawWcsdup(resolved);
+ } else {
+ wchar_t *s = wcsrchr(path, SEP);
+ if (s) {
+ *s = L'\0';
+ }
+ path2 = _Py_join_relfile(path, resolved);
+ if (path2) {
+ path2 = _Py_normpath(path2, -1);
+ }
+ PyMem_RawFree((void *)path);
+ path = path2;
+ }
+ nlink++;
+ /* 40 is the Linux kernel 4.2 limit */
+ if (nlink >= 40) {
+ PyErr_SetString(PyExc_OSError, "maximum number of symbolic links reached");
+ break;
+ }
+ }
+ if (!path) {
+ PyErr_NoMemory();
+ }
+done:
+ PyMem_RawFree((void *)path);
+ return r;
+
+#elif defined(HAVE_REALPATH)
+ PyObject *r = NULL;
+ struct stat st;
+ const char *narrow = NULL;
+ wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
+ if (!path) {
+ goto done;
+ }
+ narrow = Py_EncodeLocale(path, NULL);
+ if (!narrow) {
+ PyErr_NoMemory();
+ goto done;
+ }
+ if (lstat(narrow, &st)) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto done;
+ }
+ if (!S_ISLNK(st.st_mode)) {
+ Py_INCREF(pathobj);
+ r = pathobj;
+ goto done;
+ }
+ wchar_t resolved[MAXPATHLEN+1];
+ if (_Py_wrealpath(path, resolved, MAXPATHLEN) == NULL) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ } else {
+ r = PyUnicode_FromWideChar(resolved, -1);
+ }
+done:
+ PyMem_Free((void *)path);
+ PyMem_Free((void *)narrow);
+ return r;
+#endif
+
+ Py_INCREF(pathobj);
+ return pathobj;
+}
+
+
+static PyMethodDef getpath_methods[] = {
+ {"abspath", getpath_abspath, METH_VARARGS, NULL},
+ {"basename", getpath_basename, METH_VARARGS, NULL},
+ {"dirname", getpath_dirname, METH_VARARGS, NULL},
+ {"hassuffix", getpath_hassuffix, METH_VARARGS, NULL},
+ {"isabs", getpath_isabs, METH_VARARGS, NULL},
+ {"isdir", getpath_isdir, METH_VARARGS, NULL},
+ {"isfile", getpath_isfile, METH_VARARGS, NULL},
+ {"isxfile", getpath_isxfile, METH_VARARGS, NULL},
+ {"joinpath", getpath_joinpath, METH_VARARGS, NULL},
+ {"readlines", getpath_readlines, METH_VARARGS, NULL},
+ {"realpath", getpath_realpath, METH_VARARGS, NULL},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/* Two implementations of warn() to use depending on whether warnings
+ are enabled or not. */
+
+static PyObject *
+getpath_warn(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *msgobj;
+ if (!PyArg_ParseTuple(args, "U", &msgobj)) {
+ return NULL;
+ }
+ fprintf(stderr, "%s\n", PyUnicode_AsUTF8(msgobj));
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *
+getpath_nowarn(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef getpath_warn_method = {"warn", getpath_warn, METH_VARARGS, NULL};
+static PyMethodDef getpath_nowarn_method = {"warn", getpath_nowarn, METH_VARARGS, NULL};
+
+/* Add the helper functions to the dict */
+static int
+funcs_to_dict(PyObject *dict, int warnings)
+{
+ for (PyMethodDef *m = getpath_methods; m->ml_name; ++m) {
+ PyObject *f = PyCFunction_NewEx(m, NULL, NULL);
+ if (!f) {
+ return 0;
+ }
+ if (PyDict_SetItemString(dict, m->ml_name, f) < 0) {
+ Py_DECREF(f);
+ return 0;
+ }
+ Py_DECREF(f);
+ }
+ PyMethodDef *m2 = warnings ? &getpath_warn_method : &getpath_nowarn_method;
+ PyObject *f = PyCFunction_NewEx(m2, NULL, NULL);
+ if (!f) {
+ return 0;
+ }
+ if (PyDict_SetItemString(dict, m2->ml_name, f) < 0) {
+ Py_DECREF(f);
+ return 0;
+ }
+ Py_DECREF(f);
+ return 1;
+}
+
+
+/* Add a wide-character string constant to the dict */
+static int
+wchar_to_dict(PyObject *dict, const char *key, const wchar_t *s)
+{
+ PyObject *u;
+ int r;
+ if (s && s[0]) {
+ u = PyUnicode_FromWideChar(s, -1);
+ if (!u) {
+ return 0;
+ }
+ } else {
+ u = Py_None;
+ Py_INCREF(u);
+ }
+ r = PyDict_SetItemString(dict, key, u) == 0;
+ Py_DECREF(u);
+ return r;
+}
+
+
+/* Add a narrow string constant to the dict, using default locale decoding */
+static int
+decode_to_dict(PyObject *dict, const char *key, const char *s)
+{
+ PyObject *u = NULL;
+ int r;
+ if (s && s[0]) {
+ size_t len;
+ const wchar_t *w = Py_DecodeLocale(s, &len);
+ if (w) {
+ u = PyUnicode_FromWideChar(w, len);
+ PyMem_RawFree((void *)w);
+ }
+ if (!u) {
+ return 0;
+ }
+ } else {
+ u = Py_None;
+ Py_INCREF(u);
+ }
+ r = PyDict_SetItemString(dict, key, u) == 0;
+ Py_DECREF(u);
+ return r;
+}
+
+/* Add an environment variable to the dict, optionally clearing it afterwards */
+static int
+env_to_dict(PyObject *dict, const char *key, int and_clear)
+{
+ PyObject *u = NULL;
+ int r = 0;
+ assert(strncmp(key, "ENV_", 4) == 0);
+ assert(strlen(key) < 64);
+#ifdef MS_WINDOWS
+ wchar_t wkey[64];
+ // Quick convert to wchar_t, since we know key is ASCII
+ wchar_t *wp = wkey;
+ for (const char *p = &key[4]; *p; ++p) {
+ assert(*p < 128);
+ *wp++ = *p;
+ }
+ *wp = L'\0';
+ const wchar_t *v = _wgetenv(wkey);
+ if (v) {
+ u = PyUnicode_FromWideChar(v, -1);
+ if (!u) {
+ PyErr_Clear();
+ }
+ }
+#else
+ const char *v = getenv(&key[4]);
+ if (v) {
+ size_t len;
+ const wchar_t *w = Py_DecodeLocale(v, &len);
+ if (w) {
+ u = PyUnicode_FromWideChar(w, len);
+ if (!u) {
+ PyErr_Clear();
+ }
+ PyMem_RawFree((void *)w);
+ }
+ }
+#endif
+ if (u) {
+ r = PyDict_SetItemString(dict, key, u) == 0;
+ Py_DECREF(u);
+ } else {
+ r = PyDict_SetItemString(dict, key, Py_None) == 0;
+ }
+ if (r && and_clear) {
+#ifdef MS_WINDOWS
+ _wputenv_s(wkey, L"");
+#else
+ unsetenv(&key[4]);
+#endif
+ }
+ return r;
+}
+
+
+/* Add an integer constant to the dict */
+static int
+int_to_dict(PyObject *dict, const char *key, int v)
+{
+ PyObject *o;
+ int r;
+ o = PyLong_FromLong(v);
+ if (!o) {
+ return 0;
+ }
+ r = PyDict_SetItemString(dict, key, o) == 0;
+ Py_DECREF(o);
+ return r;
+}
+
+
+#ifdef MS_WINDOWS
+static int
+winmodule_to_dict(PyObject *dict, const char *key, HMODULE mod)
+{
+ wchar_t *buffer = NULL;
+ for (DWORD cch = 256; buffer == NULL && cch < (1024 * 1024); cch *= 2) {
+ buffer = (wchar_t*)PyMem_RawMalloc(cch * sizeof(wchar_t));
+ if (buffer) {
+ if (GetModuleFileNameW(mod, buffer, cch) == cch) {
+ PyMem_RawFree(buffer);
+ buffer = NULL;
+ }
+ }
+ }
+ int r = wchar_to_dict(dict, key, buffer);
+ PyMem_RawFree(buffer);
+ return r;
+}
+#endif
+
+
+/* Add the current executable's path to the dict */
+static int
+progname_to_dict(PyObject *dict, const char *key)
+{
+#ifdef MS_WINDOWS
+ return winmodule_to_dict(dict, key, NULL);
+#elif defined(__APPLE__)
+ char *path;
+ uint32_t pathLen = 256;
+ while (pathLen) {
+ path = PyMem_RawMalloc((pathLen + 1) * sizeof(char));
+ if (!path) {
+ return 0;
+ }
+ if (_NSGetExecutablePath(path, &pathLen) != 0) {
+ PyMem_RawFree(path);
+ continue;
+ }
+ // Only keep if the path is absolute
+ if (path[0] == SEP) {
+ int r = decode_to_dict(dict, key, path);
+ PyMem_RawFree(path);
+ return r;
+ }
+ // Fall back and store None
+ PyMem_RawFree(path);
+ break;
+ }
+#endif
+ return PyDict_SetItemString(dict, key, Py_None) == 0;
+}
+
+
+/* Add the runtime library's path to the dict */
+static int
+library_to_dict(PyObject *dict, const char *key)
+{
+#ifdef MS_WINDOWS
+#ifdef Py_ENABLE_SHARED
+ extern HMODULE PyWin_DLLhModule;
+ if (PyWin_DLLhModule) {
+ return winmodule_to_dict(dict, key, PyWin_DLLhModule);
+ }
+#endif
+#elif defined(WITH_NEXT_FRAMEWORK)
+ static char modPath[MAXPATHLEN + 1];
+ static int modPathInitialized = -1;
+ if (modPathInitialized < 0) {
+ modPathInitialized = 0;
+
+ /* On Mac OS X we have a special case if we're running from a framework.
+ This is because the python home should be set relative to the library,
+ which is in the framework, not relative to the executable, which may
+ be outside of the framework. Except when we're in the build
+ directory... */
+ NSSymbol symbol = NSLookupAndBindSymbol("_Py_Initialize");
+ if (symbol != NULL) {
+ NSModule pythonModule = NSModuleForSymbol(symbol);
+ if (pythonModule != NULL) {
+ /* Use dylib functions to find out where the framework was loaded from */
+ const char *path = NSLibraryNameForModule(pythonModule);
+ if (path) {
+ strncpy(modPath, path, MAXPATHLEN);
+ modPathInitialized = 1;
+ }
+ }
+ }
+ }
+ if (modPathInitialized > 0) {
+ return decode_to_dict(dict, key, modPath);
+ }
+#endif
+ return PyDict_SetItemString(dict, key, Py_None) == 0;
+}
+
+
+PyObject *
+_Py_Get_Getpath_CodeObject(void)
+{
+ return PyMarshal_ReadObjectFromString(
+ (const char*)_Py_M__getpath, sizeof(_Py_M__getpath));
+}
+
+
+/* Perform the actual path calculation.
+
+ When compute_path_config is 0, this only reads any initialised path
+ config values into the PyConfig struct. For example, Py_SetHome() or
+ Py_SetPath(). The only error should be due to failed memory allocation.
+
+ When compute_path_config is 1, full path calculation is performed.
+ The GIL must be held, and there may be filesystem access, side
+ effects, and potential unraisable errors that are reported directly
+ to stderr.
+
+ Calling this function multiple times on the same PyConfig is only
+ safe because already-configured values are not recalculated. To
+ actually recalculate paths, you need a clean PyConfig.
+*/
+PyStatus
+_PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
+{
+ PyStatus status = _PyPathConfig_ReadGlobal(config);
+
+ if (_PyStatus_EXCEPTION(status) || !compute_path_config) {
+ return status;
+ }
+
+ if (!_PyThreadState_UncheckedGet()) {
+ return PyStatus_Error("cannot calculate path configuration without GIL");
+ }
+
+ PyObject *configDict = _PyConfig_AsDict(config);
+ if (!configDict) {
+ PyErr_Clear();
+ return PyStatus_NoMemory();
+ }
+
+ PyObject *dict = PyDict_New();
+ if (!dict) {
+ PyErr_Clear();
+ Py_DECREF(configDict);
+ return PyStatus_NoMemory();
+ }
+
+ if (PyDict_SetItemString(dict, "config", configDict) < 0) {
+ PyErr_Clear();
+ Py_DECREF(configDict);
+ Py_DECREF(dict);
+ return PyStatus_NoMemory();
+ }
+ /* reference now held by dict */
+ Py_DECREF(configDict);
+
+ PyObject *co = _Py_Get_Getpath_CodeObject();
+ if (!co || !PyCode_Check(co)) {
+ PyErr_Clear();
+ Py_XDECREF(co);
+ Py_DECREF(dict);
+ return PyStatus_Error("error reading frozen getpath.py");
+ }
+
+#ifdef MS_WINDOWS
+ PyObject *winreg = PyImport_ImportModule("winreg");
+ if (!winreg || PyDict_SetItemString(dict, "winreg", winreg) < 0) {
+ PyErr_Clear();
+ Py_XDECREF(winreg);
+ if (PyDict_SetItemString(dict, "winreg", Py_None) < 0) {
+ PyErr_Clear();
+ Py_DECREF(co);
+ Py_DECREF(dict);
+ return PyStatus_Error("error importing winreg module");
+ }
+ } else {
+ Py_DECREF(winreg);
+ }
+#endif
+
+ if (
+#ifdef MS_WINDOWS
+ !decode_to_dict(dict, "os_name", "nt") ||
+#elif defined(__APPLE__)
+ !decode_to_dict(dict, "os_name", "darwin") ||
+#else
+ !decode_to_dict(dict, "os_name", "posix") ||
+#endif
+#ifdef WITH_NEXT_FRAMEWORK
+ !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 1) ||
+#else
+ !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 0) ||
+#endif
+ !decode_to_dict(dict, "PREFIX", PREFIX) ||
+ !decode_to_dict(dict, "EXEC_PREFIX", EXEC_PREFIX) ||
+ !decode_to_dict(dict, "PYTHONPATH", PYTHONPATH) ||
+ !decode_to_dict(dict, "VPATH", VPATH) ||
+ !decode_to_dict(dict, "PLATLIBDIR", PLATLIBDIR) ||
+ !decode_to_dict(dict, "PYDEBUGEXT", PYDEBUGEXT) ||
+ !int_to_dict(dict, "VERSION_MAJOR", PY_MAJOR_VERSION) ||
+ !int_to_dict(dict, "VERSION_MINOR", PY_MINOR_VERSION) ||
+ !decode_to_dict(dict, "PYWINVER", PYWINVER) ||
+ !wchar_to_dict(dict, "EXE_SUFFIX", EXE_SUFFIX) ||
+ !env_to_dict(dict, "ENV_PATH", 0) ||
+ !env_to_dict(dict, "ENV_PYTHONHOME", 0) ||
+ !env_to_dict(dict, "ENV_PYTHONEXECUTABLE", 0) ||
+ !env_to_dict(dict, "ENV___PYVENV_LAUNCHER__", 1) ||
+ !progname_to_dict(dict, "real_executable") ||
+ !library_to_dict(dict, "library") ||
+ !wchar_to_dict(dict, "executable_dir", NULL) ||
+ !wchar_to_dict(dict, "py_setpath", _PyPathConfig_GetGlobalModuleSearchPath()) ||
+ !funcs_to_dict(dict, config->pathconfig_warnings) ||
+#ifndef MS_WINDOWS
+ PyDict_SetItemString(dict, "winreg", Py_None) < 0 ||
+#endif
+ PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0
+ ) {
+ Py_DECREF(co);
+ Py_DECREF(dict);
+ _PyErr_WriteUnraisableMsg("error evaluating initial values", NULL);
+ return PyStatus_Error("error evaluating initial values");
+ }
+
+ PyObject *r = PyEval_EvalCode(co, dict, dict);
+ Py_DECREF(co);
+
+ if (!r) {
+ Py_DECREF(dict);
+ _PyErr_WriteUnraisableMsg("error evaluating path", NULL);
+ return PyStatus_Error("error evaluating path");
+ }
+ Py_DECREF(r);
+
+#if 0
+ PyObject *it = PyObject_GetIter(configDict);
+ for (PyObject *k = PyIter_Next(it); k; k = PyIter_Next(it)) {
+ if (!strcmp("__builtins__", PyUnicode_AsUTF8(k))) {
+ Py_DECREF(k);
+ continue;
+ }
+ fprintf(stderr, "%s = ", PyUnicode_AsUTF8(k));
+ PyObject *o = PyDict_GetItem(configDict, k);
+ o = PyObject_Repr(o);
+ fprintf(stderr, "%s\n", PyUnicode_AsUTF8(o));
+ Py_DECREF(o);
+ Py_DECREF(k);
+ }
+ Py_DECREF(it);
+#endif
+
+ if (_PyConfig_FromDict(config, configDict) < 0) {
+ _PyErr_WriteUnraisableMsg("reading getpath results", NULL);
+ Py_DECREF(dict);
+ return PyStatus_Error("error getting getpath results");
+ }
+
+ Py_DECREF(dict);
+
+ return _PyStatus_OK();
+}
+