summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-23 17:03:20 +0100
committerGitHub <noreply@github.com>2017-11-23 17:03:20 +0100
commit0327bde9da203bb256b58218d012ca76ad0db4e4 (patch)
treea54c0feb235156b9c01db641ebbf18f0a695ad56
parentbdb8315c21825487b54852ff0511fb4881ea2181 (diff)
downloadcpython-git-0327bde9da203bb256b58218d012ca76ad0db4e4.tar.gz
bpo-32030: Rewrite calculate_path() (#4521)
* calculate_path() rewritten in Modules/getpath.c and PC/getpathp.c * Move global variables into a new PyPathConfig structure. * calculate_path(): * Split the huge calculate_path() function into subfunctions. * Add PyCalculatePath structure to pass data between subfunctions. * Document PyCalculatePath fields. * Move cleanup code into a new calculate_free() subfunction * calculate_init() now handles Py_DecodeLocale() failures properly * calculate_path() is now atomic: only replace PyPathConfig (path_config) at once on success. * _Py_GetPythonHomeWithConfig() now returns an error on failure * Add _Py_INIT_NO_MEMORY() helper: report a memory allocation failure * Coding style fixes (PEP 7)
-rw-r--r--Include/pylifecycle.h38
-rw-r--r--Modules/getpath.c855
-rw-r--r--Modules/main.c56
-rw-r--r--PC/getpathp.c593
-rw-r--r--Python/pylifecycle.c25
5 files changed, 966 insertions, 601 deletions
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h
index 3b603c87ad..efdc58eed8 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 62f5e69584..d8125ae2ca 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -7,7 +7,7 @@
#include <string.h>
#ifdef __APPLE__
-#include <mach-o/dyld.h>
+# include <mach-o/dyld.h>
#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. */
+/* 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 <prefix>\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,87 +527,85 @@ 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)
+calculate_exec_prefix(PyCalculatePath *calculate, PyPathConfig *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
-#ifdef __APPLE__
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
- uint32_t nsexeclength = MAXPATHLEN;
-#else
- unsigned long nsexeclength = MAXPATHLEN;
-#endif
- char execpath[MAXPATHLEN+1];
-#endif
- wchar_t *_pythonpath, *_prefix, *_exec_prefix;
- wchar_t *lib_python;
+ 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 <exec_prefix>\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.) */
+}
- _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");
+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);
+ }
}
-
- if (_path) {
- path_buffer = Py_DecodeLocale(_path, NULL);
- path = path_buffer;
+ 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(prog, SEP))
- wcsncpy(progpath, prog, MAXPATHLEN);
+ 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;
+#else
+ unsigned long nsexeclength = MAXPATHLEN;
+#endif
+ char execpath[MAXPATHLEN+1];
+
/* 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, calculate->argv0_path);
- wcscpy(tmpbuffer, 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 <prefix>\n");
- wcsncpy(prefix, _prefix, MAXPATHLEN);
- joinpath(prefix, lib_python);
- }
- 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);
- }
- 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];
-
- 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 <exec_prefix>\n");
- wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
- joinpath(exec_prefix, L"lib/lib-dynload");
+ if (env_file == NULL) {
+ return;
}
- /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
- if ((!pfound || !efound) && !Py_FrozenFlag)
- fprintf(stderr,
- "Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
+ /* 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);
+ }
+ fclose(env_file);
+}
- /* 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;
- }
+static void
+calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config)
+{
+ wcsncpy(calculate->zip_path, config->prefix, MAXPATHLEN);
+ calculate->zip_path[MAXPATHLEN] = L'\0';
+
+ 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];
+}
- defpath = _pythonpath;
- prefixsz = wcslen(prefix) + 1;
+
+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;
+ }
+
+ 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);
- }
- }
- else {
- if (env_path) {
- wcscpy(buf, env_path);
- wcscat(buf, delimiter);
- }
+ if (calculate->module_search_path_env) {
+ wcscpy(buf, calculate->module_search_path_env);
+ 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;
+ }
+
+ 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);
+ }
+ }
+
+ 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);
}
- 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);
+ 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;
+ }
}
- else
- wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
+ return _Py_INIT_OK();
+}
+
- PyMem_RawFree(_pythonpath);
- PyMem_RawFree(_prefix);
- PyMem_RawFree(_exec_prefix);
- PyMem_RawFree(lib_python);
+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 <prefix>[:<exec_prefix>]\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 07e0d2aa85..349d8c3f32 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 4756dc8abb..e0cb9a2575 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;index<numKeys;index++) {
@@ -349,14 +396,18 @@ getpythonregpath(HKEY keyBase, int skipcore)
/* Get the sub-key name */
DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
NULL, NULL, NULL, NULL );
- if (rc!=ERROR_SUCCESS) goto done;
+ if (rc!=ERROR_SUCCESS) {
+ goto done;
+ }
/* Open the sub-key */
rc=RegOpenKeyExW(newKey,
keyBuf, /* subkey */
0, /* reserved */
KEY_READ,
&subKey);
- if (rc!=ERROR_SUCCESS) goto done;
+ if (rc!=ERROR_SUCCESS) {
+ goto done;
+ }
/* Find the value of the buffer size, malloc, then read it */
RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
if (reqdSize) {
@@ -372,7 +423,9 @@ getpythonregpath(HKEY keyBase, int skipcore)
}
/* return null if no path to return */
- if (dataSize == 0) goto done;
+ if (dataSize == 0) {
+ goto done;
+ }
/* original datasize from RegQueryInfo doesn't include the \0 */
dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
@@ -392,8 +445,9 @@ getpythonregpath(HKEY keyBase, int skipcore)
dataSize -= (DWORD)len;
}
}
- if (skipcore)
+ if (skipcore) {
*szCur = '\0';
+ }
else {
/* If we have no values, we don't need a ';' */
if (numKeys) {
@@ -420,33 +474,34 @@ done:
PyMem_RawFree(ppPaths[index]);
PyMem_RawFree(ppPaths);
}
- if (newKey)
+ if (newKey) {
RegCloseKey(newKey);
+ }
PyMem_RawFree(keyBuf);
return retval;
}
#endif /* Py_ENABLE_SHARED */
+
static void
-get_progpath(void)
+get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath)
{
- extern wchar_t *Py_GetProgramName(void);
- wchar_t *path = _wgetenv(L"PATH");
- wchar_t *prog = Py_GetProgramName();
+ wchar_t *path = calculate->path_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;
-
- int skiphome, skipdefault;
- wchar_t *machinepath = NULL;
- wchar_t *userpath = NULL;
- wchar_t zip_path[MAXPATHLEN+1];
+ _PyInitError err;
- if (config) {
- envpath = config->module_search_path_env;
+ err = _Py_GetPythonHomeWithConfig(main_config, &calculate->home);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ 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;
+ wchar_t *path = _wgetenv(L"PYTHONPATH");
+ if (path && *path != '\0') {
+ calculate->module_search_path_env = path;
+ }
}
- get_progpath();
- /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
- wcscpy_s(argv0_path, MAXPATHLEN+1, progpath);
- reduce(argv0_path);
+ calculate->path_env = _wgetenv(L"PATH");
- /* Search for a sys.path file */
- {
- wchar_t spbuffer[MAXPATHLEN+1];
+ wchar_t *prog = Py_GetProgramName();
+ if (prog == NULL || *prog == '\0') {
+ prog = L"python";
+ }
+ calculate->prog = prog;
- if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) ||
- (progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) {
+ return _Py_INIT_OK();
+}
- if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) {
- return;
- }
+
+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;
+}
- /* 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 envbuffer[MAXPATHLEN+1];
- wchar_t tmpbuffer[MAXPATHLEN+1];
- const wchar_t *env_cfg = L"pyvenv.cfg";
- FILE * env_file = NULL;
+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);
- wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path);
+ 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;
}
}
- /* Calculate zip archive path from DLL or exe path */
- change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip");
+ if (env_file == NULL) {
+ return;
+ }
- 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;
+ /* 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);
}
- else
- wcscpy_s(prefix, MAXPATHLEN+1, pythonhome);
+ fclose(env_file);
+}
- skiphome = pythonhome==NULL ? 0 : 1;
+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(calculate->zip_path,
+ config->dllpath[0] ? config->dllpath : config->progpath,
+ L".zip");
+
+ 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);
+ }
+
+ 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;
-
- module_search_path = buf = PyMem_RawMalloc(bufsz*sizeof(wchar_t));
+ 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;
+ }
+
+ 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 != 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_config.module_search_path != NULL) {
+ PyMem_RawFree(path_config.module_search_path);
+ path_config.module_search_path = NULL;
+ }
+
+ 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 5bbbbc68f0..8d2ec4e91c 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 */