/src/Python-3.8.3/Python/preconfig.c
Line  | Count  | Source  | 
1  |  | #include "Python.h"  | 
2  |  | #include "pycore_initconfig.h"  | 
3  |  | #include "pycore_getopt.h"  | 
4  |  | #include "pycore_pystate.h"   /* _PyRuntime_Initialize() */  | 
5  |  | #include <locale.h>       /* setlocale() */  | 
6  |  |  | 
7  |  |  | 
8  |  | #define DECODE_LOCALE_ERR(NAME, LEN) \  | 
9  | 0  |     (((LEN) == -2) \  | 
10  | 0  |      ? _PyStatus_ERR("cannot decode " NAME) \ | 
11  | 0  |      : _PyStatus_NO_MEMORY())  | 
12  |  |  | 
13  |  |  | 
14  |  | /* Forward declarations */  | 
15  |  | static void  | 
16  |  | preconfig_copy(PyPreConfig *config, const PyPreConfig *config2);  | 
17  |  |  | 
18  |  |  | 
19  |  | /* --- File system encoding/errors -------------------------------- */  | 
20  |  |  | 
21  |  | /* The filesystem encoding is chosen by config_init_fs_encoding(),  | 
22  |  |    see also initfsencoding().  | 
23  |  |  | 
24  |  |    Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors  | 
25  |  |    are encoded to UTF-8. */  | 
26  |  | const char *Py_FileSystemDefaultEncoding = NULL;  | 
27  |  | int Py_HasFileSystemDefaultEncoding = 0;  | 
28  |  | const char *Py_FileSystemDefaultEncodeErrors = NULL;  | 
29  |  | int _Py_HasFileSystemDefaultEncodeErrors = 0;  | 
30  |  |  | 
31  |  | void  | 
32  |  | _Py_ClearFileSystemEncoding(void)  | 
33  | 14  | { | 
34  | 14  |     if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { | 
35  | 0  |         PyMem_RawFree((char*)Py_FileSystemDefaultEncoding);  | 
36  | 0  |         Py_FileSystemDefaultEncoding = NULL;  | 
37  | 0  |     }  | 
38  | 14  |     if (!_Py_HasFileSystemDefaultEncodeErrors && Py_FileSystemDefaultEncodeErrors) { | 
39  | 0  |         PyMem_RawFree((char*)Py_FileSystemDefaultEncodeErrors);  | 
40  | 0  |         Py_FileSystemDefaultEncodeErrors = NULL;  | 
41  | 0  |     }  | 
42  | 14  | }  | 
43  |  |  | 
44  |  |  | 
45  |  | /* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors  | 
46  |  |    global configuration variables. */  | 
47  |  | int  | 
48  |  | _Py_SetFileSystemEncoding(const char *encoding, const char *errors)  | 
49  | 14  | { | 
50  | 14  |     char *encoding2 = _PyMem_RawStrdup(encoding);  | 
51  | 14  |     if (encoding2 == NULL) { | 
52  | 0  |         return -1;  | 
53  | 0  |     }  | 
54  |  |  | 
55  | 14  |     char *errors2 = _PyMem_RawStrdup(errors);  | 
56  | 14  |     if (errors2 == NULL) { | 
57  | 0  |         PyMem_RawFree(encoding2);  | 
58  | 0  |         return -1;  | 
59  | 0  |     }  | 
60  |  |  | 
61  | 14  |     _Py_ClearFileSystemEncoding();  | 
62  |  |  | 
63  | 14  |     Py_FileSystemDefaultEncoding = encoding2;  | 
64  | 14  |     Py_HasFileSystemDefaultEncoding = 0;  | 
65  |  |  | 
66  | 14  |     Py_FileSystemDefaultEncodeErrors = errors2;  | 
67  | 14  |     _Py_HasFileSystemDefaultEncodeErrors = 0;  | 
68  | 14  |     return 0;  | 
69  | 14  | }  | 
70  |  |  | 
71  |  |  | 
72  |  | /* --- _PyArgv ---------------------------------------------------- */  | 
73  |  |  | 
74  |  | /* Decode bytes_argv using Py_DecodeLocale() */  | 
75  |  | PyStatus  | 
76  |  | _PyArgv_AsWstrList(const _PyArgv *args, PyWideStringList *list)  | 
77  | 0  | { | 
78  | 0  |     PyWideStringList wargv = _PyWideStringList_INIT;  | 
79  | 0  |     if (args->use_bytes_argv) { | 
80  | 0  |         size_t size = sizeof(wchar_t*) * args->argc;  | 
81  | 0  |         wargv.items = (wchar_t **)PyMem_RawMalloc(size);  | 
82  | 0  |         if (wargv.items == NULL) { | 
83  | 0  |             return _PyStatus_NO_MEMORY();  | 
84  | 0  |         }  | 
85  |  |  | 
86  | 0  |         for (Py_ssize_t i = 0; i < args->argc; i++) { | 
87  | 0  |             size_t len;  | 
88  | 0  |             wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);  | 
89  | 0  |             if (arg == NULL) { | 
90  | 0  |                 _PyWideStringList_Clear(&wargv);  | 
91  | 0  |                 return DECODE_LOCALE_ERR("command line arguments", | 
92  | 0  |                                          (Py_ssize_t)len);  | 
93  | 0  |             }  | 
94  | 0  |             wargv.items[i] = arg;  | 
95  | 0  |             wargv.length++;  | 
96  | 0  |         }  | 
97  |  |  | 
98  | 0  |         _PyWideStringList_Clear(list);  | 
99  | 0  |         *list = wargv;  | 
100  | 0  |     }  | 
101  | 0  |     else { | 
102  | 0  |         wargv.length = args->argc;  | 
103  | 0  |         wargv.items = (wchar_t **)args->wchar_argv;  | 
104  | 0  |         if (_PyWideStringList_Copy(list, &wargv) < 0) { | 
105  | 0  |             return _PyStatus_NO_MEMORY();  | 
106  | 0  |         }  | 
107  | 0  |     }  | 
108  | 0  |     return _PyStatus_OK();  | 
109  | 0  | }  | 
110  |  |  | 
111  |  |  | 
112  |  | /* --- _PyPreCmdline ------------------------------------------------- */  | 
113  |  |  | 
114  |  | void  | 
115  |  | _PyPreCmdline_Clear(_PyPreCmdline *cmdline)  | 
116  | 28  | { | 
117  | 28  |     _PyWideStringList_Clear(&cmdline->argv);  | 
118  | 28  |     _PyWideStringList_Clear(&cmdline->xoptions);  | 
119  | 28  | }  | 
120  |  |  | 
121  |  |  | 
122  |  | PyStatus  | 
123  |  | _PyPreCmdline_SetArgv(_PyPreCmdline *cmdline, const _PyArgv *args)  | 
124  | 0  | { | 
125  | 0  |     return _PyArgv_AsWstrList(args, &cmdline->argv);  | 
126  | 0  | }  | 
127  |  |  | 
128  |  |  | 
129  |  | static void  | 
130  |  | precmdline_get_preconfig(_PyPreCmdline *cmdline, const PyPreConfig *config)  | 
131  | 28  | { | 
132  | 28  | #define COPY_ATTR(ATTR) \  | 
133  | 84  |     if (config->ATTR != -1) { \ | 
134  | 70  |         cmdline->ATTR = config->ATTR; \  | 
135  | 70  |     }  | 
136  |  |  | 
137  | 28  |     COPY_ATTR(isolated);  | 
138  | 28  |     COPY_ATTR(use_environment);  | 
139  | 28  |     COPY_ATTR(dev_mode);  | 
140  |  |  | 
141  | 28  | #undef COPY_ATTR  | 
142  | 28  | }  | 
143  |  |  | 
144  |  |  | 
145  |  | static void  | 
146  |  | precmdline_set_preconfig(const _PyPreCmdline *cmdline, PyPreConfig *config)  | 
147  | 14  | { | 
148  | 14  | #define COPY_ATTR(ATTR) \  | 
149  | 42  |     config->ATTR = cmdline->ATTR  | 
150  |  |  | 
151  | 14  |     COPY_ATTR(isolated);  | 
152  | 14  |     COPY_ATTR(use_environment);  | 
153  | 14  |     COPY_ATTR(dev_mode);  | 
154  |  |  | 
155  | 14  | #undef COPY_ATTR  | 
156  | 14  | }  | 
157  |  |  | 
158  |  |  | 
159  |  | PyStatus  | 
160  |  | _PyPreCmdline_SetConfig(const _PyPreCmdline *cmdline, PyConfig *config)  | 
161  | 14  | { | 
162  | 14  | #define COPY_ATTR(ATTR) \  | 
163  | 42  |     config->ATTR = cmdline->ATTR  | 
164  |  |  | 
165  | 14  |     PyStatus status = _PyWideStringList_Extend(&config->xoptions, &cmdline->xoptions);  | 
166  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
167  | 0  |         return status;  | 
168  | 0  |     }  | 
169  |  |  | 
170  | 14  |     COPY_ATTR(isolated);  | 
171  | 14  |     COPY_ATTR(use_environment);  | 
172  | 14  |     COPY_ATTR(dev_mode);  | 
173  | 14  |     return _PyStatus_OK();  | 
174  |  |  | 
175  | 14  | #undef COPY_ATTR  | 
176  | 14  | }  | 
177  |  |  | 
178  |  |  | 
179  |  | /* Parse the command line arguments */  | 
180  |  | static PyStatus  | 
181  |  | precmdline_parse_cmdline(_PyPreCmdline *cmdline)  | 
182  | 0  | { | 
183  | 0  |     const PyWideStringList *argv = &cmdline->argv;  | 
184  |  | 
  | 
185  | 0  |     _PyOS_ResetGetOpt();  | 
186  |  |     /* Don't log parsing errors into stderr here: PyConfig_Read()  | 
187  |  |        is responsible for that */  | 
188  | 0  |     _PyOS_opterr = 0;  | 
189  | 0  |     do { | 
190  | 0  |         int longindex = -1;  | 
191  | 0  |         int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);  | 
192  |  | 
  | 
193  | 0  |         if (c == EOF || c == 'c' || c == 'm') { | 
194  | 0  |             break;  | 
195  | 0  |         }  | 
196  |  |  | 
197  | 0  |         switch (c) { | 
198  | 0  |         case 'E':  | 
199  | 0  |             cmdline->use_environment = 0;  | 
200  | 0  |             break;  | 
201  |  |  | 
202  | 0  |         case 'I':  | 
203  | 0  |             cmdline->isolated = 1;  | 
204  | 0  |             break;  | 
205  |  |  | 
206  | 0  |         case 'X':  | 
207  | 0  |         { | 
208  | 0  |             PyStatus status = PyWideStringList_Append(&cmdline->xoptions,  | 
209  | 0  |                                                       _PyOS_optarg);  | 
210  | 0  |             if (_PyStatus_EXCEPTION(status)) { | 
211  | 0  |                 return status;  | 
212  | 0  |             }  | 
213  | 0  |             break;  | 
214  | 0  |         }  | 
215  |  |  | 
216  | 0  |         default:  | 
217  |  |             /* ignore other argument:  | 
218  |  |                handled by PyConfig_Read() */  | 
219  | 0  |             break;  | 
220  | 0  |         }  | 
221  | 0  |     } while (1);  | 
222  |  |  | 
223  | 0  |     return _PyStatus_OK();  | 
224  | 0  | }  | 
225  |  |  | 
226  |  |  | 
227  |  | PyStatus  | 
228  |  | _PyPreCmdline_Read(_PyPreCmdline *cmdline, const PyPreConfig *preconfig)  | 
229  | 28  | { | 
230  | 28  |     precmdline_get_preconfig(cmdline, preconfig);  | 
231  |  |  | 
232  | 28  |     if (preconfig->parse_argv) { | 
233  | 0  |         PyStatus status = precmdline_parse_cmdline(cmdline);  | 
234  | 0  |         if (_PyStatus_EXCEPTION(status)) { | 
235  | 0  |             return status;  | 
236  | 0  |         }  | 
237  | 0  |     }  | 
238  |  |  | 
239  |  |     /* isolated, use_environment */  | 
240  | 28  |     if (cmdline->isolated < 0) { | 
241  | 0  |         cmdline->isolated = 0;  | 
242  | 0  |     }  | 
243  | 28  |     if (cmdline->isolated > 0) { | 
244  | 0  |         cmdline->use_environment = 0;  | 
245  | 0  |     }  | 
246  | 28  |     if (cmdline->use_environment < 0) { | 
247  | 0  |         cmdline->use_environment = 0;  | 
248  | 0  |     }  | 
249  |  |  | 
250  |  |     /* dev_mode */  | 
251  | 28  |     if ((cmdline->dev_mode < 0)  | 
252  | 14  |         && (_Py_get_xoption(&cmdline->xoptions, L"dev")  | 
253  | 14  |             || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE")))  | 
254  | 0  |     { | 
255  | 0  |         cmdline->dev_mode = 1;  | 
256  | 0  |     }  | 
257  | 28  |     if (cmdline->dev_mode < 0) { | 
258  | 14  |         cmdline->dev_mode = 0;  | 
259  | 14  |     }  | 
260  |  |  | 
261  | 28  |     assert(cmdline->use_environment >= 0);  | 
262  | 28  |     assert(cmdline->isolated >= 0);  | 
263  | 28  |     assert(cmdline->dev_mode >= 0);  | 
264  |  |  | 
265  | 28  |     return _PyStatus_OK();  | 
266  | 28  | }  | 
267  |  |  | 
268  |  |  | 
269  |  | /* --- PyPreConfig ----------------------------------------------- */  | 
270  |  |  | 
271  |  |  | 
272  |  | void  | 
273  |  | _PyPreConfig_InitCompatConfig(PyPreConfig *config)  | 
274  | 84  | { | 
275  | 84  |     memset(config, 0, sizeof(*config));  | 
276  |  |  | 
277  | 84  |     config->_config_init = (int)_PyConfig_INIT_COMPAT;  | 
278  | 84  |     config->parse_argv = 0;  | 
279  | 84  |     config->isolated = -1;  | 
280  | 84  |     config->use_environment = -1;  | 
281  | 84  |     config->configure_locale = 1;  | 
282  |  |  | 
283  |  |     /* bpo-36443: C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)  | 
284  |  |        are disabled by default using the Compat configuration.  | 
285  |  |  | 
286  |  |        Py_UTF8Mode=1 enables the UTF-8 mode. PYTHONUTF8 environment variable  | 
287  |  |        is ignored (even if use_environment=1). */  | 
288  | 84  |     config->utf8_mode = 0;  | 
289  | 84  |     config->coerce_c_locale = 0;  | 
290  | 84  |     config->coerce_c_locale_warn = 0;  | 
291  |  |  | 
292  | 84  |     config->dev_mode = -1;  | 
293  | 84  |     config->allocator = PYMEM_ALLOCATOR_NOT_SET;  | 
294  |  | #ifdef MS_WINDOWS  | 
295  |  |     config->legacy_windows_fs_encoding = -1;  | 
296  |  | #endif  | 
297  | 84  | }  | 
298  |  |  | 
299  |  |  | 
300  |  | void  | 
301  |  | PyPreConfig_InitPythonConfig(PyPreConfig *config)  | 
302  | 70  | { | 
303  | 70  |     _PyPreConfig_InitCompatConfig(config);  | 
304  |  |  | 
305  | 70  |     config->_config_init = (int)_PyConfig_INIT_PYTHON;  | 
306  | 70  |     config->isolated = 0;  | 
307  | 70  |     config->parse_argv = 1;  | 
308  | 70  |     config->use_environment = 1;  | 
309  |  |     /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)  | 
310  |  |        depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE  | 
311  |  |        environment variables. */  | 
312  | 70  |     config->coerce_c_locale = -1;  | 
313  | 70  |     config->coerce_c_locale_warn = -1;  | 
314  | 70  |     config->utf8_mode = -1;  | 
315  |  | #ifdef MS_WINDOWS  | 
316  |  |     config->legacy_windows_fs_encoding = 0;  | 
317  |  | #endif  | 
318  | 70  | }  | 
319  |  |  | 
320  |  |  | 
321  |  | void  | 
322  |  | PyPreConfig_InitIsolatedConfig(PyPreConfig *config)  | 
323  | 0  | { | 
324  | 0  |     _PyPreConfig_InitCompatConfig(config);  | 
325  |  | 
  | 
326  | 0  |     config->_config_init = (int)_PyConfig_INIT_ISOLATED;  | 
327  | 0  |     config->configure_locale = 0;  | 
328  | 0  |     config->isolated = 1;  | 
329  | 0  |     config->use_environment = 0;  | 
330  | 0  |     config->utf8_mode = 0;  | 
331  | 0  |     config->dev_mode = 0;  | 
332  |  | #ifdef MS_WINDOWS  | 
333  |  |     config->legacy_windows_fs_encoding = 0;  | 
334  |  | #endif  | 
335  | 0  | }  | 
336  |  |  | 
337  |  |  | 
338  |  | PyStatus  | 
339  |  | _PyPreConfig_InitFromPreConfig(PyPreConfig *config,  | 
340  |  |                                const PyPreConfig *config2)  | 
341  | 56  | { | 
342  | 56  |     PyPreConfig_InitPythonConfig(config);  | 
343  | 56  |     preconfig_copy(config, config2);  | 
344  | 56  |     return _PyStatus_OK();  | 
345  | 56  | }  | 
346  |  |  | 
347  |  |  | 
348  |  | void  | 
349  |  | _PyPreConfig_InitFromConfig(PyPreConfig *preconfig, const PyConfig *config)  | 
350  | 14  | { | 
351  | 14  |     _PyConfigInitEnum config_init = (_PyConfigInitEnum)config->_config_init;  | 
352  | 14  |     switch (config_init) { | 
353  | 0  |     case _PyConfig_INIT_PYTHON:  | 
354  | 0  |         PyPreConfig_InitPythonConfig(preconfig);  | 
355  | 0  |         break;  | 
356  | 0  |     case _PyConfig_INIT_ISOLATED:  | 
357  | 0  |         PyPreConfig_InitIsolatedConfig(preconfig);  | 
358  | 0  |         break;  | 
359  | 14  |     case _PyConfig_INIT_COMPAT:  | 
360  | 14  |     default:  | 
361  | 14  |         _PyPreConfig_InitCompatConfig(preconfig);  | 
362  | 14  |     }  | 
363  |  |  | 
364  | 14  |     _PyPreConfig_GetConfig(preconfig, config);  | 
365  | 14  | }  | 
366  |  |  | 
367  |  |  | 
368  |  | static void  | 
369  |  | preconfig_copy(PyPreConfig *config, const PyPreConfig *config2)  | 
370  | 70  | { | 
371  | 700  | #define COPY_ATTR(ATTR) config->ATTR = config2->ATTR  | 
372  |  |  | 
373  | 70  |     COPY_ATTR(_config_init);  | 
374  | 70  |     COPY_ATTR(parse_argv);  | 
375  | 70  |     COPY_ATTR(isolated);  | 
376  | 70  |     COPY_ATTR(use_environment);  | 
377  | 70  |     COPY_ATTR(configure_locale);  | 
378  | 70  |     COPY_ATTR(dev_mode);  | 
379  | 70  |     COPY_ATTR(coerce_c_locale);  | 
380  | 70  |     COPY_ATTR(coerce_c_locale_warn);  | 
381  | 70  |     COPY_ATTR(utf8_mode);  | 
382  | 70  |     COPY_ATTR(allocator);  | 
383  |  | #ifdef MS_WINDOWS  | 
384  |  |     COPY_ATTR(legacy_windows_fs_encoding);  | 
385  |  | #endif  | 
386  |  |  | 
387  | 70  | #undef COPY_ATTR  | 
388  | 70  | }  | 
389  |  |  | 
390  |  |  | 
391  |  | PyObject*  | 
392  |  | _PyPreConfig_AsDict(const PyPreConfig *config)  | 
393  | 0  | { | 
394  | 0  |     PyObject *dict;  | 
395  |  | 
  | 
396  | 0  |     dict = PyDict_New();  | 
397  | 0  |     if (dict == NULL) { | 
398  | 0  |         return NULL;  | 
399  | 0  |     }  | 
400  |  |  | 
401  | 0  | #define SET_ITEM_INT(ATTR) \  | 
402  | 0  |         do { \ | 
403  | 0  |             PyObject *obj = PyLong_FromLong(config->ATTR); \  | 
404  | 0  |             if (obj == NULL) { \ | 
405  | 0  |                 goto fail; \  | 
406  | 0  |             } \  | 
407  | 0  |             int res = PyDict_SetItemString(dict, #ATTR, obj); \  | 
408  | 0  |             Py_DECREF(obj); \  | 
409  | 0  |             if (res < 0) { \ | 
410  | 0  |                 goto fail; \  | 
411  | 0  |             } \  | 
412  | 0  |         } while (0)  | 
413  |  |  | 
414  | 0  |     SET_ITEM_INT(_config_init);  | 
415  | 0  |     SET_ITEM_INT(parse_argv);  | 
416  | 0  |     SET_ITEM_INT(isolated);  | 
417  | 0  |     SET_ITEM_INT(use_environment);  | 
418  | 0  |     SET_ITEM_INT(configure_locale);  | 
419  | 0  |     SET_ITEM_INT(coerce_c_locale);  | 
420  | 0  |     SET_ITEM_INT(coerce_c_locale_warn);  | 
421  | 0  |     SET_ITEM_INT(utf8_mode);  | 
422  |  | #ifdef MS_WINDOWS  | 
423  |  |     SET_ITEM_INT(legacy_windows_fs_encoding);  | 
424  |  | #endif  | 
425  | 0  |     SET_ITEM_INT(dev_mode);  | 
426  | 0  |     SET_ITEM_INT(allocator);  | 
427  | 0  |     return dict;  | 
428  |  |  | 
429  | 0  | fail:  | 
430  | 0  |     Py_DECREF(dict);  | 
431  | 0  |     return NULL;  | 
432  |  | 
  | 
433  | 0  | #undef SET_ITEM_INT  | 
434  | 0  | }  | 
435  |  |  | 
436  |  |  | 
437  |  | void  | 
438  |  | _PyPreConfig_GetConfig(PyPreConfig *preconfig, const PyConfig *config)  | 
439  | 28  | { | 
440  | 28  | #define COPY_ATTR(ATTR) \  | 
441  | 112  |     if (config->ATTR != -1) { \ | 
442  | 56  |         preconfig->ATTR = config->ATTR; \  | 
443  | 56  |     }  | 
444  |  |  | 
445  | 28  |     COPY_ATTR(parse_argv);  | 
446  | 28  |     COPY_ATTR(isolated);  | 
447  | 28  |     COPY_ATTR(use_environment);  | 
448  | 28  |     COPY_ATTR(dev_mode);  | 
449  |  |  | 
450  | 28  | #undef COPY_ATTR  | 
451  | 28  | }  | 
452  |  |  | 
453  |  |  | 
454  |  | static void  | 
455  |  | preconfig_get_global_vars(PyPreConfig *config)  | 
456  | 14  | { | 
457  | 14  |     if (config->_config_init != _PyConfig_INIT_COMPAT) { | 
458  |  |         /* Python and Isolated configuration ignore global variables */  | 
459  | 0  |         return;  | 
460  | 0  |     }  | 
461  |  |  | 
462  | 14  | #define COPY_FLAG(ATTR, VALUE) \  | 
463  | 14  |     if (config->ATTR < 0) { \ | 
464  | 14  |         config->ATTR = VALUE; \  | 
465  | 14  |     }  | 
466  | 14  | #define COPY_NOT_FLAG(ATTR, VALUE) \  | 
467  | 14  |     if (config->ATTR < 0) { \ | 
468  | 14  |         config->ATTR = !(VALUE); \  | 
469  | 14  |     }  | 
470  |  |  | 
471  | 14  |     COPY_FLAG(isolated, Py_IsolatedFlag);  | 
472  | 14  |     COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);  | 
473  | 14  |     if (Py_UTF8Mode > 0) { | 
474  | 0  |         config->utf8_mode = Py_UTF8Mode;  | 
475  | 0  |     }  | 
476  |  | #ifdef MS_WINDOWS  | 
477  |  |     COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);  | 
478  |  | #endif  | 
479  |  |  | 
480  | 14  | #undef COPY_FLAG  | 
481  | 14  | #undef COPY_NOT_FLAG  | 
482  | 14  | }  | 
483  |  |  | 
484  |  |  | 
485  |  | static void  | 
486  |  | preconfig_set_global_vars(const PyPreConfig *config)  | 
487  | 14  | { | 
488  | 14  | #define COPY_FLAG(ATTR, VAR) \  | 
489  | 28  |     if (config->ATTR >= 0) { \ | 
490  | 28  |         VAR = config->ATTR; \  | 
491  | 28  |     }  | 
492  | 14  | #define COPY_NOT_FLAG(ATTR, VAR) \  | 
493  | 14  |     if (config->ATTR >= 0) { \ | 
494  | 14  |         VAR = !config->ATTR; \  | 
495  | 14  |     }  | 
496  |  |  | 
497  | 14  |     COPY_FLAG(isolated, Py_IsolatedFlag);  | 
498  | 14  |     COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);  | 
499  |  | #ifdef MS_WINDOWS  | 
500  |  |     COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);  | 
501  |  | #endif  | 
502  | 14  |     COPY_FLAG(utf8_mode, Py_UTF8Mode);  | 
503  |  |  | 
504  | 14  | #undef COPY_FLAG  | 
505  | 14  | #undef COPY_NOT_FLAG  | 
506  | 14  | }  | 
507  |  |  | 
508  |  |  | 
509  |  | const char*  | 
510  |  | _Py_GetEnv(int use_environment, const char *name)  | 
511  | 238  | { | 
512  | 238  |     assert(use_environment >= 0);  | 
513  |  |  | 
514  | 238  |     if (!use_environment) { | 
515  | 0  |         return NULL;  | 
516  | 0  |     }  | 
517  |  |  | 
518  | 238  |     const char *var = getenv(name);  | 
519  | 238  |     if (var && var[0] != '\0') { | 
520  | 14  |         return var;  | 
521  | 14  |     }  | 
522  | 224  |     else { | 
523  | 224  |         return NULL;  | 
524  | 224  |     }  | 
525  | 238  | }  | 
526  |  |  | 
527  |  |  | 
528  |  | int  | 
529  |  | _Py_str_to_int(const char *str, int *result)  | 
530  | 14  | { | 
531  | 14  |     const char *endptr = str;  | 
532  | 14  |     errno = 0;  | 
533  | 14  |     long value = strtol(str, (char **)&endptr, 10);  | 
534  | 14  |     if (*endptr != '\0' || errno == ERANGE) { | 
535  | 0  |         return -1;  | 
536  | 0  |     }  | 
537  | 14  |     if (value < INT_MIN || value > INT_MAX) { | 
538  | 0  |         return -1;  | 
539  | 0  |     }  | 
540  |  |  | 
541  | 14  |     *result = (int)value;  | 
542  | 14  |     return 0;  | 
543  | 14  | }  | 
544  |  |  | 
545  |  |  | 
546  |  | void  | 
547  |  | _Py_get_env_flag(int use_environment, int *flag, const char *name)  | 
548  | 98  | { | 
549  | 98  |     const char *var = _Py_GetEnv(use_environment, name);  | 
550  | 98  |     if (!var) { | 
551  | 84  |         return;  | 
552  | 84  |     }  | 
553  | 14  |     int value;  | 
554  | 14  |     if (_Py_str_to_int(var, &value) < 0 || value < 0) { | 
555  |  |         /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */  | 
556  | 0  |         value = 1;  | 
557  | 0  |     }  | 
558  | 14  |     if (*flag < value) { | 
559  | 14  |         *flag = value;  | 
560  | 14  |     }  | 
561  | 14  | }  | 
562  |  |  | 
563  |  |  | 
564  |  | const wchar_t*  | 
565  |  | _Py_get_xoption(const PyWideStringList *xoptions, const wchar_t *name)  | 
566  | 98  | { | 
567  | 98  |     for (Py_ssize_t i=0; i < xoptions->length; i++) { | 
568  | 0  |         const wchar_t *option = xoptions->items[i];  | 
569  | 0  |         size_t len;  | 
570  | 0  |         wchar_t *sep = wcschr(option, L'=');  | 
571  | 0  |         if (sep != NULL) { | 
572  | 0  |             len = (sep - option);  | 
573  | 0  |         }  | 
574  | 0  |         else { | 
575  | 0  |             len = wcslen(option);  | 
576  | 0  |         }  | 
577  | 0  |         if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') { | 
578  | 0  |             return option;  | 
579  | 0  |         }  | 
580  | 0  |     }  | 
581  | 98  |     return NULL;  | 
582  | 98  | }  | 
583  |  |  | 
584  |  |  | 
585  |  | static PyStatus  | 
586  |  | preconfig_init_utf8_mode(PyPreConfig *config, const _PyPreCmdline *cmdline)  | 
587  | 14  | { | 
588  |  | #ifdef MS_WINDOWS  | 
589  |  |     if (config->legacy_windows_fs_encoding) { | 
590  |  |         config->utf8_mode = 0;  | 
591  |  |     }  | 
592  |  | #endif  | 
593  |  |  | 
594  | 14  |     if (config->utf8_mode >= 0) { | 
595  | 14  |         return _PyStatus_OK();  | 
596  | 14  |     }  | 
597  |  |  | 
598  | 0  |     const wchar_t *xopt;  | 
599  | 0  |     xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");  | 
600  | 0  |     if (xopt) { | 
601  | 0  |         wchar_t *sep = wcschr(xopt, L'=');  | 
602  | 0  |         if (sep) { | 
603  | 0  |             xopt = sep + 1;  | 
604  | 0  |             if (wcscmp(xopt, L"1") == 0) { | 
605  | 0  |                 config->utf8_mode = 1;  | 
606  | 0  |             }  | 
607  | 0  |             else if (wcscmp(xopt, L"0") == 0) { | 
608  | 0  |                 config->utf8_mode = 0;  | 
609  | 0  |             }  | 
610  | 0  |             else { | 
611  | 0  |                 return _PyStatus_ERR("invalid -X utf8 option value"); | 
612  | 0  |             }  | 
613  | 0  |         }  | 
614  | 0  |         else { | 
615  | 0  |             config->utf8_mode = 1;  | 
616  | 0  |         }  | 
617  | 0  |         return _PyStatus_OK();  | 
618  | 0  |     }  | 
619  |  |  | 
620  | 0  |     const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8");  | 
621  | 0  |     if (opt) { | 
622  | 0  |         if (strcmp(opt, "1") == 0) { | 
623  | 0  |             config->utf8_mode = 1;  | 
624  | 0  |         }  | 
625  | 0  |         else if (strcmp(opt, "0") == 0) { | 
626  | 0  |             config->utf8_mode = 0;  | 
627  | 0  |         }  | 
628  | 0  |         else { | 
629  | 0  |             return _PyStatus_ERR("invalid PYTHONUTF8 environment " | 
630  | 0  |                                 "variable value");  | 
631  | 0  |         }  | 
632  | 0  |         return _PyStatus_OK();  | 
633  | 0  |     }  | 
634  |  |  | 
635  |  |  | 
636  | 0  | #ifndef MS_WINDOWS  | 
637  | 0  |     if (config->utf8_mode < 0) { | 
638  |  |         /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */  | 
639  | 0  |         const char *ctype_loc = setlocale(LC_CTYPE, NULL);  | 
640  | 0  |         if (ctype_loc != NULL  | 
641  | 0  |            && (strcmp(ctype_loc, "C") == 0  | 
642  | 0  |                || strcmp(ctype_loc, "POSIX") == 0))  | 
643  | 0  |         { | 
644  | 0  |             config->utf8_mode = 1;  | 
645  | 0  |         }  | 
646  | 0  |     }  | 
647  | 0  | #endif  | 
648  |  | 
  | 
649  | 0  |     if (config->utf8_mode < 0) { | 
650  | 0  |         config->utf8_mode = 0;  | 
651  | 0  |     }  | 
652  | 0  |     return _PyStatus_OK();  | 
653  | 0  | }  | 
654  |  |  | 
655  |  |  | 
656  |  | static void  | 
657  |  | preconfig_init_coerce_c_locale(PyPreConfig *config)  | 
658  | 14  | { | 
659  | 14  |     if (!config->configure_locale) { | 
660  | 0  |         config->coerce_c_locale = 0;  | 
661  | 0  |         config->coerce_c_locale_warn = 0;  | 
662  | 0  |         return;  | 
663  | 0  |     }  | 
664  |  |  | 
665  | 14  |     const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");  | 
666  | 14  |     if (env) { | 
667  | 0  |         if (strcmp(env, "0") == 0) { | 
668  | 0  |             if (config->coerce_c_locale < 0) { | 
669  | 0  |                 config->coerce_c_locale = 0;  | 
670  | 0  |             }  | 
671  | 0  |         }  | 
672  | 0  |         else if (strcmp(env, "warn") == 0) { | 
673  | 0  |             if (config->coerce_c_locale_warn < 0) { | 
674  | 0  |                 config->coerce_c_locale_warn = 1;  | 
675  | 0  |             }  | 
676  | 0  |         }  | 
677  | 0  |         else { | 
678  | 0  |             if (config->coerce_c_locale < 0) { | 
679  | 0  |                 config->coerce_c_locale = 1;  | 
680  | 0  |             }  | 
681  | 0  |         }  | 
682  | 0  |     }  | 
683  |  |  | 
684  |  |     /* Test if coerce_c_locale equals to -1 or equals to 1:  | 
685  |  |        PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.  | 
686  |  |        It is only coerced if if the LC_CTYPE locale is "C". */  | 
687  | 14  |     if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) { | 
688  |  |         /* The C locale enables the C locale coercion (PEP 538) */  | 
689  | 0  |         if (_Py_LegacyLocaleDetected(0)) { | 
690  | 0  |             config->coerce_c_locale = 2;  | 
691  | 0  |         }  | 
692  | 0  |         else { | 
693  | 0  |             config->coerce_c_locale = 0;  | 
694  | 0  |         }  | 
695  | 0  |     }  | 
696  |  |  | 
697  | 14  |     if (config->coerce_c_locale_warn < 0) { | 
698  | 0  |         config->coerce_c_locale_warn = 0;  | 
699  | 0  |     }  | 
700  | 14  | }  | 
701  |  |  | 
702  |  |  | 
703  |  | static PyStatus  | 
704  |  | preconfig_init_allocator(PyPreConfig *config)  | 
705  | 14  | { | 
706  | 14  |     if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) { | 
707  |  |         /* bpo-34247. The PYTHONMALLOC environment variable has the priority  | 
708  |  |            over PYTHONDEV env var and "-X dev" command line option.  | 
709  |  |            For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory  | 
710  |  |            allocators to "malloc" (and not to "debug"). */  | 
711  | 14  |         const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");  | 
712  | 14  |         if (envvar) { | 
713  | 0  |             PyMemAllocatorName name;  | 
714  | 0  |             if (_PyMem_GetAllocatorName(envvar, &name) < 0) { | 
715  | 0  |                 return _PyStatus_ERR("PYTHONMALLOC: unknown allocator"); | 
716  | 0  |             }  | 
717  | 0  |             config->allocator = (int)name;  | 
718  | 0  |         }  | 
719  | 14  |     }  | 
720  |  |  | 
721  | 14  |     if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) { | 
722  | 0  |         config->allocator = PYMEM_ALLOCATOR_DEBUG;  | 
723  | 0  |     }  | 
724  | 14  |     return _PyStatus_OK();  | 
725  | 14  | }  | 
726  |  |  | 
727  |  |  | 
728  |  | static PyStatus  | 
729  |  | preconfig_read(PyPreConfig *config, _PyPreCmdline *cmdline)  | 
730  | 14  | { | 
731  | 14  |     PyStatus status;  | 
732  |  |  | 
733  | 14  |     status = _PyPreCmdline_Read(cmdline, config);  | 
734  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
735  | 0  |         return status;  | 
736  | 0  |     }  | 
737  |  |  | 
738  | 14  |     precmdline_set_preconfig(cmdline, config);  | 
739  |  |  | 
740  |  |     /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */  | 
741  |  | #ifdef MS_WINDOWS  | 
742  |  |     _Py_get_env_flag(config->use_environment,  | 
743  |  |                      &config->legacy_windows_fs_encoding,  | 
744  |  |                      "PYTHONLEGACYWINDOWSFSENCODING");  | 
745  |  | #endif  | 
746  |  |  | 
747  | 14  |     preconfig_init_coerce_c_locale(config);  | 
748  |  |  | 
749  | 14  |     status = preconfig_init_utf8_mode(config, cmdline);  | 
750  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
751  | 0  |         return status;  | 
752  | 0  |     }  | 
753  |  |  | 
754  |  |     /* allocator */  | 
755  | 14  |     status = preconfig_init_allocator(config);  | 
756  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
757  | 0  |         return status;  | 
758  | 0  |     }  | 
759  |  |  | 
760  | 14  |     assert(config->coerce_c_locale >= 0);  | 
761  | 14  |     assert(config->coerce_c_locale_warn >= 0);  | 
762  |  | #ifdef MS_WINDOWS  | 
763  |  |     assert(config->legacy_windows_fs_encoding >= 0);  | 
764  |  | #endif  | 
765  | 14  |     assert(config->utf8_mode >= 0);  | 
766  | 14  |     assert(config->isolated >= 0);  | 
767  | 14  |     assert(config->use_environment >= 0);  | 
768  | 14  |     assert(config->dev_mode >= 0);  | 
769  |  |  | 
770  | 14  |     return _PyStatus_OK();  | 
771  | 14  | }  | 
772  |  |  | 
773  |  |  | 
774  |  | /* Read the configuration from:  | 
775  |  |  | 
776  |  |    - command line arguments  | 
777  |  |    - environment variables  | 
778  |  |    - Py_xxx global configuration variables  | 
779  |  |    - the LC_CTYPE locale */  | 
780  |  | PyStatus  | 
781  |  | _PyPreConfig_Read(PyPreConfig *config, const _PyArgv *args)  | 
782  | 14  | { | 
783  | 14  |     PyStatus status;  | 
784  |  |  | 
785  | 14  |     status = _PyRuntime_Initialize();  | 
786  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
787  | 0  |         return status;  | 
788  | 0  |     }  | 
789  |  |  | 
790  | 14  |     preconfig_get_global_vars(config);  | 
791  |  |  | 
792  |  |     /* Copy LC_CTYPE locale, since it's modified later */  | 
793  | 14  |     const char *loc = setlocale(LC_CTYPE, NULL);  | 
794  | 14  |     if (loc == NULL) { | 
795  | 0  |         return _PyStatus_ERR("failed to LC_CTYPE locale"); | 
796  | 0  |     }  | 
797  | 14  |     char *init_ctype_locale = _PyMem_RawStrdup(loc);  | 
798  | 14  |     if (init_ctype_locale == NULL) { | 
799  | 0  |         return _PyStatus_NO_MEMORY();  | 
800  | 0  |     }  | 
801  |  |  | 
802  |  |     /* Save the config to be able to restore it if encodings change */  | 
803  | 14  |     PyPreConfig save_config;  | 
804  |  |  | 
805  | 14  |     status = _PyPreConfig_InitFromPreConfig(&save_config, config);  | 
806  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
807  | 0  |         return status;  | 
808  | 0  |     }  | 
809  |  |  | 
810  |  |     /* Set LC_CTYPE to the user preferred locale */  | 
811  | 14  |     if (config->configure_locale) { | 
812  | 14  |         _Py_SetLocaleFromEnv(LC_CTYPE);  | 
813  | 14  |     }  | 
814  |  |  | 
815  | 14  |     _PyPreCmdline cmdline = _PyPreCmdline_INIT;  | 
816  | 14  |     int init_utf8_mode = Py_UTF8Mode;  | 
817  |  | #ifdef MS_WINDOWS  | 
818  |  |     int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;  | 
819  |  | #endif  | 
820  |  |  | 
821  | 14  |     if (args) { | 
822  | 0  |         status = _PyPreCmdline_SetArgv(&cmdline, args);  | 
823  | 0  |         if (_PyStatus_EXCEPTION(status)) { | 
824  | 0  |             goto done;  | 
825  | 0  |         }  | 
826  | 0  |     }  | 
827  |  |  | 
828  | 14  |     int locale_coerced = 0;  | 
829  | 14  |     int loops = 0;  | 
830  |  |  | 
831  | 14  |     while (1) { | 
832  | 14  |         int utf8_mode = config->utf8_mode;  | 
833  |  |  | 
834  |  |         /* Watchdog to prevent an infinite loop */  | 
835  | 14  |         loops++;  | 
836  | 14  |         if (loops == 3) { | 
837  | 0  |             status = _PyStatus_ERR("Encoding changed twice while " | 
838  | 0  |                                "reading the configuration");  | 
839  | 0  |             goto done;  | 
840  | 0  |         }  | 
841  |  |  | 
842  |  |         /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend  | 
843  |  |            on Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */  | 
844  | 14  |         Py_UTF8Mode = config->utf8_mode;  | 
845  |  | #ifdef MS_WINDOWS  | 
846  |  |         Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;  | 
847  |  | #endif  | 
848  |  |  | 
849  | 14  |         status = preconfig_read(config, &cmdline);  | 
850  | 14  |         if (_PyStatus_EXCEPTION(status)) { | 
851  | 0  |             goto done;  | 
852  | 0  |         }  | 
853  |  |  | 
854  |  |         /* The legacy C locale assumes ASCII as the default text encoding, which  | 
855  |  |          * causes problems not only for the CPython runtime, but also other  | 
856  |  |          * components like GNU readline.  | 
857  |  |          *  | 
858  |  |          * Accordingly, when the CLI detects it, it attempts to coerce it to a  | 
859  |  |          * more capable UTF-8 based alternative.  | 
860  |  |          *  | 
861  |  |          * See the documentation of the PYTHONCOERCECLOCALE setting for more  | 
862  |  |          * details.  | 
863  |  |          */  | 
864  | 14  |         int encoding_changed = 0;  | 
865  | 14  |         if (config->coerce_c_locale && !locale_coerced) { | 
866  | 0  |             locale_coerced = 1;  | 
867  | 0  |             _Py_CoerceLegacyLocale(0);  | 
868  | 0  |             encoding_changed = 1;  | 
869  | 0  |         }  | 
870  |  |  | 
871  | 14  |         if (utf8_mode == -1) { | 
872  | 0  |             if (config->utf8_mode == 1) { | 
873  |  |                 /* UTF-8 Mode enabled */  | 
874  | 0  |                 encoding_changed = 1;  | 
875  | 0  |             }  | 
876  | 0  |         }  | 
877  | 14  |         else { | 
878  | 14  |             if (config->utf8_mode != utf8_mode) { | 
879  | 0  |                 encoding_changed = 1;  | 
880  | 0  |             }  | 
881  | 14  |         }  | 
882  |  |  | 
883  | 14  |         if (!encoding_changed) { | 
884  | 14  |             break;  | 
885  | 14  |         }  | 
886  |  |  | 
887  |  |         /* Reset the configuration before reading again the configuration,  | 
888  |  |            just keep UTF-8 Mode value. */  | 
889  | 0  |         int new_utf8_mode = config->utf8_mode;  | 
890  | 0  |         int new_coerce_c_locale = config->coerce_c_locale;  | 
891  | 0  |         preconfig_copy(config, &save_config);  | 
892  | 0  |         config->utf8_mode = new_utf8_mode;  | 
893  | 0  |         config->coerce_c_locale = new_coerce_c_locale;  | 
894  |  |  | 
895  |  |         /* The encoding changed: read again the configuration  | 
896  |  |            with the new encoding */  | 
897  | 0  |     }  | 
898  | 14  |     status = _PyStatus_OK();  | 
899  |  |  | 
900  | 14  | done:  | 
901  | 14  |     if (init_ctype_locale != NULL) { | 
902  | 14  |         setlocale(LC_CTYPE, init_ctype_locale);  | 
903  | 14  |         PyMem_RawFree(init_ctype_locale);  | 
904  | 14  |     }  | 
905  | 14  |     Py_UTF8Mode = init_utf8_mode ;  | 
906  |  | #ifdef MS_WINDOWS  | 
907  |  |     Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;  | 
908  |  | #endif  | 
909  | 14  |     _PyPreCmdline_Clear(&cmdline);  | 
910  | 14  |     return status;  | 
911  | 14  | }  | 
912  |  |  | 
913  |  |  | 
914  |  | /* Write the pre-configuration:  | 
915  |  |  | 
916  |  |    - set the memory allocators  | 
917  |  |    - set Py_xxx global configuration variables  | 
918  |  |    - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode  | 
919  |  |      (PEP 540)  | 
920  |  |  | 
921  |  |    The applied configuration is written into _PyRuntime.preconfig.  | 
922  |  |    If the C locale cannot be coerced, set coerce_c_locale to 0.  | 
923  |  |  | 
924  |  |    Do nothing if called after Py_Initialize(): ignore the new  | 
925  |  |    pre-configuration. */  | 
926  |  | PyStatus  | 
927  |  | _PyPreConfig_Write(const PyPreConfig *src_config)  | 
928  | 14  | { | 
929  | 14  |     PyPreConfig config;  | 
930  |  |  | 
931  | 14  |     PyStatus status = _PyPreConfig_InitFromPreConfig(&config, src_config);  | 
932  | 14  |     if (_PyStatus_EXCEPTION(status)) { | 
933  | 0  |         return status;  | 
934  | 0  |     }  | 
935  |  |  | 
936  | 14  |     if (_PyRuntime.core_initialized) { | 
937  |  |         /* bpo-34008: Calling this functions after Py_Initialize() ignores  | 
938  |  |            the new configuration. */  | 
939  | 0  |         return _PyStatus_OK();  | 
940  | 0  |     }  | 
941  |  |  | 
942  | 14  |     PyMemAllocatorName name = (PyMemAllocatorName)config.allocator;  | 
943  | 14  |     if (name != PYMEM_ALLOCATOR_NOT_SET) { | 
944  | 0  |         if (_PyMem_SetupAllocators(name) < 0) { | 
945  | 0  |             return _PyStatus_ERR("Unknown PYTHONMALLOC allocator"); | 
946  | 0  |         }  | 
947  | 0  |     }  | 
948  |  |  | 
949  | 14  |     preconfig_set_global_vars(&config);  | 
950  |  |  | 
951  | 14  |     if (config.configure_locale) { | 
952  | 14  |         if (config.coerce_c_locale) { | 
953  | 0  |             if (!_Py_CoerceLegacyLocale(config.coerce_c_locale_warn)) { | 
954  |  |                 /* C locale not coerced */  | 
955  | 0  |                 config.coerce_c_locale = 0;  | 
956  | 0  |             }  | 
957  | 0  |         }  | 
958  |  |  | 
959  |  |         /* Set LC_CTYPE to the user preferred locale */  | 
960  | 14  |         _Py_SetLocaleFromEnv(LC_CTYPE);  | 
961  | 14  |     }  | 
962  |  |  | 
963  |  |     /* Write the new pre-configuration into _PyRuntime */  | 
964  | 14  |     preconfig_copy(&_PyRuntime.preconfig, &config);  | 
965  |  |  | 
966  | 14  |     return _PyStatus_OK();  | 
967  | 14  | }  |