text: #include "Python.h"
  #include "pycore_initconfig.h"
  #include "pycore_getopt.h"
  #include "pycore_pystate.h"   /* _PyRuntime_Initialize() */
  #include <locale.h>       /* setlocale() */
  
  
  #define DECODE_LOCALE_ERR(NAME, LEN) \
      (((LEN) == -2) \
       ? _PyStatus_ERR("cannot decode " NAME) \
       : _PyStatus_NO_MEMORY())
  
  
  /* Forward declarations */
  static void
  preconfig_copy(PyPreConfig *config, const PyPreConfig *config2);
  
  
  /* --- File system encoding/errors -------------------------------- */
  
  /* The filesystem encoding is chosen by config_init_fs_encoding(),
     see also initfsencoding().
  
     Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
     are encoded to UTF-8. */
  const char *Py_FileSystemDefaultEncoding = NULL;
  int Py_HasFileSystemDefaultEncoding = 0;
  const char *Py_FileSystemDefaultEncodeErrors = NULL;
  int _Py_HasFileSystemDefaultEncodeErrors = 0;
  
  void
  _Py_ClearFileSystemEncoding(void)
  {
      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;
      }
  }
  
  
  /* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
     global configuration variables. */
  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_FileSystemDefaultEncoding = encoding2;
      Py_HasFileSystemDefaultEncoding = 0;
  
      Py_FileSystemDefaultEncodeErrors = errors2;
      _Py_HasFileSystemDefaultEncodeErrors = 0;
      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",
                                           (Py_ssize_t)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);
      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;
      }
  
      assert(cmdline->use_environment >= 0);
      assert(cmdline->isolated >= 0);
      assert(cmdline->dev_mode >= 0);
  
      return _PyStatus_OK();
  }
  
  
  /* --- PyPreConfig ----------------------------------------------- */
  
  
  static PyStatus
  preconfig_check_struct_size(PyPreConfig *config)
  {
      if (config->struct_size != sizeof(PyPreConfig)) {
          return _PyStatus_ERR("unsupported PyPreConfig structure size "
                               "(Python version mismatch?)");
      }
      return _PyStatus_OK();
  }
  
  
  PyStatus
  _PyPreConfig_InitCompatConfig(PyPreConfig *config)
  {
      size_t struct_size = config->struct_size;
      memset(config, 0, sizeof(*config));
      config->struct_size = struct_size;
  
      PyStatus status = preconfig_check_struct_size(config);
      if (_PyStatus_EXCEPTION(status)) {
          _PyStatus_UPDATE_FUNC(status);
          return status;
      }
  
      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
      return _PyStatus_OK();
  }
  
  
  PyStatus
  PyPreConfig_InitPythonConfig(PyPreConfig *config)
  {
      PyStatus status = _PyPreConfig_InitCompatConfig(config);
      if (_PyStatus_EXCEPTION(status)) {
          _PyStatus_UPDATE_FUNC(status);
          return status;
      }
  
      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
      return _PyStatus_OK();
  }
  
  
  PyStatus
  PyPreConfig_InitIsolatedConfig(PyPreConfig *config)
  {
      PyStatus status = _PyPreConfig_InitCompatConfig(config);
      if (_PyStatus_EXCEPTION(status)) {
          _PyStatus_UPDATE_FUNC(status);
          return status;
      }
  
      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
      return _PyStatus_OK();
  }
  
  
  PyStatus
  _PyPreConfig_InitFromPreConfig(PyPreConfig *config,
                                 const PyPreConfig *config2)
  {
      PyStatus status = PyPreConfig_InitPythonConfig(config);
      if (_PyStatus_EXCEPTION(status)) {
          return status;
      }
  
      preconfig_copy(config, config2);
      return _PyStatus_OK();
  }
  
  
  PyStatus
  _PyPreConfig_InitFromConfig(PyPreConfig *preconfig, const PyConfig *config)
  {
      PyStatus status;
      _PyConfigInitEnum config_init = (_PyConfigInitEnum)config->_config_init;
      switch (config_init) {
      case _PyConfig_INIT_PYTHON:
          status = PyPreConfig_InitPythonConfig(preconfig);
          break;
      case _PyConfig_INIT_ISOLATED:
          status = PyPreConfig_InitIsolatedConfig(preconfig);
          break;
      case _PyConfig_INIT_COMPAT:
      default:
          status = _PyPreConfig_InitCompatConfig(preconfig);
      }
  
      if (_PyStatus_EXCEPTION(status)) {
          return status;
      }
  
      _PyPreConfig_GetConfig(preconfig, config);
      return _PyStatus_OK();
  }
  
  
  static void
  preconfig_copy(PyPreConfig *config, const PyPreConfig *config2)
  {
      assert(config->struct_size == sizeof(PyPreConfig));
  
  #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); \
      }
  
      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
  
  #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; \
      }
  
      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);
  
  #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;
      }
  
      status = preconfig_check_struct_size(config);
      if (_PyStatus_EXCEPTION(status)) {
          _PyStatus_UPDATE_FUNC(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;
      save_config.struct_size = sizeof(PyPreConfig);
  
      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);
      }
  
      _PyPreCmdline cmdline = _PyPreCmdline_INIT;
      int init_utf8_mode = Py_UTF8Mode;
  #ifdef MS_WINDOWS
      int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
  #endif
  
      if (args) {
          status = _PyPreCmdline_SetArgv(&cmdline, args);
          if (_PyStatus_EXCEPTION(status)) {
              goto done;
          }
      }
  
      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 Py_UTF8Mode and Py_LegacyWindowsFSEncodingFlag. */
          Py_UTF8Mode = config->utf8_mode;
  #ifdef MS_WINDOWS
          Py_LegacyWindowsFSEncodingFlag = config->legacy_windows_fs_encoding;
  #endif
  
          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 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:
      if (init_ctype_locale != NULL) {
          setlocale(LC_CTYPE, init_ctype_locale);
          PyMem_RawFree(init_ctype_locale);
      }
      Py_UTF8Mode = init_utf8_mode ;
  #ifdef MS_WINDOWS
      Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
  #endif
      _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;
      config.struct_size = sizeof(PyPreConfig);
  
      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();
  }
  