1
2/* Return the initial module search path. */
3/* This version used by OS/2+EMX */
4
5/* ----------------------------------------------------------------
6   PATH RULES FOR OS/2+EMX:
7   This describes how sys.path is formed on OS/2+EMX.  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 attempt to locate the "Python Home" - if the PYTHONHOME env var
17     is set, we believe it.  Otherwise, we use the path of our host .EXE's
18     to try and locate our "landmark" (lib\\os.py) and deduce our home.
19     - If we DO have a Python Home: The relevant sub-directories (Lib,
20       plat-win, lib-tk, etc) are based on the Python Home
21     - If we DO NOT have a Python Home, the core Python Path is
22       loaded from the registry.  This is the main PythonPath key,
23       and both HKLM and HKCU are combined to form the path)
24
25   * Iff - we can not locate the Python Home, and have not had a PYTHONPATH
26     specified (ie, we have _nothing_ we can assume is a good path), a
27     default path with relative entries is used (eg. .\Lib;.\plat-win, etc)
28
29
30  The end result of all this is:
31  * When running python.exe, or any other .exe in the main Python directory
32    (either an installed version, or directly from the PCbuild directory),
33    the core path is deduced.
34
35  * When Python is hosted in another exe (different directory, embedded via
36    COM, etc), the Python Home will not be deduced, so the core path from
37    the registry is used.  Other "application paths "in the registry are
38    always read.
39
40  * If Python can't find its home and there is no registry (eg, frozen
41    exe, some very strange installation setup) you get a path with
42    some default, but relative, paths.
43
44   ---------------------------------------------------------------- */
45
46
47#include "Python.h"
48#include "osdefs.h"
49
50#ifndef PYOS_OS2
51#error This file only compilable on OS/2
52#endif
53
54#define INCL_DOS
55#include <os2.h>
56
57#include <sys/types.h>
58#include <sys/stat.h>
59#include <string.h>
60
61#if HAVE_UNISTD_H
62#include <unistd.h>
63#endif /* HAVE_UNISTD_H */
64
65/* Search in some common locations for the associated Python libraries.
66 *
67 * Py_GetPath() tries to return a sensible Python module search path.
68 *
69 * The approach is an adaptation for Windows of the strategy used in
70 * ../Modules/getpath.c; it uses the Windows Registry as one of its
71 * information sources.
72 */
73
74#ifndef LANDMARK
75#if defined(PYCC_GCC)
76#define LANDMARK "lib/os.py"
77#else
78#define LANDMARK "lib\\os.py"
79#endif
80#endif
81
82static char prefix[MAXPATHLEN+1];
83static char progpath[MAXPATHLEN+1];
84static char *module_search_path = NULL;
85
86
87static int
88is_sep(char ch) /* determine if "ch" is a separator character */
89{
90#ifdef ALTSEP
91    return ch == SEP || ch == ALTSEP;
92#else
93    return ch == SEP;
94#endif
95}
96
97/* assumes 'dir' null terminated in bounds.
98 * Never writes beyond existing terminator.
99 */
100static void
101reduce(char *dir)
102{
103    size_t i = strlen(dir);
104    while (i > 0 && !is_sep(dir[i]))
105        --i;
106    dir[i] = '\0';
107}
108
109static int
110exists(char *filename)
111{
112    struct stat buf;
113    return stat(filename, &buf) == 0;
114}
115
116/* Is module  (check for .pyc/.pyo too)
117 * Assumes 'filename' MAXPATHLEN+1 bytes long -
118 * may extend 'filename' by one character.
119 */
120static int
121ismodule(char *filename)
122{
123    if (exists(filename))
124        return 1;
125
126    /* Check for the compiled version of prefix. */
127    if (strlen(filename) < MAXPATHLEN) {
128        strcat(filename, Py_OptimizeFlag ? "o" : "c");
129        if (exists(filename))
130            return 1;
131    }
132    return 0;
133}
134
135/* Add a path component, by appending stuff to buffer.
136   buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
137   NUL-terminated string with no more than MAXPATHLEN characters (not counting
138   the trailing NUL).  It's a fatal error if it contains a string longer than
139   that (callers must be careful!).  If these requirements are met, it's
140   guaranteed that buffer will still be a NUL-terminated string with no more
141   than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
142   stuff as fits will be appended.
143*/
144
145static void
146join(char *buffer, char *stuff)
147{
148    size_t n, k;
149    if (is_sep(stuff[0]))
150        n = 0;
151    else {
152        n = strlen(buffer);
153        if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN)
154            buffer[n++] = SEP;
155    }
156    if (n > MAXPATHLEN)
157        Py_FatalError("buffer overflow in getpathp.c's joinpath()");
158    k = strlen(stuff);
159    if (n + k > MAXPATHLEN)
160        k = MAXPATHLEN - n;
161    strncpy(buffer+n, stuff, k);
162    buffer[n+k] = '\0';
163}
164
165/* gotlandmark only called by search_for_prefix, which ensures
166 * 'prefix' is null terminated in bounds.  join() ensures
167 * 'landmark' can not overflow prefix if too long.
168 */
169static int
170gotlandmark(char *landmark)
171{
172    int n, ok;
173
174    n = strlen(prefix);
175    join(prefix, landmark);
176    ok = ismodule(prefix);
177    prefix[n] = '\0';
178    return ok;
179}
180
181/* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
182 * assumption provided by only caller, calculate_path()
183 */
184static int
185search_for_prefix(char *argv0_path, char *landmark)
186{
187    /* Search from argv0_path, until landmark is found */
188    strcpy(prefix, argv0_path);
189    do {
190        if (gotlandmark(landmark))
191            return 1;
192        reduce(prefix);
193    } while (prefix[0]);
194    return 0;
195}
196
197
198static void
199get_progpath(void)
200{
201    extern char *Py_GetProgramName(void);
202    char *path = getenv("PATH");
203    char *prog = Py_GetProgramName();
204
205    PPIB pib;
206    if ((DosGetInfoBlocks(NULL, &pib) == 0) &&
207        (DosQueryModuleName(pib->pib_hmte, sizeof(progpath), progpath) == 0))
208        return;
209
210    if (prog == NULL || *prog == '\0')
211        prog = "python";
212
213    /* If there is no slash in the argv0 path, then we have to
214     * assume python is on the user's $PATH, since there's no
215     * other way to find a directory to start the search from.  If
216     * $PATH isn't exported, you lose.
217     */
218#ifdef ALTSEP
219    if (strchr(prog, SEP) || strchr(prog, ALTSEP))
220#else
221    if (strchr(prog, SEP))
222#endif
223        strncpy(progpath, prog, MAXPATHLEN);
224    else if (path) {
225        while (1) {
226            char *delim = strchr(path, DELIM);
227
228            if (delim) {
229                size_t len = delim - path;
230                /* ensure we can't overwrite buffer */
231#if !defined(PYCC_GCC)
232                len = min(MAXPATHLEN,len);
233#else
234                len = MAXPATHLEN < len ? MAXPATHLEN : len;
235#endif
236                strncpy(progpath, path, len);
237                *(progpath + len) = '\0';
238            }
239            else
240                strncpy(progpath, path, MAXPATHLEN);
241
242            /* join() is safe for MAXPATHLEN+1 size buffer */
243            join(progpath, prog);
244            if (exists(progpath))
245                break;
246
247            if (!delim) {
248                progpath[0] = '\0';
249                break;
250            }
251            path = delim + 1;
252        }
253    }
254    else
255        progpath[0] = '\0';
256}
257
258static void
259calculate_path(void)
260{
261    char argv0_path[MAXPATHLEN+1];
262    char *buf;
263    size_t bufsz;
264    char *pythonhome = Py_GetPythonHome();
265    char *envpath = getenv("PYTHONPATH");
266    char zip_path[MAXPATHLEN+1];
267    size_t len;
268
269    get_progpath();
270    /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
271    strcpy(argv0_path, progpath);
272    reduce(argv0_path);
273    if (pythonhome == NULL || *pythonhome == '\0') {
274        if (search_for_prefix(argv0_path, LANDMARK))
275            pythonhome = prefix;
276        else
277            pythonhome = NULL;
278    }
279    else
280        strncpy(prefix, pythonhome, MAXPATHLEN);
281
282    if (envpath && *envpath == '\0')
283        envpath = NULL;
284
285    /* Calculate zip archive path */
286    strncpy(zip_path, progpath, MAXPATHLEN);
287    zip_path[MAXPATHLEN] = '\0';
288    len = strlen(zip_path);
289    if (len > 4) {
290        zip_path[len-3] = 'z';  /* change ending to "zip" */
291        zip_path[len-2] = 'i';
292        zip_path[len-1] = 'p';
293    }
294    else {
295        zip_path[0] = 0;
296    }
297
298    /* We need to construct a path from the following parts.
299     * (1) the PYTHONPATH environment variable, if set;
300     * (2) the zip archive file path;
301     * (3) the PYTHONPATH config macro, with the leading "."
302     *     of each component replaced with pythonhome, if set;
303     * (4) the directory containing the executable (argv0_path).
304     * The length calculation calculates #3 first.
305     */
306
307    /* Calculate size of return buffer */
308    if (pythonhome != NULL) {
309        char *p;
310        bufsz = 1;
311        for (p = PYTHONPATH; *p; p++) {
312            if (*p == DELIM)
313                bufsz++; /* number of DELIM plus one */
314        }
315        bufsz *= strlen(pythonhome);
316    }
317    else
318        bufsz = 0;
319    bufsz += strlen(PYTHONPATH) + 1;
320    bufsz += strlen(argv0_path) + 1;
321    bufsz += strlen(zip_path) + 1;
322    if (envpath != NULL)
323        bufsz += strlen(envpath) + 1;
324
325    module_search_path = buf = malloc(bufsz);
326    if (buf == NULL) {
327        /* We can't exit, so print a warning and limp along */
328        fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
329        if (envpath) {
330            fprintf(stderr, "Using environment $PYTHONPATH.\n");
331            module_search_path = envpath;
332        }
333        else {
334            fprintf(stderr, "Using default static path.\n");
335            module_search_path = PYTHONPATH;
336        }
337        return;
338    }
339
340    if (envpath) {
341        strcpy(buf, envpath);
342        buf = strchr(buf, '\0');
343        *buf++ = DELIM;
344    }
345    if (zip_path[0]) {
346        strcpy(buf, zip_path);
347        buf = strchr(buf, '\0');
348        *buf++ = DELIM;
349    }
350
351    if (pythonhome == NULL) {
352        strcpy(buf, PYTHONPATH);
353        buf = strchr(buf, '\0');
354    }
355    else {
356        char *p = PYTHONPATH;
357        char *q;
358        size_t n;
359        for (;;) {
360            q = strchr(p, DELIM);
361            if (q == NULL)
362                n = strlen(p);
363            else
364                n = q-p;
365            if (p[0] == '.' && is_sep(p[1])) {
366                strcpy(buf, pythonhome);
367                buf = strchr(buf, '\0');
368                p++;
369                n--;
370            }
371            strncpy(buf, p, n);
372            buf += n;
373            if (q == NULL)
374                break;
375            *buf++ = DELIM;
376            p = q+1;
377        }
378    }
379    if (argv0_path) {
380        *buf++ = DELIM;
381        strcpy(buf, argv0_path);
382        buf = strchr(buf, '\0');
383    }
384    *buf = '\0';
385}
386
387
388/* External interface */
389
390char *
391Py_GetPath(void)
392{
393    if (!module_search_path)
394        calculate_path();
395    return module_search_path;
396}
397
398char *
399Py_GetPrefix(void)
400{
401    if (!module_search_path)
402        calculate_path();
403    return prefix;
404}
405
406char *
407Py_GetExecPrefix(void)
408{
409    return Py_GetPrefix();
410}
411
412char *
413Py_GetProgramFullPath(void)
414{
415    if (!module_search_path)
416        calculate_path();
417    return progpath;
418}
419