1 
2 /* Return the initial module search path. */
3 /* Used by DOS, OS/2, Windows 3.1, Windows 95/98, Windows NT. */
4 
5 /* ----------------------------------------------------------------
6    PATH RULES FOR WINDOWS:
7    This describes how sys.path is formed on Windows.  It describes the
8    functionality, not the implementation (ie, the order in which these
9    are actually fetched is different)
10 
11    * Python always adds an empty entry at the start, which corresponds
12      to the current directory.
13 
14    * If the PYTHONPATH env. var. exists, its entries are added next.
15 
16    * We look in the registry for "application paths" - that is, sub-keys
17      under the main PythonPath registry key.  These are added next (the
18      order of sub-key processing is undefined).
19      HKEY_CURRENT_USER is searched and added first.
20      HKEY_LOCAL_MACHINE is searched and added next.
21      (Note that all known installers only use HKLM, so HKCU is typically
22      empty)
23 
24    * We attempt to locate the "Python Home" - if the PYTHONHOME env var
25      is set, we believe it.  Otherwise, we use the path of our host .EXE's
26      to try and locate our "landmark" (lib\\os.py) and deduce our home.
27      - If we DO have a Python Home: The relevant sub-directories (Lib,
28        plat-win, lib-tk, etc) are based on the Python Home
29      - If we DO NOT have a Python Home, the core Python Path is
30        loaded from the registry.  This is the main PythonPath key,
31        and both HKLM and HKCU are combined to form the path)
32 
33    * Iff - we can not locate the Python Home, have not had a PYTHONPATH
34      specified, and can't locate any Registry entries (ie, we have _nothing_
35      we can assume is a good path), a default path with relative entries is
36      used (eg. .\Lib;.\plat-win, etc)
37 
38 
39   The end result of all this is:
40   * When running python.exe, or any other .exe in the main Python directory
41     (either an installed version, or directly from the PCbuild directory),
42     the core path is deduced, and the core paths in the registry are
43     ignored.  Other "application paths" in the registry are always read.
44 
45   * When Python is hosted in another exe (different directory, embedded via
46     COM, etc), the Python Home will not be deduced, so the core path from
47     the registry is used.  Other "application paths" in the registry are
48     always read.
49 
50   * If Python can't find its home and there is no registry (eg, frozen
51     exe, some very strange installation setup) you get a path with
52     some default, but relative, paths.
53 
54    ---------------------------------------------------------------- */
55 
56 
57 #include "Python.h"
58 #include "osdefs.h"
59 
60 #ifdef MS_WINDOWS
61 #include <windows.h>
62 #include <tchar.h>
63 #endif
64 
65 #ifdef HAVE_SYS_TYPES_H
66 #include <sys/types.h>
67 #endif /* HAVE_SYS_TYPES_H */
68 
69 #ifdef HAVE_SYS_STAT_H
70 #include <sys/stat.h>
71 #endif /* HAVE_SYS_STAT_H */
72 
73 #include <string.h>
74 
75 /* Search in some common locations for the associated Python libraries.
76  *
77  * Py_GetPath() tries to return a sensible Python module search path.
78  *
79  * The approach is an adaptation for Windows of the strategy used in
80  * ../Modules/getpath.c; it uses the Windows Registry as one of its
81  * information sources.
82  */
83 
84 #ifndef LANDMARK
85 #define LANDMARK "lib\\os.py"
86 #endif
87 
88 static char prefix[MAXPATHLEN+1];
89 static char progpath[MAXPATHLEN+1];
90 static char dllpath[MAXPATHLEN+1];
91 static char *module_search_path = NULL;
92 
93 
94 static int
is_sep(char ch)95 is_sep(char ch) /* determine if "ch" is a separator character */
96 {
97 #ifdef ALTSEP
98     return ch == SEP || ch == ALTSEP;
99 #else
100     return ch == SEP;
101 #endif
102 }
103 
104 /* assumes 'dir' null terminated in bounds.  Never writes
105    beyond existing terminator.
106 */
107 static void
reduce(char * dir)108 reduce(char *dir)
109 {
110     size_t i = strlen(dir);
111     while (i > 0 && !is_sep(dir[i]))
112         --i;
113     dir[i] = '\0';
114 }
115 
116 
117 static int
exists(char * filename)118 exists(char *filename)
119 {
120     struct stat buf;
121     return stat(filename, &buf) == 0;
122 }
123 
124 /* Assumes 'filename' MAXPATHLEN+1 bytes long -
125    may extend 'filename' by one character.
126 */
127 static int
ismodule(char * filename)128 ismodule(char *filename)        /* Is module -- check for .pyc/.pyo too */
129 {
130     if (exists(filename))
131         return 1;
132 
133     /* Check for the compiled version of prefix. */
134     if (strlen(filename) < MAXPATHLEN) {
135         strcat(filename, Py_OptimizeFlag ? "o" : "c");
136         if (exists(filename))
137             return 1;
138     }
139     return 0;
140 }
141 
142 /* Add a path component, by appending stuff to buffer.
143    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
144    NUL-terminated string with no more than MAXPATHLEN characters (not counting
145    the trailing NUL).  It's a fatal error if it contains a string longer than
146    that (callers must be careful!).  If these requirements are met, it's
147    guaranteed that buffer will still be a NUL-terminated string with no more
148    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
149    stuff as fits will be appended.
150 */
151 static void
join(char * buffer,char * stuff)152 join(char *buffer, char *stuff)
153 {
154     size_t n, k;
155     if (is_sep(stuff[0]))
156         n = 0;
157     else {
158         n = strlen(buffer);
159         if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN)
160             buffer[n++] = SEP;
161     }
162     if (n > MAXPATHLEN)
163         Py_FatalError("buffer overflow in getpathp.c's joinpath()");
164     k = strlen(stuff);
165     if (n + k > MAXPATHLEN)
166         k = MAXPATHLEN - n;
167     strncpy(buffer+n, stuff, k);
168     buffer[n+k] = '\0';
169 }
170 
171 /* gotlandmark only called by search_for_prefix, which ensures
172    'prefix' is null terminated in bounds.  join() ensures
173    'landmark' can not overflow prefix if too long.
174 */
175 static int
gotlandmark(char * landmark)176 gotlandmark(char *landmark)
177 {
178     int ok;
179     Py_ssize_t n;
180 
181     n = strlen(prefix);
182     join(prefix, landmark);
183     ok = ismodule(prefix);
184     prefix[n] = '\0';
185     return ok;
186 }
187 
188 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
189    assumption provided by only caller, calculate_path() */
190 static int
search_for_prefix(char * argv0_path,char * landmark)191 search_for_prefix(char *argv0_path, char *landmark)
192 {
193     /* Search from argv0_path, until landmark is found */
194     strcpy(prefix, argv0_path);
195     do {
196         if (gotlandmark(landmark))
197             return 1;
198         reduce(prefix);
199     } while (prefix[0]);
200     return 0;
201 }
202 
203 #ifdef MS_WINDOWS
204 #ifdef Py_ENABLE_SHARED
205 
206 /* a string loaded from the DLL at startup.*/
207 extern const char *PyWin_DLLVersionString;
208 
209 
210 /* Load a PYTHONPATH value from the registry.
211    Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
212 
213    Works in both Unicode and 8bit environments.  Only uses the
214    Ex family of functions so it also works with Windows CE.
215 
216    Returns NULL, or a pointer that should be freed.
217 
218    XXX - this code is pretty strange, as it used to also
219    work on Win16, where the buffer sizes werent available
220    in advance.  It could be simplied now Win16/Win32s is dead!
221 */
222 
223 static char *
getpythonregpath(HKEY keyBase,int skipcore)224 getpythonregpath(HKEY keyBase, int skipcore)
225 {
226     HKEY newKey = 0;
227     DWORD dataSize = 0;
228     DWORD numKeys = 0;
229     LONG rc;
230     char *retval = NULL;
231     TCHAR *dataBuf = NULL;
232     static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\");
233     static const TCHAR keySuffix[] = _T("\\PythonPath");
234     size_t versionLen;
235     DWORD index;
236     TCHAR *keyBuf = NULL;
237     TCHAR *keyBufPtr;
238     TCHAR **ppPaths = NULL;
239 
240     /* Tried to use sysget("winver") but here is too early :-( */
241     versionLen = _tcslen(PyWin_DLLVersionString);
242     /* Space for all the chars, plus one \0 */
243     keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) +
244                                 sizeof(TCHAR)*(versionLen-1) +
245                                 sizeof(keySuffix));
246     if (keyBuf==NULL) goto done;
247 
248     memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(TCHAR));
249     keyBufPtr += sizeof(keyPrefix)/sizeof(TCHAR) - 1;
250     memcpy(keyBufPtr, PyWin_DLLVersionString, versionLen * sizeof(TCHAR));
251     keyBufPtr += versionLen;
252     /* NULL comes with this one! */
253     memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
254     /* Open the root Python key */
255     rc=RegOpenKeyEx(keyBase,
256                     keyBuf, /* subkey */
257             0, /* reserved */
258             KEY_READ,
259             &newKey);
260     if (rc!=ERROR_SUCCESS) goto done;
261     /* Find out how big our core buffer is, and how many subkeys we have */
262     rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
263                     NULL, NULL, &dataSize, NULL, NULL);
264     if (rc!=ERROR_SUCCESS) goto done;
265     if (skipcore) dataSize = 0; /* Only count core ones if we want them! */
266     /* Allocate a temp array of char buffers, so we only need to loop
267        reading the registry once
268     */
269     ppPaths = malloc( sizeof(TCHAR *) * numKeys );
270     if (ppPaths==NULL) goto done;
271     memset(ppPaths, 0, sizeof(TCHAR *) * numKeys);
272     /* Loop over all subkeys, allocating a temp sub-buffer. */
273     for(index=0;index<numKeys;index++) {
274         TCHAR keyBuf[MAX_PATH+1];
275         HKEY subKey = 0;
276         DWORD reqdSize = MAX_PATH+1;
277         /* Get the sub-key name */
278         DWORD rc = RegEnumKeyEx(newKey, index, keyBuf, &reqdSize,
279                                 NULL, NULL, NULL, NULL );
280         if (rc!=ERROR_SUCCESS) goto done;
281         /* Open the sub-key */
282         rc=RegOpenKeyEx(newKey,
283                                         keyBuf, /* subkey */
284                         0, /* reserved */
285                         KEY_READ,
286                         &subKey);
287         if (rc!=ERROR_SUCCESS) goto done;
288         /* Find the value of the buffer size, malloc, then read it */
289         RegQueryValueEx(subKey, NULL, 0, NULL, NULL, &reqdSize);
290         if (reqdSize) {
291             ppPaths[index] = malloc(reqdSize);
292             if (ppPaths[index]) {
293                 RegQueryValueEx(subKey, NULL, 0, NULL,
294                                 (LPBYTE)ppPaths[index],
295                                 &reqdSize);
296                 dataSize += reqdSize + 1; /* 1 for the ";" */
297             }
298         }
299         RegCloseKey(subKey);
300     }
301 
302     /* return null if no path to return */
303     if (dataSize == 0) goto done;
304 
305     /* original datasize from RegQueryInfo doesn't include the \0 */
306     dataBuf = malloc((dataSize+1) * sizeof(TCHAR));
307     if (dataBuf) {
308         TCHAR *szCur = dataBuf;
309         DWORD reqdSize = dataSize;
310         /* Copy our collected strings */
311         for (index=0;index<numKeys;index++) {
312             if (index > 0) {
313                 *(szCur++) = _T(';');
314                 dataSize--;
315             }
316             if (ppPaths[index]) {
317                 Py_ssize_t len = _tcslen(ppPaths[index]);
318                 _tcsncpy(szCur, ppPaths[index], len);
319                 szCur += len;
320                 assert(dataSize > (DWORD)len);
321                 dataSize -= (DWORD)len;
322             }
323         }
324         if (skipcore)
325             *szCur = '\0';
326         else {
327             /* If we have no values, we dont need a ';' */
328             if (numKeys) {
329                 *(szCur++) = _T(';');
330                 dataSize--;
331             }
332             /* Now append the core path entries -
333                this will include the NULL
334             */
335             rc = RegQueryValueEx(newKey, NULL, 0, NULL,
336                                  (LPBYTE)szCur, &dataSize);
337         }
338         /* And set the result - caller must free
339            If MBCS, it is fine as is.  If Unicode, allocate new
340            buffer and convert.
341         */
342 #ifdef UNICODE
343         retval = (char *)malloc(reqdSize+1);
344         if (retval)
345             WideCharToMultiByte(CP_ACP, 0,
346                             dataBuf, -1, /* source */
347                     retval, reqdSize+1, /* dest */
348                     NULL, NULL);
349         free(dataBuf);
350 #else
351         retval = dataBuf;
352 #endif
353     }
354 done:
355     /* Loop freeing my temp buffers */
356     if (ppPaths) {
357         for(index=0;index<numKeys;index++)
358             if (ppPaths[index]) free(ppPaths[index]);
359         free(ppPaths);
360     }
361     if (newKey)
362         RegCloseKey(newKey);
363     if (keyBuf)
364         free(keyBuf);
365     return retval;
366 }
367 #endif /* Py_ENABLE_SHARED */
368 #endif /* MS_WINDOWS */
369 
370 static void
get_progpath(void)371 get_progpath(void)
372 {
373     extern char *Py_GetProgramName(void);
374     char *path = getenv("PATH");
375     char *prog = Py_GetProgramName();
376 
377 #ifdef MS_WINDOWS
378     extern HANDLE PyWin_DLLhModule;
379 #ifdef UNICODE
380     WCHAR wprogpath[MAXPATHLEN+1];
381     /* Windows documents that GetModuleFileName() will "truncate",
382        but makes no mention of the null terminator.  Play it safe.
383        PLUS Windows itself defines MAX_PATH as the same, but anyway...
384     */
385 #ifdef Py_ENABLE_SHARED
386     wprogpath[MAXPATHLEN]=_T('\0');
387     if (PyWin_DLLhModule &&
388         GetModuleFileName(PyWin_DLLhModule, wprogpath, MAXPATHLEN)) {
389         WideCharToMultiByte(CP_ACP, 0,
390                             wprogpath, -1,
391                             dllpath, MAXPATHLEN+1,
392                             NULL, NULL);
393     }
394 #else
395     dllpath[0] = 0;
396 #endif
397     wprogpath[MAXPATHLEN]=_T('\0');
398     if (GetModuleFileName(NULL, wprogpath, MAXPATHLEN)) {
399         WideCharToMultiByte(CP_ACP, 0,
400                             wprogpath, -1,
401                             progpath, MAXPATHLEN+1,
402                             NULL, NULL);
403         return;
404     }
405 #else
406     /* static init of progpath ensures final char remains \0 */
407 #ifdef Py_ENABLE_SHARED
408     if (PyWin_DLLhModule)
409         if (!GetModuleFileName(PyWin_DLLhModule, dllpath, MAXPATHLEN))
410             dllpath[0] = 0;
411 #else
412     dllpath[0] = 0;
413 #endif
414     if (GetModuleFileName(NULL, progpath, MAXPATHLEN))
415         return;
416 #endif
417 #endif
418     if (prog == NULL || *prog == '\0')
419         prog = "python";
420 
421     /* If there is no slash in the argv0 path, then we have to
422      * assume python is on the user's $PATH, since there's no
423      * other way to find a directory to start the search from.  If
424      * $PATH isn't exported, you lose.
425      */
426 #ifdef ALTSEP
427     if (strchr(prog, SEP) || strchr(prog, ALTSEP))
428 #else
429     if (strchr(prog, SEP))
430 #endif
431         strncpy(progpath, prog, MAXPATHLEN);
432     else if (path) {
433         while (1) {
434             char *delim = strchr(path, DELIM);
435 
436             if (delim) {
437                 size_t len = delim - path;
438                 /* ensure we can't overwrite buffer */
439                 len = min(MAXPATHLEN,len);
440                 strncpy(progpath, path, len);
441                 *(progpath + len) = '\0';
442             }
443             else
444                 strncpy(progpath, path, MAXPATHLEN);
445 
446             /* join() is safe for MAXPATHLEN+1 size buffer */
447             join(progpath, prog);
448             if (exists(progpath))
449                 break;
450 
451             if (!delim) {
452                 progpath[0] = '\0';
453                 break;
454             }
455             path = delim + 1;
456         }
457     }
458     else
459         progpath[0] = '\0';
460 }
461 
462 static void
calculate_path(void)463 calculate_path(void)
464 {
465     char argv0_path[MAXPATHLEN+1];
466     char *buf;
467     size_t bufsz;
468     char *pythonhome = Py_GetPythonHome();
469     char *envpath = Py_GETENV("PYTHONPATH");
470 
471 #ifdef MS_WINDOWS
472     int skiphome, skipdefault;
473     char *machinepath = NULL;
474     char *userpath = NULL;
475     char zip_path[MAXPATHLEN+1];
476     size_t len;
477 #endif
478 
479     get_progpath();
480     /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
481     strcpy(argv0_path, progpath);
482     reduce(argv0_path);
483     if (pythonhome == NULL || *pythonhome == '\0') {
484         if (search_for_prefix(argv0_path, LANDMARK))
485             pythonhome = prefix;
486         else
487             pythonhome = NULL;
488     }
489     else
490         strncpy(prefix, pythonhome, MAXPATHLEN);
491 
492     if (envpath && *envpath == '\0')
493         envpath = NULL;
494 
495 
496 #ifdef MS_WINDOWS
497     /* Calculate zip archive path */
498     if (dllpath[0])             /* use name of python DLL */
499         strncpy(zip_path, dllpath, MAXPATHLEN);
500     else                        /* use name of executable program */
501         strncpy(zip_path, progpath, MAXPATHLEN);
502     zip_path[MAXPATHLEN] = '\0';
503     len = strlen(zip_path);
504     if (len > 4) {
505         zip_path[len-3] = 'z';          /* change ending to "zip" */
506         zip_path[len-2] = 'i';
507         zip_path[len-1] = 'p';
508     }
509     else {
510         zip_path[0] = 0;
511     }
512 
513     skiphome = pythonhome==NULL ? 0 : 1;
514 #ifdef Py_ENABLE_SHARED
515     machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);
516     userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome);
517 #endif
518     /* We only use the default relative PYTHONPATH if we havent
519        anything better to use! */
520     skipdefault = envpath!=NULL || pythonhome!=NULL || \
521                   machinepath!=NULL || userpath!=NULL;
522 #endif
523 
524     /* We need to construct a path from the following parts.
525        (1) the PYTHONPATH environment variable, if set;
526        (2) for Win32, the zip archive file path;
527        (3) for Win32, the machinepath and userpath, if set;
528        (4) the PYTHONPATH config macro, with the leading "."
529            of each component replaced with pythonhome, if set;
530        (5) the directory containing the executable (argv0_path).
531        The length calculation calculates #4 first.
532        Extra rules:
533        - If PYTHONHOME is set (in any way) item (3) is ignored.
534        - If registry values are used, (4) and (5) are ignored.
535     */
536 
537     /* Calculate size of return buffer */
538     if (pythonhome != NULL) {
539         char *p;
540         bufsz = 1;
541         for (p = PYTHONPATH; *p; p++) {
542             if (*p == DELIM)
543                 bufsz++; /* number of DELIM plus one */
544         }
545         bufsz *= strlen(pythonhome);
546     }
547     else
548         bufsz = 0;
549     bufsz += strlen(PYTHONPATH) + 1;
550     bufsz += strlen(argv0_path) + 1;
551 #ifdef MS_WINDOWS
552     if (userpath)
553         bufsz += strlen(userpath) + 1;
554     if (machinepath)
555         bufsz += strlen(machinepath) + 1;
556     bufsz += strlen(zip_path) + 1;
557 #endif
558     if (envpath != NULL)
559         bufsz += strlen(envpath) + 1;
560 
561     module_search_path = buf = malloc(bufsz);
562     if (buf == NULL) {
563         /* We can't exit, so print a warning and limp along */
564         fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
565         if (envpath) {
566             fprintf(stderr, "Using environment $PYTHONPATH.\n");
567             module_search_path = envpath;
568         }
569         else {
570             fprintf(stderr, "Using default static path.\n");
571             module_search_path = PYTHONPATH;
572         }
573 #ifdef MS_WINDOWS
574         if (machinepath)
575             free(machinepath);
576         if (userpath)
577             free(userpath);
578 #endif /* MS_WINDOWS */
579         return;
580     }
581 
582     if (envpath) {
583         strcpy(buf, envpath);
584         buf = strchr(buf, '\0');
585         *buf++ = DELIM;
586     }
587 #ifdef MS_WINDOWS
588     if (zip_path[0]) {
589         strcpy(buf, zip_path);
590         buf = strchr(buf, '\0');
591         *buf++ = DELIM;
592     }
593     if (userpath) {
594         strcpy(buf, userpath);
595         buf = strchr(buf, '\0');
596         *buf++ = DELIM;
597         free(userpath);
598     }
599     if (machinepath) {
600         strcpy(buf, machinepath);
601         buf = strchr(buf, '\0');
602         *buf++ = DELIM;
603         free(machinepath);
604     }
605     if (pythonhome == NULL) {
606         if (!skipdefault) {
607             strcpy(buf, PYTHONPATH);
608             buf = strchr(buf, '\0');
609         }
610     }
611 #else
612     if (pythonhome == NULL) {
613         strcpy(buf, PYTHONPATH);
614         buf = strchr(buf, '\0');
615     }
616 #endif /* MS_WINDOWS */
617     else {
618         char *p = PYTHONPATH;
619         char *q;
620         size_t n;
621         for (;;) {
622             q = strchr(p, DELIM);
623             if (q == NULL)
624                 n = strlen(p);
625             else
626                 n = q-p;
627             if (p[0] == '.' && is_sep(p[1])) {
628                 strcpy(buf, pythonhome);
629                 buf = strchr(buf, '\0');
630                 p++;
631                 n--;
632             }
633             strncpy(buf, p, n);
634             buf += n;
635             if (q == NULL)
636                 break;
637             *buf++ = DELIM;
638             p = q+1;
639         }
640     }
641     if (argv0_path) {
642         *buf++ = DELIM;
643         strcpy(buf, argv0_path);
644         buf = strchr(buf, '\0');
645     }
646     *buf = '\0';
647     /* Now to pull one last hack/trick.  If sys.prefix is
648        empty, then try and find it somewhere on the paths
649        we calculated.  We scan backwards, as our general policy
650        is that Python core directories are at the *end* of
651        sys.path.  We assume that our "lib" directory is
652        on the path, and that our 'prefix' directory is
653        the parent of that.
654     */
655     if (*prefix=='\0') {
656         char lookBuf[MAXPATHLEN+1];
657         char *look = buf - 1; /* 'buf' is at the end of the buffer */
658         while (1) {
659             Py_ssize_t nchars;
660             char *lookEnd = look;
661             /* 'look' will end up one character before the
662                start of the path in question - even if this
663                is one character before the start of the buffer
664             */
665             while (look >= module_search_path && *look != DELIM)
666                 look--;
667             nchars = lookEnd-look;
668             strncpy(lookBuf, look+1, nchars);
669             lookBuf[nchars] = '\0';
670             /* Up one level to the parent */
671             reduce(lookBuf);
672             if (search_for_prefix(lookBuf, LANDMARK)) {
673                 break;
674             }
675             /* If we are out of paths to search - give up */
676             if (look < module_search_path)
677                 break;
678             look--;
679         }
680     }
681 }
682 
683 
684 /* External interface */
685 
686 char *
Py_GetPath(void)687 Py_GetPath(void)
688 {
689     if (!module_search_path)
690         calculate_path();
691     return module_search_path;
692 }
693 
694 char *
Py_GetPrefix(void)695 Py_GetPrefix(void)
696 {
697     if (!module_search_path)
698         calculate_path();
699     return prefix;
700 }
701 
702 char *
Py_GetExecPrefix(void)703 Py_GetExecPrefix(void)
704 {
705     return Py_GetPrefix();
706 }
707 
708 char *
Py_GetProgramFullPath(void)709 Py_GetProgramFullPath(void)
710 {
711     if (!module_search_path)
712         calculate_path();
713     return progpath;
714 }
715