Fix off-by-one error that resulted in missed characters
[pytest.git] / PC / os2emx / getpathp.c
blob5839eab3654a675dd90520d0907d603f6a00d3c0
2 /* Return the initial module search path. */
3 /* This version used by OS/2+EMX */
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)
11 * Python always adds an empty entry at the start, which corresponds
12 to the current directory.
14 * If the PYTHONPATH env. var. exists, its entries are added next.
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)
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)
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.
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.
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.
44 ---------------------------------------------------------------- */
47 #include "Python.h"
48 #include "osdefs.h"
50 #ifndef PYOS_OS2
51 #error This file only compilable on OS/2
52 #endif
54 #define INCL_DOS
55 #include <os2.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <string.h>
61 #if HAVE_UNISTD_H
62 #include <unistd.h>
63 #endif /* HAVE_UNISTD_H */
65 /* Search in some common locations for the associated Python libraries.
67 * Py_GetPath() tries to return a sensible Python module search path.
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.
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
82 static char prefix[MAXPATHLEN+1];
83 static char progpath[MAXPATHLEN+1];
84 static char *module_search_path = NULL;
87 static int
88 is_sep(char ch) /* determine if "ch" is a separator character */
90 #ifdef ALTSEP
91 return ch == SEP || ch == ALTSEP;
92 #else
93 return ch == SEP;
94 #endif
97 /* assumes 'dir' null terminated in bounds.
98 * Never writes beyond existing terminator.
100 static void
101 reduce(char *dir)
103 size_t i = strlen(dir);
104 while (i > 0 && !is_sep(dir[i]))
105 --i;
106 dir[i] = '\0';
109 static int
110 exists(char *filename)
112 struct stat buf;
113 return stat(filename, &buf) == 0;
116 /* Is module (check for .pyc/.pyo too)
117 * Assumes 'filename' MAXPATHLEN+1 bytes long -
118 * may extend 'filename' by one character.
120 static int
121 ismodule(char *filename)
123 if (exists(filename))
124 return 1;
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;
132 return 0;
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.
145 static void
146 join(char *buffer, char *stuff)
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;
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';
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.
169 static int
170 gotlandmark(char *landmark)
172 int n, ok;
174 n = strlen(prefix);
175 join(prefix, landmark);
176 ok = ismodule(prefix);
177 prefix[n] = '\0';
178 return ok;
181 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
182 * assumption provided by only caller, calculate_path()
184 static int
185 search_for_prefix(char *argv0_path, char *landmark)
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;
198 static void
199 get_progpath(void)
201 extern char *Py_GetProgramName(void);
202 char *path = getenv("PATH");
203 char *prog = Py_GetProgramName();
205 PPIB pib;
206 if ((DosGetInfoBlocks(NULL, &pib) == 0) &&
207 (DosQueryModuleName(pib->pib_hmte, sizeof(progpath), progpath) == 0))
208 return;
210 if (prog == NULL || *prog == '\0')
211 prog = "python";
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.
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);
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';
239 else
240 strncpy(progpath, path, MAXPATHLEN);
242 /* join() is safe for MAXPATHLEN+1 size buffer */
243 join(progpath, prog);
244 if (exists(progpath))
245 break;
247 if (!delim) {
248 progpath[0] = '\0';
249 break;
251 path = delim + 1;
254 else
255 progpath[0] = '\0';
258 static void
259 calculate_path(void)
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;
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;
279 else
280 strncpy(prefix, pythonhome, MAXPATHLEN);
282 if (envpath && *envpath == '\0')
283 envpath = NULL;
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';
294 else {
295 zip_path[0] = 0;
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.
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 */
315 bufsz *= strlen(pythonhome);
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;
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;
333 else {
334 fprintf(stderr, "Using default static path.\n");
335 module_search_path = PYTHONPATH;
337 return;
340 if (envpath) {
341 strcpy(buf, envpath);
342 buf = strchr(buf, '\0');
343 *buf++ = DELIM;
345 if (zip_path[0]) {
346 strcpy(buf, zip_path);
347 buf = strchr(buf, '\0');
348 *buf++ = DELIM;
351 if (pythonhome == NULL) {
352 strcpy(buf, PYTHONPATH);
353 buf = strchr(buf, '\0');
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--;
371 strncpy(buf, p, n);
372 buf += n;
373 if (q == NULL)
374 break;
375 *buf++ = DELIM;
376 p = q+1;
379 if (argv0_path) {
380 *buf++ = DELIM;
381 strcpy(buf, argv0_path);
382 buf = strchr(buf, '\0');
384 *buf = '\0';
388 /* External interface */
390 char *
391 Py_GetPath(void)
393 if (!module_search_path)
394 calculate_path();
395 return module_search_path;
398 char *
399 Py_GetPrefix(void)
401 if (!module_search_path)
402 calculate_path();
403 return prefix;
406 char *
407 Py_GetExecPrefix(void)
409 return Py_GetPrefix();
412 char *
413 Py_GetProgramFullPath(void)
415 if (!module_search_path)
416 calculate_path();
417 return progpath;