diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:24:06 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:41:34 +0300 |
commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python3/src/Modules/getpath.c | |
parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
download | ydb-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.c | 962 |
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(); +} + |