Much rewritten. Added Win32 registry stuff (from getpath_nt.c, which
is now obsolete), and changed the default path calculations.
$PYTHONPATH is now added as a prefix (like it's always been on Unix);
$PYTHONHOME takes precedence over the program pathname; and only one
landmark is needed.
diff --git a/PC/getpathp.c b/PC/getpathp.c
index b6279e7..1a50dd9 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -37,6 +37,7 @@
#ifdef MS_WIN32
#include <windows.h>
+extern BOOL PyWin_IsWin32s();
#endif
#include <sys/types.h>
@@ -70,13 +71,14 @@
*/
#ifndef LANDMARK
-#define LANDMARK "Modules\\Setup.in"
+#define LANDMARK "lib\\string.py"
#endif
static char prefix[MAXPATHLEN+1];
static char progpath[MAXPATHLEN+1];
static char *module_search_path = NULL;
+
static int
is_sep(ch) /* determine if "ch" is a separator character */
char ch;
@@ -88,6 +90,7 @@
#endif
}
+
static void
reduce(dir)
char *dir;
@@ -141,25 +144,121 @@
do {
n = strlen(prefix);
join(prefix, landmark);
- if (exists(prefix))
+ if (exists(prefix)) {
+ prefix[n] = '\0';
return 1;
+ }
prefix[n] = '\0';
reduce(prefix);
} while (prefix[0]);
return 0;
}
+#ifdef MS_WIN32
+
+/* Load a PYTHONPATH value from the registry.
+ Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
+
+ Returns NULL, or a pointer that should be freed.
+*/
+
+static char *
+getpythonregpath(HKEY keyBase, BOOL bWin32s)
+{
+ HKEY newKey = 0;
+ DWORD nameSize = 0;
+ DWORD dataSize = 0;
+ DWORD numEntries = 0;
+ LONG rc;
+ char *retval = NULL;
+ char *dataBuf;
+ rc=RegOpenKey(keyBase,
+ "Software\\Python\\PythonCore\\"
+ MS_DLL_ID "\\PythonPath",
+ &newKey);
+ if (rc==ERROR_SUCCESS) {
+ RegQueryInfoKey(newKey, NULL, NULL, NULL, NULL, NULL, NULL,
+ &numEntries, &nameSize, &dataSize, NULL, NULL);
+ }
+ if (bWin32s && numEntries==0 && dataSize==0) {
+ /* must hardcode for Win32s */
+ numEntries = 1;
+ dataSize = 511;
+ }
+ if (numEntries) {
+ /* Loop over all subkeys. */
+ /* Win32s doesnt know how many subkeys, so we do
+ it twice */
+ char keyBuf[MAX_PATH+1];
+ int index = 0;
+ int off = 0;
+ for(index=0;;index++) {
+ long reqdSize = 0;
+ DWORD rc = RegEnumKey(newKey,
+ index, keyBuf, MAX_PATH+1);
+ if (rc) break;
+ rc = RegQueryValue(newKey, keyBuf, NULL, &reqdSize);
+ if (rc) break;
+ if (bWin32s && reqdSize==0) reqdSize = 512;
+ dataSize += reqdSize + 1; /* 1 for the ";" */
+ }
+ dataBuf = malloc(dataSize+1);
+ if (dataBuf==NULL)
+ return NULL; /* pretty serious? Raise error? */
+ /* Now loop over, grabbing the paths.
+ Subkeys before main library */
+ for(index=0;;index++) {
+ int adjust;
+ long reqdSize = dataSize;
+ DWORD rc = RegEnumKey(newKey,
+ index, keyBuf,MAX_PATH+1);
+ if (rc) break;
+ rc = RegQueryValue(newKey,
+ keyBuf, dataBuf+off, &reqdSize);
+ if (rc) break;
+ if (reqdSize>1) {
+ /* If Nothing, or only '\0' copied. */
+ adjust = strlen(dataBuf+off);
+ dataSize -= adjust;
+ off += adjust;
+ dataBuf[off++] = ';';
+ dataBuf[off] = '\0';
+ dataSize--;
+ }
+ }
+ /* Additionally, win32s doesnt work as expected, so
+ the specific strlen() is required for 3.1. */
+ rc = RegQueryValue(newKey, "", dataBuf+off, &dataSize);
+ if (rc==ERROR_SUCCESS) {
+ if (strlen(dataBuf)==0)
+ free(dataBuf);
+ else
+ retval = dataBuf; /* caller will free */
+ }
+ else
+ free(dataBuf);
+ }
+
+ if (newKey)
+ RegCloseKey(newKey);
+ return retval;
+}
+#endif /* MS_WIN32 */
+
static void
get_progpath()
{
-#ifdef MS_WIN32
- if (!GetModuleFileName(NULL, progpath, MAXPATHLEN))
- progpath[0] = '\0'; /* failure */
-#else
extern char *Py_GetProgramName();
char *path = getenv("PATH");
char *prog = Py_GetProgramName();
+#ifdef MS_WIN32
+ if (GetModuleFileName(NULL, progpath, MAXPATHLEN))
+ return;
+#endif
+ if (prog == NULL || *prog == '\0')
+ prog = "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
* other way to find a directory to start the search from. If
@@ -196,76 +295,142 @@
}
else
progpath[0] = '\0';
-#endif
}
static void
calculate_path()
{
- char ch, *pt, *pt2;
char argv0_path[MAXPATHLEN+1];
char *buf;
int bufsz;
+ char *pythonhome = getenv("PYTHONHOME");
+ char *envpath = getenv("PYTHONPATH");
+#ifdef MS_WIN32
+ char *machinepath, *userpath;
+
+ /* Are we running under Windows 3.1(1) Win32s? */
+ if (PyWin_IsWin32s()) {
+ /* Only CLASSES_ROOT is supported */
+ machinepath = getpythonregpath(HKEY_CLASSES_ROOT, TRUE);
+ userpath = NULL;
+ } else {
+ machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, FALSE);
+ userpath = getpythonregpath(HKEY_CURRENT_USER, FALSE);
+ }
+#endif
get_progpath();
strcpy(argv0_path, progpath);
reduce(argv0_path);
+ if (pythonhome == NULL || *pythonhome == '\0') {
+ if (search_for_prefix(argv0_path, LANDMARK))
+ pythonhome = prefix;
+ else
+ pythonhome = NULL;
+ }
+ else
+ strcpy(prefix, pythonhome);
- if (search_for_prefix(argv0_path, LANDMARK)) {
- reduce(prefix);
- reduce(prefix);
- join(prefix, "lib");
- }
- else if ((module_search_path = getenv("PYTHONPATH")) != 0) {
- return; /* if PYTHONPATH environment variable exists, we are done */
- }
- else { /* Try the executable_directory/lib */
- strcpy(prefix, progpath);
- reduce(prefix);
- join(prefix, "lib");
- join(prefix, "string.py"); /* Look for lib/string.py */
- if (exists(prefix)) {
- reduce(prefix);
+ if (envpath && *envpath == '\0')
+ envpath = NULL;
+
+ /* We need to construct a path from the following parts:
+ (1) the PYTHONPATH environment variable, if set;
+ (2) for Win32, the machinepath and userpath, if set;
+ (3) the PYTHONPATH config macro, with the leading "."
+ of each component replaced with pythonhome, if set;
+ (4) the directory containing the executable (argv0_path).
+ The length calculation calculates #3 first.
+ */
+
+ /* Calculate size of return buffer */
+ if (pythonhome != NULL) {
+ char *p;
+ bufsz = 1;
+ for (p = PYTHONPATH; *p; p++) {
+ if (*p == DELIM)
+ bufsz++; /* number of DELIM plus one */
}
- else { /* No module search path!!! */
- module_search_path = PYTHONPATH;
- return;
- }
+ bufsz *= strlen(pythonhome);
}
-
-
- /* If we get here, we need to return a path equal to the compiled
- PYTHONPATH with ".\lib" replaced by our "prefix" directory */
-
- bufsz = 1; /* Calculate size of return buffer. */
- for (pt = PYTHONPATH; *pt; pt++)
- if (*pt == DELIM)
- bufsz++; /* number of DELIM plus one */
- bufsz *= strlen(PYTHONPATH) + strlen(prefix); /* high estimate */
+ else
+ bufsz = 0;
+ bufsz += strlen(PYTHONPATH);
+ if (envpath != NULL)
+ bufsz += strlen(envpath) + 1;
bufsz += strlen(argv0_path) + 1;
+#ifdef MS_WIN32
+ if (machinepath)
+ bufsz += strlen(machinepath) + 1;
+ if (userpath)
+ bufsz += strlen(userpath) + 1;
+#endif
module_search_path = buf = malloc(bufsz);
-
if (buf == NULL) {
/* We can't exit, so print a warning and limp along */
- fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n");
- fprintf(stderr, "Using default static PYTHONPATH.\n");
- module_search_path = PYTHONPATH;
+ fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
+ if (envpath) {
+ fprintf(stderr, "Using default static $PYTHONPATH.\n");
+ module_search_path = envpath;
+ }
+ else {
+ fprintf(stderr, "Using environment $PYTHONPATH.\n");
+ module_search_path = PYTHONPATH;
+ }
return;
}
- for (pt = PYTHONPATH; *pt; pt++) {
- if (!strncmp(pt, ".\\lib", 5) &&
- ((ch = *(pt + 5)) == '\\' || ch == DELIM || !ch)) {
- pt += 4;
- for (pt2 = prefix; *pt2; pt2++)
- *buf++ = *pt2;
- }
- else
- *buf++ = *pt;
+
+ if (envpath) {
+ strcpy(buf, envpath);
+ buf = strchr(buf, '\0');
+ *buf++ = DELIM;
}
- *buf++ = DELIM;
- strcpy(buf, argv0_path);
- buf += strlen(buf);
+#ifdef MS_WIN32
+ if (machinepath) {
+ strcpy(buf, machinepath);
+ buf = strchr(buf, '\0');
+ *buf++ = DELIM;
+ }
+ if (userpath) {
+ strcpy(buf, userpath);
+ buf = strchr(buf, '\0');
+ *buf++ = DELIM;
+ }
+#endif
+ if (pythonhome == NULL) {
+ strcpy(buf, PYTHONPATH);
+ buf = strchr(buf, '\0');
+ }
+ else {
+ char *p = PYTHONPATH;
+ char *q;
+ int n;
+ for (;;) {
+ q = strchr(p, DELIM);
+ if (q == NULL)
+ n = strlen(p);
+ else
+ n = q-p;
+ if (p[0] == '.' && is_sep(p[1])) {
+ strcpy(buf, pythonhome);
+ buf = strchr(buf, '\0');
+ p++;
+ n--;
+ }
+ strncpy(buf, p, n);
+ buf += n;
+ if (q == NULL)
+ break;
+ *buf++ = DELIM;
+ p = q+1;
+ }
+ }
+ if (argv0_path) {
+ *buf++ = DELIM;
+ strcpy(buf, argv0_path);
+ buf = strchr(buf, '\0');
+ }
*buf = '\0';
}
@@ -283,17 +448,19 @@
char *
Py_GetPrefix()
{
- return "";
+ if (!module_search_path)
+ calculate_path();
+ return prefix;
}
char *
Py_GetExecPrefix()
{
- return "";
+ return Py_GetPrefix();
}
char *
-Py_GetProgramFullPath() /* Full path to Python executable */
+Py_GetProgramFullPath()
{
if (!module_search_path)
calculate_path();