| /* 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) | 
 | { | 
 |     const char *path; | 
 |     if (!PyArg_ParseTuple(args, "s", &path)) { | 
 |         return NULL; | 
 |     } | 
 |     const char *name = strrchr(path, SEP); | 
 |     return PyUnicode_FromString(name ? name + 1 : path); | 
 | } | 
 |  | 
 |  | 
 | static PyObject * | 
 | getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args) | 
 | { | 
 |     const char *path; | 
 |     if (!PyArg_ParseTuple(args, "s", &path)) { | 
 |         return NULL; | 
 |     } | 
 |     const char *name = strrchr(path, SEP); | 
 |     if (!name) { | 
 |         return PyUnicode_FromStringAndSize(NULL, 0); | 
 |     } | 
 |     return PyUnicode_FromStringAndSize(path, (name - path)); | 
 | } | 
 |  | 
 |  | 
 | 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_FromString(NULL); | 
 |     } | 
 |     /* 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_normpath(_Py_join_relfile(path, resolved), -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 | 
 |     extern HMODULE PyWin_DLLhModule; | 
 |     if (PyWin_DLLhModule) { | 
 |         return winmodule_to_dict(dict, key, PyWin_DLLhModule); | 
 |     } | 
 | #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(); | 
 | } | 
 |  |