diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 3b603c87ad4..efdc58eed8e 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -7,23 +7,7 @@ extern "C" { #endif -PyAPI_FUNC(void) Py_SetProgramName(wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); - -PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); -#ifdef Py_BUILD_CORE -PyAPI_FUNC(wchar_t *) _Py_GetPythonHomeWithConfig( - const _PyMainInterpreterConfig *config); -#endif - #ifndef Py_LIMITED_API -/* Only used by applications that embed the interpreter and need to - * override the standard encoding determination mechanism - */ -PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, - const char *errors); - typedef struct { const char *prefix; const char *msg; @@ -46,9 +30,31 @@ typedef struct { Don't abort() the process on such error. */ #define _Py_INIT_USER_ERR(MSG) \ (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1} +#define _Py_INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed") #define _Py_INIT_FAILED(err) \ (err.msg != NULL) +#endif + + +PyAPI_FUNC(void) Py_SetProgramName(wchar_t *); +PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); + +PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); +PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); +#ifdef Py_BUILD_CORE +PyAPI_FUNC(_PyInitError) _Py_GetPythonHomeWithConfig( + const _PyMainInterpreterConfig *config, + wchar_t **home); +#endif + +#ifndef Py_LIMITED_API +/* Only used by applications that embed the interpreter and need to + * override the standard encoding determination mechanism + */ +PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, + const char *errors); + /* PEP 432 Multi-phase initialization API (Private while provisional!) */ PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *); PyAPI_FUNC(int) _Py_IsCoreInitialized(void); diff --git a/Modules/getpath.c b/Modules/getpath.c index 62f5e695849..d8125ae2cac 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -7,7 +7,7 @@ #include #ifdef __APPLE__ -#include +# include #endif /* Search in some common locations for the associated Python libraries. @@ -97,7 +97,7 @@ */ #ifdef __cplusplus - extern "C" { +extern "C" { #endif @@ -109,13 +109,38 @@ #define LANDMARK L"os.py" #endif -static wchar_t prefix[MAXPATHLEN+1]; -static wchar_t exec_prefix[MAXPATHLEN+1]; -static wchar_t progpath[MAXPATHLEN+1]; -static wchar_t *module_search_path = NULL; +typedef struct { + wchar_t prefix[MAXPATHLEN+1]; + wchar_t exec_prefix[MAXPATHLEN+1]; + wchar_t progpath[MAXPATHLEN+1]; + wchar_t *module_search_path; +} PyPathConfig; + +typedef struct { + wchar_t *path_env; /* PATH environment variable */ + wchar_t *home; /* PYTHONHOME environment variable */ + wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ + wchar_t *module_search_path_buffer; + + wchar_t *prog; /* Program name */ + wchar_t *pythonpath; /* PYTHONPATH define */ + wchar_t *prefix; /* PREFIX define */ + wchar_t *exec_prefix; /* EXEC_PREFIX define */ + + wchar_t *lib_python; /* "lib/pythonX.Y" */ + wchar_t argv0_path[MAXPATHLEN+1]; + wchar_t zip_path[MAXPATHLEN+1]; /* ".../lib/pythonXY.zip" */ + + int prefix_found; /* found platform independent libraries? */ + int exec_prefix_found; /* found the platform dependent libraries? */ +} PyCalculatePath; + +static const wchar_t delimiter[2] = {DELIM, '\0'}; +static const wchar_t separator[2] = {SEP, '\0'}; +static PyPathConfig path_config = {.module_search_path = NULL}; + /* Get file status. Encode the path to the locale encoding. */ - static int _Py_wstat(const wchar_t* path, struct stat *buf) { @@ -131,6 +156,7 @@ _Py_wstat(const wchar_t* path, struct stat *buf) return err; } + static void reduce(wchar_t *dir) { @@ -140,14 +166,17 @@ reduce(wchar_t *dir) dir[i] = '\0'; } + static int isfile(wchar_t *filename) /* Is file, not directory */ { struct stat buf; - if (_Py_wstat(filename, &buf) != 0) + if (_Py_wstat(filename, &buf) != 0) { return 0; - if (!S_ISREG(buf.st_mode)) + } + if (!S_ISREG(buf.st_mode)) { return 0; + } return 1; } @@ -155,41 +184,50 @@ isfile(wchar_t *filename) /* Is file, not directory */ static int ismodule(wchar_t *filename) /* Is module -- check for .pyc too */ { - if (isfile(filename)) + if (isfile(filename)) { return 1; + } /* Check for the compiled version of prefix. */ if (wcslen(filename) < MAXPATHLEN) { wcscat(filename, L"c"); - if (isfile(filename)) + if (isfile(filename)) { return 1; + } } return 0; } +/* Is executable file */ static int -isxfile(wchar_t *filename) /* Is executable file */ +isxfile(wchar_t *filename) { struct stat buf; - if (_Py_wstat(filename, &buf) != 0) + if (_Py_wstat(filename, &buf) != 0) { return 0; - if (!S_ISREG(buf.st_mode)) + } + if (!S_ISREG(buf.st_mode)) { return 0; - if ((buf.st_mode & 0111) == 0) + } + if ((buf.st_mode & 0111) == 0) { return 0; + } return 1; } +/* Is directory */ static int -isdir(wchar_t *filename) /* Is directory */ +isdir(wchar_t *filename) { struct stat buf; - if (_Py_wstat(filename, &buf) != 0) + if (_Py_wstat(filename, &buf) != 0) { return 0; - if (!S_ISDIR(buf.st_mode)) + } + if (!S_ISDIR(buf.st_mode)) { return 0; + } return 1; } @@ -207,58 +245,67 @@ static void joinpath(wchar_t *buffer, wchar_t *stuff) { size_t n, k; - if (stuff[0] == SEP) + if (stuff[0] == SEP) { n = 0; + } else { n = wcslen(buffer); - if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) + if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) { buffer[n++] = SEP; + } } - if (n > MAXPATHLEN) + if (n > MAXPATHLEN) { Py_FatalError("buffer overflow in getpath.c's joinpath()"); + } k = wcslen(stuff); - if (n + k > MAXPATHLEN) + if (n + k > MAXPATHLEN) { k = MAXPATHLEN - n; + } wcsncpy(buffer+n, stuff, k); buffer[n+k] = '\0'; } + /* copy_absolute requires that path be allocated at least MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */ static void copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen) { - if (p[0] == SEP) + if (p[0] == SEP) { wcscpy(path, p); + } else { if (!_Py_wgetcwd(path, pathlen)) { /* unable to get the current directory */ wcscpy(path, p); return; } - if (p[0] == '.' && p[1] == SEP) + if (p[0] == '.' && p[1] == SEP) { p += 2; + } joinpath(path, p); } } + /* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */ static void absolutize(wchar_t *path) { wchar_t buffer[MAXPATHLEN+1]; - if (path[0] == SEP) + if (path[0] == SEP) { return; + } copy_absolute(buffer, path, MAXPATHLEN+1); wcscpy(path, buffer); } + /* search for a prefix value in an environment file. If found, copy it to the provided buffer, which is expected to be no more than MAXPATHLEN bytes long. */ - static int find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) { @@ -272,15 +319,18 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) PyObject * decoded; int n; - if (p == NULL) + if (p == NULL) { break; + } n = strlen(p); if (p[n - 1] != '\n') { /* line has overflowed - bail */ break; } - if (p[0] == '#') /* Comment - skip */ + if (p[0] == '#') { + /* Comment - skip */ continue; + } decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape"); if (decoded != NULL) { Py_ssize_t k; @@ -307,106 +357,151 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) return result; } + /* search_for_prefix requires that argv0_path be no more than MAXPATHLEN bytes long. */ static int -search_for_prefix(wchar_t *argv0_path, wchar_t *home, wchar_t *_prefix, - wchar_t *lib_python) +search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config) { size_t n; wchar_t *vpath; /* If PYTHONHOME is set, we believe it unconditionally */ - if (home) { - wchar_t *delim; - wcsncpy(prefix, home, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - delim = wcschr(prefix, DELIM); - if (delim) + if (calculate->home) { + wcsncpy(config->prefix, calculate->home, MAXPATHLEN); + config->prefix[MAXPATHLEN] = L'\0'; + wchar_t *delim = wcschr(config->prefix, DELIM); + if (delim) { *delim = L'\0'; - joinpath(prefix, lib_python); - joinpath(prefix, LANDMARK); + } + joinpath(config->prefix, calculate->lib_python); + joinpath(config->prefix, LANDMARK); return 1; } /* Check to see if argv[0] is in the build directory */ - wcsncpy(prefix, argv0_path, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - joinpath(prefix, L"Modules/Setup"); - if (isfile(prefix)) { + wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN); + config->prefix[MAXPATHLEN] = L'\0'; + joinpath(config->prefix, L"Modules/Setup"); + if (isfile(config->prefix)) { /* Check VPATH to see if argv0_path is in the build directory. */ vpath = Py_DecodeLocale(VPATH, NULL); if (vpath != NULL) { - wcsncpy(prefix, argv0_path, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - joinpath(prefix, vpath); + wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN); + config->prefix[MAXPATHLEN] = L'\0'; + joinpath(config->prefix, vpath); PyMem_RawFree(vpath); - joinpath(prefix, L"Lib"); - joinpath(prefix, LANDMARK); - if (ismodule(prefix)) + joinpath(config->prefix, L"Lib"); + joinpath(config->prefix, LANDMARK); + if (ismodule(config->prefix)) { return -1; + } } } /* Search from argv0_path, until root is found */ - copy_absolute(prefix, argv0_path, MAXPATHLEN+1); + copy_absolute(config->prefix, calculate->argv0_path, MAXPATHLEN+1); do { - n = wcslen(prefix); - joinpath(prefix, lib_python); - joinpath(prefix, LANDMARK); - if (ismodule(prefix)) + n = wcslen(config->prefix); + joinpath(config->prefix, calculate->lib_python); + joinpath(config->prefix, LANDMARK); + if (ismodule(config->prefix)) { return 1; - prefix[n] = L'\0'; - reduce(prefix); - } while (prefix[0]); + } + config->prefix[n] = L'\0'; + reduce(config->prefix); + } while (config->prefix[0]); /* Look at configure's PREFIX */ - wcsncpy(prefix, _prefix, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - joinpath(prefix, lib_python); - joinpath(prefix, LANDMARK); - if (ismodule(prefix)) + wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN); + config->prefix[MAXPATHLEN] = L'\0'; + joinpath(config->prefix, calculate->lib_python); + joinpath(config->prefix, LANDMARK); + if (ismodule(config->prefix)) { return 1; + } /* Fail */ return 0; } +static void +calculate_prefix(PyCalculatePath *calculate, PyPathConfig *config) +{ + calculate->prefix_found = search_for_prefix(calculate, config); + if (!calculate->prefix_found) { + if (!Py_FrozenFlag) { + fprintf(stderr, + "Could not find platform independent libraries \n"); + } + wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN); + joinpath(config->prefix, calculate->lib_python); + } + else { + reduce(config->prefix); + } +} + + +static void +calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config) +{ + /* Reduce prefix and exec_prefix to their essence, + * e.g. /usr/local/lib/python1.5 is reduced to /usr/local. + * If we're loading relative to the build directory, + * return the compiled-in defaults instead. + */ + if (calculate->prefix_found > 0) { + reduce(config->prefix); + reduce(config->prefix); + /* The prefix is the root directory, but reduce() chopped + * off the "/". */ + if (!config->prefix[0]) { + wcscpy(config->prefix, separator); + } + } + else { + wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN); + } +} + + /* search_for_exec_prefix requires that argv0_path be no more than MAXPATHLEN bytes long. */ static int -search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, - wchar_t *_exec_prefix, wchar_t *lib_python) +search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config) { size_t n; /* If PYTHONHOME is set, we believe it unconditionally */ - if (home) { - wchar_t *delim; - delim = wcschr(home, DELIM); - if (delim) - wcsncpy(exec_prefix, delim+1, MAXPATHLEN); - else - wcsncpy(exec_prefix, home, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - joinpath(exec_prefix, lib_python); - joinpath(exec_prefix, L"lib-dynload"); + if (calculate->home) { + wchar_t *delim = wcschr(calculate->home, DELIM); + if (delim) { + wcsncpy(config->exec_prefix, delim+1, MAXPATHLEN); + } + else { + wcsncpy(config->exec_prefix, calculate->home, MAXPATHLEN); + } + config->exec_prefix[MAXPATHLEN] = L'\0'; + joinpath(config->exec_prefix, calculate->lib_python); + joinpath(config->exec_prefix, L"lib-dynload"); return 1; } /* Check to see if argv[0] is in the build directory. "pybuilddir.txt" is written by setup.py and contains the relative path to the location of shared library modules. */ - wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - joinpath(exec_prefix, L"pybuilddir.txt"); - if (isfile(exec_prefix)) { - FILE *f = _Py_wfopen(exec_prefix, L"rb"); - if (f == NULL) + wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN); + config->exec_prefix[MAXPATHLEN] = L'\0'; + joinpath(config->exec_prefix, L"pybuilddir.txt"); + if (isfile(config->exec_prefix)) { + FILE *f = _Py_wfopen(config->exec_prefix, L"rb"); + if (f == NULL) { errno = 0; + } else { char buf[MAXPATHLEN+1]; PyObject *decoded; @@ -422,9 +517,9 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, Py_DECREF(decoded); if (k >= 0) { rel_builddir_path[k] = L'\0'; - wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - joinpath(exec_prefix, rel_builddir_path); + wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN); + config->exec_prefix[MAXPATHLEN] = L'\0'; + joinpath(config->exec_prefix, rel_builddir_path); return -1; } } @@ -432,52 +527,77 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, } /* Search from argv0_path, until root is found */ - copy_absolute(exec_prefix, argv0_path, MAXPATHLEN+1); + copy_absolute(config->exec_prefix, calculate->argv0_path, MAXPATHLEN+1); do { - n = wcslen(exec_prefix); - joinpath(exec_prefix, lib_python); - joinpath(exec_prefix, L"lib-dynload"); - if (isdir(exec_prefix)) + n = wcslen(config->exec_prefix); + joinpath(config->exec_prefix, calculate->lib_python); + joinpath(config->exec_prefix, L"lib-dynload"); + if (isdir(config->exec_prefix)) { return 1; - exec_prefix[n] = L'\0'; - reduce(exec_prefix); - } while (exec_prefix[0]); + } + config->exec_prefix[n] = L'\0'; + reduce(config->exec_prefix); + } while (config->exec_prefix[0]); /* Look at configure's EXEC_PREFIX */ - wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - joinpath(exec_prefix, lib_python); - joinpath(exec_prefix, L"lib-dynload"); - if (isdir(exec_prefix)) + wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN); + config->exec_prefix[MAXPATHLEN] = L'\0'; + joinpath(config->exec_prefix, calculate->lib_python); + joinpath(config->exec_prefix, L"lib-dynload"); + if (isdir(config->exec_prefix)) { return 1; + } /* Fail */ return 0; } -static void -calculate_path(const _PyMainInterpreterConfig *config) -{ - extern wchar_t *Py_GetProgramName(void); - static const wchar_t delimiter[2] = {DELIM, '\0'}; - static const wchar_t separator[2] = {SEP, '\0'}; - wchar_t *home = _Py_GetPythonHomeWithConfig(config); - char *_path = getenv("PATH"); - wchar_t *path_buffer = NULL; - wchar_t *path = NULL; - wchar_t *prog = Py_GetProgramName(); - wchar_t argv0_path[MAXPATHLEN+1]; - wchar_t zip_path[MAXPATHLEN+1]; - int pfound, efound; /* 1 if found; -1 if found build directory */ - wchar_t *buf; - size_t bufsz; - size_t prefixsz; - wchar_t *defpath; -#ifdef WITH_NEXT_FRAMEWORK - NSModule pythonModule; - const char* modPath; -#endif +static void +calculate_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config) +{ + calculate->exec_prefix_found = search_for_exec_prefix(calculate, config); + if (!calculate->exec_prefix_found) { + if (!Py_FrozenFlag) { + fprintf(stderr, + "Could not find platform dependent libraries \n"); + } + wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN); + joinpath(config->exec_prefix, L"lib/lib-dynload"); + } + /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ +} + + +static void +calculate_reduce_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config) +{ + if (calculate->exec_prefix_found > 0) { + reduce(config->exec_prefix); + reduce(config->exec_prefix); + reduce(config->exec_prefix); + if (!config->exec_prefix[0]) { + wcscpy(config->exec_prefix, separator); + } + } + else { + wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN); + } +} + + +static void +calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config) +{ + /* If there is no slash in the argv0 path, then we have to + * assume python is on the user's $PATH, since there's no + * other way to find a directory to start the search from. If + * $PATH isn't exported, you lose. + */ + if (wcschr(calculate->prog, SEP)) { + wcsncpy(config->progpath, calculate->prog, MAXPATHLEN); + } + #ifdef __APPLE__ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 uint32_t nsexeclength = MAXPATHLEN; @@ -485,34 +605,7 @@ calculate_path(const _PyMainInterpreterConfig *config) unsigned long nsexeclength = MAXPATHLEN; #endif char execpath[MAXPATHLEN+1]; -#endif - wchar_t *_pythonpath, *_prefix, *_exec_prefix; - wchar_t *lib_python; - _pythonpath = Py_DecodeLocale(PYTHONPATH, NULL); - _prefix = Py_DecodeLocale(PREFIX, NULL); - _exec_prefix = Py_DecodeLocale(EXEC_PREFIX, NULL); - lib_python = Py_DecodeLocale("lib/python" VERSION, NULL); - - if (!_pythonpath || !_prefix || !_exec_prefix || !lib_python) { - Py_FatalError( - "Unable to decode path variables in getpath.c: " - "memory error"); - } - - if (_path) { - path_buffer = Py_DecodeLocale(_path, NULL); - path = path_buffer; - } - - /* If there is no slash in the argv0 path, then we have to - * assume python is on the user's $PATH, since there's no - * other way to find a directory to start the search from. If - * $PATH isn't exported, you lose. - */ - if (wcschr(prog, SEP)) - wcsncpy(progpath, prog, MAXPATHLEN); -#ifdef __APPLE__ /* On Mac OS X, if a script uses an interpreter of the form * "#!/opt/python2.3/bin/python", the kernel only passes "python" * as argv[0], which falls through to the $PATH search below. @@ -524,47 +617,60 @@ calculate_path(const _PyMainInterpreterConfig *config) * absolutize() should help us out below */ else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && execpath[0] == SEP) { - size_t r = mbstowcs(progpath, execpath, MAXPATHLEN+1); + size_t r = mbstowcs(config->progpath, execpath, MAXPATHLEN+1); if (r == (size_t)-1 || r > MAXPATHLEN) { /* Could not convert execpath, or it's too long. */ - progpath[0] = '\0'; + config->progpath[0] = '\0'; } } #endif /* __APPLE__ */ - else if (path) { + else if (calculate->path_env) { + wchar_t *path = calculate->path_env; while (1) { wchar_t *delim = wcschr(path, DELIM); if (delim) { size_t len = delim - path; - if (len > MAXPATHLEN) + if (len > MAXPATHLEN) { len = MAXPATHLEN; - wcsncpy(progpath, path, len); - *(progpath + len) = '\0'; + } + wcsncpy(config->progpath, path, len); + *(config->progpath + len) = '\0'; + } + else { + wcsncpy(config->progpath, path, MAXPATHLEN); } - else - wcsncpy(progpath, path, MAXPATHLEN); - joinpath(progpath, prog); - if (isxfile(progpath)) + joinpath(config->progpath, calculate->prog); + if (isxfile(config->progpath)) { break; + } if (!delim) { - progpath[0] = L'\0'; + config->progpath[0] = L'\0'; break; } path = delim + 1; } } - else - progpath[0] = '\0'; - PyMem_RawFree(path_buffer); - if (progpath[0] != SEP && progpath[0] != '\0') - absolutize(progpath); - wcsncpy(argv0_path, progpath, MAXPATHLEN); - argv0_path[MAXPATHLEN] = '\0'; + else { + config->progpath[0] = '\0'; + } + if (config->progpath[0] != SEP && config->progpath[0] != '\0') { + absolutize(config->progpath); + } +} + + +static void +calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config) +{ + wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN); + calculate->argv0_path[MAXPATHLEN] = '\0'; #ifdef WITH_NEXT_FRAMEWORK + NSModule pythonModule; + /* 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 @@ -572,7 +678,7 @@ calculate_path(const _PyMainInterpreterConfig *config) */ pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize")); /* Use dylib functions to find out where the framework was loaded from */ - modPath = NSLibraryNameForModule(pythonModule); + const char* modPath = NSLibraryNameForModule(pythonModule); if (modPath != NULL) { /* We're in a framework. */ /* See if we might be in the build directory. The framework in the @@ -587,153 +693,132 @@ calculate_path(const _PyMainInterpreterConfig *config) Py_FatalError("Cannot decode framework location"); } - wcsncpy(argv0_path, wbuf, MAXPATHLEN); - reduce(argv0_path); - joinpath(argv0_path, lib_python); - joinpath(argv0_path, LANDMARK); - if (!ismodule(argv0_path)) { + wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN); + reduce(calculate->argv0_path); + joinpath(calculate->argv0_path, calculate->lib_python); + joinpath(calculate->argv0_path, LANDMARK); + if (!ismodule(calculate->argv0_path)) { /* We are in the build directory so use the name of the executable - we know that the absolute path is passed */ - wcsncpy(argv0_path, progpath, MAXPATHLEN); + wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN); } else { /* Use the location of the library as the progpath */ - wcsncpy(argv0_path, wbuf, MAXPATHLEN); + wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN); } PyMem_RawFree(wbuf); } #endif #if HAVE_READLINK - { - wchar_t tmpbuffer[MAXPATHLEN+1]; - int linklen = _Py_wreadlink(progpath, tmpbuffer, MAXPATHLEN); - while (linklen != -1) { - if (tmpbuffer[0] == SEP) - /* tmpbuffer should never be longer than MAXPATHLEN, - but extra check does not hurt */ - wcsncpy(argv0_path, tmpbuffer, MAXPATHLEN); - else { - /* Interpret relative to progpath */ - reduce(argv0_path); - joinpath(argv0_path, tmpbuffer); - } - linklen = _Py_wreadlink(argv0_path, tmpbuffer, MAXPATHLEN); + wchar_t tmpbuffer[MAXPATHLEN+1]; + int linklen = _Py_wreadlink(config->progpath, tmpbuffer, MAXPATHLEN); + while (linklen != -1) { + if (tmpbuffer[0] == SEP) { + /* tmpbuffer should never be longer than MAXPATHLEN, + but extra check does not hurt */ + wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN); } + else { + /* Interpret relative to progpath */ + reduce(calculate->argv0_path); + joinpath(calculate->argv0_path, tmpbuffer); + } + linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, MAXPATHLEN); } #endif /* HAVE_READLINK */ - reduce(argv0_path); + reduce(calculate->argv0_path); /* At this point, argv0_path is guaranteed to be less than - MAXPATHLEN bytes long. - */ + MAXPATHLEN bytes long. */ +} - /* Search for an environment configuration file, first in the - executable's directory and then in the parent directory. - If found, open it for use when searching for prefixes. - */ - { - wchar_t tmpbuffer[MAXPATHLEN+1]; - wchar_t *env_cfg = L"pyvenv.cfg"; - FILE * env_file = NULL; +/* Search for an "pyvenv.cfg" environment configuration file, first in the + executable's directory and then in the parent directory. + If found, open it for use when searching for prefixes. +*/ +static void +calculate_read_pyenv(PyCalculatePath *calculate) +{ + wchar_t tmpbuffer[MAXPATHLEN+1]; + wchar_t *env_cfg = L"pyvenv.cfg"; + FILE *env_file; - wcscpy(tmpbuffer, argv0_path); + wcscpy(tmpbuffer, calculate->argv0_path); + joinpath(tmpbuffer, env_cfg); + env_file = _Py_wfopen(tmpbuffer, L"r"); + if (env_file == NULL) { + errno = 0; + + reduce(tmpbuffer); + reduce(tmpbuffer); joinpath(tmpbuffer, env_cfg); + env_file = _Py_wfopen(tmpbuffer, L"r"); if (env_file == NULL) { errno = 0; - reduce(tmpbuffer); - reduce(tmpbuffer); - joinpath(tmpbuffer, env_cfg); - env_file = _Py_wfopen(tmpbuffer, L"r"); - if (env_file == NULL) { - errno = 0; - } - } - if (env_file != NULL) { - /* Look for a 'home' variable and set argv0_path to it, if found */ - if (find_env_config_value(env_file, L"home", tmpbuffer)) { - wcscpy(argv0_path, tmpbuffer); - } - fclose(env_file); - env_file = NULL; } } - pfound = search_for_prefix(argv0_path, home, _prefix, lib_python); - if (!pfound) { - if (!Py_FrozenFlag) - fprintf(stderr, - "Could not find platform independent libraries \n"); - wcsncpy(prefix, _prefix, MAXPATHLEN); - joinpath(prefix, lib_python); + if (env_file == NULL) { + return; } - else - reduce(prefix); - wcsncpy(zip_path, prefix, MAXPATHLEN); - zip_path[MAXPATHLEN] = L'\0'; - if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */ - reduce(zip_path); - reduce(zip_path); + /* Look for a 'home' variable and set argv0_path to it, if found */ + if (find_env_config_value(env_file, L"home", tmpbuffer)) { + wcscpy(calculate->argv0_path, tmpbuffer); } - else - wcsncpy(zip_path, _prefix, MAXPATHLEN); - joinpath(zip_path, L"lib/python00.zip"); - bufsz = wcslen(zip_path); /* Replace "00" with version */ - zip_path[bufsz - 6] = VERSION[0]; - zip_path[bufsz - 5] = VERSION[2]; + fclose(env_file); +} - efound = search_for_exec_prefix(argv0_path, home, - _exec_prefix, lib_python); - if (!efound) { - if (!Py_FrozenFlag) - fprintf(stderr, - "Could not find platform dependent libraries \n"); - wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); - joinpath(exec_prefix, L"lib/lib-dynload"); - } - /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ - if ((!pfound || !efound) && !Py_FrozenFlag) - fprintf(stderr, - "Consider setting $PYTHONHOME to [:]\n"); +static void +calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config) +{ + wcsncpy(calculate->zip_path, config->prefix, MAXPATHLEN); + calculate->zip_path[MAXPATHLEN] = L'\0'; - /* Calculate size of return buffer. - */ - bufsz = 0; - - wchar_t *env_path = NULL; - if (config) { - if (config->module_search_path_env) { - bufsz += wcslen(config->module_search_path_env) + 1; - } + if (calculate->prefix_found > 0) { + /* Use the reduced prefix returned by Py_GetPrefix() */ + reduce(calculate->zip_path); + reduce(calculate->zip_path); } else { - char *env_pathb = Py_GETENV("PYTHONPATH"); - if (env_pathb && env_pathb[0] != '\0') { - size_t env_path_len; - env_path = Py_DecodeLocale(env_pathb, &env_path_len); - /* FIXME: handle decoding and memory error */ - if (env_path != NULL) { - bufsz += env_path_len + 1; - } - } + wcsncpy(calculate->zip_path, calculate->prefix, MAXPATHLEN); + } + joinpath(calculate->zip_path, L"lib/python00.zip"); + + /* Replace "00" with version */ + size_t bufsz = wcslen(calculate->zip_path); + calculate->zip_path[bufsz - 6] = VERSION[0]; + calculate->zip_path[bufsz - 5] = VERSION[2]; +} + + +static wchar_t * +calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config) +{ + /* Calculate size of return buffer */ + size_t bufsz = 0; + if (calculate->module_search_path_env != NULL) { + bufsz += wcslen(calculate->module_search_path_env) + 1; } - defpath = _pythonpath; - prefixsz = wcslen(prefix) + 1; + wchar_t *defpath = calculate->pythonpath; + size_t prefixsz = wcslen(config->prefix) + 1; while (1) { wchar_t *delim = wcschr(defpath, DELIM); - if (defpath[0] != SEP) + if (defpath[0] != SEP) { /* Paths are relative to prefix */ bufsz += prefixsz; + } - if (delim) + if (delim) { bufsz += delim - defpath + 1; + } else { bufsz += wcslen(defpath) + 1; break; @@ -741,46 +826,40 @@ calculate_path(const _PyMainInterpreterConfig *config) defpath = delim + 1; } - bufsz += wcslen(zip_path) + 1; - bufsz += wcslen(exec_prefix) + 1; + bufsz += wcslen(calculate->zip_path) + 1; + bufsz += wcslen(config->exec_prefix) + 1; - buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t)); + /* Allocate the buffer */ + wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t)); if (buf == NULL) { Py_FatalError( "Not enough memory for dynamic PYTHONPATH"); } + buf[0] = '\0'; /* Run-time value of $PYTHONPATH goes first */ - buf[0] = '\0'; - if (config) { - if (config->module_search_path_env) { - wcscpy(buf, config->module_search_path_env); - wcscat(buf, delimiter); - } + if (calculate->module_search_path_env) { + wcscpy(buf, calculate->module_search_path_env); + wcscat(buf, delimiter); } - else { - if (env_path) { - wcscpy(buf, env_path); - wcscat(buf, delimiter); - } - } - PyMem_RawFree(env_path); /* Next is the default zip path */ - wcscat(buf, zip_path); + wcscat(buf, calculate->zip_path); wcscat(buf, delimiter); /* Next goes merge of compile-time $PYTHONPATH with * dynamically located prefix. */ - defpath = _pythonpath; + defpath = calculate->pythonpath; while (1) { wchar_t *delim = wcschr(defpath, DELIM); if (defpath[0] != SEP) { - wcscat(buf, prefix); - if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP && - defpath[0] != (delim ? DELIM : L'\0')) { /* not empty */ + wcscat(buf, config->prefix); + if (prefixsz >= 2 && config->prefix[prefixsz - 2] != SEP && + defpath[0] != (delim ? DELIM : L'\0')) + { + /* not empty */ wcscat(buf, separator); } } @@ -800,41 +879,130 @@ calculate_path(const _PyMainInterpreterConfig *config) wcscat(buf, delimiter); /* Finally, on goes the directory for dynamic-load modules */ - wcscat(buf, exec_prefix); + wcscat(buf, config->exec_prefix); - /* And publish the results */ - module_search_path = buf; + return buf; +} - /* Reduce prefix and exec_prefix to their essence, - * e.g. /usr/local/lib/python1.5 is reduced to /usr/local. - * If we're loading relative to the build directory, - * return the compiled-in defaults instead. - */ - if (pfound > 0) { - reduce(prefix); - reduce(prefix); - /* The prefix is the root directory, but reduce() chopped - * off the "/". */ - if (!prefix[0]) - wcscpy(prefix, separator); + +#define DECODE_FAILED(NAME, LEN) \ + ((LEN) == (size_t)-2) \ + ? _Py_INIT_ERR("failed to decode " #NAME) \ + : _Py_INIT_NO_MEMORY() + + +static _PyInitError +calculate_init(PyCalculatePath *calculate, + const _PyMainInterpreterConfig *main_config) +{ + _PyInitError err; + + err = _Py_GetPythonHomeWithConfig(main_config, &calculate->home); + if (_Py_INIT_FAILED(err)) { + return err; } - else - wcsncpy(prefix, _prefix, MAXPATHLEN); - if (efound > 0) { - reduce(exec_prefix); - reduce(exec_prefix); - reduce(exec_prefix); - if (!exec_prefix[0]) - wcscpy(exec_prefix, separator); + size_t len; + char *path = getenv("PATH"); + if (path) { + calculate->path_env = Py_DecodeLocale(path, &len); + if (!calculate->path_env) { + return DECODE_FAILED("PATH environment variable", len); + } } - else - wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); - PyMem_RawFree(_pythonpath); - PyMem_RawFree(_prefix); - PyMem_RawFree(_exec_prefix); - PyMem_RawFree(lib_python); + calculate->prog = Py_GetProgramName(); + + calculate->pythonpath = Py_DecodeLocale(PYTHONPATH, &len); + if (!calculate->pythonpath) { + return DECODE_FAILED("PYTHONPATH define", len); + } + calculate->prefix = Py_DecodeLocale(PREFIX, &len); + if (!calculate->prefix) { + return DECODE_FAILED("PREFIX define", len); + } + calculate->exec_prefix = Py_DecodeLocale(EXEC_PREFIX, &len); + if (!calculate->prefix) { + return DECODE_FAILED("EXEC_PREFIX define", len); + } + calculate->lib_python = Py_DecodeLocale("lib/python" VERSION, &len); + if (!calculate->lib_python) { + return DECODE_FAILED("EXEC_PREFIX define", len); + } + + calculate->module_search_path_env = NULL; + if (main_config) { + if (main_config->module_search_path_env) { + calculate->module_search_path_env = main_config->module_search_path_env; + } + + } + else { + char *pythonpath = Py_GETENV("PYTHONPATH"); + if (pythonpath && pythonpath[0] != '\0') { + calculate->module_search_path_buffer = Py_DecodeLocale(pythonpath, &len); + if (!calculate->module_search_path_buffer) { + return DECODE_FAILED("PYTHONPATH environment variable", len); + } + calculate->module_search_path_env = calculate->module_search_path_buffer; + } + } + return _Py_INIT_OK(); +} + + +static void +calculate_free(PyCalculatePath *calculate) +{ + PyMem_RawFree(calculate->pythonpath); + PyMem_RawFree(calculate->prefix); + PyMem_RawFree(calculate->exec_prefix); + PyMem_RawFree(calculate->lib_python); + PyMem_RawFree(calculate->path_env); + PyMem_RawFree(calculate->module_search_path_buffer); +} + + +static void +calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config) +{ + calculate_progpath(calculate, config); + calculate_argv0_path(calculate, config); + calculate_read_pyenv(calculate); + calculate_prefix(calculate, config); + calculate_zip_path(calculate, config); + calculate_exec_prefix(calculate, config); + + if ((!calculate->prefix_found || !calculate->exec_prefix_found) && !Py_FrozenFlag) { + fprintf(stderr, + "Consider setting $PYTHONHOME to [:]\n"); + } + + config->module_search_path = calculate_module_search_path(calculate, config); + calculate_reduce_prefix(calculate, config); + calculate_reduce_exec_prefix(calculate, config); +} + + +static void +calculate_path(const _PyMainInterpreterConfig *main_config) +{ + PyCalculatePath calculate; + memset(&calculate, 0, sizeof(calculate)); + + _PyInitError err = calculate_init(&calculate, main_config); + if (_Py_INIT_FAILED(err)) { + calculate_free(&calculate); + _Py_FatalInitError(err); + } + + PyPathConfig new_path_config; + memset(&new_path_config, 0, sizeof(new_path_config)); + + calculate_path_impl(&calculate, &new_path_config); + path_config = new_path_config; + + calculate_free(&calculate); } @@ -842,63 +1010,74 @@ calculate_path(const _PyMainInterpreterConfig *config) void Py_SetPath(const wchar_t *path) { - if (module_search_path != NULL) { - PyMem_RawFree(module_search_path); - module_search_path = NULL; + if (path_config.module_search_path != NULL) { + PyMem_RawFree(path_config.module_search_path); + path_config.module_search_path = NULL; } - if (path != NULL) { - extern wchar_t *Py_GetProgramName(void); - wchar_t *prog = Py_GetProgramName(); - wcsncpy(progpath, prog, MAXPATHLEN); - exec_prefix[0] = prefix[0] = L'\0'; - module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); - if (module_search_path != NULL) - wcscpy(module_search_path, path); + + if (path == NULL) { + return; + } + + wchar_t *prog = Py_GetProgramName(); + wcsncpy(path_config.progpath, prog, MAXPATHLEN); + path_config.exec_prefix[0] = path_config.prefix[0] = L'\0'; + path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); + if (path_config.module_search_path != NULL) { + wcscpy(path_config.module_search_path, path); } } + wchar_t * -_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) +_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config) { - if (!module_search_path) { - calculate_path(config); + if (!path_config.module_search_path) { + calculate_path(main_config); } - return module_search_path; + return path_config.module_search_path; } + wchar_t * Py_GetPath(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return module_search_path; + } + return path_config.module_search_path; } + wchar_t * Py_GetPrefix(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return prefix; + } + return path_config.prefix; } + wchar_t * Py_GetExecPrefix(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return exec_prefix; + } + return path_config.exec_prefix; } + wchar_t * Py_GetProgramFullPath(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return progpath; + } + return path_config.progpath; } - #ifdef __cplusplus } #endif diff --git a/Modules/main.c b/Modules/main.c index 07e0d2aa85c..349d8c3f323 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -36,6 +36,16 @@ extern "C" { #endif +#define SET_DECODE_ERROR(NAME, LEN) \ + do { \ + if ((LEN) == (size_t)-2) { \ + pymain->err = _Py_INIT_ERR("failed to decode " #NAME); \ + } \ + else { \ + pymain->err = _Py_INIT_NO_MEMORY(); \ + } \ + } while (0) + /* For Py_GetArgcArgv(); set by main() */ static wchar_t **orig_argv; static int orig_argc; @@ -417,9 +427,6 @@ typedef struct { .env_warning_options = {0, NULL}} -#define INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed") - - static void pymain_optlist_clear(_Py_OptList *list) { @@ -510,14 +517,14 @@ pymain_wstrdup(_PyMain *pymain, wchar_t *str) { size_t len = wcslen(str) + 1; /* +1 for NUL character */ if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return NULL; } size_t size = len * sizeof(wchar_t); wchar_t *str2 = PyMem_RawMalloc(size); if (str2 == NULL) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return NULL; } @@ -538,7 +545,7 @@ pymain_optlist_append(_PyMain *pymain, _Py_OptList *list, wchar_t *str) wchar_t **options2 = (wchar_t **)PyMem_RawRealloc(list->options, size); if (options2 == NULL) { PyMem_RawFree(str2); - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } options2[list->len] = str2; @@ -571,7 +578,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain) size_t len = wcslen(_PyOS_optarg) + 1 + 1; wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len); if (command == NULL) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } memcpy(command, _PyOS_optarg, len * sizeof(wchar_t)); @@ -717,7 +724,7 @@ pymain_add_xoptions(_PyMain *pymain) for (size_t i=0; i < options->len; i++) { wchar_t *option = options->options[i]; if (_PySys_AddXOptionWithError(option) < 0) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } } @@ -748,11 +755,11 @@ pymain_add_warnings_options(_PyMain *pymain) PySys_ResetWarnOptions(); if (pymain_add_warnings_optlist(&pymain->env_warning_options) < 0) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } if (pymain_add_warnings_optlist(&pymain->cmdline.warning_options) < 0) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } return 0; @@ -801,7 +808,7 @@ pymain_warnings_envvar(_PyMain *pymain) C89 wcstok */ buf = (char *)PyMem_RawMalloc(strlen(p) + 1); if (buf == NULL) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } strcpy(buf, p); @@ -811,13 +818,7 @@ pymain_warnings_envvar(_PyMain *pymain) size_t len; wchar_t *warning = Py_DecodeLocale(p, &len); if (warning == NULL) { - if (len == (size_t)-2) { - pymain->err = _Py_INIT_ERR("failed to decode " - "PYTHONWARNINGS"); - } - else { - pymain->err = INIT_NO_MEMORY(); - } + SET_DECODE_ERROR("PYTHONWARNINGS environment variable", len); return -1; } if (pymain_optlist_append(pymain, &pymain->env_warning_options, @@ -902,7 +903,7 @@ pymain_get_program_name(_PyMain *pymain) buffer = PyMem_RawMalloc(len * sizeof(wchar_t)); if (buffer == NULL) { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } @@ -919,15 +920,8 @@ pymain_get_program_name(_PyMain *pymain) size_t len; wchar_t* wbuf = Py_DecodeLocale(pyvenv_launcher, &len); if (wbuf == NULL) { - if (len == (size_t)-2) { - pymain->err = _Py_INIT_ERR("failed to decode " - "__PYVENV_LAUNCHER__"); - return -1; - } - else { - pymain->err = INIT_NO_MEMORY(); - return -1; - } + SET_DECODE_ERROR("__PYVENV_LAUNCHER__", len); + return -1; } pymain->program_name = wbuf; } @@ -1403,7 +1397,7 @@ pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest, return -2; } else { - pymain->err = INIT_NO_MEMORY(); + pymain->err = _Py_INIT_NO_MEMORY(); return -1; } } @@ -1421,7 +1415,7 @@ pymain_init_pythonpath(_PyMain *pymain) L"PYTHONPATH", "PYTHONPATH"); if (res < 0) { if (res == -2) { - pymain->err = _Py_INIT_ERR("failed to decode PYTHONPATH"); + SET_DECODE_ERROR("PYTHONPATH", (size_t)-2); } return -1; } @@ -1450,7 +1444,7 @@ pymain_init_pythonhome(_PyMain *pymain) L"PYTHONHOME", "PYTHONHOME"); if (res < 0) { if (res == -2) { - pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME"); + SET_DECODE_ERROR("PYTHONHOME", (size_t)-2); } return -1; } diff --git a/PC/getpathp.c b/PC/getpathp.c index 4756dc8abbb..e0cb9a25758 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -116,14 +116,34 @@ #define LANDMARK L"lib\\os.py" #endif -static wchar_t prefix[MAXPATHLEN+1]; -static wchar_t progpath[MAXPATHLEN+1]; -static wchar_t dllpath[MAXPATHLEN+1]; -static wchar_t *module_search_path = NULL; +typedef struct { + wchar_t prefix[MAXPATHLEN+1]; + wchar_t progpath[MAXPATHLEN+1]; + wchar_t dllpath[MAXPATHLEN+1]; + wchar_t *module_search_path; +} PyPathConfig; + +typedef struct { + wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ + wchar_t *path_env; /* PATH environment variable */ + wchar_t *home; /* PYTHONHOME environment variable */ + + /* Registry key "Software\Python\PythonCore\PythonPath" */ + wchar_t *machine_path; /* from HKEY_LOCAL_MACHINE */ + wchar_t *user_path; /* from HKEY_CURRENT_USER */ + + wchar_t *prog; /* Program name */ + wchar_t argv0_path[MAXPATHLEN+1]; + wchar_t zip_path[MAXPATHLEN+1]; +} PyCalculatePath; +static PyPathConfig path_config = {.module_search_path = NULL}; + + +/* determine if "ch" is a separator character */ static int -is_sep(wchar_t ch) /* determine if "ch" is a separator character */ +is_sep(wchar_t ch) { #ifdef ALTSEP return ch == SEP || ch == ALTSEP; @@ -132,28 +152,31 @@ is_sep(wchar_t ch) /* determine if "ch" is a separator character */ #endif } + /* assumes 'dir' null terminated in bounds. Never writes - beyond existing terminator. -*/ + beyond existing terminator. */ static void reduce(wchar_t *dir) { size_t i = wcsnlen_s(dir, MAXPATHLEN+1); - if (i >= MAXPATHLEN+1) + if (i >= MAXPATHLEN+1) { Py_FatalError("buffer overflow in getpathp.c's reduce()"); + } while (i > 0 && !is_sep(dir[i])) --i; dir[i] = '\0'; } + static int change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) { size_t src_len = wcsnlen_s(src, MAXPATHLEN+1); size_t i = src_len; - if (i >= MAXPATHLEN+1) + if (i >= MAXPATHLEN+1) { Py_FatalError("buffer overflow in getpathp.c's reduce()"); + } while (i > 0 && src[i] != '.' && !is_sep(src[i])) --i; @@ -163,11 +186,13 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) return -1; } - if (is_sep(src[i])) + if (is_sep(src[i])) { i = src_len; + } if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) || - wcscat_s(dest, MAXPATHLEN+1, ext)) { + wcscat_s(dest, MAXPATHLEN+1, ext)) + { dest[0] = '\0'; return -1; } @@ -175,22 +200,25 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) return 0; } + static int exists(wchar_t *filename) { return GetFileAttributesW(filename) != 0xFFFFFFFF; } -/* Assumes 'filename' MAXPATHLEN+1 bytes long - - may extend 'filename' by one character. -*/ + +/* Is module -- check for .pyc too. + Assumes 'filename' MAXPATHLEN+1 bytes long - + may extend 'filename' by one character. */ static int -ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc too */ +ismodule(wchar_t *filename, int update_filename) { size_t n; - if (exists(filename)) + if (exists(filename)) { return 1; + } /* Check for the compiled version of prefix. */ n = wcsnlen_s(filename, MAXPATHLEN+1); @@ -199,13 +227,15 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc filename[n] = L'c'; filename[n + 1] = L'\0'; exist = exists(filename); - if (!update_filename) + if (!update_filename) { filename[n] = L'\0'; + } return exist; } return 0; } + /* Add a path component, by appending stuff to buffer. buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a NUL-terminated string with no more than MAXPATHLEN characters (not counting @@ -217,7 +247,9 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc */ static int _PathCchCombineEx_Initialized = 0; -typedef HRESULT(__stdcall *PPathCchCombineEx)(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore, unsigned long dwFlags); +typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut, + PCWSTR pszPathIn, PCWSTR pszMore, + unsigned long dwFlags); static PPathCchCombineEx _PathCchCombineEx; static void @@ -225,28 +257,32 @@ join(wchar_t *buffer, const wchar_t *stuff) { if (_PathCchCombineEx_Initialized == 0) { HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll"); - if (pathapi) + if (pathapi) { _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx"); - else + } + else { _PathCchCombineEx = NULL; + } _PathCchCombineEx_Initialized = 1; } if (_PathCchCombineEx) { - if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) + if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) { Py_FatalError("buffer overflow in getpathp.c's join()"); + } } else { - if (!PathCombineW(buffer, buffer, stuff)) + if (!PathCombineW(buffer, buffer, stuff)) { Py_FatalError("buffer overflow in getpathp.c's join()"); + } } } + /* gotlandmark only called by search_for_prefix, which ensures 'prefix' is null terminated in bounds. join() ensures - 'landmark' can not overflow prefix if too long. -*/ + 'landmark' can not overflow prefix if too long. */ static int -gotlandmark(const wchar_t *landmark) +gotlandmark(wchar_t *prefix, const wchar_t *landmark) { int ok; Py_ssize_t n = wcsnlen_s(prefix, MAXPATHLEN); @@ -257,27 +293,29 @@ gotlandmark(const wchar_t *landmark) return ok; } + /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd. assumption provided by only caller, calculate_path() */ static int -search_for_prefix(wchar_t *argv0_path, const wchar_t *landmark) +search_for_prefix(wchar_t *prefix, wchar_t *argv0_path, const wchar_t *landmark) { /* Search from argv0_path, until landmark is found */ wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path); do { - if (gotlandmark(landmark)) + if (gotlandmark(prefix, landmark)) { return 1; + } reduce(prefix); } while (prefix[0]); return 0; } + #ifdef Py_ENABLE_SHARED /* a string loaded from the DLL at startup.*/ extern const char *PyWin_DLLVersionString; - /* Load a PYTHONPATH value from the registry. Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER. @@ -290,7 +328,6 @@ extern const char *PyWin_DLLVersionString; work on Win16, where the buffer sizes werent available in advance. It could be simplied now Win16/Win32s is dead! */ - static wchar_t * getpythonregpath(HKEY keyBase, int skipcore) { @@ -315,7 +352,9 @@ getpythonregpath(HKEY keyBase, int skipcore) sizeof(WCHAR)*(versionLen-1) + sizeof(keySuffix); keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen); - if (keyBuf==NULL) goto done; + if (keyBuf==NULL) { + goto done; + } memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR)); keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1; @@ -329,17 +368,25 @@ getpythonregpath(HKEY keyBase, int skipcore) 0, /* reserved */ KEY_READ, &newKey); - if (rc!=ERROR_SUCCESS) goto done; + if (rc!=ERROR_SUCCESS) { + goto done; + } /* Find out how big our core buffer is, and how many subkeys we have */ rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL, NULL, NULL, &dataSize, NULL, NULL); - if (rc!=ERROR_SUCCESS) goto done; - if (skipcore) dataSize = 0; /* Only count core ones if we want them! */ + if (rc!=ERROR_SUCCESS) { + goto done; + } + if (skipcore) { + dataSize = 0; /* Only count core ones if we want them! */ + } /* Allocate a temp array of char buffers, so we only need to loop reading the registry once */ ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys ); - if (ppPaths==NULL) goto done; + if (ppPaths==NULL) { + goto done; + } memset(ppPaths, 0, sizeof(WCHAR *) * numKeys); /* Loop over all subkeys, allocating a temp sub-buffer. */ for(index=0;indexpath_env; #ifdef Py_ENABLE_SHARED extern HANDLE PyWin_DLLhModule; /* static init of progpath ensures final char remains \0 */ - if (PyWin_DLLhModule) - if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) + if (PyWin_DLLhModule) { + if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) { dllpath[0] = 0; + } + } #else dllpath[0] = 0; #endif - if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) + if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) { return; - if (prog == NULL || *prog == '\0') - prog = L"python"; + } /* If there is no slash in the argv0 path, then we have to * assume python is on the user's $PATH, since there's no @@ -454,11 +509,13 @@ get_progpath(void) * $PATH isn't exported, you lose. */ #ifdef ALTSEP - if (wcschr(prog, SEP) || wcschr(prog, ALTSEP)) + if (wcschr(calculate->prog, SEP) || wcschr(calculate->prog, ALTSEP)) #else - if (wcschr(prog, SEP)) + if (wcschr(calculate->prog, SEP)) #endif - wcsncpy(progpath, prog, MAXPATHLEN); + { + wcsncpy(progpath, calculate->prog, MAXPATHLEN); + } else if (path) { while (1) { wchar_t *delim = wcschr(path, DELIM); @@ -470,13 +527,15 @@ get_progpath(void) wcsncpy(progpath, path, len); *(progpath + len) = '\0'; } - else + else { wcsncpy(progpath, path, MAXPATHLEN); + } /* join() is safe for MAXPATHLEN+1 size buffer */ - join(progpath, prog); - if (exists(progpath)) + join(progpath, calculate->prog); + if (exists(progpath)) { break; + } if (!delim) { progpath[0] = '\0'; @@ -485,10 +544,12 @@ get_progpath(void) path = delim + 1; } } - else + else { progpath[0] = '\0'; + } } + static int find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) { @@ -502,15 +563,18 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) PyObject * decoded; size_t n; - if (p == NULL) + if (p == NULL) { break; + } n = strlen(p); if (p[n - 1] != '\n') { /* line has overflowed - bail */ break; } - if (p[0] == '#') /* Comment - skip */ + if (p[0] == '#') { + /* Comment - skip */ continue; + } decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape"); if (decoded != NULL) { Py_ssize_t k; @@ -537,12 +601,14 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) return result; } -static int + +static wchar_t* read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) { FILE *sp_file = _Py_wfopen(path, L"r"); - if (sp_file == NULL) - return -1; + if (sp_file == NULL) { + return NULL; + } wcscpy_s(prefix, MAXPATHLEN+1, path); reduce(prefix); @@ -558,10 +624,12 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) while (!feof(sp_file)) { char line[MAXPATHLEN + 1]; char *p = fgets(line, MAXPATHLEN + 1, sp_file); - if (!p) + if (!p) { break; - if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') + } + if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') { continue; + } while (*++p) { if (*p == '\r' || *p == '\n') { *p = '\0'; @@ -611,126 +679,176 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) PyMem_RawFree(wline); } - module_search_path = buf; - fclose(sp_file); - return 0; + return buf; error: PyMem_RawFree(buf); fclose(sp_file); - return -1; + return NULL; } -static void -calculate_path(const _PyMainInterpreterConfig *config) +static _PyInitError +calculate_init(PyCalculatePath *calculate, + const _PyMainInterpreterConfig *main_config) { - wchar_t argv0_path[MAXPATHLEN+1]; - wchar_t *buf; - size_t bufsz; - wchar_t *pythonhome = _Py_GetPythonHomeWithConfig(config); - wchar_t *envpath = NULL; + _PyInitError err; - int skiphome, skipdefault; - wchar_t *machinepath = NULL; - wchar_t *userpath = NULL; - wchar_t zip_path[MAXPATHLEN+1]; + err = _Py_GetPythonHomeWithConfig(main_config, &calculate->home); + if (_Py_INIT_FAILED(err)) { + return err; + } - if (config) { - envpath = config->module_search_path_env; + if (main_config) { + calculate->module_search_path_env = main_config->module_search_path_env; } else if (!Py_IgnoreEnvironmentFlag) { - envpath = _wgetenv(L"PYTHONPATH"); - if (envpath && *envpath == '\0') - envpath = NULL; - } - - get_progpath(); - /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ - wcscpy_s(argv0_path, MAXPATHLEN+1, progpath); - reduce(argv0_path); - - /* Search for a sys.path file */ - { - wchar_t spbuffer[MAXPATHLEN+1]; - - if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) || - (progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) { - - if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) { - return; - } + wchar_t *path = _wgetenv(L"PYTHONPATH"); + if (path && *path != '\0') { + calculate->module_search_path_env = path; } } - /* Search for an environment configuration file, first in the - executable's directory and then in the parent directory. - If found, open it for use when searching for prefixes. - */ + calculate->path_env = _wgetenv(L"PATH"); - { - wchar_t envbuffer[MAXPATHLEN+1]; - wchar_t tmpbuffer[MAXPATHLEN+1]; - const wchar_t *env_cfg = L"pyvenv.cfg"; - FILE * env_file = NULL; + wchar_t *prog = Py_GetProgramName(); + if (prog == NULL || *prog == '\0') { + prog = L"python"; + } + calculate->prog = prog; - wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path); + return _Py_INIT_OK(); +} + + +static int +get_pth_filename(wchar_t *spbuffer, PyPathConfig *config) +{ + if (config->dllpath[0]) { + if (!change_ext(spbuffer, config->dllpath, L"._pth") && exists(spbuffer)) { + return 1; + } + } + if (config->progpath[0]) { + if (!change_ext(spbuffer, config->progpath, L"._pth") && exists(spbuffer)) { + return 1; + } + } + return 0; +} + + +static int +calculate_pth_file(PyPathConfig *config) +{ + wchar_t spbuffer[MAXPATHLEN+1]; + + if (!get_pth_filename(spbuffer, config)) { + return 0; + } + + config->module_search_path = read_pth_file(spbuffer, config->prefix, + &Py_IsolatedFlag, + &Py_NoSiteFlag); + if (!config->module_search_path) { + return 0; + } + return 1; +} + + +/* Search for an environment configuration file, first in the + executable's directory and then in the parent directory. + If found, open it for use when searching for prefixes. +*/ +static void +calculate_pyvenv_file(PyCalculatePath *calculate) +{ + wchar_t envbuffer[MAXPATHLEN+1]; + const wchar_t *env_cfg = L"pyvenv.cfg"; + + wcscpy_s(envbuffer, MAXPATHLEN+1, calculate->argv0_path); + join(envbuffer, env_cfg); + + FILE *env_file = _Py_wfopen(envbuffer, L"r"); + if (env_file == NULL) { + errno = 0; + reduce(envbuffer); + reduce(envbuffer); join(envbuffer, env_cfg); env_file = _Py_wfopen(envbuffer, L"r"); if (env_file == NULL) { errno = 0; - reduce(envbuffer); - reduce(envbuffer); - join(envbuffer, env_cfg); - env_file = _Py_wfopen(envbuffer, L"r"); - if (env_file == NULL) { - errno = 0; - } - } - if (env_file != NULL) { - /* Look for a 'home' variable and set argv0_path to it, if found */ - if (find_env_config_value(env_file, L"home", tmpbuffer)) { - wcscpy_s(argv0_path, MAXPATHLEN+1, tmpbuffer); - } - fclose(env_file); - env_file = NULL; } } + if (env_file == NULL) { + return; + } + + /* Look for a 'home' variable and set argv0_path to it, if found */ + wchar_t tmpbuffer[MAXPATHLEN+1]; + if (find_env_config_value(env_file, L"home", tmpbuffer)) { + wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, tmpbuffer); + } + fclose(env_file); +} + + +static void +calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config, + const _PyMainInterpreterConfig *main_config) +{ + get_progpath(calculate, config->progpath, config->dllpath); + /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ + wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->progpath); + reduce(calculate->argv0_path); + + /* Search for a sys.path file */ + if (calculate_pth_file(config)) { + return; + } + + calculate_pyvenv_file(calculate); + /* Calculate zip archive path from DLL or exe path */ - change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip"); + change_ext(calculate->zip_path, + config->dllpath[0] ? config->dllpath : config->progpath, + L".zip"); - if (pythonhome == NULL || *pythonhome == '\0') { - if (zip_path[0] && exists(zip_path)) { - wcscpy_s(prefix, MAXPATHLEN+1, zip_path); - reduce(prefix); - pythonhome = prefix; - } else if (search_for_prefix(argv0_path, LANDMARK)) - pythonhome = prefix; - else - pythonhome = NULL; + if (calculate->home == NULL || *calculate->home == '\0') { + if (calculate->zip_path[0] && exists(calculate->zip_path)) { + wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->zip_path); + reduce(config->prefix); + calculate->home = config->prefix; + } else if (search_for_prefix(config->prefix, calculate->argv0_path, LANDMARK)) { + calculate->home = config->prefix; + } + else { + calculate->home = NULL; + } + } + else { + wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->home); } - else - wcscpy_s(prefix, MAXPATHLEN+1, pythonhome); - - skiphome = pythonhome==NULL ? 0 : 1; + int skiphome = calculate->home==NULL ? 0 : 1; #ifdef Py_ENABLE_SHARED - machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); - userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome); + calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); + calculate->user_path = getpythonregpath(HKEY_CURRENT_USER, skiphome); #endif /* We only use the default relative PYTHONPATH if we haven't anything better to use! */ - skipdefault = envpath!=NULL || pythonhome!=NULL || \ - machinepath!=NULL || userpath!=NULL; + int skipdefault = (calculate->module_search_path_env!=NULL || calculate->home!=NULL || \ + calculate->machine_path!=NULL || calculate->user_path!=NULL); /* We need to construct a path from the following parts. (1) the PYTHONPATH environment variable, if set; (2) for Win32, the zip archive file path; - (3) for Win32, the machinepath and userpath, if set; + (3) for Win32, the machine_path and user_path, if set; (4) the PYTHONPATH config macro, with the leading "." - of each component replaced with pythonhome, if set; + of each component replaced with home, if set; (5) the directory containing the executable (argv0_path). The length calculation calculates #4 first. Extra rules: @@ -739,74 +857,80 @@ calculate_path(const _PyMainInterpreterConfig *config) */ /* Calculate size of return buffer */ - if (pythonhome != NULL) { + size_t bufsz = 0; + if (calculate->home != NULL) { wchar_t *p; bufsz = 1; for (p = PYTHONPATH; *p; p++) { - if (*p == DELIM) + if (*p == DELIM) { bufsz++; /* number of DELIM plus one */ + } } - bufsz *= wcslen(pythonhome); + bufsz *= wcslen(calculate->home); } - else - bufsz = 0; bufsz += wcslen(PYTHONPATH) + 1; - bufsz += wcslen(argv0_path) + 1; - if (userpath) - bufsz += wcslen(userpath) + 1; - if (machinepath) - bufsz += wcslen(machinepath) + 1; - bufsz += wcslen(zip_path) + 1; - if (envpath != NULL) - bufsz += wcslen(envpath) + 1; + bufsz += wcslen(calculate->argv0_path) + 1; + if (calculate->user_path) { + bufsz += wcslen(calculate->user_path) + 1; + } + if (calculate->machine_path) { + bufsz += wcslen(calculate->machine_path) + 1; + } + bufsz += wcslen(calculate->zip_path) + 1; + if (calculate->module_search_path_env != NULL) { + bufsz += wcslen(calculate->module_search_path_env) + 1; + } - module_search_path = buf = PyMem_RawMalloc(bufsz*sizeof(wchar_t)); + wchar_t *buf, *start_buf; + buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t)); if (buf == NULL) { /* We can't exit, so print a warning and limp along */ fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n"); - if (envpath) { + if (calculate->module_search_path_env) { fprintf(stderr, "Using environment $PYTHONPATH.\n"); - module_search_path = envpath; + config->module_search_path = calculate->module_search_path_env; } else { fprintf(stderr, "Using default static path.\n"); - module_search_path = PYTHONPATH; + config->module_search_path = PYTHONPATH; } - PyMem_RawFree(machinepath); - PyMem_RawFree(userpath); return; } + start_buf = buf; - if (envpath) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), envpath)) + if (calculate->module_search_path_env) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->module_search_path_env)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; } - if (zip_path[0]) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), zip_path)) + if (calculate->zip_path[0]) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; } - if (userpath) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), userpath)) + if (calculate->user_path) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; - PyMem_RawFree(userpath); } - if (machinepath) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), machinepath)) + if (calculate->machine_path) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; - PyMem_RawFree(machinepath); } - if (pythonhome == NULL) { + if (calculate->home == NULL) { if (!skipdefault) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), PYTHONPATH)) + if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; } @@ -816,13 +940,16 @@ calculate_path(const _PyMainInterpreterConfig *config) size_t n; for (;;) { q = wcschr(p, DELIM); - if (q == NULL) + if (q == NULL) { n = wcslen(p); - else + } + else { n = q-p; + } if (p[0] == '.' && is_sep(p[1])) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), pythonhome)) + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); p++; n--; @@ -830,17 +957,19 @@ calculate_path(const _PyMainInterpreterConfig *config) wcsncpy(buf, p, n); buf += n; *buf++ = DELIM; - if (q == NULL) + if (q == NULL) { break; + } p = q+1; } } - if (argv0_path) { - wcscpy(buf, argv0_path); + if (calculate->argv0_path) { + wcscpy(buf, calculate->argv0_path); buf = wcschr(buf, L'\0'); *buf++ = DELIM; } *(buf - 1) = L'\0'; + /* Now to pull one last hack/trick. If sys.prefix is empty, then try and find it somewhere on the paths we calculated. We scan backwards, as our general policy @@ -849,7 +978,7 @@ calculate_path(const _PyMainInterpreterConfig *config) on the path, and that our 'prefix' directory is the parent of that. */ - if (*prefix==L'\0') { + if (config->prefix[0] == L'\0') { wchar_t lookBuf[MAXPATHLEN+1]; wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */ while (1) { @@ -859,84 +988,129 @@ calculate_path(const _PyMainInterpreterConfig *config) start of the path in question - even if this is one character before the start of the buffer */ - while (look >= module_search_path && *look != DELIM) + while (look >= start_buf && *look != DELIM) look--; nchars = lookEnd-look; wcsncpy(lookBuf, look+1, nchars); lookBuf[nchars] = L'\0'; /* Up one level to the parent */ reduce(lookBuf); - if (search_for_prefix(lookBuf, LANDMARK)) { + if (search_for_prefix(config->prefix, lookBuf, LANDMARK)) { break; } /* If we are out of paths to search - give up */ - if (look < module_search_path) + if (look < start_buf) { break; + } look--; } } + + config->module_search_path = start_buf; } +static void +calculate_free(PyCalculatePath *calculate) +{ + PyMem_RawFree(calculate->machine_path); + PyMem_RawFree(calculate->user_path); +} + +static void +calculate_path(const _PyMainInterpreterConfig *main_config) +{ + PyCalculatePath calculate; + memset(&calculate, 0, sizeof(calculate)); + + _PyInitError err = calculate_init(&calculate, main_config); + if (_Py_INIT_FAILED(err)) { + calculate_free(&calculate); + _Py_FatalInitError(err); + } + + PyPathConfig new_path_config; + memset(&new_path_config, 0, sizeof(new_path_config)); + + calculate_path_impl(&calculate, &new_path_config, main_config); + path_config = new_path_config; + + calculate_free(&calculate); +} + + + /* External interface */ void Py_SetPath(const wchar_t *path) { - if (module_search_path != NULL) { - PyMem_RawFree(module_search_path); - module_search_path = NULL; + if (path_config.module_search_path != NULL) { + PyMem_RawFree(path_config.module_search_path); + path_config.module_search_path = NULL; } - if (path != NULL) { - extern wchar_t *Py_GetProgramName(void); - wchar_t *prog = Py_GetProgramName(); - wcsncpy(progpath, prog, MAXPATHLEN); - prefix[0] = L'\0'; - module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); - if (module_search_path != NULL) - wcscpy(module_search_path, path); + + if (path == NULL) { + return; + } + + wchar_t *prog = Py_GetProgramName(); + wcsncpy(path_config.progpath, prog, MAXPATHLEN); + path_config.prefix[0] = L'\0'; + path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); + if (path_config.module_search_path != NULL) { + wcscpy(path_config.module_search_path, path); } } + wchar_t * -_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) +_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config) { - if (!module_search_path) { - calculate_path(config); + if (!path_config.module_search_path) { + calculate_path(main_config); } - return module_search_path; + return path_config.module_search_path; } + wchar_t * Py_GetPath(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return module_search_path; + } + return path_config.module_search_path; } + wchar_t * Py_GetPrefix(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return prefix; + } + return path_config.prefix; } + wchar_t * Py_GetExecPrefix(void) { return Py_GetPrefix(); } + wchar_t * Py_GetProgramFullPath(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return progpath; + } + return path_config.progpath; } + /* Load python3.dll before loading any extension module that might refer to it. That way, we can be sure that always the python3.dll corresponding to this python DLL is loaded, not a python3.dll that might be on the path @@ -950,20 +1124,23 @@ _Py_CheckPython3() { wchar_t py3path[MAXPATHLEN+1]; wchar_t *s; - if (python3_checked) + if (python3_checked) { return hPython3 != NULL; + } python3_checked = 1; /* If there is a python3.dll next to the python3y.dll, assume this is a build tree; use that DLL */ - wcscpy(py3path, dllpath); + wcscpy(py3path, path_config.dllpath); s = wcsrchr(py3path, L'\\'); - if (!s) + if (!s) { s = py3path; + } wcscpy(s, L"\\python3.dll"); hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (hPython3 != NULL) + if (hPython3 != NULL) { return 1; + } /* Check sys.prefix\DLLs\python3.dll */ wcscpy(py3path, Py_GetPrefix()); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5bbbbc68f08..8d2ec4e91c3 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1477,8 +1477,9 @@ Py_SetPythonHome(wchar_t *home) default_home = home; } -wchar_t * -_Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config) + +_PyInitError +_Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config, wchar_t **homep) { /* Use a static buffer to avoid heap memory allocation failure. Py_GetPythonHome() doesn't allow to report error, and the caller @@ -1486,32 +1487,40 @@ _Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config) static wchar_t buffer[MAXPATHLEN+1]; if (default_home) { - return default_home; + *homep = default_home; + return _Py_INIT_OK(); } if (config) { - return config->pythonhome; + *homep = config->pythonhome; + return _Py_INIT_OK(); } char *home = Py_GETENV("PYTHONHOME"); if (!home) { - return NULL; + *homep = NULL; + return _Py_INIT_OK(); } size_t size = Py_ARRAY_LENGTH(buffer); size_t r = mbstowcs(buffer, home, size); if (r == (size_t)-1 || r >= size) { /* conversion failed or the static buffer is too small */ - return NULL; + *homep = NULL; + return _Py_INIT_ERR("failed to decode PYTHONHOME environment variable"); } - return buffer; + *homep = buffer; + return _Py_INIT_OK(); } wchar_t * Py_GetPythonHome(void) { - return _Py_GetPythonHomeWithConfig(NULL); + wchar_t *home; + /* Ignore error */ + (void)_Py_GetPythonHomeWithConfig(NULL, &home); + return home; } /* Add the __main__ module */