blob: 748084ba44894e27d06ab027b63ebd3b1c242c38 [file] [log] [blame]
Victor Stinner31a83932017-12-04 13:39:15 +01001/* Path configuration like module_search_path (sys.path) */
2
3#include "Python.h"
4#include "osdefs.h"
5#include "internal/pystate.h"
6
7#ifdef __cplusplus
8extern "C" {
9#endif
10
11
12_PyPathConfig _Py_path_config = _PyPathConfig_INIT;
13
14
15void
16_PyPathConfig_Clear(_PyPathConfig *config)
17{
18 /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
19 since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
20 called before Py_Initialize() which can changes the memory allocator. */
21 PyMemAllocatorEx old_alloc;
22 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
23
24#define CLEAR(ATTR) \
25 do { \
26 PyMem_RawFree(ATTR); \
27 ATTR = NULL; \
28 } while (0)
29
30 CLEAR(config->prefix);
31 CLEAR(config->program_full_path);
32#ifdef MS_WINDOWS
33 CLEAR(config->dll_path);
34#else
35 CLEAR(config->exec_prefix);
36#endif
37 CLEAR(config->module_search_path);
38 CLEAR(config->home);
39 CLEAR(config->program_name);
40#undef CLEAR
41
42 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
43}
44
45
46/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
47 and Py_GetProgramFullPath() */
48_PyInitError
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010049_PyPathConfig_Init(const _PyCoreConfig *core_config)
Victor Stinner31a83932017-12-04 13:39:15 +010050{
51 if (_Py_path_config.module_search_path) {
52 /* Already initialized */
53 return _Py_INIT_OK();
54 }
55
56 _PyInitError err;
57 _PyPathConfig new_config = _PyPathConfig_INIT;
58
59 PyMemAllocatorEx old_alloc;
60 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
61
62 /* Calculate program_full_path, prefix, exec_prefix (Unix)
63 or dll_path (Windows), and module_search_path */
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010064 err = _PyPathConfig_Calculate(&new_config, core_config);
Victor Stinner31a83932017-12-04 13:39:15 +010065 if (_Py_INIT_FAILED(err)) {
66 _PyPathConfig_Clear(&new_config);
67 goto done;
68 }
69
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010070 /* Copy home and program_name from core_config */
71 if (core_config->home != NULL) {
72 new_config.home = _PyMem_RawWcsdup(core_config->home);
Victor Stinner31a83932017-12-04 13:39:15 +010073 if (new_config.home == NULL) {
74 err = _Py_INIT_NO_MEMORY();
75 goto done;
76 }
77 }
78 else {
79 new_config.home = NULL;
80 }
81
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010082 new_config.program_name = _PyMem_RawWcsdup(core_config->program_name);
Victor Stinner31a83932017-12-04 13:39:15 +010083 if (new_config.program_name == NULL) {
84 err = _Py_INIT_NO_MEMORY();
85 goto done;
86 }
87
88 _PyPathConfig_Clear(&_Py_path_config);
89 _Py_path_config = new_config;
90
91 err = _Py_INIT_OK();
92
93done:
94 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
95 return err;
96}
97
98
99static void
100pathconfig_global_init(void)
101{
102 if (_Py_path_config.module_search_path) {
103 /* Already initialized */
104 return;
105 }
106
107 _PyInitError err;
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100108 _PyCoreConfig config = _PyCoreConfig_INIT;
Victor Stinner31a83932017-12-04 13:39:15 +0100109
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100110 err = _PyCoreConfig_ReadEnv(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100111 if (_Py_INIT_FAILED(err)) {
112 goto error;
113 }
114
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100115 err = _PyCoreConfig_Read(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100116 if (_Py_INIT_FAILED(err)) {
117 goto error;
118 }
119
120 err = _PyPathConfig_Init(&config);
121 if (_Py_INIT_FAILED(err)) {
122 goto error;
123 }
124
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100125 _PyCoreConfig_Clear(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100126 return;
127
128error:
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100129 _PyCoreConfig_Clear(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100130 _Py_FatalInitError(err);
131}
132
133
134/* External interface */
135
136void
137Py_SetPath(const wchar_t *path)
138{
139 if (path == NULL) {
140 _PyPathConfig_Clear(&_Py_path_config);
141 return;
142 }
143
144 PyMemAllocatorEx old_alloc;
145 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
146
147 _PyPathConfig new_config;
148 new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName());
149 new_config.prefix = _PyMem_RawWcsdup(L"");
150#ifdef MS_WINDOWS
151 new_config.dll_path = _PyMem_RawWcsdup(L"");
152#else
153 new_config.exec_prefix = _PyMem_RawWcsdup(L"");
154#endif
155 new_config.module_search_path = _PyMem_RawWcsdup(path);
156
157 /* steal the home and program_name values (to leave them unchanged) */
158 new_config.home = _Py_path_config.home;
159 _Py_path_config.home = NULL;
160 new_config.program_name = _Py_path_config.program_name;
161 _Py_path_config.program_name = NULL;
162
163 _PyPathConfig_Clear(&_Py_path_config);
164 _Py_path_config = new_config;
165
166 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
167}
168
169
170void
Serhiy Storchaka4ae06c52017-12-12 13:55:04 +0200171Py_SetPythonHome(const wchar_t *home)
Victor Stinner31a83932017-12-04 13:39:15 +0100172{
173 if (home == NULL) {
174 return;
175 }
176
177 PyMemAllocatorEx old_alloc;
178 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
179
180 PyMem_RawFree(_Py_path_config.home);
181 _Py_path_config.home = _PyMem_RawWcsdup(home);
182
183 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
184
185 if (_Py_path_config.home == NULL) {
186 Py_FatalError("Py_SetPythonHome() failed: out of memory");
187 }
188}
189
190
191void
Serhiy Storchaka4ae06c52017-12-12 13:55:04 +0200192Py_SetProgramName(const wchar_t *program_name)
Victor Stinner31a83932017-12-04 13:39:15 +0100193{
194 if (program_name == NULL || program_name[0] == L'\0') {
195 return;
196 }
197
198 PyMemAllocatorEx old_alloc;
199 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
200
201 PyMem_RawFree(_Py_path_config.program_name);
202 _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
203
204 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
205
206 if (_Py_path_config.program_name == NULL) {
207 Py_FatalError("Py_SetProgramName() failed: out of memory");
208 }
209}
210
211
212wchar_t *
213Py_GetPath(void)
214{
215 pathconfig_global_init();
216 return _Py_path_config.module_search_path;
217}
218
219
220wchar_t *
221Py_GetPrefix(void)
222{
223 pathconfig_global_init();
224 return _Py_path_config.prefix;
225}
226
227
228wchar_t *
229Py_GetExecPrefix(void)
230{
231#ifdef MS_WINDOWS
232 return Py_GetPrefix();
233#else
234 pathconfig_global_init();
235 return _Py_path_config.exec_prefix;
236#endif
237}
238
239
240wchar_t *
241Py_GetProgramFullPath(void)
242{
243 pathconfig_global_init();
244 return _Py_path_config.program_full_path;
245}
246
247
248wchar_t*
249Py_GetPythonHome(void)
250{
251 pathconfig_global_init();
252 return _Py_path_config.home;
253}
254
255
256wchar_t *
257Py_GetProgramName(void)
258{
259 pathconfig_global_init();
260 return _Py_path_config.program_name;
261}
262
263
Victor Stinner11a247d2017-12-13 21:05:57 +0100264#define _HAVE_SCRIPT_ARGUMENT(argc, argv) \
265 (argc > 0 && argv0 != NULL && \
266 wcscmp(argv0, L"-c") != 0 && wcscmp(argv0, L"-m") != 0)
267
268/* Compute argv[0] which will be prepended to sys.argv */
269PyObject*
270_PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
271{
272 wchar_t *argv0;
273 wchar_t *p = NULL;
274 Py_ssize_t n = 0;
275#ifdef HAVE_READLINK
276 wchar_t link[MAXPATHLEN+1];
277 wchar_t argv0copy[2*MAXPATHLEN+1];
278 int nr = 0;
279#endif
280#if defined(HAVE_REALPATH)
281 wchar_t fullpath[MAXPATHLEN];
282#elif defined(MS_WINDOWS)
283 wchar_t fullpath[MAX_PATH];
284#endif
285
286
287 argv0 = argv[0];
288
289#ifdef HAVE_READLINK
290 if (_HAVE_SCRIPT_ARGUMENT(argc, argv))
291 nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
292 if (nr > 0) {
293 /* It's a symlink */
294 link[nr] = '\0';
295 if (link[0] == SEP)
296 argv0 = link; /* Link to absolute path */
297 else if (wcschr(link, SEP) == NULL)
298 ; /* Link without path */
299 else {
300 /* Must join(dirname(argv0), link) */
301 wchar_t *q = wcsrchr(argv0, SEP);
302 if (q == NULL)
303 argv0 = link; /* argv0 without path */
304 else {
305 /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
306 wcsncpy(argv0copy, argv0, MAXPATHLEN);
307 q = wcsrchr(argv0copy, SEP);
308 wcsncpy(q+1, link, MAXPATHLEN);
309 q[MAXPATHLEN + 1] = L'\0';
310 argv0 = argv0copy;
311 }
312 }
313 }
314#endif /* HAVE_READLINK */
315
316#if SEP == '\\'
317 /* Special case for Microsoft filename syntax */
318 if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
319 wchar_t *q;
320#if defined(MS_WINDOWS)
321 /* Replace the first element in argv with the full path. */
322 wchar_t *ptemp;
323 if (GetFullPathNameW(argv0,
324 Py_ARRAY_LENGTH(fullpath),
325 fullpath,
326 &ptemp)) {
327 argv0 = fullpath;
328 }
329#endif
330 p = wcsrchr(argv0, SEP);
331 /* Test for alternate separator */
332 q = wcsrchr(p ? p : argv0, '/');
333 if (q != NULL)
334 p = q;
335 if (p != NULL) {
336 n = p + 1 - argv0;
337 if (n > 1 && p[-1] != ':')
338 n--; /* Drop trailing separator */
339 }
340 }
341#else /* All other filename syntaxes */
342 if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
343#if defined(HAVE_REALPATH)
344 if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
345 argv0 = fullpath;
346 }
347#endif
348 p = wcsrchr(argv0, SEP);
349 }
350 if (p != NULL) {
351 n = p + 1 - argv0;
352#if SEP == '/' /* Special case for Unix filename syntax */
353 if (n > 1)
354 n--; /* Drop trailing separator */
355#endif /* Unix */
356 }
357#endif /* All others */
358
359 return PyUnicode_FromWideChar(argv0, n);
360}
361
Victor Stinner31a83932017-12-04 13:39:15 +0100362#ifdef __cplusplus
363}
364#endif