blob: 985af39cb00d7d3c8c23622ee423613ffc9acc0c [file] [log] [blame]
Victor Stinner91b9ecf2019-03-01 17:52:56 +01001#include "Python.h"
2#include "pycore_coreconfig.h"
Victor Stinner6dcb5422019-03-05 02:44:12 +01003#include "pycore_getopt.h"
Victor Stinner5a02e0d2019-03-05 12:32:09 +01004#include "pycore_pystate.h" /* _PyRuntime_Initialize() */
5#include <locale.h> /* setlocale() */
Victor Stinner91b9ecf2019-03-01 17:52:56 +01006
7
8#define DECODE_LOCALE_ERR(NAME, LEN) \
9 (((LEN) == -2) \
Victor Stinnerdb719752019-05-01 05:35:33 +020010 ? _Py_INIT_ERR("cannot decode " NAME) \
Victor Stinner91b9ecf2019-03-01 17:52:56 +010011 : _Py_INIT_NO_MEMORY())
12
13
14/* --- File system encoding/errors -------------------------------- */
15
16/* The filesystem encoding is chosen by config_init_fs_encoding(),
Victor Stinner709d23d2019-05-02 14:56:30 -040017 see also initfsencoding().
18
19 Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
20 are encoded to UTF-8. */
Victor Stinner91b9ecf2019-03-01 17:52:56 +010021const char *Py_FileSystemDefaultEncoding = NULL;
22int Py_HasFileSystemDefaultEncoding = 0;
23const char *Py_FileSystemDefaultEncodeErrors = NULL;
24int _Py_HasFileSystemDefaultEncodeErrors = 0;
25
26void
27_Py_ClearFileSystemEncoding(void)
28{
29 if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) {
30 PyMem_RawFree((char*)Py_FileSystemDefaultEncoding);
31 Py_FileSystemDefaultEncoding = NULL;
32 }
33 if (!_Py_HasFileSystemDefaultEncodeErrors && Py_FileSystemDefaultEncodeErrors) {
34 PyMem_RawFree((char*)Py_FileSystemDefaultEncodeErrors);
35 Py_FileSystemDefaultEncodeErrors = NULL;
36 }
37}
38
39
40/* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
41 global configuration variables. */
42int
43_Py_SetFileSystemEncoding(const char *encoding, const char *errors)
44{
45 char *encoding2 = _PyMem_RawStrdup(encoding);
46 if (encoding2 == NULL) {
47 return -1;
48 }
49
50 char *errors2 = _PyMem_RawStrdup(errors);
51 if (errors2 == NULL) {
52 PyMem_RawFree(encoding2);
53 return -1;
54 }
55
56 _Py_ClearFileSystemEncoding();
57
58 Py_FileSystemDefaultEncoding = encoding2;
59 Py_HasFileSystemDefaultEncoding = 0;
60
61 Py_FileSystemDefaultEncodeErrors = errors2;
62 _Py_HasFileSystemDefaultEncodeErrors = 0;
63 return 0;
64}
65
66
67/* --- _PyArgv ---------------------------------------------------- */
68
Victor Stinnerf8ba6f52019-03-26 16:58:50 +010069/* Decode bytes_argv using Py_DecodeLocale() */
Victor Stinner91b9ecf2019-03-01 17:52:56 +010070_PyInitError
Victor Stinner74f65682019-03-15 15:08:05 +010071_PyArgv_AsWstrList(const _PyArgv *args, _PyWstrList *list)
Victor Stinner91b9ecf2019-03-01 17:52:56 +010072{
Victor Stinner74f65682019-03-15 15:08:05 +010073 _PyWstrList wargv = _PyWstrList_INIT;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010074 if (args->use_bytes_argv) {
Victor Stinner74f65682019-03-15 15:08:05 +010075 size_t size = sizeof(wchar_t*) * args->argc;
76 wargv.items = (wchar_t **)PyMem_RawMalloc(size);
77 if (wargv.items == NULL) {
Victor Stinner91b9ecf2019-03-01 17:52:56 +010078 return _Py_INIT_NO_MEMORY();
79 }
80
Victor Stinner74f65682019-03-15 15:08:05 +010081 for (Py_ssize_t i = 0; i < args->argc; i++) {
Victor Stinner91b9ecf2019-03-01 17:52:56 +010082 size_t len;
83 wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
84 if (arg == NULL) {
Victor Stinner74f65682019-03-15 15:08:05 +010085 _PyWstrList_Clear(&wargv);
Victor Stinner91b9ecf2019-03-01 17:52:56 +010086 return DECODE_LOCALE_ERR("command line arguments",
87 (Py_ssize_t)len);
88 }
Victor Stinner74f65682019-03-15 15:08:05 +010089 wargv.items[i] = arg;
90 wargv.length++;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010091 }
Victor Stinner74f65682019-03-15 15:08:05 +010092
93 _PyWstrList_Clear(list);
94 *list = wargv;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010095 }
96 else {
Victor Stinner74f65682019-03-15 15:08:05 +010097 wargv.length = args->argc;
98 wargv.items = args->wchar_argv;
99 if (_PyWstrList_Copy(list, &wargv) < 0) {
100 return _Py_INIT_NO_MEMORY();
101 }
Victor Stinner91b9ecf2019-03-01 17:52:56 +0100102 }
Victor Stinner91b9ecf2019-03-01 17:52:56 +0100103 return _Py_INIT_OK();
104}
Victor Stinnercad1f742019-03-05 02:01:27 +0100105
106
Victor Stinner6dcb5422019-03-05 02:44:12 +0100107/* --- _PyPreCmdline ------------------------------------------------- */
108
Victor Stinnerfa153762019-03-20 04:25:38 +0100109void
110_PyPreCmdline_Clear(_PyPreCmdline *cmdline)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100111{
Victor Stinner74f65682019-03-15 15:08:05 +0100112 _PyWstrList_Clear(&cmdline->argv);
113 _PyWstrList_Clear(&cmdline->xoptions);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100114}
115
116
Victor Stinnerfa153762019-03-20 04:25:38 +0100117_PyInitError
Victor Stinnerf72346c2019-03-25 17:54:58 +0100118_PyPreCmdline_SetArgv(_PyPreCmdline *cmdline, const _PyArgv *args)
Victor Stinnerfa153762019-03-20 04:25:38 +0100119{
120 return _PyArgv_AsWstrList(args, &cmdline->argv);
121}
122
123
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100124static void
Victor Stinnerf72346c2019-03-25 17:54:58 +0100125_PyPreCmdline_GetPreConfig(_PyPreCmdline *cmdline, const _PyPreConfig *config)
126{
127#define COPY_ATTR(ATTR) \
128 if (config->ATTR != -1) { \
129 cmdline->ATTR = config->ATTR; \
130 }
131
Victor Stinnerf72346c2019-03-25 17:54:58 +0100132 COPY_ATTR(isolated);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100133 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100134 COPY_ATTR(dev_mode);
135
136#undef COPY_ATTR
137}
138
139
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100140static void
Victor Stinner20004952019-03-26 02:31:11 +0100141_PyPreCmdline_SetPreConfig(const _PyPreCmdline *cmdline, _PyPreConfig *config)
142{
143#define COPY_ATTR(ATTR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100144 config->ATTR = cmdline->ATTR
Victor Stinner20004952019-03-26 02:31:11 +0100145
Victor Stinner20004952019-03-26 02:31:11 +0100146 COPY_ATTR(isolated);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100147 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100148 COPY_ATTR(dev_mode);
Victor Stinnerf72346c2019-03-25 17:54:58 +0100149
150#undef COPY_ATTR
151}
152
153
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100154int
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100155_PyPreCmdline_SetCoreConfig(const _PyPreCmdline *cmdline, _PyCoreConfig *config)
156{
157#define COPY_ATTR(ATTR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100158 config->ATTR = cmdline->ATTR
159
160 if (_PyWstrList_Extend(&config->xoptions, &cmdline->xoptions) < 0) {
161 return -1;
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100162 }
163
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100164 COPY_ATTR(isolated);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100165 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100166 COPY_ATTR(dev_mode);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100167 return 0;
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100168
169#undef COPY_ATTR
170}
171
172
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100173/* Parse the command line arguments */
174static _PyInitError
175precmdline_parse_cmdline(_PyPreCmdline *cmdline)
176{
Victor Stinner870b0352019-05-17 03:15:12 +0200177 const _PyWstrList *argv = &cmdline->argv;
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100178
179 _PyOS_ResetGetOpt();
180 /* Don't log parsing errors into stderr here: _PyCoreConfig_Read()
181 is responsible for that */
182 _PyOS_opterr = 0;
183 do {
184 int longindex = -1;
185 int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
186
187 if (c == EOF || c == 'c' || c == 'm') {
188 break;
189 }
190
191 switch (c) {
192 case 'E':
193 cmdline->use_environment = 0;
194 break;
195
196 case 'I':
197 cmdline->isolated = 1;
198 break;
199
200 case 'X':
201 {
202 if (_PyWstrList_Append(&cmdline->xoptions, _PyOS_optarg) < 0) {
203 return _Py_INIT_NO_MEMORY();
204 }
205 break;
206 }
207
208 default:
209 /* ignore other argument:
210 handled by _PyCoreConfig_Read() */
211 break;
212 }
213 } while (1);
214
215 return _Py_INIT_OK();
216}
217
218
219_PyInitError
220_PyPreCmdline_Read(_PyPreCmdline *cmdline,
Victor Stinner5ac27a52019-03-27 13:40:14 +0100221 const _PyPreConfig *preconfig)
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100222{
223 if (preconfig) {
224 _PyPreCmdline_GetPreConfig(cmdline, preconfig);
225 }
226
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100227 _PyInitError err = precmdline_parse_cmdline(cmdline);
228 if (_Py_INIT_FAILED(err)) {
229 return err;
230 }
231
232 /* isolated, use_environment */
233 if (cmdline->isolated < 0) {
234 cmdline->isolated = 0;
235 }
236 if (cmdline->isolated > 0) {
237 cmdline->use_environment = 0;
238 }
239 if (cmdline->use_environment < 0) {
240 cmdline->use_environment = 0;
241 }
242
243 /* dev_mode */
244 if ((cmdline && _Py_get_xoption(&cmdline->xoptions, L"dev"))
245 || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE"))
246 {
247 cmdline->dev_mode = 1;
248 }
249 if (cmdline->dev_mode < 0) {
250 cmdline->dev_mode = 0;
251 }
252
253 assert(cmdline->use_environment >= 0);
254 assert(cmdline->isolated >= 0);
255 assert(cmdline->dev_mode >= 0);
256
257 return _Py_INIT_OK();
258}
259
260
Victor Stinnercad1f742019-03-05 02:01:27 +0100261/* --- _PyPreConfig ----------------------------------------------- */
262
Victor Stinnercab5d072019-05-17 19:01:14 +0200263void
264_PyPreConfig_Init(_PyPreConfig *config)
265{
266 *config = _PyPreConfig_INIT;
267}
268
269
270void
271_PyPreConfig_InitPythonConfig(_PyPreConfig *config)
272{
273 _PyPreConfig_Init(config);
274
275 /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)
276 depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE
277 environment variables. */
278 config->coerce_c_locale = -1;
279 config->coerce_c_locale_warn = -1;
280 config->utf8_mode = -1;
281}
282
283
284void
285_PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
286{
287 _PyPreConfig_Init(config);
288
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200289 config->configure_locale = 0;
Victor Stinnercab5d072019-05-17 19:01:14 +0200290 config->isolated = 1;
291 config->use_environment = 0;
292#ifdef MS_WINDOWS
293 config->legacy_windows_fs_encoding = 0;
294#endif
295 config->utf8_mode = 0;
296 config->dev_mode = 0;
297}
298
299
Victor Stinnercad1f742019-03-05 02:01:27 +0100300int
301_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
302{
Victor Stinnercad1f742019-03-05 02:01:27 +0100303#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100304#define COPY_STR_ATTR(ATTR) \
305 do { \
306 if (config2->ATTR != NULL) { \
307 config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
308 if (config->ATTR == NULL) { \
309 return -1; \
310 } \
311 } \
312 } while (0)
Victor Stinnercad1f742019-03-05 02:01:27 +0100313
314 COPY_ATTR(isolated);
315 COPY_ATTR(use_environment);
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200316 COPY_ATTR(configure_locale);
Victor Stinner20004952019-03-26 02:31:11 +0100317 COPY_ATTR(dev_mode);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100318 COPY_ATTR(coerce_c_locale);
319 COPY_ATTR(coerce_c_locale_warn);
320#ifdef MS_WINDOWS
321 COPY_ATTR(legacy_windows_fs_encoding);
322#endif
323 COPY_ATTR(utf8_mode);
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200324 COPY_ATTR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100325
326#undef COPY_ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100327#undef COPY_STR_ATTR
Victor Stinnercad1f742019-03-05 02:01:27 +0100328 return 0;
329}
330
331
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100332PyObject*
333_PyPreConfig_AsDict(const _PyPreConfig *config)
334{
335 PyObject *dict;
336
337 dict = PyDict_New();
338 if (dict == NULL) {
339 return NULL;
340 }
341
342#define SET_ITEM(KEY, EXPR) \
343 do { \
344 PyObject *obj = (EXPR); \
345 if (obj == NULL) { \
346 goto fail; \
347 } \
348 int res = PyDict_SetItemString(dict, (KEY), obj); \
349 Py_DECREF(obj); \
350 if (res < 0) { \
351 goto fail; \
352 } \
353 } while (0)
354#define SET_ITEM_INT(ATTR) \
355 SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
356#define FROM_STRING(STR) \
357 ((STR != NULL) ? \
358 PyUnicode_FromString(STR) \
359 : (Py_INCREF(Py_None), Py_None))
360#define SET_ITEM_STR(ATTR) \
361 SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
362
363 SET_ITEM_INT(isolated);
364 SET_ITEM_INT(use_environment);
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200365 SET_ITEM_INT(configure_locale);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100366 SET_ITEM_INT(coerce_c_locale);
367 SET_ITEM_INT(coerce_c_locale_warn);
368 SET_ITEM_INT(utf8_mode);
369#ifdef MS_WINDOWS
370 SET_ITEM_INT(legacy_windows_fs_encoding);
371#endif
372 SET_ITEM_INT(dev_mode);
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200373 SET_ITEM_INT(allocator);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100374 return dict;
375
376fail:
377 Py_DECREF(dict);
378 return NULL;
379
380#undef FROM_STRING
381#undef SET_ITEM
382#undef SET_ITEM_INT
383#undef SET_ITEM_STR
384}
385
386
Victor Stinner5ac27a52019-03-27 13:40:14 +0100387void
Victor Stinnercab5d072019-05-17 19:01:14 +0200388_PyPreConfig_GetCoreConfig(_PyPreConfig *config,
Victor Stinner5ac27a52019-03-27 13:40:14 +0100389 const _PyCoreConfig *core_config)
390{
391#define COPY_ATTR(ATTR) \
392 if (core_config->ATTR != -1) { \
393 config->ATTR = core_config->ATTR; \
394 }
395
396 COPY_ATTR(isolated);
397 COPY_ATTR(use_environment);
398 COPY_ATTR(dev_mode);
399
400#undef COPY_ATTR
401}
402
403
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100404static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100405_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
406{
407#define COPY_FLAG(ATTR, VALUE) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200408 if (config->ATTR < 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100409 config->ATTR = VALUE; \
410 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100411#define COPY_NOT_FLAG(ATTR, VALUE) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200412 if (config->ATTR < 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100413 config->ATTR = !(VALUE); \
414 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100415
416 COPY_FLAG(isolated, Py_IsolatedFlag);
417 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100418#ifdef MS_WINDOWS
419 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
420#endif
Victor Stinnercab5d072019-05-17 19:01:14 +0200421 if (config->utf8_mode == -2) {
422 config->utf8_mode = Py_UTF8Mode;
Victor Stinnerd929f182019-03-27 18:28:46 +0100423 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100424
425#undef COPY_FLAG
426#undef COPY_NOT_FLAG
427}
428
429
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100430static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100431_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
432{
433#define COPY_FLAG(ATTR, VAR) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200434 if (config->ATTR >= 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100435 VAR = config->ATTR; \
436 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100437#define COPY_NOT_FLAG(ATTR, VAR) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200438 if (config->ATTR >= 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100439 VAR = !config->ATTR; \
440 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100441
442 COPY_FLAG(isolated, Py_IsolatedFlag);
443 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100444#ifdef MS_WINDOWS
445 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
446#endif
447 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100448
449#undef COPY_FLAG
450#undef COPY_NOT_FLAG
451}
452
453
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100454const char*
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100455_Py_GetEnv(int use_environment, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100456{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100457 assert(use_environment >= 0);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100458
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100459 if (!use_environment) {
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100460 return NULL;
461 }
462
463 const char *var = getenv(name);
464 if (var && var[0] != '\0') {
465 return var;
466 }
467 else {
468 return NULL;
469 }
470}
471
472
473int
474_Py_str_to_int(const char *str, int *result)
475{
476 const char *endptr = str;
477 errno = 0;
478 long value = strtol(str, (char **)&endptr, 10);
479 if (*endptr != '\0' || errno == ERANGE) {
480 return -1;
481 }
482 if (value < INT_MIN || value > INT_MAX) {
483 return -1;
484 }
485
486 *result = (int)value;
487 return 0;
488}
489
490
491void
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100492_Py_get_env_flag(int use_environment, int *flag, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100493{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100494 const char *var = _Py_GetEnv(use_environment, name);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100495 if (!var) {
496 return;
497 }
498 int value;
499 if (_Py_str_to_int(var, &value) < 0 || value < 0) {
500 /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
501 value = 1;
502 }
503 if (*flag < value) {
504 *flag = value;
505 }
506}
507
508
509const wchar_t*
Victor Stinner74f65682019-03-15 15:08:05 +0100510_Py_get_xoption(const _PyWstrList *xoptions, const wchar_t *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100511{
Victor Stinner74f65682019-03-15 15:08:05 +0100512 for (Py_ssize_t i=0; i < xoptions->length; i++) {
513 const wchar_t *option = xoptions->items[i];
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100514 size_t len;
515 wchar_t *sep = wcschr(option, L'=');
516 if (sep != NULL) {
517 len = (sep - option);
518 }
519 else {
520 len = wcslen(option);
521 }
522 if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
523 return option;
524 }
525 }
526 return NULL;
527}
528
529
530static _PyInitError
531preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
532{
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100533#ifdef MS_WINDOWS
534 if (config->legacy_windows_fs_encoding) {
535 config->utf8_mode = 0;
536 }
537#endif
538
539 if (config->utf8_mode >= 0) {
540 return _Py_INIT_OK();
541 }
542
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100543 const wchar_t *xopt;
544 if (cmdline) {
Victor Stinner74f65682019-03-15 15:08:05 +0100545 xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100546 }
547 else {
548 xopt = NULL;
549 }
550 if (xopt) {
551 wchar_t *sep = wcschr(xopt, L'=');
552 if (sep) {
553 xopt = sep + 1;
554 if (wcscmp(xopt, L"1") == 0) {
555 config->utf8_mode = 1;
556 }
557 else if (wcscmp(xopt, L"0") == 0) {
558 config->utf8_mode = 0;
559 }
560 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200561 return _Py_INIT_ERR("invalid -X utf8 option value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100562 }
563 }
564 else {
565 config->utf8_mode = 1;
566 }
567 return _Py_INIT_OK();
568 }
569
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100570 const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100571 if (opt) {
572 if (strcmp(opt, "1") == 0) {
573 config->utf8_mode = 1;
574 }
575 else if (strcmp(opt, "0") == 0) {
576 config->utf8_mode = 0;
577 }
578 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200579 return _Py_INIT_ERR("invalid PYTHONUTF8 environment "
580 "variable value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100581 }
582 return _Py_INIT_OK();
583 }
584
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100585
586#ifndef MS_WINDOWS
587 if (config->utf8_mode < 0) {
588 /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
589 const char *ctype_loc = setlocale(LC_CTYPE, NULL);
590 if (ctype_loc != NULL
591 && (strcmp(ctype_loc, "C") == 0
592 || strcmp(ctype_loc, "POSIX") == 0))
593 {
594 config->utf8_mode = 1;
595 }
596 }
597#endif
598
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100599 if (config->utf8_mode < 0) {
600 config->utf8_mode = 0;
601 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100602 return _Py_INIT_OK();
603}
604
605
606static void
607preconfig_init_coerce_c_locale(_PyPreConfig *config)
608{
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200609 if (!config->configure_locale) {
610 config->coerce_c_locale = 0;
611 config->coerce_c_locale_warn = 0;
612 return;
613 }
614
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100615 const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
616 if (env) {
617 if (strcmp(env, "0") == 0) {
618 if (config->coerce_c_locale < 0) {
619 config->coerce_c_locale = 0;
620 }
621 }
622 else if (strcmp(env, "warn") == 0) {
Victor Stinnercab5d072019-05-17 19:01:14 +0200623 if (config->coerce_c_locale_warn < 0) {
624 config->coerce_c_locale_warn = 1;
625 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100626 }
627 else {
628 if (config->coerce_c_locale < 0) {
629 config->coerce_c_locale = 1;
630 }
631 }
632 }
633
634 /* Test if coerce_c_locale equals to -1 or equals to 1:
635 PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.
636 It is only coerced if if the LC_CTYPE locale is "C". */
Victor Stinnercab5d072019-05-17 19:01:14 +0200637 if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
638 /* The C locale enables the C locale coercion (PEP 538) */
639 if (_Py_LegacyLocaleDetected()) {
640 config->coerce_c_locale = 2;
641 }
642 else {
643 config->coerce_c_locale = 0;
644 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100645 }
646
Victor Stinnercab5d072019-05-17 19:01:14 +0200647 if (config->coerce_c_locale_warn < 0) {
648 config->coerce_c_locale_warn = 0;
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100649 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100650}
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100651
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100652
653static _PyInitError
654preconfig_init_allocator(_PyPreConfig *config)
655{
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200656 if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
Victor Stinner25d13f32019-03-06 12:51:53 +0100657 /* bpo-34247. The PYTHONMALLOC environment variable has the priority
658 over PYTHONDEV env var and "-X dev" command line option.
659 For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
660 allocators to "malloc" (and not to "debug"). */
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200661 const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
662 if (envvar) {
663 if (_PyMem_GetAllocatorName(envvar, &config->allocator) < 0) {
664 return _Py_INIT_ERR("PYTHONMALLOC: unknown allocator");
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100665 }
666 }
667 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100668
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200669 if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
670 config->allocator = PYMEM_ALLOCATOR_DEBUG;
Victor Stinner25d13f32019-03-06 12:51:53 +0100671 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100672 return _Py_INIT_OK();
673}
674
675
676static _PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100677preconfig_read(_PyPreConfig *config, _PyPreCmdline *cmdline)
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100678{
679 _PyInitError err;
680
Victor Stinner5ac27a52019-03-27 13:40:14 +0100681 err = _PyPreCmdline_Read(cmdline, config);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100682 if (_Py_INIT_FAILED(err)) {
683 return err;
684 }
685
686 _PyPreCmdline_SetPreConfig(cmdline, config);
687
688 /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */
689#ifdef MS_WINDOWS
690 _Py_get_env_flag(config->use_environment,
691 &config->legacy_windows_fs_encoding,
692 "PYTHONLEGACYWINDOWSFSENCODING");
693#endif
694
695 preconfig_init_coerce_c_locale(config);
696
697 err = preconfig_init_utf8_mode(config, cmdline);
698 if (_Py_INIT_FAILED(err)) {
699 return err;
700 }
701
702 /* allocator */
703 err = preconfig_init_allocator(config);
704 if (_Py_INIT_FAILED(err)) {
705 return err;
706 }
Victor Stinner25d13f32019-03-06 12:51:53 +0100707
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100708 assert(config->coerce_c_locale >= 0);
Victor Stinnercab5d072019-05-17 19:01:14 +0200709 assert(config->coerce_c_locale_warn >= 0);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100710#ifdef MS_WINDOWS
711 assert(config->legacy_windows_fs_encoding >= 0);
712#endif
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100713 assert(config->utf8_mode >= 0);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100714 assert(config->isolated >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100715 assert(config->use_environment >= 0);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100716 assert(config->dev_mode >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100717
718 return _Py_INIT_OK();
719}
720
721
Victor Stinner4fffd382019-03-06 01:44:31 +0100722/* Read the configuration from:
723
724 - command line arguments
725 - environment variables
726 - Py_xxx global configuration variables
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100727 - the LC_CTYPE locale */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100728_PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100729_PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100730{
731 _PyInitError err;
732
733 err = _PyRuntime_Initialize();
734 if (_Py_INIT_FAILED(err)) {
735 return err;
736 }
737
Victor Stinnerf29084d2019-03-20 02:20:13 +0100738 _PyPreConfig_GetGlobalConfig(config);
739
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100740 /* Copy LC_CTYPE locale, since it's modified later */
741 const char *loc = setlocale(LC_CTYPE, NULL);
742 if (loc == NULL) {
743 return _Py_INIT_ERR("failed to LC_CTYPE locale");
744 }
745 char *init_ctype_locale = _PyMem_RawStrdup(loc);
746 if (init_ctype_locale == NULL) {
747 return _Py_INIT_NO_MEMORY();
748 }
749
750 /* Save the config to be able to restore it if encodings change */
Victor Stinnercab5d072019-05-17 19:01:14 +0200751 _PyPreConfig save_config;
752 _PyPreConfig_Init(&save_config);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100753 if (_PyPreConfig_Copy(&save_config, config) < 0) {
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100754 return _Py_INIT_NO_MEMORY();
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100755 }
756
757 /* Set LC_CTYPE to the user preferred locale */
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200758 if (config->configure_locale) {
759 _Py_SetLocaleFromEnv(LC_CTYPE);
760 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100761
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100762 _PyPreCmdline cmdline = _PyPreCmdline_INIT;
Victor Stinner6a8c3132019-04-05 11:44:04 +0200763 int init_utf8_mode = Py_UTF8Mode;
764#ifdef MS_WINDOWS
765 int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
766#endif
767
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100768 if (args) {
769 err = _PyPreCmdline_SetArgv(&cmdline, args);
770 if (_Py_INIT_FAILED(err)) {
771 goto done;
772 }
773 }
774
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100775 int locale_coerced = 0;
776 int loops = 0;
777
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100778 while (1) {
779 int utf8_mode = config->utf8_mode;
780
781 /* Watchdog to prevent an infinite loop */
782 loops++;
783 if (loops == 3) {
784 err = _Py_INIT_ERR("Encoding changed twice while "
785 "reading the configuration");
786 goto done;
787 }
788
789 /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend
790 on Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */
791 Py_UTF8Mode = config->utf8_mode;
792#ifdef MS_WINDOWS
793 Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
794#endif
795
Victor Stinner5ac27a52019-03-27 13:40:14 +0100796 err = preconfig_read(config, &cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100797 if (_Py_INIT_FAILED(err)) {
798 goto done;
799 }
800
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100801 /* The legacy C locale assumes ASCII as the default text encoding, which
802 * causes problems not only for the CPython runtime, but also other
803 * components like GNU readline.
804 *
805 * Accordingly, when the CLI detects it, it attempts to coerce it to a
806 * more capable UTF-8 based alternative.
807 *
808 * See the documentation of the PYTHONCOERCECLOCALE setting for more
809 * details.
810 */
811 int encoding_changed = 0;
812 if (config->coerce_c_locale && !locale_coerced) {
813 locale_coerced = 1;
814 _Py_CoerceLegacyLocale(0);
815 encoding_changed = 1;
816 }
817
818 if (utf8_mode == -1) {
819 if (config->utf8_mode == 1) {
820 /* UTF-8 Mode enabled */
821 encoding_changed = 1;
822 }
823 }
824 else {
825 if (config->utf8_mode != utf8_mode) {
826 encoding_changed = 1;
827 }
828 }
829
830 if (!encoding_changed) {
831 break;
832 }
833
834 /* Reset the configuration before reading again the configuration,
835 just keep UTF-8 Mode value. */
836 int new_utf8_mode = config->utf8_mode;
837 int new_coerce_c_locale = config->coerce_c_locale;
838 if (_PyPreConfig_Copy(config, &save_config) < 0) {
839 err = _Py_INIT_NO_MEMORY();
840 goto done;
841 }
842 config->utf8_mode = new_utf8_mode;
843 config->coerce_c_locale = new_coerce_c_locale;
844
845 /* The encoding changed: read again the configuration
846 with the new encoding */
847 }
848 err = _Py_INIT_OK();
849
850done:
851 if (init_ctype_locale != NULL) {
852 setlocale(LC_CTYPE, init_ctype_locale);
Victor Stinnerc1834442019-03-18 22:24:28 +0100853 PyMem_RawFree(init_ctype_locale);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100854 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100855 Py_UTF8Mode = init_utf8_mode ;
856#ifdef MS_WINDOWS
857 Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
858#endif
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100859 _PyPreCmdline_Clear(&cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100860 return err;
861}
862
863
Victor Stinner4fffd382019-03-06 01:44:31 +0100864/* Write the pre-configuration:
865
866 - set the memory allocators
867 - set Py_xxx global configuration variables
868 - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
869 (PEP 540)
Victor Stinnerc656e252019-03-06 01:13:43 +0100870
871 If the memory allocator is changed, config is re-allocated with new
Victor Stinner4fffd382019-03-06 01:44:31 +0100872 allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
873
874 Do nothing if called after Py_Initialize(): ignore the new
875 pre-configuration. */
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100876_PyInitError
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200877_PyPreConfig_Write(const _PyPreConfig *config)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100878{
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100879 if (_PyRuntime.core_initialized) {
Victor Stinner4fffd382019-03-06 01:44:31 +0100880 /* bpo-34008: Calling this functions after Py_Initialize() ignores
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100881 the new configuration. */
Victor Stinnerc656e252019-03-06 01:13:43 +0100882 return _Py_INIT_OK();
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100883 }
884
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200885 if (config->allocator != PYMEM_ALLOCATOR_NOT_SET) {
886 if (_PyMem_SetupAllocators(config->allocator) < 0) {
887 return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100888 }
889 }
890
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100891 _PyPreConfig_SetGlobalConfig(config);
892
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200893 if (config->configure_locale) {
894 if (config->coerce_c_locale) {
895 _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
896 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100897
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200898 /* Set LC_CTYPE to the user preferred locale */
899 _Py_SetLocaleFromEnv(LC_CTYPE);
900 }
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100901
Victor Stinner6d5ee972019-03-23 12:05:43 +0100902 /* Write the new pre-configuration into _PyRuntime */
903 PyMemAllocatorEx old_alloc;
904 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
905 int res = _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
906 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
907 if (res < 0) {
908 return _Py_INIT_NO_MEMORY();
909 }
910
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100911 return _Py_INIT_OK();
Victor Stinner6dcb5422019-03-05 02:44:12 +0100912}