Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/Python/pathconfig.c
Line
Count
Source (jump to first uncovered line)
1
/* Path configuration like module_search_path (sys.path) */
2
3
#include "Python.h"
4
#include "osdefs.h"
5
#include "pycore_initconfig.h"
6
#include "pycore_fileutils.h"
7
#include "pycore_pathconfig.h"
8
#include "pycore_pymem.h"
9
#include "pycore_pystate.h"
10
#include <wchar.h>
11
12
#ifdef __cplusplus
13
extern "C" {
14
#endif
15
16
17
_PyPathConfig _Py_path_config = _PyPathConfig_INIT;
18
#ifdef MS_WINDOWS
19
wchar_t *_Py_dll_path = NULL;
20
#endif
21
22
23
static int
24
copy_wstr(wchar_t **dst, const wchar_t *src)
25
266
{
26
266
    assert(*dst == NULL);
27
266
    if (src != NULL) {
28
196
        *dst = _PyMem_RawWcsdup(src);
29
196
        if (*dst == NULL) {
30
0
            return -1;
31
0
        }
32
196
    }
33
70
    else {
34
70
        *dst = NULL;
35
70
    }
36
266
    return 0;
37
266
}
38
39
40
static void
41
pathconfig_clear(_PyPathConfig *config)
42
28
{
43
    /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
44
       since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
45
       called before Py_Initialize() which can changes the memory allocator. */
46
28
    PyMemAllocatorEx old_alloc;
47
28
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
48
49
28
#define CLEAR(ATTR) \
50
168
    do { \
51
168
        PyMem_RawFree(ATTR); \
52
168
        ATTR = NULL; \
53
168
    } while (0)
54
55
28
    CLEAR(config->program_full_path);
56
28
    CLEAR(config->prefix);
57
28
    CLEAR(config->exec_prefix);
58
28
    CLEAR(config->module_search_path);
59
28
    CLEAR(config->program_name);
60
28
    CLEAR(config->home);
61
#ifdef MS_WINDOWS
62
    CLEAR(config->base_executable);
63
#endif
64
65
28
#undef CLEAR
66
67
28
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
68
28
}
69
70
71
static PyStatus
72
pathconfig_copy(_PyPathConfig *config, const _PyPathConfig *config2)
73
14
{
74
14
    pathconfig_clear(config);
75
76
14
#define COPY_ATTR(ATTR) \
77
84
    do { \
78
84
        if (copy_wstr(&config->ATTR, config2->ATTR) < 0) { \
79
0
            return _PyStatus_NO_MEMORY(); \
80
0
        } \
81
84
    } while (0)
82
83
14
    COPY_ATTR(program_full_path);
84
14
    COPY_ATTR(prefix);
85
14
    COPY_ATTR(exec_prefix);
86
14
    COPY_ATTR(module_search_path);
87
14
    COPY_ATTR(program_name);
88
14
    COPY_ATTR(home);
89
#ifdef MS_WINDOWS
90
    config->isolated = config2->isolated;
91
    config->site_import = config2->site_import;
92
    COPY_ATTR(base_executable);
93
#endif
94
95
14
#undef COPY_ATTR
96
97
14
    return _PyStatus_OK();
98
14
}
99
100
101
void
102
_PyPathConfig_ClearGlobal(void)
103
0
{
104
0
    PyMemAllocatorEx old_alloc;
105
0
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
106
107
0
    pathconfig_clear(&_Py_path_config);
108
#ifdef MS_WINDOWS
109
    PyMem_RawFree(_Py_dll_path);
110
    _Py_dll_path = NULL;
111
#endif
112
113
0
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
114
0
}
115
116
117
static wchar_t*
118
_PyWideStringList_Join(const PyWideStringList *list, wchar_t sep)
119
14
{
120
14
    size_t len = 1;   /* NUL terminator */
121
70
    for (Py_ssize_t i=0; i < list->length; i++) {
122
56
        if (i != 0) {
123
42
            len++;
124
42
        }
125
56
        len += wcslen(list->items[i]);
126
56
    }
127
128
14
    wchar_t *text = PyMem_RawMalloc(len * sizeof(wchar_t));
129
14
    if (text == NULL) {
130
0
        return NULL;
131
0
    }
132
14
    wchar_t *str = text;
133
70
    for (Py_ssize_t i=0; i < list->length; i++) {
134
56
        wchar_t *path = list->items[i];
135
56
        if (i != 0) {
136
42
            *str++ = sep;
137
42
        }
138
56
        len = wcslen(path);
139
56
        memcpy(str, path, len * sizeof(wchar_t));
140
56
        str += len;
141
56
    }
142
14
    *str = L'\0';
143
144
14
    return text;
145
14
}
146
147
148
#ifdef MS_WINDOWS
149
/* Initialize _Py_dll_path on Windows. Do nothing on other platforms. */
150
static PyStatus
151
_PyPathConfig_InitDLLPath(void)
152
{
153
    if (_Py_dll_path != NULL) {
154
        /* Already set: nothing to do */
155
        return _PyStatus_OK();
156
    }
157
158
    PyMemAllocatorEx old_alloc;
159
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
160
161
    _Py_dll_path = _Py_GetDLLPath();
162
163
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
164
165
    if (_Py_dll_path == NULL) {
166
        return _PyStatus_NO_MEMORY();
167
    }
168
    return _PyStatus_OK();
169
}
170
#endif
171
172
173
static PyStatus
174
pathconfig_set_from_config(_PyPathConfig *pathconfig, const PyConfig *config)
175
28
{
176
28
    PyStatus status;
177
28
    PyMemAllocatorEx old_alloc;
178
28
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
179
180
28
    if (config->module_search_paths_set) {
181
14
        PyMem_RawFree(pathconfig->module_search_path);
182
14
        pathconfig->module_search_path = _PyWideStringList_Join(&config->module_search_paths, DELIM);
183
14
        if (pathconfig->module_search_path == NULL) {
184
0
            goto no_memory;
185
0
        }
186
14
    }
187
188
28
#define COPY_CONFIG(PATH_ATTR, CONFIG_ATTR) \
189
140
        if (config->CONFIG_ATTR) { \
190
98
            PyMem_RawFree(pathconfig->PATH_ATTR); \
191
98
            pathconfig->PATH_ATTR = NULL; \
192
98
            if (copy_wstr(&pathconfig->PATH_ATTR, config->CONFIG_ATTR) < 0) { \
193
0
                goto no_memory; \
194
0
            } \
195
98
        }
196
197
28
    COPY_CONFIG(program_full_path, executable);
198
28
    COPY_CONFIG(prefix, prefix);
199
28
    COPY_CONFIG(exec_prefix, exec_prefix);
200
28
    COPY_CONFIG(program_name, program_name);
201
28
    COPY_CONFIG(home, home);
202
#ifdef MS_WINDOWS
203
    COPY_CONFIG(base_executable, base_executable);
204
#endif
205
206
28
#undef COPY_CONFIG
207
208
28
    status = _PyStatus_OK();
209
28
    goto done;
210
211
0
no_memory:
212
0
    status = _PyStatus_NO_MEMORY();
213
214
28
done:
215
28
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
216
28
    return status;
217
0
}
218
219
220
PyStatus
221
_PyConfig_WritePathConfig(const PyConfig *config)
222
14
{
223
#ifdef MS_WINDOWS
224
    PyStatus status = _PyPathConfig_InitDLLPath();
225
    if (_PyStatus_EXCEPTION(status)) {
226
        return status;
227
    }
228
#endif
229
230
14
    return pathconfig_set_from_config(&_Py_path_config, config);
231
14
}
232
233
234
static PyStatus
235
config_init_module_search_paths(PyConfig *config, _PyPathConfig *pathconfig)
236
14
{
237
14
    assert(!config->module_search_paths_set);
238
239
14
    _PyWideStringList_Clear(&config->module_search_paths);
240
241
14
    const wchar_t *sys_path = pathconfig->module_search_path;
242
14
    const wchar_t delim = DELIM;
243
14
    const wchar_t *p = sys_path;
244
56
    while (1) {
245
56
        p = wcschr(sys_path, delim);
246
56
        if (p == NULL) {
247
14
            p = sys_path + wcslen(sys_path); /* End of string */
248
14
        }
249
250
56
        size_t path_len = (p - sys_path);
251
56
        wchar_t *path = PyMem_RawMalloc((path_len + 1) * sizeof(wchar_t));
252
56
        if (path == NULL) {
253
0
            return _PyStatus_NO_MEMORY();
254
0
        }
255
56
        memcpy(path, sys_path, path_len * sizeof(wchar_t));
256
56
        path[path_len] = L'\0';
257
258
56
        PyStatus status = PyWideStringList_Append(&config->module_search_paths, path);
259
56
        PyMem_RawFree(path);
260
56
        if (_PyStatus_EXCEPTION(status)) {
261
0
            return status;
262
0
        }
263
264
56
        if (*p == '\0') {
265
14
            break;
266
14
        }
267
42
        sys_path = p + 1;
268
42
    }
269
14
    config->module_search_paths_set = 1;
270
14
    return _PyStatus_OK();
271
14
}
272
273
274
/* Calculate the path configuration:
275
276
   - exec_prefix
277
   - module_search_path
278
   - prefix
279
   - program_full_path
280
281
   On Windows, more fields are calculated:
282
283
   - base_executable
284
   - isolated
285
   - site_import
286
287
   On other platforms, isolated and site_import are left unchanged, and
288
   _PyConfig_InitPathConfig() copies executable to base_executable (if it's not
289
   set).
290
291
   Priority, highest to lowest:
292
293
   - PyConfig
294
   - _Py_path_config: set by Py_SetPath(), Py_SetPythonHome()
295
     and Py_SetProgramName()
296
   - _PyPathConfig_Calculate()
297
*/
298
static PyStatus
299
pathconfig_calculate(_PyPathConfig *pathconfig, const PyConfig *config)
300
14
{
301
14
    PyStatus status;
302
303
14
    PyMemAllocatorEx old_alloc;
304
14
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
305
306
14
    status = pathconfig_copy(pathconfig, &_Py_path_config);
307
14
    if (_PyStatus_EXCEPTION(status)) {
308
0
        goto done;
309
0
    }
310
311
14
    status = pathconfig_set_from_config(pathconfig, config);
312
14
    if (_PyStatus_EXCEPTION(status)) {
313
0
        goto done;
314
0
    }
315
316
14
    if (_Py_path_config.module_search_path == NULL) {
317
14
        status = _PyPathConfig_Calculate(pathconfig, config);
318
14
    }
319
0
    else {
320
        /* Py_SetPath() has been called: avoid _PyPathConfig_Calculate() */
321
0
    }
322
323
14
done:
324
14
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
325
14
    return status;
326
14
}
327
328
329
static PyStatus
330
config_calculate_pathconfig(PyConfig *config)
331
14
{
332
14
    _PyPathConfig pathconfig = _PyPathConfig_INIT;
333
14
    PyStatus status;
334
335
14
    status = pathconfig_calculate(&pathconfig, config);
336
14
    if (_PyStatus_EXCEPTION(status)) {
337
0
        goto done;
338
0
    }
339
340
14
    if (!config->module_search_paths_set) {
341
14
        status = config_init_module_search_paths(config, &pathconfig);
342
14
        if (_PyStatus_EXCEPTION(status)) {
343
0
            goto done;
344
0
        }
345
14
    }
346
347
14
#define COPY_ATTR(PATH_ATTR, CONFIG_ATTR) \
348
42
        if (config->CONFIG_ATTR == NULL) { \
349
42
            if (copy_wstr(&config->CONFIG_ATTR, pathconfig.PATH_ATTR) < 0) { \
350
0
                goto no_memory; \
351
0
            } \
352
42
        }
353
354
#ifdef MS_WINDOWS
355
    if (config->executable != NULL && config->base_executable == NULL) {
356
        /* If executable is set explicitly in the configuration,
357
           ignore calculated base_executable: _PyConfig_InitPathConfig()
358
           will copy executable to base_executable */
359
    }
360
    else {
361
        COPY_ATTR(base_executable, base_executable);
362
    }
363
#endif
364
365
14
    COPY_ATTR(program_full_path, executable);
366
14
    COPY_ATTR(prefix, prefix);
367
14
    COPY_ATTR(exec_prefix, exec_prefix);
368
369
14
#undef COPY_ATTR
370
371
#ifdef MS_WINDOWS
372
    /* If a ._pth file is found: isolated and site_import are overriden */
373
    if (pathconfig.isolated != -1) {
374
        config->isolated = pathconfig.isolated;
375
    }
376
    if (pathconfig.site_import != -1) {
377
        config->site_import = pathconfig.site_import;
378
    }
379
#endif
380
381
14
    status = _PyStatus_OK();
382
14
    goto done;
383
384
0
no_memory:
385
0
    status = _PyStatus_NO_MEMORY();
386
387
14
done:
388
14
    pathconfig_clear(&pathconfig);
389
14
    return status;
390
0
}
391
392
393
PyStatus
394
_PyConfig_InitPathConfig(PyConfig *config)
395
14
{
396
    /* Do we need to calculate the path? */
397
14
    if (!config->module_search_paths_set
398
14
        || config->executable == NULL
399
14
        || config->prefix == NULL
400
14
        || config->exec_prefix == NULL)
401
14
    {
402
14
        PyStatus status = config_calculate_pathconfig(config);
403
14
        if (_PyStatus_EXCEPTION(status)) {
404
0
            return status;
405
0
        }
406
14
    }
407
408
14
    if (config->base_prefix == NULL) {
409
14
        if (copy_wstr(&config->base_prefix, config->prefix) < 0) {
410
0
            return _PyStatus_NO_MEMORY();
411
0
        }
412
14
    }
413
414
14
    if (config->base_exec_prefix == NULL) {
415
14
        if (copy_wstr(&config->base_exec_prefix,
416
14
                      config->exec_prefix) < 0) {
417
0
            return _PyStatus_NO_MEMORY();
418
0
        }
419
14
    }
420
421
14
    if (config->base_executable == NULL) {
422
14
        if (copy_wstr(&config->base_executable,
423
14
                      config->executable) < 0) {
424
0
            return _PyStatus_NO_MEMORY();
425
0
        }
426
14
    }
427
428
14
    return _PyStatus_OK();
429
14
}
430
431
432
static PyStatus
433
pathconfig_global_read(_PyPathConfig *pathconfig)
434
0
{
435
0
    PyConfig config;
436
0
    _PyConfig_InitCompatConfig(&config);
437
438
    /* Call _PyConfig_InitPathConfig() */
439
0
    PyStatus status = PyConfig_Read(&config);
440
0
    if (_PyStatus_EXCEPTION(status)) {
441
0
        goto done;
442
0
    }
443
444
0
    status = pathconfig_set_from_config(pathconfig, &config);
445
446
0
done:
447
0
    PyConfig_Clear(&config);
448
0
    return status;
449
0
}
450
451
452
static void
453
pathconfig_global_init(void)
454
0
{
455
0
    PyStatus status;
456
457
#ifdef MS_WINDOWS
458
    status = _PyPathConfig_InitDLLPath();
459
    if (_PyStatus_EXCEPTION(status)) {
460
        Py_ExitStatusException(status);
461
    }
462
#endif
463
464
0
    if (_Py_path_config.module_search_path == NULL) {
465
0
        status = pathconfig_global_read(&_Py_path_config);
466
0
        if (_PyStatus_EXCEPTION(status)) {
467
0
            Py_ExitStatusException(status);
468
0
        }
469
0
    }
470
0
    else {
471
        /* Global configuration already initialized */
472
0
    }
473
474
0
    assert(_Py_path_config.program_full_path != NULL);
475
0
    assert(_Py_path_config.prefix != NULL);
476
0
    assert(_Py_path_config.exec_prefix != NULL);
477
0
    assert(_Py_path_config.module_search_path != NULL);
478
0
    assert(_Py_path_config.program_name != NULL);
479
    /* home can be NULL */
480
#ifdef MS_WINDOWS
481
    assert(_Py_path_config.base_executable != NULL);
482
#endif
483
0
}
484
485
486
/* External interface */
487
488
void
489
Py_SetPath(const wchar_t *path)
490
0
{
491
0
    if (path == NULL) {
492
0
        pathconfig_clear(&_Py_path_config);
493
0
        return;
494
0
    }
495
496
0
    PyMemAllocatorEx old_alloc;
497
0
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
498
499
    /* Getting the program full path calls pathconfig_global_init() */
500
0
    wchar_t *program_full_path = _PyMem_RawWcsdup(Py_GetProgramFullPath());
501
502
0
    PyMem_RawFree(_Py_path_config.program_full_path);
503
0
    PyMem_RawFree(_Py_path_config.prefix);
504
0
    PyMem_RawFree(_Py_path_config.exec_prefix);
505
0
    PyMem_RawFree(_Py_path_config.module_search_path);
506
507
0
    _Py_path_config.program_full_path = program_full_path;
508
0
    _Py_path_config.prefix = _PyMem_RawWcsdup(L"");
509
0
    _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L"");
510
0
    _Py_path_config.module_search_path = _PyMem_RawWcsdup(path);
511
512
0
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
513
514
0
    if (_Py_path_config.program_full_path == NULL
515
0
        || _Py_path_config.prefix == NULL
516
0
        || _Py_path_config.exec_prefix == NULL
517
0
        || _Py_path_config.module_search_path == NULL)
518
0
    {
519
0
        Py_FatalError("Py_SetPath() failed: out of memory");
520
0
    }
521
0
}
522
523
524
void
525
Py_SetPythonHome(const wchar_t *home)
526
14
{
527
14
    if (home == NULL) {
528
0
        return;
529
0
    }
530
531
14
    PyMemAllocatorEx old_alloc;
532
14
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
533
534
14
    PyMem_RawFree(_Py_path_config.home);
535
14
    _Py_path_config.home = _PyMem_RawWcsdup(home);
536
537
14
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
538
539
14
    if (_Py_path_config.home == NULL) {
540
0
        Py_FatalError("Py_SetPythonHome() failed: out of memory");
541
0
    }
542
14
}
543
544
545
void
546
Py_SetProgramName(const wchar_t *program_name)
547
0
{
548
0
    if (program_name == NULL || program_name[0] == L'\0') {
549
0
        return;
550
0
    }
551
552
0
    PyMemAllocatorEx old_alloc;
553
0
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
554
555
0
    PyMem_RawFree(_Py_path_config.program_name);
556
0
    _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
557
558
0
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
559
560
0
    if (_Py_path_config.program_name == NULL) {
561
0
        Py_FatalError("Py_SetProgramName() failed: out of memory");
562
0
    }
563
0
}
564
565
void
566
_Py_SetProgramFullPath(const wchar_t *program_full_path)
567
0
{
568
0
    if (program_full_path == NULL || program_full_path[0] == L'\0') {
569
0
        return;
570
0
    }
571
572
0
    PyMemAllocatorEx old_alloc;
573
0
    _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
574
575
0
    PyMem_RawFree(_Py_path_config.program_full_path);
576
0
    _Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path);
577
578
0
    PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
579
580
0
    if (_Py_path_config.program_full_path == NULL) {
581
0
        Py_FatalError("_Py_SetProgramFullPath() failed: out of memory");
582
0
    }
583
0
}
584
585
586
wchar_t *
587
Py_GetPath(void)
588
0
{
589
0
    pathconfig_global_init();
590
0
    return _Py_path_config.module_search_path;
591
0
}
592
593
594
wchar_t *
595
Py_GetPrefix(void)
596
0
{
597
0
    pathconfig_global_init();
598
0
    return _Py_path_config.prefix;
599
0
}
600
601
602
wchar_t *
603
Py_GetExecPrefix(void)
604
0
{
605
0
    pathconfig_global_init();
606
0
    return _Py_path_config.exec_prefix;
607
0
}
608
609
610
wchar_t *
611
Py_GetProgramFullPath(void)
612
0
{
613
0
    pathconfig_global_init();
614
0
    return _Py_path_config.program_full_path;
615
0
}
616
617
618
wchar_t*
619
Py_GetPythonHome(void)
620
0
{
621
0
    pathconfig_global_init();
622
0
    return _Py_path_config.home;
623
0
}
624
625
626
wchar_t *
627
Py_GetProgramName(void)
628
0
{
629
0
    pathconfig_global_init();
630
0
    return _Py_path_config.program_name;
631
0
}
632
633
/* Compute module search path from argv[0] or the current working
634
   directory ("-m module" case) which will be prepended to sys.argv:
635
   sys.path[0].
636
637
   Return 1 if the path is correctly resolved and written into *path0_p.
638
639
   Return 0 if it fails to resolve the full path. For example, return 0 if the
640
   current working directory has been removed (bpo-36236) or if argv is empty.
641
642
   Raise an exception and return -1 on error.
643
   */
644
int
645
_PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p)
646
0
{
647
0
    assert(_PyWideStringList_CheckConsistency(argv));
648
649
0
    if (argv->length == 0) {
650
        /* Leave sys.path unchanged if sys.argv is empty */
651
0
        return 0;
652
0
    }
653
654
0
    wchar_t *argv0 = argv->items[0];
655
0
    int have_module_arg = (wcscmp(argv0, L"-m") == 0);
656
0
    int have_script_arg = (!have_module_arg && (wcscmp(argv0, L"-c") != 0));
657
658
0
    wchar_t *path0 = argv0;
659
0
    Py_ssize_t n = 0;
660
661
0
#ifdef HAVE_REALPATH
662
0
    wchar_t fullpath[MAXPATHLEN];
663
#elif defined(MS_WINDOWS)
664
    wchar_t fullpath[MAX_PATH];
665
#endif
666
667
0
    if (have_module_arg) {
668
0
#if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
669
0
        if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) {
670
0
            return 0;
671
0
        }
672
0
        path0 = fullpath;
673
#else
674
        path0 = L".";
675
#endif
676
0
        n = wcslen(path0);
677
0
    }
678
679
0
#ifdef HAVE_READLINK
680
0
    wchar_t link[MAXPATHLEN + 1];
681
0
    int nr = 0;
682
683
0
    if (have_script_arg) {
684
0
        nr = _Py_wreadlink(path0, link, Py_ARRAY_LENGTH(link));
685
0
    }
686
0
    if (nr > 0) {
687
        /* It's a symlink */
688
0
        link[nr] = '\0';
689
0
        if (link[0] == SEP) {
690
0
            path0 = link; /* Link to absolute path */
691
0
        }
692
0
        else if (wcschr(link, SEP) == NULL) {
693
            /* Link without path */
694
0
        }
695
0
        else {
696
            /* Must join(dirname(path0), link) */
697
0
            wchar_t *q = wcsrchr(path0, SEP);
698
0
            if (q == NULL) {
699
                /* path0 without path */
700
0
                path0 = link;
701
0
            }
702
0
            else {
703
                /* Must make a copy, path0copy has room for 2 * MAXPATHLEN */
704
0
                wchar_t path0copy[2 * MAXPATHLEN + 1];
705
0
                wcsncpy(path0copy, path0, MAXPATHLEN);
706
0
                q = wcsrchr(path0copy, SEP);
707
0
                wcsncpy(q+1, link, MAXPATHLEN);
708
0
                q[MAXPATHLEN + 1] = L'\0';
709
0
                path0 = path0copy;
710
0
            }
711
0
        }
712
0
    }
713
0
#endif /* HAVE_READLINK */
714
715
0
    wchar_t *p = NULL;
716
717
#if SEP == '\\'
718
    /* Special case for Microsoft filename syntax */
719
    if (have_script_arg) {
720
        wchar_t *q;
721
#if defined(MS_WINDOWS)
722
        /* Replace the first element in argv with the full path. */
723
        wchar_t *ptemp;
724
        if (GetFullPathNameW(path0,
725
                           Py_ARRAY_LENGTH(fullpath),
726
                           fullpath,
727
                           &ptemp)) {
728
            path0 = fullpath;
729
        }
730
#endif
731
        p = wcsrchr(path0, SEP);
732
        /* Test for alternate separator */
733
        q = wcsrchr(p ? p : path0, '/');
734
        if (q != NULL)
735
            p = q;
736
        if (p != NULL) {
737
            n = p + 1 - path0;
738
            if (n > 1 && p[-1] != ':')
739
                n--; /* Drop trailing separator */
740
        }
741
    }
742
#else
743
    /* All other filename syntaxes */
744
0
    if (have_script_arg) {
745
0
#if defined(HAVE_REALPATH)
746
0
        if (_Py_wrealpath(path0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
747
0
            path0 = fullpath;
748
0
        }
749
0
#endif
750
0
        p = wcsrchr(path0, SEP);
751
0
    }
752
0
    if (p != NULL) {
753
0
        n = p + 1 - path0;
754
0
#if SEP == '/' /* Special case for Unix filename syntax */
755
0
        if (n > 1) {
756
            /* Drop trailing separator */
757
0
            n--;
758
0
        }
759
0
#endif /* Unix */
760
0
    }
761
0
#endif /* All others */
762
763
0
    PyObject *path0_obj = PyUnicode_FromWideChar(path0, n);
764
0
    if (path0_obj == NULL) {
765
0
        return -1;
766
0
    }
767
768
0
    *path0_p = path0_obj;
769
0
    return 1;
770
0
}
771
772
773
#ifdef MS_WINDOWS
774
#define WCSTOK wcstok_s
775
#else
776
0
#define WCSTOK wcstok
777
#endif
778
779
/* Search for a prefix value in an environment file (pyvenv.cfg).
780
   If found, copy it into the provided buffer. */
781
int
782
_Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
783
                       wchar_t *value, size_t value_size)
784
0
{
785
0
    int result = 0; /* meaning not found */
786
0
    char buffer[MAXPATHLEN * 2 + 1];  /* allow extra for key, '=', etc. */
787
0
    buffer[Py_ARRAY_LENGTH(buffer)-1] = '\0';
788
789
0
    fseek(env_file, 0, SEEK_SET);
790
0
    while (!feof(env_file)) {
791
0
        char * p = fgets(buffer, Py_ARRAY_LENGTH(buffer) - 1, env_file);
792
793
0
        if (p == NULL) {
794
0
            break;
795
0
        }
796
797
0
        size_t n = strlen(p);
798
0
        if (p[n - 1] != '\n') {
799
            /* line has overflowed - bail */
800
0
            break;
801
0
        }
802
0
        if (p[0] == '#') {
803
            /* Comment - skip */
804
0
            continue;
805
0
        }
806
807
0
        wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n, NULL);
808
0
        if (tmpbuffer) {
809
0
            wchar_t * state;
810
0
            wchar_t * tok = WCSTOK(tmpbuffer, L" \t\r\n", &state);
811
0
            if ((tok != NULL) && !wcscmp(tok, key)) {
812
0
                tok = WCSTOK(NULL, L" \t", &state);
813
0
                if ((tok != NULL) && !wcscmp(tok, L"=")) {
814
0
                    tok = WCSTOK(NULL, L"\r\n", &state);
815
0
                    if (tok != NULL) {
816
0
                        wcsncpy(value, tok, value_size - 1);
817
0
                        value[value_size - 1] = L'\0';
818
0
                        result = 1;
819
0
                        PyMem_RawFree(tmpbuffer);
820
0
                        break;
821
0
                    }
822
0
                }
823
0
            }
824
0
            PyMem_RawFree(tmpbuffer);
825
0
        }
826
0
    }
827
0
    return result;
828
0
}
829
830
#ifdef __cplusplus
831
}
832
#endif