summaryrefslogtreecommitdiffstats
path: root/Modules/getpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/getpath.c')
-rw-r--r--Modules/getpath.c223
1 files changed, 109 insertions, 114 deletions
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 112d6d3..b7f9573 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -48,7 +48,7 @@
* argv0_path. For prefix, the landmark's path is derived from the VPATH
* preprocessor variable (taking into account that its value is almost, but
* not quite, what we need). For exec_prefix, the landmark is
- * Modules/Setup. If the landmark is found, we're done.
+ * pybuilddir.txt. If the landmark is found, we're done.
*
* For the remaining steps, the prefix landmark will always be
* lib/python$VERSION/os.py and the exec_prefix will always be
@@ -90,6 +90,9 @@
* known use of sys.prefix and sys.exec_prefix is for the ILU installation
* process to find the installed Python tree.
*
+ * An embedding application can use Py_SetPath() to override all of
+ * these authomatic path computations.
+ *
* NOTE: Windows MSVC builds use PC/getpathp.c instead!
*/
@@ -131,73 +134,8 @@ 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;
-static wchar_t lib_python[] = L"lib/python" VERSION;
-
-/* In principle, this should use HAVE__WSTAT, and _wstat
- should be detected by autoconf. However, no current
- POSIX system provides that function, so testing for
- it is pointless.
- Not sure whether the MS_WINDOWS guards are necessary:
- perhaps for cygwin/mingw builds?
-*/
-#ifndef MS_WINDOWS
-static int
-_wstat(const wchar_t* path, struct stat *buf)
-{
- char fname[PATH_MAX];
- size_t res = wcstombs(fname, path, sizeof(fname));
- if (res == (size_t)-1) {
- errno = EINVAL;
- return -1;
- }
- return stat(fname, buf);
-}
-#endif
-
-#ifndef MS_WINDOWS
-static wchar_t*
-_wgetcwd(wchar_t *buf, size_t size)
-{
- char fname[PATH_MAX];
- if (getcwd(fname, PATH_MAX) == NULL)
- return NULL;
- if (mbstowcs(buf, fname, size) >= size) {
- errno = ERANGE;
- return NULL;
- }
- return buf;
-}
-#endif
-
-#ifdef HAVE_READLINK
-int
-_Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz)
-{
- char cbuf[PATH_MAX];
- char cpath[PATH_MAX];
- int res;
- size_t r1 = wcstombs(cpath, path, PATH_MAX);
- if (r1 == (size_t)-1 || r1 >= PATH_MAX) {
- errno = EINVAL;
- return -1;
- }
- res = (int)readlink(cpath, cbuf, PATH_MAX);
- if (res == -1)
- return -1;
- if (res == PATH_MAX) {
- errno = EINVAL;
- return -1;
- }
- cbuf[res] = '\0'; /* buf will be null terminated */
- r1 = mbstowcs(buf, cbuf, bufsiz);
- if (r1 == -1) {
- errno = EINVAL;
- return -1;
- }
- return (int)r1;
-
-}
-#endif
+static int module_search_path_malloced = 0;
+static wchar_t *lib_python = L"lib/python" VERSION;
static void
reduce(wchar_t *dir)
@@ -208,12 +146,11 @@ reduce(wchar_t *dir)
dir[i] = '\0';
}
-
static int
isfile(wchar_t *filename) /* Is file, not directory */
{
struct stat buf;
- if (_wstat(filename, &buf) != 0)
+ if (_Py_wstat(filename, &buf) != 0)
return 0;
if (!S_ISREG(buf.st_mode))
return 0;
@@ -241,7 +178,7 @@ static int
isxfile(wchar_t *filename) /* Is executable file */
{
struct stat buf;
- if (_wstat(filename, &buf) != 0)
+ if (_Py_wstat(filename, &buf) != 0)
return 0;
if (!S_ISREG(buf.st_mode))
return 0;
@@ -255,7 +192,7 @@ static int
isdir(wchar_t *filename) /* Is directory */
{
struct stat buf;
- if (_wstat(filename, &buf) != 0)
+ if (_Py_wstat(filename, &buf) != 0)
return 0;
if (!S_ISDIR(buf.st_mode))
return 0;
@@ -295,12 +232,12 @@ joinpath(wchar_t *buffer, wchar_t *stuff)
/* 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)
+copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen)
{
if (p[0] == SEP)
wcscpy(path, p);
else {
- if (!_wgetcwd(path, MAXPATHLEN)) {
+ if (!_Py_wgetcwd(path, pathlen)) {
/* unable to get the current directory */
wcscpy(path, p);
return;
@@ -315,11 +252,11 @@ copy_absolute(wchar_t *path, wchar_t *p)
static void
absolutize(wchar_t *path)
{
- wchar_t buffer[MAXPATHLEN + 1];
+ wchar_t buffer[MAXPATHLEN+1];
if (path[0] == SEP)
return;
- copy_absolute(buffer, path);
+ copy_absolute(buffer, path, MAXPATHLEN+1);
wcscpy(path, buffer);
}
@@ -327,7 +264,7 @@ absolutize(wchar_t *path)
bytes long.
*/
static int
-search_for_prefix(wchar_t *argv0_path, wchar_t *home)
+search_for_prefix(wchar_t *argv0_path, wchar_t *home, wchar_t *_prefix)
{
size_t n;
wchar_t *vpath;
@@ -349,17 +286,20 @@ search_for_prefix(wchar_t *argv0_path, wchar_t *home)
joinpath(prefix, L"Modules/Setup");
if (isfile(prefix)) {
/* Check VPATH to see if argv0_path is in the build directory. */
- vpath = L"" VPATH;
- wcscpy(prefix, argv0_path);
- joinpath(prefix, vpath);
- joinpath(prefix, L"Lib");
- joinpath(prefix, LANDMARK);
- if (ismodule(prefix))
- return -1;
+ vpath = _Py_char2wchar(VPATH, NULL);
+ if (vpath != NULL) {
+ wcscpy(prefix, argv0_path);
+ joinpath(prefix, vpath);
+ PyMem_Free(vpath);
+ joinpath(prefix, L"Lib");
+ joinpath(prefix, LANDMARK);
+ if (ismodule(prefix))
+ return -1;
+ }
}
/* Search from argv0_path, until root is found */
- copy_absolute(prefix, argv0_path);
+ copy_absolute(prefix, argv0_path, MAXPATHLEN+1);
do {
n = wcslen(prefix);
joinpath(prefix, lib_python);
@@ -371,7 +311,7 @@ search_for_prefix(wchar_t *argv0_path, wchar_t *home)
} while (prefix[0]);
/* Look at configure's PREFIX */
- wcsncpy(prefix, L"" PREFIX, MAXPATHLEN);
+ wcsncpy(prefix, _prefix, MAXPATHLEN);
joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK);
if (ismodule(prefix))
@@ -386,7 +326,7 @@ search_for_prefix(wchar_t *argv0_path, wchar_t *home)
MAXPATHLEN bytes long.
*/
static int
-search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home)
+search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, wchar_t *_exec_prefix)
{
size_t n;
@@ -403,16 +343,40 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home)
return 1;
}
- /* Check to see if argv[0] is in the build directory */
+ /* 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. */
wcscpy(exec_prefix, argv0_path);
- joinpath(exec_prefix, L"Modules/Setup");
+ joinpath(exec_prefix, L"pybuilddir.txt");
if (isfile(exec_prefix)) {
- reduce(exec_prefix);
- return -1;
+ FILE *f = _Py_wfopen(exec_prefix, L"rb");
+ if (f == NULL)
+ errno = 0;
+ else {
+ char buf[MAXPATHLEN+1];
+ PyObject *decoded;
+ wchar_t rel_builddir_path[MAXPATHLEN+1];
+ n = fread(buf, 1, MAXPATHLEN, f);
+ buf[n] = '\0';
+ fclose(f);
+ decoded = PyUnicode_DecodeUTF8(buf, n, "surrogateescape");
+ if (decoded != NULL) {
+ Py_ssize_t k;
+ k = PyUnicode_AsWideChar(decoded,
+ rel_builddir_path, MAXPATHLEN);
+ Py_DECREF(decoded);
+ if (k >= 0) {
+ rel_builddir_path[k] = L'\0';
+ wcscpy(exec_prefix, argv0_path);
+ joinpath(exec_prefix, rel_builddir_path);
+ return -1;
+ }
+ }
+ }
}
/* Search from argv0_path, until root is found */
- copy_absolute(exec_prefix, argv0_path);
+ copy_absolute(exec_prefix, argv0_path, MAXPATHLEN+1);
do {
n = wcslen(exec_prefix);
joinpath(exec_prefix, lib_python);
@@ -424,7 +388,7 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home)
} while (exec_prefix[0]);
/* Look at configure's EXEC_PREFIX */
- wcsncpy(exec_prefix, L"" EXEC_PREFIX, MAXPATHLEN);
+ wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, L"lib-dynload");
if (isdir(exec_prefix))
@@ -434,7 +398,6 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home)
return 0;
}
-
static void
calculate_path(void)
{
@@ -442,12 +405,11 @@ calculate_path(void)
static wchar_t delimiter[2] = {DELIM, '\0'};
static wchar_t separator[2] = {SEP, '\0'};
- wchar_t *pythonpath = L"" PYTHONPATH;
char *_rtpypath = Py_GETENV("PYTHONPATH"); /* XXX use wide version on Windows */
wchar_t rtpypath[MAXPATHLEN+1];
wchar_t *home = Py_GetPythonHome();
char *_path = getenv("PATH");
- wchar_t wpath[MAXPATHLEN+1];
+ wchar_t *path_buffer = NULL;
wchar_t *path = NULL;
wchar_t *prog = Py_GetProgramName();
wchar_t argv0_path[MAXPATHLEN+1];
@@ -456,7 +418,7 @@ calculate_path(void)
wchar_t *buf;
size_t bufsz;
size_t prefixsz;
- wchar_t *defpath = pythonpath;
+ wchar_t *defpath;
#ifdef WITH_NEXT_FRAMEWORK
NSModule pythonModule;
#endif
@@ -466,16 +428,23 @@ calculate_path(void)
#else
unsigned long nsexeclength = MAXPATHLEN;
#endif
- char execpath[MAXPATHLEN+1];
+ char execpath[MAXPATHLEN+1];
#endif
+ wchar_t *_pythonpath, *_prefix, *_exec_prefix;
+
+ _pythonpath = _Py_char2wchar(PYTHONPATH, NULL);
+ _prefix = _Py_char2wchar(PREFIX, NULL);
+ _exec_prefix = _Py_char2wchar(EXEC_PREFIX, NULL);
+
+ if (!_pythonpath || !_prefix || !_exec_prefix) {
+ Py_FatalError(
+ "Unable to decode path variables in getpath.c: "
+ "memory error");
+ }
if (_path) {
- size_t r = mbstowcs(wpath, _path, MAXPATHLEN+1);
- path = wpath;
- if (r == (size_t)-1 || r > MAXPATHLEN) {
- /* Could not convert PATH, or it's too long. */
- path = NULL;
- }
+ path_buffer = _Py_char2wchar(_path, NULL);
+ path = path_buffer;
}
/* If there is no slash in the argv0 path, then we have to
@@ -531,6 +500,8 @@ calculate_path(void)
}
else
progpath[0] = '\0';
+ if (path_buffer != NULL)
+ PyMem_Free(path_buffer);
if (progpath[0] != SEP && progpath[0] != '\0')
absolutize(progpath);
wcsncpy(argv0_path, progpath, MAXPATHLEN);
@@ -594,11 +565,11 @@ calculate_path(void)
MAXPATHLEN bytes long.
*/
- if (!(pfound = search_for_prefix(argv0_path, home))) {
+ if (!(pfound = search_for_prefix(argv0_path, home, _prefix))) {
if (!Py_FrozenFlag)
fprintf(stderr,
"Could not find platform independent libraries <prefix>\n");
- wcsncpy(prefix, L"" PREFIX, MAXPATHLEN);
+ wcsncpy(prefix, _prefix, MAXPATHLEN);
joinpath(prefix, lib_python);
}
else
@@ -611,17 +582,17 @@ calculate_path(void)
reduce(zip_path);
}
else
- wcsncpy(zip_path, L"" PREFIX, MAXPATHLEN);
+ 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];
- if (!(efound = search_for_exec_prefix(argv0_path, home))) {
+ if (!(efound = search_for_exec_prefix(argv0_path, home, _exec_prefix))) {
if (!Py_FrozenFlag)
fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n");
- wcsncpy(exec_prefix, L"" EXEC_PREFIX, MAXPATHLEN);
+ wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
joinpath(exec_prefix, L"lib/lib-dynload");
}
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
@@ -643,8 +614,8 @@ calculate_path(void)
bufsz += wcslen(rtpypath) + 1;
}
+ defpath = _pythonpath;
prefixsz = wcslen(prefix) + 1;
-
while (1) {
wchar_t *delim = wcschr(defpath, DELIM);
@@ -664,7 +635,6 @@ calculate_path(void)
bufsz += wcslen(zip_path) + 1;
bufsz += wcslen(exec_prefix) + 1;
- /* This is the only malloc call in this file */
buf = (wchar_t *)PyMem_Malloc(bufsz*sizeof(wchar_t));
if (buf == NULL) {
@@ -689,7 +659,7 @@ calculate_path(void)
/* Next goes merge of compile-time $PYTHONPATH with
* dynamically located prefix.
*/
- defpath = pythonpath;
+ defpath = _pythonpath;
while (1) {
wchar_t *delim = wcschr(defpath, DELIM);
@@ -717,6 +687,7 @@ calculate_path(void)
/* And publish the results */
module_search_path = buf;
+ module_search_path_malloced = 1;
}
/* Reduce prefix and exec_prefix to their essence,
@@ -733,7 +704,7 @@ calculate_path(void)
wcscpy(prefix, separator);
}
else
- wcsncpy(prefix, L"" PREFIX, MAXPATHLEN);
+ wcsncpy(prefix, _prefix, MAXPATHLEN);
if (efound > 0) {
reduce(exec_prefix);
@@ -743,11 +714,35 @@ calculate_path(void)
wcscpy(exec_prefix, separator);
}
else
- wcsncpy(exec_prefix, L"" EXEC_PREFIX, MAXPATHLEN);
+ wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
+
+ PyMem_Free(_pythonpath);
+ PyMem_Free(_prefix);
+ PyMem_Free(_exec_prefix);
}
/* External interface */
+void
+Py_SetPath(const wchar_t *path)
+{
+ if (module_search_path != NULL) {
+ if (module_search_path_malloced)
+ PyMem_Free(module_search_path);
+ module_search_path = NULL;
+ module_search_path_malloced = 0;
+ }
+ 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_Malloc((wcslen(path) + 1) * sizeof(wchar_t));
+ module_search_path_malloced = 1;
+ if (module_search_path != NULL)
+ wcscpy(module_search_path, path);
+ }
+}
wchar_t *
Py_GetPath(void)