blob: 0f4bd8ece534c0d43ca0f9cd0639fecba99ec849 [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 */
Victor Stinnerbab0db62019-05-18 03:21:27 +0200244 if ((cmdline->dev_mode < 0)
245 && (_Py_get_xoption(&cmdline->xoptions, L"dev")
246 || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE")))
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100247 {
248 cmdline->dev_mode = 1;
249 }
250 if (cmdline->dev_mode < 0) {
251 cmdline->dev_mode = 0;
252 }
253
254 assert(cmdline->use_environment >= 0);
255 assert(cmdline->isolated >= 0);
256 assert(cmdline->dev_mode >= 0);
257
258 return _Py_INIT_OK();
259}
260
261
Victor Stinnercad1f742019-03-05 02:01:27 +0100262/* --- _PyPreConfig ----------------------------------------------- */
263
Victor Stinnerbab0db62019-05-18 03:21:27 +0200264
Victor Stinnercab5d072019-05-17 19:01:14 +0200265void
266_PyPreConfig_Init(_PyPreConfig *config)
267{
Victor Stinnerbab0db62019-05-18 03:21:27 +0200268 memset(config, 0, sizeof(*config));
269
270 config->_config_version = _Py_CONFIG_VERSION;
271 config->isolated = -1;
272 config->use_environment = -1;
273 config->configure_locale = 1;
274 config->utf8_mode = -2;
275 config->dev_mode = -1;
276 config->allocator = PYMEM_ALLOCATOR_NOT_SET;
277#ifdef MS_WINDOWS
278 config->legacy_windows_fs_encoding = -1;
279#endif
Victor Stinnercab5d072019-05-17 19:01:14 +0200280}
281
282
283void
284_PyPreConfig_InitPythonConfig(_PyPreConfig *config)
285{
286 _PyPreConfig_Init(config);
287
288 /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)
289 depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE
290 environment variables. */
291 config->coerce_c_locale = -1;
292 config->coerce_c_locale_warn = -1;
293 config->utf8_mode = -1;
294}
295
296
297void
298_PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
299{
300 _PyPreConfig_Init(config);
301
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200302 config->configure_locale = 0;
Victor Stinnercab5d072019-05-17 19:01:14 +0200303 config->isolated = 1;
304 config->use_environment = 0;
Victor Stinnerbab0db62019-05-18 03:21:27 +0200305 config->utf8_mode = 0;
306 config->dev_mode = 0;
Victor Stinnercab5d072019-05-17 19:01:14 +0200307#ifdef MS_WINDOWS
308 config->legacy_windows_fs_encoding = 0;
309#endif
Victor Stinnercab5d072019-05-17 19:01:14 +0200310}
311
312
Victor Stinnerb5947842019-05-18 00:38:16 +0200313void
Victor Stinnercad1f742019-03-05 02:01:27 +0100314_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
315{
Victor Stinnercad1f742019-03-05 02:01:27 +0100316#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
317
318 COPY_ATTR(isolated);
319 COPY_ATTR(use_environment);
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200320 COPY_ATTR(configure_locale);
Victor Stinner20004952019-03-26 02:31:11 +0100321 COPY_ATTR(dev_mode);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100322 COPY_ATTR(coerce_c_locale);
323 COPY_ATTR(coerce_c_locale_warn);
Victor Stinnerb5947842019-05-18 00:38:16 +0200324 COPY_ATTR(utf8_mode);
325 COPY_ATTR(allocator);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100326#ifdef MS_WINDOWS
327 COPY_ATTR(legacy_windows_fs_encoding);
328#endif
Victor Stinnercad1f742019-03-05 02:01:27 +0100329
330#undef COPY_ATTR
Victor Stinnercad1f742019-03-05 02:01:27 +0100331}
332
333
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100334PyObject*
335_PyPreConfig_AsDict(const _PyPreConfig *config)
336{
337 PyObject *dict;
338
339 dict = PyDict_New();
340 if (dict == NULL) {
341 return NULL;
342 }
343
344#define SET_ITEM(KEY, EXPR) \
345 do { \
346 PyObject *obj = (EXPR); \
347 if (obj == NULL) { \
348 goto fail; \
349 } \
350 int res = PyDict_SetItemString(dict, (KEY), obj); \
351 Py_DECREF(obj); \
352 if (res < 0) { \
353 goto fail; \
354 } \
355 } while (0)
356#define SET_ITEM_INT(ATTR) \
357 SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
358#define FROM_STRING(STR) \
359 ((STR != NULL) ? \
360 PyUnicode_FromString(STR) \
361 : (Py_INCREF(Py_None), Py_None))
362#define SET_ITEM_STR(ATTR) \
363 SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
364
365 SET_ITEM_INT(isolated);
366 SET_ITEM_INT(use_environment);
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200367 SET_ITEM_INT(configure_locale);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100368 SET_ITEM_INT(coerce_c_locale);
369 SET_ITEM_INT(coerce_c_locale_warn);
370 SET_ITEM_INT(utf8_mode);
371#ifdef MS_WINDOWS
372 SET_ITEM_INT(legacy_windows_fs_encoding);
373#endif
374 SET_ITEM_INT(dev_mode);
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200375 SET_ITEM_INT(allocator);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100376 return dict;
377
378fail:
379 Py_DECREF(dict);
380 return NULL;
381
382#undef FROM_STRING
383#undef SET_ITEM
384#undef SET_ITEM_INT
385#undef SET_ITEM_STR
386}
387
388
Victor Stinner5ac27a52019-03-27 13:40:14 +0100389void
Victor Stinnercab5d072019-05-17 19:01:14 +0200390_PyPreConfig_GetCoreConfig(_PyPreConfig *config,
Victor Stinner5ac27a52019-03-27 13:40:14 +0100391 const _PyCoreConfig *core_config)
392{
393#define COPY_ATTR(ATTR) \
394 if (core_config->ATTR != -1) { \
395 config->ATTR = core_config->ATTR; \
396 }
397
398 COPY_ATTR(isolated);
399 COPY_ATTR(use_environment);
400 COPY_ATTR(dev_mode);
401
402#undef COPY_ATTR
403}
404
405
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100406static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100407_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
408{
409#define COPY_FLAG(ATTR, VALUE) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200410 if (config->ATTR < 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100411 config->ATTR = VALUE; \
412 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100413#define COPY_NOT_FLAG(ATTR, VALUE) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200414 if (config->ATTR < 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100415 config->ATTR = !(VALUE); \
416 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100417
418 COPY_FLAG(isolated, Py_IsolatedFlag);
419 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100420#ifdef MS_WINDOWS
421 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
422#endif
Victor Stinnercab5d072019-05-17 19:01:14 +0200423 if (config->utf8_mode == -2) {
424 config->utf8_mode = Py_UTF8Mode;
Victor Stinnerd929f182019-03-27 18:28:46 +0100425 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100426
427#undef COPY_FLAG
428#undef COPY_NOT_FLAG
429}
430
431
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100432static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100433_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
434{
435#define COPY_FLAG(ATTR, VAR) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200436 if (config->ATTR >= 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100437 VAR = config->ATTR; \
438 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100439#define COPY_NOT_FLAG(ATTR, VAR) \
Victor Stinnercab5d072019-05-17 19:01:14 +0200440 if (config->ATTR >= 0) { \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100441 VAR = !config->ATTR; \
442 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100443
444 COPY_FLAG(isolated, Py_IsolatedFlag);
445 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100446#ifdef MS_WINDOWS
447 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
448#endif
449 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100450
451#undef COPY_FLAG
452#undef COPY_NOT_FLAG
453}
454
455
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100456const char*
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100457_Py_GetEnv(int use_environment, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100458{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100459 assert(use_environment >= 0);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100460
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100461 if (!use_environment) {
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100462 return NULL;
463 }
464
465 const char *var = getenv(name);
466 if (var && var[0] != '\0') {
467 return var;
468 }
469 else {
470 return NULL;
471 }
472}
473
474
475int
476_Py_str_to_int(const char *str, int *result)
477{
478 const char *endptr = str;
479 errno = 0;
480 long value = strtol(str, (char **)&endptr, 10);
481 if (*endptr != '\0' || errno == ERANGE) {
482 return -1;
483 }
484 if (value < INT_MIN || value > INT_MAX) {
485 return -1;
486 }
487
488 *result = (int)value;
489 return 0;
490}
491
492
493void
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100494_Py_get_env_flag(int use_environment, int *flag, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100495{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100496 const char *var = _Py_GetEnv(use_environment, name);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100497 if (!var) {
498 return;
499 }
500 int value;
501 if (_Py_str_to_int(var, &value) < 0 || value < 0) {
502 /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
503 value = 1;
504 }
505 if (*flag < value) {
506 *flag = value;
507 }
508}
509
510
511const wchar_t*
Victor Stinner74f65682019-03-15 15:08:05 +0100512_Py_get_xoption(const _PyWstrList *xoptions, const wchar_t *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100513{
Victor Stinner74f65682019-03-15 15:08:05 +0100514 for (Py_ssize_t i=0; i < xoptions->length; i++) {
515 const wchar_t *option = xoptions->items[i];
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100516 size_t len;
517 wchar_t *sep = wcschr(option, L'=');
518 if (sep != NULL) {
519 len = (sep - option);
520 }
521 else {
522 len = wcslen(option);
523 }
524 if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
525 return option;
526 }
527 }
528 return NULL;
529}
530
531
532static _PyInitError
533preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
534{
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100535#ifdef MS_WINDOWS
536 if (config->legacy_windows_fs_encoding) {
537 config->utf8_mode = 0;
538 }
539#endif
540
541 if (config->utf8_mode >= 0) {
542 return _Py_INIT_OK();
543 }
544
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100545 const wchar_t *xopt;
546 if (cmdline) {
Victor Stinner74f65682019-03-15 15:08:05 +0100547 xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100548 }
549 else {
550 xopt = NULL;
551 }
552 if (xopt) {
553 wchar_t *sep = wcschr(xopt, L'=');
554 if (sep) {
555 xopt = sep + 1;
556 if (wcscmp(xopt, L"1") == 0) {
557 config->utf8_mode = 1;
558 }
559 else if (wcscmp(xopt, L"0") == 0) {
560 config->utf8_mode = 0;
561 }
562 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200563 return _Py_INIT_ERR("invalid -X utf8 option value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100564 }
565 }
566 else {
567 config->utf8_mode = 1;
568 }
569 return _Py_INIT_OK();
570 }
571
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100572 const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100573 if (opt) {
574 if (strcmp(opt, "1") == 0) {
575 config->utf8_mode = 1;
576 }
577 else if (strcmp(opt, "0") == 0) {
578 config->utf8_mode = 0;
579 }
580 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200581 return _Py_INIT_ERR("invalid PYTHONUTF8 environment "
582 "variable value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100583 }
584 return _Py_INIT_OK();
585 }
586
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100587
588#ifndef MS_WINDOWS
589 if (config->utf8_mode < 0) {
590 /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
591 const char *ctype_loc = setlocale(LC_CTYPE, NULL);
592 if (ctype_loc != NULL
593 && (strcmp(ctype_loc, "C") == 0
594 || strcmp(ctype_loc, "POSIX") == 0))
595 {
596 config->utf8_mode = 1;
597 }
598 }
599#endif
600
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100601 if (config->utf8_mode < 0) {
602 config->utf8_mode = 0;
603 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100604 return _Py_INIT_OK();
605}
606
607
608static void
609preconfig_init_coerce_c_locale(_PyPreConfig *config)
610{
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200611 if (!config->configure_locale) {
612 config->coerce_c_locale = 0;
613 config->coerce_c_locale_warn = 0;
614 return;
615 }
616
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100617 const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
618 if (env) {
619 if (strcmp(env, "0") == 0) {
620 if (config->coerce_c_locale < 0) {
621 config->coerce_c_locale = 0;
622 }
623 }
624 else if (strcmp(env, "warn") == 0) {
Victor Stinnercab5d072019-05-17 19:01:14 +0200625 if (config->coerce_c_locale_warn < 0) {
626 config->coerce_c_locale_warn = 1;
627 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100628 }
629 else {
630 if (config->coerce_c_locale < 0) {
631 config->coerce_c_locale = 1;
632 }
633 }
634 }
635
636 /* Test if coerce_c_locale equals to -1 or equals to 1:
637 PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.
638 It is only coerced if if the LC_CTYPE locale is "C". */
Victor Stinnercab5d072019-05-17 19:01:14 +0200639 if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
640 /* The C locale enables the C locale coercion (PEP 538) */
641 if (_Py_LegacyLocaleDetected()) {
642 config->coerce_c_locale = 2;
643 }
644 else {
645 config->coerce_c_locale = 0;
646 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100647 }
648
Victor Stinnercab5d072019-05-17 19:01:14 +0200649 if (config->coerce_c_locale_warn < 0) {
650 config->coerce_c_locale_warn = 0;
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100651 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100652}
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100653
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100654
655static _PyInitError
656preconfig_init_allocator(_PyPreConfig *config)
657{
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200658 if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
Victor Stinner25d13f32019-03-06 12:51:53 +0100659 /* bpo-34247. The PYTHONMALLOC environment variable has the priority
660 over PYTHONDEV env var and "-X dev" command line option.
661 For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
662 allocators to "malloc" (and not to "debug"). */
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200663 const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
664 if (envvar) {
665 if (_PyMem_GetAllocatorName(envvar, &config->allocator) < 0) {
666 return _Py_INIT_ERR("PYTHONMALLOC: unknown allocator");
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100667 }
668 }
669 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100670
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200671 if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
672 config->allocator = PYMEM_ALLOCATOR_DEBUG;
Victor Stinner25d13f32019-03-06 12:51:53 +0100673 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100674 return _Py_INIT_OK();
675}
676
677
678static _PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100679preconfig_read(_PyPreConfig *config, _PyPreCmdline *cmdline)
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100680{
681 _PyInitError err;
682
Victor Stinner5ac27a52019-03-27 13:40:14 +0100683 err = _PyPreCmdline_Read(cmdline, config);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100684 if (_Py_INIT_FAILED(err)) {
685 return err;
686 }
687
688 _PyPreCmdline_SetPreConfig(cmdline, config);
689
690 /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */
691#ifdef MS_WINDOWS
692 _Py_get_env_flag(config->use_environment,
693 &config->legacy_windows_fs_encoding,
694 "PYTHONLEGACYWINDOWSFSENCODING");
695#endif
696
697 preconfig_init_coerce_c_locale(config);
698
699 err = preconfig_init_utf8_mode(config, cmdline);
700 if (_Py_INIT_FAILED(err)) {
701 return err;
702 }
703
704 /* allocator */
705 err = preconfig_init_allocator(config);
706 if (_Py_INIT_FAILED(err)) {
707 return err;
708 }
Victor Stinner25d13f32019-03-06 12:51:53 +0100709
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100710 assert(config->coerce_c_locale >= 0);
Victor Stinnercab5d072019-05-17 19:01:14 +0200711 assert(config->coerce_c_locale_warn >= 0);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100712#ifdef MS_WINDOWS
713 assert(config->legacy_windows_fs_encoding >= 0);
714#endif
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100715 assert(config->utf8_mode >= 0);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100716 assert(config->isolated >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100717 assert(config->use_environment >= 0);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100718 assert(config->dev_mode >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100719
720 return _Py_INIT_OK();
721}
722
723
Victor Stinner4fffd382019-03-06 01:44:31 +0100724/* Read the configuration from:
725
726 - command line arguments
727 - environment variables
728 - Py_xxx global configuration variables
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100729 - the LC_CTYPE locale */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100730_PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100731_PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100732{
733 _PyInitError err;
734
735 err = _PyRuntime_Initialize();
736 if (_Py_INIT_FAILED(err)) {
737 return err;
738 }
739
Victor Stinnerf29084d2019-03-20 02:20:13 +0100740 _PyPreConfig_GetGlobalConfig(config);
741
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100742 /* Copy LC_CTYPE locale, since it's modified later */
743 const char *loc = setlocale(LC_CTYPE, NULL);
744 if (loc == NULL) {
745 return _Py_INIT_ERR("failed to LC_CTYPE locale");
746 }
747 char *init_ctype_locale = _PyMem_RawStrdup(loc);
748 if (init_ctype_locale == NULL) {
749 return _Py_INIT_NO_MEMORY();
750 }
751
752 /* Save the config to be able to restore it if encodings change */
Victor Stinnercab5d072019-05-17 19:01:14 +0200753 _PyPreConfig save_config;
754 _PyPreConfig_Init(&save_config);
Victor Stinnerb5947842019-05-18 00:38:16 +0200755 _PyPreConfig_Copy(&save_config, config);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100756
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;
Victor Stinnerb5947842019-05-18 00:38:16 +0200838 _PyPreConfig_Copy(config, &save_config);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100839 config->utf8_mode = new_utf8_mode;
840 config->coerce_c_locale = new_coerce_c_locale;
841
842 /* The encoding changed: read again the configuration
843 with the new encoding */
844 }
845 err = _Py_INIT_OK();
846
847done:
848 if (init_ctype_locale != NULL) {
849 setlocale(LC_CTYPE, init_ctype_locale);
Victor Stinnerc1834442019-03-18 22:24:28 +0100850 PyMem_RawFree(init_ctype_locale);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100851 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100852 Py_UTF8Mode = init_utf8_mode ;
853#ifdef MS_WINDOWS
854 Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
855#endif
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100856 _PyPreCmdline_Clear(&cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100857 return err;
858}
859
860
Victor Stinner4fffd382019-03-06 01:44:31 +0100861/* Write the pre-configuration:
862
863 - set the memory allocators
864 - set Py_xxx global configuration variables
865 - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
866 (PEP 540)
Victor Stinnerc656e252019-03-06 01:13:43 +0100867
868 If the memory allocator is changed, config is re-allocated with new
Victor Stinner4fffd382019-03-06 01:44:31 +0100869 allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
870
871 Do nothing if called after Py_Initialize(): ignore the new
872 pre-configuration. */
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100873_PyInitError
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200874_PyPreConfig_Write(const _PyPreConfig *config)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100875{
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100876 if (_PyRuntime.core_initialized) {
Victor Stinner4fffd382019-03-06 01:44:31 +0100877 /* bpo-34008: Calling this functions after Py_Initialize() ignores
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100878 the new configuration. */
Victor Stinnerc656e252019-03-06 01:13:43 +0100879 return _Py_INIT_OK();
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100880 }
881
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200882 if (config->allocator != PYMEM_ALLOCATOR_NOT_SET) {
883 if (_PyMem_SetupAllocators(config->allocator) < 0) {
884 return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100885 }
886 }
887
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100888 _PyPreConfig_SetGlobalConfig(config);
889
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200890 if (config->configure_locale) {
891 if (config->coerce_c_locale) {
892 _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
893 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100894
Victor Stinnerbcfbbd72019-05-17 22:44:16 +0200895 /* Set LC_CTYPE to the user preferred locale */
896 _Py_SetLocaleFromEnv(LC_CTYPE);
897 }
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100898
Victor Stinner6d5ee972019-03-23 12:05:43 +0100899 /* Write the new pre-configuration into _PyRuntime */
Victor Stinnerb5947842019-05-18 00:38:16 +0200900 _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
Victor Stinner6d5ee972019-03-23 12:05:43 +0100901
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100902 return _Py_INIT_OK();
Victor Stinner6dcb5422019-03-05 02:44:12 +0100903}