blob: a149ea54f65a5a65985d196708a97aca459ce503 [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
Victor Stinner74f65682019-03-15 15:08:05 +010067_PyArgv_AsWstrList(const _PyArgv *args, _PyWstrList *list)
Victor Stinner91b9ecf2019-03-01 17:52:56 +010068{
Victor Stinner74f65682019-03-15 15:08:05 +010069 _PyWstrList wargv = _PyWstrList_INIT;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010070 if (args->use_bytes_argv) {
Victor Stinner74f65682019-03-15 15:08:05 +010071 size_t size = sizeof(wchar_t*) * args->argc;
72 wargv.items = (wchar_t **)PyMem_RawMalloc(size);
73 if (wargv.items == NULL) {
Victor Stinner91b9ecf2019-03-01 17:52:56 +010074 return _Py_INIT_NO_MEMORY();
75 }
76
Victor Stinner74f65682019-03-15 15:08:05 +010077 for (Py_ssize_t i = 0; i < args->argc; i++) {
Victor Stinner91b9ecf2019-03-01 17:52:56 +010078 size_t len;
79 wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
80 if (arg == NULL) {
Victor Stinner74f65682019-03-15 15:08:05 +010081 _PyWstrList_Clear(&wargv);
Victor Stinner91b9ecf2019-03-01 17:52:56 +010082 return DECODE_LOCALE_ERR("command line arguments",
83 (Py_ssize_t)len);
84 }
Victor Stinner74f65682019-03-15 15:08:05 +010085 wargv.items[i] = arg;
86 wargv.length++;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010087 }
Victor Stinner74f65682019-03-15 15:08:05 +010088
89 _PyWstrList_Clear(list);
90 *list = wargv;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010091 }
92 else {
Victor Stinner74f65682019-03-15 15:08:05 +010093 wargv.length = args->argc;
94 wargv.items = args->wchar_argv;
95 if (_PyWstrList_Copy(list, &wargv) < 0) {
96 return _Py_INIT_NO_MEMORY();
97 }
Victor Stinner91b9ecf2019-03-01 17:52:56 +010098 }
Victor Stinner91b9ecf2019-03-01 17:52:56 +010099 return _Py_INIT_OK();
100}
Victor Stinnercad1f742019-03-05 02:01:27 +0100101
102
Victor Stinner6dcb5422019-03-05 02:44:12 +0100103/* --- _PyPreCmdline ------------------------------------------------- */
104
105typedef struct {
Victor Stinner74f65682019-03-15 15:08:05 +0100106 _PyWstrList argv;
107 _PyWstrList xoptions; /* -X options */
Victor Stinner6dcb5422019-03-05 02:44:12 +0100108} _PyPreCmdline;
109
110
111static void
112precmdline_clear(_PyPreCmdline *cmdline)
113{
Victor Stinner74f65682019-03-15 15:08:05 +0100114 _PyWstrList_Clear(&cmdline->argv);
115 _PyWstrList_Clear(&cmdline->xoptions);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100116}
117
118
Victor Stinnercad1f742019-03-05 02:01:27 +0100119/* --- _PyPreConfig ----------------------------------------------- */
120
121void
122_PyPreConfig_Clear(_PyPreConfig *config)
123{
Victor Stinnerc656e252019-03-06 01:13:43 +0100124 PyMem_RawFree(config->allocator);
125 config->allocator = NULL;
Victor Stinnercad1f742019-03-05 02:01:27 +0100126}
127
128
129int
130_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
131{
132 _PyPreConfig_Clear(config);
133
134#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100135#define COPY_STR_ATTR(ATTR) \
136 do { \
137 if (config2->ATTR != NULL) { \
138 config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
139 if (config->ATTR == NULL) { \
140 return -1; \
141 } \
142 } \
143 } while (0)
Victor Stinnercad1f742019-03-05 02:01:27 +0100144
145 COPY_ATTR(isolated);
146 COPY_ATTR(use_environment);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100147 COPY_ATTR(coerce_c_locale);
148 COPY_ATTR(coerce_c_locale_warn);
149#ifdef MS_WINDOWS
150 COPY_ATTR(legacy_windows_fs_encoding);
151#endif
152 COPY_ATTR(utf8_mode);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100153 COPY_ATTR(dev_mode);
154 COPY_STR_ATTR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100155
156#undef COPY_ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100157#undef COPY_STR_ATTR
Victor Stinnercad1f742019-03-05 02:01:27 +0100158 return 0;
159}
160
161
162void
163_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
164{
165#define COPY_FLAG(ATTR, VALUE) \
166 if (config->ATTR == -1) { \
167 config->ATTR = VALUE; \
168 }
169#define COPY_NOT_FLAG(ATTR, VALUE) \
170 if (config->ATTR == -1) { \
171 config->ATTR = !(VALUE); \
172 }
173
174 COPY_FLAG(isolated, Py_IsolatedFlag);
175 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100176#ifdef MS_WINDOWS
177 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
178#endif
179 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100180
181#undef COPY_FLAG
182#undef COPY_NOT_FLAG
183}
184
185
186void
187_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
188{
189#define COPY_FLAG(ATTR, VAR) \
190 if (config->ATTR != -1) { \
191 VAR = config->ATTR; \
192 }
193#define COPY_NOT_FLAG(ATTR, VAR) \
194 if (config->ATTR != -1) { \
195 VAR = !config->ATTR; \
196 }
197
198 COPY_FLAG(isolated, Py_IsolatedFlag);
199 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100200#ifdef MS_WINDOWS
201 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
202#endif
203 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100204
205#undef COPY_FLAG
206#undef COPY_NOT_FLAG
207}
208
209
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100210const char*
211_PyPreConfig_GetEnv(const _PyPreConfig *config, const char *name)
212{
213 assert(config->use_environment >= 0);
214
215 if (!config->use_environment) {
216 return NULL;
217 }
218
219 const char *var = getenv(name);
220 if (var && var[0] != '\0') {
221 return var;
222 }
223 else {
224 return NULL;
225 }
226}
227
228
229int
230_Py_str_to_int(const char *str, int *result)
231{
232 const char *endptr = str;
233 errno = 0;
234 long value = strtol(str, (char **)&endptr, 10);
235 if (*endptr != '\0' || errno == ERANGE) {
236 return -1;
237 }
238 if (value < INT_MIN || value > INT_MAX) {
239 return -1;
240 }
241
242 *result = (int)value;
243 return 0;
244}
245
246
247void
248_Py_get_env_flag(_PyPreConfig *config, int *flag, const char *name)
249{
250 const char *var = _PyPreConfig_GetEnv(config, name);
251 if (!var) {
252 return;
253 }
254 int value;
255 if (_Py_str_to_int(var, &value) < 0 || value < 0) {
256 /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
257 value = 1;
258 }
259 if (*flag < value) {
260 *flag = value;
261 }
262}
263
264
265const wchar_t*
Victor Stinner74f65682019-03-15 15:08:05 +0100266_Py_get_xoption(const _PyWstrList *xoptions, const wchar_t *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100267{
Victor Stinner74f65682019-03-15 15:08:05 +0100268 for (Py_ssize_t i=0; i < xoptions->length; i++) {
269 const wchar_t *option = xoptions->items[i];
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100270 size_t len;
271 wchar_t *sep = wcschr(option, L'=');
272 if (sep != NULL) {
273 len = (sep - option);
274 }
275 else {
276 len = wcslen(option);
277 }
278 if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
279 return option;
280 }
281 }
282 return NULL;
283}
284
285
286static _PyInitError
287preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
288{
289 const wchar_t *xopt;
290 if (cmdline) {
Victor Stinner74f65682019-03-15 15:08:05 +0100291 xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100292 }
293 else {
294 xopt = NULL;
295 }
296 if (xopt) {
297 wchar_t *sep = wcschr(xopt, L'=');
298 if (sep) {
299 xopt = sep + 1;
300 if (wcscmp(xopt, L"1") == 0) {
301 config->utf8_mode = 1;
302 }
303 else if (wcscmp(xopt, L"0") == 0) {
304 config->utf8_mode = 0;
305 }
306 else {
307 return _Py_INIT_USER_ERR("invalid -X utf8 option value");
308 }
309 }
310 else {
311 config->utf8_mode = 1;
312 }
313 return _Py_INIT_OK();
314 }
315
316 const char *opt = _PyPreConfig_GetEnv(config, "PYTHONUTF8");
317 if (opt) {
318 if (strcmp(opt, "1") == 0) {
319 config->utf8_mode = 1;
320 }
321 else if (strcmp(opt, "0") == 0) {
322 config->utf8_mode = 0;
323 }
324 else {
325 return _Py_INIT_USER_ERR("invalid PYTHONUTF8 environment "
326 "variable value");
327 }
328 return _Py_INIT_OK();
329 }
330
331 return _Py_INIT_OK();
332}
333
334
335static void
336preconfig_init_locale(_PyPreConfig *config)
337{
338 /* Test also if coerce_c_locale equals 1: PYTHONCOERCECLOCALE=1 doesn't
339 imply that the C locale is always coerced. It is only coerced if
340 if the LC_CTYPE locale is "C". */
341 if (config->coerce_c_locale != 0) {
342 /* The C locale enables the C locale coercion (PEP 538) */
343 if (_Py_LegacyLocaleDetected()) {
344 config->coerce_c_locale = 1;
345 }
346 else {
347 config->coerce_c_locale = 0;
348 }
349 }
350}
351
352
353static _PyInitError
354preconfig_read(_PyPreConfig *config, const _PyPreCmdline *cmdline)
Victor Stinnercad1f742019-03-05 02:01:27 +0100355{
356 _PyPreConfig_GetGlobalConfig(config);
357
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100358 /* isolated and use_environment */
Victor Stinnercad1f742019-03-05 02:01:27 +0100359 if (config->isolated > 0) {
360 config->use_environment = 0;
361 }
362
363 /* Default values */
364 if (config->use_environment < 0) {
365 config->use_environment = 0;
366 }
367
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100368 /* legacy_windows_fs_encoding, utf8_mode, coerce_c_locale */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100369 if (config->use_environment) {
370#ifdef MS_WINDOWS
371 _Py_get_env_flag(config, &config->legacy_windows_fs_encoding,
372 "PYTHONLEGACYWINDOWSFSENCODING");
373#endif
374
375 const char *env = _PyPreConfig_GetEnv(config, "PYTHONCOERCECLOCALE");
376 if (env) {
377 if (strcmp(env, "0") == 0) {
378 if (config->coerce_c_locale < 0) {
379 config->coerce_c_locale = 0;
380 }
381 }
382 else if (strcmp(env, "warn") == 0) {
383 config->coerce_c_locale_warn = 1;
384 }
385 else {
386 if (config->coerce_c_locale < 0) {
387 config->coerce_c_locale = 1;
388 }
389 }
390 }
391 }
392
393#ifdef MS_WINDOWS
394 if (config->legacy_windows_fs_encoding) {
395 config->utf8_mode = 0;
396 }
397#endif
398
399 if (config->utf8_mode < 0) {
400 _PyInitError err = preconfig_init_utf8_mode(config, cmdline);
401 if (_Py_INIT_FAILED(err)) {
402 return err;
403 }
404 }
405
406 if (config->coerce_c_locale != 0) {
407 preconfig_init_locale(config);
408 }
409
410#ifndef MS_WINDOWS
411 if (config->utf8_mode < 0) {
412 /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
413 const char *ctype_loc = setlocale(LC_CTYPE, NULL);
414 if (ctype_loc != NULL
415 && (strcmp(ctype_loc, "C") == 0
416 || strcmp(ctype_loc, "POSIX") == 0))
417 {
418 config->utf8_mode = 1;
419 }
420 }
421#endif
422
423 if (config->coerce_c_locale < 0) {
424 config->coerce_c_locale = 0;
425 }
426 if (config->utf8_mode < 0) {
427 config->utf8_mode = 0;
428 }
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100429 if (config->coerce_c_locale < 0) {
430 config->coerce_c_locale = 0;
431 }
432
433 /* dev_mode */
Victor Stinner74f65682019-03-15 15:08:05 +0100434 if ((cmdline && _Py_get_xoption(&cmdline->xoptions, L"dev"))
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100435 || _PyPreConfig_GetEnv(config, "PYTHONDEVMODE"))
436 {
437 config->dev_mode = 1;
438 }
439 if (config->dev_mode < 0) {
440 config->dev_mode = 0;
441 }
442
443 /* allocator */
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100444 if (config->allocator == NULL) {
Victor Stinner25d13f32019-03-06 12:51:53 +0100445 /* bpo-34247. The PYTHONMALLOC environment variable has the priority
446 over PYTHONDEV env var and "-X dev" command line option.
447 For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
448 allocators to "malloc" (and not to "debug"). */
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100449 const char *allocator = _PyPreConfig_GetEnv(config, "PYTHONMALLOC");
450 if (allocator) {
451 config->allocator = _PyMem_RawStrdup(allocator);
452 if (config->allocator == NULL) {
453 return _Py_INIT_NO_MEMORY();
454 }
455 }
456 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100457
Victor Stinner25d13f32019-03-06 12:51:53 +0100458 if (config->dev_mode && config->allocator == NULL) {
459 config->allocator = _PyMem_RawStrdup("debug");
460 if (config->allocator == NULL) {
461 return _Py_INIT_NO_MEMORY();
462 }
463 }
464
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100465 assert(config->coerce_c_locale >= 0);
466 assert(config->utf8_mode >= 0);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100467 assert(config->isolated >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100468 assert(config->use_environment >= 0);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100469 assert(config->dev_mode >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100470
471 return _Py_INIT_OK();
472}
473
474
Victor Stinner4fffd382019-03-06 01:44:31 +0100475static _PyInitError
476get_ctype_locale(char **locale_p)
477{
478 const char *loc = setlocale(LC_CTYPE, NULL);
479 if (loc == NULL) {
480 return _Py_INIT_ERR("failed to LC_CTYPE locale");
481 }
482
483 char *copy = _PyMem_RawStrdup(loc);
484 if (copy == NULL) {
485 return _Py_INIT_NO_MEMORY();
486 }
487
488 *locale_p = copy;
489 return _Py_INIT_OK();
490}
491
492
493/* Read the configuration from:
494
495 - environment variables
496 - Py_xxx global configuration variables
497 - the LC_CTYPE locale
498
499 See _PyPreConfig_ReadFromArgv() to parse also command line arguments. */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100500_PyInitError
501_PyPreConfig_Read(_PyPreConfig *config)
502{
Victor Stinner4fffd382019-03-06 01:44:31 +0100503 _PyInitError err;
504 char *old_loc;
505
506 err = get_ctype_locale(&old_loc);
507 if (_Py_INIT_FAILED(err)) {
508 return err;
509 }
510
511 /* Set LC_CTYPE to the user preferred locale */
512 _Py_SetLocaleFromEnv(LC_CTYPE);
513
514 err = preconfig_read(config, NULL);
515
516 setlocale(LC_CTYPE, old_loc);
btharpere130a072019-03-19 06:50:25 -0400517 PyMem_RawFree(old_loc);
Victor Stinner4fffd382019-03-06 01:44:31 +0100518
519 return err;
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100520}
521
522
Victor Stinnercad1f742019-03-05 02:01:27 +0100523int
524_PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
525{
526#define SET_ITEM(KEY, EXPR) \
527 do { \
528 PyObject *obj = (EXPR); \
529 if (obj == NULL) { \
530 goto fail; \
531 } \
532 int res = PyDict_SetItemString(dict, (KEY), obj); \
533 Py_DECREF(obj); \
534 if (res < 0) { \
535 goto fail; \
536 } \
537 } while (0)
538#define SET_ITEM_INT(ATTR) \
539 SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100540#define FROM_STRING(STR) \
541 ((STR != NULL) ? \
542 PyUnicode_FromString(STR) \
543 : (Py_INCREF(Py_None), Py_None))
544#define SET_ITEM_STR(ATTR) \
545 SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
Victor Stinnercad1f742019-03-05 02:01:27 +0100546
547 SET_ITEM_INT(isolated);
548 SET_ITEM_INT(use_environment);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100549 SET_ITEM_INT(coerce_c_locale);
550 SET_ITEM_INT(coerce_c_locale_warn);
551 SET_ITEM_INT(utf8_mode);
552#ifdef MS_WINDOWS
553 SET_ITEM_INT(legacy_windows_fs_encoding);
554#endif
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100555 SET_ITEM_INT(dev_mode);
556 SET_ITEM_STR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100557 return 0;
558
559fail:
560 return -1;
561
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100562#undef FROM_STRING
Victor Stinnercad1f742019-03-05 02:01:27 +0100563#undef SET_ITEM
564#undef SET_ITEM_INT
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100565#undef SET_ITEM_STR
Victor Stinnercad1f742019-03-05 02:01:27 +0100566}
Victor Stinner6dcb5422019-03-05 02:44:12 +0100567
568
569/* Parse the command line arguments */
570static _PyInitError
571preconfig_parse_cmdline(_PyPreConfig *config, _PyPreCmdline *cmdline)
572{
573 _PyOS_ResetGetOpt();
574 /* Don't log parsing errors into stderr here: _PyCoreConfig_ReadFromArgv()
575 is responsible for that */
576 _PyOS_opterr = 0;
577 do {
578 int longindex = -1;
Victor Stinner74f65682019-03-15 15:08:05 +0100579 int c = _PyOS_GetOpt(cmdline->argv.length, cmdline->argv.items, &longindex);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100580
581 if (c == EOF || c == 'c' || c == 'm') {
582 break;
583 }
584
585 switch (c) {
586 case 'E':
587 config->use_environment = 0;
588 break;
589
590 case 'I':
591 config->isolated++;
592 break;
593
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100594 case 'X':
595 {
Victor Stinner74f65682019-03-15 15:08:05 +0100596 if (_PyWstrList_Append(&cmdline->xoptions, _PyOS_optarg) < 0) {
597 return _Py_INIT_NO_MEMORY();
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100598 }
599 break;
600 }
601
Victor Stinner6dcb5422019-03-05 02:44:12 +0100602 default:
603 /* ignore other argument:
604 handled by _PyCoreConfig_ReadFromArgv() */
605 break;
606 }
607 } while (1);
608
609 return _Py_INIT_OK();
610}
611
612
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100613static _PyInitError
614preconfig_from_argv(_PyPreConfig *config, const _PyArgv *args)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100615{
616 _PyInitError err;
617
618 _PyPreCmdline cmdline;
619 memset(&cmdline, 0, sizeof(cmdline));
Victor Stinner6dcb5422019-03-05 02:44:12 +0100620
Victor Stinner74f65682019-03-15 15:08:05 +0100621 err = _PyArgv_AsWstrList(args, &cmdline.argv);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100622 if (_Py_INIT_FAILED(err)) {
623 goto done;
624 }
625
626 err = preconfig_parse_cmdline(config, &cmdline);
627 if (_Py_INIT_FAILED(err)) {
628 goto done;
629 }
630
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100631 err = preconfig_read(config, &cmdline);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100632 if (_Py_INIT_FAILED(err)) {
633 goto done;
634 }
635 err = _Py_INIT_OK();
636
637done:
638 precmdline_clear(&cmdline);
639 return err;
640}
641
642
Victor Stinner4fffd382019-03-06 01:44:31 +0100643/* Read the configuration from:
644
645 - command line arguments
646 - environment variables
647 - Py_xxx global configuration variables
648 - the LC_CTYPE locale
649
650 See _PyPreConfig_ReadFromArgv() to parse also command line arguments. */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100651_PyInitError
652_PyPreConfig_ReadFromArgv(_PyPreConfig *config, const _PyArgv *args)
653{
654 _PyInitError err;
655
656 err = _PyRuntime_Initialize();
657 if (_Py_INIT_FAILED(err)) {
658 return err;
659 }
660
661 char *init_ctype_locale = NULL;
662 int init_utf8_mode = Py_UTF8Mode;
663#ifdef MS_WINDOWS
664 int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
665#endif
666 _PyPreConfig save_config = _PyPreConfig_INIT;
667 int locale_coerced = 0;
668 int loops = 0;
669
Victor Stinner4fffd382019-03-06 01:44:31 +0100670 err = get_ctype_locale(&init_ctype_locale);
671 if (_Py_INIT_FAILED(err)) {
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100672 goto done;
673 }
674
Victor Stinnerf29084d2019-03-20 02:20:13 +0100675 _PyPreConfig_GetGlobalConfig(config);
676
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100677 if (_PyPreConfig_Copy(&save_config, config) < 0) {
678 err = _Py_INIT_NO_MEMORY();
679 goto done;
680 }
681
682 /* Set LC_CTYPE to the user preferred locale */
683 _Py_SetLocaleFromEnv(LC_CTYPE);
684
685 while (1) {
686 int utf8_mode = config->utf8_mode;
687
688 /* Watchdog to prevent an infinite loop */
689 loops++;
690 if (loops == 3) {
691 err = _Py_INIT_ERR("Encoding changed twice while "
692 "reading the configuration");
693 goto done;
694 }
695
696 /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend
697 on Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */
698 Py_UTF8Mode = config->utf8_mode;
699#ifdef MS_WINDOWS
700 Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
701#endif
702
703 err = preconfig_from_argv(config, args);
704 if (_Py_INIT_FAILED(err)) {
705 goto done;
706 }
707
708 if (locale_coerced) {
709 config->coerce_c_locale = 1;
710 }
711
712 /* The legacy C locale assumes ASCII as the default text encoding, which
713 * causes problems not only for the CPython runtime, but also other
714 * components like GNU readline.
715 *
716 * Accordingly, when the CLI detects it, it attempts to coerce it to a
717 * more capable UTF-8 based alternative.
718 *
719 * See the documentation of the PYTHONCOERCECLOCALE setting for more
720 * details.
721 */
722 int encoding_changed = 0;
723 if (config->coerce_c_locale && !locale_coerced) {
724 locale_coerced = 1;
725 _Py_CoerceLegacyLocale(0);
726 encoding_changed = 1;
727 }
728
729 if (utf8_mode == -1) {
730 if (config->utf8_mode == 1) {
731 /* UTF-8 Mode enabled */
732 encoding_changed = 1;
733 }
734 }
735 else {
736 if (config->utf8_mode != utf8_mode) {
737 encoding_changed = 1;
738 }
739 }
740
741 if (!encoding_changed) {
742 break;
743 }
744
745 /* Reset the configuration before reading again the configuration,
746 just keep UTF-8 Mode value. */
747 int new_utf8_mode = config->utf8_mode;
748 int new_coerce_c_locale = config->coerce_c_locale;
749 if (_PyPreConfig_Copy(config, &save_config) < 0) {
750 err = _Py_INIT_NO_MEMORY();
751 goto done;
752 }
753 config->utf8_mode = new_utf8_mode;
754 config->coerce_c_locale = new_coerce_c_locale;
755
756 /* The encoding changed: read again the configuration
757 with the new encoding */
758 }
759 err = _Py_INIT_OK();
760
761done:
762 if (init_ctype_locale != NULL) {
763 setlocale(LC_CTYPE, init_ctype_locale);
Victor Stinnerc1834442019-03-18 22:24:28 +0100764 PyMem_RawFree(init_ctype_locale);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100765 }
766 _PyPreConfig_Clear(&save_config);
767 Py_UTF8Mode = init_utf8_mode ;
768#ifdef MS_WINDOWS
769 Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
770#endif
771 return err;
772}
773
774
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100775static _PyInitError
Victor Stinnerc656e252019-03-06 01:13:43 +0100776_PyPreConfig_SetAllocator(_PyPreConfig *config)
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100777{
Victor Stinnerc656e252019-03-06 01:13:43 +0100778 assert(!_PyRuntime.core_initialized);
779
780 PyMemAllocatorEx old_alloc;
781 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
782
783 if (_PyMem_SetupAllocators(config->allocator) < 0) {
784 return _Py_INIT_USER_ERR("Unknown PYTHONMALLOC allocator");
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100785 }
Victor Stinnerc656e252019-03-06 01:13:43 +0100786
787 /* Copy the pre-configuration with the new allocator */
788 _PyPreConfig config2 = _PyPreConfig_INIT;
789 if (_PyPreConfig_Copy(&config2, config) < 0) {
790 _PyPreConfig_Clear(&config2);
791 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
792 return _Py_INIT_NO_MEMORY();
793 }
794
795 /* Free the old config and replace config with config2. Since config now
796 owns the data, don't free config2. */
797 PyMemAllocatorEx new_alloc;
798 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
799 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
800 _PyPreConfig_Clear(config);
801 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
802
803 *config = config2;
804
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100805 return _Py_INIT_OK();
806}
807
808
Victor Stinner4fffd382019-03-06 01:44:31 +0100809/* Write the pre-configuration:
810
811 - set the memory allocators
812 - set Py_xxx global configuration variables
813 - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
814 (PEP 540)
Victor Stinnerc656e252019-03-06 01:13:43 +0100815
816 If the memory allocator is changed, config is re-allocated with new
Victor Stinner4fffd382019-03-06 01:44:31 +0100817 allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
818
819 Do nothing if called after Py_Initialize(): ignore the new
820 pre-configuration. */
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100821_PyInitError
Victor Stinnerc656e252019-03-06 01:13:43 +0100822_PyPreConfig_Write(_PyPreConfig *config)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100823{
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100824 if (_PyRuntime.core_initialized) {
Victor Stinner4fffd382019-03-06 01:44:31 +0100825 /* bpo-34008: Calling this functions after Py_Initialize() ignores
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100826 the new configuration. */
Victor Stinnerc656e252019-03-06 01:13:43 +0100827 return _Py_INIT_OK();
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100828 }
829
830 if (config->allocator != NULL) {
Victor Stinnerc656e252019-03-06 01:13:43 +0100831 _PyInitError err = _PyPreConfig_SetAllocator(config);
832 if (_Py_INIT_FAILED(err)) {
833 return err;
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100834 }
835 }
836
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100837 _PyPreConfig_SetGlobalConfig(config);
838
839 if (config->coerce_c_locale) {
840 _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
841 }
842
843 /* Set LC_CTYPE to the user preferred locale */
844 _Py_SetLocaleFromEnv(LC_CTYPE);
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100845
846 return _Py_INIT_OK();
Victor Stinner6dcb5422019-03-05 02:44:12 +0100847}