blob: 50d66b1249220b1d269d8d55a32ed19455310490 [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) \
10 ? _Py_INIT_USER_ERR("cannot decode " NAME) \
11 : _Py_INIT_NO_MEMORY())
12
13
14/* --- File system encoding/errors -------------------------------- */
15
16/* The filesystem encoding is chosen by config_init_fs_encoding(),
17 see also initfsencoding(). */
18const char *Py_FileSystemDefaultEncoding = NULL;
19int Py_HasFileSystemDefaultEncoding = 0;
20const char *Py_FileSystemDefaultEncodeErrors = NULL;
21int _Py_HasFileSystemDefaultEncodeErrors = 0;
22
23void
24_Py_ClearFileSystemEncoding(void)
25{
26 if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) {
27 PyMem_RawFree((char*)Py_FileSystemDefaultEncoding);
28 Py_FileSystemDefaultEncoding = NULL;
29 }
30 if (!_Py_HasFileSystemDefaultEncodeErrors && Py_FileSystemDefaultEncodeErrors) {
31 PyMem_RawFree((char*)Py_FileSystemDefaultEncodeErrors);
32 Py_FileSystemDefaultEncodeErrors = NULL;
33 }
34}
35
36
37/* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
38 global configuration variables. */
39int
40_Py_SetFileSystemEncoding(const char *encoding, const char *errors)
41{
42 char *encoding2 = _PyMem_RawStrdup(encoding);
43 if (encoding2 == NULL) {
44 return -1;
45 }
46
47 char *errors2 = _PyMem_RawStrdup(errors);
48 if (errors2 == NULL) {
49 PyMem_RawFree(encoding2);
50 return -1;
51 }
52
53 _Py_ClearFileSystemEncoding();
54
55 Py_FileSystemDefaultEncoding = encoding2;
56 Py_HasFileSystemDefaultEncoding = 0;
57
58 Py_FileSystemDefaultEncodeErrors = errors2;
59 _Py_HasFileSystemDefaultEncodeErrors = 0;
60 return 0;
61}
62
63
64/* --- _PyArgv ---------------------------------------------------- */
65
66_PyInitError
67_PyArgv_Decode(const _PyArgv *args, wchar_t*** argv_p)
68{
69 wchar_t** argv;
70 if (args->use_bytes_argv) {
71 /* +1 for a the NULL terminator */
72 size_t size = sizeof(wchar_t*) * (args->argc + 1);
73 argv = (wchar_t **)PyMem_RawMalloc(size);
74 if (argv == NULL) {
75 return _Py_INIT_NO_MEMORY();
76 }
77
78 for (int i = 0; i < args->argc; i++) {
79 size_t len;
80 wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
81 if (arg == NULL) {
82 _Py_wstrlist_clear(i, argv);
83 return DECODE_LOCALE_ERR("command line arguments",
84 (Py_ssize_t)len);
85 }
86 argv[i] = arg;
87 }
88 argv[args->argc] = NULL;
89 }
90 else {
91 argv = args->wchar_argv;
92 }
93 *argv_p = argv;
94 return _Py_INIT_OK();
95}
Victor Stinnercad1f742019-03-05 02:01:27 +010096
97
Victor Stinner6dcb5422019-03-05 02:44:12 +010098/* --- _PyPreCmdline ------------------------------------------------- */
99
100typedef struct {
101 const _PyArgv *args;
102 int argc;
103 wchar_t **argv;
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100104 int nxoption; /* Number of -X options */
105 wchar_t **xoptions; /* -X options */
Victor Stinner6dcb5422019-03-05 02:44:12 +0100106} _PyPreCmdline;
107
108
109static void
110precmdline_clear(_PyPreCmdline *cmdline)
111{
112 if (cmdline->args->use_bytes_argv && cmdline->argv != NULL) {
113 _Py_wstrlist_clear(cmdline->args->argc, cmdline->argv);
114 }
115 cmdline->argv = NULL;
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100116
117 _Py_wstrlist_clear(cmdline->nxoption, cmdline->xoptions);
118 cmdline->nxoption = 0;
119 cmdline->xoptions = NULL;
Victor Stinner6dcb5422019-03-05 02:44:12 +0100120}
121
122
Victor Stinnercad1f742019-03-05 02:01:27 +0100123/* --- _PyPreConfig ----------------------------------------------- */
124
125void
126_PyPreConfig_Clear(_PyPreConfig *config)
127{
Victor Stinnerc656e252019-03-06 01:13:43 +0100128 PyMem_RawFree(config->allocator);
129 config->allocator = NULL;
Victor Stinnercad1f742019-03-05 02:01:27 +0100130}
131
132
133int
134_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
135{
136 _PyPreConfig_Clear(config);
137
138#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100139#define COPY_STR_ATTR(ATTR) \
140 do { \
141 if (config2->ATTR != NULL) { \
142 config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
143 if (config->ATTR == NULL) { \
144 return -1; \
145 } \
146 } \
147 } while (0)
Victor Stinnercad1f742019-03-05 02:01:27 +0100148
149 COPY_ATTR(isolated);
150 COPY_ATTR(use_environment);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100151 COPY_ATTR(coerce_c_locale);
152 COPY_ATTR(coerce_c_locale_warn);
153#ifdef MS_WINDOWS
154 COPY_ATTR(legacy_windows_fs_encoding);
155#endif
156 COPY_ATTR(utf8_mode);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100157 COPY_ATTR(dev_mode);
158 COPY_STR_ATTR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100159
160#undef COPY_ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100161#undef COPY_STR_ATTR
Victor Stinnercad1f742019-03-05 02:01:27 +0100162 return 0;
163}
164
165
166void
167_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
168{
169#define COPY_FLAG(ATTR, VALUE) \
170 if (config->ATTR == -1) { \
171 config->ATTR = VALUE; \
172 }
173#define COPY_NOT_FLAG(ATTR, VALUE) \
174 if (config->ATTR == -1) { \
175 config->ATTR = !(VALUE); \
176 }
177
178 COPY_FLAG(isolated, Py_IsolatedFlag);
179 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100180#ifdef MS_WINDOWS
181 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
182#endif
183 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100184
185#undef COPY_FLAG
186#undef COPY_NOT_FLAG
187}
188
189
190void
191_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
192{
193#define COPY_FLAG(ATTR, VAR) \
194 if (config->ATTR != -1) { \
195 VAR = config->ATTR; \
196 }
197#define COPY_NOT_FLAG(ATTR, VAR) \
198 if (config->ATTR != -1) { \
199 VAR = !config->ATTR; \
200 }
201
202 COPY_FLAG(isolated, Py_IsolatedFlag);
203 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100204#ifdef MS_WINDOWS
205 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
206#endif
207 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100208
209#undef COPY_FLAG
210#undef COPY_NOT_FLAG
211}
212
213
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100214const char*
215_PyPreConfig_GetEnv(const _PyPreConfig *config, const char *name)
216{
217 assert(config->use_environment >= 0);
218
219 if (!config->use_environment) {
220 return NULL;
221 }
222
223 const char *var = getenv(name);
224 if (var && var[0] != '\0') {
225 return var;
226 }
227 else {
228 return NULL;
229 }
230}
231
232
233int
234_Py_str_to_int(const char *str, int *result)
235{
236 const char *endptr = str;
237 errno = 0;
238 long value = strtol(str, (char **)&endptr, 10);
239 if (*endptr != '\0' || errno == ERANGE) {
240 return -1;
241 }
242 if (value < INT_MIN || value > INT_MAX) {
243 return -1;
244 }
245
246 *result = (int)value;
247 return 0;
248}
249
250
251void
252_Py_get_env_flag(_PyPreConfig *config, int *flag, const char *name)
253{
254 const char *var = _PyPreConfig_GetEnv(config, name);
255 if (!var) {
256 return;
257 }
258 int value;
259 if (_Py_str_to_int(var, &value) < 0 || value < 0) {
260 /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
261 value = 1;
262 }
263 if (*flag < value) {
264 *flag = value;
265 }
266}
267
268
269const wchar_t*
270_Py_get_xoption(int nxoption, wchar_t * const *xoptions, const wchar_t *name)
271{
272 for (int i=0; i < nxoption; i++) {
273 const wchar_t *option = xoptions[i];
274 size_t len;
275 wchar_t *sep = wcschr(option, L'=');
276 if (sep != NULL) {
277 len = (sep - option);
278 }
279 else {
280 len = wcslen(option);
281 }
282 if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
283 return option;
284 }
285 }
286 return NULL;
287}
288
289
290static _PyInitError
291preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
292{
293 const wchar_t *xopt;
294 if (cmdline) {
295 xopt = _Py_get_xoption(cmdline->nxoption, cmdline->xoptions, L"utf8");
296 }
297 else {
298 xopt = NULL;
299 }
300 if (xopt) {
301 wchar_t *sep = wcschr(xopt, L'=');
302 if (sep) {
303 xopt = sep + 1;
304 if (wcscmp(xopt, L"1") == 0) {
305 config->utf8_mode = 1;
306 }
307 else if (wcscmp(xopt, L"0") == 0) {
308 config->utf8_mode = 0;
309 }
310 else {
311 return _Py_INIT_USER_ERR("invalid -X utf8 option value");
312 }
313 }
314 else {
315 config->utf8_mode = 1;
316 }
317 return _Py_INIT_OK();
318 }
319
320 const char *opt = _PyPreConfig_GetEnv(config, "PYTHONUTF8");
321 if (opt) {
322 if (strcmp(opt, "1") == 0) {
323 config->utf8_mode = 1;
324 }
325 else if (strcmp(opt, "0") == 0) {
326 config->utf8_mode = 0;
327 }
328 else {
329 return _Py_INIT_USER_ERR("invalid PYTHONUTF8 environment "
330 "variable value");
331 }
332 return _Py_INIT_OK();
333 }
334
335 return _Py_INIT_OK();
336}
337
338
339static void
340preconfig_init_locale(_PyPreConfig *config)
341{
342 /* Test also if coerce_c_locale equals 1: PYTHONCOERCECLOCALE=1 doesn't
343 imply that the C locale is always coerced. It is only coerced if
344 if the LC_CTYPE locale is "C". */
345 if (config->coerce_c_locale != 0) {
346 /* The C locale enables the C locale coercion (PEP 538) */
347 if (_Py_LegacyLocaleDetected()) {
348 config->coerce_c_locale = 1;
349 }
350 else {
351 config->coerce_c_locale = 0;
352 }
353 }
354}
355
356
357static _PyInitError
358preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
Victor Stinnercad1f742019-03-05 02:01:27 +0100359{
360 _PyPreConfig_GetGlobalConfig(config);
361
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100362 /* isolated and use_environment */
Victor Stinnercad1f742019-03-05 02:01:27 +0100363 if (config->isolated > 0) {
364 config->use_environment = 0;
365 }
366
367 /* Default values */
368 if (config->use_environment < 0) {
369 config->use_environment = 0;
370 }
371
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100372 /* legacy_windows_fs_encoding, utf8_mode, coerce_c_locale */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100373 if (config->use_environment) {
374#ifdef MS_WINDOWS
375 _Py_get_env_flag(config, &config->legacy_windows_fs_encoding,
376 "PYTHONLEGACYWINDOWSFSENCODING");
377#endif
378
379 const char *env = _PyPreConfig_GetEnv(config, "PYTHONCOERCECLOCALE");
380 if (env) {
381 if (strcmp(env, "0") == 0) {
382 if (config->coerce_c_locale < 0) {
383 config->coerce_c_locale = 0;
384 }
385 }
386 else if (strcmp(env, "warn") == 0) {
387 config->coerce_c_locale_warn = 1;
388 }
389 else {
390 if (config->coerce_c_locale < 0) {
391 config->coerce_c_locale = 1;
392 }
393 }
394 }
395 }
396
397#ifdef MS_WINDOWS
398 if (config->legacy_windows_fs_encoding) {
399 config->utf8_mode = 0;
400 }
401#endif
402
403 if (config->utf8_mode < 0) {
404 _PyInitError err = preconfig_init_utf8_mode(config, cmdline);
405 if (_Py_INIT_FAILED(err)) {
406 return err;
407 }
408 }
409
410 if (config->coerce_c_locale != 0) {
411 preconfig_init_locale(config);
412 }
413
414#ifndef MS_WINDOWS
415 if (config->utf8_mode < 0) {
416 /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
417 const char *ctype_loc = setlocale(LC_CTYPE, NULL);
418 if (ctype_loc != NULL
419 && (strcmp(ctype_loc, "C") == 0
420 || strcmp(ctype_loc, "POSIX") == 0))
421 {
422 config->utf8_mode = 1;
423 }
424 }
425#endif
426
427 if (config->coerce_c_locale < 0) {
428 config->coerce_c_locale = 0;
429 }
430 if (config->utf8_mode < 0) {
431 config->utf8_mode = 0;
432 }
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100433 if (config->coerce_c_locale < 0) {
434 config->coerce_c_locale = 0;
435 }
436
437 /* dev_mode */
438 if ((cmdline && _Py_get_xoption(cmdline->nxoption, cmdline->xoptions, L"dev"))
439 || _PyPreConfig_GetEnv(config, "PYTHONDEVMODE"))
440 {
441 config->dev_mode = 1;
442 }
443 if (config->dev_mode < 0) {
444 config->dev_mode = 0;
445 }
446
447 /* allocator */
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100448 if (config->allocator == NULL) {
Victor Stinner25d13f32019-03-06 12:51:53 +0100449 /* bpo-34247. The PYTHONMALLOC environment variable has the priority
450 over PYTHONDEV env var and "-X dev" command line option.
451 For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
452 allocators to "malloc" (and not to "debug"). */
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100453 const char *allocator = _PyPreConfig_GetEnv(config, "PYTHONMALLOC");
454 if (allocator) {
455 config->allocator = _PyMem_RawStrdup(allocator);
456 if (config->allocator == NULL) {
457 return _Py_INIT_NO_MEMORY();
458 }
459 }
460 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100461
Victor Stinner25d13f32019-03-06 12:51:53 +0100462 if (config->dev_mode && config->allocator == NULL) {
463 config->allocator = _PyMem_RawStrdup("debug");
464 if (config->allocator == NULL) {
465 return _Py_INIT_NO_MEMORY();
466 }
467 }
468
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100469 assert(config->coerce_c_locale >= 0);
470 assert(config->utf8_mode >= 0);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100471 assert(config->isolated >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100472 assert(config->use_environment >= 0);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100473 assert(config->dev_mode >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100474
475 return _Py_INIT_OK();
476}
477
478
Victor Stinner4fffd382019-03-06 01:44:31 +0100479static _PyInitError
480get_ctype_locale(char **locale_p)
481{
482 const char *loc = setlocale(LC_CTYPE, NULL);
483 if (loc == NULL) {
484 return _Py_INIT_ERR("failed to LC_CTYPE locale");
485 }
486
487 char *copy = _PyMem_RawStrdup(loc);
488 if (copy == NULL) {
489 return _Py_INIT_NO_MEMORY();
490 }
491
492 *locale_p = copy;
493 return _Py_INIT_OK();
494}
495
496
497/* Read the configuration from:
498
499 - environment variables
500 - Py_xxx global configuration variables
501 - the LC_CTYPE locale
502
503 See _PyPreConfig_ReadFromArgv() to parse also command line arguments. */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100504_PyInitError
505_PyPreConfig_Read(_PyPreConfig *config)
506{
Victor Stinner4fffd382019-03-06 01:44:31 +0100507 _PyInitError err;
508 char *old_loc;
509
510 err = get_ctype_locale(&old_loc);
511 if (_Py_INIT_FAILED(err)) {
512 return err;
513 }
514
515 /* Set LC_CTYPE to the user preferred locale */
516 _Py_SetLocaleFromEnv(LC_CTYPE);
517
518 err = preconfig_read(config, NULL);
519
520 setlocale(LC_CTYPE, old_loc);
521
522 return err;
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100523}
524
525
Victor Stinnercad1f742019-03-05 02:01:27 +0100526int
527_PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
528{
529#define SET_ITEM(KEY, EXPR) \
530 do { \
531 PyObject *obj = (EXPR); \
532 if (obj == NULL) { \
533 goto fail; \
534 } \
535 int res = PyDict_SetItemString(dict, (KEY), obj); \
536 Py_DECREF(obj); \
537 if (res < 0) { \
538 goto fail; \
539 } \
540 } while (0)
541#define SET_ITEM_INT(ATTR) \
542 SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100543#define FROM_STRING(STR) \
544 ((STR != NULL) ? \
545 PyUnicode_FromString(STR) \
546 : (Py_INCREF(Py_None), Py_None))
547#define SET_ITEM_STR(ATTR) \
548 SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
Victor Stinnercad1f742019-03-05 02:01:27 +0100549
550 SET_ITEM_INT(isolated);
551 SET_ITEM_INT(use_environment);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100552 SET_ITEM_INT(coerce_c_locale);
553 SET_ITEM_INT(coerce_c_locale_warn);
554 SET_ITEM_INT(utf8_mode);
555#ifdef MS_WINDOWS
556 SET_ITEM_INT(legacy_windows_fs_encoding);
557#endif
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100558 SET_ITEM_INT(dev_mode);
559 SET_ITEM_STR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100560 return 0;
561
562fail:
563 return -1;
564
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100565#undef FROM_STRING
Victor Stinnercad1f742019-03-05 02:01:27 +0100566#undef SET_ITEM
567#undef SET_ITEM_INT
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100568#undef SET_ITEM_STR
Victor Stinnercad1f742019-03-05 02:01:27 +0100569}
Victor Stinner6dcb5422019-03-05 02:44:12 +0100570
571
572/* Parse the command line arguments */
573static _PyInitError
574preconfig_parse_cmdline(_PyPreConfig *config, _PyPreCmdline *cmdline)
575{
576 _PyOS_ResetGetOpt();
577 /* Don't log parsing errors into stderr here: _PyCoreConfig_ReadFromArgv()
578 is responsible for that */
579 _PyOS_opterr = 0;
580 do {
581 int longindex = -1;
582 int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, &longindex);
583
584 if (c == EOF || c == 'c' || c == 'm') {
585 break;
586 }
587
588 switch (c) {
589 case 'E':
590 config->use_environment = 0;
591 break;
592
593 case 'I':
594 config->isolated++;
595 break;
596
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100597 case 'X':
598 {
599 _PyInitError err;
600 err = _Py_wstrlist_append(&cmdline->nxoption,
601 &cmdline->xoptions,
602 _PyOS_optarg);
603 if (_Py_INIT_FAILED(err)) {
604 return err;
605 }
606 break;
607 }
608
Victor Stinner6dcb5422019-03-05 02:44:12 +0100609 default:
610 /* ignore other argument:
611 handled by _PyCoreConfig_ReadFromArgv() */
612 break;
613 }
614 } while (1);
615
616 return _Py_INIT_OK();
617}
618
619
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100620static _PyInitError
621preconfig_from_argv(_PyPreConfig *config, const _PyArgv *args)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100622{
623 _PyInitError err;
624
625 _PyPreCmdline cmdline;
626 memset(&cmdline, 0, sizeof(cmdline));
627 cmdline.args = args;
628
629 err = _PyArgv_Decode(cmdline.args, &cmdline.argv);
630 if (_Py_INIT_FAILED(err)) {
631 goto done;
632 }
633
634 err = preconfig_parse_cmdline(config, &cmdline);
635 if (_Py_INIT_FAILED(err)) {
636 goto done;
637 }
638
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100639 err = preconfig_read(config, &cmdline);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100640 if (_Py_INIT_FAILED(err)) {
641 goto done;
642 }
643 err = _Py_INIT_OK();
644
645done:
646 precmdline_clear(&cmdline);
647 return err;
648}
649
650
Victor Stinner4fffd382019-03-06 01:44:31 +0100651/* Read the configuration from:
652
653 - command line arguments
654 - environment variables
655 - Py_xxx global configuration variables
656 - the LC_CTYPE locale
657
658 See _PyPreConfig_ReadFromArgv() to parse also command line arguments. */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100659_PyInitError
660_PyPreConfig_ReadFromArgv(_PyPreConfig *config, const _PyArgv *args)
661{
662 _PyInitError err;
663
664 err = _PyRuntime_Initialize();
665 if (_Py_INIT_FAILED(err)) {
666 return err;
667 }
668
669 char *init_ctype_locale = NULL;
670 int init_utf8_mode = Py_UTF8Mode;
671#ifdef MS_WINDOWS
672 int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
673#endif
674 _PyPreConfig save_config = _PyPreConfig_INIT;
675 int locale_coerced = 0;
676 int loops = 0;
677
Victor Stinner4fffd382019-03-06 01:44:31 +0100678 err = get_ctype_locale(&init_ctype_locale);
679 if (_Py_INIT_FAILED(err)) {
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100680 goto done;
681 }
682
683 if (_PyPreConfig_Copy(&save_config, config) < 0) {
684 err = _Py_INIT_NO_MEMORY();
685 goto done;
686 }
687
688 /* Set LC_CTYPE to the user preferred locale */
689 _Py_SetLocaleFromEnv(LC_CTYPE);
690
691 while (1) {
692 int utf8_mode = config->utf8_mode;
693
694 /* Watchdog to prevent an infinite loop */
695 loops++;
696 if (loops == 3) {
697 err = _Py_INIT_ERR("Encoding changed twice while "
698 "reading the configuration");
699 goto done;
700 }
701
702 /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend
703 on Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */
704 Py_UTF8Mode = config->utf8_mode;
705#ifdef MS_WINDOWS
706 Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
707#endif
708
709 err = preconfig_from_argv(config, args);
710 if (_Py_INIT_FAILED(err)) {
711 goto done;
712 }
713
714 if (locale_coerced) {
715 config->coerce_c_locale = 1;
716 }
717
718 /* The legacy C locale assumes ASCII as the default text encoding, which
719 * causes problems not only for the CPython runtime, but also other
720 * components like GNU readline.
721 *
722 * Accordingly, when the CLI detects it, it attempts to coerce it to a
723 * more capable UTF-8 based alternative.
724 *
725 * See the documentation of the PYTHONCOERCECLOCALE setting for more
726 * details.
727 */
728 int encoding_changed = 0;
729 if (config->coerce_c_locale && !locale_coerced) {
730 locale_coerced = 1;
731 _Py_CoerceLegacyLocale(0);
732 encoding_changed = 1;
733 }
734
735 if (utf8_mode == -1) {
736 if (config->utf8_mode == 1) {
737 /* UTF-8 Mode enabled */
738 encoding_changed = 1;
739 }
740 }
741 else {
742 if (config->utf8_mode != utf8_mode) {
743 encoding_changed = 1;
744 }
745 }
746
747 if (!encoding_changed) {
748 break;
749 }
750
751 /* Reset the configuration before reading again the configuration,
752 just keep UTF-8 Mode value. */
753 int new_utf8_mode = config->utf8_mode;
754 int new_coerce_c_locale = config->coerce_c_locale;
755 if (_PyPreConfig_Copy(config, &save_config) < 0) {
756 err = _Py_INIT_NO_MEMORY();
757 goto done;
758 }
759 config->utf8_mode = new_utf8_mode;
760 config->coerce_c_locale = new_coerce_c_locale;
761
762 /* The encoding changed: read again the configuration
763 with the new encoding */
764 }
765 err = _Py_INIT_OK();
766
767done:
768 if (init_ctype_locale != NULL) {
769 setlocale(LC_CTYPE, init_ctype_locale);
770 }
771 _PyPreConfig_Clear(&save_config);
772 Py_UTF8Mode = init_utf8_mode ;
773#ifdef MS_WINDOWS
774 Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
775#endif
776 return err;
777}
778
779
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100780static _PyInitError
Victor Stinnerc656e252019-03-06 01:13:43 +0100781_PyPreConfig_SetAllocator(_PyPreConfig *config)
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100782{
Victor Stinnerc656e252019-03-06 01:13:43 +0100783 assert(!_PyRuntime.core_initialized);
784
785 PyMemAllocatorEx old_alloc;
786 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
787
788 if (_PyMem_SetupAllocators(config->allocator) < 0) {
789 return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100790 }
Victor Stinnerc656e252019-03-06 01:13:43 +0100791
792 /* Copy the pre-configuration with the new allocator */
793 _PyPreConfig config2 = _PyPreConfig_INIT;
794 if (_PyPreConfig_Copy(&config2, config) < 0) {
795 _PyPreConfig_Clear(&config2);
796 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
797 return _Py_INIT_NO_MEMORY();
798 }
799
800 /* Free the old config and replace config with config2. Since config now
801 owns the data, don't free config2. */
802 PyMemAllocatorEx new_alloc;
803 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
804 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
805 _PyPreConfig_Clear(config);
806 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
807
808 *config = config2;
809
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100810 return _Py_INIT_OK();
811}
812
813
Victor Stinner4fffd382019-03-06 01:44:31 +0100814/* Write the pre-configuration:
815
816 - set the memory allocators
817 - set Py_xxx global configuration variables
818 - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
819 (PEP 540)
Victor Stinnerc656e252019-03-06 01:13:43 +0100820
821 If the memory allocator is changed, config is re-allocated with new
Victor Stinner4fffd382019-03-06 01:44:31 +0100822 allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
823
824 Do nothing if called after Py_Initialize(): ignore the new
825 pre-configuration. */
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100826_PyInitError
Victor Stinnerc656e252019-03-06 01:13:43 +0100827_PyPreConfig_Write(_PyPreConfig *config)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100828{
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100829 if (_PyRuntime.core_initialized) {
Victor Stinner4fffd382019-03-06 01:44:31 +0100830 /* bpo-34008: Calling this functions after Py_Initialize() ignores
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100831 the new configuration. */
Victor Stinnerc656e252019-03-06 01:13:43 +0100832 return _Py_INIT_OK();
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100833 }
834
835 if (config->allocator != NULL) {
Victor Stinnerc656e252019-03-06 01:13:43 +0100836 _PyInitError err = _PyPreConfig_SetAllocator(config);
837 if (_Py_INIT_FAILED(err)) {
838 return err;
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100839 }
840 }
841
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100842 _PyPreConfig_SetGlobalConfig(config);
843
844 if (config->coerce_c_locale) {
845 _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
846 }
847
848 /* Set LC_CTYPE to the user preferred locale */
849 _Py_SetLocaleFromEnv(LC_CTYPE);
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100850
851 return _Py_INIT_OK();
Victor Stinner6dcb5422019-03-05 02:44:12 +0100852}