blob: 2bbf8e6fb7fb4040af49403ae67591f40ff427aa [file] [log] [blame]
Victor Stinner91b9ecf2019-03-01 17:52:56 +01001#include "Python.h"
2#include "pycore_coreconfig.h"
Victor Stinner6dcb5422019-03-05 02:44:12 +01003#include "pycore_getopt.h"
Victor Stinner5a02e0d2019-03-05 12:32:09 +01004#include "pycore_pystate.h" /* _PyRuntime_Initialize() */
5#include <locale.h> /* setlocale() */
Victor Stinner91b9ecf2019-03-01 17:52:56 +01006
7
8#define DECODE_LOCALE_ERR(NAME, LEN) \
9 (((LEN) == -2) \
Victor Stinnerdb719752019-05-01 05:35:33 +020010 ? _Py_INIT_ERR("cannot decode " NAME) \
Victor Stinner91b9ecf2019-03-01 17:52:56 +010011 : _Py_INIT_NO_MEMORY())
12
13
14/* --- File system encoding/errors -------------------------------- */
15
16/* The filesystem encoding is chosen by config_init_fs_encoding(),
Victor Stinner709d23d2019-05-02 14:56:30 -040017 see also initfsencoding().
18
19 Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
20 are encoded to UTF-8. */
Victor Stinner91b9ecf2019-03-01 17:52:56 +010021const char *Py_FileSystemDefaultEncoding = NULL;
22int Py_HasFileSystemDefaultEncoding = 0;
23const char *Py_FileSystemDefaultEncodeErrors = NULL;
24int _Py_HasFileSystemDefaultEncodeErrors = 0;
25
26void
27_Py_ClearFileSystemEncoding(void)
28{
29 if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) {
30 PyMem_RawFree((char*)Py_FileSystemDefaultEncoding);
31 Py_FileSystemDefaultEncoding = NULL;
32 }
33 if (!_Py_HasFileSystemDefaultEncodeErrors && Py_FileSystemDefaultEncodeErrors) {
34 PyMem_RawFree((char*)Py_FileSystemDefaultEncodeErrors);
35 Py_FileSystemDefaultEncodeErrors = NULL;
36 }
37}
38
39
40/* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
41 global configuration variables. */
42int
43_Py_SetFileSystemEncoding(const char *encoding, const char *errors)
44{
45 char *encoding2 = _PyMem_RawStrdup(encoding);
46 if (encoding2 == NULL) {
47 return -1;
48 }
49
50 char *errors2 = _PyMem_RawStrdup(errors);
51 if (errors2 == NULL) {
52 PyMem_RawFree(encoding2);
53 return -1;
54 }
55
56 _Py_ClearFileSystemEncoding();
57
58 Py_FileSystemDefaultEncoding = encoding2;
59 Py_HasFileSystemDefaultEncoding = 0;
60
61 Py_FileSystemDefaultEncodeErrors = errors2;
62 _Py_HasFileSystemDefaultEncodeErrors = 0;
63 return 0;
64}
65
66
67/* --- _PyArgv ---------------------------------------------------- */
68
Victor Stinnerf8ba6f52019-03-26 16:58:50 +010069/* Decode bytes_argv using Py_DecodeLocale() */
Victor Stinner91b9ecf2019-03-01 17:52:56 +010070_PyInitError
Victor Stinner74f65682019-03-15 15:08:05 +010071_PyArgv_AsWstrList(const _PyArgv *args, _PyWstrList *list)
Victor Stinner91b9ecf2019-03-01 17:52:56 +010072{
Victor Stinner74f65682019-03-15 15:08:05 +010073 _PyWstrList wargv = _PyWstrList_INIT;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010074 if (args->use_bytes_argv) {
Victor Stinner74f65682019-03-15 15:08:05 +010075 size_t size = sizeof(wchar_t*) * args->argc;
76 wargv.items = (wchar_t **)PyMem_RawMalloc(size);
77 if (wargv.items == NULL) {
Victor Stinner91b9ecf2019-03-01 17:52:56 +010078 return _Py_INIT_NO_MEMORY();
79 }
80
Victor Stinner74f65682019-03-15 15:08:05 +010081 for (Py_ssize_t i = 0; i < args->argc; i++) {
Victor Stinner91b9ecf2019-03-01 17:52:56 +010082 size_t len;
83 wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
84 if (arg == NULL) {
Victor Stinner74f65682019-03-15 15:08:05 +010085 _PyWstrList_Clear(&wargv);
Victor Stinner91b9ecf2019-03-01 17:52:56 +010086 return DECODE_LOCALE_ERR("command line arguments",
87 (Py_ssize_t)len);
88 }
Victor Stinner74f65682019-03-15 15:08:05 +010089 wargv.items[i] = arg;
90 wargv.length++;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010091 }
Victor Stinner74f65682019-03-15 15:08:05 +010092
93 _PyWstrList_Clear(list);
94 *list = wargv;
Victor Stinner91b9ecf2019-03-01 17:52:56 +010095 }
96 else {
Victor Stinner74f65682019-03-15 15:08:05 +010097 wargv.length = args->argc;
98 wargv.items = args->wchar_argv;
99 if (_PyWstrList_Copy(list, &wargv) < 0) {
100 return _Py_INIT_NO_MEMORY();
101 }
Victor Stinner91b9ecf2019-03-01 17:52:56 +0100102 }
Victor Stinner91b9ecf2019-03-01 17:52:56 +0100103 return _Py_INIT_OK();
104}
Victor Stinnercad1f742019-03-05 02:01:27 +0100105
106
Victor Stinner6dcb5422019-03-05 02:44:12 +0100107/* --- _PyPreCmdline ------------------------------------------------- */
108
Victor Stinnerfa153762019-03-20 04:25:38 +0100109void
110_PyPreCmdline_Clear(_PyPreCmdline *cmdline)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100111{
Victor Stinner74f65682019-03-15 15:08:05 +0100112 _PyWstrList_Clear(&cmdline->argv);
113 _PyWstrList_Clear(&cmdline->xoptions);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100114}
115
116
Victor Stinnerfa153762019-03-20 04:25:38 +0100117_PyInitError
Victor Stinnerf72346c2019-03-25 17:54:58 +0100118_PyPreCmdline_SetArgv(_PyPreCmdline *cmdline, const _PyArgv *args)
Victor Stinnerfa153762019-03-20 04:25:38 +0100119{
120 return _PyArgv_AsWstrList(args, &cmdline->argv);
121}
122
123
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100124static void
Victor Stinnerf72346c2019-03-25 17:54:58 +0100125_PyPreCmdline_GetPreConfig(_PyPreCmdline *cmdline, const _PyPreConfig *config)
126{
127#define COPY_ATTR(ATTR) \
128 if (config->ATTR != -1) { \
129 cmdline->ATTR = config->ATTR; \
130 }
131
Victor Stinnerf72346c2019-03-25 17:54:58 +0100132 COPY_ATTR(isolated);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100133 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100134 COPY_ATTR(dev_mode);
135
136#undef COPY_ATTR
137}
138
139
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100140static void
Victor Stinner20004952019-03-26 02:31:11 +0100141_PyPreCmdline_SetPreConfig(const _PyPreCmdline *cmdline, _PyPreConfig *config)
142{
143#define COPY_ATTR(ATTR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100144 config->ATTR = cmdline->ATTR
Victor Stinner20004952019-03-26 02:31:11 +0100145
Victor Stinner20004952019-03-26 02:31:11 +0100146 COPY_ATTR(isolated);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100147 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100148 COPY_ATTR(dev_mode);
Victor Stinnerf72346c2019-03-25 17:54:58 +0100149
150#undef COPY_ATTR
151}
152
153
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100154int
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100155_PyPreCmdline_SetCoreConfig(const _PyPreCmdline *cmdline, _PyCoreConfig *config)
156{
157#define COPY_ATTR(ATTR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100158 config->ATTR = cmdline->ATTR
159
160 if (_PyWstrList_Extend(&config->xoptions, &cmdline->xoptions) < 0) {
161 return -1;
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100162 }
163
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100164 COPY_ATTR(isolated);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100165 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100166 COPY_ATTR(dev_mode);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100167 return 0;
Victor Stinnera6fbc4e2019-03-25 18:37:10 +0100168
169#undef COPY_ATTR
170}
171
172
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100173/* Parse the command line arguments */
174static _PyInitError
175precmdline_parse_cmdline(_PyPreCmdline *cmdline)
176{
Victor Stinner870b0352019-05-17 03:15:12 +0200177 const _PyWstrList *argv = &cmdline->argv;
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100178
179 _PyOS_ResetGetOpt();
180 /* Don't log parsing errors into stderr here: _PyCoreConfig_Read()
181 is responsible for that */
182 _PyOS_opterr = 0;
183 do {
184 int longindex = -1;
185 int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
186
187 if (c == EOF || c == 'c' || c == 'm') {
188 break;
189 }
190
191 switch (c) {
192 case 'E':
193 cmdline->use_environment = 0;
194 break;
195
196 case 'I':
197 cmdline->isolated = 1;
198 break;
199
200 case 'X':
201 {
202 if (_PyWstrList_Append(&cmdline->xoptions, _PyOS_optarg) < 0) {
203 return _Py_INIT_NO_MEMORY();
204 }
205 break;
206 }
207
208 default:
209 /* ignore other argument:
210 handled by _PyCoreConfig_Read() */
211 break;
212 }
213 } while (1);
214
215 return _Py_INIT_OK();
216}
217
218
219_PyInitError
220_PyPreCmdline_Read(_PyPreCmdline *cmdline,
Victor Stinner5ac27a52019-03-27 13:40:14 +0100221 const _PyPreConfig *preconfig)
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100222{
223 if (preconfig) {
224 _PyPreCmdline_GetPreConfig(cmdline, preconfig);
225 }
226
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100227 _PyInitError err = precmdline_parse_cmdline(cmdline);
228 if (_Py_INIT_FAILED(err)) {
229 return err;
230 }
231
232 /* isolated, use_environment */
233 if (cmdline->isolated < 0) {
234 cmdline->isolated = 0;
235 }
236 if (cmdline->isolated > 0) {
237 cmdline->use_environment = 0;
238 }
239 if (cmdline->use_environment < 0) {
240 cmdline->use_environment = 0;
241 }
242
243 /* dev_mode */
244 if ((cmdline && _Py_get_xoption(&cmdline->xoptions, L"dev"))
245 || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE"))
246 {
247 cmdline->dev_mode = 1;
248 }
249 if (cmdline->dev_mode < 0) {
250 cmdline->dev_mode = 0;
251 }
252
253 assert(cmdline->use_environment >= 0);
254 assert(cmdline->isolated >= 0);
255 assert(cmdline->dev_mode >= 0);
256
257 return _Py_INIT_OK();
258}
259
260
Victor Stinnercad1f742019-03-05 02:01:27 +0100261/* --- _PyPreConfig ----------------------------------------------- */
262
Victor Stinnercad1f742019-03-05 02:01:27 +0100263int
264_PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
265{
Victor Stinnercad1f742019-03-05 02:01:27 +0100266#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100267#define COPY_STR_ATTR(ATTR) \
268 do { \
269 if (config2->ATTR != NULL) { \
270 config->ATTR = _PyMem_RawStrdup(config2->ATTR); \
271 if (config->ATTR == NULL) { \
272 return -1; \
273 } \
274 } \
275 } while (0)
Victor Stinnercad1f742019-03-05 02:01:27 +0100276
277 COPY_ATTR(isolated);
278 COPY_ATTR(use_environment);
Victor Stinner20004952019-03-26 02:31:11 +0100279 COPY_ATTR(dev_mode);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100280 COPY_ATTR(coerce_c_locale);
281 COPY_ATTR(coerce_c_locale_warn);
282#ifdef MS_WINDOWS
283 COPY_ATTR(legacy_windows_fs_encoding);
284#endif
285 COPY_ATTR(utf8_mode);
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200286 COPY_ATTR(allocator);
Victor Stinnercad1f742019-03-05 02:01:27 +0100287
288#undef COPY_ATTR
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100289#undef COPY_STR_ATTR
Victor Stinnercad1f742019-03-05 02:01:27 +0100290 return 0;
291}
292
293
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100294PyObject*
295_PyPreConfig_AsDict(const _PyPreConfig *config)
296{
297 PyObject *dict;
298
299 dict = PyDict_New();
300 if (dict == NULL) {
301 return NULL;
302 }
303
304#define SET_ITEM(KEY, EXPR) \
305 do { \
306 PyObject *obj = (EXPR); \
307 if (obj == NULL) { \
308 goto fail; \
309 } \
310 int res = PyDict_SetItemString(dict, (KEY), obj); \
311 Py_DECREF(obj); \
312 if (res < 0) { \
313 goto fail; \
314 } \
315 } while (0)
316#define SET_ITEM_INT(ATTR) \
317 SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
318#define FROM_STRING(STR) \
319 ((STR != NULL) ? \
320 PyUnicode_FromString(STR) \
321 : (Py_INCREF(Py_None), Py_None))
322#define SET_ITEM_STR(ATTR) \
323 SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
324
325 SET_ITEM_INT(isolated);
326 SET_ITEM_INT(use_environment);
327 SET_ITEM_INT(coerce_c_locale);
328 SET_ITEM_INT(coerce_c_locale_warn);
329 SET_ITEM_INT(utf8_mode);
330#ifdef MS_WINDOWS
331 SET_ITEM_INT(legacy_windows_fs_encoding);
332#endif
333 SET_ITEM_INT(dev_mode);
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200334 SET_ITEM_INT(allocator);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100335 return dict;
336
337fail:
338 Py_DECREF(dict);
339 return NULL;
340
341#undef FROM_STRING
342#undef SET_ITEM
343#undef SET_ITEM_INT
344#undef SET_ITEM_STR
345}
346
347
Victor Stinner5ac27a52019-03-27 13:40:14 +0100348void
349_PyCoreConfig_GetCoreConfig(_PyPreConfig *config,
350 const _PyCoreConfig *core_config)
351{
352#define COPY_ATTR(ATTR) \
353 if (core_config->ATTR != -1) { \
354 config->ATTR = core_config->ATTR; \
355 }
356
357 COPY_ATTR(isolated);
358 COPY_ATTR(use_environment);
359 COPY_ATTR(dev_mode);
360
361#undef COPY_ATTR
362}
363
364
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100365static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100366_PyPreConfig_GetGlobalConfig(_PyPreConfig *config)
367{
368#define COPY_FLAG(ATTR, VALUE) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100369 if (config->ATTR == -1) { \
370 config->ATTR = VALUE; \
371 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100372#define COPY_NOT_FLAG(ATTR, VALUE) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100373 if (config->ATTR == -1) { \
374 config->ATTR = !(VALUE); \
375 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100376
377 COPY_FLAG(isolated, Py_IsolatedFlag);
378 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100379#ifdef MS_WINDOWS
380 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
381#endif
Victor Stinnerd929f182019-03-27 18:28:46 +0100382 if (Py_UTF8Mode > 0) {
383 config->utf8_mode = 1;
384 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100385
386#undef COPY_FLAG
387#undef COPY_NOT_FLAG
388}
389
390
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100391static void
Victor Stinnercad1f742019-03-05 02:01:27 +0100392_PyPreConfig_SetGlobalConfig(const _PyPreConfig *config)
393{
394#define COPY_FLAG(ATTR, VAR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100395 if (config->ATTR != -1) { \
396 VAR = config->ATTR; \
397 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100398#define COPY_NOT_FLAG(ATTR, VAR) \
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100399 if (config->ATTR != -1) { \
400 VAR = !config->ATTR; \
401 }
Victor Stinnercad1f742019-03-05 02:01:27 +0100402
403 COPY_FLAG(isolated, Py_IsolatedFlag);
404 COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100405#ifdef MS_WINDOWS
406 COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
407#endif
408 COPY_FLAG(utf8_mode, Py_UTF8Mode);
Victor Stinnercad1f742019-03-05 02:01:27 +0100409
410#undef COPY_FLAG
411#undef COPY_NOT_FLAG
412}
413
414
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100415const char*
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100416_Py_GetEnv(int use_environment, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100417{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100418 assert(use_environment >= 0);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100419
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100420 if (!use_environment) {
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100421 return NULL;
422 }
423
424 const char *var = getenv(name);
425 if (var && var[0] != '\0') {
426 return var;
427 }
428 else {
429 return NULL;
430 }
431}
432
433
434int
435_Py_str_to_int(const char *str, int *result)
436{
437 const char *endptr = str;
438 errno = 0;
439 long value = strtol(str, (char **)&endptr, 10);
440 if (*endptr != '\0' || errno == ERANGE) {
441 return -1;
442 }
443 if (value < INT_MIN || value > INT_MAX) {
444 return -1;
445 }
446
447 *result = (int)value;
448 return 0;
449}
450
451
452void
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100453_Py_get_env_flag(int use_environment, int *flag, const char *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100454{
Victor Stinnerf78a5e92019-03-26 00:03:15 +0100455 const char *var = _Py_GetEnv(use_environment, name);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100456 if (!var) {
457 return;
458 }
459 int value;
460 if (_Py_str_to_int(var, &value) < 0 || value < 0) {
461 /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
462 value = 1;
463 }
464 if (*flag < value) {
465 *flag = value;
466 }
467}
468
469
470const wchar_t*
Victor Stinner74f65682019-03-15 15:08:05 +0100471_Py_get_xoption(const _PyWstrList *xoptions, const wchar_t *name)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100472{
Victor Stinner74f65682019-03-15 15:08:05 +0100473 for (Py_ssize_t i=0; i < xoptions->length; i++) {
474 const wchar_t *option = xoptions->items[i];
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100475 size_t len;
476 wchar_t *sep = wcschr(option, L'=');
477 if (sep != NULL) {
478 len = (sep - option);
479 }
480 else {
481 len = wcslen(option);
482 }
483 if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
484 return option;
485 }
486 }
487 return NULL;
488}
489
490
491static _PyInitError
492preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
493{
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100494#ifdef MS_WINDOWS
495 if (config->legacy_windows_fs_encoding) {
496 config->utf8_mode = 0;
497 }
498#endif
499
500 if (config->utf8_mode >= 0) {
501 return _Py_INIT_OK();
502 }
503
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100504 const wchar_t *xopt;
505 if (cmdline) {
Victor Stinner74f65682019-03-15 15:08:05 +0100506 xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100507 }
508 else {
509 xopt = NULL;
510 }
511 if (xopt) {
512 wchar_t *sep = wcschr(xopt, L'=');
513 if (sep) {
514 xopt = sep + 1;
515 if (wcscmp(xopt, L"1") == 0) {
516 config->utf8_mode = 1;
517 }
518 else if (wcscmp(xopt, L"0") == 0) {
519 config->utf8_mode = 0;
520 }
521 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200522 return _Py_INIT_ERR("invalid -X utf8 option value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100523 }
524 }
525 else {
526 config->utf8_mode = 1;
527 }
528 return _Py_INIT_OK();
529 }
530
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100531 const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100532 if (opt) {
533 if (strcmp(opt, "1") == 0) {
534 config->utf8_mode = 1;
535 }
536 else if (strcmp(opt, "0") == 0) {
537 config->utf8_mode = 0;
538 }
539 else {
Victor Stinnerdb719752019-05-01 05:35:33 +0200540 return _Py_INIT_ERR("invalid PYTHONUTF8 environment "
541 "variable value");
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100542 }
543 return _Py_INIT_OK();
544 }
545
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100546
547#ifndef MS_WINDOWS
548 if (config->utf8_mode < 0) {
549 /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
550 const char *ctype_loc = setlocale(LC_CTYPE, NULL);
551 if (ctype_loc != NULL
552 && (strcmp(ctype_loc, "C") == 0
553 || strcmp(ctype_loc, "POSIX") == 0))
554 {
555 config->utf8_mode = 1;
556 }
557 }
558#endif
559
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100560 if (config->utf8_mode < 0) {
561 config->utf8_mode = 0;
562 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100563 return _Py_INIT_OK();
564}
565
566
567static void
568preconfig_init_coerce_c_locale(_PyPreConfig *config)
569{
570 const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
571 if (env) {
572 if (strcmp(env, "0") == 0) {
573 if (config->coerce_c_locale < 0) {
574 config->coerce_c_locale = 0;
575 }
576 }
577 else if (strcmp(env, "warn") == 0) {
578 config->coerce_c_locale_warn = 1;
579 }
580 else {
581 if (config->coerce_c_locale < 0) {
582 config->coerce_c_locale = 1;
583 }
584 }
585 }
586
587 /* Test if coerce_c_locale equals to -1 or equals to 1:
588 PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.
589 It is only coerced if if the LC_CTYPE locale is "C". */
590 if (config->coerce_c_locale == 0 || config->coerce_c_locale == 2) {
591 return;
592 }
593
594 /* The C locale enables the C locale coercion (PEP 538) */
595 if (_Py_LegacyLocaleDetected()) {
596 config->coerce_c_locale = 2;
597 }
598 else {
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100599 config->coerce_c_locale = 0;
600 }
601
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100602 assert(config->coerce_c_locale >= 0);
603}
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100604
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100605
606static _PyInitError
607preconfig_init_allocator(_PyPreConfig *config)
608{
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200609 if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
Victor Stinner25d13f32019-03-06 12:51:53 +0100610 /* bpo-34247. The PYTHONMALLOC environment variable has the priority
611 over PYTHONDEV env var and "-X dev" command line option.
612 For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
613 allocators to "malloc" (and not to "debug"). */
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200614 const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
615 if (envvar) {
616 if (_PyMem_GetAllocatorName(envvar, &config->allocator) < 0) {
617 return _Py_INIT_ERR("PYTHONMALLOC: unknown allocator");
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100618 }
619 }
620 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100621
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200622 if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
623 config->allocator = PYMEM_ALLOCATOR_DEBUG;
Victor Stinner25d13f32019-03-06 12:51:53 +0100624 }
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100625 return _Py_INIT_OK();
626}
627
628
629static _PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100630preconfig_read(_PyPreConfig *config, _PyPreCmdline *cmdline)
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100631{
632 _PyInitError err;
633
Victor Stinner5ac27a52019-03-27 13:40:14 +0100634 err = _PyPreCmdline_Read(cmdline, config);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100635 if (_Py_INIT_FAILED(err)) {
636 return err;
637 }
638
639 _PyPreCmdline_SetPreConfig(cmdline, config);
640
641 /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */
642#ifdef MS_WINDOWS
643 _Py_get_env_flag(config->use_environment,
644 &config->legacy_windows_fs_encoding,
645 "PYTHONLEGACYWINDOWSFSENCODING");
646#endif
647
648 preconfig_init_coerce_c_locale(config);
649
650 err = preconfig_init_utf8_mode(config, cmdline);
651 if (_Py_INIT_FAILED(err)) {
652 return err;
653 }
654
655 /* allocator */
656 err = preconfig_init_allocator(config);
657 if (_Py_INIT_FAILED(err)) {
658 return err;
659 }
Victor Stinner25d13f32019-03-06 12:51:53 +0100660
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100661 assert(config->coerce_c_locale >= 0);
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100662#ifdef MS_WINDOWS
663 assert(config->legacy_windows_fs_encoding >= 0);
664#endif
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100665 assert(config->utf8_mode >= 0);
Victor Stinner6dcb5422019-03-05 02:44:12 +0100666 assert(config->isolated >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100667 assert(config->use_environment >= 0);
Victor Stinnerb35be4b2019-03-05 17:37:44 +0100668 assert(config->dev_mode >= 0);
Victor Stinnercad1f742019-03-05 02:01:27 +0100669
670 return _Py_INIT_OK();
671}
672
673
Victor Stinner4fffd382019-03-06 01:44:31 +0100674/* Read the configuration from:
675
676 - command line arguments
677 - environment variables
678 - Py_xxx global configuration variables
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100679 - the LC_CTYPE locale */
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100680_PyInitError
Victor Stinner5ac27a52019-03-27 13:40:14 +0100681_PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100682{
683 _PyInitError err;
684
685 err = _PyRuntime_Initialize();
686 if (_Py_INIT_FAILED(err)) {
687 return err;
688 }
689
Victor Stinnerf29084d2019-03-20 02:20:13 +0100690 _PyPreConfig_GetGlobalConfig(config);
691
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100692 /* Copy LC_CTYPE locale, since it's modified later */
693 const char *loc = setlocale(LC_CTYPE, NULL);
694 if (loc == NULL) {
695 return _Py_INIT_ERR("failed to LC_CTYPE locale");
696 }
697 char *init_ctype_locale = _PyMem_RawStrdup(loc);
698 if (init_ctype_locale == NULL) {
699 return _Py_INIT_NO_MEMORY();
700 }
701
702 /* Save the config to be able to restore it if encodings change */
703 _PyPreConfig save_config = _PyPreConfig_INIT;
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100704 if (_PyPreConfig_Copy(&save_config, config) < 0) {
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100705 return _Py_INIT_NO_MEMORY();
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100706 }
707
708 /* Set LC_CTYPE to the user preferred locale */
709 _Py_SetLocaleFromEnv(LC_CTYPE);
710
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100711 _PyPreCmdline cmdline = _PyPreCmdline_INIT;
Victor Stinner6a8c3132019-04-05 11:44:04 +0200712 int init_utf8_mode = Py_UTF8Mode;
713#ifdef MS_WINDOWS
714 int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
715#endif
716
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100717 if (args) {
718 err = _PyPreCmdline_SetArgv(&cmdline, args);
719 if (_Py_INIT_FAILED(err)) {
720 goto done;
721 }
722 }
723
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100724 int locale_coerced = 0;
725 int loops = 0;
726
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100727 while (1) {
728 int utf8_mode = config->utf8_mode;
729
730 /* Watchdog to prevent an infinite loop */
731 loops++;
732 if (loops == 3) {
733 err = _Py_INIT_ERR("Encoding changed twice while "
734 "reading the configuration");
735 goto done;
736 }
737
738 /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend
739 on Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */
740 Py_UTF8Mode = config->utf8_mode;
741#ifdef MS_WINDOWS
742 Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
743#endif
744
Victor Stinner5ac27a52019-03-27 13:40:14 +0100745 err = preconfig_read(config, &cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100746 if (_Py_INIT_FAILED(err)) {
747 goto done;
748 }
749
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100750 /* The legacy C locale assumes ASCII as the default text encoding, which
751 * causes problems not only for the CPython runtime, but also other
752 * components like GNU readline.
753 *
754 * Accordingly, when the CLI detects it, it attempts to coerce it to a
755 * more capable UTF-8 based alternative.
756 *
757 * See the documentation of the PYTHONCOERCECLOCALE setting for more
758 * details.
759 */
760 int encoding_changed = 0;
761 if (config->coerce_c_locale && !locale_coerced) {
762 locale_coerced = 1;
763 _Py_CoerceLegacyLocale(0);
764 encoding_changed = 1;
765 }
766
767 if (utf8_mode == -1) {
768 if (config->utf8_mode == 1) {
769 /* UTF-8 Mode enabled */
770 encoding_changed = 1;
771 }
772 }
773 else {
774 if (config->utf8_mode != utf8_mode) {
775 encoding_changed = 1;
776 }
777 }
778
779 if (!encoding_changed) {
780 break;
781 }
782
783 /* Reset the configuration before reading again the configuration,
784 just keep UTF-8 Mode value. */
785 int new_utf8_mode = config->utf8_mode;
786 int new_coerce_c_locale = config->coerce_c_locale;
787 if (_PyPreConfig_Copy(config, &save_config) < 0) {
788 err = _Py_INIT_NO_MEMORY();
789 goto done;
790 }
791 config->utf8_mode = new_utf8_mode;
792 config->coerce_c_locale = new_coerce_c_locale;
793
794 /* The encoding changed: read again the configuration
795 with the new encoding */
796 }
797 err = _Py_INIT_OK();
798
799done:
800 if (init_ctype_locale != NULL) {
801 setlocale(LC_CTYPE, init_ctype_locale);
Victor Stinnerc1834442019-03-18 22:24:28 +0100802 PyMem_RawFree(init_ctype_locale);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100803 }
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100804 Py_UTF8Mode = init_utf8_mode ;
805#ifdef MS_WINDOWS
806 Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
807#endif
Victor Stinnerf8ba6f52019-03-26 16:58:50 +0100808 _PyPreCmdline_Clear(&cmdline);
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100809 return err;
810}
811
812
Victor Stinner4fffd382019-03-06 01:44:31 +0100813/* Write the pre-configuration:
814
815 - set the memory allocators
816 - set Py_xxx global configuration variables
817 - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
818 (PEP 540)
Victor Stinnerc656e252019-03-06 01:13:43 +0100819
820 If the memory allocator is changed, config is re-allocated with new
Victor Stinner4fffd382019-03-06 01:44:31 +0100821 allocator. So calling _PyPreConfig_Clear(config) is safe after this call.
822
823 Do nothing if called after Py_Initialize(): ignore the new
824 pre-configuration. */
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100825_PyInitError
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200826_PyPreConfig_Write(const _PyPreConfig *config)
Victor Stinner6dcb5422019-03-05 02:44:12 +0100827{
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100828 if (_PyRuntime.core_initialized) {
Victor Stinner4fffd382019-03-06 01:44:31 +0100829 /* bpo-34008: Calling this functions after Py_Initialize() ignores
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100830 the new configuration. */
Victor Stinnerc656e252019-03-06 01:13:43 +0100831 return _Py_INIT_OK();
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100832 }
833
Victor Stinnerb16b4e42019-05-17 15:20:52 +0200834 if (config->allocator != PYMEM_ALLOCATOR_NOT_SET) {
835 if (_PyMem_SetupAllocators(config->allocator) < 0) {
836 return _Py_INIT_ERR("Unknown PYTHONMALLOC allocator");
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100837 }
838 }
839
Victor Stinner5a02e0d2019-03-05 12:32:09 +0100840 _PyPreConfig_SetGlobalConfig(config);
841
842 if (config->coerce_c_locale) {
843 _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
844 }
845
846 /* Set LC_CTYPE to the user preferred locale */
847 _Py_SetLocaleFromEnv(LC_CTYPE);
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100848
Victor Stinner6d5ee972019-03-23 12:05:43 +0100849 /* Write the new pre-configuration into _PyRuntime */
850 PyMemAllocatorEx old_alloc;
851 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
852 int res = _PyPreConfig_Copy(&_PyRuntime.preconfig, config);
853 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
854 if (res < 0) {
855 return _Py_INIT_NO_MEMORY();
856 }
857
Victor Stinner7d2ef3e2019-03-06 00:36:56 +0100858 return _Py_INIT_OK();
Victor Stinner6dcb5422019-03-05 02:44:12 +0100859}