123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- #include "Python.h"
- #include "pycore_fileutils.h" // DECODE_LOCALE_ERR
- #include "pycore_getopt.h" // _PyOS_GetOpt()
- #include "pycore_initconfig.h" // _PyArgv
- #include "pycore_pymem.h" // _PyMem_GetAllocatorName()
- #include "pycore_runtime.h" // _PyRuntime_Initialize()
- #include <locale.h> // setlocale()
- #include <stdlib.h> // getenv()
- /* Forward declarations */
- static void
- preconfig_copy(PyPreConfig *config, const PyPreConfig *config2);
- /* --- File system encoding/errors -------------------------------- */
- const char *Py_FileSystemDefaultEncoding = NULL;
- int Py_HasFileSystemDefaultEncoding = 0;
- const char *Py_FileSystemDefaultEncodeErrors = NULL;
- int _Py_HasFileSystemDefaultEncodeErrors = 0;
- void
- _Py_ClearFileSystemEncoding(void)
- {
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
- if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) {
- PyMem_RawFree((char*)Py_FileSystemDefaultEncoding);
- Py_FileSystemDefaultEncoding = NULL;
- }
- if (!_Py_HasFileSystemDefaultEncodeErrors && Py_FileSystemDefaultEncodeErrors) {
- PyMem_RawFree((char*)Py_FileSystemDefaultEncodeErrors);
- Py_FileSystemDefaultEncodeErrors = NULL;
- }
- _Py_COMP_DIAG_POP
- }
- /* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
- global configuration variables to PyConfig.filesystem_encoding and
- PyConfig.filesystem_errors (encoded to UTF-8).
- Function called by _PyUnicode_InitEncodings(). */
- int
- _Py_SetFileSystemEncoding(const char *encoding, const char *errors)
- {
- char *encoding2 = _PyMem_RawStrdup(encoding);
- if (encoding2 == NULL) {
- return -1;
- }
- char *errors2 = _PyMem_RawStrdup(errors);
- if (errors2 == NULL) {
- PyMem_RawFree(encoding2);
- return -1;
- }
- _Py_ClearFileSystemEncoding();
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
- Py_FileSystemDefaultEncoding = encoding2;
- Py_HasFileSystemDefaultEncoding = 0;
- Py_FileSystemDefaultEncodeErrors = errors2;
- _Py_HasFileSystemDefaultEncodeErrors = 0;
- _Py_COMP_DIAG_POP
- return 0;
- }
- /* --- _PyArgv ---------------------------------------------------- */
- /* Decode bytes_argv using Py_DecodeLocale() */
- PyStatus
- _PyArgv_AsWstrList(const _PyArgv *args, PyWideStringList *list)
- {
- PyWideStringList wargv = _PyWideStringList_INIT;
- if (args->use_bytes_argv) {
- size_t size = sizeof(wchar_t*) * args->argc;
- wargv.items = (wchar_t **)PyMem_RawMalloc(size);
- if (wargv.items == NULL) {
- return _PyStatus_NO_MEMORY();
- }
- for (Py_ssize_t i = 0; i < args->argc; i++) {
- size_t len;
- wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
- if (arg == NULL) {
- _PyWideStringList_Clear(&wargv);
- return DECODE_LOCALE_ERR("command line arguments", len);
- }
- wargv.items[i] = arg;
- wargv.length++;
- }
- _PyWideStringList_Clear(list);
- *list = wargv;
- }
- else {
- wargv.length = args->argc;
- wargv.items = (wchar_t **)args->wchar_argv;
- if (_PyWideStringList_Copy(list, &wargv) < 0) {
- return _PyStatus_NO_MEMORY();
- }
- }
- return _PyStatus_OK();
- }
- /* --- _PyPreCmdline ------------------------------------------------- */
- void
- _PyPreCmdline_Clear(_PyPreCmdline *cmdline)
- {
- _PyWideStringList_Clear(&cmdline->argv);
- _PyWideStringList_Clear(&cmdline->xoptions);
- }
- PyStatus
- _PyPreCmdline_SetArgv(_PyPreCmdline *cmdline, const _PyArgv *args)
- {
- return _PyArgv_AsWstrList(args, &cmdline->argv);
- }
- static void
- precmdline_get_preconfig(_PyPreCmdline *cmdline, const PyPreConfig *config)
- {
- #define COPY_ATTR(ATTR) \
- if (config->ATTR != -1) { \
- cmdline->ATTR = config->ATTR; \
- }
- COPY_ATTR(isolated);
- COPY_ATTR(use_environment);
- COPY_ATTR(dev_mode);
- #undef COPY_ATTR
- }
- static void
- precmdline_set_preconfig(const _PyPreCmdline *cmdline, PyPreConfig *config)
- {
- #define COPY_ATTR(ATTR) \
- config->ATTR = cmdline->ATTR
- COPY_ATTR(isolated);
- COPY_ATTR(use_environment);
- COPY_ATTR(dev_mode);
- #undef COPY_ATTR
- }
- PyStatus
- _PyPreCmdline_SetConfig(const _PyPreCmdline *cmdline, PyConfig *config)
- {
- #define COPY_ATTR(ATTR) \
- config->ATTR = cmdline->ATTR
- PyStatus status = _PyWideStringList_Extend(&config->xoptions, &cmdline->xoptions);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- COPY_ATTR(isolated);
- COPY_ATTR(use_environment);
- COPY_ATTR(dev_mode);
- COPY_ATTR(warn_default_encoding);
- return _PyStatus_OK();
- #undef COPY_ATTR
- }
- /* Parse the command line arguments */
- static PyStatus
- precmdline_parse_cmdline(_PyPreCmdline *cmdline)
- {
- const PyWideStringList *argv = &cmdline->argv;
- _PyOS_ResetGetOpt();
- /* Don't log parsing errors into stderr here: PyConfig_Read()
- is responsible for that */
- _PyOS_opterr = 0;
- do {
- int longindex = -1;
- int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
- if (c == EOF || c == 'c' || c == 'm') {
- break;
- }
- switch (c) {
- case 'E':
- cmdline->use_environment = 0;
- break;
- case 'I':
- cmdline->isolated = 1;
- break;
- case 'X':
- {
- PyStatus status = PyWideStringList_Append(&cmdline->xoptions,
- _PyOS_optarg);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- break;
- }
- default:
- /* ignore other argument:
- handled by PyConfig_Read() */
- break;
- }
- } while (1);
- return _PyStatus_OK();
- }
- PyStatus
- _PyPreCmdline_Read(_PyPreCmdline *cmdline, const PyPreConfig *preconfig)
- {
- precmdline_get_preconfig(cmdline, preconfig);
- if (preconfig->parse_argv) {
- PyStatus status = precmdline_parse_cmdline(cmdline);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- }
- /* isolated, use_environment */
- if (cmdline->isolated < 0) {
- cmdline->isolated = 0;
- }
- if (cmdline->isolated > 0) {
- cmdline->use_environment = 0;
- }
- if (cmdline->use_environment < 0) {
- cmdline->use_environment = 0;
- }
- /* dev_mode */
- if ((cmdline->dev_mode < 0)
- && (_Py_get_xoption(&cmdline->xoptions, L"dev")
- || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE")))
- {
- cmdline->dev_mode = 1;
- }
- if (cmdline->dev_mode < 0) {
- cmdline->dev_mode = 0;
- }
- // warn_default_encoding
- if (_Py_get_xoption(&cmdline->xoptions, L"warn_default_encoding")
- || _Py_GetEnv(cmdline->use_environment, "PYTHONWARNDEFAULTENCODING"))
- {
- cmdline->warn_default_encoding = 1;
- }
- assert(cmdline->use_environment >= 0);
- assert(cmdline->isolated >= 0);
- assert(cmdline->dev_mode >= 0);
- assert(cmdline->warn_default_encoding >= 0);
- return _PyStatus_OK();
- }
- /* --- PyPreConfig ----------------------------------------------- */
- void
- _PyPreConfig_InitCompatConfig(PyPreConfig *config)
- {
- memset(config, 0, sizeof(*config));
- config->_config_init = (int)_PyConfig_INIT_COMPAT;
- config->parse_argv = 0;
- config->isolated = -1;
- config->use_environment = -1;
- config->configure_locale = 1;
- /* bpo-36443: C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)
- are disabled by default using the Compat configuration.
- Py_UTF8Mode=1 enables the UTF-8 mode. PYTHONUTF8 environment variable
- is ignored (even if use_environment=1). */
- config->utf8_mode = 0;
- config->coerce_c_locale = 0;
- config->coerce_c_locale_warn = 0;
- config->dev_mode = -1;
- config->allocator = PYMEM_ALLOCATOR_NOT_SET;
- #ifdef MS_WINDOWS
- config->legacy_windows_fs_encoding = -1;
- #endif
- }
- void
- PyPreConfig_InitPythonConfig(PyPreConfig *config)
- {
- _PyPreConfig_InitCompatConfig(config);
- config->_config_init = (int)_PyConfig_INIT_PYTHON;
- config->isolated = 0;
- config->parse_argv = 1;
- config->use_environment = 1;
- /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540)
- depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE
- environment variables. */
- config->coerce_c_locale = -1;
- config->coerce_c_locale_warn = -1;
- config->utf8_mode = -1;
- #ifdef MS_WINDOWS
- config->legacy_windows_fs_encoding = 0;
- #endif
- }
- void
- PyPreConfig_InitIsolatedConfig(PyPreConfig *config)
- {
- _PyPreConfig_InitCompatConfig(config);
- config->_config_init = (int)_PyConfig_INIT_ISOLATED;
- config->configure_locale = 0;
- config->isolated = 1;
- config->use_environment = 0;
- config->utf8_mode = 0;
- config->dev_mode = 0;
- #ifdef MS_WINDOWS
- config->legacy_windows_fs_encoding = 0;
- #endif
- }
- PyStatus
- _PyPreConfig_InitFromPreConfig(PyPreConfig *config,
- const PyPreConfig *config2)
- {
- PyPreConfig_InitPythonConfig(config);
- preconfig_copy(config, config2);
- return _PyStatus_OK();
- }
- void
- _PyPreConfig_InitFromConfig(PyPreConfig *preconfig, const PyConfig *config)
- {
- _PyConfigInitEnum config_init = (_PyConfigInitEnum)config->_config_init;
- switch (config_init) {
- case _PyConfig_INIT_PYTHON:
- PyPreConfig_InitPythonConfig(preconfig);
- break;
- case _PyConfig_INIT_ISOLATED:
- PyPreConfig_InitIsolatedConfig(preconfig);
- break;
- case _PyConfig_INIT_COMPAT:
- default:
- _PyPreConfig_InitCompatConfig(preconfig);
- }
- _PyPreConfig_GetConfig(preconfig, config);
- }
- static void
- preconfig_copy(PyPreConfig *config, const PyPreConfig *config2)
- {
- #define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
- COPY_ATTR(_config_init);
- COPY_ATTR(parse_argv);
- COPY_ATTR(isolated);
- COPY_ATTR(use_environment);
- COPY_ATTR(configure_locale);
- COPY_ATTR(dev_mode);
- COPY_ATTR(coerce_c_locale);
- COPY_ATTR(coerce_c_locale_warn);
- COPY_ATTR(utf8_mode);
- COPY_ATTR(allocator);
- #ifdef MS_WINDOWS
- COPY_ATTR(legacy_windows_fs_encoding);
- #endif
- #undef COPY_ATTR
- }
- PyObject*
- _PyPreConfig_AsDict(const PyPreConfig *config)
- {
- PyObject *dict;
- dict = PyDict_New();
- if (dict == NULL) {
- return NULL;
- }
- #define SET_ITEM_INT(ATTR) \
- do { \
- PyObject *obj = PyLong_FromLong(config->ATTR); \
- if (obj == NULL) { \
- goto fail; \
- } \
- int res = PyDict_SetItemString(dict, #ATTR, obj); \
- Py_DECREF(obj); \
- if (res < 0) { \
- goto fail; \
- } \
- } while (0)
- SET_ITEM_INT(_config_init);
- SET_ITEM_INT(parse_argv);
- SET_ITEM_INT(isolated);
- SET_ITEM_INT(use_environment);
- SET_ITEM_INT(configure_locale);
- SET_ITEM_INT(coerce_c_locale);
- SET_ITEM_INT(coerce_c_locale_warn);
- SET_ITEM_INT(utf8_mode);
- #ifdef MS_WINDOWS
- SET_ITEM_INT(legacy_windows_fs_encoding);
- #endif
- SET_ITEM_INT(dev_mode);
- SET_ITEM_INT(allocator);
- return dict;
- fail:
- Py_DECREF(dict);
- return NULL;
- #undef SET_ITEM_INT
- }
- void
- _PyPreConfig_GetConfig(PyPreConfig *preconfig, const PyConfig *config)
- {
- #define COPY_ATTR(ATTR) \
- if (config->ATTR != -1) { \
- preconfig->ATTR = config->ATTR; \
- }
- COPY_ATTR(parse_argv);
- COPY_ATTR(isolated);
- COPY_ATTR(use_environment);
- COPY_ATTR(dev_mode);
- #undef COPY_ATTR
- }
- static void
- preconfig_get_global_vars(PyPreConfig *config)
- {
- if (config->_config_init != _PyConfig_INIT_COMPAT) {
- /* Python and Isolated configuration ignore global variables */
- return;
- }
- #define COPY_FLAG(ATTR, VALUE) \
- if (config->ATTR < 0) { \
- config->ATTR = VALUE; \
- }
- #define COPY_NOT_FLAG(ATTR, VALUE) \
- if (config->ATTR < 0) { \
- config->ATTR = !(VALUE); \
- }
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
- COPY_FLAG(isolated, Py_IsolatedFlag);
- COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
- if (Py_UTF8Mode > 0) {
- config->utf8_mode = Py_UTF8Mode;
- }
- #ifdef MS_WINDOWS
- COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
- #endif
- _Py_COMP_DIAG_POP
- #undef COPY_FLAG
- #undef COPY_NOT_FLAG
- }
- static void
- preconfig_set_global_vars(const PyPreConfig *config)
- {
- #define COPY_FLAG(ATTR, VAR) \
- if (config->ATTR >= 0) { \
- VAR = config->ATTR; \
- }
- #define COPY_NOT_FLAG(ATTR, VAR) \
- if (config->ATTR >= 0) { \
- VAR = !config->ATTR; \
- }
- _Py_COMP_DIAG_PUSH
- _Py_COMP_DIAG_IGNORE_DEPR_DECLS
- COPY_FLAG(isolated, Py_IsolatedFlag);
- COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
- #ifdef MS_WINDOWS
- COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag);
- #endif
- COPY_FLAG(utf8_mode, Py_UTF8Mode);
- _Py_COMP_DIAG_POP
- #undef COPY_FLAG
- #undef COPY_NOT_FLAG
- }
- const char*
- _Py_GetEnv(int use_environment, const char *name)
- {
- assert(use_environment >= 0);
- if (!use_environment) {
- return NULL;
- }
- const char *var = getenv(name);
- if (var && var[0] != '\0') {
- return var;
- }
- else {
- return NULL;
- }
- }
- int
- _Py_str_to_int(const char *str, int *result)
- {
- const char *endptr = str;
- errno = 0;
- long value = strtol(str, (char **)&endptr, 10);
- if (*endptr != '\0' || errno == ERANGE) {
- return -1;
- }
- if (value < INT_MIN || value > INT_MAX) {
- return -1;
- }
- *result = (int)value;
- return 0;
- }
- void
- _Py_get_env_flag(int use_environment, int *flag, const char *name)
- {
- const char *var = _Py_GetEnv(use_environment, name);
- if (!var) {
- return;
- }
- int value;
- if (_Py_str_to_int(var, &value) < 0 || value < 0) {
- /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */
- value = 1;
- }
- if (*flag < value) {
- *flag = value;
- }
- }
- const wchar_t*
- _Py_get_xoption(const PyWideStringList *xoptions, const wchar_t *name)
- {
- for (Py_ssize_t i=0; i < xoptions->length; i++) {
- const wchar_t *option = xoptions->items[i];
- size_t len;
- wchar_t *sep = wcschr(option, L'=');
- if (sep != NULL) {
- len = (sep - option);
- }
- else {
- len = wcslen(option);
- }
- if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') {
- return option;
- }
- }
- return NULL;
- }
- static PyStatus
- preconfig_init_utf8_mode(PyPreConfig *config, const _PyPreCmdline *cmdline)
- {
- #ifdef MS_WINDOWS
- if (config->legacy_windows_fs_encoding) {
- config->utf8_mode = 0;
- }
- #endif
- if (config->utf8_mode >= 0) {
- return _PyStatus_OK();
- }
- const wchar_t *xopt;
- xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8");
- if (xopt) {
- wchar_t *sep = wcschr(xopt, L'=');
- if (sep) {
- xopt = sep + 1;
- if (wcscmp(xopt, L"1") == 0) {
- config->utf8_mode = 1;
- }
- else if (wcscmp(xopt, L"0") == 0) {
- config->utf8_mode = 0;
- }
- else {
- return _PyStatus_ERR("invalid -X utf8 option value");
- }
- }
- else {
- config->utf8_mode = 1;
- }
- return _PyStatus_OK();
- }
- const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8");
- if (opt) {
- if (strcmp(opt, "1") == 0) {
- config->utf8_mode = 1;
- }
- else if (strcmp(opt, "0") == 0) {
- config->utf8_mode = 0;
- }
- else {
- return _PyStatus_ERR("invalid PYTHONUTF8 environment "
- "variable value");
- }
- return _PyStatus_OK();
- }
- #ifndef MS_WINDOWS
- if (config->utf8_mode < 0) {
- /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */
- const char *ctype_loc = setlocale(LC_CTYPE, NULL);
- if (ctype_loc != NULL
- && (strcmp(ctype_loc, "C") == 0
- || strcmp(ctype_loc, "POSIX") == 0))
- {
- config->utf8_mode = 1;
- }
- }
- #endif
- if (config->utf8_mode < 0) {
- config->utf8_mode = 0;
- }
- return _PyStatus_OK();
- }
- static void
- preconfig_init_coerce_c_locale(PyPreConfig *config)
- {
- if (!config->configure_locale) {
- config->coerce_c_locale = 0;
- config->coerce_c_locale_warn = 0;
- return;
- }
- const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
- if (env) {
- if (strcmp(env, "0") == 0) {
- if (config->coerce_c_locale < 0) {
- config->coerce_c_locale = 0;
- }
- }
- else if (strcmp(env, "warn") == 0) {
- if (config->coerce_c_locale_warn < 0) {
- config->coerce_c_locale_warn = 1;
- }
- }
- else {
- if (config->coerce_c_locale < 0) {
- config->coerce_c_locale = 1;
- }
- }
- }
- /* Test if coerce_c_locale equals to -1 or equals to 1:
- PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced.
- It is only coerced if if the LC_CTYPE locale is "C". */
- if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) {
- /* The C locale enables the C locale coercion (PEP 538) */
- if (_Py_LegacyLocaleDetected(0)) {
- config->coerce_c_locale = 2;
- }
- else {
- config->coerce_c_locale = 0;
- }
- }
- if (config->coerce_c_locale_warn < 0) {
- config->coerce_c_locale_warn = 0;
- }
- }
- static PyStatus
- preconfig_init_allocator(PyPreConfig *config)
- {
- if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
- /* bpo-34247. The PYTHONMALLOC environment variable has the priority
- over PYTHONDEV env var and "-X dev" command line option.
- For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory
- allocators to "malloc" (and not to "debug"). */
- const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC");
- if (envvar) {
- PyMemAllocatorName name;
- if (_PyMem_GetAllocatorName(envvar, &name) < 0) {
- return _PyStatus_ERR("PYTHONMALLOC: unknown allocator");
- }
- config->allocator = (int)name;
- }
- }
- if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) {
- config->allocator = PYMEM_ALLOCATOR_DEBUG;
- }
- return _PyStatus_OK();
- }
- static PyStatus
- preconfig_read(PyPreConfig *config, _PyPreCmdline *cmdline)
- {
- PyStatus status;
- status = _PyPreCmdline_Read(cmdline, config);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- precmdline_set_preconfig(cmdline, config);
- /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */
- #ifdef MS_WINDOWS
- _Py_get_env_flag(config->use_environment,
- &config->legacy_windows_fs_encoding,
- "PYTHONLEGACYWINDOWSFSENCODING");
- #endif
- preconfig_init_coerce_c_locale(config);
- status = preconfig_init_utf8_mode(config, cmdline);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- /* allocator */
- status = preconfig_init_allocator(config);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- assert(config->coerce_c_locale >= 0);
- assert(config->coerce_c_locale_warn >= 0);
- #ifdef MS_WINDOWS
- assert(config->legacy_windows_fs_encoding >= 0);
- #endif
- assert(config->utf8_mode >= 0);
- assert(config->isolated >= 0);
- assert(config->use_environment >= 0);
- assert(config->dev_mode >= 0);
- return _PyStatus_OK();
- }
- /* Read the configuration from:
- - command line arguments
- - environment variables
- - Py_xxx global configuration variables
- - the LC_CTYPE locale */
- PyStatus
- _PyPreConfig_Read(PyPreConfig *config, const _PyArgv *args)
- {
- PyStatus status;
- status = _PyRuntime_Initialize();
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- preconfig_get_global_vars(config);
- /* Copy LC_CTYPE locale, since it's modified later */
- const char *loc = setlocale(LC_CTYPE, NULL);
- if (loc == NULL) {
- return _PyStatus_ERR("failed to LC_CTYPE locale");
- }
- char *init_ctype_locale = _PyMem_RawStrdup(loc);
- if (init_ctype_locale == NULL) {
- return _PyStatus_NO_MEMORY();
- }
- /* Save the config to be able to restore it if encodings change */
- PyPreConfig save_config;
- status = _PyPreConfig_InitFromPreConfig(&save_config, config);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- /* Set LC_CTYPE to the user preferred locale */
- if (config->configure_locale) {
- _Py_SetLocaleFromEnv(LC_CTYPE);
- }
- PyPreConfig save_runtime_config;
- preconfig_copy(&save_runtime_config, &_PyRuntime.preconfig);
- _PyPreCmdline cmdline = _PyPreCmdline_INIT;
- int locale_coerced = 0;
- int loops = 0;
- while (1) {
- int utf8_mode = config->utf8_mode;
- /* Watchdog to prevent an infinite loop */
- loops++;
- if (loops == 3) {
- status = _PyStatus_ERR("Encoding changed twice while "
- "reading the configuration");
- goto done;
- }
- /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend
- on the utf8_mode and legacy_windows_fs_encoding members
- of _PyRuntime.preconfig. */
- preconfig_copy(&_PyRuntime.preconfig, config);
- if (args) {
- // Set command line arguments at each iteration. If they are bytes
- // strings, they are decoded from the new encoding.
- status = _PyPreCmdline_SetArgv(&cmdline, args);
- if (_PyStatus_EXCEPTION(status)) {
- goto done;
- }
- }
- status = preconfig_read(config, &cmdline);
- if (_PyStatus_EXCEPTION(status)) {
- goto done;
- }
- /* The legacy C locale assumes ASCII as the default text encoding, which
- * causes problems not only for the CPython runtime, but also other
- * components like GNU readline.
- *
- * Accordingly, when the CLI detects it, it attempts to coerce it to a
- * more capable UTF-8 based alternative.
- *
- * See the documentation of the PYTHONCOERCECLOCALE setting for more
- * details.
- */
- int encoding_changed = 0;
- if (config->coerce_c_locale && !locale_coerced) {
- locale_coerced = 1;
- _Py_CoerceLegacyLocale(0);
- encoding_changed = 1;
- }
- if (utf8_mode == -1) {
- if (config->utf8_mode == 1) {
- /* UTF-8 Mode enabled */
- encoding_changed = 1;
- }
- }
- else {
- if (config->utf8_mode != utf8_mode) {
- encoding_changed = 1;
- }
- }
- if (!encoding_changed) {
- break;
- }
- /* Reset the configuration before reading again the configuration,
- just keep UTF-8 Mode and coerce C locale value. */
- int new_utf8_mode = config->utf8_mode;
- int new_coerce_c_locale = config->coerce_c_locale;
- preconfig_copy(config, &save_config);
- config->utf8_mode = new_utf8_mode;
- config->coerce_c_locale = new_coerce_c_locale;
- /* The encoding changed: read again the configuration
- with the new encoding */
- }
- status = _PyStatus_OK();
- done:
- // Revert side effects
- setlocale(LC_CTYPE, init_ctype_locale);
- PyMem_RawFree(init_ctype_locale);
- preconfig_copy(&_PyRuntime.preconfig, &save_runtime_config);
- _PyPreCmdline_Clear(&cmdline);
- return status;
- }
- /* Write the pre-configuration:
- - set the memory allocators
- - set Py_xxx global configuration variables
- - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode
- (PEP 540)
- The applied configuration is written into _PyRuntime.preconfig.
- If the C locale cannot be coerced, set coerce_c_locale to 0.
- Do nothing if called after Py_Initialize(): ignore the new
- pre-configuration. */
- PyStatus
- _PyPreConfig_Write(const PyPreConfig *src_config)
- {
- PyPreConfig config;
- PyStatus status = _PyPreConfig_InitFromPreConfig(&config, src_config);
- if (_PyStatus_EXCEPTION(status)) {
- return status;
- }
- if (_PyRuntime.core_initialized) {
- /* bpo-34008: Calling this functions after Py_Initialize() ignores
- the new configuration. */
- return _PyStatus_OK();
- }
- PyMemAllocatorName name = (PyMemAllocatorName)config.allocator;
- if (name != PYMEM_ALLOCATOR_NOT_SET) {
- if (_PyMem_SetupAllocators(name) < 0) {
- return _PyStatus_ERR("Unknown PYTHONMALLOC allocator");
- }
- }
- preconfig_set_global_vars(&config);
- if (config.configure_locale) {
- if (config.coerce_c_locale) {
- if (!_Py_CoerceLegacyLocale(config.coerce_c_locale_warn)) {
- /* C locale not coerced */
- config.coerce_c_locale = 0;
- }
- }
- /* Set LC_CTYPE to the user preferred locale */
- _Py_SetLocaleFromEnv(LC_CTYPE);
- }
- /* Write the new pre-configuration into _PyRuntime */
- preconfig_copy(&_PyRuntime.preconfig, &config);
- return _PyStatus_OK();
- }
|