blob: 48b9e8383aae146c697c0da1fae629eacaa1f255 [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{
177 _PyWstrList *argv = &cmdline->argv;
178
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
263void
264_PyPreConfig_Clear(_PyPreConfig *config)
265{
Victor Stinnerc656e252019-03-06 01:13:43 +0100266 PyMem_RawFree(config->allocator);
267 config->allocator = NULL;
Victor Stinnercad1f742019-03-05 02:01:27 +0100268}
269
270
271int
272_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
273{
274 _PyPreConfig_Clear(config);
275
276#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100277#define COPY_STR_ATTR(ATTR) \
278 do { \
279 if (config2->ATTR != NULL) { \
280 config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
281 if (config->ATTR == NULL) { \
282 return -1; \
283 } \
284 } \
285 } while (0)
Victor Stinnercad1f742019-03-05 02:01:27 +0100286
287 COPY_ATTR(isolated);
288 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100289 COPY_ATTR(dev_mode);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100290 COPY_ATTR(coerce_c_locale);
291 COPY_ATTR(coerce_c_locale_warn);
292#ifdef MS_WINDOWS
293 COPY_ATTR(legacy_windows_fs_encoding);
294#endif
295 COPY_ATTR(utf8_mode);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100296 COPY_STR_ATTR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100297
298#undef COPY_ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100299#undef COPY_STR_ATTR
Victor Stinnercad1f742019-03-05 02:01:27 +0100300 return 0;
301}
302
303
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100304PyObject*
305_PyPreConfig_AsDict(const _PyPreConfig *config)
306{
307 PyObject *dict;
308
309 dict = PyDict_New();
310 if (dict == NULL) {
311 return NULL;
312 }
313
314#define SET_ITEM(KEY, EXPR) \
315 do { \
316 PyObject *obj = (EXPR); \
317 if (obj == NULL) { \
318 goto fail; \
319 } \
320 int res = PyDict_SetItemString(dict, (KEY), obj); \
321 Py_DECREF(obj); \
322 if (res < 0) { \
323 goto fail; \
324 } \
325 } while (0)
326#define SET_ITEM_INT(ATTR) \
327 SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
328#define FROM_STRING(STR) \
329 ((STR != NULL) ? \
330 PyUnicode_FromString(STR) \
331 : (Py_INCREF(Py_None), Py_None))
332#define SET_ITEM_STR(ATTR) \
333 SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
334
335 SET_ITEM_INT(isolated);
336 SET_ITEM_INT(use_environment);
337 SET_ITEM_INT(coerce_c_locale);
338 SET_ITEM_INT(coerce_c_locale_warn);
339 SET_ITEM_INT(utf8_mode);
340#ifdef MS_WINDOWS
341 SET_ITEM_INT(legacy_windows_fs_encoding);
342#endif
343 SET_ITEM_INT(dev_mode);
344 SET_ITEM_STR(allocator);
345 return dict;
346
347fail:
348 Py_DECREF(dict);
349 return NULL;
350
351#undef FROM_STRING
352#undef SET_ITEM
353#undef SET_ITEM_INT
354#undef SET_ITEM_STR
355}
356
357
Victor Stinner5ac27a52019-03-27 13:40:14 +0100358void
359_PyCoreConfig_GetCoreConfig(_PyPreConfig *config,
360 const _PyCoreConfig *core_config)
361{
362#define COPY_ATTR(ATTR) \
363 if (core_config->ATTR != -1) { \
364 config->ATTR = core_config->ATTR; \
365 }
366
367 COPY_ATTR(isolated);
368 COPY_ATTR(use_environment);
369 COPY_ATTR(dev_mode);
370
371#undef COPY_ATTR
372}
373
374
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100375static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100376_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
377{
378#define COPY_FLAG(ATTR, VALUE) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100379 if (config->ATTR == -1) { \
380 config->ATTR = VALUE; \
381 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100382#define COPY_NOT_FLAG(ATTR, VALUE) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100383 if (config->ATTR == -1) { \
384 config->ATTR = !(VALUE); \
385 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100386
387 COPY_FLAG(isolated, Py_IsolatedFlag);
388 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100389#ifdef MS_WINDOWS
390 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
391#endif
Victor Stinnerd929f182019-03-27 18:28:46 +0100392 if (Py_UTF8Mode > 0) {
393 config->utf8_mode = 1;
394 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100395
396#undef COPY_FLAG
397#undef COPY_NOT_FLAG
398}
399
400
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100401static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100402_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
403{
404#define COPY_FLAG(ATTR, VAR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100405 if (config->ATTR != -1) { \
406 VAR = config->ATTR; \
407 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100408#define COPY_NOT_FLAG(ATTR, VAR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100409 if (config->ATTR != -1) { \
410 VAR = !config->ATTR; \
411 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100412
413 COPY_FLAG(isolated, Py_IsolatedFlag);
414 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100415#ifdef MS_WINDOWS
416 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
417#endif
418 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100419
420#undef COPY_FLAG
421#undef COPY_NOT_FLAG
422}
423
424
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100425const char*
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100426_Py_GetEnv(int use_environment, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100427{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100428 assert(use_environment >= 0);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100429
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100430 if (!use_environment) {
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100431 return NULL;
432 }
433
434 const char *var = getenv(name);
435 if (var && var[0] != '\0') {
436 return var;
437 }
438 else {
439 return NULL;
440 }
441}
442
443
444int
445_Py_str_to_int(const char *str, int *result)
446{
447 const char *endptr = str;
448 errno = 0;
449 long value = strtol(str, (char **)&endptr, 10);
450 if (*endptr != '\0' || errno == ERANGE) {
451 return -1;
452 }
453 if (value < INT_MIN || value > INT_MAX) {
454 return -1;
455 }
456
457 *result = (int)value;
458 return 0;
459}
460
461
462void
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100463_Py_get_env_flag(int use_environment, int *flag, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100464{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100465 const char *var = _Py_GetEnv(use_environment, name);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100466 if (!var) {
467 return;
468 }
469 int value;
470 if (_Py_str_to_int(var, &value) < 0 || value < 0) {
471 /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
472 value = 1;
473 }
474 if (*flag < value) {
475 *flag = value;
476 }
477}
478
479
480const wchar_t*
Victor Stinner74f65682019-03-15 15:08:05 +0100481_Py_get_xoption(const _PyWstrList *xoptions, const wchar_t *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100482{
Victor Stinner74f65682019-03-15 15:08:05 +0100483 for (Py_ssize_t i=0; i < xoptions->length; i++) {
484 const wchar_t *option = xoptions->items[i];
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100485 size_t len;
486 wchar_t *sep = wcschr(option, L'=');
487 if (sep != NULL) {
488 len = (sep - option);
489 }
490 else {
491 len = wcslen(option);
492 }
493 if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
494 return option;
495 }
496 }
497 return NULL;
498}
499
500
501static _PyInitError
502preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
503{
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100504#ifdef MS_WINDOWS
505 if (config->legacy_windows_fs_encoding) {
506 config->utf8_mode = 0;
507 }
508#endif
509
510 if (config->utf8_mode >= 0) {
511 return _Py_INIT_OK();
512 }
513
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100514 const wchar_t *xopt;
515 if (cmdline) {
Victor Stinner74f65682019-03-15 15:08:05 +0100516 xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100517 }
518 else {
519 xopt = NULL;
520 }
521 if (xopt) {
522 wchar_t *sep = wcschr(xopt, L'=');
523 if (sep) {
524 xopt = sep + 1;
525 if (wcscmp(xopt, L"1") == 0) {
526 config->utf8_mode = 1;
527 }
528 else if (wcscmp(xopt, L"0") == 0) {
529 config->utf8_mode = 0;
530 }
531 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200532 return _Py_INIT_ERR("invalid -X utf8 option value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100533 }
534 }
535 else {
536 config->utf8_mode = 1;
537 }
538 return _Py_INIT_OK();
539 }
540
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100541 const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100542 if (opt) {
543 if (strcmp(opt, "1") == 0) {
544 config->utf8_mode = 1;
545 }
546 else if (strcmp(opt, "0") == 0) {
547 config->utf8_mode = 0;
548 }
549 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200550 return _Py_INIT_ERR("invalid PYTHONUTF8 environment "
551 "variable value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100552 }
553 return _Py_INIT_OK();
554 }
555
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100556
557#ifndef MS_WINDOWS
558 if (config->utf8_mode < 0) {
559 /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
560 const char *ctype_loc = setlocale(LC_CTYPE, NULL);
561 if (ctype_loc != NULL
562 && (strcmp(ctype_loc, "C") == 0
563 || strcmp(ctype_loc, "POSIX") == 0))
564 {
565 config->utf8_mode = 1;
566 }
567 }
568#endif
569
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100570 if (config->utf8_mode < 0) {
571 config->utf8_mode = 0;
572 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100573 return _Py_INIT_OK();
574}
575
576
577static void
578preconfig_init_coerce_c_locale(_PyPreConfig *config)
579{
580 const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
581 if (env) {
582 if (strcmp(env, "0") == 0) {
583 if (config->coerce_c_locale < 0) {
584 config->coerce_c_locale = 0;
585 }
586 }
587 else if (strcmp(env, "warn") == 0) {
588 config->coerce_c_locale_warn = 1;
589 }
590 else {
591 if (config->coerce_c_locale < 0) {
592 config->coerce_c_locale = 1;
593 }
594 }
595 }
596
597 /* Test if coerce_c_locale equals to -1 or equals to 1:
598 PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.
599 It is only coerced if if the LC_CTYPE locale is "C". */
600 if (config->coerce_c_locale == 0 || config->coerce_c_locale == 2) {
601 return;
602 }
603
604 /* The C locale enables the C locale coercion (PEP 538) */
605 if (_Py_LegacyLocaleDetected()) {
606 config->coerce_c_locale = 2;
607 }
608 else {
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100609 config->coerce_c_locale = 0;
610 }
611
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100612 assert(config->coerce_c_locale >= 0);
613}
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100614
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100615
616static _PyInitError
617preconfig_init_allocator(_PyPreConfig *config)
618{
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100619 if (config->allocator == NULL) {
Victor Stinner25d13f32019-03-06 12:51:53 +0100620 /* bpo-34247. The PYTHONMALLOC environment variable has the priority
621 over PYTHONDEV env var and "-X dev" command line option.
622 For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
623 allocators to "malloc" (and not to "debug"). */
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100624 const char *allocator = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100625 if (allocator) {
626 config->allocator = _PyMem_RawStrdup(allocator);
627 if (config->allocator == NULL) {
628 return _Py_INIT_NO_MEMORY();
629 }
630 }
631 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100632
Victor Stinner25d13f32019-03-06 12:51:53 +0100633 if (config->dev_mode && config->allocator == NULL) {
634 config->allocator = _PyMem_RawStrdup("debug");
635 if (config->allocator == NULL) {
636 return _Py_INIT_NO_MEMORY();
637 }
638 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100639 return _Py_INIT_OK();
640}
641
642
643static _PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100644preconfig_read(_PyPreConfig *config, _PyPreCmdline *cmdline)
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100645{
646 _PyInitError err;
647
Victor Stinner5ac27a52019-03-27 13:40:14 +0100648 err = _PyPreCmdline_Read(cmdline, config);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100649 if (_Py_INIT_FAILED(err)) {
650 return err;
651 }
652
653 _PyPreCmdline_SetPreConfig(cmdline, config);
654
655 /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */
656#ifdef MS_WINDOWS
657 _Py_get_env_flag(config->use_environment,
658 &config->legacy_windows_fs_encoding,
659 "PYTHONLEGACYWINDOWSFSENCODING");
660#endif
661
662 preconfig_init_coerce_c_locale(config);
663
664 err = preconfig_init_utf8_mode(config, cmdline);
665 if (_Py_INIT_FAILED(err)) {
666 return err;
667 }
668
669 /* allocator */
670 err = preconfig_init_allocator(config);
671 if (_Py_INIT_FAILED(err)) {
672 return err;
673 }
Victor Stinner25d13f32019-03-06 12:51:53 +0100674
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100675 assert(config->coerce_c_locale >= 0);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100676#ifdef MS_WINDOWS
677 assert(config->legacy_windows_fs_encoding >= 0);
678#endif
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100679 assert(config->utf8_mode >= 0);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100680 assert(config->isolated >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100681 assert(config->use_environment >= 0);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100682 assert(config->dev_mode >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100683
684 return _Py_INIT_OK();
685}
686
687
Victor Stinner4fffd382019-03-06 01:44:31 +0100688/* Read the configuration from:
689
690 - command line arguments
691 - environment variables
692 - Py_xxx global configuration variables
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100693 - the LC_CTYPE locale */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100694_PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100695_PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100696{
697 _PyInitError err;
698
699 err = _PyRuntime_Initialize();
700 if (_Py_INIT_FAILED(err)) {
701 return err;
702 }
703
Victor Stinnerf29084d2019-03-20 02:20:13 +0100704 _PyPreConfig_GetGlobalConfig(config);
705
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100706 /* Copy LC_CTYPE locale, since it's modified later */
707 const char *loc = setlocale(LC_CTYPE, NULL);
708 if (loc == NULL) {
709 return _Py_INIT_ERR("failed to LC_CTYPE locale");
710 }
711 char *init_ctype_locale = _PyMem_RawStrdup(loc);
712 if (init_ctype_locale == NULL) {
713 return _Py_INIT_NO_MEMORY();
714 }
715
716 /* Save the config to be able to restore it if encodings change */
717 _PyPreConfig save_config = _PyPreConfig_INIT;
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100718 if (_PyPreConfig_Copy(&save_config, config) < 0) {
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100719 return _Py_INIT_NO_MEMORY();
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100720 }
721
722 /* Set LC_CTYPE to the user preferred locale */
723 _Py_SetLocaleFromEnv(LC_CTYPE);
724
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100725 _PyPreCmdline cmdline = _PyPreCmdline_INIT;
Victor Stinner6a8c3132019-04-05 11:44:04 +0200726 int init_utf8_mode = Py_UTF8Mode;
727#ifdef MS_WINDOWS
728 int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
729#endif
730
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100731 if (args) {
732 err = _PyPreCmdline_SetArgv(&cmdline, args);
733 if (_Py_INIT_FAILED(err)) {
734 goto done;
735 }
736 }
737
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100738 int locale_coerced = 0;
739 int loops = 0;
740
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100741 while (1) {
742 int utf8_mode = config->utf8_mode;
743
744 /* Watchdog to prevent an infinite loop */
745 loops++;
746 if (loops == 3) {
747 err = _Py_INIT_ERR("Encoding changed twice while "
748 "reading the configuration");
749 goto done;
750 }
751
752 /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend
753 on Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */
754 Py_UTF8Mode = config->utf8_mode;
755#ifdef MS_WINDOWS
756 Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
757#endif
758
Victor Stinner5ac27a52019-03-27 13:40:14 +0100759 err = preconfig_read(config, &cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100760 if (_Py_INIT_FAILED(err)) {
761 goto done;
762 }
763
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100764 /* The legacy C locale assumes ASCII as the default text encoding, which
765 * causes problems not only for the CPython runtime, but also other
766 * components like GNU readline.
767 *
768 * Accordingly, when the CLI detects it, it attempts to coerce it to a
769 * more capable UTF-8 based alternative.
770 *
771 * See the documentation of the PYTHONCOERCECLOCALE setting for more
772 * details.
773 */
774 int encoding_changed = 0;
775 if (config->coerce_c_locale && !locale_coerced) {
776 locale_coerced = 1;
777 _Py_CoerceLegacyLocale(0);
778 encoding_changed = 1;
779 }
780
781 if (utf8_mode == -1) {
782 if (config->utf8_mode == 1) {
783 /* UTF-8 Mode enabled */
784 encoding_changed = 1;
785 }
786 }
787 else {
788 if (config->utf8_mode != utf8_mode) {
789 encoding_changed = 1;
790 }
791 }
792
793 if (!encoding_changed) {
794 break;
795 }
796
797 /* Reset the configuration before reading again the configuration,
798 just keep UTF-8 Mode value. */
799 int new_utf8_mode = config->utf8_mode;
800 int new_coerce_c_locale = config->coerce_c_locale;
801 if (_PyPreConfig_Copy(config, &save_config) < 0) {
802 err = _Py_INIT_NO_MEMORY();
803 goto done;
804 }
805 config->utf8_mode = new_utf8_mode;
806 config->coerce_c_locale = new_coerce_c_locale;
807
808 /* The encoding changed: read again the configuration
809 with the new encoding */
810 }
811 err = _Py_INIT_OK();
812
813done:
814 if (init_ctype_locale != NULL) {
815 setlocale(LC_CTYPE, init_ctype_locale);
Victor Stinnerc1834442019-03-18 22:24:28 +0100816 PyMem_RawFree(init_ctype_locale);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100817 }
818 _PyPreConfig_Clear(&save_config);
819 Py_UTF8Mode = init_utf8_mode ;
820#ifdef MS_WINDOWS
821 Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
822#endif
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100823 _PyPreCmdline_Clear(&cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100824 return err;
825}
826
827
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100828static _PyInitError
Victor Stinnerc656e252019-03-06 01:13:43 +0100829_PyPreConfig_SetAllocator(_PyPreConfig *config)
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100830{
Victor Stinnerc656e252019-03-06 01:13:43 +0100831 assert(!_PyRuntime.core_initialized);
832
833 PyMemAllocatorEx old_alloc;
834 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
835
836 if (_PyMem_SetupAllocators(config->allocator) < 0) {
Victor Stinnerdb719752019-05-01 05:35:33 +0200837 return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100838 }
Victor Stinnerc656e252019-03-06 01:13:43 +0100839
840 /* Copy the pre-configuration with the new allocator */
841 _PyPreConfig config2 = _PyPreConfig_INIT;
842 if (_PyPreConfig_Copy(&config2, config) < 0) {
843 _PyPreConfig_Clear(&config2);
844 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
845 return _Py_INIT_NO_MEMORY();
846 }
847
848 /* Free the old config and replace config with config2. Since config now
849 owns the data, don't free config2. */
850 PyMemAllocatorEx new_alloc;
851 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
852 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
853 _PyPreConfig_Clear(config);
854 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &new_alloc);
855
856 *config = config2;
857
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100858 return _Py_INIT_OK();
859}
860
861
Victor Stinner4fffd382019-03-06 01:44:31 +0100862/* Write the pre-configuration:
863
864 - set the memory allocators
865 - set Py_xxx global configuration variables
866 - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
867 (PEP 540)
Victor Stinnerc656e252019-03-06 01:13:43 +0100868
869 If the memory allocator is changed, config is re-allocated with new
Victor Stinner4fffd382019-03-06 01:44:31 +0100870 allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
871
872 Do nothing if called after Py_Initialize(): ignore the new
873 pre-configuration. */
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100874_PyInitError
Victor Stinnerc656e252019-03-06 01:13:43 +0100875_PyPreConfig_Write(_PyPreConfig *config)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100876{
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100877 if (_PyRuntime.core_initialized) {
Victor Stinner4fffd382019-03-06 01:44:31 +0100878 /* bpo-34008: Calling this functions after Py_Initialize() ignores
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100879 the new configuration. */
Victor Stinnerc656e252019-03-06 01:13:43 +0100880 return _Py_INIT_OK();
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100881 }
882
883 if (config->allocator != NULL) {
Victor Stinnerc656e252019-03-06 01:13:43 +0100884 _PyInitError err = _PyPreConfig_SetAllocator(config);
885 if (_Py_INIT_FAILED(err)) {
886 return err;
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100887 }
888 }
889
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100890 _PyPreConfig_SetGlobalConfig(config);
891
892 if (config->coerce_c_locale) {
893 _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
894 }
895
896 /* Set LC_CTYPE to the user preferred locale */
897 _Py_SetLocaleFromEnv(LC_CTYPE);
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100898
Victor Stinner6d5ee972019-03-23 12:05:43 +0100899 /* Write the new pre-configuration into _PyRuntime */
900 PyMemAllocatorEx old_alloc;
901 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
902 int res = _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
903 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
904 if (res < 0) {
905 return _Py_INIT_NO_MEMORY();
906 }
907
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100908 return _Py_INIT_OK();
Victor Stinner6dcb5422019-03-05 02:44:12 +0100909}