Missing from previous check-in.
authordarylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 28 Jun 2011 19:44:23 +0000 (19:44 +0000)
committerdarylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 28 Jun 2011 19:44:23 +0000 (19:44 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11922 6f19259b-4bc3-4df7-8a09-765794883524

AppPkg/Applications/Python/Efi/getpathp.c [new file with mode: 0644]

diff --git a/AppPkg/Applications/Python/Efi/getpathp.c b/AppPkg/Applications/Python/Efi/getpathp.c
new file mode 100644 (file)
index 0000000..9f78806
--- /dev/null
@@ -0,0 +1,714 @@
+\r
+/* Return the initial module search path. */\r
+/* Used by DOS, OS/2, Windows 3.1, Windows 95/98, Windows NT. */\r
+\r
+/* ----------------------------------------------------------------\r
+   PATH RULES FOR WINDOWS:\r
+   This describes how sys.path is formed on Windows.  It describes the\r
+   functionality, not the implementation (ie, the order in which these\r
+   are actually fetched is different)\r
+\r
+   * Python always adds an empty entry at the start, which corresponds\r
+     to the current directory.\r
+\r
+   * If the PYTHONPATH env. var. exists, its entries are added next.\r
+\r
+   * We look in the registry for "application paths" - that is, sub-keys\r
+     under the main PythonPath registry key.  These are added next (the\r
+     order of sub-key processing is undefined).\r
+     HKEY_CURRENT_USER is searched and added first.\r
+     HKEY_LOCAL_MACHINE is searched and added next.\r
+     (Note that all known installers only use HKLM, so HKCU is typically\r
+     empty)\r
+\r
+   * We attempt to locate the "Python Home" - if the PYTHONHOME env var\r
+     is set, we believe it.  Otherwise, we use the path of our host .EXE's\r
+     to try and locate our "landmark" (lib\\os.py) and deduce our home.\r
+     - If we DO have a Python Home: The relevant sub-directories (Lib,\r
+       plat-win, lib-tk, etc) are based on the Python Home\r
+     - If we DO NOT have a Python Home, the core Python Path is\r
+       loaded from the registry.  This is the main PythonPath key,\r
+       and both HKLM and HKCU are combined to form the path)\r
+\r
+   * Iff - we can not locate the Python Home, have not had a PYTHONPATH\r
+     specified, and can't locate any Registry entries (ie, we have _nothing_\r
+     we can assume is a good path), a default path with relative entries is\r
+     used (eg. .\Lib;.\plat-win, etc)\r
+\r
+\r
+  The end result of all this is:\r
+  * When running python.exe, or any other .exe in the main Python directory\r
+    (either an installed version, or directly from the PCbuild directory),\r
+    the core path is deduced, and the core paths in the registry are\r
+    ignored.  Other "application paths" in the registry are always read.\r
+\r
+  * When Python is hosted in another exe (different directory, embedded via\r
+    COM, etc), the Python Home will not be deduced, so the core path from\r
+    the registry is used.  Other "application paths" in the registry are\r
+    always read.\r
+\r
+  * If Python can't find its home and there is no registry (eg, frozen\r
+    exe, some very strange installation setup) you get a path with\r
+    some default, but relative, paths.\r
+\r
+   ---------------------------------------------------------------- */\r
+\r
+\r
+#include "Python.h"\r
+#include "osdefs.h"\r
+\r
+#ifdef MS_WINDOWS\r
+#include <windows.h>\r
+#include <tchar.h>\r
+#endif\r
+\r
+#ifdef HAVE_SYS_TYPES_H\r
+#include <sys/types.h>\r
+#endif /* HAVE_SYS_TYPES_H */\r
+\r
+#ifdef HAVE_SYS_STAT_H\r
+#include <sys/stat.h>\r
+#endif /* HAVE_SYS_STAT_H */\r
+\r
+#include <string.h>\r
+\r
+/* Search in some common locations for the associated Python libraries.\r
+ *\r
+ * Py_GetPath() tries to return a sensible Python module search path.\r
+ *\r
+ * The approach is an adaptation for Windows of the strategy used in\r
+ * ../Modules/getpath.c; it uses the Windows Registry as one of its\r
+ * information sources.\r
+ */\r
+\r
+#ifndef LANDMARK\r
+#define LANDMARK "lib\\os.py"\r
+#endif\r
+\r
+static char prefix[MAXPATHLEN+1];\r
+static char progpath[MAXPATHLEN+1];\r
+static char dllpath[MAXPATHLEN+1];\r
+static char *module_search_path = NULL;\r
+\r
+\r
+static int\r
+is_sep(char ch) /* determine if "ch" is a separator character */\r
+{\r
+#ifdef ALTSEP\r
+    return ch == SEP || ch == ALTSEP;\r
+#else\r
+    return ch == SEP;\r
+#endif\r
+}\r
+\r
+/* assumes 'dir' null terminated in bounds.  Never writes\r
+   beyond existing terminator.\r
+*/\r
+static void\r
+reduce(char *dir)\r
+{\r
+    size_t i = strlen(dir);\r
+    while (i > 0 && !is_sep(dir[i]))\r
+        --i;\r
+    dir[i] = '\0';\r
+}\r
+\r
+\r
+static int\r
+exists(char *filename)\r
+{\r
+    struct stat buf;\r
+    return stat(filename, &buf) == 0;\r
+}\r
+\r
+/* Assumes 'filename' MAXPATHLEN+1 bytes long -\r
+   may extend 'filename' by one character.\r
+*/\r
+static int\r
+ismodule(char *filename)        /* Is module -- check for .pyc/.pyo too */\r
+{\r
+    if (exists(filename))\r
+        return 1;\r
+\r
+    /* Check for the compiled version of prefix. */\r
+    if (strlen(filename) < MAXPATHLEN) {\r
+        strcat(filename, Py_OptimizeFlag ? "o" : "c");\r
+        if (exists(filename))\r
+            return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+/* Add a path component, by appending stuff to buffer.\r
+   buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a\r
+   NUL-terminated string with no more than MAXPATHLEN characters (not counting\r
+   the trailing NUL).  It's a fatal error if it contains a string longer than\r
+   that (callers must be careful!).  If these requirements are met, it's\r
+   guaranteed that buffer will still be a NUL-terminated string with no more\r
+   than MAXPATHLEN characters at exit.  If stuff is too long, only as much of\r
+   stuff as fits will be appended.\r
+*/\r
+static void\r
+join(char *buffer, char *stuff)\r
+{\r
+    size_t n, k;\r
+    if (is_sep(stuff[0]))\r
+        n = 0;\r
+    else {\r
+        n = strlen(buffer);\r
+        if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN)\r
+            buffer[n++] = SEP;\r
+    }\r
+    if (n > MAXPATHLEN)\r
+        Py_FatalError("buffer overflow in getpathp.c's joinpath()");\r
+    k = strlen(stuff);\r
+    if (n + k > MAXPATHLEN)\r
+        k = MAXPATHLEN - n;\r
+    strncpy(buffer+n, stuff, k);\r
+    buffer[n+k] = '\0';\r
+}\r
+\r
+/* gotlandmark only called by search_for_prefix, which ensures\r
+   'prefix' is null terminated in bounds.  join() ensures\r
+   'landmark' can not overflow prefix if too long.\r
+*/\r
+static int\r
+gotlandmark(char *landmark)\r
+{\r
+    int ok;\r
+    Py_ssize_t n;\r
+\r
+    n = strlen(prefix);\r
+    join(prefix, landmark);\r
+    ok = ismodule(prefix);\r
+    prefix[n] = '\0';\r
+    return ok;\r
+}\r
+\r
+/* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.\r
+   assumption provided by only caller, calculate_path() */\r
+static int\r
+search_for_prefix(char *argv0_path, char *landmark)\r
+{\r
+    /* Search from argv0_path, until landmark is found */\r
+    strcpy(prefix, argv0_path);\r
+    do {\r
+        if (gotlandmark(landmark))\r
+            return 1;\r
+        reduce(prefix);\r
+    } while (prefix[0]);\r
+    return 0;\r
+}\r
+\r
+#ifdef MS_WINDOWS\r
+#ifdef Py_ENABLE_SHARED\r
+\r
+/* a string loaded from the DLL at startup.*/\r
+extern const char *PyWin_DLLVersionString;\r
+\r
+\r
+/* Load a PYTHONPATH value from the registry.\r
+   Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.\r
+\r
+   Works in both Unicode and 8bit environments.  Only uses the\r
+   Ex family of functions so it also works with Windows CE.\r
+\r
+   Returns NULL, or a pointer that should be freed.\r
+\r
+   XXX - this code is pretty strange, as it used to also\r
+   work on Win16, where the buffer sizes werent available\r
+   in advance.  It could be simplied now Win16/Win32s is dead!\r
+*/\r
+\r
+static char *\r
+getpythonregpath(HKEY keyBase, int skipcore)\r
+{\r
+    HKEY newKey = 0;\r
+    DWORD dataSize = 0;\r
+    DWORD numKeys = 0;\r
+    LONG rc;\r
+    char *retval = NULL;\r
+    TCHAR *dataBuf = NULL;\r
+    static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\");\r
+    static const TCHAR keySuffix[] = _T("\\PythonPath");\r
+    size_t versionLen;\r
+    DWORD index;\r
+    TCHAR *keyBuf = NULL;\r
+    TCHAR *keyBufPtr;\r
+    TCHAR **ppPaths = NULL;\r
+\r
+    /* Tried to use sysget("winver") but here is too early :-( */\r
+    versionLen = _tcslen(PyWin_DLLVersionString);\r
+    /* Space for all the chars, plus one \0 */\r
+    keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) +\r
+                                sizeof(TCHAR)*(versionLen-1) +\r
+                                sizeof(keySuffix));\r
+    if (keyBuf==NULL) goto done;\r
+\r
+    memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(TCHAR));\r
+    keyBufPtr += sizeof(keyPrefix)/sizeof(TCHAR) - 1;\r
+    memcpy(keyBufPtr, PyWin_DLLVersionString, versionLen * sizeof(TCHAR));\r
+    keyBufPtr += versionLen;\r
+    /* NULL comes with this one! */\r
+    memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));\r
+    /* Open the root Python key */\r
+    rc=RegOpenKeyEx(keyBase,\r
+                    keyBuf, /* subkey */\r
+            0, /* reserved */\r
+            KEY_READ,\r
+            &newKey);\r
+    if (rc!=ERROR_SUCCESS) goto done;\r
+    /* Find out how big our core buffer is, and how many subkeys we have */\r
+    rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,\r
+                    NULL, NULL, &dataSize, NULL, NULL);\r
+    if (rc!=ERROR_SUCCESS) goto done;\r
+    if (skipcore) dataSize = 0; /* Only count core ones if we want them! */\r
+    /* Allocate a temp array of char buffers, so we only need to loop\r
+       reading the registry once\r
+    */\r
+    ppPaths = malloc( sizeof(TCHAR *) * numKeys );\r
+    if (ppPaths==NULL) goto done;\r
+    memset(ppPaths, 0, sizeof(TCHAR *) * numKeys);\r
+    /* Loop over all subkeys, allocating a temp sub-buffer. */\r
+    for(index=0;index<numKeys;index++) {\r
+        TCHAR keyBuf[MAX_PATH+1];\r
+        HKEY subKey = 0;\r
+        DWORD reqdSize = MAX_PATH+1;\r
+        /* Get the sub-key name */\r
+        DWORD rc = RegEnumKeyEx(newKey, index, keyBuf, &reqdSize,\r
+                                NULL, NULL, NULL, NULL );\r
+        if (rc!=ERROR_SUCCESS) goto done;\r
+        /* Open the sub-key */\r
+        rc=RegOpenKeyEx(newKey,\r
+                                        keyBuf, /* subkey */\r
+                        0, /* reserved */\r
+                        KEY_READ,\r
+                        &subKey);\r
+        if (rc!=ERROR_SUCCESS) goto done;\r
+        /* Find the value of the buffer size, malloc, then read it */\r
+        RegQueryValueEx(subKey, NULL, 0, NULL, NULL, &reqdSize);\r
+        if (reqdSize) {\r
+            ppPaths[index] = malloc(reqdSize);\r
+            if (ppPaths[index]) {\r
+                RegQueryValueEx(subKey, NULL, 0, NULL,\r
+                                (LPBYTE)ppPaths[index],\r
+                                &reqdSize);\r
+                dataSize += reqdSize + 1; /* 1 for the ";" */\r
+            }\r
+        }\r
+        RegCloseKey(subKey);\r
+    }\r
+\r
+    /* return null if no path to return */\r
+    if (dataSize == 0) goto done;\r
+\r
+    /* original datasize from RegQueryInfo doesn't include the \0 */\r
+    dataBuf = malloc((dataSize+1) * sizeof(TCHAR));\r
+    if (dataBuf) {\r
+        TCHAR *szCur = dataBuf;\r
+        DWORD reqdSize = dataSize;\r
+        /* Copy our collected strings */\r
+        for (index=0;index<numKeys;index++) {\r
+            if (index > 0) {\r
+                *(szCur++) = _T(';');\r
+                dataSize--;\r
+            }\r
+            if (ppPaths[index]) {\r
+                Py_ssize_t len = _tcslen(ppPaths[index]);\r
+                _tcsncpy(szCur, ppPaths[index], len);\r
+                szCur += len;\r
+                assert(dataSize > (DWORD)len);\r
+                dataSize -= (DWORD)len;\r
+            }\r
+        }\r
+        if (skipcore)\r
+            *szCur = '\0';\r
+        else {\r
+            /* If we have no values, we dont need a ';' */\r
+            if (numKeys) {\r
+                *(szCur++) = _T(';');\r
+                dataSize--;\r
+            }\r
+            /* Now append the core path entries -\r
+               this will include the NULL\r
+            */\r
+            rc = RegQueryValueEx(newKey, NULL, 0, NULL,\r
+                                 (LPBYTE)szCur, &dataSize);\r
+        }\r
+        /* And set the result - caller must free\r
+           If MBCS, it is fine as is.  If Unicode, allocate new\r
+           buffer and convert.\r
+        */\r
+#ifdef UNICODE\r
+        retval = (char *)malloc(reqdSize+1);\r
+        if (retval)\r
+            WideCharToMultiByte(CP_ACP, 0,\r
+                            dataBuf, -1, /* source */\r
+                    retval, reqdSize+1, /* dest */\r
+                    NULL, NULL);\r
+        free(dataBuf);\r
+#else\r
+        retval = dataBuf;\r
+#endif\r
+    }\r
+done:\r
+    /* Loop freeing my temp buffers */\r
+    if (ppPaths) {\r
+        for(index=0;index<numKeys;index++)\r
+            if (ppPaths[index]) free(ppPaths[index]);\r
+        free(ppPaths);\r
+    }\r
+    if (newKey)\r
+        RegCloseKey(newKey);\r
+    if (keyBuf)\r
+        free(keyBuf);\r
+    return retval;\r
+}\r
+#endif /* Py_ENABLE_SHARED */\r
+#endif /* MS_WINDOWS */\r
+\r
+static void\r
+get_progpath(void)\r
+{\r
+    extern char *Py_GetProgramName(void);\r
+    char *path = getenv("PATH");\r
+    char *prog = Py_GetProgramName();\r
+\r
+#ifdef MS_WINDOWS\r
+    extern HANDLE PyWin_DLLhModule;\r
+#ifdef UNICODE\r
+    WCHAR wprogpath[MAXPATHLEN+1];\r
+    /* Windows documents that GetModuleFileName() will "truncate",\r
+       but makes no mention of the null terminator.  Play it safe.\r
+       PLUS Windows itself defines MAX_PATH as the same, but anyway...\r
+    */\r
+#ifdef Py_ENABLE_SHARED\r
+    wprogpath[MAXPATHLEN]=_T('\0');\r
+    if (PyWin_DLLhModule &&\r
+        GetModuleFileName(PyWin_DLLhModule, wprogpath, MAXPATHLEN)) {\r
+        WideCharToMultiByte(CP_ACP, 0,\r
+                            wprogpath, -1,\r
+                            dllpath, MAXPATHLEN+1,\r
+                            NULL, NULL);\r
+    }\r
+#else\r
+    dllpath[0] = 0;\r
+#endif\r
+    wprogpath[MAXPATHLEN]=_T('\0');\r
+    if (GetModuleFileName(NULL, wprogpath, MAXPATHLEN)) {\r
+        WideCharToMultiByte(CP_ACP, 0,\r
+                            wprogpath, -1,\r
+                            progpath, MAXPATHLEN+1,\r
+                            NULL, NULL);\r
+        return;\r
+    }\r
+#else\r
+    /* static init of progpath ensures final char remains \0 */\r
+#ifdef Py_ENABLE_SHARED\r
+    if (PyWin_DLLhModule)\r
+        if (!GetModuleFileName(PyWin_DLLhModule, dllpath, MAXPATHLEN))\r
+            dllpath[0] = 0;\r
+#else\r
+    dllpath[0] = 0;\r
+#endif\r
+    if (GetModuleFileName(NULL, progpath, MAXPATHLEN))\r
+        return;\r
+#endif\r
+#endif\r
+    if (prog == NULL || *prog == '\0')\r
+        prog = "python";\r
+\r
+    /* If there is no slash in the argv0 path, then we have to\r
+     * assume python is on the user's $PATH, since there's no\r
+     * other way to find a directory to start the search from.  If\r
+     * $PATH isn't exported, you lose.\r
+     */\r
+#ifdef ALTSEP\r
+    if (strchr(prog, SEP) || strchr(prog, ALTSEP))\r
+#else\r
+    if (strchr(prog, SEP))\r
+#endif\r
+        strncpy(progpath, prog, MAXPATHLEN);\r
+    else if (path) {\r
+        while (1) {\r
+            char *delim = strchr(path, DELIM);\r
+\r
+            if (delim) {\r
+                size_t len = delim - path;\r
+                /* ensure we can't overwrite buffer */\r
+                len = MIN(MAXPATHLEN,len);\r
+                strncpy(progpath, path, len);\r
+                *(progpath + len) = '\0';\r
+            }\r
+            else\r
+                strncpy(progpath, path, MAXPATHLEN);\r
+\r
+            /* join() is safe for MAXPATHLEN+1 size buffer */\r
+            join(progpath, prog);\r
+            if (exists(progpath))\r
+                break;\r
+\r
+            if (!delim) {\r
+                progpath[0] = '\0';\r
+                break;\r
+            }\r
+            path = delim + 1;\r
+        }\r
+    }\r
+    else\r
+        progpath[0] = '\0';\r
+}\r
+\r
+static void\r
+calculate_path(void)\r
+{\r
+    char argv0_path[MAXPATHLEN+1];\r
+    char *buf;\r
+    size_t bufsz;\r
+    char *pythonhome = Py_GetPythonHome();\r
+    char *envpath = Py_GETENV("PYTHONPATH");\r
+\r
+#ifdef MS_WINDOWS\r
+    int skiphome, skipdefault;\r
+    char *machinepath = NULL;\r
+    char *userpath = NULL;\r
+    char zip_path[MAXPATHLEN+1];\r
+    size_t len;\r
+#endif\r
+\r
+    get_progpath();\r
+    /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */\r
+    strcpy(argv0_path, progpath);\r
+    reduce(argv0_path);\r
+    if (pythonhome == NULL || *pythonhome == '\0') {\r
+        if (search_for_prefix(argv0_path, LANDMARK))\r
+            pythonhome = prefix;\r
+        else\r
+            pythonhome = NULL;\r
+    }\r
+    else\r
+        strncpy(prefix, pythonhome, MAXPATHLEN);\r
+\r
+    if (envpath && *envpath == '\0')\r
+        envpath = NULL;\r
+\r
+\r
+#ifdef MS_WINDOWS\r
+    /* Calculate zip archive path */\r
+    if (dllpath[0])             /* use name of python DLL */\r
+        strncpy(zip_path, dllpath, MAXPATHLEN);\r
+    else                        /* use name of executable program */\r
+        strncpy(zip_path, progpath, MAXPATHLEN);\r
+    zip_path[MAXPATHLEN] = '\0';\r
+    len = strlen(zip_path);\r
+    if (len > 4) {\r
+        zip_path[len-3] = 'z';          /* change ending to "zip" */\r
+        zip_path[len-2] = 'i';\r
+        zip_path[len-1] = 'p';\r
+    }\r
+    else {\r
+        zip_path[0] = 0;\r
+    }\r
+\r
+    skiphome = pythonhome==NULL ? 0 : 1;\r
+#ifdef Py_ENABLE_SHARED\r
+    machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);\r
+    userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome);\r
+#endif\r
+    /* We only use the default relative PYTHONPATH if we havent\r
+       anything better to use! */\r
+    skipdefault = envpath!=NULL || pythonhome!=NULL || \\r
+                  machinepath!=NULL || userpath!=NULL;\r
+#endif\r
+\r
+    /* We need to construct a path from the following parts.\r
+       (1) the PYTHONPATH environment variable, if set;\r
+       (2) for Win32, the zip archive file path;\r
+       (3) for Win32, the machinepath and userpath, if set;\r
+       (4) the PYTHONPATH config macro, with the leading "."\r
+           of each component replaced with pythonhome, if set;\r
+       (5) the directory containing the executable (argv0_path).\r
+       The length calculation calculates #4 first.\r
+       Extra rules:\r
+       - If PYTHONHOME is set (in any way) item (3) is ignored.\r
+       - If registry values are used, (4) and (5) are ignored.\r
+    */\r
+\r
+    /* Calculate size of return buffer */\r
+    if (pythonhome != NULL) {\r
+        char *p;\r
+        bufsz = 1;\r
+        for (p = PYTHONPATH; *p; p++) {\r
+            if (*p == DELIM)\r
+                bufsz++; /* number of DELIM plus one */\r
+        }\r
+        bufsz *= strlen(pythonhome);\r
+    }\r
+    else\r
+        bufsz = 0;\r
+    bufsz += strlen(PYTHONPATH) + 1;\r
+    bufsz += strlen(argv0_path) + 1;\r
+#ifdef MS_WINDOWS\r
+    if (userpath)\r
+        bufsz += strlen(userpath) + 1;\r
+    if (machinepath)\r
+        bufsz += strlen(machinepath) + 1;\r
+    bufsz += strlen(zip_path) + 1;\r
+#endif\r
+    if (envpath != NULL)\r
+        bufsz += strlen(envpath) + 1;\r
+\r
+    module_search_path = buf = malloc(bufsz);\r
+    if (buf == NULL) {\r
+        /* We can't exit, so print a warning and limp along */\r
+        fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");\r
+        if (envpath) {\r
+            fprintf(stderr, "Using environment $PYTHONPATH.\n");\r
+            module_search_path = envpath;\r
+        }\r
+        else {\r
+            fprintf(stderr, "Using default static path.\n");\r
+            module_search_path = PYTHONPATH;\r
+        }\r
+#ifdef MS_WINDOWS\r
+        if (machinepath)\r
+            free(machinepath);\r
+        if (userpath)\r
+            free(userpath);\r
+#endif /* MS_WINDOWS */\r
+        return;\r
+    }\r
+\r
+    if (envpath) {\r
+        strcpy(buf, envpath);\r
+        buf = strchr(buf, '\0');\r
+        *buf++ = DELIM;\r
+    }\r
+#ifdef MS_WINDOWS\r
+    if (zip_path[0]) {\r
+        strcpy(buf, zip_path);\r
+        buf = strchr(buf, '\0');\r
+        *buf++ = DELIM;\r
+    }\r
+    if (userpath) {\r
+        strcpy(buf, userpath);\r
+        buf = strchr(buf, '\0');\r
+        *buf++ = DELIM;\r
+        free(userpath);\r
+    }\r
+    if (machinepath) {\r
+        strcpy(buf, machinepath);\r
+        buf = strchr(buf, '\0');\r
+        *buf++ = DELIM;\r
+        free(machinepath);\r
+    }\r
+    if (pythonhome == NULL) {\r
+        if (!skipdefault) {\r
+            strcpy(buf, PYTHONPATH);\r
+            buf = strchr(buf, '\0');\r
+        }\r
+    }\r
+#else\r
+    if (pythonhome == NULL) {\r
+        strcpy(buf, PYTHONPATH);\r
+        buf = strchr(buf, '\0');\r
+    }\r
+#endif /* MS_WINDOWS */\r
+    else {\r
+        char *p = PYTHONPATH;\r
+        char *q;\r
+        size_t n;\r
+        for (;;) {\r
+            q = strchr(p, DELIM);\r
+            if (q == NULL)\r
+                n = strlen(p);\r
+            else\r
+                n = q-p;\r
+            if (p[0] == '.' && is_sep(p[1])) {\r
+                strcpy(buf, pythonhome);\r
+                buf = strchr(buf, '\0');\r
+                p++;\r
+                n--;\r
+            }\r
+            strncpy(buf, p, n);\r
+            buf += n;\r
+            if (q == NULL)\r
+                break;\r
+            *buf++ = DELIM;\r
+            p = q+1;\r
+        }\r
+    }\r
+    if (argv0_path) {\r
+        *buf++ = DELIM;\r
+        strcpy(buf, argv0_path);\r
+        buf = strchr(buf, '\0');\r
+    }\r
+    *buf = '\0';\r
+    /* Now to pull one last hack/trick.  If sys.prefix is\r
+       empty, then try and find it somewhere on the paths\r
+       we calculated.  We scan backwards, as our general policy\r
+       is that Python core directories are at the *end* of\r
+       sys.path.  We assume that our "lib" directory is\r
+       on the path, and that our 'prefix' directory is\r
+       the parent of that.\r
+    */\r
+    if (*prefix=='\0') {\r
+        char lookBuf[MAXPATHLEN+1];\r
+        char *look = buf - 1; /* 'buf' is at the end of the buffer */\r
+        while (1) {\r
+            Py_ssize_t nchars;\r
+            char *lookEnd = look;\r
+            /* 'look' will end up one character before the\r
+               start of the path in question - even if this\r
+               is one character before the start of the buffer\r
+            */\r
+            while (look >= module_search_path && *look != DELIM)\r
+                look--;\r
+            nchars = lookEnd-look;\r
+            strncpy(lookBuf, look+1, nchars);\r
+            lookBuf[nchars] = '\0';\r
+            /* Up one level to the parent */\r
+            reduce(lookBuf);\r
+            if (search_for_prefix(lookBuf, LANDMARK)) {\r
+                break;\r
+            }\r
+            /* If we are out of paths to search - give up */\r
+            if (look < module_search_path)\r
+                break;\r
+            look--;\r
+        }\r
+    }\r
+}\r
+\r
+\r
+/* External interface */\r
+\r
+char *\r
+Py_GetPath(void)\r
+{\r
+    if (!module_search_path)\r
+        calculate_path();\r
+    return module_search_path;\r
+}\r
+\r
+char *\r
+Py_GetPrefix(void)\r
+{\r
+    if (!module_search_path)\r
+        calculate_path();\r
+    return prefix;\r
+}\r
+\r
+char *\r
+Py_GetExecPrefix(void)\r
+{\r
+    return Py_GetPrefix();\r
+}\r
+\r
+char *\r
+Py_GetProgramFullPath(void)\r
+{\r
+    if (!module_search_path)\r
+        calculate_path();\r
+    return progpath;\r
+}\r