Home | History | Annotate | Download | only in os2vacpp
      1 
      2 /* Return the initial module search path. */
      3 /* Used by DOS, OS/2, Windows 3.1.  Works on NT too. */
      4 
      5 #include "Python.h"
      6 #include "osdefs.h"
      7 
      8 #ifdef MS_WIN32
      9 #include <windows.h>
     10 extern BOOL PyWin_IsWin32s(void);
     11 #endif
     12 
     13 #include <sys/types.h>
     14 #include <sys/stat.h>
     15 #include <string.h>
     16 
     17 #if HAVE_UNISTD_H
     18 #include <unistd.h>
     19 #endif /* HAVE_UNISTD_H */
     20 
     21 /* Search in some common locations for the associated Python libraries.
     22  *
     23  * Two directories must be found, the platform independent directory
     24  * (prefix), containing the common .py and .pyc files, and the platform
     25  * dependent directory (exec_prefix), containing the shared library
     26  * modules.  Note that prefix and exec_prefix can be the same directory,
     27  * but for some installations, they are different.
     28  *
     29  * Py_GetPath() tries to return a sensible Python module search path.
     30  *
     31  * First, we look to see if the executable is in a subdirectory of
     32  * the Python build directory.  We calculate the full path of the
     33  * directory containing the executable as progpath.  We work backwards
     34  * along progpath and look for $dir/Modules/Setup.in, a distinctive
     35  * landmark.  If found, we use $dir/Lib as $root.  The returned
     36  * Python path is the compiled #define PYTHONPATH with all the initial
     37  * "./lib" replaced by $root.
     38  *
     39  * Otherwise, if there is a PYTHONPATH environment variable, we return that.
     40  *
     41  * Otherwise we try to find $progpath/lib/os.py, and if found, then
     42  * root is $progpath/lib, and we return Python path as compiled PYTHONPATH
     43  * with all "./lib" replaced by $root (as above).
     44  *
     45  */
     46 
     47 #ifndef LANDMARK
     48 #define LANDMARK "lib\\os.py"
     49 #endif
     50 
     51 static char prefix[MAXPATHLEN+1];
     52 static char exec_prefix[MAXPATHLEN+1];
     53 static char progpath[MAXPATHLEN+1];
     54 static char *module_search_path = NULL;
     55 
     56 
     57 static int
     58 is_sep(char ch) /* determine if "ch" is a separator character */
     59 {
     60 #ifdef ALTSEP
     61     return ch == SEP || ch == ALTSEP;
     62 #else
     63     return ch == SEP;
     64 #endif
     65 }
     66 
     67 
     68 static void
     69 reduce(char *dir)
     70 {
     71     int i = strlen(dir);
     72     while (i > 0 && !is_sep(dir[i]))
     73         --i;
     74     dir[i] = '\0';
     75 }
     76 
     77 
     78 static int
     79 exists(char *filename)
     80 {
     81     struct stat buf;
     82     return stat(filename, &buf) == 0;
     83 }
     84 
     85 
     86 /* Add a path component, by appending stuff to buffer.
     87    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
     88    NUL-terminated string with no more than MAXPATHLEN characters (not counting
     89    the trailing NUL).  It's a fatal error if it contains a string longer than
     90    that (callers must be careful!).  If these requirements are met, it's
     91    guaranteed that buffer will still be a NUL-terminated string with no more
     92    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
     93    stuff as fits will be appended.
     94 */
     95 static void
     96 join(char *buffer, char *stuff)
     97 {
     98     int n, k;
     99     if (is_sep(stuff[0]))
    100         n = 0;
    101     else {
    102         n = strlen(buffer);
    103         if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN)
    104             buffer[n++] = SEP;
    105     }
    106     if (n > MAXPATHLEN)
    107         Py_FatalError("buffer overflow in getpathp.c's joinpath()");
    108     k = strlen(stuff);
    109     if (n + k > MAXPATHLEN)
    110         k = MAXPATHLEN - n;
    111     strncpy(buffer+n, stuff, k);
    112     buffer[n+k] = '\0';
    113 }
    114 
    115 
    116 static int
    117 search_for_prefix(char *argv0_path, char *landmark)
    118 {
    119     int n;
    120 
    121     /* Search from argv0_path, until root is found */
    122     strcpy(prefix, argv0_path);
    123     do {
    124         n = strlen(prefix);
    125         join(prefix, landmark);
    126         if (exists(prefix)) {
    127             prefix[n] = '\0';
    128             return 1;
    129         }
    130         prefix[n] = '\0';
    131         reduce(prefix);
    132     } while (prefix[0]);
    133     return 0;
    134 }
    135 
    136 #ifdef MS_WIN32
    137 #include "malloc.h" // for alloca - see comments below!
    138 extern const char *PyWin_DLLVersionString; // a string loaded from the DLL at startup.
    139 
    140 
    141 /* Load a PYTHONPATH value from the registry.
    142    Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
    143 
    144    Returns NULL, or a pointer that should be freed.
    145 */
    146 
    147 static char *
    148 getpythonregpath(HKEY keyBase, BOOL bWin32s)
    149 {
    150     HKEY newKey = 0;
    151     DWORD nameSize = 0;
    152     DWORD dataSize = 0;
    153     DWORD numEntries = 0;
    154     LONG rc;
    155     char *retval = NULL;
    156     char *dataBuf;
    157     const char keyPrefix[] = "Software\\Python\\PythonCore\\";
    158     const char keySuffix[] = "\\PythonPath";
    159     int versionLen;
    160     char *keyBuf;
    161 
    162     // Tried to use sysget("winver") but here is too early :-(
    163     versionLen = strlen(PyWin_DLLVersionString);
    164     // alloca == no free required, but memory only local to fn.
    165     // also no heap fragmentation!  Am I being silly?
    166     keyBuf = alloca(sizeof(keyPrefix)-1 + versionLen + sizeof(keySuffix)); // chars only, plus 1 NULL.
    167     // lots of constants here for the compiler to optimize away :-)
    168     memcpy(keyBuf, keyPrefix, sizeof(keyPrefix)-1);
    169     memcpy(keyBuf+sizeof(keyPrefix)-1, PyWin_DLLVersionString, versionLen);
    170     memcpy(keyBuf+sizeof(keyPrefix)-1+versionLen, keySuffix, sizeof(keySuffix)); // NULL comes with this one!
    171 
    172     rc=RegOpenKey(keyBase,
    173                   keyBuf,
    174                   &newKey);
    175     if (rc==ERROR_SUCCESS) {
    176         RegQueryInfoKey(newKey, NULL, NULL, NULL, NULL, NULL, NULL,
    177                         &numEntries, &nameSize, &dataSize, NULL, NULL);
    178     }
    179     if (bWin32s && numEntries==0 && dataSize==0) {
    180         /* must hardcode for Win32s */
    181         numEntries = 1;
    182         dataSize = 511;
    183     }
    184     if (numEntries) {
    185         /* Loop over all subkeys. */
    186         /* Win32s doesnt know how many subkeys, so we do
    187            it twice */
    188         char keyBuf[MAX_PATH+1];
    189         int index = 0;
    190         int off = 0;
    191         for(index=0;;index++) {
    192             long reqdSize = 0;
    193             DWORD rc = RegEnumKey(newKey,
    194                                   index, keyBuf, MAX_PATH+1);
    195             if (rc) break;
    196             rc = RegQueryValue(newKey, keyBuf, NULL, &reqdSize);
    197             if (rc) break;
    198             if (bWin32s && reqdSize==0) reqdSize = 512;
    199             dataSize += reqdSize + 1; /* 1 for the ";" */
    200         }
    201         dataBuf = malloc(dataSize+1);
    202         if (dataBuf==NULL)
    203             return NULL; /* pretty serious?  Raise error? */
    204         /* Now loop over, grabbing the paths.
    205            Subkeys before main library */
    206         for(index=0;;index++) {
    207             int adjust;
    208             long reqdSize = dataSize;
    209             DWORD rc = RegEnumKey(newKey,
    210                                   index, keyBuf,MAX_PATH+1);
    211             if (rc) break;
    212             rc = RegQueryValue(newKey,
    213                                keyBuf, dataBuf+off, &reqdSize);
    214             if (rc) break;
    215             if (reqdSize>1) {
    216                 /* If Nothing, or only '\0' copied. */
    217                 adjust = strlen(dataBuf+off);
    218                 dataSize -= adjust;
    219                 off += adjust;
    220                 dataBuf[off++] = ';';
    221                 dataBuf[off] = '\0';
    222                 dataSize--;
    223             }
    224         }
    225         /* Additionally, win32s doesnt work as expected, so
    226            the specific strlen() is required for 3.1. */
    227         rc = RegQueryValue(newKey, "", dataBuf+off, &dataSize);
    228         if (rc==ERROR_SUCCESS) {
    229             if (strlen(dataBuf)==0)
    230                 free(dataBuf);
    231             else
    232                 retval = dataBuf; /* caller will free */
    233         }
    234         else
    235             free(dataBuf);
    236     }
    237 
    238     if (newKey)
    239         RegCloseKey(newKey);
    240     return retval;
    241 }
    242 #endif /* MS_WIN32 */
    243 
    244 static void
    245 get_progpath(void)
    246 {
    247     extern char *Py_GetProgramName(void);
    248     char *path = getenv("PATH");
    249     char *prog = Py_GetProgramName();
    250 
    251 #ifdef MS_WIN32
    252     if (GetModuleFileName(NULL, progpath, MAXPATHLEN))
    253         return;
    254 #endif
    255     if (prog == NULL || *prog == '\0')
    256         prog = "python";
    257 
    258     /* If there is no slash in the argv0 path, then we have to
    259      * assume python is on the user's $PATH, since there's no
    260      * other way to find a directory to start the search from.  If
    261      * $PATH isn't exported, you lose.
    262      */
    263 #ifdef ALTSEP
    264     if (strchr(prog, SEP) || strchr(prog, ALTSEP))
    265 #else
    266     if (strchr(prog, SEP))
    267 #endif
    268         strcpy(progpath, prog);
    269     else if (path) {
    270         while (1) {
    271             char *delim = strchr(path, DELIM);
    272 
    273             if (delim) {
    274                 int len = delim - path;
    275                 strncpy(progpath, path, len);
    276                 *(progpath + len) = '\0';
    277             }
    278             else
    279                 strcpy(progpath, path);
    280 
    281             join(progpath, prog);
    282             if (exists(progpath))
    283                 break;
    284 
    285             if (!delim) {
    286                 progpath[0] = '\0';
    287                 break;
    288             }
    289             path = delim + 1;
    290         }
    291     }
    292     else
    293         progpath[0] = '\0';
    294 }
    295 
    296 static void
    297 calculate_path(void)
    298 {
    299     char argv0_path[MAXPATHLEN+1];
    300     char *buf;
    301     int bufsz;
    302     char *pythonhome = Py_GetPythonHome();
    303     char *envpath = Py_GETENV("PYTHONPATH");
    304 #ifdef MS_WIN32
    305     char *machinepath, *userpath;
    306 
    307     /* Are we running under Windows 3.1(1) Win32s? */
    308     if (PyWin_IsWin32s()) {
    309         /* Only CLASSES_ROOT is supported */
    310         machinepath = getpythonregpath(HKEY_CLASSES_ROOT, TRUE);
    311         userpath = NULL;
    312     } else {
    313         machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, FALSE);
    314         userpath = getpythonregpath(HKEY_CURRENT_USER, FALSE);
    315     }
    316 #endif
    317 
    318     get_progpath();
    319     strcpy(argv0_path, progpath);
    320     reduce(argv0_path);
    321     if (pythonhome == NULL || *pythonhome == '\0') {
    322         if (search_for_prefix(argv0_path, LANDMARK))
    323             pythonhome = prefix;
    324         else
    325             pythonhome = NULL;
    326     }
    327     else {
    328         char *delim;
    329 
    330         strcpy(prefix, pythonhome);
    331 
    332         /* Extract Any Optional Trailing EXEC_PREFIX */
    333         /* e.g. PYTHONHOME=<prefix>:<exec_prefix>   */
    334         delim = strchr(prefix, DELIM);
    335         if (delim) {
    336             *delim = '\0';
    337             strcpy(exec_prefix, delim+1);
    338         } else
    339             strcpy(exec_prefix, EXEC_PREFIX);
    340     }
    341 
    342     if (envpath && *envpath == '\0')
    343         envpath = NULL;
    344 
    345     /* We need to construct a path from the following parts:
    346        (1) the PYTHONPATH environment variable, if set;
    347        (2) for Win32, the machinepath and userpath, if set;
    348        (3) the PYTHONPATH config macro, with the leading "."
    349            of each component replaced with pythonhome, if set;
    350        (4) the directory containing the executable (argv0_path).
    351        The length calculation calculates #3 first.
    352     */
    353 
    354     /* Calculate size of return buffer */
    355     if (pythonhome != NULL) {
    356         char *p;
    357         bufsz = 1;
    358         for (p = PYTHONPATH; *p; p++) {
    359             if (*p == DELIM)
    360                 bufsz++; /* number of DELIM plus one */
    361         }
    362         bufsz *= strlen(pythonhome);
    363     }
    364     else
    365         bufsz = 0;
    366     bufsz += strlen(PYTHONPATH) + 1;
    367     if (envpath != NULL)
    368         bufsz += strlen(envpath) + 1;
    369     bufsz += strlen(argv0_path) + 1;
    370 #ifdef MS_WIN32
    371     if (machinepath)
    372         bufsz += strlen(machinepath) + 1;
    373     if (userpath)
    374         bufsz += strlen(userpath) + 1;
    375 #endif
    376 
    377     module_search_path = buf = malloc(bufsz);
    378     if (buf == NULL) {
    379         /* We can't exit, so print a warning and limp along */
    380         fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
    381         if (envpath) {
    382             fprintf(stderr, "Using default static $PYTHONPATH.\n");
    383             module_search_path = envpath;
    384         }
    385         else {
    386             fprintf(stderr, "Using environment $PYTHONPATH.\n");
    387             module_search_path = PYTHONPATH;
    388         }
    389         return;
    390     }
    391 
    392     if (envpath) {
    393         strcpy(buf, envpath);
    394         buf = strchr(buf, '\0');
    395         *buf++ = DELIM;
    396     }
    397 #ifdef MS_WIN32
    398     if (machinepath) {
    399         strcpy(buf, machinepath);
    400         buf = strchr(buf, '\0');
    401         *buf++ = DELIM;
    402     }
    403     if (userpath) {
    404         strcpy(buf, userpath);
    405         buf = strchr(buf, '\0');
    406         *buf++ = DELIM;
    407     }
    408 #endif
    409     if (pythonhome == NULL) {
    410         strcpy(buf, PYTHONPATH);
    411         buf = strchr(buf, '\0');
    412     }
    413     else {
    414         char *p = PYTHONPATH;
    415         char *q;
    416         int n;
    417         for (;;) {
    418             q = strchr(p, DELIM);
    419             if (q == NULL)
    420                 n = strlen(p);
    421             else
    422                 n = q-p;
    423             if (p[0] == '.' && is_sep(p[1])) {
    424                 strcpy(buf, pythonhome);
    425                 buf = strchr(buf, '\0');
    426                 p++;
    427                 n--;
    428             }
    429             strncpy(buf, p, n);
    430             buf += n;
    431             if (q == NULL)
    432                 break;
    433             *buf++ = DELIM;
    434             p = q+1;
    435         }
    436     }
    437     if (argv0_path) {
    438         *buf++ = DELIM;
    439         strcpy(buf, argv0_path);
    440         buf = strchr(buf, '\0');
    441     }
    442     *buf = '\0';
    443 }
    444 
    445 
    446 /* External interface */
    447 
    448 char *
    449 Py_GetPath(void)
    450 {
    451     if (!module_search_path)
    452         calculate_path();
    453 
    454     return module_search_path;
    455 }
    456 
    457 char *
    458 Py_GetPrefix(void)
    459 {
    460     if (!module_search_path)
    461         calculate_path();
    462 
    463     return prefix;
    464 }
    465 
    466 char *
    467 Py_GetExecPrefix(void)
    468 {
    469     if (!module_search_path)
    470         calculate_path();
    471 
    472     return exec_prefix;
    473 }
    474 
    475 char *
    476 Py_GetProgramFullPath(void)
    477 {
    478     if (!module_search_path)
    479         calculate_path();
    480 
    481     return progpath;
    482 }
    483